本文将介绍如何通过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的。

  1. 创建RTMP,使用RTMP_Alloc()函数。
  2. 初始化RTMP,RTMP_Init(rtmp);
  3. 设置RTMP连接地址,RTMP_SetupURL(rtmp, addr);
  4. 连接,RTMP_Connect(rtmp, NULL)

librtmp的基本步骤

  1. initialize RTMP Object
  2. configure RTMP URL
  3. connect Nginx(Media Stream Server)
  4. 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++实现)相关推荐

  1. 音视频开发系列(14):将视频和音频同时推流到nginx服务器上

    上次分享了视频录制代码的封装,这次分享一下同时将视频和音频推流到服务器上,注意(这次分享的内容不包括音视频同步方面的),所以会出现音视频不同步的情 音视频同时发送的策略主要是:利用一个链表存储音视频帧 ...

  2. flv文件转换,完美解决

    近来入了一台手机,要在手机上看视频,则要下载一个个软件,这能解决啊.转换成3gp格式吗,但是,近来遇到一个棘手问题,也是最多人问的问题,就是在网上看到的视频如何拿下来,拿下来还不简单,就是在C:\Do ...

  3. 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) 不要在 ...

  4. 使用FLVPlayback组件播放fms(fcs)的流式FLV文件

    main.asc文件 C:\Program Files\Macromedia\Flash 8\Samples and Tutorials\Samples\Components\FLVPlayback\ ...

  5. (转)rtmp协议简单解析以及用其发送h264的flv文件

    Adobe公司太坑人了,官方文档公布的信息根本就不全,如果只按照他上面的写的话,是没法用的.按照文档上面的流程,server和client连接之后首先要进行握手,握手成功之后进行一些交互,其实就是交互 ...

  6. FLV文件中VideoPacket的详解

    FLV文件中VideoPacket的详解 众所周知,FLV文件体主要有三种Tag组成:AUDIODATA.VIDEODATA和SCRIPTDATA,其中SCRIPTDATA中包含了MetaData,通 ...

  7. 分析flv文件的信息

    上一篇博文"FLV文件格式解析"提到的小工具FLVParse,是由于工作需要,我自己写的一个小程序. 这个工具的主要功能是查看FLV的文件结构,帮助我们理解FLV格式.另外,如果涉 ...

  8. 分析FLV文件分析和解析器的开源代码

    分析一下GitHub上一份FLV文件分析和解析器的开源代码 GitHub源码地址:功能强大的 FLV 文件分析和解析器 :可以将flv文件的视频tag中的h264类型数据和音频tag中的aac类型数据 ...

  9. python flv转mp4_ffmpeg将多个flv文件合成为mp4(python版)

    需求 直播生成的flv片段需要做个归档,把指定的文件夹中的flv合并成一个mp4,简单的转码合并操作直接用命令行调用来实现. 注意事项 flv文件直接合并生成mp4的话只有第一个flv的内容才能播放, ...

最新文章

  1. php 接口使用场景,接口使用场景、trait基本功能
  2. 【必读】2019年深度学习自然语言处理最新十大发展趋势, 附报告下载
  3. [转载]深入理解JavaScript闭包(closure)
  4. 送餐机器人被解雇,人工智能“人性”待进化
  5. excel 进行二叉树_Excel下拉菜单,那些你不知道的操作
  6. idea编译的文件怎么用cmd打开_JAVA学习册|基础语法|cmd输出HelloWorld
  7. 浮点数的二进制表示学习笔记
  8. 杭电ACM 2017
  9. 微软开源InnerEye:让医学影像AI普及化
  10. 【Angular 4】数据绑定
  11. 数据挖掘实战—基于水色图像的水质评价
  12. 分组在re模块中的使用
  13. 网站建设如何选择CMS网站系统
  14. eNsp 多区域OSPF配置
  15. sub求阶乘c语言,用VB编写程序求S=A!+B!+C!,要求阶乘的计算使用Sub过程来实现,参数A、B、C的值从键盘输入的程序代码?...
  16. TI单芯片毫米波雷达代码走读(十八)—— 多普勒维CA-CFAR检测之C代码实现
  17. 补阳气吃什么 补阳气的食物
  18. 博士读一半决定放弃了,丢人吗?
  19. 电路基础之:差模信号与共模信号
  20. 建站神器:使用Hexo+Kaze+Gitee 自建博客

热门文章

  1. centos单机部署greenplum
  2. 基于 cz88 纯真IP数据库开发的 IP 解析服务 - 支持 http 协议请求或 rpc 协议请求,也支持第三方包的方式引入直接使用
  3. Guice——轻量级注解Guice简单之美
  4. 完美世界广告萨克斯背景音乐
  5. 2020年7月中国编程语言排行榜
  6. js 把字符串转成json对象的三种方法
  7. Windows Mobile告别式 昔日经典回忆录
  8. (Shortest Paths Algorithm)
  9. 如何区分客户端是手机端还是PC端
  10. 1.Hashmap 解决hash冲突为什么使用红黑树