Videos files recorded on most phones were coming in sideways; files recorded on some laptop cameras were coming in upside down. In both cases the display_matrix metadata of the video stream was not applied. This required changing internal container format of movie proxies to be MP4 instead of AVI, since AVI does not support rotation metadata. File extension kept at ".avi" to not disturb existing expectations. It might be better to "bake" rotation into proxies while building them, but right now we do not have a trivial way of doing that. Note that this is a potential behavior change; if someone already had manually rotated video strips, they would have to undo that rotation now. Pull Request: https://projects.blender.org/blender/blender/pulls/130455
This commit is contained in:
committed by
Aras Pranckevicius
parent
0ab0f41c1e
commit
611940805e
@@ -17,6 +17,7 @@
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/cpu.h>
|
||||
#include <libavutil/display.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
/* Check if our ffmpeg is new enough, avoids user complaints.
|
||||
@@ -168,6 +169,44 @@ FFMPEG_INLINE size_t ffmpeg_get_buffer_alignment()
|
||||
return align;
|
||||
}
|
||||
|
||||
FFMPEG_INLINE void ffmpeg_copy_display_matrix(const AVStream *src, AVStream *dst)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 29, 100)
|
||||
const AVPacketSideData *src_matrix = av_packet_side_data_get(src->codecpar->coded_side_data,
|
||||
src->codecpar->nb_coded_side_data,
|
||||
AV_PKT_DATA_DISPLAYMATRIX);
|
||||
if (src_matrix != nullptr) {
|
||||
uint8_t *dst_matrix = (uint8_t *)av_memdup(src_matrix->data, src_matrix->size);
|
||||
av_packet_side_data_add(&dst->codecpar->coded_side_data,
|
||||
&dst->codecpar->nb_coded_side_data,
|
||||
AV_PKT_DATA_DISPLAYMATRIX,
|
||||
dst_matrix,
|
||||
src_matrix->size,
|
||||
0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
FFMPEG_INLINE int ffmpeg_get_video_rotation(const AVStream *stream)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 29, 100)
|
||||
const AVPacketSideData *src_matrix = av_packet_side_data_get(
|
||||
stream->codecpar->coded_side_data,
|
||||
stream->codecpar->nb_coded_side_data,
|
||||
AV_PKT_DATA_DISPLAYMATRIX);
|
||||
if (src_matrix != nullptr) {
|
||||
/* ffmpeg reports rotation in [-180..+180] range; our image rotation
|
||||
* uses different direction and [0..360] range. */
|
||||
double theta = -av_display_rotation_get((const int32_t *)src_matrix->data);
|
||||
if (theta < 0.0) {
|
||||
theta += 360.0;
|
||||
}
|
||||
return int(theta);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deinterlace code block
|
||||
*
|
||||
|
||||
@@ -34,6 +34,7 @@ struct ImBufAnim {
|
||||
double frs_sec_base;
|
||||
double start_offset;
|
||||
int x, y;
|
||||
int video_rotation;
|
||||
|
||||
/* for number */
|
||||
char filepath[1024];
|
||||
|
||||
@@ -356,6 +356,8 @@ static int startffmpeg(ImBufAnim *anim)
|
||||
|
||||
anim->x = pCodecCtx->width;
|
||||
anim->y = pCodecCtx->height;
|
||||
anim->video_rotation = ffmpeg_get_video_rotation(video_stream);
|
||||
|
||||
/* Decode >8bit videos into floating point image. */
|
||||
anim->is_float = calc_pix_fmt_max_component_bits(pCodecCtx->pix_fmt) > 8;
|
||||
|
||||
@@ -652,6 +654,11 @@ static void ffmpeg_postprocess(ImBufAnim *anim, AVFrame *input, ImBuf *ibuf)
|
||||
if (filter_y) {
|
||||
IMB_filtery(ibuf);
|
||||
}
|
||||
|
||||
/* Rotate video if display matrix is multiple of 90 degrees. */
|
||||
if (ELEM(anim->video_rotation, 90, 180, 270)) {
|
||||
IMB_rotate_orthogonal(ibuf, anim->video_rotation);
|
||||
}
|
||||
}
|
||||
|
||||
static void final_frame_log(ImBufAnim *anim,
|
||||
@@ -1355,10 +1362,10 @@ bool IMB_anim_get_fps(const ImBufAnim *anim,
|
||||
|
||||
int IMB_anim_get_image_width(ImBufAnim *anim)
|
||||
{
|
||||
return anim->x;
|
||||
return ELEM(anim->video_rotation, 90, 270) ? anim->y : anim->x;
|
||||
}
|
||||
|
||||
int IMB_anim_get_image_height(ImBufAnim *anim)
|
||||
{
|
||||
return anim->y;
|
||||
return ELEM(anim->video_rotation, 90, 270) ? anim->x : anim->y;
|
||||
}
|
||||
|
||||
@@ -470,7 +470,10 @@ static proxy_output_ctx *alloc_proxy_output_ffmpeg(ImBufAnim *anim,
|
||||
}
|
||||
|
||||
rv->of = avformat_alloc_context();
|
||||
rv->of->oformat = av_guess_format("avi", nullptr, nullptr);
|
||||
/* Note: we keep on using .avi extension for proxies,
|
||||
* but actual container can not be AVI, since it does not support
|
||||
* video rotation metadata. */
|
||||
rv->of->oformat = av_guess_format("mp4", nullptr, nullptr);
|
||||
|
||||
rv->of->url = av_strdup(filepath);
|
||||
|
||||
@@ -551,6 +554,8 @@ static proxy_output_ctx *alloc_proxy_output_ffmpeg(ImBufAnim *anim,
|
||||
|
||||
avcodec_parameters_from_context(rv->st->codecpar, rv->c);
|
||||
|
||||
ffmpeg_copy_display_matrix(st, rv->st);
|
||||
|
||||
int ret = avio_open(&rv->of->pb, filepath, AVIO_FLAG_WRITE);
|
||||
|
||||
if (ret < 0) {
|
||||
|
||||
Reference in New Issue
Block a user