1. 程式人生 > >H264 推流到RTMP伺服器

H264 推流到RTMP伺服器

下面是我最近了解PUST H264流到RTMP伺服器上的一些筆記,參考了上面的連結,看別人的不如自己動手實踐一下,以下便是實驗過程記錄。

一、FLV結構簡析

關於FLV的結構,雷博的博文已經詳細說明了,在這裡可以參考一張圖片
這裡寫圖片描述
由上面的圖片可以看出,FLV的整體結構為Header + Body. 其中Body則由 Tag + PreviousTagSizeN的方式組成,每一個Tag由Tag Header + Tag Data組成。
其中,在Video_File_Format_Specification_V10.pdf中,對每一個TAG的Tag Data有了更詳細的說明(暫時只關注視訊tag):
這裡寫圖片描述


這裡寫圖片描述

關於上面對Tag Data結構的說明,以前在做本地FLV視訊PUSH到RTMP的測試中,並沒有關注,只是直接將Tag Data封包進RTMP Packet裡面傳送出去即可。

二、H264結構簡析

H264的碼流結構主要由SPS、 PPS、 IDR 幀(包含一個或多個 I-Slice)、 P 幀(包含一個或多個P-Slice)、 B 幀(包含一個或多個 B-Slice)等部分組成。

關於SPS和PPS,引用以下:

  • 將一個視訊序列 (從 IDR 幀開始到下一個 IDR 幀之前的資料稱為一個視訊序列) 全部影象的共同特徵抽取出來,放在 SPS 語法單元中。
  • 將各個影象的典型特徵抽取出來,放在 PPS 語法單元中。
  • 只有視訊序列之間才能切換 SPS,即只有 IDR 幀的第一個 slice 可以切換 SPS。
  • 只有影象之間才能切換 PPS,即只有每幀影象的第一個 slice 才能切換 PPS

H.264 的所有語法結構最終都被封裝成 nalu。碼流中的 nalu單元必須定義合適的分隔符,否則無法區分,因此採用字首碼“00 00 01”或者“00 00 00 01”來區分每一個nalu單元。在每個字首碼後面緊跟的一個位元組為nalu的語法結構,由三部分組成forbidden_bit(1bit),nal_reference_bit(2bits)(優先順序),nal_unit_type(5bits)(型別)。
forbidden_bit:禁止位。
nal_reference_bit:當前NAL的優先順序,值越大,該NAL越重要。
nal_unit_type :NAL型別。
其中,我們著重需要關注的是nal_unit_type ,因為它代表了這個NALU的具體荷載資料的型別,我們可以通過 nal_unit_type & 0x1f的方式來獲取其型別,具體定義如下:
這裡寫圖片描述

三、H264流的封裝

在PUSH FLV到RTMP伺服器的時候,我們只需將FLV 的Tag Data封裝進RTMP Packet,然後呼叫RTMP_SendPacket()函式將資料傳送出去。
因此,在將H264 PUSH給RTMP伺服器的時候,我們也需要按照FLV的格式將H264資料進行封包。因此我們需要構造視訊Tag,並且我們在傳送第一包資料前,需要構造“AVC Sequence Header”,用於告訴RTMP伺服器解碼相關的資訊。
再次呈上上面的兩幅圖:
這裡寫圖片描述
這裡寫圖片描述

上面兩幅圖為FLV 每一個TAG 中的Tag Data裡面的組成,因此我們需要根據上面的結構構造視訊同步包 和 H264碼流包

1)視訊同步包的構造[AVC Sequence Header]

視訊同步包的構造,其實是需要我們將H264中的SPS PPS按照一定的格式發給RTMP伺服器,供RTMP伺服器解碼器進行解碼。根據上面的圖片可知,當構造視訊同步包的時候,各個結構如下:

VIDEODATA
FrameType == 1
CodecID == 7
VideoData == AVCVIDEOPACKET

AVCVIDEOPACKET
AVCPacketType == 0x00
CompositionTime == 0x000000
Data == AVCDecoderConfigurationRecord

接下來繼續構造AVCDecoderConfigurationRecord,參考上面連結,AVCDecoderConfigurationRecord相關結構如下:

這裡寫圖片描述

因此我們需要將H264中的SPS PPS資訊按照上面的結構進行填充,程式碼如下:

int send_sps_pps(unsigned char* index_body,int index_body_len)
{
    unsigned char *sps,*pps;
    int sps_temp,pps_temp;
    int sps_len,pps_len;
    int i,temp;
    unsigned char body[1024];
    memset(body,0,1024);

    /* find *sps *pps */
    temp = find_sps_pps(index_body,index_body_len,&sps_temp,&pps_temp,&sps_len,&pps_len);
    if(temp < 0)
        return -1;
    sps = index_body + sps_temp;
    pps = index_body + pps_temp;

    /*去掉幀界定符*/ 
    sps += 4;
    pps += 4;
    sps_len -= 4;
    pps_len -= 4;

    /*AVC head*/
    i = 0;
    body[i++] = 0x17;
    body[i++] = 0x00;
    body[i++] = 0x00;
    body[i++] = 0x00;
    body[i++] = 0x00;

    /*AVCDecoderConfigurationRecord*/
    body[i++] = 0x01;
    body[i++] = *(sps+1);
    body[i++] = *(sps+2);
    body[i++] = *(sps+3);
    body[i++] = 0xff;

    /*sps*/
    body[i++]   = 0xe1;
    body[i++] = (sps_len >> 8) & 0xff;
    body[i++] = sps_len & 0xff;
    memcpy(&body[i],sps,sps_len);
    i +=  sps_len;

    /*pps*/
    body[i++]   = 0x01;
    body[i++] = (pps_len >> 8) & 0xff;
    body[i++] = (pps_len) & 0xff;
    memcpy(&body[i],pps,pps_len);
    i +=  pps_len;

    /*send rtmp packet*/
    if(rtmp_packet_send(body,i,RTMP_PACKET_TYPE_VIDEO,0) < 0)
        return -2;
    return temp;
}

2)H264普通資料包的構建

構建了上面的視訊同步包後,我們需要將H264的荷載的資料即H264的I P B等資料封包進去。根據上面的圖片,結構資訊如下:

VIDEODATA
FrameType ==(I frame ? 1 :2)
CodecID == 7
VideoData == AVCVIDEOPACKET

AVCVIDEOPACKET
AVCPacketType == 0x01
CompositionTime == 0x000000
Data == NALU

上面的Data == H264 NALU Size + NALU Raw Data

程式碼如下:

int send_rtmp_video(unsigned char* index_body,int index_body_len,unsigned int timestamp)
{
    unsigned char *body;
    int type;

    /*去掉幀界定符*/  
    if (index_body[2] == 0x00) { /*00 00 00 01*/  
            index_body += 4;  
            index_body_len -= 4;  
    } else if (index_body[2] == 0x01){ /*00 00 01*/  
            index_body += 3;  
            index_body_len -= 3;  
    }  

    /*申請傳送資料空間*/
    body = (unsigned char*)malloc(index_body_len+9); 

     /*send video packet*/   
    memset(body,0,index_body_len+9);  

    /*key frame*/  
    body[0] = 0x27;  
    type = index_body[0]&0x1f;  
    if (type == NAL_SLICE_IDR)   
      body[0] = 0x17;  

     /*nal unit*/  
    body[1] = 0x01;  
    body[2] = 0x00;  
    body[3] = 0x00;  
    body[4] = 0x00;  

    //data length
    body[5] = (index_body_len >> 24) & 0xff;  
    body[6] = (index_body_len >> 16) & 0xff;  
    body[7] = (index_body_len >>  8) & 0xff;  
    body[8] = (index_body_len ) & 0xff;  

    /*copy data*/  
    memcpy(&body[9],index_body,index_body_len);  

    /*send rtmp packet*/
    if(rtmp_packet_send(body,index_body_len + 9,RTMP_PACKET_TYPE_VIDEO,timestamp) < 0)
        return -1;


    /*釋放傳送資料空間*/
    free(body);

    return 0;

}

四、小結

在剛開始接觸H264 PUSH到RTMP時,一頭霧水,不理解如何進行操作,然後通過查閱資料,得到了初步的瞭解,將H264推流到RTMP伺服器,關鍵的也就是視訊同步包的構造,和H264普通資料包的構造,以及在將這些資料封包進RTMP Packet時候,要注意時間戳之間的關係。除了這些,其他方面例如RTMP的初始化,建立連線等方面則和RTMPDUMP中的流程一致。

相關推薦

H264 RTMP伺服器

下面是我最近了解PUST H264流到RTMP伺服器上的一些筆記,參考了上面的連結,看別人的不如自己動手實踐一下,以下便是實驗過程記錄。 一、FLV結構簡析 關於FLV的結構,雷博的博文已經詳細說明了,在這裡可以參考一張圖片 由上面的圖片可以

C#FFmpeg視訊採集與RTMP伺服器程式碼思路整理

C#視訊採集與推送RTMP伺服器程式碼思路整理:在看過FFmpeg後是否認為寫C#的視訊流採集和推送還是一頭霧水啊?深有此感。領導是C#的高手,說可以通過C或C++的程式碼直接複製貼上到C#工程然後進行適配程式碼就可以了,因為C#使用ffmpeg的類名和變數、方法等都與C保持

C#RTMP,攝像頭、麥克風、桌面、音效卡(附原始碼)

  這段時間一直都在研究推流的技術,經過斷斷續續將近兩個月的摸索實踐,終於能穩定地推流了。        這個demo的主要功能就是將採集到的攝像頭或桌面的視訊、以及麥克風或音效卡的音訊資料推到Nginx-RTMP伺服器上,再由Web瀏覽器去拉流並播放。   接下來介紹

h264視訊流,aac音訊(g711a轉碼)送至rtmp伺服器

這篇部落格是寫給新手的,我就不介紹rtmp流的格式了,因為是直接使用rtmp的庫的,rtmp的格式對我的程式沒有什麼影響。對於h264視訊流和aac音訊格式簡要的介紹一下。 h264視訊格式: 下圖是h264的視訊序列,但是這樣描述的不太好(對我而

ubuntu下使用nginx和nginx-rtmp-module配置直播伺服器

本來準備在centos伺服器上搭建的,因為筆者工作系統是ubuntu,因此直接在本機上搭建,更方便快捷,配置過程比較簡單,記錄一下。 目錄 配置環境 安裝obs-studio開始第一次推流 安裝vlc播放器開始拉流 配置環境 配置環境 配

使用Nginx+nginx-rtmp-module+OBS搭建媒體伺服器

一、安裝Nginx 下載必備安裝包 建立安裝包存放資料夾 cd mkdir /usr/source #建立原始碼目錄 後面的原始碼都放在這個目錄 cd source yum -y install git #安裝git git clone https://github.

實現直接輸出h264直播rtmp伺服器

RTMP(Real Time Messaging Protocol)是常見的流媒體協議,用來傳輸音視訊資料,結合flash,廣泛用於直播、點播、聊天等應用,以及pc、移動、嵌入式等平臺,是做流媒體開發經常會接觸到的協議。我之前曾經寫過一篇文章“RTMP協議傳送H.264編碼及AAC編碼的音視

android平臺下基於ffmpeg採集Camera資料編碼成H.264RTMP伺服器

音視訊實踐學習 android全平臺編譯ffmpeg以及x264與fdk-aac實踐 ubuntu下使用nginx和nginx-rtmp-module配置直播推流伺服器 android全平臺編譯ffmpeg合併為單個庫實踐 android-studio使用c

Mac搭建nginx+rtmp伺服器,通過ffmpeg實現視訊

最近在研究關於直播方面的技術,中間遇到很多坑,在此記錄一下,以免再次跳坑 1.安裝Homebrew 開啟終端, 檢視是否已經安裝了Homebrew, 直接終端輸入命令 man brew 如果Mac已經安裝了, 會顯示一些命令的幫助資訊. 此時 輸入Q退出即可, 直接進

利用Nginx搭建RTMP視訊直播,點播伺服器,ffmpeg,回看

#下面的server是在http的一級配置標籤下的#上面的註釋對懂nginx的人是廢話,但是如果你不熟悉nginx,建議認真看看http{...# 這裡有一些其他的配置 server { listen 80;#埠 server_name rtmp-server;#設定http

ffmpeg多執行緒本地mp4 rtmph264+aac編碼

程式說明:使用了c++11的std執行緒,鎖,訊號量等東西,替換了pthread多執行緒。主要之前用windows下移植的linux發現多執行緒始終有問題,所以決定用原生的試試。不過現在想來,應該問題還是我佇列的設計問題。主要這裡有個坑,就是c語言for迴圈內部

iOS直播--Nginx伺服器搭建和RTMP,HLS實現

Nginx介紹Nginx ("engine x") 是一個高效能的HTTP和反向代理伺服器,也是一個IMAP/POP3/SMTP伺服器。Nginx是由Igor Sysoev為俄羅斯訪問量第二的Rambler.ru站點開發的,第一個公開版本0.1.0釋出於2004年10月

網頁顯示直播(監控)視訊 【ubuntu伺服器 (nginx+rtmp+jwplayer) 樹莓派(ffmpeg)】

阿里雲伺服器(ubuntu)搭建nginx-rtmp伺服器 此文章中不再採用windows的obs進行推流,而是採用樹莓派的ffmpeg進行推流 因此,樹莓派需要安裝 ffmpeg 在樹莓派中的 ffmpeg 推流命令(-t 10可以刪除,則一直不斷的進行推流)

FFMPEGRTMP伺服器命令

1、將檔案當作源推送到RTMP伺服器 ffmpeg -re -i localFile.mp4 -c copy -f flv rtmp://server/live/streamName 引數解釋 -r 以本地幀頻讀資料,主要用於模擬捕獲裝置。表示ffmpeg將按照幀率

NGINX-RTMP直播伺服器搭建-OBS錄製-VLC視訊流播放

網上關於視訊直播的資料還是挺多的,看了一些文章,自己也動手實踐了下。主要有三個步驟:(1)NginxRTMP伺服器搭建(2)視訊錄製推流器 (3)拉流器(播放器),有了這些就可以開始簡單視訊相關的直播了。對於延時什麼的,還需要深入去研究 ,以及如何進行視訊開發等後續再深入研究

基於LFLive實現rtmp到本地nginx伺服器

基於之前搭建的nginx + rtmp伺服器,現在結合LFLivekit,編碼獲取攝像頭視屏,麥克風音訊編碼推流 首先先將需要準備的東西下載下來整合到你的工程中去 在github上下載LFLivekit整合到你的工程中去 需要在工程中新增相應的frame

使用ffmpeg迴圈(迴圈讀取視訊檔案)送EasyDSS RTMP媒體伺服器的方法

需求 在做EasyDSS開發時,總是在測試推流效果。 有時候,我們想使用OBS進行推流測試,也可以,這很好。 以及其他RTMP推流工具。 但是,別忘了,還有ffmpeg這個神器。ffmpeg可以獲取各種視訊流,並推送給EasyDSS RTMP流媒體伺

ffmpeg rtmp nginx搭建的rtmp伺服器

1、利用nginx搭建的rtmp伺服器 下載nginx-rtmp-module模組,解壓 下載nginx,解壓 進入nginx目錄下,編譯安裝nginx支援rtmp流媒體配置 ./configure

安裝nginx伺服器用於rtmp(ios端)測試

今天本來週末,在家裡沒什麼事,這幾天正在研究直播的問題,對這個很感興趣,所以在自己的電腦上又重新搭建了一次環境,順便給大家記錄下安裝流程。 安裝nginx首先要確保已經安裝了homebrew。至於具體的安裝步驟很簡單,這裡都記錄下來各自的安裝命令。 1.安裝

javaCV開發詳解之4:轉器實現(也可作為本地收器、器,新增新增圖片及文字水印,視訊影象幀儲存),實現rtsp/rtmp/本地檔案轉發到rtmp媒體伺服器(基於javaCV-FFMPEG)

javaCV系列文章: 補充篇: 歡迎大家積極開心的加入討論群 javacpp-ffmpeg: 前言: 本章基於javaCV實現轉流器和收流器功能,測試採用監控rtsp地址轉發至rtmp伺服器地址 新增openCV儲存圖片功能。 補充: