版本历史:
- 7月30日:整理文档。
- 7月29日:整理代码。
FFmpeg源码调试系列文档:
- FFmpeg源码调试:解析H.264 SPS(Sequence Parameter Set)中帧的宽高
- FFmpeg源码调试:解析H.264 SPS(Sequence Parameter Set)中视频的颜色空间及其范围
题外话:之前让一个组员搜索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等值,如下图所示。

更多信息可参考我另一个文档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
网友评论