SRS提供的librtmp
librtmp是一個客戶端庫,好像是rtmpdump提供的一個客戶端RTMP庫。
應用場景
librtmp的主要應用場景包括:
- 播放RTMP流:譬如rtmpdump,將服務器的流讀取后保存為flv文件。
- 推流:提供推流到RTMP服務器。
- 基于同步阻塞socket,客戶端用可以了。
- arm:編譯出來給arm-linux用,譬如某些設備上,采集后推送到RTMP服務器。
- 不支持直接發布h.264裸碼流,而srs-librtmp支持,參考:publish-h264-raw-data
備注:關于鏈接ssl,握手協議,簡單握手和復雜握手,參考RTMP握手協議
備注:ARM上使用srs-librtmp需要交叉編譯,參考srs-arm,即使用交叉編譯環境編譯srs-librtmp(可以不依賴于其他庫,ssl/st都不需要)
librtmp做Server
群里有很多人問,librtmp如何做server,實在不勝其騷擾,所以單列一章。
server的特點是會有多個客戶端連接,至少有兩個:一個推流連接,一個播放連接。所以server有兩種策略:
- 每個連接一個線程或進程:像apache。這樣可以用同步socket來收發數據(同步簡單)。壞處就是沒法支持很高并發,1000個已經到頂了,得開1000個線程/進程啊。
- 使用單進程,但是用異步socket:像nginx這樣。好處就是能支持很高并發。壞處就是異步socket麻煩。
rtmpdump提供的librtmp,當然是基于同步socket的。所以使用librtmp做server,只能采取第一種方法,即用多線程處理多個連接。多線程多麻煩啊!要鎖,同步,而且還支持不了多少個。
librtmp的定位就是客戶端程序,偏偏要超越它的定位去使用,這種大約只有中國人才能這樣“無所畏懼”。
嵌入式設備上做rtmp server,當然可以用srs/crtmpd/nginx-rtmp,輪也輪不到librtmp。
SRS為何提供librtmp
srs提供的客戶端srs-librtmp的定位和librtmp不一樣,主要是:
- librtmp的代碼確實很爛,毋庸置疑,典型的代碼堆積。
- librtmp接口定義不良好,這個對比srs就可以看出,使用起來得看實現代碼。
- 沒有實例:接口的使用最好提供實例,srs提供了publish/play/rtmpdump實例。
- 最小依賴關系:srs調整了模塊化,只取出了core/kernel/rtmp三個模塊,其他代碼沒有編譯到srs-librtmp中,避免了冗余。
- 最少依賴庫:srs-librtmp只依賴c/c++標準庫(若需要復雜握手需要依賴openssl,srs也編譯出來了,只需要加入鏈接即可)。
- 不依賴st:srs-librtmp使用同步阻塞socket,沒有使用st(st主要是服務器處理并發需要)。
- SRS提供了測速函數,直接調用srs-librtmp就可以完成到服務器的測速。參考:Bandwidth Test
- SRS提供了日志接口,可以獲取服務器端的信息,譬如版本,對應的session id。參考:Tracable log
- 支持直接發布h.264裸碼流,參考:publish-h264-raw-data
- SRS可以直接導出一個srs-librtmp的project,編譯成.h和.a使用。或者導出為.h和.cpp,一個大文件。參考:export srs librtmp
一句話,srs為何提供客戶端開發庫?因為rtmp客戶端開發不方便,不直觀,不簡潔。
Export Srs Librtmp
SRS在2.0提供了導出srs-librtmp的編譯選項,可以將srs-librtmp單獨導出為project,單獨編譯生成.h和.a,方便在linux和windows平臺編譯。
使用方法,導出為project,可以make成.h和.a:
dir=/home/winlin/srs-librtmp && rm -rf $dir && ./configure --export-librtmp-project=$dir && cd $dir && make && ./objs/research/librtmp/srs_play rtmp://ossrs.net/live/livestreamSRS將srs-librtmp導出為獨立可以make的項目,生成.a靜態庫和.h頭文件,以及生成了srs-librtmp的所有實例。
還可以直接導出為一個文件,提供了簡單的使用實例,其他實例參考research的其他例子:
dir=/home/winlin/srs-librtmp && rm -rf $dir && ./configure --export-librtmp-single=$dir && cd $dir && gcc example.c srs_librtmp.cpp -g -O0 -lstdc++ -o example && strip example && ./example備注:導出目錄支持相對目錄和絕對目錄。
編譯srs-librtmp
編譯SRS時,會自動編譯srs-librtmp,譬如:
./configure --with-librtmp --without-ssl編譯會生成srs-librtmp和對應的實例。
備注:支持librtmp只需要打開--with-librtmp,但推薦打開--without-ssl,不依賴于ssl,對于一般客戶端(不需要模擬flash)足夠了。這樣srs-librtmp不依賴于任何其他庫,在x86/x64/arm等平臺都可以編譯和運行
備注:就算打開了--with-ssl,srslibrtmp也只提供simple_handshake函數,不提供complex_handshake函數。所以推薦關閉ssl,不依賴于ssl,沒有實際的用處。
SRS編譯成功后,用戶就可以使用這些庫開發
Windows下編譯srs-librtmp
srs-librtmp可以只依賴于c++和socket,可以在windows下編譯。
先使用SRS導出srs-librtmp,然后在vs中編譯,參考:export srs librtmp
使用了一些linux的頭文件,需要做一些portal。
注意:srs-librtmp客戶端推流和抓流,不需要ssl庫。代碼都是c++/stl,網絡部分用的是同步socket。
數據格式
srs-librtmp提供了一系列接口函數,就數據按照一定格式發送到服務器,或者從服務器讀取音視頻數據。
數據接口包括:
- 讀取數據包:int srs_read_packet(int* type, u_int32_t* timestamp, char** data, int* size)
- 發送數據包:int srs_write_packet(int type, u_int32_t timestamp, char* data, int size)
- 發送h.264裸碼流:參考publish-h264-raw-data
接口接受的的數據(char* data),音視頻數據,格式為flv的Video/Audio數據。參考srs的doc目錄的規范文件video_file_format_spec_v10_1.pdf
- 音頻數據格式參考:E.4.2.1 AUDIODATA,p76,譬如,aac編碼的音頻數據。
- 視頻數據格式參考:E.4.3.1 VIDEODATA,p78,譬如,h.264編碼的視頻數據。
- 腳本數據格式參考:E.4.4.1 SCRIPTDATA,p80,譬如,onMetadata,流的信息(寬高,碼率,分辨率等)
數據類型(int type)定義如下(E.4.1 FLV Tag,page 75):
- 音頻:8 = audio,宏定義:SRS_RTMP_TYPE_AUDIO
- 視頻:9 = video,宏定義:SRS_RTMP_TYPE_VIDEO
- 腳本數據:18 = script data,宏定義:SRS_RTMP_TYPE_SCRIPT
其他的數據,譬如時間戳,都是通過參數接受和發送。
另外,文檔其他重要信息:
- flv文件頭格式:E.2 The FLV header,p74。
- flv文件主體格式:E.3 The FLV File Body,p74。
- tag頭格式:E.4.1 FLV Tag,p75。
使用flv格式的原因:
- flv的格式足夠簡單。
- ffmpeg也是用的這種格式
- 收到流后加上flv tag header,就可以直接保存為flv文件
- 從flv文件解封裝數據后,只要將tag的內容給接口就可以,flv的tag頭很簡單。
Publish H.264 Raw Data
SRS-librtmp支持發布h.264裸碼流,直接調用api即可將數據發送給SRS。
參考博客:http://blog.csdn.net/win_lin/article/details/41170653
總結起來就是說,H264的裸碼流(幀)轉換RTMP時:
加了一個直接發送h264裸碼流的接口:
/** * write h.264 raw frame over RTMP to rtmp server. * @param frames the input h264 raw data, encoded h.264 I/P/B frames data. * frames can be one or more than one frame, * each frame prefixed h.264 annexb header, by N[00] 00 00 01, where N>=0, * for instance, frame = header(00 00 00 01) + payload(67 42 80 29 95 A0 14 01 6E 40) * about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211. * @paam frames_size the size of h264 raw data. * assert frames_size > 0, at least has 1 bytes header. * @param dts the dts of h.264 raw data. * @param pts the pts of h.264 raw data. * * @remark, user should free the frames. * @remark, the tbn of dts/pts is 1/1000 for RTMP, that is, in ms. * @remark, cts = pts - dts * * @return 0, success; otherswise, failed. */ extern int srs_h264_write_raw_frames(srs_rtmp_t rtmp, char* frames, int frames_size, u_int32_t dts, u_int32_t pts );對于例子中的h264流文件:http://winlinvip.github.io/srs.release/3rdparty/720p.h264.raw
里面的數據是:
// SPS 000000016742802995A014016E40 // PPS 0000000168CE3880 // IFrame 0000000165B8041014C038008B0D0D3A071..... // PFrame 0000000141E02041F8CDDC562BBDEFAD2F.....調用時,可以SPS和PPS一起發,幀一次發一個:
// SPS+PPS srs_h264_write_raw_frame('000000016742802995A014016E400000000168CE3880', size, dts, pts) // IFrame srs_h264_write_raw_frame('0000000165B8041014C038008B0D0D3A071......', size, dts, pts) // PFrame srs_h264_write_raw_frame('0000000141E02041F8CDDC562BBDEFAD2F......', size, dts, pts)調用時,可以一次發一次frame也行:
// SPS srs_h264_write_raw_frame('000000016742802995A014016E4', size, dts, pts) // PPS srs_h264_write_raw_frame('00000000168CE3880', size, dts, pts) // IFrame srs_h264_write_raw_frame('0000000165B8041014C038008B0D0D3A071......', size, dts, pts) // PFrame srs_h264_write_raw_frame('0000000141E02041F8CDDC562BBDEFAD2F......', size, dts, pts)參考:https://github.com/ossrs/srs/issues/66#issuecomment-62240521
使用:https://github.com/ossrs/srs/issues/66#issuecomment-62245512
Publish Audio Raw Stream
srs-librtmp提供了api可以將音頻裸碼流發布到SRS,支持AAC ADTS格式。
API定義如下:
/** * write an audio raw frame to srs. * not similar to h.264 video, the audio never aggregated, always * encoded one frame by one, so this api is used to write a frame. * * @param sound_format Format of SoundData. The following values are defined: * 0 = Linear PCM, platform endian * 1 = ADPCM * 2 = MP3 * 3 = Linear PCM, little endian * 4 = Nellymoser 16 kHz mono * 5 = Nellymoser 8 kHz mono * 6 = Nellymoser * 7 = G.711 A-law logarithmic PCM * 8 = G.711 mu-law logarithmic PCM * 9 = reserved * 10 = AAC * 11 = Speex * 14 = MP3 8 kHz * 15 = Device-specific sound * Formats 7, 8, 14, and 15 are reserved. * AAC is supported in Flash Player 9,0,115,0 and higher. * Speex is supported in Flash Player 10 and higher. * @param sound_rate Sampling rate. The following values are defined: * 0 = 5.5 kHz * 1 = 11 kHz * 2 = 22 kHz * 3 = 44 kHz * @param sound_size Size of each audio sample. This parameter only pertains to * uncompressed formats. Compressed formats always decode * to 16 bits internally. * 0 = 8-bit samples * 1 = 16-bit samples * @param sound_type Mono or stereo sound * 0 = Mono sound * 1 = Stereo sound * @param timestamp The timestamp of audio. * * @example /trunk/research/librtmp/srs_aac_raw_publish.c * @example /trunk/research/librtmp/srs_audio_raw_publish.c * * @remark for aac, the frame must be in ADTS format. * @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, 1.A.2.2 ADTS * @remark for aac, only support profile 1-4, AAC main/LC/SSR/LTP, * @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 23, 1.5.1.1 Audio object type * * @see https://github.com/ossrs/srs/issues/212 * @see E.4.2.1 AUDIODATA of video_file_format_spec_v10_1.pdf * * @return 0, success; otherswise, failed. */ extern int srs_audio_write_raw_frame(srs_rtmp_t rtmp, char sound_format, char sound_rate, char sound_size, char sound_type,char* frame, int frame_size, u_int32_t timestamp );/** * whether aac raw data is in adts format, * which bytes sequence matches '1111 1111 1111'B, that is 0xFFF. * @param aac_raw_data the input aac raw data, a encoded aac frame data. * @param ac_raw_size the size of aac raw data. * * @reamrk used to check whether current frame is in adts format. * @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, 1.A.2.2 ADTS * @example /trunk/research/librtmp/srs_aac_raw_publish.c * * @return 0 false; otherwise, true. */ extern srs_bool srs_aac_is_adts(char* aac_raw_data, int ac_raw_size);/** * parse the adts header to get the frame size, * which bytes sequence matches '1111 1111 1111'B, that is 0xFFF. * @param aac_raw_data the input aac raw data, a encoded aac frame data. * @param ac_raw_size the size of aac raw data. * * @return failed when <=0 failed; otherwise, ok. */ extern int srs_aac_adts_frame_size(char* aac_raw_data, int ac_raw_size);調用實例參考#212,以及srs_audio_raw_publish.c和srs_aac_raw_publish.c,參考examples.
參考:https://github.com/ossrs/srs/issues/212#issuecomment-63755405
使用實例:https://github.com/ossrs/srs/issues/212#issuecomment-64164018
srs-librtmp Examples
SRS提供了實例sample,也會在編譯srs-librtmp時自動編譯:
- research/librtmp/srs_play.c:播放RTMP流實例。
- research/librtmp/srs_publish.c:推送RTMP流實例。
- research/librtmp/srs_ingest_flv.c:讀取本地FLV文件并推送RTMP流實例。
- research/librtmp/srs_ingest_mp4.c:讀取本地MP4文件并推送RTMP流實例。
- research/librtmp/srs_ingest_rtmp.c:讀取RTMP流并推送RTMP流實例。
- research/librtmp/srs_bandwidth_check.c:帶寬測試工具。
- research/librtmp/srs_flv_injecter.c:點播FLV關鍵幀注入文件。
- research/librtmp/srs_flv_parser.c:FLV文件查看工具。
- research/librtmp/srs_detect_rtmp.c:RTMP流檢測工具。
- research/librtmp/srs_h264_raw_publish.c:H.264裸碼流發布到SRS實例。
- research/librtmp/srs_audio_raw_publish.c: Audio裸碼流發布到SRS實例。
- research/librtmp/srs_aac_raw_publish.c: Audio AAC ADTS裸碼流發布到SRS實例。
- research/librtmp/srs_rtmp_dump.c: 將RTMP流錄制成flv文件實例。
- ./objs/srs_ingest_hls: 將HLS流采集成RTMP推送給SRS。
運行實例
啟動SRS:
make && ./objs/srs -c srs.conf推流實例:
make && ./objs/research/librtmp/objs/srs_publish rtmp://127.0.0.1:1935/live/livestream備注:推流實例發送的視頻數據不是真正的視頻數據,實際使用時,譬如從攝像頭取出h.264裸碼流,需要封裝成接口要求的數據,然后調用接口發送出去。或者直接發送h264裸碼流。
播放實例:
make && ./objs/research/librtmp/objs/srs_play rtmp://ossrs.net/live/livestreamsuck rtmp stream like rtmpdump總結
以上是生活随笔為你收集整理的SRS提供的librtmp的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shell编程报错:“syntax er
- 下一篇: SRS-DOLPHIN