FLV文件推流到Nginx(C++实现)
本文将介绍如何通过librtmp将flv文件推送到Nginx。首先我们明确文件flv和rtmp flv的文件格式是不一样的,具体参考RTMP FLV和FLV文件的区别。文章结构:首先进行解析flv文件,然后从解析后的文件中,读取音频/视频文件,最后将音视频文件利用librtmp推送到Nginx服务器中。Nginx 支持RTMP就不在此赘述。该过程的实现放在下文。
解析FLV
首先我们要了解FLV文件的格式
图片来源于网络。这张图片清楚地展示了FLV的文件结构,首先是FLV Header,一般是9个字节,然后就是一系列的pre tagsize 和 tag。我们需要的是tag中的Tag Data,将它发送到服务端。FLV协议详解
获取音/视频数据
获取所谓的音视频数据就是将FLV Header,preTagSize和Body的头(tagheader)去掉,剩下的就是音视频数据了。tag header 是,1byte TT(Tag Type ),0x08音频,0x09视频,0x12 script, 2-4byte,Tag body的长度, PreTagSize - Tag Header Size = Tag body size, 5-7byte,时间戳,单位:毫秒,script它的时间戳是0, 第8个字节,扩展时间戳, 真正的时间戳格式[扩展,时间戳],一共是4字节
, 9-11,StreamId 0。
好了剩下的工作就是解析这些头了,使用fread读取二进制文件。
推流到Nginx
要推流,肯定先要连接到RTMP server的。
- 创建RTMP,使用RTMP_Alloc()函数。
- 初始化RTMP,RTMP_Init(rtmp);
- 设置RTMP连接地址,RTMP_SetupURL(rtmp, addr);
- 连接,RTMP_Connect(rtmp, NULL)
librtmp的基本步骤
- initialize RTMP Object
- configure RTMP URL
- connect Nginx(Media Stream Server)
- send data packet
源代码
//
// Created by wenfan on 2021/8/10.
//#ifndef PLAY_FLVUPSTREAM_H
#define PLAY_FLVUPSTREAM_H#include <cstdio>
#include <string>
#include <librtmp/rtmp.h>using namespace std;class FLVUpStream {public:FILE* openFLV(string flvaddr);void publish_stream();RTMP* connect_rtmp_server(string rtmpaddr);void send_data(FILE* fp, RTMP* rtmp);RTMPPacket *alloc_packet();void free_packet(RTMPPacket* rtmpPacket);
};
#endif //PLAY_FLVUPSTREAM_H
实现
//
// Created by wenfan on 2021/8/10.
//#include "FLVUpStream.h"
#include <librtmp/rtmp.h>
#include <thread>/*** 这里涉及到大小端的问题* @param fp* @param u24*/
static void read_u24(FILE* fp, unsigned int* u24 ){unsigned int tmp = 0;fread(&tmp, 1, 3 , fp);*u24 = ((tmp >> 16) & 0xFF) | ((tmp << 16) & 0xFF0000) | ((tmp) & 0xFF00);
}/*** FLV的Header一共9字节* 第1-3 byte 固定:'F' 'L' 'V'* 第4byte ,version* 第5字节的0~5位必须是0,进行保留* 第5字节的6位,是否有音频Tag* 第5字节的7位,保留,为0* 第5字节的8位,表示是否有音频Tag* 第6-9位是Header的大小,必须是9* @param flvaddr* @return*/
FILE* FLVUpStream::openFLV(string flvaddr){FILE* fp = NULL;fp = fopen(flvaddr.c_str(), "r+b");if(!fp){printf("Failed to open flv file: %s", flvaddr.c_str());return NULL;}//jump 9 byte FLV Headerfseek(fp, 13, SEEK_SET);//jump 4 byte PreTagSize//fseek(fp, 4, SEEK_CUR);return fp;
}/*** 经历5个步骤,创建好RTMP Stream* @param rtmpaddr* @return*/
RTMP* FLVUpStream::connect_rtmp_server(string rtmpaddr){RTMP* rtmp = nullptr;char* addr = new char[rtmpaddr.length()];strcpy(addr, rtmpaddr.c_str());// 1.create RTMP Object and init it;rtmp = RTMP_Alloc();if(!rtmp){printf("Failed to alloc RTMP Memory\n");goto __ERROR ;}RTMP_Init(rtmp);//2. set rtmp server address and set connection timeoutrtmp->Link.timeout = 10;RTMP_SetupURL(rtmp, addr);//3.Setup connectionif(!RTMP_Connect(rtmp, NULL)){printf("Failed to connect RTMP Server\n");goto __ERROR;}//4.The option is publish, not set the option is playRTMP_EnableWrite(rtmp);//5.create StreamRTMP_ConnectStream(rtmp, 0);return rtmp;__ERROR:if(rtmp){RTMP_Close(rtmp);RTMP_Free(rtmp);}return NULL;
}/*** 释放RTMPPacket内存* @param rtmpPacket*/
void FLVUpStream::free_packet(RTMPPacket* rtmpPacket){if(rtmpPacket){//释放分配的Packet包内内存RTMPPacket_Free(rtmpPacket);//释放包装结构体free(rtmpPacket);}
}/**** @return*/
RTMPPacket* FLVUpStream::alloc_packet(){RTMPPacket* packet;packet = (RTMPPacket*) malloc(sizeof(RTMPPacket));if(!packet){printf("Failed to alloc RTMPPacket, No Memory!\n");return NULL;}if(!RTMPPacket_Alloc(packet, 64*1024*1024*1024)) {printf("Failed to alloc RTMPPacket content, No Memory!\n");return NULL;}RTMPPacket_Reset(packet);packet->m_hasAbsTimestamp = 0;packet->m_nChannel = 0x4;return packet;
}/*** tag header* 1byte TT(Tag Type ),0x08音频,0x09视频,0x12 script* 2-4byte,Tag body的长度, PreTagSize - Tag Header Size = Tag body size* 5-7byte,时间戳,单位:毫秒,script它的时间戳是0* 第8个字节,扩展时间戳, 真正的时间戳格式[扩展,时间戳],一共是4字节* 9-11,StreamId 0** @param fp* @param pPacket*/
static int read_data(FILE *fp, RTMPPacket** pPacket){int ret = 0;size_t data_size;char tt;unsigned int tag_data_size;unsigned int ts;char extend_ts;unsigned int streamId;unsigned int preTagSize ;/*** 去读body*///read_u8(fp,&tt);fread(&tt, 1,1, fp);read_u24(fp, &tag_data_size);read_u24(fp, &ts);fread(&extend_ts, 1, 1, fp);read_u24(fp, &streamId);printf("tag header :tt : %d, ts = %d, data_size = %d, streamId = %d\n", tt, ts , tag_data_size,streamId);//读取音视频数据data_size = fread((*pPacket)->m_body, 1, tag_data_size,fp);//读取preTagSize,4个字节fread(&preTagSize, 1, 4, fp);if(data_size != tag_data_size){printf("Failed to read tag body from flv ,(data_size = %zu, tag_data_size = %d)\n", data_size, tag_data_size);return ret;}//设置packet data(*pPacket)->m_headerType = RTMP_PACKET_SIZE_LARGE;(*pPacket)->m_nTimeStamp = ts;(*pPacket)->m_packetType = tt;(*pPacket)->m_nBodySize = tag_data_size;return 1;
}/*** 推流* @param fp* @param rtmp*/
void FLVUpStream::send_data(FILE *fp, RTMP *rtmp) {//1.create RTMP_Packet ObjectRTMPPacket* packet = NULL;packet = alloc_packet();packet->m_nInfoField2 = rtmp->m_stream_id;while (1){//2.read data from flvif(!read_data(fp, &packet)){printf("over!\n");break;}//3.judge connection is nornalif(!RTMP_IsConnected(rtmp)){printf("Disconnect with the RTMP server!\n");return;}//4.send dataRTMP_SendPacket(rtmp,packet, 0);this_thread::sleep_for(std::chrono::milliseconds(10));}// realse packetfree_packet(packet);return;
}/*** 进行推流* 进行三个步骤:* 1.读取flv文件* 2.连接RTMP服务器* 3.推送音频/视频数据* @return*/
void FLVUpStream::publish_stream(){string flvaddr = "/Users/fengjianqiang/Movies/1.flv";string rtmpaddr = "rtmp://localhost:1935/rtmplive/room";//1.读取flv文件FILE* fp = openFLV(flvaddr);//2.连接RTMP服务器RTMP* rtmp = connect_rtmp_server(rtmpaddr);//3.publish audio /video datasend_data(fp, rtmp);
}
FLV文件推流到Nginx(C++实现)相关推荐
- 音视频开发系列(14):将视频和音频同时推流到nginx服务器上
上次分享了视频录制代码的封装,这次分享一下同时将视频和音频推流到服务器上,注意(这次分享的内容不包括音视频同步方面的),所以会出现音视频不同步的情 音视频同时发送的策略主要是:利用一个链表存储音视频帧 ...
- flv文件转换,完美解决
近来入了一台手机,要在手机上看视频,则要下载一个个软件,这能解决啊.转换成3gp格式吗,但是,近来遇到一个棘手问题,也是最多人问的问题,就是在网上看到的视频如何拿下来,拿下来还不简单,就是在C:\Do ...
- Nginx重启时丢失nginx.pid文件解决方法nginx: [emerg] open() “/var/run/nginx/nginx.pid“ failed (2: No such fi
nginx: [emerg] open() "/var/run/nginx/nginx.pid" failed (2: No such file or directory) 不要在 ...
- 使用FLVPlayback组件播放fms(fcs)的流式FLV文件
main.asc文件 C:\Program Files\Macromedia\Flash 8\Samples and Tutorials\Samples\Components\FLVPlayback\ ...
- (转)rtmp协议简单解析以及用其发送h264的flv文件
Adobe公司太坑人了,官方文档公布的信息根本就不全,如果只按照他上面的写的话,是没法用的.按照文档上面的流程,server和client连接之后首先要进行握手,握手成功之后进行一些交互,其实就是交互 ...
- FLV文件中VideoPacket的详解
FLV文件中VideoPacket的详解 众所周知,FLV文件体主要有三种Tag组成:AUDIODATA.VIDEODATA和SCRIPTDATA,其中SCRIPTDATA中包含了MetaData,通 ...
- 分析flv文件的信息
上一篇博文"FLV文件格式解析"提到的小工具FLVParse,是由于工作需要,我自己写的一个小程序. 这个工具的主要功能是查看FLV的文件结构,帮助我们理解FLV格式.另外,如果涉 ...
- 分析FLV文件分析和解析器的开源代码
分析一下GitHub上一份FLV文件分析和解析器的开源代码 GitHub源码地址:功能强大的 FLV 文件分析和解析器 :可以将flv文件的视频tag中的h264类型数据和音频tag中的aac类型数据 ...
- python flv转mp4_ffmpeg将多个flv文件合成为mp4(python版)
需求 直播生成的flv片段需要做个归档,把指定的文件夹中的flv合并成一个mp4,简单的转码合并操作直接用命令行调用来实现. 注意事项 flv文件直接合并生成mp4的话只有第一个flv的内容才能播放, ...
最新文章
- php 接口使用场景,接口使用场景、trait基本功能
- 【必读】2019年深度学习自然语言处理最新十大发展趋势, 附报告下载
- [转载]深入理解JavaScript闭包(closure)
- 送餐机器人被解雇,人工智能“人性”待进化
- excel 进行二叉树_Excel下拉菜单,那些你不知道的操作
- idea编译的文件怎么用cmd打开_JAVA学习册|基础语法|cmd输出HelloWorld
- 浮点数的二进制表示学习笔记
- 杭电ACM 2017
- 微软开源InnerEye:让医学影像AI普及化
- 【Angular 4】数据绑定
- 数据挖掘实战—基于水色图像的水质评价
- 分组在re模块中的使用
- 网站建设如何选择CMS网站系统
- eNsp 多区域OSPF配置
- sub求阶乘c语言,用VB编写程序求S=A!+B!+C!,要求阶乘的计算使用Sub过程来实现,参数A、B、C的值从键盘输入的程序代码?...
- TI单芯片毫米波雷达代码走读(十八)—— 多普勒维CA-CFAR检测之C代码实现
- 补阳气吃什么 补阳气的食物
- 博士读一半决定放弃了,丢人吗?
- 电路基础之:差模信号与共模信号
- 建站神器:使用Hexo+Kaze+Gitee 自建博客