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

如何通过FFmpeg C API获取displaymatrix旋转信息并修正视频?

FFmpeg处理竖屏视频旋转问题解决方案

1. 获取视频的displaymatrix旋转元数据

竖屏视频的旋转信息一般存在AVStream的侧数据(对应ffprobe检测到的displaymatrix)或元数据中,不是AVFrame的侧数据,之前遍历AVFrame找不到很正常。可以用两种方式获取:

方式一:读取AVStream的侧数据(推荐)

直接从视频流的侧数据中提取显示矩阵,再解析出旋转角度:

#include <libavutil/display.h>

// 假设已打开输入文件,拿到AVFormatContext* fmt_ctx和目标视频流索引stream_idx
AVStream* stream = fmt_ctx->streams[stream_idx];
int32_t* display_matrix = (int32_t*)av_stream_get_side_data(stream, AV_PKT_DATA_DISPLAYMATRIX, NULL);
if (display_matrix) {
    int rotation = av_display_rotation_get(display_matrix);
    // 注意:av_display_rotation_get返回0/90/180/270,-90度会返回270
    printf("视频旋转角度:%d度\n", rotation);
}

方式二:读取AVStream的元数据字段

部分视频会把旋转信息存在元数据的rotate键里,也可以兜底检查:

AVDictionaryEntry* rotate_entry = av_dict_get(stream->metadata, "rotate", NULL, 0);
if (rotate_entry) {
    int rotation = atoi(rotate_entry->value);
    printf("视频旋转角度:%d度\n", rotation);
}

实际代码里可以把两种方式结合,确保覆盖不同编码的视频。

2. 修改视频缓冲区数据修正旋转并保持宽高比

如果必须修改AVFrame的像素数据来让显示正常,用FFmpeg的swscale模块就能搞定,步骤如下:

步骤1:根据旋转角度调整输出宽高

旋转90/270/-90度时,输出的宽高要和原始帧交换;180度则宽高不变。

步骤2:用swscale做旋转转换

代码示例:

#include <libswscale/swscale.h>

// 假设原始帧是AVFrame* src_frame,已获取到rotation角度
int dst_width, dst_height;
if (rotation == 90 || rotation == 270 || rotation == -90) {
    dst_width = src_frame->height;
    dst_height = src_frame->width;
} else {
    dst_width = src_frame->width;
    dst_height = src_frame->height;
}

// 分配目标帧内存
AVFrame* dst_frame = av_frame_alloc();
dst_frame->format = src_frame->format;
dst_frame->width = dst_width;
dst_frame->height = dst_height;
av_frame_get_buffer(dst_frame, 32);

// 初始化swscale上下文,指定旋转参数
int sws_flags = SWS_BILINEAR; // 用双线性插值保证画质
if (rotation == 90) {
    sws_flags |= SWS_ROTATE_90;
} else if (rotation == 180) {
    sws_flags |= SWS_ROTATE_180;
} else if (rotation == 270 || rotation == -90) {
    sws_flags |= SWS_ROTATE_270;
}

SwsContext* sws_ctx = sws_getContext(src_frame->width, src_frame->height, 
                                     (AVPixelFormat)src_frame->format,
                                     dst_width, dst_height, 
                                     (AVPixelFormat)dst_frame->format,
                                     sws_flags, NULL, NULL, NULL);

// 执行旋转转换
sws_scale(sws_ctx, src_frame->data, src_frame->linesize, 0, src_frame->height,
          dst_frame->data, dst_frame->linesize);

// 现在用dst_frame作为修正后的帧写入OpenGL纹理即可,宽高比自动保持正确
// ...后续渲染逻辑...

// 记得用完释放资源
sws_freeContext(sws_ctx);
av_frame_free(&dst_frame);

补充:更高效的替代方案

其实没必要修改缓冲区数据,Chrome就是在渲染阶段处理的——直接在OpenGL里通过矩阵变换修正旋转,比如调整MVP矩阵或者修改顶点着色器的纹理坐标映射,这样不用拷贝像素数据,性能更好。如果你的场景允许,优先用这种方式。

内容的提问来源于stack exchange,提问作者VioGL

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 14:46:02