Condivisione della tecnologia

Nozioni di base per iniziare con audio e video: argomento H.264 (12) - Implementazione del calcolo della risoluzione video tramite attributi SPS nel codice sorgente FFmpeg

2024-07-12

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

I. Introduzione

Nella sezione precedente "Nozioni di base per iniziare con audio e video: argomento H.264 (11) - formula per il calcolo della risoluzione video "", descrive la formula per calcolare la risoluzione del video codificato H.264 attraverso gli attributi in SPS. Questo articolo spiega l'implementazione del calcolo della risoluzione video nel codice sorgente FFmpeg.

2. Implementazione del calcolo della risoluzione video nel codice sorgente FFmpeg

Dall'articolo "Nozioni di base per iniziare con audio e video: argomento H.264 (10) - Analisi della struttura che memorizza gli attributi SPS e la funzione di decodifica SPS nel codice sorgente FFmpeg》, possiamo sapere che il codice sorgente di FFmpeg decodifica SPS tramite la funzione ff_h264_decode_seq_parameter_set per ottenere gli attributi in SPS.

Nella funzione ff_h264_decode_seq_parameter_set è presente il seguente codice. Attraverso la seguente parte di codice si ottengono gli attributi necessari per calcolare la risoluzione video:

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

Quindi nella funzione parse_nal_units del file sorgente libavcodec/h264_parser.c del codice sorgente di FFmpeg, c'è il seguente codice:

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

Puoi vedere che nella funzione parse_nal_units, la risoluzione video è finalmente ottenuta attraverso la seguente istruzione:

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

Puoi vedere l'implementazione del calcolo della risoluzione video nel codice sorgente di FFmpeg e nell'articolo "Nozioni di base per iniziare con audio e video: argomento H.264 (11) - formula per il calcolo della risoluzione videoLe formule descritte in sono coerenti.