Fix #107493: Auto rotate videos fix #115661

Open
ErikHK wants to merge 7 commits from ErikHK/blender:auto_rotate_video into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
4 changed files with 374 additions and 94 deletions
Showing only changes of commit 546b4f4d18 - Show all commits

View File

@ -1,89 +0,0 @@
# SPDX-FileCopyrightText: 2020 Blender Authors
#
# SPDX-License-Identifier: BSD-3-Clause
# - Find FFmpeg library and includes.
# Set FFMPEG_FIND_COMPONENTS to the canonical names of the libraries
# before using the module.
# This module defines
# FFMPEG_INCLUDE_DIRS, where to find libavcodec/ac3_parser.h.
# FFMPEG_LIBRARIES, libraries to link against to use FFmpeg.
# FFMPEG_ROOT_DIR, The base directory to search for FFmpeg.
# This can also be an environment variable.
# FFMPEG_FOUND, If false, do not try to use FFmpeg.
# FFMPEG_<COMPONENT>_LIBRARY, the given individual component libraries.
# If `FFMPEG_ROOT_DIR` was defined in the environment, use it.
if(DEFINED FFMPEG_ROOT_DIR)
# Pass.
elseif(DEFINED ENV{FFMPEG_ROOT_DIR})
set(FFMPEG_ROOT_DIR $ENV{FFMPEG_ROOT_DIR})
else()
set(FFMPEG_ROOT_DIR "")
endif()
set(_ffmpeg_SEARCH_DIRS
${FFMPEG_ROOT_DIR}
/opt/lib/ffmpeg
)
if(NOT FFMPEG_FIND_COMPONENTS)
set(FFMPEG_FIND_COMPONENTS
# List taken from http://ffmpeg.org/download.html#build-mac
avcodec
avdevice
avfilter
avformat
avutil
swscale
swresample
)
endif()
find_path(_ffmpeg_INCLUDE_DIR
NAMES
libavcodec/ac3_parser.h
HINTS
${_ffmpeg_SEARCH_DIRS}
PATH_SUFFIXES
include
)
set(_ffmpeg_LIBRARIES)
foreach(_component ${FFMPEG_FIND_COMPONENTS})
string(TOUPPER ${_component} _upper_COMPONENT)
find_library(FFMPEG_${_upper_COMPONENT}_LIBRARY
NAMES
${_component}
HINTS
${_ffmpeg_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
if(NOT FFMPEG_${_upper_COMPONENT}_LIBRARY)
message(WARNING "Could NOT find FFmpeg ${_upper_COMPONENT}.")
endif()
list(APPEND _ffmpeg_LIBRARIES ${FFMPEG_${_upper_COMPONENT}_LIBRARY})
mark_as_advanced(FFMPEG_${_upper_COMPONENT}_LIBRARY)
endforeach()
# handle the QUIETLY and REQUIRED arguments and set FFMPEG_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FFmpeg DEFAULT_MSG
_ffmpeg_LIBRARIES _ffmpeg_INCLUDE_DIR)
if(FFMPEG_FOUND)
set(FFMPEG_LIBRARIES ${_ffmpeg_LIBRARIES})
set(FFMPEG_INCLUDE_DIRS ${_ffmpeg_INCLUDE_DIR})
endif()
mark_as_advanced(
FFMPEG_INCLUDE_DIR
)
unset(_ffmpeg_SEARCH_DIRS)
unset(_ffmpeg_LIBRARIES)
# In cmake version 3.21 and up, we can instead use the NO_CACHE option for
# find_path so we don't need to clear it from the cache here.
unset(_ffmpeg_INCLUDE_DIR CACHE)

View File

@ -749,6 +749,12 @@ struct ImBuf *IMB_double_y(struct ImBuf *ibuf1);
*/
void IMB_flipx(struct ImBuf *ibuf);
void IMB_flipy(struct ImBuf *ibuf);
void IMB_rotate90(struct ImBuf *ibuf);
/*
void IMB_rotate90(struct ImBuf *ibuf);
void IMB_rotate270(struct ImBuf *ibuf);
*/
/* Pre-multiply alpha. */

View File

@ -71,6 +71,8 @@ extern "C" {
# include <libavutil/rational.h>
# include <libswscale/swscale.h>
#include <libavutil/display.h>
# include "ffmpeg_compat.h"
}
@ -497,6 +499,17 @@ static int startffmpeg(anim *anim)
video_stream = pFormatCtx->streams[video_stream_index];
//TESTA ??
//video_stream->codecpar->height = 1920;
//video_stream->codecpar->width = 1080;
//video_stream->codecpar->height = 1920;
//video_stream->codecpar->width = 1920;
//pekar till samma som ovan!!
//pFormatCtx->streams[video_stream_index]->codecpar->height = 1920;
//pFormatCtx->streams[video_stream_index]->codecpar->width = 1080;
/* Find the decoder for the video stream */
pCodec = avcodec_find_decoder(video_stream->codecpar->codec_id);
if (pCodec == nullptr) {
@ -508,6 +521,15 @@ static int startffmpeg(anim *anim)
avcodec_parameters_to_context(pCodecCtx, video_stream->codecpar);
pCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
//TESTA !
//pCodecCtx->width = 1080;
//pCodecCtx->height = 1920;
//pCodecCtx->width = 1920;
//pCodecCtx->height = 1920;
if (pCodec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
pCodecCtx->thread_count = 0;
}
@ -522,6 +544,7 @@ static int startffmpeg(anim *anim)
pCodecCtx->thread_type = FF_THREAD_SLICE;
}
if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0) {
avformat_close_input(&pFormatCtx);
return -1;
@ -532,6 +555,20 @@ static int startffmpeg(anim *anim)
return -1;
}
//TESTA ?? width och height sattes tillbaka!!
//pCodecCtx->height = 1920;
//pCodecCtx->width = 1080;
//pCodecCtx->coded_height = 1920;
//pCodecCtx->coded_width = 1088;
//pCodecCtx->coded_width = 1088;
//video_stream->codecpar->height = 1920;
//video_stream->codecpar->width = 1080;
double video_start = 0;
double pts_time_base = av_q2d(video_stream->time_base);
@ -705,6 +742,21 @@ static int startffmpeg(anim *anim)
nullptr,
nullptr);
/*
anim->img_convert_ctx = sws_getContext(anim->x,
anim->y,
anim->pCodecCtx->pix_fmt,
anim->y,
anim->x,
AV_PIX_FMT_ABGR,
SWS_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
nullptr,
nullptr,
nullptr);
*/
if (!anim->img_convert_ctx) {
fprintf(stderr, "Can't transform color space??? Bailing out...\n");
avcodec_free_context(&anim->pCodecCtx);
@ -875,6 +927,229 @@ static void ffmpeg_postprocess(anim *anim, AVFrame *input, ImBuf *ibuf)
if (filter_y) {
IMB_filtery(ibuf);
}
<<<<<<< Updated upstream
//TESTA FLIPPA X
//IMB_flipx(ibuf);
//Also testa lägga in massa nollor!
//woop ger fint mönster :)
//for(int i = 0; i < 1920*1080*4; i+=1)
// ibuf->byte_buffer.data[i] = i % 100;
//IMB_rotate90(ibuf);
/*
void IMB_transform(const struct ImBuf *src,
struct ImBuf *dst,
eIMBTransformMode mode,
eIMBInterpolationFilterMode filter,
const int num_subsamples,
const float transform_matrix[4][4],
const struct rctf *src_crop);
*/
//ImBuf *dst = nullptr;
//IMB_transform(ibuf, 0, 0, 0, matrix);
//ImBuf * dst = (ImBuf *) malloc(sizeof(uint) * 1920 * 1080);
ImBuf * tbuf;
int x, y;
uint * rect, *frect, *ibufrect;
int skip;
ibufrect = (uint *) ibuf->byte_buffer.data;
if (ibuf == 0) return;
//if (ibuf->rect == 0) return;
tbuf = IMB_allocImBuf(ibuf->y, ibuf->x, 32, IB_rect);
if (tbuf == 0) return;
frect = (uint *) tbuf->byte_buffer.data;
skip = tbuf->y;
for (y = tbuf->y - 1; y >= 0; y--){
rect = ibufrect + y;
for (x = tbuf->x; x > 0; x--){
*frect++ = *rect;
rect += skip;
}
}
memcpy(ibufrect, tbuf->byte_buffer.data, ibuf->x * ibuf->y * sizeof(uint));
x = ibuf->x;
ibuf->x = ibuf->y;
ibuf->y = x;
IMB_freeImBuf(tbuf);
/*
int width, height;
width = ibuf->x;
height = ibuf->y;
//new imbuf
//ImBuf * dest = IMB_allocImBuf(1080, 1920, 32, IB_rect);
uint8_t * dest = (uint8_t *) malloc(sizeof(uint) * width * height);
//uint8_t * dest = nullptr;
//memcpy(dest, ibuf->byte_buffer.data, 1920*1080*4);
if (ibuf == nullptr) {
return;
}
if (ibuf->byte_buffer.data) {
uint8_t *rect = (uint8_t *)ibuf->byte_buffer.data;
for (int h = 0, dest_col = height*4 - 1; h < height; h++, --dest_col)
{
for (int w = 0; w < width; w++)
{
dest[(w * height) + dest_col] = rect[h*width + w];
dest[((w+1) * height) + dest_col] = rect[h*width + w+1];
dest[((w+2) * height) + dest_col] = rect[h*width + w+2];
dest[((w+3) * height) + dest_col] = rect[h*width + w+3];
}
}
*/
/*
for(int xi = 0, hi=height-1; xi < width*4; xi++, --hi)
{
for(int yi = 0; yi < height*4; yi++)
{
//
dest[xi + width*yi] = rect[hi*4 + yi*4];
}
}
*/
//int i;
//for (i = 0; i < width*4; i++)
// dest[i*width + 0 + 1] = rect[i + 1];
//}
//ibuf->byte_buffer.data = dest;
//ImBuf * newibuf = IMB_allocImBuf(1920, 1920, 32, IB_rect);
//copy image to larger one
//memcpy(newibuf->byte_buffer.data, ibuf->byte_buffer.data, 1920*1080*4);
//ImBuf * dst = IMB_dupImBuf(ibuf);
//for(int i = 0; i < 1920*1920*4; i+=1)
// dst->byte_buffer.data[i] = i % 100;
//float rotation_matrix[4][4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, .707, .707}, {0, 0, .707, .707} };
//float rotation_matrix[4][4] = {{1, 0, 0, -1}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} };
//float rotation_matrix[4][4] = {{0, -1, 0, 0}, {1, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} };
//float rotation_matrix[4][4] = {{1, 0, 0, 0}, {0, 0, -1, 0}, {0, 1, 0, 0}, {0, 0, 0, 1} };
/*
float rotation_matrix[4][4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} };
//unit_m3(rotation_matrix);
//ImBuf * dst = nullptr;
//dst = IMB_allocImBuf(1080, 1920, 32, IB_rect);
//transform_pivot_set_m4(transform_matrix, pivot);
//invert_m4(transform_matrix);
//void rotate_m4(float mat[4][4], char axis, float angle);
rotate_m4(rotation_matrix, 'Z', 1.570796327);
//rotate_m4(rotation_matrix, 'Z', .2);
//mat4_to_rot(rot, rotation_matrix);
//void loc_axisangle_size_to_mat4(
// float R[4][4], const float loc[3], const float axis[3], float angle, const float size[3]);
float loc[3] = {float (1080 + anim->cur_position*10), float (-400 + anim->cur_position*10), 0};
float axis[3] = {0, 0, 1};
float rot[3][3];
float size[3] = {1, 1, 1};
mat4_to_rot(rot, rotation_matrix);
loc_rot_size_to_mat4(rotation_matrix, loc, rot, size);
//loc_axisangle_size_to_mat4(rotation_matrix, loc, axis, 15, size);
IMB_transform(ibuf,
dst,
IMB_TRANSFORM_MODE_REGULAR,
IMB_FILTER_NEAREST,
1,
rotation_matrix,
nullptr);
*/
//ibuf = IMB_dupImBuf(dst);
//ibuf->x = 1920;
//ibuf->y = 1920;
//memcpy(ibuf->byte_buffer.data, dst->byte_buffer.data, 1920*1080*4);
//memcpy(ibuf->byte_buffer.data, dst->byte_buffer.data, 1920*1920*4);
//ibuf = dst;
//dst = ibuf;
//IMB_freeImBuf(dst);
=======
//auto rotate video
//get display matrix rotation to see if a rotation is in order:
uint8_t* displaymatrix = av_stream_get_side_data(anim->pFormatCtx->streams[anim->videoStream],
AV_PKT_DATA_DISPLAYMATRIX, NULL);
if(displaymatrix == nullptr)
return;
double theta = 0;
theta = av_display_rotation_get((int32_t*) displaymatrix);
//perform rotation
if(theta != 0)
{
IMB_rotate90(ibuf);
}
>>>>>>> Stashed changes
}
static void final_frame_log(anim *anim,
@ -1386,8 +1661,17 @@ static ImBuf *ffmpeg_fetchibuf(anim *anim, int position, IMB_Timecode_Type tc)
ffmpeg_decode_video_frame_scan(anim, pts_to_search);
/* Update resolution as it can change per-frame with WebM. See #100741 & #100081. */
anim->x = anim->pCodecCtx->width;
anim->y = anim->pCodecCtx->height;
//anim->x = anim->pCodecCtx->width;
//anim->y = anim->pCodecCtx->height;
//TESTA flippa här!
//anim->x = anim->pCodecCtx->height;
//anim->y = anim->pCodecCtx->width;
//anim->x = 1080;
//anim->y = 1920;
/* Certain versions of FFmpeg have a bug in libswscale which ends up in crash
* when destination buffer is not properly aligned. For example, this happens
@ -1433,9 +1717,11 @@ static ImBuf *ffmpeg_fetchibuf(anim *anim, int position, IMB_Timecode_Type tc)
/* Even with the fallback from above it is possible that the current decode frame is nullptr. In
* this case skip post-processing and return current image buffer. */
if (final_frame != nullptr) {
ffmpeg_postprocess(anim, final_frame, cur_frame_final);
}
//if (final_frame != nullptr) {
// ffmpeg_postprocess(anim, final_frame, cur_frame_final);
//}
ffmpeg_postprocess(anim, final_frame, cur_frame_final);
anim->cur_position = position;

View File

@ -108,3 +108,80 @@ void IMB_flipx(ImBuf *ibuf)
}
}
}
<<<<<<< Updated upstream
/*
void IMB_rotate90(ImBuf *ibuf){
int width, height;
ErikHK marked this conversation as resolved
Review

Reduce the scope of variables. So instead of defining them in the beginning of the function define close to where you use htem. Examples:

  • ImBuf *tbuf = IMB_allocImBuf(ibuf->y, ibuf->x, 32, IB_rect);
  • for (int y = tbuf->y - 1; y >= 0; y--) {
Reduce the scope of variables. So instead of defining them in the beginning of the function define close to where you use htem. Examples: - `ImBuf *tbuf = IMB_allocImBuf(ibuf->y, ibuf->x, 32, IB_rect);` - `for (int y = tbuf->y - 1; y >= 0; y--) {`
width = ibuf->x;
height = ibuf->y;
uint * dest = (uint *) malloc(sizeof(uint) * width * height);
//uint8_t * dest = nullptr;
ErikHK marked this conversation as resolved Outdated

nullptr instead of 0.

`nullptr` instead of `0`.
//memcpy(dest, ibuf->byte_buffer.data, 1920*1080*4);
if (ibuf == nullptr) {
return;
}

You can duplicate just the data, and use that as a const-source , and write the rotated result directly to the ibuf->byte_buffer. This way you wouldn't need the extra memcpy after the loop.

You can duplicate just the data, and use that as a const-source , and write the rotated result directly to the `ibuf->byte_buffer`. This way you wouldn't need the extra `memcpy` after the loop.

Thanks for the tip! I think I solved it in the way you suggested, but since I'm not great at memory handling and stuff in C it would be nice if you could take a look at it :)

Thanks for the tip! I think I solved it in the way you suggested, but since I'm not great at memory handling and stuff in C it would be nice if you could take a look at it :)
if (ibuf->byte_buffer.data) {
uint *rect = (uint *)ibuf->byte_buffer.data;
for (int h = 0, dest_col = height - 1; h < height; ++h, --dest_col)
{
for (int w = 0; w < width; w++)
{
dest[(w * height) + dest_col] = rect[h*width + w];
}
}
}
ibuf->byte_buffer.data = (uint8_t *) dest;
//todo: free old image?? no?
}
*/
=======
void IMB_rotate90(ImBuf * ibuf)
{
ImBuf * tbuf;
int x, y;
uint * rect, *frect, *ibufrect;
int skip;
ibufrect = (uint *) ibuf->byte_buffer.data;
if (ibuf == 0) return;
if (ibufrect == 0) return;
tbuf = IMB_allocImBuf(ibuf->y, ibuf->x, 32, IB_rect);
if (tbuf == 0) return;
frect = (uint *) tbuf->byte_buffer.data;
skip = tbuf->y;
for (y = tbuf->y - 1; y >= 0; y--){
rect = ibufrect + y;
for (x = tbuf->x; x > 0; x--){
*frect++ = *rect;
rect += skip;
}
}
memcpy(ibufrect, tbuf->byte_buffer.data, ibuf->x * ibuf->y * sizeof(uint));
x = ibuf->x;
ibuf->x = ibuf->y;
ibuf->y = x;
IMB_freeImBuf(tbuf);
}
>>>>>>> Stashed changes