1. 程式人生 > >將h.264裸碼流推送到RTMP伺服器

將h.264裸碼流推送到RTMP伺服器

  1. // SPS  
  2. 000000016742802995A014016E40  
  3. // PPS  
  4. 0000000168CE3880  
  5. // IFrame  
  6. 0000000165B8041014C038008B0D0D3A071.....  
  7. // PFrame  
  8. 0000000141E02041F8CDDC562BBDEFAD2F.....  

一般可以從IP攝像頭的sdk中拿到這種資料,一般sdk會使用如下介面:
  1. int device_read(char** pdata, int* psize, int* pdts, int* ppts);  

也有的攝像頭沒有B幀,所以dts和pts是一致的,所以後面的時間戳合併成一個:
  1. int device_read(char
    ** pdata, int* psize, int* timestamp);  

或者,使用回撥函式,當攝像頭編碼出h.264資料時回撥這個函式,格式和上面的也差不多。

本文描述瞭如何將拿到的h.264資料,通過RTMP協議釋出到RTMP伺服器,然後使用RTMP或者HLS播放。

srs-librtmp

顯然傳送h.264的資料得使用RTMP庫,rtmpdump提供的librtmp要求是flv/RTMP格式的資料,而srs-librtmp提供了介面直接傳送h.264資料。

例如:

  1. git clone https://github.com/winlinvip/simple-rtmp-server.git  

SRS目前有兩個分支,只有SRS2(即master分支)提供了h.264裸碼流傳送的功能,git clone之後要切換到這個分支:
  1. cd simple-rtmp-server/trunk  
  2. git checkout master  

如果你可以使用.h和.a庫,就可以直接編譯srs,可以看到生成了.h和.a檔案:
  1. ./configure --disable-all --with-librtmp && make &&   
  2. ls -lh objs/include/srs_librtmp.h objs/lib/srs_librtmp.a   

如果是需要將srs-librtmp匯出成一個.h和.cpp檔案,執行下面的命令,可以看到生成了.h和.cpp檔案:
  1. ./configure --export-librtmp-single=objs/srs-librtmp &&   
  2. ls -lh objs/srs-librtmp/srs_librtmp.h objs/srs-librtmp/srs_librtmp.cpp   
下面就可以編寫程式,讀取h.264裸碼流,然後呼叫srs-librtmp傳送出去了。

srs_h264_raw_publish

  1. // SPS  
  2. 000000016742802995A014016E40  
  3. // PPS  
  4. 0000000168CE3880  
  5. // IFrame  
  6. 0000000165B8041014C038008B0D0D3A071.....  
  7. // PFrame  
  8. 0000000141E02041F8CDDC562BBDEFAD2F.....  
下載這個h.264裸碼流檔案和例項檔案:
  1. wget https://raw.githubusercontent.com/winlinvip/simple-rtmp-server/master/trunk/research/librtmp/srs_h264_raw_publish.c -O objs/srs-librtmp/srs_h264_raw_publish.c --no-check-certificate &&  
  2. wget http://ossrs.net/srs.release/3rdparty/720p.h264.raw -O objs/srs-librtmp/720p.h264.raw  

檢視srs-librtmp目錄,應該是下面的結構:
  1. [[email protected] trunk]$ ls -lh  objs/srs-librtmp  
  2. total 5.8M  
  3. -rw-rw-r-- 1 winlin winlin 5.1M Nov  8 12:39 720p.h264.raw  
  4. -rw-rw-r-- 1 winlin winlin  633 Nov 16 10:32 example.c  
  5. -rw-rw-r-- 1 winlin winlin  87K Nov 16 10:36 srs_h264_raw_publish.c  
  6. -rw-rw-r-- 1 winlin winlin 557K Nov 16 10:32 srs_librtmp.cpp  
  7. -rw-rw-r-- 1 winlin winlin  20K Nov 16 10:32 srs_librtmp.h  

srs_h264_raw_publish.c讀取h.264裸碼流後,基本上讀取到的就是一個一個的h.264 annexb格式的包,參考read_h264_frame():
  1. // SPS  
  2. 000000016742802995A014016E40  
  3. // PPS  
  4. 0000000168CE3880  
  5. // IFrame  
  6. 0000000165B8041014C038008B0D0D3A071.....  
  7. // PFrame  
  8. 0000000141E02041F8CDDC562BBDEFAD2F.....  


連線RTMP和傳送的主要函式是:

  1. srs_rtmp_t rtmp = srs_rtmp_create(rtmp_url);  
  2. srs_simple_handshake(rtmp);  
  3. srs_connect_app("rtmp://127.0.0.1/live/livestream");  
  4. srs_publish_stream(rtmp);  
  5. while (!EOF) {  
  6.     read_h264_frame(&data, &size, &dts, &pts);  
  7.     srs_h264_write_raw_frames(rtmp, data, size, dts, pts);  
  8. }  

這幾個函式就可以把h.264裸碼流發出去了。

編譯和執行

若使用srs-librtmp匯出的單個.h和.cpp檔案,編譯和執行命令是:

  1. cd objs/srs-librtmp &&  
  2. gcc -g -O0 srs_h264_raw_publish.c srs_librtmp.cpp -o publisher -lstdc++ &&  
  3. ./publisher ./720p.h264.raw rtmp://ossrs.net/live/h264.raw  

播放的RTMP地址為:rtmp://ossrs.net/live/h264.raw,開啟下面的連結即可觀看流:

介面

其中有幾個錯誤可以忽略:

  • srs_h264_is_dvbsp_error:這個是因為IP攝像頭在每個I幀前都插入了SPS和PPS,所以在伺服器斷開重連時,重新呼叫srslibrtmp的連線和publish函式,不用考慮接下來的幀是否是sps和pps。但是RTMP要求第一個video包是sps/pps,所以srs-librtmp的srs_h264_write_raw_frame()會忽略sps和pps之前的video包,然後返回一個錯誤碼,使用者只要忽略這個錯誤碼即可。
  • srs_h264_is_duplicated_sps_error:這個因為IP攝像頭在每個I幀前都插入sps和pps,這些重複的sps和pps會導致hls頻繁的插入discontinue資訊,所以srs-librtmp只有在sps和pps都變化時才傳送新的sequence header包,而不是每次都發送。所以sps重複時會返回一個錯誤碼,使用者忽略這個錯誤即可。
  • srs_h264_is_duplicated_pps_error:這個和上面的錯誤一樣,是pps重複,使用者忽略即可。

目前的介面宣告如下,最新的介面宣告以程式碼為準:

  1. /** 
  2. * write h.264 raw frame over RTMP to rtmp server. 
  3. * @param frames the input h264 raw data, encoded h.264 I/P/B frames data. 
  4. *       frames can be one or more than one frame, 
  5. *       each frame prefixed h.264 annexb header, by N[00] 00 00 01, where N>=0,  
  6. *       for instance, frame = header(00 00 00 01) + payload(67 42 80 29 95 A0 14 01 6E 40) 
  7. *       about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211. 
  8. * @paam frames_size the size of h264 raw data.  
  9. *       assert frames_size > 0, at least has 1 bytes header. 
  10. * @param dts the dts of h.264 raw data. 
  11. * @param pts the pts of h.264 raw data. 
  12.  
  13. * @remark, user should free the frames. 
  14. * @remark, the tbn of dts/pts is 1/1000 for RTMP, that is, in ms. 
  15. * @remark, cts = pts - dts 
  16. * @remark, use srs_h264_startswith_annexb to check whether frame is annexb format. 
  17. * @example /trunk/research/librtmp/srs_h264_raw_publish.c 
  18. * @see https://github.com/winlinvip/simple-rtmp-server/issues/66 
  19.  
  20. * @return 0, success; otherswise, failed. 
  21. *       for dvbsp error, @see srs_h264_is_dvbsp_error(). 
  22. *       for duplictated sps error, @see srs_h264_is_duplicated_sps_error(). 
  23. *       for duplictated pps error, @see srs_h264_is_duplicated_pps_error(). 
  24. */
  25. /** 
  26. For the example file:  
  27.     http://winlinvip.github.io/srs.release/3rdparty/720p.h264.raw 
  28. The data sequence is: 
  29.     // SPS 
  30.     000000016742802995A014016E40 
  31.     // PPS 
  32.     0000000168CE3880 
  33.     // IFrame 
  34.     0000000165B8041014C038008B0D0D3A071..... 
  35.     // PFrame 
  36.     0000000141E02041F8CDDC562BBDEFAD2F..... 
  37. User can send the SPS+PPS, then each frame: 
  38.     // SPS+PPS 
  39.     srs_h264_write_raw_frames('000000016742802995A014016E400000000168CE3880', size, dts, pts) 
  40.     // IFrame 
  41.     srs_h264_write_raw_frames('0000000165B8041014C038008B0D0D3A071......', size, dts, pts) 
  42.     // PFrame 
  43.     srs_h264_write_raw_frames('0000000141E02041F8CDDC562BBDEFAD2F......', size, dts, pts) 
  44. User also can send one by one: 
  45.     // SPS 
  46.     srs_h264_write_raw_frames('000000016742802995A014016E4', size, dts, pts) 
  47.     // PPS 
  48.     srs_h264_write_raw_frames('00000000168CE3880', size, dts, pts) 
  49.     // IFrame 
  50.     srs_h264_write_raw_frames('0000000165B8041014C038008B0D0D3A071......', size, dts, pts) 
  51.     // PFrame 
  52.     srs_h264_write_raw_frames('0000000141E02041F8CDDC562BBDEFAD2F......', size, dts, pts)  
  53. */
  54. externint srs_h264_write_raw_frames(srs_rtmp_t rtmp,   
  55.     char* frames, int frames_size, u_int32_t dts, u_int32_t pts  
  56. );  
  57. /** 
  58. * whether error_code is dvbsp(drop video before sps/pps/sequence-header) error. 
  59. * 
  60. * @see https://github.com/winlinvip/simple-rtmp-server/issues/203 
  61. * @example /trunk/research/librtmp/srs_h264_raw_publish.c 
  62. * @remark why drop video? 
  63. *       some encoder, for example, ipcamera, will send sps/pps before each IFrame, 
  64. *       so, when error and reconnect the rtmp, the first video is not sps/pps(sequence header), 
  65. *       this will cause SRS server to disable HLS. 
  66. */
  67. extern srs_h264_bool srs_h264_is_dvbsp_error(int error_code);  
  68. /** 
  69. * whether error_code is duplicated sps error. 
  70.  
  71. * @see https://github.com/winlinvip/simple-rtmp-server/issues/204 
  72. * @example /trunk/research/librtmp/srs_h264_raw_publish.c 
  73. */
  74. extern srs_h264_bool srs_h264_is_duplicated_sps_error(int error_code);  
  75. /** 
  76. * whether error_code is duplicated pps error. 
  77.  
  78. * @see https://github.com/winlinvip/simple-rtmp-server/issues/204 
  79. * @example /trunk/research/librtmp/srs_h264_raw_publish.c 
  80. */
  81. extern srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code);  

srs-librtmp會將h.264包打包成RTMP包,不用使用者每次都要處理。

http://blog.csdn.net/win_lin/article/details/41170653

相關推薦

h.264RTMP伺服器

// SPS   000000016742802995A014016E40   // PPS   0000000168CE3880   // IFrame   0000000165B8041014C038008B0D0D3A071.....   // PFram

利用mp4v2實現H.264實時封裝

1. mp4v2庫配置、交叉編譯 mp4v2 庫是一個專用於處理mp4容器的開源專案,其使用c++編寫,並提供c語言介面。 下載mp4v2庫的最新程式碼以後,使用標準linux configure

Wireshark Lua: 一個從RTP抓包裡匯出H.264 Payload,變成264檔案(xxx.264)的Wireshark外掛

     抓取一個包含H.264 Payload RTP包的SIP會話或RTSP會話後,用Wireshark的Play功能只能播放聲音,不能播放視訊。把RTP payload直接匯出成檔案後也是不能直接播放的,因為H.264 over RTP封包是符合RFC3984規範的,

H.264視訊解析

原理 H.264原始碼流(又稱為“裸流”)是由一個一個的NALU組成的。他們的結構如下圖所示。 其中每個NALU之間通過startcode(起始碼)進行分隔,起始碼分成兩種:0x00000

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

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

如何h.264視訊直播rtmp server

如果要單純的以h.264的碼流推送攝像頭的視訊到rtmp server(ip:127.0.0.1),可以這樣: ffmpeg -f video4linux2 -vcodec libx264 -vpre default  -s 320x240 -i /dev/video0

git在遠端伺服器建立專案並原生代伺服器

1.進入到遠端伺服器 ssh name (name:遠端伺服器地址) 2.進入以後新建一個空的倉庫 git init --bare name (name:倉庫的名稱) 3.退出遠端伺服器 exit 4.到需要提交的檔案的目錄裡面(命令:cd) 5.在需要提交的檔

H.264檔案中獲取每一幀資料

    測試解碼器效能時,最常用的無非是向解碼器中推送碼流。     之前封裝了一個avc的解碼器,想做一個測試,讀取H.264裸流檔案將碼流定期定時推送到解碼器。     測試其實很簡單:     1.瞭解H.264裸流檔案的構成     2.解析H.264裸流檔案

ffmpeg視訊檔案釋出為RTSP的命令

這幾天在研究如何使用ffmpeg向rtsp伺服器推送視訊檔案的問題,通過上網查詢得到的命令基本都是:ffmpeg -re -i *.mp4 -vcodec libx264 -acodec copy -f rtsp rtsp://ip:port/*.sdp,  但是使用該命

使用FFmpeg的SDK庫實現H.264封裝進MP4檔案時全域性SPS、PPS與中SPS、PPS衝突的問題

一、問題1. 使用FFmpeg的SDK庫實現將H.264流封裝進MP4檔案的原始碼大致如下:char* filename = "./test.mp4"AVOutputFormat *fmt;AVStream* video_st;AVFormatContext *av_cont

h264視訊流,aac音訊(g711a轉rtmp伺服器

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

極光OA信用盤源下載demo在android studio中無法運行

occurred eclipse message user 極光 ××× 本機 try 成本 錯誤內容:OA信用盤源碼下載論壇:haozbbs.com Q1446595067 Android Studio導入項目報錯:Error:Could not determine th

微信生成帶引數的二維,合成海報,掃小程式

背景:公司開發的小程式要實現將產品免費給使用者試用的功能,使用者登入小程式後在產品頁可以將產品以二維碼海報的方式分享給微信好友,好友掃碼後跳轉公眾號,關注後公眾號推送小程式,點選小程式後跳轉到小程式中的相應產品頁面。 如下圖: 這裡涉及到兩個重要的環節: 1.生成帶

如何本地的檔案或者專案到遠端倉庫github

如果你需要使用git將本地的專案或者檔案推送到github,那麼你就需要安裝一個git客戶端,並且註冊一個github的賬號。 如何安裝git客戶端在windows筆記本,可以看我的這篇文章git客戶端下載和安裝以及配置,你只需要一路next,並且安裝完客戶端以

h.264視訊流封裝成flv格式檔案(二.開始動手)

封裝前要先了解下h.264格式,只需要知道一點點就可以了,我看了h.264官方文件,我靠,3百多頁,還全是中文,什麼,是中文?既然是中文的我就勉強看下吧,我靠,看起來還很複雜的,果斷不看了,不需要,也沒時間,我又不做解碼,這東西具體步驟資料又少,基本都是那一兩篇轉來轉去,這還要感謝我上一篇提到的那個連線的兄

EasyRTMP手機直播rtmpflash無法正常播放問題

問題簡介 EasyRTMP是EasyDarwin團隊開發的一套簡單易用的RTMP推送SDK。本文想講述下開發過程中遇到的一個問題。問題的現象是使用EasyRTMP推送音視訊流到自己搭建的nginx-rtmp伺服器,使用ffplay和vlc播放器都

V4L2視訊採集與H.264編碼原始碼大放:Linux視訊採集與編碼(三)

這幾天的努力也算沒有白費,現在我將貢獻出我的成果,當然程式碼很大一部分都不是我寫的。 V4L2視訊採集我參考了V4L2官方原始碼,H.264編碼我使用了開源編碼庫x264,並參考了網上的一些例子。 但

最簡單的基於FFmpeg的器(以RTMP為例)

由於工作一部分工作是作為流媒體伺服器的程式設計師。所以自己那塊也算是處理了推流器的一塊程式碼吧。 這邊是從網上轉載的文章,原文:http://blog.csdn.net/leixiaohua1020/article/details/46890487 =========

FFMPEG 抓RTSPRTMP至FMS伺服器

關於現在一般監控攝像頭一般有rtsp流的功能,這裡是相關應用 安裝FMS伺服器 下載地址可以自行百度 flash media server 這裡用5.0版本的 下載ffmpeg 配置系統的環境變數,這個不同系統配置方法不同,windows的話 右

使用ffmpeg介面h.264解碼為YUV

引數傳遞和解析 同編碼器類似,解碼器也需要傳遞引數。不過相比編碼器,解碼器在執行時所需要的大部分資訊都包含在輸入碼流中,因此輸入引數一般只需要指定一個待解碼的視訊碼流檔案即可 按照要求初始化需要的FFMpeg結構 第一步: 獲取解碼器指