【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录

一、目的

二、解决方案

[2.1 什么是FFmpeg](#2.1 什么是FFmpeg)

[2.2 FFmpeg主要功能](#2.2 FFmpeg主要功能)

[2.3 使用Xabe.FFmpeg调用FFmpeg功能](#2.3 使用Xabe.FFmpeg调用FFmpeg功能)

[2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI](#2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI)

三、总结


一、目的

当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回了一堆对应帧上的ROI数据,因此为了展示算法识别效果,把返回的Roi画到对应帧上进行展示,这里使用FFmpeg对视频进行处理,基于FFmpeg 的 drawbox 滤镜来绘制 ROI。
展示:
处理前:

处理后:

二、解决方案

2.1 什么是FFmpeg

FFmpeg 本身是一个多媒体处理工具,它可以对视频流进行各种处理(如裁剪、滤镜、编码等),以及 视频流推送到 RTMP 服务器或从 RTMP 服务器拉取流。

2.2****FFmpeg主要功能

FFmpeg 主要用于以下几个方面:

  • 推流:将本地视频文件或实时视频流推送到 RTMP 服务器。
  • 拉流:从 RTMP 服务器拉取视频流并进行处理(如转码、转封装等)。
  • 处理流:对视频流进行各种处理(如裁剪、滤镜、编码等)。

2.3 使用Xabe.FFmpeg调用FFmpeg功能

Xabe.FFmpeg 是一个基于 .NET Standard 的 FFmpeg 封装库,旨在简化媒体处理任务。它允许开发者在不了解 FFmpeg 工作原理的情况下,通过 .NET Core 应用程序调用 FFmpeg 功能,并传递自定义参数。Xabe.FFmpeg 提供了丰富的 API,支持视频和音频的转换、剪辑、合并等操作,适用于各种媒体处理需求。
本项目中使用版本为:5.2.6

cs 复制代码
dotnet add package Xabe.FFmpeg

简单使用示例:简单展示了获取视频第一帧保存为图像存储在本地(这里也可以获取任何特定帧)。

cs 复制代码
using AI.Demo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xabe.FFmpeg;

namespace AI.Demo.Common
{
    public class FFmpegutil
    {
        static FFmpegutil()
        {
            //获取存放本地ffmpg.exe路径的文件夹路径
            //如果是使用Nuget包安装的FFmpeg,默认路径是当前应用程序的根目录
            //如果是手动下载的FFmpeg,需要将ffmpeg.exe放在应用程序的根目录下
            var ffmpegPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe");
            if(File.Exists(ffmpegPath))
            {
                //如果ffmpeg.exe存在,则设置FFmpeg的可执行文件路径
                FFmpeg.SetExecutablesPath(System.IO.Path.GetDirectoryName(ffmpegPath)); //设置FFmpeg的可执行文件路径
            }
            else
            {
                throw new Exception("ffmpeg.exe not found in the application directory.");
            }
        }

        /// <summary>  
        /// 获取FFmpeg命令行参数  
        /// </summary>  
        /// <param name="inputFile">输入文件路径</param>  
        /// <param name="outputFile">输出文件路径</param>  
        /// <returns>FFmpeg命令行参数</returns>  
        public static async Task<string> GetVideoFrame(string inputFile)
        {
            //根据传入的视频文件地址,获取该视频的第一帧图片,并保存到指定的输出文件路径  
            if (string.IsNullOrEmpty(inputFile))
            {
                throw new ArgumentException("Input and output file paths must be provided.");
            }
            if (!File.Exists(inputFile))
            {
                throw new ArgumentException("file Not Exist");
            }
            //输出文件路径  
            string outputFile = System.IO.Path.ChangeExtension(inputFile, ".jpg");

            // 替换为使用 FFmpeg 的截图功能  
            await FFmpeg.Conversions.New()
                .AddParameter($"-i \"{inputFile}\" -frames:v 1 \"{outputFile}\"")
                .Start();

            return outputFile;
        }

    }
}

2.4****使用 FFmpeg 的 drawbox 滤镜来绘制 ROI

基于drawbox的enable参数来控制在特定帧上绘制,drawbox格式: "drawbox=enable='eq(n,frameIndex)':x:y:w:h:color:thickness"

cs 复制代码
 /// <summary>
 /// 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI
 /// </summary>
 /// <param name="inputFile"></param>
 /// <param name="outputFile"></param>
 /// <param name="locations"></param>
 /// <returns></returns>
 /// <exception cref="ArgumentException"></exception>
 public static async Task<bool> DrawRoiByLocation(string inputFile,ref string analyseVdeofile, List<Location> locations)
 {
     if (string.IsNullOrEmpty(inputFile))
     {
         throw new ArgumentException("Input file paths must be provided.");
     }
     if (!File.Exists(inputFile))
     {
         throw new ArgumentException("file Not Exist");
     }
     //改变输入文件的名字,增加后缀以区分输出文件
     string outputFile = System.IO.Path.ChangeExtension(inputFile, "_analyse.mp4");
     analyseVdeofile = outputFile;
     try
     {
         // 构建FFmpeg滤镜命令
         StringBuilder filterBuilder = new StringBuilder();

         // 对每个Location(帧)和ROI处理
         foreach (var location in locations)
         {
             int frameIndex = location.Index;

             // 对该帧中的每个ROI进行处理
             foreach (var roi in location.Rois)
             {
                 // 使用drawbox的enable参数来控制在特定帧上绘制
                 // 格式:drawbox=enable='eq(n,frameIndex)':x:y:w:h:color:thickness
                 string boxFilter = $"drawbox=enable='eq(n,{frameIndex})':x={roi.X}:y={roi.Y}:w={roi.W}:h={roi.H}:color=red:thickness=2";

                 if (filterBuilder.Length > 0)
                     filterBuilder.Append(",");

                 filterBuilder.Append(boxFilter);
             }
         }

         // 创建转换命令,直接使用输入文件路径而不是GetMediaInfo
         var conversion = FFmpeg.Conversions.New()
             .AddParameter($"-i \"{inputFile}\"")
             .SetOutput(outputFile);

         // 如果有滤镜,添加到命令中
         if (filterBuilder.Length > 0)
         {
             conversion.AddParameter($"-vf \"{filterBuilder}\"")
                      .AddParameter("-c:v libx264") // 使用H.264编码器
                      .AddParameter("-preset medium") // 编码速度和质量的平衡
                      .AddParameter("-crf 23") // 控制质量,值越低质量越高
                      .AddParameter("-pix_fmt yuv420p") // 设置像素格式,提高兼容性
                      .AddParameter("-c:a aac") // 使用AAC音频编码器
                      .AddParameter("-movflags +faststart"); // 优化网络播放
         }
         else
         {
             // 即使没有滤镜,也确保使用正确的编解码器
             conversion.AddParameter("-c:v libx264")
                      .AddParameter("-preset medium")
                      .AddParameter("-crf 23")
                      .AddParameter("-pix_fmt yuv420p")
                      .AddParameter("-c:a aac")
                      .AddParameter("-movflags +faststart");
         }

         // 执行命令并等待完成
         await conversion.Start();
         
         return File.Exists(outputFile);
     }
     catch (Exception ex)
     {
         Console.WriteLine($"Error drawing ROI: {ex.Message}");
         return false;
     }
 }

三、总结

FFmpeg是一个强大的 多媒体处理工具,以上的处理只是它整体功能中的一小部分。结合 Xabe.FFmpeg可以进行视频的格式转换、裁剪、增加滤镜多种功能。同时支持在桌面应用、Web应用、Api服务、云服务多种场景下的处理需求。
把之所学以文载之,欢迎大家多多交流~

相关推荐
深圳市青牛科技实业有限公司 小芋圆10 小时前
GC1809:高性能音频接收与转换芯片
科技·单片机·嵌入式硬件·音视频·智能家居·新能源
xx155802862xx10 小时前
Python如何给视频添加音频和字幕
java·python·音视频
Phoenixtree_DongZhao10 小时前
感知万物:图像与视频中识别、解释、描述与分割万物
音视频
LabVIEW开发11 小时前
LabVIEW音频测试分析
音视频·labview·labview知识
头发那是一根不剩了12 小时前
用 FFmpeg 实现 RTMP 推流直播
ffmpeg
有你有我OK12 小时前
FFmpeg介绍
ffmpeg
博思云为14 小时前
客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
重构·音视频
嘟嘟实验室14 小时前
SAM2Long本地部署,视频分割处理,绿幕抠像,超长视频支持
windows·python·音视频
dntktop14 小时前
音乐“穿梭机”AudioRelay,让你的音频“无缝对接”
运维·windows·电脑·音视频
百锦再18 小时前
.Net 优秀框架 ABP全面详解
microsoft·.net·web·blazor·abp·razor