C#利用ffmpeg借助NVIDIA GPU实现实时RTSP硬解码+硬编码录制MP4

目录

说明

效果

项目

代码

下载


说明

利用周杰的开源项目 Sdcb.FFmpeg

项目地址:https://github.com/sdcb/Sdcb.FFmpeg/

代码实现参考:https://github.com/sdcb/ffmpeg-muxing-video-demo

效果

C#利用ffmpeg借助NVIDIA GPU实现实时RTSP硬解码+硬编码录制MP4

项目

代码

using Sdcb.FFmpeg.Codecs;

using Sdcb.FFmpeg.Formats;

using Sdcb.FFmpeg.Raw;

using Sdcb.FFmpeg.Toolboxs.Extensions;

using System;

using System.Linq;

using System.Threading;

using System.Threading.Tasks;

using System.Windows.Forms;

namespace Sdcb.FFmpegDemo

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

CancellationTokenSource cts;

/// <summary>

/// 播放

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void button1_Click(object sender, EventArgs e)

{

button1.Enabled = false;

button2.Enabled = true;

cts = new CancellationTokenSource();

string rtsp_url = txtURL.Text;

//输出视频文件的名称。

string outputFile = "output.mp4";

Task.Run(() => Recording(rtsp_url, outputFile, cts.Token));

}

void Recording(string url, string outputFile, CancellationToken cancellationToken)

{

//输出视频的帧率,帧率设置为每秒25帧

AVRational frameRate = new AVRational(25, 1);

//输出视频的比特率。

long bitRate = 16 * 1024 * 1024; // 16M

//从文件夹读取

//该字符串指定了源图像的文件夹和命名模式。%03d部分表示图像以三位数字命名(例如,001.jpg,002.jpg等)。

//string sourceFolder = @".\src\%03d.jpg";

//FormatContext srcFc = FormatContext.OpenInputUrl(sourceFolder, options: new MediaDictionary

//{

// ["framerate"] = frameRate.ToString()

//});

FormatContext srcFc = FormatContext.OpenInputUrl(url);

srcFc.LoadStreamInfo();

MediaStream srcVideo = srcFc.GetVideoStream();

CodecParameters srcCodecParameters = srcVideo.Codecpar;

CodecContext videoDecoder = new CodecContext(Codec.FindDecoderByName("h264_cuvid"));

{

};

videoDecoder.FillParameters(srcCodecParameters);

videoDecoder.Open();

//var d= Codec.FindDecoders(AVCodecID.H264).Select(x => x.Name);

//var e = Codec.FindEncoders(AVCodecID.H264).Select(x => x.Name);

FormatContext dstFc = FormatContext.AllocOutput(OutputFormat.Guess("mp4"));

dstFc.VideoCodec = Codec.FindEncoderByName("h264_nvenc");

MediaStream vstream = dstFc.NewStream(dstFc.VideoCodec);

CodecContext vcodec = new CodecContext(dstFc.VideoCodec)

{

Width = srcCodecParameters.Width,

Height = srcCodecParameters.Height,

TimeBase = frameRate.Inverse(),

PixelFormat = AVPixelFormat.Yuv420p,

Flags = AV_CODEC_FLAG.GlobalHeader,

BitRate = bitRate,

};

vcodec.Open(dstFc.VideoCodec);

vstream.Codecpar.CopyFrom(vcodec);

vstream.TimeBase = vcodec.TimeBase;

IOContext io = IOContext.OpenWrite(outputFile);

dstFc.Pb = io;

dstFc.WriteHeader();

// src -- srcFc.ReadPackets() -->

// src Packet -- DecodePackets(videoDecoder) -->

// src Frame -- ConvertFrames(vcodec) -->

// dst Frame -- EncodeFrames(vcodec) -->

// dst Packet -- dstFc.InterleavedWritePacket -->

// dst

foreach (Packet packet in srcFc

.ReadPackets().Where(x => x.StreamIndex == srcVideo.Index)

.DecodePackets(videoDecoder)

.ConvertFrames(vcodec)

.EncodeFrames(vcodec)

)

{

try

{

packet.RescaleTimestamp(vcodec.TimeBase, vstream.TimeBase);

packet.StreamIndex = vstream.Index;

dstFc.InterleavedWritePacket(packet);

if (cancellationToken.IsCancellationRequested) break;

}

finally

{

packet.Unref();

}

}

dstFc.WriteTrailer();

io.Dispose();

vcodec.Dispose();

dstFc.Dispose();

videoDecoder.Dispose();

srcFc.Dispose();

}

/// <summary>

/// 停止

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void button2_Click(object sender, EventArgs e)

{

button2.Enabled = false;

button1.Enabled = true;

cts.Cancel();

}

private void Form1_Load(object sender, EventArgs e)

{

button2.Enabled = false;

button1.Enabled = true;

Sdcb.FFmpeg.Utils.FFmpegLogger.LogWriter = (level, msg) => Console.WriteLine(msg);

}

}

}

复制代码
using Sdcb.FFmpeg.Codecs;
using Sdcb.FFmpeg.Formats;
using Sdcb.FFmpeg.Raw;
using Sdcb.FFmpeg.Toolboxs.Extensions;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Sdcb.FFmpegDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        CancellationTokenSource cts;

        /// <summary>
        /// 播放
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            button2.Enabled = true;
            cts = new CancellationTokenSource();
            string rtsp_url = txtURL.Text;
            //输出视频文件的名称。
            string outputFile = "output.mp4";
            Task.Run(() => Recording(rtsp_url, outputFile, cts.Token));
        }

        void Recording(string url, string outputFile, CancellationToken cancellationToken)
        {
            //输出视频的帧率,帧率设置为每秒25帧
            AVRational frameRate = new AVRational(25, 1);
            
            //输出视频的比特率。
            long bitRate = 16 * 1024 * 1024; // 16M

            //从文件夹读取
            //该字符串指定了源图像的文件夹和命名模式。%03d部分表示图像以三位数字命名(例如,001.jpg,002.jpg等)。
            //string sourceFolder = @".\src\%03d.jpg";
            //FormatContext srcFc = FormatContext.OpenInputUrl(sourceFolder, options: new MediaDictionary
            //{
            //    ["framerate"] = frameRate.ToString()
            //});

            FormatContext srcFc = FormatContext.OpenInputUrl(url);
            srcFc.LoadStreamInfo();
            MediaStream srcVideo = srcFc.GetVideoStream();
            CodecParameters srcCodecParameters = srcVideo.Codecpar;

            CodecContext videoDecoder = new CodecContext(Codec.FindDecoderByName("h264_cuvid"));
            {
            };
            videoDecoder.FillParameters(srcCodecParameters);
            videoDecoder.Open();

            //var d=  Codec.FindDecoders(AVCodecID.H264).Select(x => x.Name);
            //var e = Codec.FindEncoders(AVCodecID.H264).Select(x => x.Name);

            FormatContext dstFc = FormatContext.AllocOutput(OutputFormat.Guess("mp4"));

            dstFc.VideoCodec = Codec.FindEncoderByName("h264_nvenc");
            MediaStream vstream = dstFc.NewStream(dstFc.VideoCodec);

            CodecContext vcodec = new CodecContext(dstFc.VideoCodec)
            {
                Width = srcCodecParameters.Width,
                Height = srcCodecParameters.Height,
                TimeBase = frameRate.Inverse(),
                PixelFormat = AVPixelFormat.Yuv420p,
                Flags = AV_CODEC_FLAG.GlobalHeader,
                BitRate = bitRate,
            };
            vcodec.Open(dstFc.VideoCodec);
            vstream.Codecpar.CopyFrom(vcodec);
            vstream.TimeBase = vcodec.TimeBase;

            IOContext io = IOContext.OpenWrite(outputFile);
            dstFc.Pb = io;
            dstFc.WriteHeader();

            // src        -- srcFc.ReadPackets()          -->
            // src Packet -- DecodePackets(videoDecoder)  -->
            // src Frame  -- ConvertFrames(vcodec)        -->
            // dst Frame  -- EncodeFrames(vcodec)         -->
            // dst Packet -- dstFc.InterleavedWritePacket -->
            // dst

            foreach (Packet packet in srcFc
                .ReadPackets().Where(x => x.StreamIndex == srcVideo.Index)
                .DecodePackets(videoDecoder)
                .ConvertFrames(vcodec)
                .EncodeFrames(vcodec)
                )
            {
                try
                {
                    packet.RescaleTimestamp(vcodec.TimeBase, vstream.TimeBase);
                    packet.StreamIndex = vstream.Index;
                    dstFc.InterleavedWritePacket(packet);

                    if (cancellationToken.IsCancellationRequested) break;
                }
                finally
                {
                    packet.Unref();
                }
            }
            dstFc.WriteTrailer();

            io.Dispose();
            vcodec.Dispose();
            dstFc.Dispose();
            videoDecoder.Dispose();
            srcFc.Dispose();

        }

        /// <summary>
        /// 停止
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            button2.Enabled = false;
            button1.Enabled = true;
            cts.Cancel();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button2.Enabled = false;
            button1.Enabled = true;
            Sdcb.FFmpeg.Utils.FFmpegLogger.LogWriter = (level, msg) => Console.WriteLine(msg);
        }
    }

}

下载

源码下载

相关推荐
小虎卫远程打卡app7 小时前
视频编解码学习十二之Android疑点
学习·视频编解码
慢一点会很快17 小时前
【FFmpeg】介绍+安装+VisualStudio配置FFMpeg库
ide·ffmpeg·visual studio
DogDaoDao1 天前
视频图像压缩领域中 DCT 的 DC 系数和 AC 系数详解
图像处理·音视频·视频编解码·dct·图像压缩·变换编码·离散余弦变换
AnalogElectronic2 天前
文件名是 ‪E:\20250512_191204.mp4, EV软件录屏,未保存直接关机损坏, 如何修复?
视频编解码
邪恶的贝利亚2 天前
《ffplay 读线程与解码线程分析:从初始化到 seek 操作,对比视频与音频解码的差异》
ffmpeg·php·音视频
小虎卫远程打卡app2 天前
视频编解码学习十一之视频原始数据
学习·视频编解码
路溪非溪3 天前
关于ffmpeg的简介和使用总结
ffmpeg
gushansanren3 天前
基于WSL用MSVC编译ffmpeg7.1
windows·ffmpeg
小虎卫远程打卡app3 天前
视频编解码学习10之成像技术原理
学习·计算机视觉·视频编解码
路baby4 天前
2025第九届御网杯网络安全大赛线上赛 区域赛WP (MISC和Crypto)(详解-思路-脚本)
安全·web安全·网络安全·视频编解码·misc·crypto·御网杯