关于RTMPdump的使用介绍,很多的都是在Windows平台的应用,雷神有做一个系列的分析,但是雷神的也主要是以Windows平台为主。本文主要的工作是将雷神《最简单的基于librtmp的示例:发布H.264(H.264通过RTMP发布)》中的工程移植到linux系统,同时修复一些问题并且添加一部分说明。
在使用该工程之前,应该有搭建好一个RTMP服务器,同时对H264数据格式有一个较好的了解。可以参考:
整个软件的流程图如下:
仔细分析RTMP264_Send 函数
/** * 将内存中的一段H.264编码的视频数据利用RTMP协议发送到服务器 * * @param read_buffer 回调函数,当数据不足的时候,系统会自动调用该函数获取输入数据。 * 2个参数功能: * uint8_t *buf:外部数据送至该地址 * int buf_size:外部数据大小 * 返回值:成功读取的内存大小 * @成功则返回1 , 失败则返回0 */ int RTMP264_Send(int (*read_buffer)(unsigned char *buf, int buf_size)) { int ret; uint32_t now,last_update; memset(&metaData,0,sizeof(RTMPMetadata)); memset(m_pFileBuf,0,BUFFER_SIZE); if((ret=read_buffer(m_pFileBuf,m_nFileBufSize))<0) { return FALSE; } NaluUnit naluUnit; // 读取SPS帧 ReadFirstNaluFromBuf(naluUnit,read_buffer); metaData.nSpsLen = naluUnit.size; metaData.Sps=NULL; metaData.Sps=(unsigned char*)malloc(naluUnit.size); memcpy(metaData.Sps,naluUnit.data,naluUnit.size); // 读取PPS帧 ReadOneNaluFromBuf(naluUnit,read_buffer); metaData.nPpsLen = naluUnit.size; metaData.Pps=NULL; metaData.Pps=(unsigned char*)malloc(naluUnit.size); memcpy(metaData.Pps,naluUnit.data,naluUnit.size); // 解码SPS,获取视频图像宽、高信息 int width = 0,height = 0, fps=0; h264_decode_sps(metaData.Sps,metaData.nSpsLen,width,height,fps); //metaData.nWidth = width; //metaData.nHeight = height; if(fps) metaData.nFrameRate = fps; else metaData.nFrameRate = 25; //发送PPS,SPS //ret=SendVideoSpsPps(metaData.Pps,metaData.nPpsLen,metaData.Sps,metaData.nSpsLen); //if(ret!=1) // return FALSE; unsigned int tick = 0; unsigned int tick_gap = 1000/metaData.nFrameRate; //printf(" nFrameRate = %d \n ",metaData.nFrameRate); ReadOneNaluFromBuf(naluUnit,read_buffer); int bKeyframe = (naluUnit.type == 0x05) ? TRUE : FALSE; while(SendH264Packet(naluUnit.data,naluUnit.size,bKeyframe,tick)) { got_sps_pps: //if(naluUnit.size==8581) printf("NALU size:%8d\n",naluUnit.size); last_update=RTMP_GetTime(); if(!ReadOneNaluFromBuf(naluUnit,read_buffer)) goto end; if(naluUnit.type == 0x07 || naluUnit.type == 0x08) goto got_sps_pps; bKeyframe = (naluUnit.type == 0x05) ? TRUE : FALSE; tick +=tick_gap; now=RTMP_GetTime(); //msleep(tick_gap-now+last_update); //printf("now = %d, last_update = %d, now - last_update = %d \n",now,last_update,now - last_update); msleep(tick_gap); } end: free(metaData.Sps); free(metaData.Pps); return TRUE; }在开始循环获取数据之前,先读取h264文件的SPS和PPS。SPS是序列参数集,PPS是图像参数集。在SPS序列参数集中可以解析出图像的宽,高和帧率等信息。而在h264文件中,最开始的两帧数据就是SPS和PPS,这个h264文件只存在一个SPS帧和一个PPS帧。在做RTMP 传输的时候,它需要在每次发送H264的I帧之前,发送SPS序列参数集帧和PPS图像参数集帧。在我们这里的处理方式是,先提取出SPS和PPS帧,然后保存起来,然后每次发送I帧之前都发送一次SPS和PPS帧。SPS帧和PPS帧如下:
工程文件如下:
lcb@ubuntu:~/test/RTMP/rtmp_push_h264$ tree . ├── cuc_ieschool.h264 ├── include │ ├── librtmp │ │ ├── amf.h │ │ ├── bytes.h │ │ ├── dhgroups.h │ │ ├── dh.h │ │ ├── handshake.h │ │ ├── http.h │ │ ├── log.h │ │ ├── rtmp.h │ │ └── rtmp_sys.h │ ├── librtmp_send264.h │ └── sps_decode.h ├── lib │ ├── librtmp.a │ ├── librtmp.so │ └── librtmp.so.0 ├── librtmp_send264.cpp ├── Makefile ├── simplest_librtmp_send264.cpp └── src
完整的工程下载地址:
RTMPdump(libRTMP) 通过RTMP 发布H264数据