C#开发FFMPEG例子(API方式) FFmpeg推送udp组播流

代码及工程见https://download.csdn.net/download/daqinzl/88156926

开发工具:visual studio 2019

播放,可采用ffmpeg工具集里的ffplay.exe, 执行命令 ffplay udp://238.1.1.10:6016

也可以参考(C#开发FFMPEG例子(API方式) FFmpeg拉取udp组播流并播放) https://blog.csdn.net/daqinzl/article/details/132112075

网上用C/C++调用FFmpeg的API例子很多,

c#使用ffmpeg.autogen的方式很简单,直接复制C/C++调用FFmpeg的API的代码到C#中,然后在FFmpeg的方法前加上ffmpeg.即可。

C/C++调用FFmpeg的API推送udp组播流的例子可以参考:https://blog.csdn.net/daqinzl/article/details/132080204

主要参考文档(C#开发FFMPEG例子(API方式) FFmpeg拉取RTMP流并播放):https://blog.csdn.net/vanjoge/article/details/79657874

参考文档实现了拉取rtmp流并播放,本文在参考文档提供的源码的基础上,结合C/C++调用FFmpeg的API的例子,做了一些修改,用C#使用ffmpeg.autogen实现推送udp组播流。

主要代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using System.Windows.Forms;

using FFmpeg.AutoGen;

namespace FFmpegDemo

{

static unsafe class Program

{

/// <summary>

/// 应用程序的主入口点。

/// </summary>

[STAThread]

static void Main()

{

//Application.EnableVisualStyles();

//Application.SetCompatibleTextRenderingDefault(false);

//Application.Run(new frmPlayer());

//FFmpegDLL目录查找和设置

FFmpegBinariesHelper.RegisterFFmpegBinaries();

ffmpeg.av_register_all();

ffmpeg.avdevice_register_all();

ffmpeg.avcodec_register_all();

ffmpeg.avformat_network_init();

AVFormatContext* m_fmt_ctx = null;

AVInputFormat* m_input_fmt = null;

int video_stream = -1;

//ffmpeg.avcodec_register_all();

string deviceName = "desktop";

string inputformat = "gdigrab";

int FPS = 23; //15

m_fmt_ctx = ffmpeg.avformat_alloc_context();

m_input_fmt = ffmpeg.av_find_input_format(inputformat);

AVDictionary* deoptions = null;

ffmpeg.av_dict_set_int(&deoptions, "framerate", FPS, ffmpeg.AV_DICT_MATCH_CASE);

ffmpeg.av_dict_set_int(&deoptions, "rtbufsize", 3041280 * 100 * 5, 0);

//如果不设置的话,在输入源是直播流的时候,会花屏。单位bytes

//av_dict_set(&deoptions, "buffer_size", "10485760", 0);

//av_dict_set(&deoptions, "reuse", "1", 0);

int ret = ffmpeg.avformat_open_input(&m_fmt_ctx, deviceName, m_input_fmt, &deoptions);

if (ret != 0)

{

return;

}

ffmpeg.av_dict_free(&deoptions);

ret = ffmpeg.avformat_find_stream_info(m_fmt_ctx, null);

if (ret < 0)

{

return;

}

ffmpeg.av_dump_format(m_fmt_ctx, 0, deviceName, 0);

video_stream = ffmpeg.av_find_best_stream(m_fmt_ctx, 0, -1, -1, null, 0); //AVMEDIA_TYPE_VIDEO

if (video_stream < 0)

{

return;

}

AVCodecContext* _codec_ctx = m_fmt_ctx->streams[video_stream]->codec;

AVCodec* _codec = ffmpeg.avcodec_find_decoder(_codec_ctx->codec_id);

if (_codec == null)

{

return;

}

ret = ffmpeg.avcodec_open2(_codec_ctx, _codec, null);

if (ret != 0)

{

return;

}

int width = m_fmt_ctx->streams[video_stream]->codec->width;

int height = m_fmt_ctx->streams[video_stream]->codec->height;

int fps = m_fmt_ctx->streams[video_stream]->codec->framerate.num > 0 ? m_fmt_ctx->streams[video_stream]->codec->framerate.num : 25;

AVPixelFormat videoType = m_fmt_ctx->streams[video_stream]->codec->pix_fmt;

//std::cout << "avstream timebase : " << m_fmt_ctx->streams[video_stream]->time_base.num << " / " << m_fmt_ctx->streams[video_stream]->time_base.den << endl;

Console.WriteLine("avstream timebase : " + m_fmt_ctx->streams[video_stream]->time_base.num + " / " + m_fmt_ctx->streams[video_stream]->time_base.den);

AVDictionary* enoptions = null;

//av_dict_set(&enoptions, "preset", "superfast", 0);

//av_dict_set(&enoptions, "tune", "zerolatency", 0);

ffmpeg.av_dict_set(&enoptions, "preset", "ultrafast", 0);

ffmpeg.av_dict_set(&enoptions, "tune", "zerolatency", 0);

//TODO

//av_dict_set(&enoptions, "pkt_size", "1316", 0); //Maximum UDP packet size

av_dict_set(&dic, "fifo_size", "18800", 0);

av_dict_set(&enoptions, "buffer_size", "0", 1);

av_dict_set(&dic, "bitrate", "11000000", 0);

av_dict_set(&dic, "buffer_size", "1000000", 0);//1316

//av_dict_set(&enoptions, "reuse", "1", 0);

AVCodec* codec = ffmpeg.avcodec_find_encoder(AVCodecID.AV_CODEC_ID_H264);

if (codec == null)

{

Console.WriteLine( "avcodec_find_encoder failed!" );

return;

}

AVCodecContext* vc = ffmpeg.avcodec_alloc_context3(codec);

if (vc == null)

{

Console.WriteLine("avcodec_alloc_context3 failed!" );

return;

}

Console.WriteLine("avcodec_alloc_context3 success!" );// FFmpeg.AutoGen.

vc->flags |= (1 << 22); //AV_CODEC_FLAG_GLOBAL_HEADER

vc->codec_id = AVCodecID.AV_CODEC_ID_H264;

vc->codec_type = FFmpeg.AutoGen.AVMediaType.AVMEDIA_TYPE_VIDEO;

vc->pix_fmt = AVPixelFormat.AV_PIX_FMT_YUV420P;

vc->width = width;

vc->height = height;

vc->time_base.num = 1;

vc->time_base.den = FPS;

//vc->framerate = { FPS,1 };

//TODO

vc->framerate.num = 1;

vc->framerate.den = FPS;

vc->bit_rate = 10241000;

vc->gop_size = 120;

vc->qmin = 10;

vc->qmax = 51;

vc->max_b_frames = 0;

vc->profile = ffmpeg.FF_PROFILE_H264_MAIN;

ret = ffmpeg.avcodec_open2(vc, codec, &enoptions);

if (ret != 0)

{

return;

}

Console.WriteLine( "avcodec_open2 success!" );

ffmpeg.av_dict_free(&enoptions);

SwsContext* vsc = null;

vsc = ffmpeg.sws_getCachedContext(vsc,

width, height, (AVPixelFormat)videoType, //源宽、高、像素格式

width, height, AVPixelFormat.AV_PIX_FMT_YUV420P,//目标宽、高、像素格式

ffmpeg.SWS_BICUBIC, // 尺寸变化使用算法

null, null, null

);

if (vsc==null)

{

Console.WriteLine("sws_getCachedContext failed!");

return;

}

AVFrame* yuv = ffmpeg.av_frame_alloc();

yuv->format = (int)AVPixelFormat.AV_PIX_FMT_YUV420P;

yuv->width = width;

yuv->height = height;

yuv->pts = 0;

ret = ffmpeg.av_frame_get_buffer(yuv, 32);

if (ret != 0)

{

return;

}

//string rtmpurl = "rtmp://192.168.0.105:1935/live/desktop";

string rtmpurl = "udp://224.1.1.1:5001";

AVFormatContext* ic = null;

//ret = ffmpeg.avformat_alloc_output_context2(&ic, null, "flv", rtmpurl);

ret = ffmpeg.avformat_alloc_output_context2(&ic, null, "mpegts", rtmpurl);//UDP

if (ret < 0)

{

return;

}

AVStream* st = ffmpeg.avformat_new_stream(ic, null);

if (st == null)

{

return;

}

st->codecpar->codec_tag = 0;

ffmpeg.avcodec_parameters_from_context(st->codecpar, vc);

ffmpeg.av_dump_format(ic, 0, rtmpurl, 1);

ret = ffmpeg.avio_open(&ic->pb, rtmpurl, ffmpeg.AVIO_FLAG_WRITE);

if (ret != 0)

{

return;

}

ret = ffmpeg.avformat_write_header(ic, null);

if (ret != 0)

{

return;

}

AVPacket* packet = ffmpeg.av_packet_alloc();

AVPacket* Encodepacket = ffmpeg.av_packet_alloc();

int frameIndex = 0;

int EncodeIndex = 0;

AVFrame* rgb = ffmpeg.av_frame_alloc();

AVBitStreamFilterContext* h264bsfc = ffmpeg.av_bitstream_filter_init("h264_mp4toannexb");

long startpts = m_fmt_ctx->start_time;

long lastpts = 0;

AVRational bq = new AVRational(); bq.num = 1; bq.den = FPS;

AVRational cq = new AVRational(); cq.num = 1; cq.den = ffmpeg.AV_TIME_BASE;

long duration = ffmpeg.av_rescale_q(1, bq, cq);

int got_picture = 0;

while (frameIndex < 2000000)

{

ret = ffmpeg.av_read_frame(m_fmt_ctx, packet);

if (ret < 0)

{

break;

}

if (packet->stream_index == video_stream)

{

ret = ffmpeg.avcodec_decode_video2(_codec_ctx, rgb, &got_picture, packet);

if (ret < 0)

{

Console.WriteLine("Decode Error.\n");

return;

}

if (got_picture != null)

{

int h = ffmpeg.sws_scale(vsc, rgb->data, rgb->linesize, 0, height, //源数据

yuv->data, yuv->linesize);

long guesspts = frameIndex * duration;

yuv->pts = guesspts;

frameIndex++;

ret = ffmpeg.avcodec_encode_video2(vc, Encodepacket, yuv, &got_picture);

if (ret < 0)

{

Console.WriteLine("Failed to encode!\n");

break;

}

if (got_picture == 1)

{

Encodepacket->pts = ffmpeg.av_rescale_q(EncodeIndex, vc->time_base, st->time_base);

Encodepacket->dts = Encodepacket->pts;

//std::cout << "frameindex : " << EncodeIndex << " pts : " << Encodepacket->pts << " dts: " << Encodepacket->dts << " encodeSize:" << Encodepacket->size << " curtime - lasttime " << Encodepacket->pts - lastpts << endl;

Console.WriteLine("frameindex : " + EncodeIndex.ToString() + " pts : " + Encodepacket->pts.ToString() + " dts: " + Encodepacket->dts.ToString() + " encodeSize:" + Encodepacket->size.ToString() + " curtime - lasttime " + (Encodepacket->pts - lastpts).ToString());

lastpts = Encodepacket->pts;

ret = ffmpeg.av_interleaved_write_frame(ic, Encodepacket);

EncodeIndex++;

ffmpeg.av_packet_unref(Encodepacket);

}

}

}

ffmpeg.av_packet_unref(packet);

}

ret = ffmpeg.avcodec_send_frame(vc, null);

while (ret >= 0)

{

ret = ffmpeg.avcodec_receive_packet(vc, Encodepacket);

if (ret == ffmpeg.AVERROR(ffmpeg.EAGAIN) || ret == ffmpeg.AVERROR_EOF)

{

break;

}

if (ret < 0)

{

break;

}

ret = ffmpeg.av_interleaved_write_frame(ic, Encodepacket);

EncodeIndex++;

}

ffmpeg.av_write_trailer(ic);

ffmpeg.av_packet_free(&packet);

ffmpeg.av_packet_free(&Encodepacket);

ffmpeg.av_frame_free(&rgb);

ffmpeg.av_frame_free(&yuv);

ffmpeg.av_bitstream_filter_close(h264bsfc);

h264bsfc = null;

if (vsc != null)

{

ffmpeg.sws_freeContext(vsc);

vsc = null;

}

if (_codec_ctx != null)

ffmpeg.avcodec_close(_codec_ctx);

_codec_ctx = null;

_codec = null;

if (vc != null)

ffmpeg.avcodec_free_context(&vc);

if (m_fmt_ctx != null)

ffmpeg.avformat_close_input(&m_fmt_ctx);

if (ic!=null && (ic->flags & ffmpeg.AVFMT_NOFILE)==0)

ffmpeg.avio_closep(&ic->pb);

if (ic != null)

{

ffmpeg.avformat_free_context(ic);

ic = null;

}

m_input_fmt = null;

return;

}

}

}

相关推荐
小板凳-BGM2 小时前
C# 第二阶段 modbus
开发语言·ui·c#
黄金小码农3 小时前
c# 2024/12/25 周三
开发语言·c#
geovindu3 小时前
CSharp: Oracle Stored Procedure query table
数据库·oracle·c#·.net
yngsqq4 小时前
cad c# 二次开发 ——动态加载dll 文件制作(loada netloadx)
c#
吾与谁归in8 小时前
【C#联合halcon实现绘制ROI功能】
c#·halcon·roi
ling1s8 小时前
C#核心(18)面向对象多态vob
java·开发语言·c#
月巴月巴白勺合鸟月半10 小时前
一个C#开发的APP
c#·web
我曾经是个程序员10 小时前
C#File文件基础操作大全
开发语言·c#
三天不学习11 小时前
C# 中的记录类型简介 【代码之美系列】
后端·c#·微软技术·record·记录类型