• 摘要:一为什么要提取h264帧?  因为我们经常需要从事实流中截取一些画面,用于变动的封面,安全,鉴黄等用处。二从nginx_rtmp中怎么提取一帧h264帧呢?  前面我们讲过如何提取sps和pps,这里只需要提取一个nalu,如果是I帧就手动把sps和pps添加到帧前面就可以了。三提取实现代码  可以参照前面sps和pps提取,  从ngx_rtmp_live_av(ngx_rtmp_session
  • 一 为什么要提取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音频的这里就不详细描述了,与上面类似



    更多开源流媒体技术,请关注我们的微信:EasyDarwin