美文网首页
RTP系列:H264/H265 RTP代码分析

RTP系列:H264/H265 RTP代码分析

作者: 捧着漏勺喝汤 | 来源:发表于2020-02-29 14:40 被阅读0次

    1、H264/H265封包
    代码位置:FFmpeg的文件rtpenc_h264_hevc.c(4.0.5版本)

    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\n", buf[0] & 0x1F, size, last);
        if (size <= s->max_payload_size) {
            int buffered_size = s->buf_ptr - s->buf;
            int header_size;
            int skip_aggregate = 0;
    
            if (codec == AV_CODEC_ID_H264) {
                // H264的NAL头为1个字节
                header_size = 1;
                skip_aggregate = s->flags & FF_RTP_FLAG_H264_MODE0;
            } else {
                 // H265的NAL头为1个字节
                header_size = 2;
            }
    
            // Flush buffered NAL units if the current unit doesn't fit
            //max_payload_size一般为1500,有些会去掉tcp或者udp协议头,取1460或者1400
            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;
                        *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 {//NALU分片处理
            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\n", size,
                       s->max_payload_size, s->max_payload_size);
                return;
            }
            av_log(s1, AV_LOG_DEBUG, "NAL size %d > %d\n", size, s->max_payload_size);
            if (codec == AV_CODEC_ID_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;
                /*
                 * 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;
                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);
        }
    }
    

    2、H264解包
    代码位置:FFmpeg的文件rtpdec_h264.c(4.0.5版本)

    // return 0 on packet, no more left, 1 on packet, 1 on partial packet
    static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data,
                                  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
                                  const uint8_t *buf, int len, uint16_t seq,
                                  int flags)
    {
        uint8_t nal;
        uint8_t type;
        int result = 0;
    
        if (!len) {
            av_log(ctx, AV_LOG_ERROR, "Empty H.264 RTP packet\n");
            return AVERROR_INVALIDDATA;
        }
        nal  = buf[0];
        type = nal & 0x1f;
    
        /* Simplify the case (these are all the NAL types used internally by
         * the H.264 codec). */
        if (type >= 1 && type <= 23)
            type = 1;
        switch (type) {
        case 0:                    // undefined, but pass them through
        case 1:
            if ((result = av_new_packet(pkt, len + sizeof(start_sequence))) < 0)
                return result;
            memcpy(pkt->data, start_sequence, sizeof(start_sequence));
            memcpy(pkt->data + sizeof(start_sequence), buf, len);
            COUNT_NAL_TYPE(data, nal);
            break;
    
        case 24:                   // STAP-A (one packet, multiple nals)
            // consume the STAP-A NAL
            buf++;
            len--;
            result = ff_h264_handle_aggregated_packet(ctx, data, pkt, buf, len, 0,
                                                      NAL_COUNTERS, NAL_MASK);
            break;
    
        case 25:                   // STAP-B
        case 26:                   // MTAP-16
        case 27:                   // MTAP-24
        case 29:                   // FU-B
            avpriv_report_missing_feature(ctx, "RTP H.264 NAL unit type %d", type);
            result = AVERROR_PATCHWELCOME;
            break;
    
        case 28:                   // FU-A (fragmented nal)
            result = h264_handle_packet_fu_a(ctx, data, pkt, buf, len,
                                             NAL_COUNTERS, NAL_MASK);
            break;
    
        case 30:                   // undefined
        case 31:                   // undefined
        default:
            av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)\n", type);
            result = AVERROR_INVALIDDATA;
            break;
        }
    
        pkt->stream_index = st->index;
    
        return result;
    }
    

    3、H265解包
    代码位置:FFmpeg的文件rtpdec_hevc.c(4.0.5版本)

    static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx,
                                  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
                                  const uint8_t *buf, int len, uint16_t seq,
                                  int flags)
    {
        const uint8_t *rtp_pl = buf;
        int tid, lid, nal_type;
        int first_fragment, last_fragment, fu_type;
        uint8_t new_nal_header[2];
        int res = 0;
    
        /* sanity check for size of input packet: 1 byte payload at least */
        if (len < RTP_HEVC_PAYLOAD_HEADER_SIZE + 1) {
            av_log(ctx, AV_LOG_ERROR, "Too short RTP/HEVC packet, got %d bytes\n", len);
            return AVERROR_INVALIDDATA;
        }
    
        /*
         * decode the HEVC payload header according to section 4 of draft version 6:
         *
         *    0                   1
         *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
         *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         *   |F|   Type    |  LayerId  | TID |
         *   +-------------+-----------------+
         *
         *      Forbidden zero (F): 1 bit
         *      NAL unit type (Type): 6 bits
         *      NUH layer ID (LayerId): 6 bits
         *      NUH temporal ID plus 1 (TID): 3 bits
         */
        nal_type =  (buf[0] >> 1) & 0x3f;
        lid  = ((buf[0] << 5) & 0x20) | ((buf[1] >> 3) & 0x1f);
        tid  =   buf[1] & 0x07;
    
        /* sanity check for correct layer ID */
        if (lid) {
            /* future scalable or 3D video coding extensions */
            avpriv_report_missing_feature(ctx, "Multi-layer HEVC coding");
            return AVERROR_PATCHWELCOME;
        }
    
        /* sanity check for correct temporal ID */
        if (!tid) {
            av_log(ctx, AV_LOG_ERROR, "Illegal temporal ID in RTP/HEVC packet\n");
            return AVERROR_INVALIDDATA;
        }
    
        /* sanity check for correct NAL unit type */
        if (nal_type > 50) {
            av_log(ctx, AV_LOG_ERROR, "Unsupported (HEVC) NAL type (%d)\n", nal_type);
            return AVERROR_INVALIDDATA;
        }
    
        switch (nal_type) {
        /* video parameter set (VPS) */
        case 32:
        /* sequence parameter set (SPS) */
        case 33:
        /* picture parameter set (PPS) */
        case 34:
        /*  supplemental enhancement information (SEI) */
        case 39:
        /* single NAL unit packet */
        default:
            /* create A/V packet */
            if ((res = av_new_packet(pkt, sizeof(start_sequence) + len)) < 0)
                return res;
            /* A/V packet: copy start sequence */
            memcpy(pkt->data, start_sequence, sizeof(start_sequence));
            /* A/V packet: copy NAL unit data */
            memcpy(pkt->data + sizeof(start_sequence), buf, len);
    
            break;
        /* aggregated packet (AP) - with two or more NAL units */
        case 48:
            /* pass the HEVC payload header */
            buf += RTP_HEVC_PAYLOAD_HEADER_SIZE;
            len -= RTP_HEVC_PAYLOAD_HEADER_SIZE;
    
            /* pass the HEVC DONL field */
            if (rtp_hevc_ctx->using_donl_field) {
                buf += RTP_HEVC_DONL_FIELD_SIZE;
                len -= RTP_HEVC_DONL_FIELD_SIZE;
            }
    
            res = ff_h264_handle_aggregated_packet(ctx, rtp_hevc_ctx, pkt, buf, len,
                                                   rtp_hevc_ctx->using_donl_field ?
                                                   RTP_HEVC_DOND_FIELD_SIZE : 0,
                                                   NULL, 0);
            if (res < 0)
                return res;
            break;
        /* fragmentation unit (FU) */
        case 49:
            /* pass the HEVC payload header */
            buf += RTP_HEVC_PAYLOAD_HEADER_SIZE;
            len -= RTP_HEVC_PAYLOAD_HEADER_SIZE;
    
            /*
             *    decode the FU header
             *
             *     0 1 2 3 4 5 6 7
             *    +-+-+-+-+-+-+-+-+
             *    |S|E|  FuType   |
             *    +---------------+
             *
             *       Start fragment (S): 1 bit
             *       End fragment (E): 1 bit
             *       FuType: 6 bits
             */
            first_fragment = buf[0] & 0x80;
            last_fragment  = buf[0] & 0x40;
            fu_type        = buf[0] & 0x3f;
    
            /* pass the HEVC FU header */
            buf += RTP_HEVC_FU_HEADER_SIZE;
            len -= RTP_HEVC_FU_HEADER_SIZE;
    
            /* pass the HEVC DONL field */
            if (rtp_hevc_ctx->using_donl_field) {
                buf += RTP_HEVC_DONL_FIELD_SIZE;
                len -= RTP_HEVC_DONL_FIELD_SIZE;
            }
    
            av_log(ctx, AV_LOG_TRACE, " FU type %d with %d bytes\n", fu_type, len);
    
            /* sanity check for size of input packet: 1 byte payload at least */
            if (len <= 0) {
                if (len < 0) {
                    av_log(ctx, AV_LOG_ERROR,
                           "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
                           len, nal_type);
                    return AVERROR_INVALIDDATA;
                } else {
                    return AVERROR(EAGAIN);
                }
            }
    
            if (first_fragment && last_fragment) {
                av_log(ctx, AV_LOG_ERROR, "Illegal combination of S and E bit in RTP/HEVC packet\n");
                return AVERROR_INVALIDDATA;
            }
    
            new_nal_header[0] = (rtp_pl[0] & 0x81) | (fu_type << 1);
            new_nal_header[1] = rtp_pl[1];
    
            res = ff_h264_handle_frag_packet(pkt, buf, len, first_fragment,
                                             new_nal_header, sizeof(new_nal_header));
    
            break;
        /* PACI packet */
        case 50:
            /* Temporal scalability control information (TSCI) */
            avpriv_report_missing_feature(ctx, "PACI packets for RTP/HEVC");
            res = AVERROR_PATCHWELCOME;
            break;
        }
    
        pkt->stream_index = st->index;
    
        return res;
    }
    

    相关文章

      网友评论

          本文标题:RTP系列:H264/H265 RTP代码分析

          本文链接:https://www.haomeiwen.com/subject/hxvphhtx.html