音视频入门基础:H.264专题(12)——FFmpeg源码中通过SPS属性计算视频分辨率的实现

一、引言

在上一节《音视频入门基础:H.264专题(11)------计算视频分辨率的公式》中,讲述了通过SPS中的属性计算H.264编码的视频的分辨率的公式。本文讲解FFmpeg源码中计算视频分辨率的实现。

二、FFmpeg源码中计算视频分辨率的实现

从文章《音视频入门基础:H.264专题(10)------FFmpeg源码中,存放SPS属性的结构体和解码SPS的函数分析》中,我们可以知道,FFmpeg源码中通过ff_h264_decode_seq_parameter_set函数解码SPS,从而拿到SPS中的属性。

在ff_h264_decode_seq_parameter_set函数中有如下代码,通过下面的这部分代码拿到计算视频分辨率所需的属性:

cpp 复制代码
int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx,
                                     H264ParamSets *ps, int ignore_truncation)
{
    //...
    
    sps->gaps_in_frame_num_allowed_flag = get_bits1(gb);
    sps->mb_width                       = get_ue_golomb(gb) + 1;
    sps->mb_height                      = get_ue_golomb(gb) + 1;

    sps->frame_mbs_only_flag = get_bits1(gb);

    if (sps->mb_height >= INT_MAX / 2U) {
        av_log(avctx, AV_LOG_ERROR, "height overflow\n");
        goto fail;
    }
    sps->mb_height *= 2 - sps->frame_mbs_only_flag;

    //...

    sps->crop = get_bits1(gb);
    if (sps->crop) {
        unsigned int crop_left   = get_ue_golomb(gb);
        unsigned int crop_right  = get_ue_golomb(gb);
        unsigned int crop_top    = get_ue_golomb(gb);
        unsigned int crop_bottom = get_ue_golomb(gb);
        int width  = 16 * sps->mb_width;
        int height = 16 * sps->mb_height;

        if (avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) {
            av_log(avctx, AV_LOG_DEBUG, "discarding sps cropping, original "
                                           "values are l:%d r:%d t:%d b:%d\n",
                   crop_left, crop_right, crop_top, crop_bottom);

            sps->crop_left   =
            sps->crop_right  =
            sps->crop_top    =
            sps->crop_bottom = 0;
        } else {
            int vsub   = (sps->chroma_format_idc == 1) ? 1 : 0;
            int hsub   = (sps->chroma_format_idc == 1 ||
                          sps->chroma_format_idc == 2) ? 1 : 0;
            int step_x = 1 << hsub;
            int step_y = (2 - sps->frame_mbs_only_flag) << vsub;

            if (crop_left  > (unsigned)INT_MAX / 4 / step_x ||
                crop_right > (unsigned)INT_MAX / 4 / step_x ||
                crop_top   > (unsigned)INT_MAX / 4 / step_y ||
                crop_bottom> (unsigned)INT_MAX / 4 / step_y ||
                (crop_left + crop_right ) * step_x >= width ||
                (crop_top  + crop_bottom) * step_y >= height
            ) {
                av_log(avctx, AV_LOG_ERROR, "crop values invalid %d %d %d %d / %d %d\n",     
                      crop_left, crop_right, crop_top, crop_bottom, width, height);
                goto fail;
            }

            sps->crop_left   = crop_left   * step_x;
            sps->crop_right  = crop_right  * step_x;
            sps->crop_top    = crop_top    * step_y;
            sps->crop_bottom = crop_bottom * step_y;
        }
    } else {
        sps->crop_left   =
        sps->crop_right  =
        sps->crop_top    =
        sps->crop_bottom =
        sps->crop        = 0;
    }

    //...
}

然后在FFmpeg源码的源文件libavcodec/h264_parser.c的parse_nal_units函数中,有如下代码:

cpp 复制代码
static inline int parse_nal_units(AVCodecParserContext *s,
                                  AVCodecContext *avctx,
                                  const uint8_t * const buf, int buf_size)
{
    //...
    
    for (;;) {
        switch (nal.type) {
        case H264_NAL_SPS:
            ff_h264_decode_seq_parameter_set(&nal.gb, avctx, &p->ps, 0);
            break;
         
        //...

        case H264_NAL_IDR_SLICE:
        
        //...

        s->coded_width  = 16 * sps->mb_width;
        s->coded_height = 16 * sps->mb_height;
        s->width        = s->coded_width  - (sps->crop_right + sps->crop_left);
        s->height       = s->coded_height - (sps->crop_top   + sps->crop_bottom);
        if (s->width <= 0 || s->height <= 0) {
            s->width  = s->coded_width;
            s->height = s->coded_height;
        }
        //... 
        }
        //...
    }
}

可以看到parse_nal_units函数中最终是通过下面的语句拿到视频分辨率的:

cpp 复制代码
s->width = s->coded_width - (sps->crop_right + sps->crop_left);
s->height = s->coded_height - (sps->crop_top + sps->crop_bottom);

可以看到FFmpeg源码中计算视频分辨率的实现跟文章《音视频入门基础:H.264专题(11)------计算视频分辨率的公式》中描述的公式是一致的。

相关推荐
开开心心就好3 小时前
解决图片无页码添加功能的实用工具
javascript·python·安全·智能手机·pdf·音视频·1024程序员节
EasyCVR12 小时前
国标GB28181视频监控平台EasyCVR行业解决方案深度解读——雪亮工程、智慧城市与智慧交通
人工智能·音视频·智慧城市
“码”力全开15 小时前
打破芯片与协议壁垒:基于 Docker + 边缘计算的 GB28181/RTSP 视频智能管理平台架构设计与源码交付方案
docker·音视频·边缘计算
AI服务老曹1 天前
解密企业级视频中台:基于 GB28181/RTSP 统一接入与边缘计算的 AI 视频管理平台(附 Docker 部署与源码交付方案)
人工智能·音视频·边缘计算
shandianchengzi1 天前
【记录】LosslessCut|Linux下配置开源无损剪辑软件 LosslessCut AppImage 命令行启动和设置图标
linux·运维·服务器·音视频·视频·剪辑
zhaoshuzhaoshu1 天前
无线耳机的音频传输时延技术对比总结
音视频
ai产品老杨1 天前
深度解析:基于 Docker 与异构计算的下一代 AI 视频管理平台架构(附 GB28181/RTSP 统一接入与源码交付方案)
人工智能·docker·音视频
hz567891 天前
2026主流RTC音视频SDK选型全解析:性能对比+避坑指南+国产化适配深度横评
云计算·音视频·实时音视频·信息与通信
AI前沿资讯1 天前
哪个AI 3D创作工具更适合视频创作?——2026年V2Fun实战指南
人工智能·3d·音视频
EasyDSS1 天前
企业融媒体平台/私有化视频会议解决方案EasyDSS重构企业视频高效运维体系
重构·音视频·媒体