zoukankan      html  css  js  c++  java
  • H265 Rtp封包

       H265 Rtp封包可以参考Ffmpeg,具体实现在文件rtpenc_h264_hevc.c(4.0.1版本),核心的方法是nal_send

    这个方法有些绕,下面帖子具体的代码及注释。

    static void nal_send(AVFormatContext *s1, const uint8_t *buf, int size, int last)
    {
        RTPMuxContext *s = s1->priv_data;
        enum AVCodecID codec = s1->streams[0]->codecpar->codec_id;
    
        av_log(s1, AV_LOG_DEBUG, "Sending NAL %x of len %d M=%d
    ", buf[0] & 0x1F, size, last);
        if (size <= s->max_payload_size) {            //max_payload_size一般<= 1500
            int buffered_size = s->buf_ptr - s->buf;
            int header_size;
            int skip_aggregate = 0;
    
            if (codec == AV_CODEC_ID_H264) {
                header_size = 1;
                skip_aggregate = s->flags & FF_RTP_FLAG_H264_MODE0;
            } else {
                header_size = 2; //Hevc 头两个字节,第二个字节是0x01;第一个字节表示NAL Type,具体哪些类型可以参考Hevc.h
            }
    
            // Flush buffered NAL units if the current unit doesn't fit
            if (buffered_size + 2 + size > s->max_payload_size) {
                flush_buffered(s1, 0);
                buffered_size = 0;
            }
            // If we aren't using mode 0, and the NAL unit fits including the
            // framing (2 bytes length, plus 1/2 bytes for the STAP-A/AP marker),
            // write the unit to the buffer as a STAP-A/AP packet, otherwise flush
            // and send as single NAL.
            if (buffered_size + 2 + header_size + size <= s->max_payload_size &&
                !skip_aggregate) {
                if (buffered_size == 0) { //发送第一个数据包
                    if (codec == AV_CODEC_ID_H264) {
                        *s->buf_ptr++ = 24;
                    } else {
                        *s->buf_ptr++ = 48 << 1;   //hevc head flag  Header 为96 后面一般会跟VPS,PPS,SPS等信息,这些包字节少,可以放在一起一次发送VPS,PPS,SSP之间插入两个字节表示各类型包长度。
                        *s->buf_ptr++ = 1;
                    }
                }
                AV_WB16(s->buf_ptr, size);
                s->buf_ptr += 2; //数据包长度(两个字节表示)
                memcpy(s->buf_ptr, buf, size);
                s->buf_ptr += size;
                s->buffered_nals++;
            } else {
                flush_buffered(s1, 0);
                ff_rtp_send_data(s1, buf, size, last);
            }
        } else {
            int flag_byte, header_size;
            flush_buffered(s1, 0);
            if (codec == AV_CODEC_ID_H264 && (s->flags & FF_RTP_FLAG_H264_MODE0)) {
                av_log(s1, AV_LOG_ERROR,
                       "NAL size %d > %d, try -slice-max-size %d
    ", size,
                       s->max_payload_size, s->max_payload_size);
                return;
            }
            av_log(s1, AV_LOG_DEBUG, "NAL size %d > %d
    ", size, s->max_payload_size);
            if (codec == AV_CODEC_ID_H264) {    //视频类型为H264
                uint8_t type = buf[0] & 0x1F;
                uint8_t nri = buf[0] & 0x60;
    
                s->buf[0] = 28;        /* FU Indicator; Type = 28 ---> FU-A */
                s->buf[0] |= nri;
                s->buf[1] = type;
                s->buf[1] |= 1 << 7;
                buf  += 1;
                size -= 1;
    
                flag_byte   = 1;
                header_size = 2;
            } else {
                uint8_t nal_type = (buf[0] >> 1) & 0x3F;  // For hevc 
                /*
                 * create the HEVC payload header and transmit the buffer as fragmentation units (FU)
                 *
                 *    0                   1
                 *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
                 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 *   |F|   Type    |  LayerId  | TID |
                 *   +-------------+-----------------+
                 *
                 *      F       = 0
                 *      Type    = 49 (fragmentation unit (FU))
                 *      LayerId = 0
                 *      TID     = 1
                 */
                s->buf[0] = 49 << 1; //98只是Header,并不是真正意义上视频包类型。
                s->buf[1] = 1; //固定不变
    
                /*
                 *     create the FU header
                 *
                 *     0 1 2 3 4 5 6 7
                 *    +-+-+-+-+-+-+-+-+
                 *    |S|E|  FuType   |
                 *    +---------------+
                 *
                 *       S       = variable
                 *       E       = variable
                 *       FuType  = NAL unit type
                 */
                s->buf[2]  = nal_type; //该字节才表示真正意义上的数据类型
                /* set the S bit: mark as start fragment */
                s->buf[2] |= 1 << 7;  //第一个数据包分片
    
                /* pass the original NAL header */
                buf  += 2; //去掉两个字节的头
                size -= 2;
    
                flag_byte   = 2;
                header_size = 3;
            }
    
            while (size + header_size > s->max_payload_size) {
          //中间数据包分片 memcpy(
    &s->buf[header_size], buf, s->max_payload_size - header_size); ff_rtp_send_data(s1, s->buf, s->max_payload_size, 0); buf += s->max_payload_size - header_size; size -= s->max_payload_size - header_size; s->buf[flag_byte] &= ~(1 << 7); } s->buf[flag_byte] |= 1 << 6;//最后一个数据包分片 memcpy(&s->buf[header_size], buf, size); ff_rtp_send_data(s1, s->buf, size + header_size, last); } }

     文字表达内容有限, 更多详细可以观看相关视频,

    视频下载地址:http://www.chungen90.com/?news_3/

     Demo下载地址: http://www.chungen90.com/?news_2

    如需交流可加QQ群1038388075,766718184 或者QQ3501870

  • 相关阅读:
    XML错误信息Referenced file contains errors (http://www.springframework.org/schema/beans/spring-beans-4.0.xsd). For more information, right click on the message in the Problems View ...
    Description Resource Path Location Type Cannot change version of project facet Dynamic Web Module to 2.3.
    maven创建web报错Cannot read lifecycle mapping metadata for artifact org.apache.maven.plugins:maven-compiler-plugin:maven-compiler-plugin:3.5.1:runtime Cause: error in opening zip file
    AJAX跨域
    JavaWeb学习总结(转载)
    JDBC学习笔记
    Java动态代理之JDK实现和CGlib实现
    (转)看懂UML类图
    spring boot配置使用fastjson
    python3下django连接mysql数据库
  • 原文地址:https://www.cnblogs.com/wanggang123/p/10683048.html
Copyright © 2011-2022 走看看