關於RTMPdump的使用介紹,很多的都是在Windows平台的應用,雷神有做一個系列的分析,但是雷神的也主要是以Windows平台為主。本文主要的工作是將雷神《最簡單的基於librtmp的樣本:發布H.264(H.264通過RTMP發布)》中的工程移植到linux系統,同時修複一些問題並且添加一部分說明。
在使用該工程之前,應該有搭建好一個RTMP伺服器,同時對H264資料格式有一個較好的瞭解。可以參考:
nginx 搭建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; elsemetaData.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資料