从nginx-rtmp中提取一帧h264帧

一 为什么要提取h264帧?
    因为我们经常需要从事实流中截取一些画面,用于变动的封面,安全,鉴黄等用处。
二 从nginx_rtmp中怎么提取一帧h264帧呢?
    前面我们讲过如何提取sps和pps,这里只需要提取一个nalu,如果是I帧就手动把sps和pps添加到帧前面就可以了。


三 提取实现代码
    可以参照前面sps和pps提取,
    从ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
                 ngx_chain_t *in)函数入手
    (1)首先我们合并ngx_chain_t *in 数据。
    ngx_str_t tmp_str = {0};
    tmp_str.data = (u_char*)ngx_palloc(s->connection->pool,MAX_TAG_SIZE);
    if(tmp_str.data == NULL)
{
return NGX_ERROR;
}


ngx_chain_t *tmp_in = NULL;
int in_len = 0;
int parse_offset = 0;
for(tmp_in = in;tmp_in;tmp_in = tmp_in->next)
{
memcpy(tmp_str.data + in_len,tmp_in->buf->pos,(int)(tmp_in->buf->last - tmp_in->buf->pos));
in_len += (int)(tmp_in->buf->last - tmp_in->buf->pos);
}
tmp_str.len = in_len; 


     这里内存申请,统一用nginx自带的内存池,这样方便管理,当连接结束的时候,nginx会自动释放这个内存池。
     s->connection->pool。
     但是由于我们这个一个tag占用内存太多,因此最好是用一次申请完就释放掉,或者最好直接保存到会话中,一次申请,永久使用。
     
    (2) 接下看看合并后的数据格式,
     17 01 00 00 50 00 00 8E 72 65 88 82 
     这是开头的几个字节的数据,从数据看就比较直观了。这个直接是rtmp video message的内容,去掉了messgae头的。也就是对应的flv文件的
video tag的body。17  1 表示keyframe,7表示AVC 。接下来的字节01是 AVCPacketType,然后是3个字节的CompositionTime,
然后是4个字节的nalu数据的长度。后面接着的是nalu数据体
    (3) 实现代码
      int nalu_type = tmp_str.data[9]&0x1f;
      if(nalu_type != 5)
{
return NGX_ERROR;
}//先得到nalu type 这里我们只提取I帧,
        
parse_offset += 5;
int nalu_len = ntohl(*(unsigned int *)((char *)tmp_str.data + parse_offset));
//解析nalu数据长度
        
memcpy(nalu->data + nalu->len,s->mjpeg_info.sps.data,s->mjpeg_info.sps.len);
nalu->len += s->mjpeg_info.sps.len;//追加sps到帧前面


memcpy(nalu->data + nalu->len,s->mjpeg_info.pps.data,s->mjpeg_info.pps.len);
nalu->len += s->mjpeg_info.pps.len;//追加pps到帧前面
   
  memcpy(nalu->data + nalu->len,nalu_head,4);
nalu->len += 4;//追加nalu 头到前面 0x00000001


memcpy(nalu->data + nalu->len,&tmp_str.data[9],tmp_str.len - 9);
nalu->len += (tmp_str.len - 9);//加上刚解析出来的nalu数据体
        注意:sps和pps也都是一种nalu。


四 如何提取aac音频的这里就不详细描述了,与上面类似


你可能感兴趣的:(h264,pps,sps,rtmp,nginx)