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;
}
}
}
相关文章:

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组播流并播放)…...

nvm下载node导致npm报错无法使用
有个依赖库需要更新下node,用nvm下载后项目跑不起来了,npm -v 还报错 其实一开始是npm下载不来,然后换了淘宝镜像后还是报错 然后就只能手动下载下了 进入node.js官网 https://nodejs.org/en/download 下载后注意要安装在你nvm目录中&#x…...

LeetCode 热题 100JavaScript--2. 两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 …...

zookeeper总结
1.概念 Zookeeper 是一个分布式协调服务,可用于服务发现,分布式锁,分布式领导选举,配置管理等。Zookeeper 提供了一个类似于 Linux 文件系统的树形结构(可认为是轻量级的内存文件系统,但只适合存少量信息&…...

【程序环境与预处理玩转指南】
本章重点: 程序的翻译环境 程序的执行环境 详解:C语言程序的编译链接 预定义符号介绍 预处理指令 #define 宏和函数的对比 预处理操作符#和##的介绍 命令定义 预处理指令 #include 预处理指令 #undef 条件编译 1. 程序的翻译环境和执行环境 在…...

搭建简易syslog日志中转服务器
在某种场景下,无法接入日志审计设备,本文提供一种方式,可通过搭建简易日志中转服务器,收集到该环境下的日志后,再将其导入日志审计设备中。 0x1 开启服务 rsyslog守护进程来自于当前的linux发布版本的预装模块&#x…...

MongoDB文档-进阶使用-spring-boot整合使用MongoDB---MongoRepository完成增删改查
阿丹: 之前学习了在MongoDB客户端上的MongoDB语句现在将MongoDB整合到spring项目。 传送门: MongoDB文档--基本概念_一单成的博客-CSDN博客 MongoDB文档--基本安装-linux安装(mongodb环境搭建)-docker安装(挂载数据卷…...

什么是线程局部变量?
在Java中,线程局部变量(Thread Local Variable)是一种特殊类型的变量,每个线程都有其自己独立的副本。这意味着每个线程可以在该变量上进行操作,而不会影响其他线程的副本。线程局部变量通常用于在多线程环境中存储线程私有的数据,…...

Jmeter响应中的乱码问题
文章目录 问题描述解决办法 问题描述 Jmeter在访问接口的时候,响应内容如果有中文可能会显示乱码 响应页面没有做编码处理,JMeter默认按照ISO-8859-1编码格式进行解析 解决办法 在线程组中添加BeanShell PostProcessor后置处理器 prev.setDataEnco…...

MongoDB文档-进阶使用-MongoDB索引-createindex()与dropindex()-在MongoDB中使用正则表达式来查找
阿丹: 之前研究了MongoDB的基础增删改查。在学会基础的数据库增删改查肯定是不够的。这个时候就涉及到了数据库搜索的时候的效率。需要提高数据的搜索效率。 MongoDB索引 在所以数据库中如果没有数据索引的时候。如果需要查找到一些数据。都会去主动扫描所有可能存…...

CentOS下ZLMediaKit的可视化管理网站MediaServerUI使用
一、简介 按照 ZLMediaKit快速开始 编译运行ZLMediaKit成功后,我们可以运行其合作开源项目MediaServerUI,来对ZLMediaKit进行可视化管理。通过MediaServerUI,我们可以实现在浏览器查看ZLMediaKit的延迟率、负载率、正在进行的推拉流、服务器…...

回归预测 | MATLAB实现POA-CNN-BiGRU鹈鹕算法优化卷积双向门控循环单元多输入单输出回归预测
回归预测 | MATLAB实现POA-CNN-BiGRU鹈鹕算法优化卷积双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现POA-CNN-BiGRU鹈鹕算法优化卷积双向门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现POA-CNN-BiGRU鹈鹕…...

Rust 原生支持龙架构指令集
导读近日,Rust 开源社区发布 1.71.0 版本,实现对龙架构(LoongArch)指令集的原生支持。 龙架构操作系统发行版和开发者可基于上游社区源代码构建或直接下载 Rust 开源社区发布的龙架构二进制版本。Rust 开发者将在龙架构平台上获得…...

为生成式AI提速,亚马逊云科技Amazon EC2 P5满足GPU需求
生成式AI(Generative AI)已经成为全球范围内的一个重要趋势,得到越来越多企业和研究机构的关注和应用。纽约时间7月26日,亚马逊云科技数据库、数据分析和机器学习全球副总裁Swami Sivasubramanian在亚马逊云科技举办的纽约峰会上更…...

聊聊企业数据安全那些事~
保护企业数据安全的重要性与方法 随着信息技术的快速发展,企业数据的安全性变得越来越重要。在数字化时代,企业的核心业务和关键信息都存储在电脑系统中,一旦遭受到数据泄露、黑客攻击或恶意软件感染,将可能对企业造成严重的损害…...

日常随笔——如何把excel题库转换为word打印格式
将Excel题库转换为Word可以通过编程的方式实现。以下是一个使用Python的示例代码,该代码使用openpyxl库读取Excel文件,并使用python-docx库创建和保存Word文档。 首先,请确保已经安装了 openpyxl 和 python-docx 库。可以使用以下命令进行安…...

SpringCloud项目打包注意事项以及可能出错的几种情况
SpringCloud项目打包注意事项和可能出错的几种情况 1、检查子模块中的 parent的pom文件路径 \<relativePath/\>2、检查打包插件的位置3、检查module是否重复引用 欢迎访问我的个人博客:https://wk-blog.vip 1、检查子模块中的 parent的pom文件路径 <relat…...

ZABBIX 6.4 Mysql数据库分表
ZABBIX监控设备较多的时候,Mysql数据库容易成为性能的瓶颈,可以通过数据库分表的方式来进行优化。步骤如下: 一、停用zabbix服务 # 避免修改分区表时,数据还有写入 systemctl stop zabbix 二、备份MySQL zabbix DB 避免修改分…...

多线程-Runable和Callable的区别
在Java中,多线程可以通过实现Runnable接口或使用Callable接口来实现。这两种方式有一些区别,如下所示: 返回值: Runnable接口的run()方法没有返回值,它表示一个没有返回结果的任务。Callable接口的call()方法有返回值…...

智慧城市规划新引擎:探秘数字孪生中的二维与三维GIS技术差异
智慧城市作为人类社会发展的新阶段,正日益引领着我们迈向数字化未来的时代。在智慧城市的建设过程中,地理信息系统(GIS)扮演着举足轻重的角色。而在GIS的发展中,二维和三维GIS作为两大核心技术,在城市规划与…...

Python入门自学进阶-Web框架——38、redis、rabbitmq、git
缓存数据库redis: NoSQL(Not only SQL)泛指非关系型的数据库。为了解决大规模数据集合多重数据类的挑战。 NoSQL数据库的四大分类: 键值(Key-Value)存储数据库列存储数据库文档型数据库图形(…...

论 SoC上的Linux如何拉动外部I/O
在MCU中(如classic autosr或其他RTOS),一般可以直接通过往对应的寄存器(地址转为指针)写值, 或者调用一些硬件抽象层或者驱动接口来拉动芯片提供的GPIO。 但是在Linux中,可能不会让应用层直接去…...

SpringBoot项目如何部署SSL证书 (JKS格式)
1、SpringBoot项目如何部署SSL证书 (JKS格式) 1. 获取 SSL 证书和私钥 首先,你需要获取有效的 SSL 证书和私钥。SSL 证书是一种用于加密通信的数字证书,它可以通过购买商业 SSL 证书或使用免费的 Let’s Encrypt 证书获得。请确保你拥有证书文件和与之…...

成功解决:ValueError Cannot assign non-leaf Tensor to parameter ‘weight‘
成功解决:ValueError Cannot assign non-leaf Tensor to parameter ‘weight‘ 欢迎大家来到安静到无声的《模式识别与人工智能(程序与算法)》,如果对所写内容感兴趣请看模式识别与人工智能(程序与算法)系列讲解 - 总目录,同时这也可以作为大家学习的参考。欢迎订阅,优…...

面试之快速学习SQL-基础增删改查语句
1. SELECT SELECT column1,column2,column3 FROM table_name;SELECT * FROM table_name;2. SQL SELECT DISTINCT 语句 在表中,可能会包含重复值。这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值。 SE…...

nuxt脚手架创建项目
在初始化时遇到一个依赖找不到的问题,记录一下,如有遇到同样问题的小伙伴,希望能给你们一点指引。 从安装脚手架开始,首先 一:安装nuxt脚手架 1. C盘全局安装: npm i -g create-nuxt-app 安装后可creat…...

复现原型链污染漏洞
目录 一、复现原型链污染漏洞 hackit 2018 1、创建hackit_2018.js文件 2、运行hackit_2018.js文件 3、寻找原型链漏洞 4、污染原型链 hackit 2018 1、创建hackit_2018.js文件 const express require(express) var hbs require(hbs); var bodyParser require(body-par…...

.Net6 Web Core API 配置 Autofac 封装 --- 依赖注入
目录 一、NuGet 包导入 二、Autofac 封装类 三、Autofac 使用 四、案例测试 下列封装 采取程序集注入方法, 单个依赖注入, 也适用, 可<依赖注入>的地方配置 一、NuGet 包导入 Autofac Autofac.Extensions.DependencyInjection Autofac.Extras.DynamicProxy 二、Auto…...

鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统 em
Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下: 首页 工作台:待办工作、消息通知、预警信息,点击可进入相应的列表 项目进度图表:选择(总体或单个)项目…...

【搭建PyTorch神经网络进行气温预测】
import numpy as np import pandas as pd import matplotlib.pyplot as plt import torch import torch.optim as optim import warnings warnings.filterwarnings("ignore") %matplotlib inlinefeatures pd.read_csv(temps.csv)#看看数据长什么样子 features.head…...