1. 概述
FFmpeg 在處理視頻旋轉信息方面經歷了重要的架構變化。本文檔詳細對比了 FFmpeg 3.4 和 7.0.2 在封裝(muxing)和解封裝(demuxing)視頻旋轉信息時的差異,并提供兼容性解決方案。文檔內容由Claude Sonnet 4輔助撰寫,如有疏漏還請斧正。
- FFmpeg 3.4:支持 metadata 和 side data 雙重機制
- FFmpeg 7.0.2:主要依賴 side data 機制,弱化 metadata 支持
2. 旋轉信息存儲機制
存儲方式 | FFmpeg 3.4 | FFmpeg 7.0.2 | 說明 |
---|---|---|---|
Stream Metadata | ? 讀寫支持 | ? 僅讀取(兼容性) | stream->metadata["rotate"] |
Side Data | ? 讀寫支持 | ? 主要方式 | AV_PKT_DATA_DISPLAYMATRIX |
容器原生格式 | ? 支持 | ? 支持 | MP4 tkhd atom 等 |
// Metadata 格式(字符串)
stream->metadata["rotate"] = "90" // 90度旋轉// Side Data 格式(3x3 變換矩陣)
int32_t displaymatrix[9] = {cos(θ), -sin(θ), 0,sin(θ), cos(θ), 0,0, 0, 1
};
3. 解封裝(Demuxing)對比
3.1 FFmpeg 3.4 解封裝行為
// FFmpeg 3.4 讀取流程
void ffmpeg34_demux_rotation() {// 1. 從容器讀取 displaymatrixuint8_t *displaymatrix = read_container_displaymatrix();// 2. 設置 side dataav_stream_add_side_data(stream, AV_PKT_DATA_DISPLAYMATRIX, displaymatrix, size);// 3. 同時設置 metadata(便于應用程序使用)if (displaymatrix) {double rotation = av_display_rotation_get((int32_t*)displaymatrix);av_dict_set(&stream->metadata, "rotate", av_asprintf("%.0f", -rotation), AV_DICT_DONT_STRDUP_VAL);}
}// 應用程序讀取(推薦方式)
int getRotation_v34(AVStream *stream) {// 方式1:從 metadata 讀取(簡單)AVDictionaryEntry *t = av_dict_get(stream->metadata, "rotate", NULL, 0);if (t) return atoi(t->value);// 方式2:從 side data 讀取(精確)uint8_t *displaymatrix = av_stream_get_side_data(stream, AV_PKT_DATA_DISPLAYMATRIX, NULL);if (displaymatrix) {return (int)(-av_display_rotation_get((int32_t*)displaymatrix));}return 0;
}
3.2 FFmpeg 7.0.2 解封裝行為
// FFmpeg 7.0.2 讀取流程
void ffmpeg70_demux_rotation() {// 1. 從容器讀取 displaymatrixuint8_t *displaymatrix = read_container_displaymatrix();// 2. 只設置 side dataav_packet_side_data_add(&stream->codecpar->coded_side_data,&stream->codecpar->nb_coded_side_data,AV_PKT_DATA_DISPLAYMATRIX, displaymatrix, size, 0);// 3. 不再自動設置 metadata// stream->metadata["rotate"] 為空!
}// 應用程序讀取(新方式)
int getRotation_v70(AVStream *stream) {// 只能從 side data 讀取AVPacketSideData *side_data = av_packet_side_data_get(stream->codecpar->coded_side_data,stream->codecpar->nb_coded_side_data,AV_PKT_DATA_DISPLAYMATRIX);if (side_data && side_data->size >= 9 * sizeof(int32_t)) {double rotation = av_display_rotation_get((int32_t*)side_data->data);return (int)(-rotation);}return 0;
}
4. 封裝(Muxing)對比
4.1 FFmpeg 3.4 封裝行為
// FFmpeg 3.4 支持多種設置方式// 方式1:通過 metadata 設置(推薦)
int setRotation_v34_metadata(AVStream *stream, int degrees) {char rotation_str[16];snprintf(rotation_str, sizeof(rotation_str), "%d", degrees);// 設置 metadata,muxer 會自動轉換為 displaymatrixreturn av_dict_set(&stream->metadata, "rotate", rotation_str, 0);
}// 方式2:直接設置 side data
int setRotation_v34_sidedata(AVStream *stream, int degrees) {uint8_t *displaymatrix = av_stream_new_side_data(stream, AV_PKT_DATA_DISPLAYMATRIX, 9 * sizeof(int32_t));if (!displaymatrix) return -1;av_display_rotation_set((int32_t*)displaymatrix, -(double)degrees);return 0;
}
4.2 FFmpeg 7.0.2 封裝行為
// FFmpeg 7.0.2 主要通過 side data 設置int setRotation_v70(AVStream *stream, int degrees) {// metadata 方式可能無效,必須使用 side dataint32_t *displaymatrix = (int32_t*)av_packet_side_data_new(&stream->codecpar->coded_side_data,&stream->codecpar->nb_coded_side_data,AV_PKT_DATA_DISPLAYMATRIX,9 * sizeof(int32_t),0);if (!displaymatrix) return -1;av_display_rotation_set(displaymatrix, -(double)degrees);return 0;
}
5. 總結
FFmpeg 在處理視頻旋轉信息方面的變化反映了其向更標準化、更精確方向的演進:
- FFmpeg 3.4:過渡期版本,同時支持 metadata 和 side data
- FFmpeg 7.0.2:現代化版本,主要依賴標準化的 side data
開發者應該:
- 在新項目中優先使用 side data API
- 保持對舊版本的兼容性支持
- 進行充分的跨版本測試
- 關注 FFmpeg 的未來發展趨勢
這種變化雖然增加了開發復雜度,但提供了更好的標準兼容性和更精確的旋轉信息處理能力。