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);
        }
    }

}

下载

源码下载

相关推荐
要开心吖ZSH4 小时前
MP4 转 WAV 音频转码方案详解(ProcessBuilder + FFmpeg)
java·ffmpeg·音视频
要开心吖ZSH6 小时前
MP4 转 WAV 音频转码方案详解(互联网医院病历AI实战-JAVE2方案)
java·ffmpeg
火山上的企鹅2 天前
QGC二次开发本地媒体浏览实战(二)FFmpeg最小系统实战
qt·ffmpeg·媒体·qgc
王江奎3 天前
FFmpeg 中编译和使用 soxr 重采样引擎
ffmpeg·音视频
优选资源分享3 天前
小丸工具箱 vR236|ffmpeg 图形化视频压制工具
ffmpeg·音视频
coding_fei4 天前
将FFmpeg集成到aosp
ffmpeg
小虎卫远程打卡app4 天前
光通信与视频编码前沿技术综述:从超大容量传输到实时神经网络编码
运维·网络·信息与通信·视频编解码
狄林可4 天前
从付费软件到自主开发:我用AI和FFmpeg实现了一个录屏工具
人工智能·ffmpeg
没有余地 EliasJie5 天前
FFmpeg介绍与ESP32资源受限下的视频流传输优化策略
单片机·物联网·ffmpeg
不想看见4045 天前
Qt+FFmpeg 极简播放器示例【音视频方向简单讲解】
qt·ffmpeg·音视频