FFMpeg.AutoGen:用官方example代码介绍如何使用FFMpeg.AutoGen(未完成)

FFMpeg是一套C编译的开源工具集。主要用于视频处理,可以编解码视频,建立流媒体服务器等等。官方网站:http://ffmpeg.org/

FFMpeg.AutoGen封装方法以方便C#调用FFmpeg。项目地址:https://github.com/Ruslan-B/FFmpeg.AutoGen。可以使用NuGet安装。

本文使用ffmpeg.autogen版本4.2.2,对应ffmpeg版本也是4.2.2。

image

AutoGen只是封装调用FFmpeg,程序还是需要下在FFmpeg工具放在程序目录里,且版本要对应。 笔者用FFMpeg.AutoGetn的官方example代码介绍一下FFMpege如何使用(源代码在其github库里)。example是一个命令行程序,mian函数里面的代码如下。我将通过此函数调用顺序介绍ffmpeg.AutoGet的用法。

  1 private static void Main(string[] args)
  2         {
  3             Console.WriteLine("Current directory: " + Environment.CurrentDirectory);
  4             Console.WriteLine("Running in {0}-bit mode.", Environment.Is64BitProcess ? "64" : "32");
  5 
  6             FFmpegBinariesHelper.RegisterFFmpegBinaries();
  7 
  8             Console.WriteLine($"FFmpeg version info: {ffmpeg.av_version_info()}");
  9 
 10             //配置ffmpeg输出日志
 11             SetupLogging();
 12             //配置硬件解码器
 13             ConfigureHWDecoder(out var deviceType);
 14 
 15             //解码
 16             Console.WriteLine("Decoding...");
 17             DecodeAllFramesToImages(deviceType);
 18 
 19             //编码
 20             Console.WriteLine("Encoding...");
 21             EncodeImagesToH264();
 22         }

1.注册FFmpeg库。实际就将ffmpeg库的地址告诉autogen

  1 FFmpegBinariesHelper.RegisterFFmpegBinaries();

注册FFmpeg,这里的FFmpegBinariesHelper类需要在程序里重写。我这里摘抄官方demo的代码

  1 namespace FFmpeg.AutoGen.Example
  2 {
  3     public class FFmpegBinariesHelper
  4     {
  5         internal static void RegisterFFmpegBinaries()
  6         {
  7             var current = Environment.CurrentDirectory;
  8             var probe = Path.Combine("FFmpeg", "bin", Environment.Is64BitProcess ? "x64" : "x86");
  9             while (current != null)
 10             {
 11                 var ffmpegBinaryPath = Path.Combine(current, probe);
 12                 if (Directory.Exists(ffmpegBinaryPath))
 13                 {
 14                     Console.WriteLine($"FFmpeg binaries found in: {ffmpegBinaryPath}");
 15                     ffmpeg.RootPath = ffmpegBinaryPath;
 16                     return;
 17                 }
 18 
 19                 current = Directory.GetParent(current)?.FullName;
 20             }
 21         }
 22     }
 23 }

代码的功能就是寻找ffmpeg的路径。

核心代码:

  1 ffmpeg.RootPath = ffmpegBinaryPath;

2.ffmpeg 一些调用其的配置(可选)

2.1 配置日志输出
  1  	    /// <summary>
  2         /// 配置日志
  3         /// </summary>
  4         private static unsafe void SetupLogging()
  5         {
  6             ffmpeg.av_log_set_level(ffmpeg.AV_LOG_VERBOSE);
  7 
  8             // do not convert to local function
  9             av_log_set_callback_callback logCallback = (p0, level, format, vl) =>
 10             {
 11                 if (level > ffmpeg.av_log_get_level()) return;
 12 
 13                 var lineSize = 1024;
 14                 var lineBuffer = stackalloc byte[lineSize];
 15                 var printPrefix = 1;
 16                 ffmpeg.av_log_format_line(p0, level, format, vl, lineBuffer, lineSize, &printPrefix);
 17                 var line = Marshal.PtrToStringAnsi((IntPtr) lineBuffer);
 18                 Console.ForegroundColor = ConsoleColor.Yellow;
 19                 Console.Write(line);
 20                 Console.ResetColor();
 21             };
 22 
 23             ffmpeg.av_log_set_callback(logCallback);
 24         }

主要就是配置日志回调。

核心代码:

  1 ffmpeg.av_log_set_callback(logCallback)
2.2配置硬件解码器ffmpeg是支持硬解的.具体支持类型可以参考ffmpeg官方文档。转载网友摘录的ffmpeg支持硬解编码的枚举。

  1 enum AVHWDeviceType {
  2     AV_HWDEVICE_TYPE_NONE,
  3     AV_HWDEVICE_TYPE_VDPAU,
  4     AV_HWDEVICE_TYPE_CUDA,
  5     AV_HWDEVICE_TYPE_VAAPI,
  6      AV_HWDEVICE_TYPE_DXVA2,
  7      AV_HWDEVICE_TYPE_QSV,
  8      AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
  9      AV_HWDEVICE_TYPE_D3D11VA,
 10      AV_HWDEVICE_TYPE_DRM,
 11      AV_HWDEVICE_TYPE_OPENCL,
 12      AV_HWDEVICE_TYPE_MEDIACODEC,
 13  };
example通过 ConfigureHWDecoder(out var deviceType); 获取系统支持的硬件的解码类型,并让在命令行让用户选择。然后将用户选择的硬件解码器保存到局部变量deviceType里,解码时根据此变量解码。
  1         /// <summary>
  2         /// 配置硬件解码器
  3         /// </summary>
  4         /// <param name="HWtype"></param>
  5         private static void ConfigureHWDecoder(out AVHWDeviceType HWtype)
  6         {
  7             HWtype = AVHWDeviceType.AV_HWDEVICE_TYPE_NONE;
  8             Console.WriteLine("Use hardware acceleration for decoding?[n]");
  9             var key = Console.ReadLine();
 10             var availableHWDecoders = new Dictionary<int, AVHWDeviceType>();
 11             if (key == "y")
 12             {
 13                 Console.WriteLine("Select hardware decoder:");
 14                 var type = AVHWDeviceType.AV_HWDEVICE_TYPE_NONE;
 15                 var number = 0;
 16                 while ((type = ffmpeg.av_hwdevice_iterate_types(type)) != AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
 17                 {
 18                     Console.WriteLine($"{++number}. {type}");
 19                     availableHWDecoders.Add(number, type);
 20                 }
 21                 if (availableHWDecoders.Count == 0)
 22                 {
 23                     Console.WriteLine("Your system have no hardware decoders.");
 24                     HWtype = 。;
 25                     return;
 26                 }
 27                 int decoderNumber = availableHWDecoders.SingleOrDefault(t => t.Value == AVHWDeviceType.AV_HWDEVICE_TYPE_DXVA2).Key;
 28                 if (decoderNumber == 0)
 29                     decoderNumber = availableHWDecoders.First().Key;
 30                 Console.WriteLine($"Selected [{decoderNumber}]");
 31                 int.TryParse(Console.ReadLine(),out var inputDecoderNumber);
 32                 availableHWDecoders.TryGetValue(inputDecoderNumber == 0 ? decoderNumber: inputDecoderNumber, out HWtype);
 33             }
 34         }
 35 

核心代码:ffmpeg.av_hwdevice_iterate_types(type)获得系统支持的硬件解码。

ffmpeg.av_hwdevice_iterate_types(type)根据传入的硬件解码其类型,返回AVHWDeviceType枚举里下一个系统支持的硬件解码器类型。

3.解码

  1         /// <summary>
  2         /// 解码
  3         /// </summary>
  4         /// <param name="HWDevice"></param>
  5         private static unsafe void DecodeAllFramesToImages(AVHWDeviceType HWDevice)
  6         {
  7             // decode all frames from url, please not it might local resorce, e.g. string url = "../../sample_mpeg4.mp4";
  8             var url = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"; // be advised this file holds 1440 frames
  9             using (var vsd = new VideoStreamDecoder(url,HWDevice))
 10             {
 11                 Console.WriteLine($"codec name: {vsd.CodecName}");
 12 
 13                 var info = vsd.GetContextInfo();
 14                 info.ToList().ForEach(x => Console.WriteLine($"{x.Key} = {x.Value}"));
 15 
 16                 var sourceSize = vsd.FrameSize;
 17                 var sourcePixelFormat = HWDevice == AVHWDeviceType.AV_HWDEVICE_TYPE_NONE ? vsd.PixelFormat : GetHWPixelFormat(HWDevice);
 18                 var destinationSize = sourceSize;
 19                 var destinationPixelFormat = AVPixelFormat.AV_PIX_FMT_BGR24;
 20                 using (var vfc = new VideoFrameConverter(sourceSize, sourcePixelFormat, destinationSize, destinationPixelFormat))
 21                 {
 22                     var frameNumber = 0;
 23                     while (vsd.TryDecodeNextFrame(out var frame))
 24                     {
 25                         var convertedFrame = vfc.Convert(frame);
 26 
 27                         using (var bitmap = new Bitmap(convertedFrame.width, convertedFrame.height, convertedFrame.linesize[0], PixelFormat.Format24bppRgb, (IntPtr) convertedFrame.data[0]))
 28                             bitmap.Save($"frame.{frameNumber:D8}.jpg", ImageFormat.Jpeg);
 29 
 30                         Console.WriteLine($"frame: {frameNumber}");
 31                         frameNumber++;
 32                     }
 33                 }
 34             }
 35         }

example源代码里解码主要使用VideoStreamDecoder和VideoFrameConverter两个类。这两个类不是FFMpeg.AutoGen里的类型,而是example代码里。也就是说解码工作是需要用户自己封装解码类。图省事可以直接照搬example里的代码。笔者很推荐读一下这两个类的源代码,可以搞清楚ffmpeg的解码流程。大概的流程是:

  1 初始化AVFormatContext(音视频信息数据)——据根据源找到流——根据流配置视频格式——根据流生成解码器codecContext(解码器信息)——


其中有两个概念包和帧需要注意一下,这里转载灰色飘零博客里描述:

AVPacket

用于存储压缩的数据,分别包括有音频压缩数据,视频压缩数据和字幕压缩数据。它通常在解复用操作后存储压缩数据,然后作为输入传给解码器。或者由编码器输出然后传递给复用器。对于视频压缩数据,一个AVPacket通常包括一个视频帧。对于音频压缩数据,可能包括几个压缩的音频帧。

AVFrame

用于存储解码后的音频或者视频数据。AVFrame必须通过av_frame_alloc进行分配,通过av_frame_free释放。

两者之间的关系

av_read_frame得到压缩的数据包AVPacket,一般有三种压缩的数据包(视频、音频和字幕),都用AVPacket表示。

然后调用avcodec_send_packet 和 avcodec_receive_frame对AVPacket进行解码得到AVFrame。

注:从 FFmpeg 3.x 开始,avcodec_decode_video2 就被废弃了,取而代之的是 avcodec_send_packet 和 avcodec_receive_frame。




参考文档:

【1】FFmpeg视频解码硬件加速

【2】FFmpeg开发之PacketQueue中AVPacket和AVFrame关系

【3】ffmpeg+ffserver搭建流媒体服务器

【4】FFmpeg框架的基础知识

【5】FFMPEG-数据结构解释(AVCodecContext,AVStream,AVFormatContext)

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
机器学习是一种人工智能(AI)的子领域,致力于研究如何利用数据和算法让计算机系统具备学习能力,从而能够自动地完成特定任务或者改进自身性能。机器学习的核心思想是让计算机系统通过学习数据中的模式和规律来实现目标,而不需要显式地编程。 机器学习应用非常广泛,包括但不限于以下领域: 图像识别和计算机视觉: 机器学习在图像识别、目标检测、人脸识别、图像分割等方面有着广泛的应用。例如,通过深度学习技术,可以训练神经网络来识别图像中的对象、人脸或者场景,用于智能监控、自动驾驶、医学影像分析等领域。 自然语言处理: 机器学习在自然语言处理领域有着重要的应用,包括文本分类、情感分析、机器翻译、语音识别等。例如,通过深度学习模型,可以训练神经网络来理解和生成自然语言,用于智能客服、智能助手、机器翻译等场景。 推荐系统: 推荐系统利用机器学习算法分析用户的行为和偏好,为用户推荐个性化的产品或服务。例如,电商网站可以利用机器学习算法分析用户的购买历史和浏览行为,向用户推荐感兴趣的商品。 预测和预测分析: 机器学习可以用于预测来事件的发生概率或者趋势。例如,金融领域可以利用机器学习算法进行股票价格预测、信用评分、欺诈检测等。 医疗诊断和生物信息学: 机器学习在医疗诊断、药物研发、基因组学等领域有着重要的应用。例如,可以利用机器学习算法分析医学影像数据进行疾病诊断,或者利用机器学习算法分析基因数据进行疾病风险预测。 智能交通和物联网: 机器学习可以应用于智能交通系统、智能城市管理和物联网等领域。例如,可以利用机器学习算法分析交通数据优化交通流量,或者利用机器学习算法分析传感器数据监测设备状态。 以上仅是机器学习应用的一部分,随着机器学习技术的不断发展和应用场景的不断拓展,机器学习在各个领域都有着重要的应用价值,并且正在改变我们的生活和工作方式。
FFmpeg.AutoGen库是一个C#封装的FFmpeg库,它可以帮助你在C#应用程序中使用FFmpeg功能。以下是一些使用FFmpeg.AutoGen库的步骤: 1. 下载FFmpeg.AutoGen库 你可以从GitHub上下载FFmpeg.AutoGen库。下载后,将其添加到你的项目中。 2. 导入FFmpeg.AutoGen命名空间 在你的代码中,使用以下语句导入FFmpeg.AutoGen命名空间: ``` using FFmpeg.AutoGen; ``` 3. 初始化FFmpeg使用FFmpeg之前,你需要先初始化它。可以使用以下代码: ``` ffmpeg.av_register_all(); ffmpeg.avcodec_register_all(); ffmpeg.avformat_network_init(); ``` 4. 打开输入文件 使用avformat_open_input函数打开输入文件,例如: ``` AVFormatContext* pFormatContext = null; if (ffmpeg.avformat_open_input(&pFormatContext, inputFile, null, null) != 0) { // 出错处理 } ``` 5. 查找流信息 使用avformat_find_stream_info函数查找流信息,例如: ``` if (ffmpeg.avformat_find_stream_info(pFormatContext, null) < 0) { // 出错处理 } ``` 6. 处理流 处理音视频流,例如: ``` AVCodecContext* pCodecContext = null; int audioStreamIndex = -1; int videoStreamIndex = -1; for (int i = 0; i < pFormatContext->nb_streams; i++) { AVStream* stream = pFormatContext->streams[i]; AVCodecParameters* codecParameters = stream->codecpar; AVCodec* codec = null; if (codecParameters->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO) { audioStreamIndex = i; codec = ffmpeg.avcodec_find_decoder(codecParameters->codec_id); pCodecContext = ffmpeg.avcodec_alloc_context3(codec); ffmpeg.avcodec_parameters_to_context(pCodecContext, codecParameters); if (ffmpeg.avcodec_open2(pCodecContext, codec, null) < 0) { // 出错处理 } } else if (codecParameters->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO) { videoStreamIndex = i; codec = ffmpeg.avcodec_find_decoder(codecParameters->codec_id); pCodecContext = ffmpeg.avcodec_alloc_context3(codec); ffmpeg.avcodec_parameters_to_context(pCodecContext, codecParameters); if (ffmpeg.avcodec_open2(pCodecContext, codec, null) < 0) { // 出错处理 } } else { // 其他流类型 } } ``` 7. 释放资源 在使用FFmpeg后,你需要释放资源。可以使用以下代码: ``` ffmpeg.avcodec_free_context(&pCodecContext); ffmpeg.avformat_close_input(&pFormatContext); ``` 以上是使用FFmpeg.AutoGen库的简单步骤,你可以根据自己的需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值