将h.264裸码流推送到RTMP服务器

h.264裸码流的格式,参考“H.264-AVC-ISO_IEC_14496-10.pdf, page 211.”,这个文档的下载地址:https://github.com/winlinvip/simple-rtmp-server/tree/develop/trunk/doc/H.264-AVC-ISO_IEC_14496-10.pdf

一个录制的h.264裸码流文件:http://winlinvip.github.io/srs.release/3rdparty/720p.h264.raw,或者:http://ossrs.net/srs.release/3rdparty/720p.h264.raw,里面的格式是annexb格式:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // SPS  
  2. 000000016742802995A014016E40  
  3. // PPS  
  4. 0000000168CE3880  
  5. // IFrame  
  6. 0000000165B8041014C038008B0D0D3A071.....  
  7. // PFrame  
  8. 0000000141E02041F8CDDC562BBDEFAD2F.....  

一般可以从IP摄像头的sdk中拿到这种数据,一般sdk会使用如下接口:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int device_read(char** pdata, int* psize, int* pdts, int* ppts);  

也有的摄像头没有B帧,所以dts和pts是一致的,所以后面的时间戳合并成一个:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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数据。

srs-librtmp是SRS服务器提供的客户端库,SRS项目参考:https://github.com/winlinvip/simple-rtmp-server

srs-librtmp的wiki参考:https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_SrsLibrtmp#publish-h264-raw-data

对应的srs的bug参考:https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521

使用git clone下来,可以选择github源,或者国内的其他镜像源,参考:https://github.com/winlinvip/simple-rtmp-server#mirrors

例如:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. git clone https://github.com/winlinvip/simple-rtmp-server.git  

SRS目前有两个分支,只有SRS2(即master分支)提供了h.264裸码流发送的功能,git clone之后要切换到这个分支:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. cd simple-rtmp-server/trunk  
  2. git checkout master  

如果你可以使用.h和.a库,就可以直接编译srs,可以看到生成了.h和.a文件:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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文件:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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

SRS提供了例子读取录制的h.264文件并发布到RTMP服务器:https://github.com/winlinvip/simple-rtmp-server/tree/develop/trunk/research/librtmp/srs_h264_raw_publish.c

录制的h.264裸码流文件:http://winlinvip.github.io/srs.release/3rdparty/720p.h264.raw,或者:http://ossrs.net/srs.release/3rdparty/720p.h264.raw,里面的格式是annexb格式:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // SPS  
  2. 000000016742802995A014016E40  
  3. // PPS  
  4. 0000000168CE3880  
  5. // IFrame  
  6. 0000000165B8041014C038008B0D0D3A071.....  
  7. // PFrame  
  8. 0000000141E02041F8CDDC562BBDEFAD2F.....  


下载这个h.264裸码流文件和实例文件:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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目录,应该是下面的结构:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. [winlin@dev6 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():

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // SPS  
  2. 000000016742802995A014016E40  
  3. // PPS  
  4. 0000000168CE3880  
  5. // IFrame  
  6. 0000000165B8041014C038008B0D0D3A071.....  
  7. // PFrame  
  8. 0000000141E02041F8CDDC562BBDEFAD2F.....  


连接RTMP和发送的主要函数是:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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文件,编译和运行命令是:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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,打开下面的链接即可观看流:

http://www.ossrs.net/srs.release/trunk/research/players/srs_player.html?server=ossrs.net&vhost=ossrs.net&stream=h264.raw&autostart=true

接口

srs-librtmp定义的h.264裸码流发送接口使用参考:https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521

其中有几个错误可以忽略:

  • 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重复,用户忽略即可。

目前的接口声明如下,最新的接口声明以代码为准:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  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. extern int 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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Linux上使用FFmpeg推RTMPh264/PC的步骤如下: 1. 首先,确保你已经安装了FFmpeg。如果没有安装,可以使用以下命令进行安装: ``` sudo apt-get install ffmpeg ``` 2. 使用以下命令将h264视频和PCMU音频推送RTMP服务器: ``` ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -tune zerolatency -b:v 2000k -maxrate 2000k -bufsize 2000k -pix_fmt yuv420p -g 50 -c:a pcm_mulaw -ar 8000 -f flv rtmp://server/live/stream ``` 解释一下上述命令的参数: - `-re`:以实时速度读取输入文件。 - `-i input.mp4`:指定输入文件的路径和名称。 - `-c:v libx264`:使用libx264编码器进行视频编码。 - `-preset veryfast`:设置视频编码速度为veryfast。 - `-tune zerolatency`:设置视频编码器为零延迟模式。 - `-b:v 2000k`:设置视频的比特率为2000k。 - `-maxrate 2000k`:设置视频的最大比特率为2000k。 - `-bufsize 2000k`:设置视频的缓冲区大小为2000k。 - `-pix_fmt yuv420p`:设置像素格式为yuv420p。 - `-g 50`:设置关键帧间隔为50帧。 - `-c:a pcm_mulaw`:使用PCM mu-law编码器进行音频编码。 - `-ar 8000`:设置音频的采样率为8000Hz。 - `-f flv`:指定输出格式为FLV。 - `rtmp://server/live/stream`:指定RTMP服务器的URL和名称。 请根据你的实际情况修改输入文件的路径和名称,以及RTMP服务器的URL和名称。 希望以上信息对你有帮助!如果你还有其他问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值