当前位置: 首页 > news >正文

FFmpeg实现rtp推流

以下是一个简单的示例代码,演示了如何使用 UDP 或 TCP 进行音视频传输:
代码未经验证,供参考

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libavformat/avformat.h>#define RTPPKT_LEN 1400
#define IPOUT_PAYNUM 1// UDP Socket
int udpSocket;// TCP Socket
int tcpSocket;// UDP 发送函数
int udp_write_buffer(void* opaque, uint8_t* buf, int buf_size) {struct sockaddr_in destAddr;memset(&destAddr, 0, sizeof(destAddr));destAddr.sin_family = AF_INET;destAddr.sin_port = htons(1234); // 设置目标端口号destAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置目标IP地址ssize_t sentBytes = sendto(udpSocket, buf, buf_size, 0, (struct sockaddr*)&destAddr, sizeof(destAddr));if (sentBytes < 0) {perror("UDP 发送失败");return -1;}return 0;
}// TCP 发送函数
int tcp_write_buffer(void* opaque, uint8_t* buf, int buf_size) {ssize_t sentBytes = send(tcpSocket, buf, buf_size, 0);if (sentBytes < 0) {perror("TCP 发送失败");return -1;}return 0;
}int main() {av_register_all();avformat_network_init();// 创建输入格式上下文AVFormatContext* inputFormatCtx = avformat_alloc_context();// 打开输入文件或网络流const char* inputUrl = "input.mp4";int ret = avformat_open_input(&inputFormatCtx, inputUrl, nullptr, nullptr);if (ret != 0) {printf("无法打开输入文件:%s\n", inputUrl);return -1;}// 获取流信息ret = avformat_find_stream_info(inputFormatCtx, nullptr);if (ret < 0) {printf("无法获取流信息\n");return -1;}// 寻找视频流索引int videoStreamIndex = -1;for (unsigned int i = 0; i < inputFormatCtx->nb_streams; i++) {if (inputFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStreamIndex = i;break;}}// 创建输出格式上下文AVFormatContext* outputFormatCtx = nullptr;ret = avformat_alloc_output_context2(&outputFormatCtx, nullptr, "rtp", "rtp://127.0.0.1:1234"); // 设置输出 URLif (ret < 0) {printf("无法创建输出格式上下文\n");return -1;}// 创建 AVIO 缓存空间unsigned char* outBuffer = (unsigned char*)av_malloc(RTPPKT_LEN * IPOUT_PAYNUM);// 创建 UDP SocketudpSocket = socket(AF_INET, SOCK_DGRAM, 0);if (udpSocket < 0) {perror("无法创建 UDP Socket");return -1;}// 创建 TCP SockettcpSocket = socket(AF_INET, SOCK_STREAM, 0);if (tcpSocket < 0) {perror("无法创建 TCP Socket");return -1;}// 创建 AVIO 上下文AVIOContext* avioOut;if (strcmp("UDP", "RTP/AVP") == 0) {avioOut = avio_alloc_context(outBuffer, RTPPKT_LEN * IPOUT_PAYNUM, 1, nullptr, nullptr, udp_write_buffer, nullptr);} else if (strcmp("TCP", "RTP/AVP") == 0) {avioOut = avio_alloc_context(outBuffer, RTPPKT_LEN * IPOUT_PAYNUM, 1, nullptr, nullptr, tcp_write_buffer, nullptr);}if (!avioOut) {printf("无法创建 AVIO 上下文\n");return -1;}avioOut->max_packet_size = RTPPKT_LEN;outputFormatCtx->pb = avioOut;outputFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO;// 复制视频流参数到输出格式上下文AVStream* outputStream = avformat_new_stream(outputFormatCtx, nullptr);ret = avcodec_parameters_copy(outputStream->codecpar, inputFormatCtx->streams[videoStreamIndex]->codecpar);if (ret < 0) {printf("无法复制视频流参数\n");return -1;}// 写入输出头部ret = avformat_write_header(outputFormatCtx, nullptr);if (ret < 0) {printf("无法写入输出头部\n");return -1;}// 开始读取和发送数据包AVPacket packet;while (av_read_frame(inputFormatCtx, &packet) >= 0) {if (packet.stream_index == videoStreamIndex) {// 发送数据包到输出上下文ret = av_interleaved_write_frame(outputFormatCtx, &packet);if (ret < 0) {printf("无法发送数据包\n");return -1;}}av_packet_unref(&packet);}// 写入输出尾部ret = av_write_trailer(outputFormatCtx);if (ret < 0) {printf("无法写入输出尾部\n");return -1;}// 关闭 Socketclose(udpSocket);close(tcpSocket);// 释放资源avformat_close_input(&inputFormatCtx);avformat_free_context(inputFormatCtx);avformat_free_context(outputFormatCtx);avio_context_free(&avioOut);av_free(outBuffer);return 0;
}

这个示例代码基于 FFmpeg 库,演示了如何使用 UDP 或 TCP 进行音视频传输。具体的步骤包括:

  1. 注册 FFmpeg 库并初始化网络模块。
  2. 创建输入格式上下文,并打开输入文件或网络流。
  3. 获取流信息,并找到视频流索引。
  4. 创建输出格式上下文,并设置输出协议为 RTP。
  5. 创建 UDP 或 TCP Socket。
  6. 创建 AVIO 缓存空间和 AVIO 上下文,并将其赋值给输出格式上下文。
  7. 复制视频流参数到输出格式上下文。
  8. 写入输出头部。
  9. 通过循环读取输入文件的数据包,并发送到输出格式上下文。
  10. 写入输出尾部。
  11. 关闭 Socket 和释放资源。

您可以根据实际需求修改相关参数,如输入文件、目标地址、端口号等,以适配您的具体场景。

相关文章:

  • 黑豹程序员-安装docker-ce
  • 使用 Taro 开发鸿蒙原生应用 —— 探秘适配鸿蒙 ArkTS 的工作原理
  • linux搭建gitlab
  • 漫谈UNIX、Linux、UNIX-Like
  • JMeter常见配置及常见问题修改
  • 教你如何完美录制电脑端游戏视频
  • 【SpringMVC】SpringMVC的请求与响应
  • 智能优化算法应用:基于非洲秃鹫算法3D无线传感器网络(WSN)覆盖优化 - 附代码
  • Python:正则表达式---贪婪匹配
  • 一些CSS的笔记
  • Redis延迟队列原理及实例
  • 爬虫实战案例 -- 爬取豆瓣读书网页内容
  • 【Xcode】解决Unable to process request - PLA Update available
  • 泛微e-cology XmlRpcServlet文件读取漏洞复现
  • rpc【通义】rpc原理【gpt】
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • Consul Config 使用Git做版本控制的实现
  • express + mock 让前后台并行开发
  • iOS编译提示和导航提示
  • JavaScript中的对象个人分享
  • MD5加密原理解析及OC版原理实现
  • Nacos系列:Nacos的Java SDK使用
  • nodejs调试方法
  • spring boot 整合mybatis 无法输出sql的问题
  • Sublime Text 2/3 绑定Eclipse快捷键
  • TCP拥塞控制
  • webgl (原生)基础入门指南【一】
  • 从PHP迁移至Golang - 基础篇
  • 对超线程几个不同角度的解释
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 模型微调
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 我的业余项目总结
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 在Unity中实现一个简单的消息管理器
  • 转载:[译] 内容加速黑科技趣谈
  • C# - 为值类型重定义相等性
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (12)Hive调优——count distinct去重优化
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (办公)springboot配置aop处理请求.
  • (定时器/计数器)中断系统(详解与使用)
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (一)Java算法:二分查找
  • (转) ns2/nam与nam实现相关的文件
  • (轉)JSON.stringify 语法实例讲解
  • .bashrc在哪里,alias妙用
  • .NET BackgroundWorker
  • .NET Framework杂记
  • .net 后台导出excel ,word