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.264推流到RTMP伺服器
音視訊實踐學習 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 rtmp推流,h264+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可以刪除,則一直不斷的進行推流)
FFMPEG推流到RTMP伺服器命令
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儲存圖片功能。 補充: