C# 使用FFmpeg.Autogen對byte[]進行編解碼

C# 使用FFmpeg.Autogen對byte[]進行編解碼,參考:https://github.com/vanjoge/CSharpVideoDemo

入口調用類:

using System;
using System.IO;
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen;namespace FFmpegAnalyzer
{public class FFmpegWrapper{/// <summary>/// 默認的編碼格式/// </summary>public AVCodecID DefaultCodecFormat { get; set; } = AVCodecID.AV_CODEC_ID_H264;/// <summary>/// 注冊FFmpeg/// </summary>public static void RegisterFFmpeg(){FFmpegBinariesHelper.RegisterFFmpegBinaries();// 初始化注冊ffmpeg相關的編碼器ffmpeg.av_register_all();ffmpeg.avcodec_register_all();ffmpeg.avformat_network_init();}/// <summary>/// 注冊日志/// <exception cref="NotSupportedException">.NET Framework 不支持日志注冊</exception>/// </summary>private unsafe void RegisterFFmpegLogger(){// 設置記錄ffmpeg日志級別ffmpeg.av_log_set_level(ffmpeg.AV_LOG_VERBOSE);av_log_set_callback_callback logCallback = (p0, level, format, vl) =>{if (level > ffmpeg.av_log_get_level()) return;var lineSize = 1024;var lineBuffer = stackalloc byte[lineSize];var printPrefix = 1;ffmpeg.av_log_format_line(p0, level, format, vl, lineBuffer, lineSize, &printPrefix);var line = Marshal.PtrToStringAnsi((IntPtr)lineBuffer);Console.Write(line);};ffmpeg.av_log_set_callback(logCallback);}#region 編碼器/// <summary>/// 創建編碼器/// </summary>/// <param name="frameSize">編碼前一幀原始數據的大小</param>/// <param name="isRgb">rgb數據</param>public void CreateEncoder(Size frameSize, bool isRgb = true){_fFmpegEncoder = new FFmpegEncoder(frameSize, isRgb);_fFmpegEncoder.CreateEncoder(DefaultCodecFormat);}/// <summary>/// 編碼/// </summary>/// <param name="frameBytes">編碼幀數據</param>/// <returns></returns>public byte[] EncodeFrames(byte[] frameBytes){return _fFmpegEncoder.EncodeFrames(frameBytes);}/// <summary>/// 釋放編碼器/// </summary>public void DisposeEncoder(){_fFmpegEncoder.Dispose();}#endregion#region 解碼器/// <summary>/// 創建解碼器/// </summary>/// <param name="decodedFrameSize">解碼后數據的大小</param>/// <param name="isRgb">Rgb數據</param>public void CreateDecoder(Size decodedFrameSize, bool isRgb = true){_fFmpegDecoder = new FFmpegDecoder(decodedFrameSize, isRgb);_fFmpegDecoder.CreateDecoder(DefaultCodecFormat);}/// <summary>/// 解碼/// </summary>/// <param name="frameBytes">解碼幀數據</param>/// <returns></returns>public byte[] DecodeFrames(byte[] frameBytes){return _fFmpegDecoder.DecodeFrames(frameBytes);}/// <summary>/// 釋放解碼器/// </summary>public void DisposeDecoder(){_fFmpegDecoder.Dispose();}#endregion/// <summary>編碼器</summary>private FFmpegEncoder _fFmpegEncoder;/// <summary>解碼器</summary>private FFmpegDecoder _fFmpegDecoder;}
}

其它業務類:

using System;
using System.IO;
using System.Runtime.InteropServices;namespace FFmpegAnalyzer
{internal class FFmpegBinariesHelper{private const string LD_LIBRARY_PATH = "LD_LIBRARY_PATH";internal static void RegisterFFmpegBinaries(){switch (Environment.OSVersion.Platform){case PlatformID.Win32NT:case PlatformID.Win32S:case PlatformID.Win32Windows:var current = AppDomain.CurrentDomain.BaseDirectory;var probe = $"FFmpeg/bin/{(Environment.Is64BitProcess ? @"x64" : @"x86")}";while (current != null){var ffmpegDirectory = Path.Combine(current, probe);if (Directory.Exists(ffmpegDirectory)){Console.WriteLine($"FFmpeg binaries found in: {ffmpegDirectory}");RegisterLibrariesSearchPath(ffmpegDirectory);return;}current = Directory.GetParent(current)?.FullName;}break;case PlatformID.Unix:case PlatformID.MacOSX:var libraryPath = Environment.GetEnvironmentVariable(LD_LIBRARY_PATH);RegisterLibrariesSearchPath(libraryPath);break;}}private static void RegisterLibrariesSearchPath(string path){switch (Environment.OSVersion.Platform){case PlatformID.Win32NT:case PlatformID.Win32S:case PlatformID.Win32Windows:SetDllDirectory(path);break;case PlatformID.Unix:case PlatformID.MacOSX:string currentValue = Environment.GetEnvironmentVariable(LD_LIBRARY_PATH);if (string.IsNullOrWhiteSpace(currentValue) == false && currentValue.Contains(path) == false){string newValue = currentValue + Path.PathSeparator + path;Environment.SetEnvironmentVariable(LD_LIBRARY_PATH, newValue);}break;}}[DllImport("kernel32", SetLastError = true)]private static extern bool SetDllDirectory(string lpPathName);}
}
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen;namespace FFmpegAnalyzer
{/// <summary>/// 解碼器/// </summary>internal unsafe class FFmpegDecoder{/// <param name="decodedFrameSize">解碼后數據的大小</param>/// <param name="isRgb">Rgb數據</param>public FFmpegDecoder(Size decodedFrameSize, bool isRgb = true){_decodedFrameSize = decodedFrameSize;_isRgb = isRgb;}/// <summary>/// 創建解碼器/// </summary>/// <param name="codecFormat">解碼格式</param>public void CreateDecoder(AVCodecID codecFormat){var originPixelFormat = AVPixelFormat.AV_PIX_FMT_YUV420P;var destinationPixelFormat = _isRgb ? AVPixelFormat.AV_PIX_FMT_RGB24 : AVPixelFormat.AV_PIX_FMT_BGRA; //獲取解碼器_pDecodec = ffmpeg.avcodec_find_decoder(codecFormat);if (_pDecodec == null) throw new InvalidOperationException("Codec not found.");_pDecodecContext = ffmpeg.avcodec_alloc_context3(_pDecodec);_pDecodecContext->width = _decodedFrameSize.Width;_pDecodecContext->height = _decodedFrameSize.Height;_pDecodecContext->time_base = new AVRational { num = 1, den = 30 };_pDecodecContext->pix_fmt = AVPixelFormat.AV_PIX_FMT_YUV420P;_pDecodecContext->framerate = new AVRational { num = 30, den = 1 };                        _pDecodecContext->gop_size = 30;// 設置預測算法_pDecodecContext->flags |= ffmpeg.AV_CODEC_FLAG_PSNR;_pDecodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST;_pDecodecContext->max_b_frames = 0;ffmpeg.av_opt_set(_pDecodecContext->priv_data, "preset", "veryfast", 0);ffmpeg.av_opt_set(_pDecodecContext->priv_data, "tune", "zerolatency", 0);//打開解碼器ffmpeg.avcodec_open2(_pDecodecContext, _pDecodec, null);_pConvertContext = ffmpeg.sws_getContext(_decodedFrameSize.Width,_decodedFrameSize.Height,originPixelFormat,_decodedFrameSize.Width,_decodedFrameSize.Height,destinationPixelFormat,ffmpeg.SWS_FAST_BILINEAR,null, null, null);if (_pConvertContext == null)throw new ApplicationException("Could not initialize the conversion context.");var convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixelFormat, _decodedFrameSize.Width, _decodedFrameSize.Height, 1);_convertedFrameBufferPtr = Marshal.AllocHGlobal(convertedFrameBufferSize);_dstData = new byte_ptrArray4();_dstLineSize = new int_array4();ffmpeg.av_image_fill_arrays(ref _dstData, ref _dstLineSize, (byte*)_convertedFrameBufferPtr, destinationPixelFormat,_decodedFrameSize.Width, _decodedFrameSize.Height, 1);_isCodecRunning = true;}/// <summary>/// 解碼/// </summary>/// <param name="frameBytes"></param>/// <returns></returns>public  byte[] DecodeFrames(byte[] frameBytes){if (!_isCodecRunning){throw new InvalidOperationException("解碼器未運行!");}var waitDecodePacket = ffmpeg.av_packet_alloc();var waitDecoderFrame = ffmpeg.av_frame_alloc();ffmpeg.av_frame_unref(waitDecoderFrame);fixed (byte* waitDecodeData = frameBytes){waitDecodePacket->data = waitDecodeData;waitDecodePacket->size = frameBytes.Length;ffmpeg.av_frame_unref(waitDecoderFrame);try{int error;do{ffmpeg.avcodec_send_packet(_pDecodecContext, waitDecodePacket);error = ffmpeg.avcodec_receive_frame(_pDecodecContext, waitDecoderFrame);} while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));}finally{ffmpeg.av_packet_unref(waitDecodePacket);}var decodeAfterFrame = ConvertToRgb(waitDecoderFrame);var length = _isRgb? decodeAfterFrame.height * decodeAfterFrame.width * 3: decodeAfterFrame.height * decodeAfterFrame.width * 4;byte[] buffer = new byte[length];Marshal.Copy((IntPtr)decodeAfterFrame.data[0], buffer, 0, buffer.Length);return buffer;}}/// <summary>/// 釋放/// </summary>public  void Dispose(){_isCodecRunning = false;//釋放解碼器ffmpeg.avcodec_close(_pDecodecContext);ffmpeg.av_free(_pDecodecContext);//釋放轉換器Marshal.FreeHGlobal(_convertedFrameBufferPtr);ffmpeg.sws_freeContext(_pConvertContext);}/// <summary>/// 轉換成Rgb/// </summary>/// <param name="waitDecoderFrame"></param>/// <returns></returns>private  AVFrame ConvertToRgb(AVFrame* waitDecoderFrame){ffmpeg.sws_scale(_pConvertContext, waitDecoderFrame->data, waitDecoderFrame->linesize, 0, waitDecoderFrame->height, _dstData, _dstLineSize);var decodeAfterData = new byte_ptrArray8();decodeAfterData.UpdateFrom(_dstData);var lineSize = new int_array8();lineSize.UpdateFrom(_dstLineSize);ffmpeg.av_frame_unref(waitDecoderFrame);return new AVFrame{data = decodeAfterData,linesize = lineSize,width = _decodedFrameSize.Width,height = _decodedFrameSize.Height};}//解碼器private AVCodec* _pDecodec;private AVCodecContext* _pDecodecContext;//轉換緩存區private IntPtr _convertedFrameBufferPtr;private byte_ptrArray4 _dstData;private int_array4 _dstLineSize;//格式轉換private SwsContext* _pConvertContext;private Size _decodedFrameSize;private readonly bool _isRgb;//解碼器正在運行private bool _isCodecRunning;}
}
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using FFmpeg.AutoGen;namespace FFmpegAnalyzer
{/// <summary>/// 編碼器/// </summary>internal unsafe class FFmpegEncoder{/// <param name="frameSize">編碼前一幀原始數據的大小</param>/// <param name="isRgb">rgb數據</param>public FFmpegEncoder(Size frameSize, bool isRgb = true){_frameSize = frameSize;_isRgb = isRgb;_rowPitch = isRgb ? _frameSize.Width * 3 : _frameSize.Width * 4;}/// <summary>/// 創建編碼器/// </summary>public  void CreateEncoder(AVCodecID codecFormat){var originPixelFormat = _isRgb ? AVPixelFormat.AV_PIX_FMT_RGB24 : AVPixelFormat.AV_PIX_FMT_BGRA;var destinationPixelFormat = AVPixelFormat.AV_PIX_FMT_YUV420P;_pCodec = ffmpeg.avcodec_find_encoder(codecFormat);if (_pCodec == null)throw new InvalidOperationException("Codec not found.");_pCodecContext = ffmpeg.avcodec_alloc_context3(_pCodec);_pCodecContext->width = _frameSize.Width;_pCodecContext->height = _frameSize.Height;_pCodecContext->framerate = new AVRational { num = 30, den = 1 };_pCodecContext->time_base = new AVRational {num = 1, den = 30};_pCodecContext->gop_size = 30;_pCodecContext->pix_fmt = destinationPixelFormat;// 設置預測算法_pCodecContext->flags |= ffmpeg.AV_CODEC_FLAG_PSNR;_pCodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST;_pCodecContext->max_b_frames = 0;ffmpeg.av_opt_set(_pCodecContext->priv_data, "preset", "veryfast", 0);ffmpeg.av_opt_set(_pCodecContext->priv_data, "tune", "zerolatency", 0);//打開編碼器ffmpeg.avcodec_open2(_pCodecContext, _pCodec, null);_pConvertContext = ffmpeg.sws_getContext(_frameSize.Width, _frameSize.Height, originPixelFormat, _frameSize.Width, _frameSize.Height, destinationPixelFormat,ffmpeg.SWS_FAST_BILINEAR, null, null, null);if (_pConvertContext == null)throw new ApplicationException("Could not initialize the conversion context.");var convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixelFormat, _frameSize.Width, _frameSize.Height, 1);_convertedFrameBufferPtr = Marshal.AllocHGlobal(convertedFrameBufferSize);_dstData = new byte_ptrArray4();_dstLineSize = new int_array4();ffmpeg.av_image_fill_arrays(ref _dstData, ref _dstLineSize, (byte*)_convertedFrameBufferPtr, destinationPixelFormat, _frameSize.Width, _frameSize.Height, 1);_isCodecRunning = true;}/// <summary>/// 釋放/// </summary>public  void Dispose(){if (!_isCodecRunning) return;_isCodecRunning = false;//釋放編碼器ffmpeg.avcodec_close(_pCodecContext);ffmpeg.av_free(_pCodecContext);//釋放轉換器Marshal.FreeHGlobal(_convertedFrameBufferPtr);ffmpeg.sws_freeContext(_pConvertContext);}/// <summary>/// 編碼/// </summary>/// <param name="frameBytes"></param>/// <returns></returns>public  byte[] EncodeFrames(byte[] frameBytes){if (!_isCodecRunning){throw new InvalidOperationException("編碼器未運行!");}fixed (byte* pBitmapData = frameBytes){var waitToYuvFrame = new AVFrame{data = new byte_ptrArray8 { [0] = pBitmapData },linesize = new int_array8 { [0] = _rowPitch },height = _frameSize.Height};var rgbToYuv = ConvertToYuv(waitToYuvFrame, _frameSize.Width, _frameSize.Height);byte[] buffer;var pPacket = ffmpeg.av_packet_alloc();try{int error;do{ffmpeg.avcodec_send_frame(_pCodecContext, &rgbToYuv);error = ffmpeg.avcodec_receive_packet(_pCodecContext, pPacket);} while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));buffer = new byte[pPacket->size];Marshal.Copy(new IntPtr(pPacket->data), buffer, 0, pPacket->size);}finally{ffmpeg.av_frame_unref(&rgbToYuv);ffmpeg.av_packet_unref(pPacket);}return buffer;}}/// <summary>/// 轉換成Yuv格式/// </summary>/// <param name="waitConvertYuvFrame"></param>/// <param name="width"></param>/// <param name="height"></param>/// <returns></returns>private  AVFrame ConvertToYuv(AVFrame waitConvertYuvFrame, int width, int height){ffmpeg.sws_scale(_pConvertContext, waitConvertYuvFrame.data, waitConvertYuvFrame.linesize, 0, waitConvertYuvFrame.height, _dstData, _dstLineSize);var data = new byte_ptrArray8();data.UpdateFrom(_dstData);var lineSize = new int_array8();lineSize.UpdateFrom(_dstLineSize);ffmpeg.av_frame_unref(&waitConvertYuvFrame);return new AVFrame{data = data,linesize = lineSize,width = width,height = height};}//編碼器private AVCodec* _pCodec;private AVCodecContext* _pCodecContext;//轉換緩存區private IntPtr _convertedFrameBufferPtr;private byte_ptrArray4 _dstData;private int_array4 _dstLineSize;//格式轉換private SwsContext* _pConvertContext;private Size _frameSize;private readonly int _rowPitch;private readonly bool _isRgb;//編碼器正在運行private bool _isCodecRunning;}
}
using FFmpeg.AutoGen;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;namespace FFmpegAnalyzer
{public sealed unsafe class VideoFrameConverter : IDisposable{private readonly IntPtr _convertedFrameBufferPtr;private readonly System.Drawing.Size _destinationSize;private readonly byte_ptrArray4 _dstData;private readonly int_array4 _dstLinesize;private readonly SwsContext* _pConvertContext;/// <summary>/// 幀格式轉換/// </summary>/// <param name="sourceSize"></param>/// <param name="sourcePixelFormat"></param>/// <param name="destinationSize"></param>/// <param name="destinationPixelFormat"></param>public VideoFrameConverter(System.Drawing.Size sourceSize, AVPixelFormat sourcePixelFormat,System.Drawing.Size destinationSize, AVPixelFormat destinationPixelFormat){_destinationSize = destinationSize;//分配并返回一個SwsContext。您需要它使用sws_scale()執行伸縮/轉換操作//主要就是使用SwsContext進行轉換!!!_pConvertContext = ffmpeg.sws_getContext((int)sourceSize.Width, (int)sourceSize.Height, sourcePixelFormat,(int)destinationSize.Width,(int)destinationSize.Height, destinationPixelFormat,ffmpeg.SWS_FAST_BILINEAR //默認算法 還有其他算法, null, null, null //額外參數 在flasgs指定的算法,而使用的參數。如果  SWS_BICUBIC  SWS_GAUSS  SWS_LANCZOS這些算法。  這里沒有使用);if (_pConvertContext == null) throw new ApplicationException("Could not initialize the conversion context.");//獲取媒體幀所需要的大小var convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixelFormat, (int)destinationSize.Width, (int)destinationSize.Height, 1);//申請非托管內存,unsafe代碼_convertedFrameBufferPtr = Marshal.AllocHGlobal(convertedFrameBufferSize);//轉換幀的內存指針_dstData = new byte_ptrArray4();_dstLinesize = new int_array4();//掛在幀數據的內存區把_dstData里存的的指針指向_convertedFrameBufferPtrffmpeg.av_image_fill_arrays(ref _dstData, ref _dstLinesize, (byte*)_convertedFrameBufferPtr, destinationPixelFormat, (int)destinationSize.Width, (int)destinationSize.Height, 1);}public void Dispose(){Marshal.FreeHGlobal(_convertedFrameBufferPtr);ffmpeg.sws_freeContext(_pConvertContext);}public AVFrame Convert(AVFrame sourceFrame){//轉換格式ffmpeg.sws_scale(_pConvertContext, sourceFrame.data, sourceFrame.linesize, 0, sourceFrame.height, _dstData, _dstLinesize);var data = new byte_ptrArray8();data.UpdateFrom(_dstData);var linesize = new int_array8();linesize.UpdateFrom(_dstLinesize);return new AVFrame{data = data,linesize = linesize,width = (int)_destinationSize.Width,height = (int)_destinationSize.Height};}}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using FFmpeg.AutoGen;namespace FFmpegAnalyzer
{public sealed unsafe class VideoStreamDecoder : IDisposable{private readonly AVCodecContext* _pCodecContext;private readonly AVFormatContext* _pFormatContext;private readonly int _streamIndex;//private readonly AVFrame* _pFrame;//private readonly AVFrame* _receivedFrame;private readonly AVPacket* _pPacket;/// <summary>/// 視頻解碼器/// </summary>/// <param name="url">視頻流URL</param>/// <param name="HWDeviceType">硬件解碼器類型(默認AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)</param>public VideoStreamDecoder(string url, AVHWDeviceType HWDeviceType = AVHWDeviceType.AV_HWDEVICE_TYPE_NONE){//分配一個AVFormatContext_pFormatContext = ffmpeg.avformat_alloc_context();//分配一個AVFrame_receivedFrame = ffmpeg.av_frame_alloc();var pFormatContext = _pFormatContext;//將源音視頻流傳遞給ffmpeg即ffmpeg打開源視頻流ffmpeg.avformat_open_input(&pFormatContext, url, null, null);//獲取音視頻流信息ffmpeg.avformat_find_stream_info(_pFormatContext, null);AVCodec* codec = null;//在源里找到最佳的流,如果指定了解碼器,則根據解碼器尋找流,將解碼器傳遞給codec_streamIndex = ffmpeg.av_find_best_stream(_pFormatContext, AVMediaType.AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);//根據解碼器分配一個AVCodecContext ,僅僅分配工具,還沒有初始化。_pCodecContext = ffmpeg.avcodec_alloc_context3(codec);//如果硬解碼if (HWDeviceType != AVHWDeviceType.AV_HWDEVICE_TYPE_NONE){//根據硬件編碼類型創建AVHWDeviceContext,存在AVFormatContext.hw_device_ctx (_pCodecContext->hw_device_ctx)ffmpeg.av_hwdevice_ctx_create(&_pCodecContext->hw_device_ctx, HWDeviceType, null, null, 0);}//將最佳流的格式參數傳遞給codecContextffmpeg.avcodec_parameters_to_context(_pCodecContext, _pFormatContext->streams[_streamIndex]->codecpar);//根據codec初始化pCodecContext 。與_pCodecContext = ffmpeg.avcodec_alloc_context3(codec);對應ffmpeg.avcodec_open2(_pCodecContext, codec, null);CodecName = ffmpeg.avcodec_get_name(codec->id);FrameSize = new System.Drawing.Size(_pCodecContext->width, _pCodecContext->height);PixelFormat = _pCodecContext->pix_fmt;//分配AVPacket/* AVPacket用于存儲壓縮的數據,分別包括有音頻壓縮數據,視頻壓縮數據和字幕壓縮數據。它通常在解復用操作后存儲壓縮數據,然后作為輸入傳給解碼器。或者由編碼器輸出然后傳遞給復用器。對于視頻壓縮數據,一個AVPacket通常包括一個視頻幀。對于音頻壓縮數據,可能包括幾個壓縮的音頻幀。*/_pPacket = ffmpeg.av_packet_alloc();//分配AVFrame/*AVFrame用于存儲解碼后的音頻或者視頻數據。AVFrame必須通過av_frame_alloc進行分配,通過av_frame_free釋放。*/_pFrame = ffmpeg.av_frame_alloc();}public string CodecName { get; }public System.Drawing.Size FrameSize { get; }public AVPixelFormat PixelFormat { get; }public void Dispose(){ffmpeg.av_frame_unref(_pFrame);ffmpeg.av_free(_pFrame);ffmpeg.av_packet_unref(_pPacket);ffmpeg.av_free(_pPacket);ffmpeg.avcodec_close(_pCodecContext);var pFormatContext = _pFormatContext;ffmpeg.avformat_close_input(&pFormatContext);}/// <summary>/// 解碼下一幀幀/// </summary>/// <param name="frame">參數返回解碼后的幀</param>/// <returns></returns>public bool TryDecodeNextFrame(out AVFrame frame){//取消幀的引用。幀將不會被任何資源引用ffmpeg.av_frame_unref(_pFrame);ffmpeg.av_frame_unref(_receivedFrame);int error;do{try{#region 讀取幀忽略無效幀do{//讀取無效幀error = ffmpeg.av_read_frame(_pFormatContext, _pPacket);//根據pFormatContext讀取幀,返回到Packet中if (error == ffmpeg.AVERROR_EOF)//如果已經是影視片流末尾則返回{frame = *_pFrame;return false;}} while (_pPacket->stream_index != _streamIndex); //忽略掉音視頻流里面與有效流(初始化(構造函數)時標記的_streamIndex)不一致的流#endregion//將幀數據放入解碼器ffmpeg.avcodec_send_packet(_pCodecContext, _pPacket);  //將原始數據數據(_pPacket)作為輸入提供給解碼器(_pCodecContext)}finally{//消除對_pPacket的引用ffmpeg.av_packet_unref(_pPacket);}//讀取解碼器里解碼(_pCodecContext)后的幀通過參數返回(_pFrame)error = ffmpeg.avcodec_receive_frame(_pCodecContext, _pFrame);} while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));//當返回值等于 EAGAIN(再試一次),if (_pCodecContext->hw_device_ctx != null)//如果配置了硬件解碼則調用硬件解碼器解碼{//將_pFrame通過硬件解碼后放入_receivedFrameffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0);frame = *_receivedFrame;}else{frame = *_pFrame;}return true;}/// <summary>/// 獲取媒體TAG信息/// </summary>/// <returns></returns>public IReadOnlyDictionary<string, string> GetContextInfo(){AVDictionaryEntry* tag = null;var result = new Dictionary<string, string>();while ((tag = ffmpeg.av_dict_get(_pFormatContext->metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null){var key = Marshal.PtrToStringAnsi((IntPtr)tag->key);var value = Marshal.PtrToStringAnsi((IntPtr)tag->value);result.Add(key, value);}return result;}}
}

需要將ffmpeg的類庫復制到生成目錄上(對應FFmpegBinariesHelper.RegisterFFmpegBinaries()中的生成路徑)

?使用代碼:

FFmpegWrapper.RegisterFFmpeg();
_ffMpegWrapper = new FFmpegWrapper();
_ffMpegWrapper.CreateEncoder(new System.Drawing.Size(1920, 1080), true);_ffMpegWrapper1 = new FFmpegWrapper();
_ffMpegWrapper1.CreateDecoder(new System.Drawing.Size(1920, 1080), true);
var encodeFrames = _ffMpegWrapper.EncodeFrames(Data);
var decodeFrames = _ffMpegWrapper1.DecodeFrames(encodeFrames);

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36099.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36099.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36099.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++11異步與通信之 packaged_task

概念簡介 packaged_task 用于包裝可調用目標(Callable)為一個對象,如lambda&#xff0c;普通函數&#xff0c;小括號重載等&#xff0c;用于異步調用。 其返回值或所拋異常被存儲于能通過 std::future 對象訪問的共享狀態中&#xff0c;和promise類似。 將函數的調用與函數返…

時序預測 | MATLAB實現EEMD-LSTM、LSTM集合經驗模態分解結合長短期記憶神經網絡時間序列預測對比

時序預測 | MATLAB實現EEMD-LSTM、LSTM集合經驗模態分解結合長短期記憶神經網絡時間序列預測對比 目錄 時序預測 | MATLAB實現EEMD-LSTM、LSTM集合經驗模態分解結合長短期記憶神經網絡時間序列預測對比效果一覽基本介紹模型搭建程序設計參考資料 效果一覽 基本介紹 時序預測 | …

小龜帶你妙寫排序之快速排序

快速排序 一. 快速排序原理二. 題目三. 快速排序的思路分析&#xff08;圖文結合&#xff09;四.代碼 一. 快速排序原理 先從數據序列中選一個元素&#xff0c;并將序列中所有比該元素小的元素都放到它的右邊或左邊&#xff0c;再對左右兩邊分別用同樣的方法處之直到每一個待處…

runtime error: member access within misaligned address(力扣最常見錯誤之一)

runtime error: member access within misaligned address&#xff08;力扣最常見錯誤之一&#xff09; 前言原因和解決辦法總結 前言 最近博主在刷力扣時&#xff0c;明明代碼邏輯都沒問題&#xff0c;但總是報下面這個錯誤&#xff1a; runtime error: member access within…

django實現登錄和登錄的鑒權

1、創建數據庫的管理員表 在models.py 中定義admin表&#xff0c;為了簡單&#xff0c;表里只有用戶名和密碼還有默認加的id 三個字段 from django.db import models# Create your models here.class Admin(models.Model):username models.CharField(verbose_name"用戶…

源碼框架-三勾軟件

javaspringboot微信小程序商城SAAS前后端源碼: 三勾商城是開發友好的微信小程序商城&#xff0c;框架支持SAAS&#xff0c;支持發布 iOS Android 公眾號 H5 各種小程序&#xff08;微信/支付寶/百度/頭條/QQ/釘釘/淘寶&#xff09;等多個平臺&#xff0c;不可多得的二開神器…

訓練用于序列分類任務的 RoBERTa 模型的適配器

介紹 NLP當前的趨勢包括下載和微調具有數百萬甚至數十億參數的預訓練模型。然而,存儲和共享如此大的訓練模型非常耗時、緩慢且昂貴。這些限制阻礙了 RoBERTa 模型開發更多用途和適應性更強的 NLP 技術,該模型可以從多個任務中學習并針對多個任務進行學習;在本文中,我們將重…

Kafka:安裝和配置

producer&#xff1a;發布消息的對象&#xff0c;稱為消息產生者 &#xff08;Kafka topic producer&#xff09; topic&#xff1a;Kafka將消息分門別類&#xff0c;每一個消息稱為一個主題&#xff08;topic&#xff09; consumer&#xff1a;訂閱消息并處理發布消息的對象…

模擬 枚舉

分享牛客算法基礎精選題單題目打卡!!! 目錄 字符串的展開 多項式輸出 機器翻譯 : 鋪地毯 : [NOIP2016]回文日期 字符串的展開 原題鏈接 : 字符串的展開 思路 : 模擬 代碼 : #include<iostream> #include<cstring> #include<algorithm> using na…

Java課題筆記~ ServletContext

單個Servlet的配置對象 web.xml <servlet><servlet-name>FirstServlet</servlet-name><servlet-class>com.ambow.test.FirstServlet</servlet-class><init-param><param-name>charset</param-name><param-value>utf-8&…

centos自動同步北京時間

1、安裝ntpdate服務 yum -y install ntpdate 2、加入自動任務計劃 查找ntpdate的路徑&#xff1a; which ntpdate 復制這個路徑。 編輯自動任務計劃并加入ntpdate&#xff1a; crontab -e # 每小時第30分鐘同步AD域控時間 30 * * * * /usr/sbin/ntpdate -u 192.168.2.8 > …

DP——動態規劃

DP——動態規劃 動態規劃算法動態規劃的一般步驟特殊DP——背包0-1背包問題完全背包問題 總結 動態規劃算法 當涉及到解決具有重疊子問題的優化問題時&#xff0c;動態規劃是一種常用的算法技術。它通過將問題分解為一系列重疊子問題&#xff0c;并使用遞歸或迭代的方式來解決…

Spring Cloud Gateway系例—GatewayFilter 工廠

目錄 6.1.AddRequestHeader 6.2.AddRequestHeadersIfNotPresent 6.3.AddRequestParameter 6.4.AddResponseHeader 6.5.CircuitBreaker 6.5.1. 熔斷指定的狀態碼 6.6.CacheRequestBody 6.7.DedupeResponseHeader 6.8.FallbackHeaders 6.9.JsonToGrpc 6.10.LocalRespo…

TypeScript 非空斷言

TypeScript 非空斷言 發布于 2020-04-08 15:20:15 17.5K0 舉報 一、非空斷言有啥用 介紹非空斷言前&#xff0c;先來看個示例&#xff1a; function sayHello(name: string | undefined) {let sname: string name; // Error } 對于以上代碼&#xff0c;TypeScript 編譯器…

用戶端Web自動化測試-L1

目錄&#xff1a; Web自動化測試價值與體系環境安裝與使用自動化用例錄制自動化測試用例結構分析web瀏覽器控制常見控件定位方法強制等待與隱式等待常見控件交互方法自動化測試定位策略搜索功能自動化測試用戶端Web自動化測試 1.Web自動化測試價值與體系 功能測試場景: UI 自…

IntelliJ Idea 編譯時控制臺上中文輸出亂碼

猜測原因是IDEA啟動時未指定編碼信息&#xff0c;故與系統編碼保持一致&#xff08;windows中文系統默認為GBK編碼&#xff09;,當以UTF-8編碼進行編譯在控制臺會以GBK編碼輸出,從而導致亂碼 解決方案 指定Idea啟動時JVM的默認編碼為UTF-8 Help -> Edit Custom Options P…

本地圖片的image加密解密-Python 3.10-win10

本地圖片的image加密解密- Python 3.10 pyt3int22 -根據1zip下圖片批量生成加密的-物體識別.py import ioimport os import base64 import json # 指定圖片文件夾 image_dir = "./1zip/" base64code_dir = "./base64code/" base64_to_dir = "./bas…

AUTOSAR規范與ECU軟件開發(基礎篇)2.5 AUTOSAR方法論

前言 AUTOSAR方法論(AUTOSAR Methodology) 中車用控制器軟件的開發涉及系統級、 ECU級和軟件組件級。 系統級主要考慮系統功能需求、 硬件資源、 系統約束, 然后建立系統架構; ECU級根據抽象后的信息對ECU進行配置; 系統級和ECU級設計的同時, 伴隨著軟件組件級的開發。 上…

Sql server還原失敗(數據庫正在使用,無法獲得對數據庫的獨占訪問權)

一.Sql server還原失敗(數據庫正在使用,無法獲得對數據庫的獨占訪問權) 本次測試使用數據庫實例SqlServer2008r2版 錯誤詳細&#xff1a; 標題: Microsoft SQL Server Management Studio ------------------------------ 還原數據庫“Mvc_HNHZ”時失敗。 (Microsoft.SqlServer.…

《甲午》觀后感——GPT-3.5所寫

《甲午》是一部令人深思的紀錄片&#xff0c;通過生動的畫面和真實的故事&#xff0c;向觀眾展示了中國歷史上的一段重要時期。觀看這部紀錄片&#xff0c;我深受觸動&#xff0c;對歷史的認識也得到了深化。 首先&#xff0c;這部紀錄片通過精心搜集的歷史資料和珍貴的影像資料…