You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FFmpeg的extract_mvs能否提取H.264子宏块(8x4/4x8/4x4)运动矢量?

解决FFmpeg extract_mvs.c无法提取H.264子宏块(8x4/4x8/4x4)运动矢量的问题

你遇到的问题是因为FFmpeg自带的extract_mvs.c默认只解析到8x8尺寸的宏块,而H.264中8x4、4x8、4x4这类子宏块的运动矢量是作为8x8宏块的子分区数据存在的,需要修改代码来递归处理这些子分区。

问题根源

从x264的输出可以确认这些子宏块确实存在:

x264 [info]: mb P I16..4: 1.9% 0.4% 0.2% P16..4: 20.1% 17.9% 28.4% 11.2% 7.2% skip:12.7%

其中P16..4的后两个数值对应8x4/4x8和4x4子宏块的占比,但extract_mvs.c的原始逻辑只处理了MB_TYPE_16x16、MB_TYPE_16x8、MB_TYPE_8x16、MB_TYPE_8x8这几种宏块类型,没有深入解析8x8块内部的子分区。

修改extract_mvs.c的具体方法

找到extract_mvs.c中处理宏块的核心逻辑(通常在decode_mb或类似函数里),添加对8x8块子分区的解析:

  1. 当检测到宏块类型为MB_TYPE_8x8时,遍历该宏块下的4个8x8子块:
if (mb_type & MB_TYPE_8x8) {
    for (int sub_mb_idx = 0; sub_mb_idx < 4; sub_mb_idx++) {
        int sub_mb_type = s->current_picture.mb_type[mb_idx * 4 + sub_mb_idx];
        // 处理子块的分区类型
        handle_sub_mb_mvs(s, mb_idx, sub_mb_idx, sub_mb_type);
    }
}
  1. 实现handle_sub_mb_mvs函数,解析8x8子块的子分区(8x4、4x8、4x4):
static void handle_sub_mb_mvs(MpegEncContext *s, int mb_idx, int sub_mb_idx, int sub_mb_type) {
    int mb_x = mb_idx % s->mb_width;
    int mb_y = mb_idx / s->mb_width;
    int sub_x = (sub_mb_idx % 2) * 8;
    int sub_y = (sub_mb_idx / 2) * 8;

    // 处理8x4类型子宏块
    if (sub_mb_type & MB_TYPE_8x4) {
        for (int i = 0; i < 2; i++) {
            int mv_x = s->current_picture.motion_val[0][mb_idx*16 + sub_mb_idx*4 + i][0];
            int mv_y = s->current_picture.motion_val[0][mb_idx*16 + sub_mb_idx*4 + i][1];
            printf("Sub-MB: 8x4, Pos: (%d,%d), MV: (%d,%d)\n", 
                   mb_x*16 + sub_x, mb_y*16 + sub_y + i*4, mv_x, mv_y);
        }
    } 
    // 处理4x8类型子宏块
    else if (sub_mb_type & MB_TYPE_4x8) {
        for (int i = 0; i < 2; i++) {
            int mv_x = s->current_picture.motion_val[0][mb_idx*16 + sub_mb_idx*4 + i][0];
            int mv_y = s->current_picture.motion_val[0][mb_idx*16 + sub_mb_idx*4 + i][1];
            printf("Sub-MB: 4x8, Pos: (%d,%d), MV: (%d,%d)\n", 
                   mb_x*16 + sub_x + i*4, mb_y*16 + sub_y, mv_x, mv_y);
        }
    } 
    // 处理4x4类型子宏块
    else if (sub_mb_type & MB_TYPE_4x4) {
        for (int i = 0; i < 4; i++) {
            int mv_x = s->current_picture.motion_val[0][mb_idx*16 + sub_mb_idx*4 + i][0];
            int mv_y = s->current_picture.motion_val[0][mb_idx*16 + sub_mb_idx*4 + i][1];
            int px = mb_x*16 + sub_x + (i%2)*4;
            int py = mb_y*16 + sub_y + (i/2)*4;
            printf("Sub-MB: 4x4, Pos: (%d,%d), MV: (%d,%d)\n", px, py, mv_x, mv_y);
        }
    }
}
  1. 确保代码能访问MpegEncContext、motion_val等结构体成员,若涉及静态权限问题,可调整FFmpeg编译选项或代码的访问逻辑。

编译与测试

修改后重新编译FFmpeg,用新生成的extract_mvs工具处理目标视频,即可提取到8x4、4x8、4x4这类子宏块的运动矢量。

内容的提问来源于stack exchange,提问作者黄舒心

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 02:50:34