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;

        }
    }
}
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24155.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【雕爷学编程】Arduino动手做(186)---WeMos ESP32开发板9

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

Flutter游戏引擎Flame系列笔记 - 1.Flame引擎概述

Flutter游戏引擎Flame系列笔记 1.Flame引擎概述 - 文章信息 - Author: 李俊才(jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132119035 【介绍】…

03.利用Redis实现缓存功能---解决缓存穿透版

学习目标&#xff1a; 提示&#xff1a;学习如何利用Redis实现添加缓存功能解决缓存穿透版 学习产出&#xff1a; 缓存穿透讲解图&#xff1a; 解决方案&#xff1a; 采用缓存空对象采用布隆过滤器 解决方案流程图&#xff1a; 1. 准备pom环境 <dependency><gro…

MapReduce基础原理、MR与MPP区别

MapReduce概述 MapReduce&#xff08;MR&#xff09;本质上是一种用于数据处理的编程模型&#xff1b;MapReduce用于海量数据的计算&#xff0c;HDFS用于海量数据的存储&#xff08;Hadoop Distributed File System&#xff0c;Hadoop分布式文件系统&#xff09;。Hadoop MapR…

uniapp:图片验证码检验问题处理

图形验证码功能实现 uniapp&#xff1a;解决图形验证码问题及利用arraybuffer二进制转base64格式图片&#xff08;后端传的图片数据形式&#xff1a;x00\x10JFIF\x00\x01\x02\x00…&#xff09;_❆VE❆的博客-CSDN博客 UI稿&#xff1a; 需求&#xff1a;向后端请求验证码图片&…

arcgis--网络分析(理论篇)

1、定义概念 &#xff08;1&#xff09;网络&#xff1a;由一系列相互联通的点和线组成&#xff0c;用来描述地理要素&#xff08;资源&#xff09;的流动情况。 &#xff08;2&#xff09;网络分析&#xff1a;对地理网络&#xff08;如交通网络、水系网络&#xff09;&…

RTT(RT-Thread)时钟管理

目录 时钟管理 时钟节拍 RTT工程目录结构介绍 配置文件&#xff1a;rtconfig.h 获取系统节拍 获取系统节拍数函数 实例 定时器 RT_Thread定时器介绍 定时器源码分析&#xff08;了解即可&#xff09; rt_system_timer_init (硬件定时器初始化) rt_system_timer_thr…

安全防护,保障企业图文档安全的有效方法

随着企业现在数据量的不断增加和数据泄露事件的频发&#xff0c;图文档的安全性成为了企业必须高度关注的问题。传统的纸质文件存储方式已不适应现代企业的需求&#xff0c;而在线图文档管理成为了更加安全可靠的数字化解决方案。那么在在线图文档管理中&#xff0c;如何采取有…

RW-Everything的RwDrv.sys驱动调用

RW-Everything的RwDrv.sys驱动调用 一、RwDrv.sys二、示例代码三、总结 一、RwDrv.sys RW-Everything是一个硬件底层的工具&#xff0c;可用于物理内存、BIOS、PCI和IO端口的查看和修改&#xff0c;其基于驱动RwDrv.sys来实现&#xff0c;利用这个驱动可以实现系统的侵入。 二…

Windows测试模式打开/关闭 C++ Windows驱动开发

Windows测试模式打开 管理员身份运行CMD 2.输入&#xff1a;bcdedit /set testsigning on 重启计算机 右下角显示&#xff1a; 测试模式成功开启 Windows测试模式关闭 同理&#xff0c;第二步修改为&#xff1a; 重启后右下角&#xff1a; 没有测试模式显示&#xff0c;关闭…

图像处理学习笔记

图像处理的流程&#xff1a;获取图像-分割区域-特征提取。 嵌入式工业读码器 &#xff1a;包括DM码、QR码、vericode码 Blob分析与形态学 1.Blob区域是Blobs这一数据类型在halcon中的一种贴切的表达形式。 采集图像-区域分割&#xff0c;最后通过特征&#xff08;如圆度、面积、…

类与对象【中】

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析2 目录 &#x1f449;&#x1f3fb;类的默认6个成员函数&#x1f449;&#x1f3fb;构造…

代码编辑器实践之vue-codemirror使用

前言 程序员用到IDE次数比较频繁&#xff0c;比如vscode、idea等&#xff0c;这些都是市场上比较流行的代码编辑器&#xff0c;拥有非常全面的功能。但是有时候在项目开发上也会用到代码编辑器&#xff0c;比如复杂的Array<Object>输入&#xff0c;或者需要用到用户交互…

1、Thonny+MicroPython+ESP32开发环境搭建

1. 整体流程说明 1.1 ESP32 大白话来说:ESP32就是一个开发板,上面有芯片以及用到的其它硬件 1.2 ESP32运行程序? 只要是硬件电路(数字电路)那么就可以通过编程的方式对其进行控制 那么这个开发板能认识什么样的程序呢?python?C?C++?Java?。。。。 答:只认识二…

【linux--->数据链路层协议】

文章目录 [TOC](文章目录) 一、数据链路层协议概念二、以太网帧格式1.字段分析 三、局域网通信原理四、ARP协议1.结构2.作用3.ARP通信过程4.ARP协议相关命令 五、局域网内中间人原理六、DNS系统(域名系统)1.域名概念2.DNS系统组成3.DNS协议3.浏览器输入域名后的通信过程4.dig工…

Linux 创建子进程

文章目录 前言一、进程&#xff0c;线程&#xff0c;程序 区分二、创建子进程三、创建多个进程1. 获取进程号2. 循环创建多个进程 四、进程工具。1. ps 查看当前进程.2. kill 进程终止. 总结 前言 在计算机科学中&#xff0c;进程&#xff08;Process&#xff09;、线程&#…

ChatGPT已打破图灵测试,新的测试方法在路上

生信麻瓜的 ChatGPT 4.0 初体验 偷个懒&#xff0c;用ChatGPT 帮我写段生物信息代码 代码看不懂&#xff1f;ChatGPT 帮你解释&#xff0c;详细到爆&#xff01; 如果 ChatGPT 给出的的代码不太完善&#xff0c;如何请他一步步改好&#xff1f; 全球最佳的人工智能系统可以通过…

删除这4个文件夹,流畅使用手机无忧

在现代社会中&#xff0c;手机已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着使用时间的增长&#xff0c;我们可能会遇到手机卡顿和内存不足的问题&#xff0c;让我们感到十分困扰。手机卡顿不仅影响使用体验&#xff0c;还可能导致应用程序运行缓慢&#xff0c;甚…

flex 布局使用 space-between 时将最后一行左对齐

1.使用占位元素 特点&#xff1a;适用于任意列数布局&#xff0c;比较简单&#xff0c;缺点是会产生空标签 方法&#xff1a;使用循环体循环一整行空元素。宽度为单个元素宽度&#xff0c;高度为0 <div class"flex-box"><div class"item-box" v…

HTML <ruby> 标签

实例 一个 ruby 注释&#xff1a; <ruby> 漢 <rt><rp>(</rp>ㄏㄢˋ<rp>)</rp></rt> </ruby>定义和用法 <ruby> 标签定义 ruby 注释&#xff08;中文注音或字符&#xff09;。 在东亚使用&#xff0c;显示的是东亚字…