美文网首页音视频技术iOS进阶
FFmpeg源码调试:解析H.264 SPS(Sequence

FFmpeg源码调试:解析H.264 SPS(Sequence

作者: 熊皮皮 | 来源:发表于2016-07-30 19:29 被阅读1851次

版本历史:

  • 7月30日:整理文档。
  • 7月29日:整理代码。

FFmpeg源码调试系列文档:

题外话:之前让一个组员搜索FFmpeg如何处理Full Range Video与Video Range Video,就像iOS Core Video那样进行区分,他告诉找不到资料。本篇文档一是解答此问题,二是另一个组员四哥最近在学习H.264编码规则,一起讨论学习进展。

上篇文档FFmpeg源码调试:解析H.264 SPS(Sequence Parameter Set)中帧的宽高介绍了FFmpeg解析H.264 SPS遇到的宽高计算问题及其处理办法,本文档继续描述SPS中获取视频像素的色彩空间及其范围等内容,对应iOS Core Video的CMFormatDescription中颜色转换矩阵CVImageBufferYCbCrMatrix、FullRangeVideo等值,如下图所示。

CMSampleBuffer格式描述

更多信息可参考我另一个文档iOS 音视频高级编程:AVAssetReaderTrackOutput改变CMFormatDescription导致Video Toolbox解码失败与不解码GPU直接显示H.264帧

SPS解析完裁剪信息后,开始处理vui_parameters_present_flag信息,当此字段有值时,由decode_vui_parameters函数作详细解析,详细代码如下。

static inline int decode_vui_parameters(H264Context *h, SPS *sps)
{
    int aspect_ratio_info_present_flag;
    unsigned int aspect_ratio_idc;

    aspect_ratio_info_present_flag = get_bits1(&h->gb);

    if (aspect_ratio_info_present_flag) {
        aspect_ratio_idc = get_bits(&h->gb, 8);
        if (aspect_ratio_idc == EXTENDED_SAR) {
            sps->sar.num = get_bits(&h->gb, 16);
            sps->sar.den = get_bits(&h->gb, 16);
        } else if (aspect_ratio_idc < FF_ARRAY_ELEMS(ff_h264_pixel_aspect)) {
            sps->sar = ff_h264_pixel_aspect[aspect_ratio_idc];
        } else {
            av_log(h->avctx, AV_LOG_ERROR, "illegal aspect ratio\n");
            return AVERROR_INVALIDDATA;
        }
    } else {
        sps->sar.num =
        sps->sar.den = 0;
    }

    if (get_bits1(&h->gb))      /* overscan_info_present_flag */
        get_bits1(&h->gb);      /* overscan_appropriate_flag */

    sps->video_signal_type_present_flag = get_bits1(&h->gb);
    if (sps->video_signal_type_present_flag) {
        get_bits(&h->gb, 3);                 /* video_format */
        sps->full_range = get_bits1(&h->gb); /* video_full_range_flag */

        sps->colour_description_present_flag = get_bits1(&h->gb);
        if (sps->colour_description_present_flag) {
            sps->color_primaries = get_bits(&h->gb, 8); /* colour_primaries */
            sps->color_trc       = get_bits(&h->gb, 8); /* transfer_characteristics */
            sps->colorspace      = get_bits(&h->gb, 8); /* matrix_coefficients */
            if (sps->color_primaries >= AVCOL_PRI_NB)
                sps->color_primaries = AVCOL_PRI_UNSPECIFIED;
            if (sps->color_trc >= AVCOL_TRC_NB)
                sps->color_trc = AVCOL_TRC_UNSPECIFIED;
            if (sps->colorspace >= AVCOL_SPC_NB)
                sps->colorspace = AVCOL_SPC_UNSPECIFIED;
        }
    }

    /* chroma_location_info_present_flag */
    if (get_bits1(&h->gb)) {
        /* chroma_sample_location_type_top_field */
        h->avctx->chroma_sample_location = get_ue_golomb(&h->gb) + 1;
        get_ue_golomb(&h->gb);  /* chroma_sample_location_type_bottom_field */
    }

    if (show_bits1(&h->gb) && get_bits_left(&h->gb) < 10) {
        av_log(h->avctx, AV_LOG_WARNING, "Truncated VUI\n");
        return 0;
    }

    sps->timing_info_present_flag = get_bits1(&h->gb);
    if (sps->timing_info_present_flag) {
        unsigned num_units_in_tick = get_bits_long(&h->gb, 32);
        unsigned time_scale        = get_bits_long(&h->gb, 32);
        if (!num_units_in_tick || !time_scale) {
            av_log(h->avctx, AV_LOG_ERROR,
                   "time_scale/num_units_in_tick invalid or unsupported (%u/%u)\n",
                   time_scale, num_units_in_tick);
            sps->timing_info_present_flag = 0;
        } else {
            sps->num_units_in_tick = num_units_in_tick;
            sps->time_scale = time_scale;
        }
        sps->fixed_frame_rate_flag = get_bits1(&h->gb);
    }

    sps->nal_hrd_parameters_present_flag = get_bits1(&h->gb);
    if (sps->nal_hrd_parameters_present_flag)
        if (decode_hrd_parameters(h, sps) < 0)
            return AVERROR_INVALIDDATA;
    sps->vcl_hrd_parameters_present_flag = get_bits1(&h->gb);
    if (sps->vcl_hrd_parameters_present_flag)
        if (decode_hrd_parameters(h, sps) < 0)
            return AVERROR_INVALIDDATA;
    if (sps->nal_hrd_parameters_present_flag ||
        sps->vcl_hrd_parameters_present_flag)
        get_bits1(&h->gb);     /* low_delay_hrd_flag */
    sps->pic_struct_present_flag = get_bits1(&h->gb);
    if (!get_bits_left(&h->gb))
        return 0;
    sps->bitstream_restriction_flag = get_bits1(&h->gb);
    if (sps->bitstream_restriction_flag) {
        get_bits1(&h->gb);     /* motion_vectors_over_pic_boundaries_flag */
        get_ue_golomb(&h->gb); /* max_bytes_per_pic_denom */
        get_ue_golomb(&h->gb); /* max_bits_per_mb_denom */
        get_ue_golomb(&h->gb); /* log2_max_mv_length_horizontal */
        get_ue_golomb(&h->gb); /* log2_max_mv_length_vertical */
        sps->num_reorder_frames = get_ue_golomb(&h->gb);
        get_ue_golomb(&h->gb); /*max_dec_frame_buffering*/

        if (get_bits_left(&h->gb) < 0) {
            sps->num_reorder_frames         = 0;
            sps->bitstream_restriction_flag = 0;
        }

        if (sps->num_reorder_frames > 16U
            /* max_dec_frame_buffering || max_dec_frame_buffering > 16 */) {
            av_log(h->avctx, AV_LOG_ERROR,
                   "Clipping illegal num_reorder_frames %d\n",
                   sps->num_reorder_frames);
            sps->num_reorder_frames = 16;
            return AVERROR_INVALIDDATA;
        }
    }

    return 0;
}

代码分析:

1、aspect_ratio_info_present_flag及SAR

有关帧存储比例信息可参考我另一个文档FFmpeg av_dump_format输出的tbn、tbc、tbr、PAR、DAR的含义

若aspect_ratio_idc不是拓展SAR(EXTENDED_SAR,值255),则检索全局数组变量ff_h264_pixel_aspect中对应的值。

static const AVRational ff_h264_pixel_aspect[17] = {
    {   0,  1 },
    {   1,  1 },
    {  12, 11 },
    {  10, 11 },
    {  16, 11 },
    {  40, 33 },
    {  24, 11 },
    {  20, 11 },
    {  32, 11 },
    {  80, 33 },
    {  18, 11 },
    {  15, 11 },
    {  64, 33 },
    { 160, 99 },
    {   4,  3 },
    {   3,  2 },
    {   2,  1 },
};

2、Full Range Video与Video Range Video

当存在video_signal_type_present_flag时,读取full_range信息,这决定了YUV转成RGB时使用的颜色转换矩阵的范围,更多信息可参考我另一个文档音视频开发:RGB与YUV相互转换问题

接着确定color_primaries、color_trc和colorspace信息。有关colour_primaries、transfer_characteristics与matrix_coefficients之间的区别,后续文档再描述。

FFmpeg中颜色空间相关定义如下。

/**
  * Chromaticity coordinates of the source primaries.
  */
enum AVColorPrimaries {
    AVCOL_PRI_RESERVED0   = 0,
    AVCOL_PRI_BT709       = 1,  ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B
    AVCOL_PRI_UNSPECIFIED = 2,
    AVCOL_PRI_RESERVED    = 3,
    AVCOL_PRI_BT470M      = 4,  ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20)

    AVCOL_PRI_BT470BG     = 5,  ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM
    AVCOL_PRI_SMPTE170M   = 6,  ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC
    AVCOL_PRI_SMPTE240M   = 7,  ///< functionally identical to above
    AVCOL_PRI_FILM        = 8,  ///< colour filters using Illuminant C
    AVCOL_PRI_BT2020      = 9,  ///< ITU-R BT2020
    AVCOL_PRI_SMPTEST428_1= 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ)
    AVCOL_PRI_NB,               ///< Not part of ABI
};

/**
 * Color Transfer Characteristic.
 */
enum AVColorTransferCharacteristic {
    AVCOL_TRC_RESERVED0    = 0,
    AVCOL_TRC_BT709        = 1,  ///< also ITU-R BT1361
    AVCOL_TRC_UNSPECIFIED  = 2,
    AVCOL_TRC_RESERVED     = 3,
    AVCOL_TRC_GAMMA22      = 4,  ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM
    AVCOL_TRC_GAMMA28      = 5,  ///< also ITU-R BT470BG
    AVCOL_TRC_SMPTE170M    = 6,  ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC
    AVCOL_TRC_SMPTE240M    = 7,
    AVCOL_TRC_LINEAR       = 8,  ///< "Linear transfer characteristics"
    AVCOL_TRC_LOG          = 9,  ///< "Logarithmic transfer characteristic (100:1 range)"
    AVCOL_TRC_LOG_SQRT     = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)"
    AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4
    AVCOL_TRC_BT1361_ECG   = 12, ///< ITU-R BT1361 Extended Colour Gamut
    AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC)
    AVCOL_TRC_BT2020_10    = 14, ///< ITU-R BT2020 for 10 bit system
    AVCOL_TRC_BT2020_12    = 15, ///< ITU-R BT2020 for 12 bit system
    AVCOL_TRC_SMPTEST2084  = 16, ///< SMPTE ST 2084 for 10, 12, 14 and 16 bit systems
    AVCOL_TRC_SMPTEST428_1 = 17, ///< SMPTE ST 428-1
    AVCOL_TRC_NB,                ///< Not part of ABI
};

/**
 * YUV colorspace type.
 */
enum AVColorSpace {
    AVCOL_SPC_RGB         = 0,  ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB)
    AVCOL_SPC_BT709       = 1,  ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B
    AVCOL_SPC_UNSPECIFIED = 2,
    AVCOL_SPC_RESERVED    = 3,
    AVCOL_SPC_FCC         = 4,  ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20)
    AVCOL_SPC_BT470BG     = 5,  ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601
    AVCOL_SPC_SMPTE170M   = 6,  ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above
    AVCOL_SPC_SMPTE240M   = 7,
    AVCOL_SPC_YCOCG       = 8,  ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16
    AVCOL_SPC_BT2020_NCL  = 9,  ///< ITU-R BT2020 non-constant luminance system
    AVCOL_SPC_BT2020_CL   = 10, ///< ITU-R BT2020 constant luminance system
    AVCOL_SPC_NB,               ///< Not part of ABI
};

3、chroma_location_info_present_flag

当chroma_location_info_present_flag字段存在有效值时,读取chroma_sample_location_type_top_field和chroma_sample_location_type_bottom_field信息。这在CMSampleBuffer中也有记录。FFmpeg对色度采样位置的定义如下。

/**
 * Location of chroma samples.
 *
 * Illustration showing the location of the first (top left) chroma sample of the
 * image, the left shows only luma, the right
 * shows the location of the chroma sample, the 2 could be imagined to overlay
 * each other but are drawn separately due to limitations of ASCII
 *
 *                1st 2nd       1st 2nd horizontal luma sample positions
 *                 v   v         v   v
 *                 ______        ______
 *1st luma line > |X   X ...    |3 4 X ...     X are luma samples,
 *                |             |1 2           1-6 are possible chroma positions
 *2nd luma line > |X   X ...    |5 6 X ...     0 is undefined/unknown position
 */
enum AVChromaLocation {
    AVCHROMA_LOC_UNSPECIFIED = 0,
    AVCHROMA_LOC_LEFT        = 1, ///< mpeg2/4 4:2:0, h264 default for 4:2:0
    AVCHROMA_LOC_CENTER      = 2, ///< mpeg1 4:2:0, jpeg 4:2:0, h263 4:2:0
    AVCHROMA_LOC_TOPLEFT     = 3, ///< ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2
    AVCHROMA_LOC_TOP         = 4,
    AVCHROMA_LOC_BOTTOMLEFT  = 5,
    AVCHROMA_LOC_BOTTOM      = 6,
    AVCHROMA_LOC_NB,              ///< Not part of ABI
};

4、timing_info_present_flag

相关文章

网友评论

    本文标题:FFmpeg源码调试:解析H.264 SPS(Sequence

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