Technology Sharing

Basics of audio and video: H.264 topic (12) - Implementation of calculating video resolution through SPS attributes in FFmpeg source code

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

I. Introduction

In the previous sectionBasics of audio and video: H.264 topic (11) - Formula for calculating video resolutionIn the article, the formula for calculating the resolution of H.264 encoded videos using the attributes in SPS is described. This article explains how to calculate the video resolution in the FFmpeg source code.

2. Implementation of calculating video resolution in FFmpeg source code

From the articleBasics of audio and video: H.264 topic (10) - Analysis of the structure storing SPS attributes and the function for decoding SPS in the FFmpeg source code》, we can know that the FFmpeg source code decodes SPS through the ff_h264_decode_seq_parameter_set function to obtain the attributes in SPS.

There is the following code in the ff_h264_decode_seq_parameter_set function, which can be used to obtain the properties required to calculate the video resolution:

  1. int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx,
  2. H264ParamSets *ps, int ignore_truncation)
  3. {
  4. //...
  5. sps->gaps_in_frame_num_allowed_flag = get_bits1(gb);
  6. sps->mb_width = get_ue_golomb(gb) + 1;
  7. sps->mb_height = get_ue_golomb(gb) + 1;
  8. sps->frame_mbs_only_flag = get_bits1(gb);
  9. if (sps->mb_height >= INT_MAX / 2U) {
  10. av_log(avctx, AV_LOG_ERROR, "height overflown");
  11. goto fail;
  12. }
  13. sps->mb_height *= 2 - sps->frame_mbs_only_flag;
  14. //...
  15. sps->crop = get_bits1(gb);
  16. if (sps->crop) {
  17. unsigned int crop_left = get_ue_golomb(gb);
  18. unsigned int crop_right = get_ue_golomb(gb);
  19. unsigned int crop_top = get_ue_golomb(gb);
  20. unsigned int crop_bottom = get_ue_golomb(gb);
  21. int width = 16 * sps->mb_width;
  22. int height = 16 * sps->mb_height;
  23. if (avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) {
  24. av_log(avctx, AV_LOG_DEBUG, "discarding sps cropping, original "
  25. "values are l:%d r:%d t:%d b:%dn",
  26. crop_left, crop_right, crop_top, crop_bottom);
  27. sps->crop_left =
  28. sps->crop_right =
  29. sps->crop_top =
  30. sps->crop_bottom = 0;
  31. } else {
  32. int vsub = (sps->chroma_format_idc == 1) ? 1 : 0;
  33. int hsub = (sps->chroma_format_idc == 1 ||
  34. sps->chroma_format_idc == 2) ? 1 : 0;
  35. int step_x = 1 << hsub;
  36. int step_y = (2 - sps->frame_mbs_only_flag) << vsub;
  37. if (crop_left > (unsigned)INT_MAX / 4 / step_x ||
  38. crop_right > (unsigned)INT_MAX / 4 / step_x ||
  39. crop_top > (unsigned)INT_MAX / 4 / step_y ||
  40. crop_bottom> (unsigned)INT_MAX / 4 / step_y ||
  41. (crop_left + crop_right ) * step_x >= width ||
  42. (crop_top + crop_bottom) * step_y >= height
  43. ) {
  44. av_log(avctx, AV_LOG_ERROR, "crop values invalid %d %d %d %d / %d %dn",
  45. crop_left, crop_right, crop_top, crop_bottom, width, height);
  46. goto fail;
  47. }
  48. sps->crop_left = crop_left * step_x;
  49. sps->crop_right = crop_right * step_x;
  50. sps->crop_top = crop_top * step_y;
  51. sps->crop_bottom = crop_bottom * step_y;
  52. }
  53. } else {
  54. sps->crop_left =
  55. sps->crop_right =
  56. sps->crop_top =
  57. sps->crop_bottom =
  58. sps->crop = 0;
  59. }
  60. //...
  61. }

Then in the parse_nal_units function of the source file libavcodec/h264_parser.c of the FFmpeg source code, there is the following code:

  1. static inline int parse_nal_units(AVCodecParserContext *s,
  2. AVCodecContext *avctx,
  3. const uint8_t * const buf, int buf_size)
  4. {
  5. //...
  6. for (;;) {
  7. switch (nal.type) {
  8. case H264_NAL_SPS:
  9. ff_h264_decode_seq_parameter_set(&nal.gb, avctx, &p->ps, 0);
  10. break;
  11. //...
  12. case H264_NAL_IDR_SLICE:
  13. //...
  14. s->coded_width = 16 * sps->mb_width;
  15. s->coded_height = 16 * sps->mb_height;
  16. s->width = s->coded_width - (sps->crop_right + sps->crop_left);
  17. s->height = s->coded_height - (sps->crop_top + sps->crop_bottom);
  18. if (s->width <= 0 || s->height <= 0) {
  19. s->width = s->coded_width;
  20. s->height = s->coded_height;
  21. }
  22. //...
  23. }
  24. //...
  25. }
  26. }

It can be seen that the parse_nal_units function finally gets the video resolution through the following statement:

  1. s->width = s->coded_width - (sps->crop_right + sps->crop_left);
  2. s->height = s->coded_height - (sps->crop_top + sps->crop_bottom);

You can see the implementation of calculating video resolution in FFmpeg source code and the article "Basics of audio and video: H.264 topic (11) - Formula for calculating video resolution》is consistent with the formula described in .