hi3516 srs rtmp h264


原文链接: hi3516 srs rtmp h264

将h.264裸码流推送到RTMP服务器 - 试客网

本文主要是基于srs开放实现的rtmp协议源码进行推送H264裸码流。

1、建立rtmp连接(初始化阶段)

const char* rtmp_url = "rtmp://172.19.33.115:1935/live/livestream";
srs_rtmp_t rtmp;
{

//目前一路 进行url创建和握手
rtmp = srs_rtmp_create(rtmp_url);

if (srs_rtmp_handshake(rtmp) != 0) {
    MessageBox("simple handshake failed.");
    //goto rtmp_destroy;
}
srs_human_trace("simple handshake success");

if (srs_rtmp_connect_app(rtmp) != 0) {
    MessageBox("connect vhost/app failed.");
    //goto rtmp_destroy;
}
srs_human_trace("connect vhost/app success");

if (srs_rtmp_publish_stream(rtmp) != 0) {
    MessageBox("publish stream failed.");
    //goto rtmp_destroy;
}
srs_human_trace("publish stream success");

}

2、发送裸流码

{

static int pts = 0;
static int dts = 0;

if (pRawFrameInfo->uiFrameType == 1 || pRawFrameInfo->uiFrameType == 5 || pRawFrameInfo->uiFrameType == 7 || pRawFrameInfo->uiFrameType == 8)//7为sps 8为pps 5为I帧 1为P帧
{
    if(NULL != rtmp)
    {
        srs_h264_write_raw_frames(rtmp, (char*)pBuf, uiBufSize, dts, pts);//pBuf是H264裸码流数据,uiBufSize是码流大小
        dts += 1000 / 25;
        pts = dts;
    }
}

}

3、资源销毁

srs_rtmp_destroy(rtmp);
4、最后附上rtmp协议实现源码下载路径,将该文件引入到自己的工程,即可相关函数调用

https://download.csdn.net/download/zzqgtt/10598373
————————————————
版权声明:本文为CSDN博主「zzqgtt」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zzqgtt/article/details/81603543





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

<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-3019150162.css">

<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-3019150162.css">

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格式:

```s
// SPS
000000016742802995A014016E40
// PPS
0000000168CE3880
// IFrame
0000000165B8041014C038008B0D0D3A071.....
// PFrame
0000000141E02041F8CDDC562BBDEFAD2F.....

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

int device_read(char** pdata, int* psize, int* pdts, int* ppts);

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

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

例如:

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

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

cd simple-rtmp-server/trunk
git checkout master

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

./configure --disable-all --with-librtmp && make && 
ls -lh objs/include/srs_librtmp.h objs/lib/srs_librtmp.a

如果是需要将srs-librtmp导出成一个.h和.cpp文件,执行下面的命令,可以看到生成了.h和.cpp文件:

./configure --export-librtmp-single=objs/srs-librtmp && 
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格式:

// SPS
000000016742802995A014016E40
// PPS
0000000168CE3880
// IFrame
0000000165B8041014C038008B0D0D3A071.....
// PFrame
0000000141E02041F8CDDC562BBDEFAD2F.....

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

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 &&
wget http://ossrs.net/srs.release/3rdparty/720p.h264.raw -O objs/srs-librtmp/720p.h264.raw

查看srs-librtmp目录,应该是下面的结构:

[winlin@dev6 trunk]$ ls -lh  objs/srs-librtmp
total 5.8M
-rw-rw-r-- 1 winlin winlin 5.1M Nov  8 12:39 720p.h264.raw
-rw-rw-r-- 1 winlin winlin  633 Nov 16 10:32 example.c
-rw-rw-r-- 1 winlin winlin  87K Nov 16 10:36 srs_h264_raw_publish.c
-rw-rw-r-- 1 winlin winlin 557K Nov 16 10:32 srs_librtmp.cpp
-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():

// SPS
000000016742802995A014016E40
// PPS
0000000168CE3880
// IFrame
0000000165B8041014C038008B0D0D3A071.....
// PFrame
0000000141E02041F8CDDC562BBDEFAD2F.....

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

srs_rtmp_t rtmp = srs_rtmp_create(rtmp_url);
srs_simple_handshake(rtmp);
srs_connect_app("rtmp://127.0.0.1/live/livestream");
srs_publish_stream(rtmp);
while (!EOF) {
    read_h264_frame(&data, &size, &dts, &pts);
    srs_h264_write_raw_frames(rtmp, data, size, dts, pts);
}

这几个函数就可以把h.264裸码流发出去了。

编译和运行

若使用srs-librtmp导出的单个.h和.cpp文件,编译和运行命令是:

cd objs/srs-librtmp &&
gcc -g -O0 srs_h264_raw_publish.c srs_librtmp.cpp -o publisher -lstdc++ &&
./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重复,用户忽略即可。

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

/**
* 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
* @remark, use srs_h264_startswith_annexb to check whether frame is annexb format.
* @example /trunk/research/librtmp/srs_h264_raw_publish.c
* @see https://github.com/winlinvip/simple-rtmp-server/issues/66
* 
* @return 0, success; otherswise, failed.
*       for dvbsp error, @see srs_h264_is_dvbsp_error().
*       for duplictated sps error, @see srs_h264_is_duplicated_sps_error().
*       for duplictated pps error, @see srs_h264_is_duplicated_pps_error().
*/
/**
For the example file: 
    http://winlinvip.github.io/srs.release/3rdparty/720p.h264.raw
The data sequence is:
    // SPS
    000000016742802995A014016E40
    // PPS
    0000000168CE3880
    // IFrame
    0000000165B8041014C038008B0D0D3A071.....
    // PFrame
    0000000141E02041F8CDDC562BBDEFAD2F.....
User can send the SPS+PPS, then each frame:
    // SPS+PPS
    srs_h264_write_raw_frames('000000016742802995A014016E400000000168CE3880', size, dts, pts)
    // IFrame
    srs_h264_write_raw_frames('0000000165B8041014C038008B0D0D3A071......', size, dts, pts)
    // PFrame
    srs_h264_write_raw_frames('0000000141E02041F8CDDC562BBDEFAD2F......', size, dts, pts)
User also can send one by one:
    // SPS
    srs_h264_write_raw_frames('000000016742802995A014016E4', size, dts, pts)
    // PPS
    srs_h264_write_raw_frames('00000000168CE3880', size, dts, pts)
    // IFrame
    srs_h264_write_raw_frames('0000000165B8041014C038008B0D0D3A071......', size, dts, pts)
    // PFrame
    srs_h264_write_raw_frames('0000000141E02041F8CDDC562BBDEFAD2F......', size, dts, pts) 
*/
extern int srs_h264_write_raw_frames(srs_rtmp_t rtmp, 
    char* frames, int frames_size, u_int32_t dts, u_int32_t pts
);
/**
* whether error_code is dvbsp(drop video before sps/pps/sequence-header) error.
*
* @see https://github.com/winlinvip/simple-rtmp-server/issues/203
* @example /trunk/research/librtmp/srs_h264_raw_publish.c
* @remark why drop video?
*       some encoder, for example, ipcamera, will send sps/pps before each IFrame,
*       so, when error and reconnect the rtmp, the first video is not sps/pps(sequence header),
*       this will cause SRS server to disable HLS.
*/
extern srs_h264_bool srs_h264_is_dvbsp_error(int error_code);
/**
* whether error_code is duplicated sps error.
* 
* @see https://github.com/winlinvip/simple-rtmp-server/issues/204
* @example /trunk/research/librtmp/srs_h264_raw_publish.c
*/
extern srs_h264_bool srs_h264_is_duplicated_sps_error(int error_code);
/**
* whether error_code is duplicated pps error.
* 
* @see https://github.com/winlinvip/simple-rtmp-server/issues/204
* @example /trunk/research/librtmp/srs_h264_raw_publish.c
*/
extern srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code);

srs-librtmp会将h.264包打包成RTMP包,不用用户每次都要处理。

`