diff options
author | John Stebbins <[email protected]> | 2016-01-25 08:50:13 -0800 |
---|---|---|
committer | John Stebbins <[email protected]> | 2016-01-25 08:50:13 -0800 |
commit | 14ec182e0a9c1554e4472c735a2f8162e18378ce (patch) | |
tree | 392154c425fc513893bd4109b20d36579eab1c93 | |
parent | 554e8336455e23b56e0c6dbc18d768aa10fc9d03 (diff) | |
parent | e104c704293edb45b714dca5923b162992205442 (diff) |
Merge pull request #60 from jstebbins/rotate
rotate: use libavfilter
-rw-r--r-- | libhb/avfilter.c | 13 | ||||
-rw-r--r-- | libhb/param.c | 135 | ||||
-rw-r--r-- | libhb/rotate.c | 429 |
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", °rees, &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; -} |