Partage de technologie

Bases pour démarrer avec l'audio et la vidéo : sujet H.264 (12) - Implémentation du calcul de la résolution vidéo via les attributs SPS dans le code source FFmpeg

2024-07-12

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

Introduction

Dans la section précédente "Notions de base pour démarrer avec l'audio et la vidéo : sujet H.264 (11) - formule de calcul de la résolution vidéo "", décrit la formule de calcul de la résolution de la vidéo codée H.264 via les attributs de SPS. Cet article explique l'implémentation du calcul de la résolution vidéo dans le code source de FFmpeg.

2. Implémentation du calcul de la résolution vidéo dans le code source de FFmpeg

Extrait de l'article "Bases pour démarrer avec l'audio et la vidéo : sujet H.264 (10) - Analyse de la structure qui stocke les attributs SPS et de la fonction de décodage SPS dans le code source FFmpeg》, on peut savoir que le code source de FFmpeg décode SPS via la fonction ff_h264_decode_seq_parameter_set pour obtenir les attributs dans SPS.

Il y a le code suivant dans la fonction ff_h264_decode_seq_parameter_set. Grâce à la partie suivante du code, les attributs nécessaires au calcul de la résolution vidéo sont obtenus :

  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. }

Ensuite dans la fonction parse_nal_units du fichier source libavcodec/h264_parser.c du code source de FFmpeg, on trouve le code suivant :

  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. }

Vous pouvez voir que dans la fonction parse_nal_units, la résolution vidéo est finalement obtenue grâce à l'instruction suivante :

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

Vous pouvez voir l'implémentation du calcul de la résolution vidéo dans le code source de FFmpeg et l'article "Notions de base pour démarrer avec l'audio et la vidéo : sujet H.264 (11) - formule de calcul de la résolution vidéoLes formules décrites dans sont cohérentes.