summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Stebbins <[email protected]>2016-01-25 08:50:13 -0800
committerJohn Stebbins <[email protected]>2016-01-25 08:50:13 -0800
commit14ec182e0a9c1554e4472c735a2f8162e18378ce (patch)
tree392154c425fc513893bd4109b20d36579eab1c93
parent554e8336455e23b56e0c6dbc18d768aa10fc9d03 (diff)
parente104c704293edb45b714dca5923b162992205442 (diff)
Merge pull request #60 from jstebbins/rotate
rotate: use libavfilter
-rw-r--r--libhb/avfilter.c13
-rw-r--r--libhb/param.c135
-rw-r--r--libhb/rotate.c429
3 files changed, 142 insertions, 435 deletions
diff --git a/libhb/avfilter.c b/libhb/avfilter.c
index a58f6009e..b145b7a0d 100644
--- a/libhb/avfilter.c
+++ b/libhb/avfilter.c
@@ -62,6 +62,18 @@ hb_filter_object_t hb_filter_pad =
.info = avfilter_info,
};
+hb_filter_object_t hb_filter_rotate =
+{
+ .id = HB_FILTER_ROTATE,
+ .enforce_order = 1,
+ .name = "avfilter",
+ .settings = NULL,
+ .init = avfilter_init,
+ .work = avfilter_work,
+ .close = avfilter_close,
+ .info = avfilter_info,
+};
+
static AVFilterContext * append_filter( hb_filter_private_t * pv,
const char * name, const char * args)
{
@@ -416,6 +428,7 @@ void hb_avfilter_combine( hb_list_t * list )
switch (filter->id)
{
case HB_FILTER_AVFILTER:
+ case HB_FILTER_ROTATE:
case HB_FILTER_PAD:
if (avfilter != NULL)
{
diff --git a/libhb/param.c b/libhb/param.c
index f56f3957b..8deaed3c3 100644
--- a/libhb/param.c
+++ b/libhb/param.c
@@ -104,6 +104,129 @@ static filter_param_map_t param_map[] =
{ HB_FILTER_INVALID, NULL, NULL, 0 }
};
+/* 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)
+ */
+char *
+generate_rotate_settings(const char * preset, const char * tune)
+{
+ char ** args;
+ const char * trans = NULL;
+ char * result;
+ int ii, angle = 180, flip = 0, hflip = 0, vflip = 0;
+
+ args = hb_str_vsplit(preset, ':');
+ for (ii = 0; ii < 2 && args[ii]; ii++)
+ {
+ switch (ii)
+ {
+ case 0:
+ angle = strtol(args[ii], &result, 0);
+ break;
+ case 1:
+ flip = strtol(args[ii], &result, 0);
+ break;
+ default:
+ break;
+ }
+ }
+ hb_str_vfree(args);
+ if (angle < 8 && ii == 1)
+ {
+ // Legacy value
+ switch (angle)
+ {
+ case 1:
+ vflip = 1;
+ break;
+ case 2:
+ hflip = 1;
+ break;
+ case 3:
+ vflip = hflip = 1;
+ break;
+ case 4:
+ trans = "clock";
+ break;
+ case 5:
+ trans = "cclock_flip";
+ break;
+ case 6:
+ trans = "clock_flip";
+ break;
+ case 7:
+ trans = "cclock";
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ const char * clock;
+ const char * cclock;
+ if (flip)
+ {
+ clock = "clock_flip";
+ cclock = "cclock_flip";
+ }
+ else
+ {
+ clock = "clock";
+ cclock = "cclock";
+ }
+ switch (angle)
+ {
+ case 0:
+ hflip = flip;
+ break;
+ case 90:
+ trans = clock;
+ break;
+ case 180:
+ vflip = hflip = 1;
+ break;
+ case 270:
+ trans = cclock;
+ break;
+ default:
+ break;
+ }
+ }
+ if (trans != NULL)
+ {
+ return hb_strdup_printf("transpose='dir=%s'", trans);
+ }
+ else if (vflip || hflip)
+ {
+ return hb_strdup_printf("%s%s%s",
+ vflip ? "vflip" : "",
+ hflip ? ", " : "",
+ hflip ? "hflip" : "");
+ }
+ else
+ {
+ return (char*)hb_filter_off;
+ }
+}
+
/* Pad presets and tunes
*
* There are currently no presets and tunes for pad
@@ -615,15 +738,15 @@ hb_generate_filter_settings(int filter_id, const char *preset, const char *tune)
if (hb_validate_filter_settings(filter_id, preset)) return NULL;
return generate_pad_settings(preset, tune);
+ case HB_FILTER_ROTATE:
+ if (preset == NULL) return NULL;
+ if (!strcasecmp(preset, "off")) return (char*)hb_filter_off;
+ if (hb_validate_filter_settings(filter_id, preset)) return NULL;
+
+ return generate_rotate_settings(preset, tune);
case HB_FILTER_NLMEANS:
filter_param = generate_nlmeans_settings(preset, tune);
break;
- case HB_FILTER_ROTATE:
- if (atoi(preset) == 0)
- filter_param = (char*)hb_filter_off;
- else
- filter_param = strdup(preset);
- break;
case HB_FILTER_DEBLOCK:
if (atoi(preset) < 5)
filter_param = (char*)hb_filter_off;
diff --git a/libhb/rotate.c b/libhb/rotate.c
deleted file mode 100644
index f407eabbf..000000000
--- a/libhb/rotate.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/* rorate.c
-
- Copyright (c) 2003-2016 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 "hb.h"
-#include "hbffmpeg.h"
-#include "taskset.h"
-
-#define MODE_DEFAULT 3
-// 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)
-
-typedef struct rotate_arguments_s {
- hb_buffer_t *dst;
- hb_buffer_t *src;
-} rotate_arguments_t;
-
-struct hb_filter_private_s
-{
- int mode;
- int width;
- int height;
- hb_rational_t par;
-
- int cpu_count;
-
- taskset_t rotate_taskset; // Threads for Rotate - one per CPU
- rotate_arguments_t *rotate_arguments; // Arguments to thread for work
-};
-
-static int hb_rotate_init( hb_filter_object_t * filter,
- hb_filter_init_t * init );
-
-static int hb_rotate_work( hb_filter_object_t * filter,
- hb_buffer_t ** buf_in,
- hb_buffer_t ** buf_out );
-
-static void hb_rotate_close( hb_filter_object_t * filter );
-
-static hb_filter_info_t * hb_rotate_info( hb_filter_object_t * filter );
-
-hb_filter_object_t hb_filter_rotate =
-{
- .id = HB_FILTER_ROTATE,
- .enforce_order = 1,
- .name = "Rotate (rotate & flip image axes)",
- .settings = NULL,
- .init = hb_rotate_init,
- .work = hb_rotate_work,
- .close = hb_rotate_close,
- .info = hb_rotate_info
-};
-
-
-typedef struct rotate_thread_arg_s {
- hb_filter_private_t *pv;
- int segment;
-} rotate_thread_arg_t;
-
-/*
- * rotate this segment of all three planes in a single thread.
- */
-void rotate_filter_thread( void *thread_args_v )
-{
- rotate_arguments_t *rotate_work = NULL;
- hb_filter_private_t * pv;
- int run = 1;
- int plane;
- int segment, segment_start, segment_stop;
- rotate_thread_arg_t *thread_args = thread_args_v;
- uint8_t *dst;
- hb_buffer_t *dst_buf;
- hb_buffer_t *src_buf;
- int y;
-
-
- pv = thread_args->pv;
- segment = thread_args->segment;
-
- hb_log("Rotate thread started for segment %d", segment);
-
- while( run )
- {
- /*
- * Wait here until there is work to do.
- */
- taskset_thread_wait4start( &pv->rotate_taskset, segment );
-
- if( taskset_thread_stop( &pv->rotate_taskset, segment ) )
- {
- /*
- * No more work to do, exit this thread.
- */
- run = 0;
- goto report_completion;
- }
-
- rotate_work = &pv->rotate_arguments[segment];
- if( rotate_work->dst == NULL )
- {
- hb_error( "Thread started when no work available" );
- hb_snooze(500);
- goto report_completion;
- }
-
- /*
- * Process all three planes, but only this segment of it.
- */
- dst_buf = rotate_work->dst;
- src_buf = rotate_work->src;
- for( plane = 0; plane < 3; plane++)
- {
- int dst_stride, src_stride;
-
- dst = dst_buf->plane[plane].data;
- dst_stride = dst_buf->plane[plane].stride;
- src_stride = src_buf->plane[plane].stride;
-
- int h = src_buf->plane[plane].height;
- int w = src_buf->plane[plane].width;
- segment_start = ( h / pv->cpu_count ) * segment;
- if( segment == pv->cpu_count - 1 )
- {
- /*
- * Final segment
- */
- segment_stop = h;
- } else {
- segment_stop = ( h / pv->cpu_count ) * ( segment + 1 );
- }
-
- for( y = segment_start; y < segment_stop; y++ )
- {
- uint8_t * cur;
- int x, xo, yo;
-
- cur = &src_buf->plane[plane].data[y * src_stride];
- for( x = 0; x < w; x++)
- {
- if( pv->mode & 1 )
- {
- yo = h - y - 1;
- }
- else
- {
- yo = y;
- }
- if( pv->mode & 2 )
- {
- xo = w - x - 1;
- }
- else
- {
- xo = x;
- }
- if( pv->mode & 4 ) // Rotate 90 clockwise
- {
- int tmp = xo;
- xo = h - yo - 1;
- yo = tmp;
- }
- dst[yo*dst_stride + xo] = cur[x];
- }
- }
- }
-
-report_completion:
- /*
- * Finished this segment, let everyone know.
- */
- taskset_thread_complete( &pv->rotate_taskset, segment );
- }
-}
-
-
-/*
- * threaded rotate - each thread rotates a single segment of all
- * three planes. Where a segment is defined as the frame divided by
- * the number of CPUs.
- *
- * This function blocks until the frame is rotated.
- */
-static void rotate_filter(
- hb_filter_private_t * pv,
- hb_buffer_t *out,
- hb_buffer_t *in )
-{
-
- int segment;
-
- for( segment = 0; segment < pv->cpu_count; segment++ )
- {
- /*
- * Setup the work for this plane.
- */
- pv->rotate_arguments[segment].dst = out;
- pv->rotate_arguments[segment].src = in;
- }
-
- /*
- * Allow the taskset threads to make one pass over the data.
- */
- taskset_cycle( &pv->rotate_taskset );
-
- /*
- * Entire frame is now rotated.
- */
-}
-
-
-static int hb_rotate_init( hb_filter_object_t * filter,
- hb_filter_init_t * init )
-{
- filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
- hb_filter_private_t * pv = filter->private_data;
-
- int degrees = MODE_DEFAULT, mirror = 0, num_params = 0;
-
- if( filter->settings )
- {
- num_params = sscanf(filter->settings, "%d:%d", &degrees, &mirror);
- }
- switch (degrees)
- {
- case 0:
- pv->mode = 0;
- break;
- case 90:
- pv->mode = 4;
- break;
- case 180:
- pv->mode = 3;
- break;
- case 270:
- pv->mode = 7;
- break;
- default:
- if (degrees & ~7)
- {
- // Unsupported rotation angle
- hb_error("Unsupported rotate mode %d", degrees);
- }
- // Legacy "mode" supplied in settings
- pv->mode = degrees & 7;
- break;
- }
- if (num_params > 1 && mirror)
- pv->mode ^= 2;
-
- pv->cpu_count = hb_get_cpu_count();
-
- /*
- * Create rotate taskset.
- */
- pv->rotate_arguments = malloc( sizeof( rotate_arguments_t ) * pv->cpu_count );
- if( pv->rotate_arguments == NULL ||
- taskset_init( &pv->rotate_taskset, /*thread_count*/pv->cpu_count,
- sizeof( rotate_thread_arg_t ) ) == 0 )
- {
- hb_error( "rotate could not initialize taskset" );
- }
-
- int i;
- for( i = 0; i < pv->cpu_count; i++ )
- {
- rotate_thread_arg_t *thread_args;
-
- thread_args = taskset_thread_args( &pv->rotate_taskset, i );
-
- thread_args->pv = pv;
- thread_args->segment = i;
- pv->rotate_arguments[i].dst = NULL;
-
- if( taskset_thread_spawn( &pv->rotate_taskset, i,
- "rotate_filter_segment",
- rotate_filter_thread,
- HB_NORMAL_PRIORITY ) == 0 )
- {
- hb_error( "rotate could not spawn thread" );
- }
- }
- // Set init width/height so the next stage in the pipline
- // knows what it will be getting
- if( pv->mode & 4 )
- {
- // 90 degree rotation, exchange width and height
- int tmp = init->geometry.width;
- init->geometry.width = init->geometry.height;
- init->geometry.height = tmp;
-
- tmp = init->geometry.par.num;
- init->geometry.par.num = init->geometry.par.den;
- init->geometry.par.den = tmp;
- }
- pv->width = init->geometry.width;
- pv->height = init->geometry.height;
- pv->par = init->geometry.par;
-
- return 0;
-}
-
-static hb_filter_info_t * hb_rotate_info( hb_filter_object_t * filter )
-{
- hb_filter_private_t * pv = filter->private_data;
- hb_filter_info_t * info;
-
- if( !pv )
- return NULL;
-
- info = calloc(1, sizeof(hb_filter_info_t));
- info->human_readable_desc = malloc(128);
- info->human_readable_desc[0] = 0;
-
- info->out.geometry.width = pv->width;
- info->out.geometry.height = pv->height;
- info->out.geometry.par = pv->par;
-
- int mirror_x = !!(pv->mode & 2);
- int mirror_y = !!(pv->mode & 1);
- int degrees = 0;
- if (mirror_y)
- {
- degrees += 180;
- mirror_x ^= 1;
- mirror_y ^= 1;
- }
- degrees += !!(pv->mode & 4) * 90;
-
- if (degrees > 0)
- {
- snprintf(info->human_readable_desc, 128, "Rotate %d%s", degrees,
- mirror_x ? " / mirror image" : "");
- }
- else if (mirror_x)
- {
- snprintf(info->human_readable_desc, 128, "Mirror image");
- }
- else
- {
- snprintf(info->human_readable_desc, 128, "No rotation or mirror!");
- }
- return info;
-}
-
-static void hb_rotate_close( hb_filter_object_t * filter )
-{
- hb_filter_private_t * pv = filter->private_data;
-
- if( !pv )
- {
- return;
- }
-
- taskset_fini( &pv->rotate_taskset );
-
- /*
- * free memory for rotate structs
- */
- free( pv->rotate_arguments );
-
- free( pv );
- filter->private_data = NULL;
-}
-
-static int hb_rotate_work( hb_filter_object_t * filter,
- hb_buffer_t ** buf_in,
- hb_buffer_t ** buf_out )
-{
- hb_filter_private_t * pv = filter->private_data;
- hb_buffer_t * in = *buf_in, * out;
-
- if (in->s.flags & HB_BUF_FLAG_EOF)
- {
- *buf_out = in;
- *buf_in = NULL;
- return HB_FILTER_DONE;
- }
- if (pv->mode == 0)
- {
- // Short circuit case where filter does nothing
- *buf_out = in;
- *buf_in = NULL;
- return HB_FILTER_OK;
- }
-
- int width_out, height_out;
- if ( pv->mode & 4 )
- {
- width_out = in->f.height;
- height_out = in->f.width;
- }
- else
- {
- width_out = in->f.width;
- height_out = in->f.height;
- }
-
- out = hb_video_buffer_init( width_out, height_out );
-
- // Rotate!
- rotate_filter( pv, out, in );
-
- out->s = in->s;
- *buf_out = out;
-
- return HB_FILTER_OK;
-}