mirror of https://github.com/HandBrake/HandBrake
270 lines
7.7 KiB
C
270 lines
7.7 KiB
C
/* rotate.c
|
|
|
|
Copyright (c) 2003-2025 HandBrake Team
|
|
This file is part of the HandBrake source code
|
|
Homepage: <http://handbrake.fr/>.
|
|
It may be used under the terms of the GNU General Public License v2.
|
|
For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
|
|
*/
|
|
|
|
#include "handbrake/common.h"
|
|
#include "handbrake/avfilter_priv.h"
|
|
|
|
static int rotate_init(hb_filter_object_t * filter, hb_filter_init_t * init);
|
|
|
|
const char rotate_template[] =
|
|
"angle=^(0|90|180|270)$:hflip=^"HB_BOOL_REG"$:disable=^"HB_BOOL_REG"$";
|
|
|
|
hb_filter_object_t hb_filter_rotate =
|
|
{
|
|
.id = HB_FILTER_ROTATE,
|
|
.enforce_order = 1,
|
|
.skip = 1,
|
|
.name = "Rotate",
|
|
.settings = NULL,
|
|
.init = rotate_init,
|
|
.work = hb_avfilter_null_work,
|
|
.close = hb_avfilter_alias_close,
|
|
.settings_template = rotate_template,
|
|
};
|
|
|
|
/* Rotate Settings:
|
|
* degrees:mirror
|
|
*
|
|
* degrees - Rotation angle, may be one of 90, 180, or 270
|
|
* mirror - Mirror image around x axis
|
|
*
|
|
* Examples:
|
|
* Mode 180:1 Mirror then rotate 180'
|
|
* Mode 0:1 Mirror
|
|
* Mode 180:0 Rotate 180'
|
|
* Mode 90:0 Rotate 90'
|
|
* Mode 270:0 Rotate 270'
|
|
*
|
|
* Legacy Mode Examples (also accepted):
|
|
* Mode 1: Flip vertically (y0 becomes yN and yN becomes y0) (aka 180:1)
|
|
* Mode 2: Flip horizontally (x0 becomes xN and xN becomes x0) (aka 0:1)
|
|
* Mode 3: Flip both horizontally and vertically (aka 180:0)
|
|
* Mode 4: Rotate 90' (aka 90:0)
|
|
* Mode 7: Flip horiz & vert plus Rotate 90' (aka 270:0)
|
|
*/
|
|
|
|
#if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ ))
|
|
static int qsv_rotate_init(hb_filter_private_t * pv, hb_filter_init_t * init, int angle, int flip)
|
|
{
|
|
hb_rational_t par = init->geometry.par;
|
|
int width = init->geometry.width;
|
|
int height = init->geometry.height;
|
|
const char * trans = NULL;
|
|
int hflip = 0, vflip = 0;
|
|
|
|
switch (angle)
|
|
{
|
|
case 0:
|
|
hflip = flip;
|
|
break;
|
|
case 90:
|
|
trans = "clock";
|
|
width = init->geometry.height;
|
|
height = init->geometry.width;
|
|
par.num = init->geometry.par.den;
|
|
par.den = init->geometry.par.num;
|
|
break;
|
|
case 180:
|
|
trans = "reversal";
|
|
break;
|
|
case 270:
|
|
trans = "cclock";
|
|
width = init->geometry.height;
|
|
height = init->geometry.width;
|
|
par.num = init->geometry.par.den;
|
|
par.den = init->geometry.par.num;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (trans != NULL)
|
|
{
|
|
hb_dict_t * avfilter = hb_dict_init();
|
|
hb_dict_t * avsettings = hb_dict_init();
|
|
|
|
if(hflip)
|
|
{
|
|
char *s = hb_strdup_printf("%s_hflip", trans);
|
|
hb_dict_set(avsettings, "transpose", hb_value_string(s));
|
|
free(s);
|
|
}
|
|
else
|
|
{
|
|
hb_dict_set(avsettings, "transpose", hb_value_string(trans));
|
|
}
|
|
hb_dict_set_int(avsettings, "async_depth", init->job->hw_device_async_depth);
|
|
hb_dict_set(avfilter, "vpp_qsv", avsettings);
|
|
pv->avfilters = avfilter;
|
|
}
|
|
else if (hflip || vflip)
|
|
{
|
|
hb_value_array_t * avfilters = hb_value_array_init();
|
|
hb_dict_t * avfilter;
|
|
hb_dict_t * avsettings = hb_dict_init();
|
|
if (vflip)
|
|
{
|
|
avfilter = hb_dict_init();
|
|
|
|
hb_dict_set(avsettings, "transpose", hb_value_string("vflip"));
|
|
hb_dict_set_int(avsettings, "async_depth", init->job->hw_device_async_depth);
|
|
hb_dict_set(avfilter, "vpp_qsv", avsettings);
|
|
pv->avfilters = avfilter;
|
|
}
|
|
if (hflip)
|
|
{
|
|
avfilter = hb_dict_init();
|
|
|
|
hb_dict_set(avsettings, "transpose", hb_value_string("hflip"));
|
|
hb_dict_set_int(avsettings, "async_depth", init->job->hw_device_async_depth);
|
|
hb_dict_set(avfilter, "vpp_qsv", avsettings);
|
|
pv->avfilters = avfilter;
|
|
}
|
|
pv->avfilters = avfilters;
|
|
}
|
|
else
|
|
{
|
|
pv->avfilters = hb_value_null();
|
|
}
|
|
|
|
init->geometry.width = width;
|
|
init->geometry.height = height;
|
|
init->geometry.par = par;
|
|
pv->output = *init;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int rotate_init(hb_filter_object_t * filter, hb_filter_init_t * init)
|
|
{
|
|
hb_filter_private_t * pv = NULL;
|
|
|
|
pv = calloc(1, sizeof(struct hb_filter_private_s));
|
|
filter->private_data = pv;
|
|
if (pv == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
pv->input = *init;
|
|
|
|
hb_dict_t * settings = filter->settings;
|
|
|
|
hb_rational_t par = init->geometry.par;
|
|
int width = init->geometry.width;
|
|
int height = init->geometry.height;
|
|
const char * trans = NULL;
|
|
int angle = 0, flip = 0, hflip = 0, vflip = 0;
|
|
|
|
hb_dict_extract_int(&angle, settings, "angle");
|
|
hb_dict_extract_bool(&flip, settings, "hflip");
|
|
|
|
const char * clock;
|
|
const char * cclock;
|
|
if (flip)
|
|
{
|
|
clock = "clock_flip";
|
|
cclock = "cclock_flip";
|
|
}
|
|
else
|
|
{
|
|
clock = "clock";
|
|
cclock = "cclock";
|
|
}
|
|
|
|
#if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ ))
|
|
if (init->hw_pix_fmt == AV_PIX_FMT_QSV)
|
|
{
|
|
qsv_rotate_init(pv, init, angle, flip);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
switch (angle)
|
|
{
|
|
case 0:
|
|
hflip = flip;
|
|
break;
|
|
case 90:
|
|
trans = clock;
|
|
width = init->geometry.height;
|
|
height = init->geometry.width;
|
|
par.num = init->geometry.par.den;
|
|
par.den = init->geometry.par.num;
|
|
break;
|
|
case 180:
|
|
vflip = 1;
|
|
hflip = !flip;
|
|
break;
|
|
case 270:
|
|
trans = cclock;
|
|
width = init->geometry.height;
|
|
height = init->geometry.width;
|
|
par.num = init->geometry.par.den;
|
|
par.den = init->geometry.par.num;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (trans != NULL)
|
|
{
|
|
hb_value_array_t * avfilters = hb_value_array_init();
|
|
|
|
hb_dict_t * avfilter = hb_dict_init();
|
|
hb_dict_t * avsettings = hb_dict_init();
|
|
|
|
hb_dict_set(avsettings, "dir", hb_value_string(trans));
|
|
hb_dict_set(avfilter, "transpose", avsettings);
|
|
|
|
hb_value_array_append(avfilters, avfilter);
|
|
|
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(init->pix_fmt);
|
|
if (desc->log2_chroma_w != desc->log2_chroma_h)
|
|
{
|
|
avfilter = hb_dict_init();
|
|
avsettings = hb_dict_init();
|
|
hb_dict_set(avsettings, "pix_fmts", hb_value_string(av_get_pix_fmt_name(init->pix_fmt)));
|
|
hb_dict_set(avfilter, "format", avsettings);
|
|
|
|
hb_value_array_append(avfilters, avfilter);
|
|
}
|
|
|
|
pv->avfilters = avfilters;
|
|
}
|
|
else if (hflip || vflip)
|
|
{
|
|
hb_value_array_t * avfilters = hb_value_array_init();
|
|
hb_dict_t * avfilter;
|
|
if (vflip)
|
|
{
|
|
avfilter = hb_dict_init();
|
|
hb_dict_set(avfilter, "vflip", hb_value_null());
|
|
hb_value_array_append(avfilters, avfilter);
|
|
}
|
|
if (hflip)
|
|
{
|
|
avfilter = hb_dict_init();
|
|
hb_dict_set(avfilter, "hflip", hb_value_null());
|
|
hb_value_array_append(avfilters, avfilter);
|
|
}
|
|
pv->avfilters = avfilters;
|
|
}
|
|
else
|
|
{
|
|
pv->avfilters = hb_value_null();
|
|
}
|
|
|
|
init->geometry.width = width;
|
|
init->geometry.height = height;
|
|
init->geometry.par = par;
|
|
pv->output = *init;
|
|
|
|
return 0;
|
|
}
|