diff options
author | John Stebbins <[email protected]> | 2019-03-18 10:10:26 -0600 |
---|---|---|
committer | John Stebbins <[email protected]> | 2019-04-08 07:44:09 -0600 |
commit | 1613985b89008c3a54961127b392a90fb1588065 (patch) | |
tree | 1773c8a37cdd637ecdfb145c9819724682aefcc8 /libhb | |
parent | 44ca510aef7890f8c52c338f3c231d02b2150b62 (diff) |
avfilter: split individual filters to separate files
Splits the initialization of pad, cropscale, deinterlace, rotate, and
colorspace into their own files. Also splits internal avfilter API into
it's own file.
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/avfilter.c | 945 | ||||
-rw-r--r-- | libhb/avfilter_priv.h | 45 | ||||
-rw-r--r-- | libhb/colorspace.c | 90 | ||||
-rw-r--r-- | libhb/cropscale.c | 194 | ||||
-rw-r--r-- | libhb/decavcodec.c | 12 | ||||
-rw-r--r-- | libhb/deinterlace.c | 122 | ||||
-rw-r--r-- | libhb/hbavfilter.c | 282 | ||||
-rw-r--r-- | libhb/hbavfilter.h | 5 | ||||
-rw-r--r-- | libhb/pad.c | 122 | ||||
-rw-r--r-- | libhb/rotate.c | 146 |
10 files changed, 1024 insertions, 939 deletions
diff --git a/libhb/avfilter.c b/libhb/avfilter.c index febd239c9..6d69c97a8 100644 --- a/libhb/avfilter.c +++ b/libhb/avfilter.c @@ -7,70 +7,17 @@ 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 "hbavfilter.h" #include "common.h" -#include "libavfilter/avfilter.h" -#include "libavfilter/buffersrc.h" -#include "libavfilter/buffersink.h" -#include "decomb.h" - - -/***** - * This is a meta-filter. By itself it makes no modifications to the video. - * Other filters use this filter to perform their function (see pad.c) - */ -struct hb_avfilter_graph_s -{ - AVFilterGraph * avgraph; - AVFilterContext * last; - AVFilterContext * input; - AVFilterContext * output; - char * settings; - AVFrame * frame; - AVRational out_time_base; -}; - -struct hb_filter_private_s -{ - int initialized; - hb_avfilter_graph_t * graph; - - // Buffer list to delay output by one frame. Required to set stop time. - hb_buffer_list_t list; - - // Placeholder settings for AVFilter aliases - hb_value_t * avfilters; - hb_filter_init_t input; - hb_filter_init_t output; -}; +#include "hbavfilter.h" +#include "avfilter_priv.h" -static int avfilter_init(hb_filter_object_t * filter, hb_filter_init_t * init); -static int avfilter_post_init( hb_filter_object_t * filter, hb_job_t * job ); +static int avfilter_init(hb_filter_object_t * filter, hb_filter_init_t * init); +static int avfilter_post_init( hb_filter_object_t * filter, hb_job_t * job ); static void avfilter_close( hb_filter_object_t * filter ); -static void avfilter_alias_close( hb_filter_object_t * filter ); static int avfilter_work( hb_filter_object_t * filter, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ); static hb_filter_info_t * avfilter_info( hb_filter_object_t * filter ); -static int null_work( hb_filter_object_t * filter, - hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ); - -static int crop_scale_init(hb_filter_object_t * filter, - hb_filter_init_t * init); -static hb_filter_info_t * crop_scale_info( hb_filter_object_t * filter ); - -static int pad_init(hb_filter_object_t * filter, hb_filter_init_t * init); - -static int rotate_init(hb_filter_object_t * filter, hb_filter_init_t * init); - -static int deinterlace_init(hb_filter_object_t * filter, - hb_filter_init_t * init); - -static int colorspace_init(hb_filter_object_t * filter, - hb_filter_init_t * init); - hb_filter_object_t hb_filter_avfilter = { .id = HB_FILTER_AVFILTER, @@ -84,258 +31,13 @@ hb_filter_object_t hb_filter_avfilter = .info = avfilter_info, }; -static const char crop_scale_template[] = - "width=^"HB_INT_REG"$:height=^"HB_INT_REG"$:" - "crop-top=^"HB_INT_REG"$:crop-bottom=^"HB_INT_REG"$:" - "crop-left=^"HB_INT_REG"$:crop-right=^"HB_INT_REG"$"; - -hb_filter_object_t hb_filter_crop_scale = -{ - .id = HB_FILTER_CROP_SCALE, - .enforce_order = 1, - .skip = 1, - .name = "Crop and Scale", - .settings = NULL, - .init = crop_scale_init, - .work = null_work, - .close = avfilter_alias_close, - .info = crop_scale_info, - .settings_template = crop_scale_template, -}; - -const char pad_template[] = - "width=^"HB_INT_REG"$:height=^"HB_INT_REG"$:color=^"HB_ALL_REG"$:" - "x=^"HB_INT_REG"$:y=^"HB_INT_REG"$"; - -hb_filter_object_t hb_filter_pad = +int hb_avfilter_null_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { - .id = HB_FILTER_PAD, - .enforce_order = 1, - .skip = 1, - .name = "Pad", - .settings = NULL, - .init = pad_init, - .work = null_work, - .close = avfilter_alias_close, - .settings_template = pad_template, -}; - -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 = null_work, - .close = avfilter_alias_close, - .settings_template = rotate_template, -}; - -const char deint_template[] = - "mode=^"HB_INT_REG"$:parity=^([01])$"; - -hb_filter_object_t hb_filter_deinterlace = -{ - .id = HB_FILTER_DEINTERLACE, - .enforce_order = 1, - .skip = 1, - .name = "Deinterlace", - .settings = NULL, - .init = deinterlace_init, - .work = null_work, - .close = avfilter_alias_close, - .settings_template = deint_template, -}; - -const char colorspace_template[] = - "format=^"HB_ALL_REG"$:range=^"HB_ALL_REG"$:primaries=^"HB_ALL_REG"$:" - "matrix=^"HB_ALL_REG"$:transfer=^"HB_ALL_REG"$"; - -hb_filter_object_t hb_filter_colorspace = -{ - .id = HB_FILTER_COLORSPACE, - .enforce_order = 1, - .skip = 1, - .name = "Colorspace", - .settings = NULL, - .init = colorspace_init, - .work = null_work, - .close = avfilter_alias_close, - .settings_template = colorspace_template, -}; - -static int null_work( hb_filter_object_t * filter, - hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) -{ - hb_log("null_work: It is an error to call this function."); + hb_log("hb_avfilter_null_work: It is an error to call this function."); return HB_WORK_DONE; } -static AVFilterContext * append_filter( hb_avfilter_graph_t * graph, - const char * name, const char * args) -{ - AVFilterContext * filter; - int result; - - result = avfilter_graph_create_filter(&filter, avfilter_get_by_name(name), - name, args, NULL, graph->avgraph); - if (result < 0) - { - return NULL; - } - if (graph->last != NULL) - { - result = avfilter_link(graph->last, 0, filter, 0); - if (result < 0) - { - avfilter_free(filter); - return NULL; - } - } - graph->last = filter; - - return filter; -} - -hb_avfilter_graph_t * -hb_avfilter_graph_init(hb_value_t * settings, hb_filter_init_t * init) -{ - hb_avfilter_graph_t * graph; - AVFilterInOut * in = NULL, * out = NULL; - AVFilterContext * avfilter; - char * settings_str; - int result; - char * filter_args; - - graph = calloc(1, sizeof(hb_avfilter_graph_t)); - if (graph == NULL) - { - return NULL; - } - - settings_str = hb_filter_settings_string(HB_FILTER_AVFILTER, settings); - if (settings_str == NULL) - { - hb_error("hb_avfilter_graph_init: no filter settings specified"); - goto fail; - } - - graph->settings = settings_str; - graph->avgraph = avfilter_graph_alloc(); - if (graph->avgraph == NULL) - { - hb_error("hb_avfilter_graph_init: avfilter_graph_alloc failed"); - goto fail; - } - - av_opt_set(graph->avgraph, "scale_sws_opts", "lanczos+accurate_rnd", 0); - - result = avfilter_graph_parse2(graph->avgraph, settings_str, &in, &out); - if (result < 0 || in == NULL || out == NULL) - { - hb_error("hb_avfilter_graph_init: avfilter_graph_parse2 failed (%s)", - settings_str); - goto fail; - } - - // Build filter input - filter_args = hb_strdup_printf( - "width=%d:height=%d:pix_fmt=%d:sar=%d/%d:" - "time_base=%d/%d:frame_rate=%d/%d", - init->geometry.width, init->geometry.height, init->pix_fmt, - init->geometry.par.num, init->geometry.par.den, - init->time_base.num, init->time_base.den, - init->vrate.num, init->vrate.den); - - avfilter = append_filter(graph, "buffer", filter_args); - free(filter_args); - if (avfilter == NULL) - { - hb_error("hb_avfilter_graph_init: failed to create buffer source filter"); - goto fail; - } - graph->input = avfilter; - - // Link input to filter chain created by avfilter_graph_parse2 - result = avfilter_link(graph->last, 0, in->filter_ctx, 0); - if (result < 0) - { - goto fail; - } - graph->last = out->filter_ctx; - - // Build filter output - avfilter = append_filter(graph, "buffersink", NULL); - if (avfilter == NULL) - { - hb_error("hb_avfilter_graph_init: failed to create buffer output filter"); - goto fail; - } -#if 0 - // Set output pix fmt to YUV420P - enum AVPixelFormat pix_fmts[2] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}; - if (av_opt_set_int_list(avfilter, "pix_fmts", pix_fmts, - AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN) < 0) - { - hb_error("hb_avfilter_graph_init: failed to set buffersink pix_fmt"); - goto fail; - } -#endif - - graph->output = avfilter; - - result = avfilter_graph_config(graph->avgraph, NULL); - if (result < 0) - { - hb_error("hb_avfilter_graph_init: failed to configure filter graph"); - goto fail; - } - - graph->frame = av_frame_alloc(); - if (graph->frame == NULL) - { - hb_error("hb_avfilter_graph_init: failed to allocate frame filter"); - goto fail; - } - - graph->out_time_base = graph->output->inputs[0]->time_base; - - avfilter_inout_free(&in); - avfilter_inout_free(&out); - - return graph; - -fail: - avfilter_inout_free(&in); - avfilter_inout_free(&out); - hb_avfilter_graph_close(&graph); - - return NULL; -} - -void hb_avfilter_graph_close(hb_avfilter_graph_t ** _g) -{ - hb_avfilter_graph_t * graph = *_g; - - if (graph == NULL) - { - return; - } - if (graph->avgraph != NULL) - { - avfilter_graph_free(&graph->avgraph); - } - free(graph->settings); - av_frame_free(&graph->frame); - free(graph); - *_g = NULL; -} - static int avfilter_init( hb_filter_object_t * filter, hb_filter_init_t * init ) { hb_filter_private_t * pv = NULL; @@ -382,6 +84,11 @@ fail: return 1; } +// avfilter_post_init is used to finalize filters that are aliases +// to avfilter (pad, rotate, cropscale, deinterlace, and colorspace). +// These filters have their own init function that gets called during +// the initial filter init pass. Then in post_init, the AVFilterGraph +// that does the real work is initialized. static int avfilter_post_init( hb_filter_object_t * filter, hb_job_t * job ) { hb_filter_private_t * pv = filter->private_data; @@ -532,7 +239,7 @@ static void avfilter_close( hb_filter_object_t * filter ) filter->private_data = NULL; } -static void avfilter_alias_close( hb_filter_object_t * filter ) +void hb_avfilter_alias_close( hb_filter_object_t * filter ) { hb_filter_private_t * pv = filter->private_data; if (pv == NULL) @@ -546,47 +253,6 @@ static void avfilter_alias_close( hb_filter_object_t * filter ) filter->private_data = NULL; } -int hb_avfilter_add_frame(hb_avfilter_graph_t * graph, AVFrame * frame) -{ - return av_buffersrc_add_frame(graph->input, frame); -} - -int hb_avfilter_get_frame(hb_avfilter_graph_t * graph, AVFrame * frame) -{ - return av_buffersink_get_frame(graph->output, frame); -} - -int hb_avfilter_add_buf(hb_avfilter_graph_t * graph, hb_buffer_t * in) -{ - if (in != NULL) - { - hb_video_buffer_to_avframe(graph->frame, in); - return av_buffersrc_add_frame(graph->input, graph->frame); - } - else - { - return av_buffersrc_add_frame(graph->input, NULL); - } -} - -hb_buffer_t * hb_avfilter_get_buf(hb_avfilter_graph_t * graph) -{ - int result; - - result = av_buffersink_get_frame(graph->output, graph->frame); - if (result >= 0) - { - return hb_avframe_to_video_buffer(graph->frame, graph->out_time_base); - } - - return NULL; -} - -int64_t hb_avfilter_get_frame_pts(hb_avfilter_graph_t * graph) -{ - return graph->frame->pts; -} - static hb_buffer_t* filterFrame( hb_filter_private_t * pv, hb_buffer_t * in ) { hb_buffer_list_t list; @@ -639,588 +305,3 @@ static int avfilter_work( hb_filter_object_t * filter, return HB_FILTER_OK; } - -void hb_avfilter_combine( hb_list_t * list) -{ - hb_filter_object_t * avfilter = NULL; - hb_value_t * settings = NULL; - int ii; - - for (ii = 0; ii < hb_list_count(list); ii++) - { - hb_filter_object_t * filter = hb_list_item(list, ii); - hb_filter_private_t * pv = filter->private_data; - switch (filter->id) - { - case HB_FILTER_AVFILTER: - { - settings = pv->avfilters; - } break; - case HB_FILTER_ROTATE: - { - settings = pv->avfilters; - } break; - case HB_FILTER_DEINTERLACE: - { - settings = pv->avfilters; - } break; - case HB_FILTER_PAD: - { - settings = pv->avfilters; - } break; - case HB_FILTER_CROP_SCALE: - { - settings = pv->avfilters; - } break; - default: - { - settings = NULL; - avfilter = NULL; - } break; - } - if (settings != NULL) - { - if (avfilter == NULL) - { - hb_filter_private_t * avpv = NULL; - avfilter = hb_filter_init(HB_FILTER_AVFILTER); - avfilter->aliased = 1; - - avpv = calloc(1, sizeof(struct hb_filter_private_s)); - avfilter->private_data = avpv; - avpv->input = pv->input; - - avfilter->settings = hb_value_array_init(); - hb_list_insert(list, ii, avfilter); - ii++; - } - - hb_value_array_concat(avfilter->settings, settings); - } - } -} - -void hb_append_filter_dict(hb_value_array_t * filters, - const char * name, hb_value_t * settings) -{ - hb_dict_t * filter_dict = hb_dict_init(); - - hb_dict_set(filter_dict, name, settings); - hb_value_array_append(filters, filter_dict); -} - -static const char * color_format_range(enum AVPixelFormat format, int range) -{ - switch (format) - { - case AV_PIX_FMT_YUVJ420P: - case AV_PIX_FMT_YUVJ422P: - case AV_PIX_FMT_YUVJ444P: - case AV_PIX_FMT_YUVJ440P: - return "full"; - default: - return range == AVCOL_RANGE_JPEG ? "full" : "limited"; - } -} - -/* CropScale Settings - * mode:parity - * - * width - scale width - * height - scale height - * crop-top - top crop margin - * crop-bottom - bottom crop margin - * crop-left - left crop margin - * crop-right - right crop margin - * - */ -static int crop_scale_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_value_array_t * avfilters = hb_value_array_init(); - int width, height, top, bottom, left, right; - const char * matrix; - - // Convert crop settings to 'crop' avfilter - hb_dict_extract_int(&top, settings, "crop-top"); - hb_dict_extract_int(&bottom, settings, "crop-bottom"); - hb_dict_extract_int(&left, settings, "crop-left"); - hb_dict_extract_int(&right, settings, "crop-right"); - if (top > 0 || bottom > 0 || left > 0 || right > 0) - { - hb_dict_t * avfilter = hb_dict_init(); - hb_dict_t * avsettings = hb_dict_init(); - - hb_dict_set_int(avsettings, "x", left); - hb_dict_set_int(avsettings, "y", top); - hb_dict_set_int(avsettings, "w", init->geometry.width - left - right); - hb_dict_set_int(avsettings, "h", init->geometry.height - top - bottom); - hb_dict_set(avfilter, "crop", avsettings); - hb_value_array_append(avfilters, avfilter); - } - - // Convert scale settings to 'scale' avfilter - hb_dict_extract_int(&width, settings, "width"); - hb_dict_extract_int(&height, settings, "height"); - - hb_dict_t * avfilter = hb_dict_init(); - hb_dict_t * avsettings = hb_dict_init(); - - hb_dict_set_int(avsettings, "width", width); - hb_dict_set_int(avsettings, "height", height); - hb_dict_set_string(avsettings, "flags", "lanczos+accurate_rnd"); - switch (init->color_matrix) - { - case HB_COLR_MAT_BT709: - matrix = "bt709"; - break; - case HB_COLR_MAT_FCC: - matrix = "fcc"; - break; - case HB_COLR_MAT_SMPTE240M: - matrix = "smpte240m"; - break; - case HB_COLR_MAT_BT470BG: - case HB_COLR_MAT_SMPTE170M: - matrix = "smpte170m"; - break; - case HB_COLR_MAT_BT2020_NCL: - case HB_COLR_MAT_BT2020_CL: - matrix = "bt2020"; - break; - default: - case HB_COLR_MAT_UNDEF: - matrix = NULL; - break; - - } - if (matrix != NULL) - { - hb_dict_set_string(avsettings, "in_color_matrix", matrix); - hb_dict_set_string(avsettings, "out_color_matrix", matrix); - } - hb_dict_set_string(avsettings, "in_range", - color_format_range(init->pix_fmt, init->color_range)); - hb_dict_set_string(avsettings, "out_range", "limited"); - hb_dict_set(avfilter, "scale", avsettings); - hb_value_array_append(avfilters, avfilter); - - init->crop[0] = top; - init->crop[1] = bottom; - init->crop[2] = left; - init->crop[3] = right; - init->geometry.width = width; - init->geometry.height = height; - pv->output = *init; - - pv->avfilters = avfilters; - - return 0; -} - -static hb_filter_info_t * crop_scale_info( hb_filter_object_t * filter ) -{ - hb_filter_private_t * pv = filter->private_data; - - if (pv == NULL) - { - return NULL; - } - - hb_filter_info_t * info; - hb_dict_t * settings = filter->settings; - int width, height, top, bottom, left, right; - - info = calloc(1, sizeof(hb_filter_info_t)); - if (info == NULL) - { - hb_error("crop_scale_info: allocation failure"); - return NULL; - } - info->output = pv->output; - - hb_dict_extract_int(&top, settings, "crop-top"); - hb_dict_extract_int(&bottom, settings, "crop-bottom"); - hb_dict_extract_int(&left, settings, "crop-left"); - hb_dict_extract_int(&right, settings, "crop-right"); - hb_dict_extract_int(&width, settings, "width"); - hb_dict_extract_int(&height, settings, "height"); - - int cropped_width = pv->input.geometry.width - (left + right); - int cropped_height = pv->input.geometry.height - (top + bottom); - - info->human_readable_desc = hb_strdup_printf( - "source: %d * %d, crop (%d/%d/%d/%d): %d * %d, scale: %d * %d", - pv->input.geometry.width, pv->input.geometry.height, - top, bottom, left, right, - cropped_width, cropped_height, width, height); - - return info; -} - -/* Pad presets and tunes - * - * There are currently no presets and tunes for pad - * The custom pad string is converted to an avformat filter graph string - */ -static int pad_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; - - int width = -1, height = -1, rgb = 0; - int x = -1, y = -1; - char * color = NULL; - - hb_dict_extract_int(&width, settings, "width"); - hb_dict_extract_int(&height, settings, "height"); - hb_dict_extract_string(&color, settings, "color"); - hb_dict_extract_int(&x, settings, "x"); - hb_dict_extract_int(&y, settings, "y"); - - if (color != NULL) - { - char * end; - rgb = strtol(color, &end, 0); - if (end == color) - { - // Not a numeric value, lookup by name - rgb = hb_rgb_lookup_by_name(color); - } - free(color); - color = hb_strdup_printf("0x%06x", rgb); - } - - char x_str[20]; - char y_str[20]; - if (x < 0) - { - snprintf(x_str, 20, "(out_w-in_w)/2"); - } - else - { - snprintf(x_str, 20, "%d", x); - } - if (y < 0) - { - snprintf(y_str, 20, "(out_h-in_h)/2"); - } - else - { - snprintf(y_str, 20, "%d", y); - } - if (width < 0) - { - width = init->geometry.width; - } - if (height < 0) - { - height = init->geometry.height; - } - hb_dict_t * avfilter = hb_dict_init(); - hb_dict_t * avsettings = hb_dict_init(); - - hb_dict_set(avsettings, "width", hb_value_int(width)); - hb_dict_set(avsettings, "height", hb_value_int(height)); - hb_dict_set(avsettings, "x", hb_value_string(x_str)); - hb_dict_set(avsettings, "y", hb_value_string(y_str)); - if (color != NULL) - { - hb_dict_set(avsettings, "color", hb_value_string(color)); - free(color); - } - hb_dict_set(avfilter, "pad", avsettings); - pv->avfilters = avfilter; - - init->geometry.width = width; - init->geometry.height = height; - pv->output = *init; - - return 0; -} - -/* 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) - */ -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; - - int width = init->geometry.width; - int height = init->geometry.height; - const char * trans = NULL; - int angle = 0, flip = 0, hflip = 0, vflip = 0, tmp; - - 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"; - } - switch (angle) - { - case 0: - hflip = flip; - break; - case 90: - trans = clock; - tmp = width; - width = height; - height = tmp; - break; - case 180: - vflip = 1; - hflip = !flip; - break; - case 270: - trans = cclock; - tmp = width; - width = height; - height = tmp; - break; - default: - break; - } - if (trans != NULL) - { - 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); - pv->avfilters = avfilter; - } - 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 = avfilter; - } - else - { - pv->avfilters = hb_value_null(); - } - - init->geometry.width = width; - init->geometry.height = height; - pv->output = *init; - - return 0; -} - -/* Deinterlace Settings - * mode:parity - * - * mode - yadif deinterlace mode - * parity - field parity - * - * Modes: - * 1 = Enabled - * 2 = Spatial - * 4 = Bob - * 8 = Selective - * - * Parity: - * 0 = Top Field First - * 1 = Bottom Field First - * -1 = Automatic detection of field parity - * - */ -static int deinterlace_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; - - int mode = 3, parity = -1; - - hb_dict_extract_int(&mode, settings, "mode"); - hb_dict_extract_int(&parity, settings, "parity"); - - if (!(mode & MODE_YADIF_ENABLE)) - { - return 0; - } - - hb_dict_t * avfilter = hb_dict_init(); - hb_dict_t * avsettings = hb_dict_init(); - - if (mode & MODE_YADIF_BOB) - { - if (mode & MODE_YADIF_SPATIAL) - { - hb_dict_set(avsettings, "mode", hb_value_string("send_field")); - } - else - { - hb_dict_set(avsettings, "mode", - hb_value_string("send_field_nospatial")); - } - } - else - { - if (mode & MODE_YADIF_SPATIAL) - { - hb_dict_set(avsettings, "mode", hb_value_string("send_frame")); - } - else - { - hb_dict_set(avsettings, "mode", - hb_value_string("send_frame_nospatial")); - } - } - - if (mode & MODE_DECOMB_SELECTIVE) - { - hb_dict_set(avsettings, "deint", hb_value_string("interlaced")); - } - if (parity == 0) - { - hb_dict_set(avsettings, "parity", hb_value_string("tff")); - } - else if (parity == 1) - { - hb_dict_set(avsettings, "parity", hb_value_string("bff")); - } - hb_dict_set(avfilter, "yadif", avsettings); - pv->avfilters = avfilter; - - pv->output = *init; - - return 0; -} - -static int colorspace_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; - - char * format = NULL, * range = NULL; - char * primaries = NULL, * transfer = NULL, * matrix = NULL; - - hb_dict_extract_string(&format, settings, "format"); - hb_dict_extract_string(&range, settings, "range"); - hb_dict_extract_string(&primaries, settings, "primaries"); - hb_dict_extract_string(&transfer, settings, "transfer"); - hb_dict_extract_string(&matrix, settings, "matrix"); - - if (!(format || range || primaries || transfer || matrix)) - { - return 0; - } - - hb_dict_t * avfilter = hb_dict_init(); - hb_dict_t * avsettings = hb_dict_init(); - - if (format) - { - hb_dict_set_string(avsettings, "format", format); - } - if (range) - { - hb_dict_set_string(avsettings, "range", range); - } - if (primaries) - { - hb_dict_set_string(avsettings, "primaries", primaries); - } - if (transfer) - { - hb_dict_set_string(avsettings, "trc", transfer); - } - if (matrix) - { - hb_dict_set_string(avsettings, "space", matrix); - } - hb_dict_set(avfilter, "colorspace", avsettings); - pv->avfilters = avfilter; - - pv->output = *init; - - return 0; -} diff --git a/libhb/avfilter_priv.h b/libhb/avfilter_priv.h new file mode 100644 index 000000000..a0430fd62 --- /dev/null +++ b/libhb/avfilter_priv.h @@ -0,0 +1,45 @@ +/* avfilter_priv.h + + Copyright (c) 2003-2019 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 + */ + +#ifndef HB_AVFILTER_PRIV_H +#define HB_AVFILTER_PRIV_H + +#include "libavfilter/avfilter.h" +#include "hbavfilter.h" + +struct hb_avfilter_graph_s +{ + AVFilterGraph * avgraph; + AVFilterContext * last; + AVFilterContext * input; + AVFilterContext * output; + char * settings; + AVFrame * frame; + AVRational out_time_base; +}; + +struct hb_filter_private_s +{ + int initialized; + hb_avfilter_graph_t * graph; + + // Buffer list to delay output by one frame. Required to set stop time. + hb_buffer_list_t list; + + // Placeholder settings for AVFilter aliases + hb_value_t * avfilters; + hb_filter_init_t input; + hb_filter_init_t output; +}; + +int hb_avfilter_null_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ); +void hb_avfilter_alias_close( hb_filter_object_t * filter ); + +#endif // HB_AVFILTER_PRIV_H diff --git a/libhb/colorspace.c b/libhb/colorspace.c new file mode 100644 index 000000000..581886561 --- /dev/null +++ b/libhb/colorspace.c @@ -0,0 +1,90 @@ +/* colorspace.c + + Copyright (c) 2003-2015 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 "common.h" +#include "avfilter_priv.h" + +static int colorspace_init(hb_filter_object_t * filter, + hb_filter_init_t * init); + +const char colorspace_template[] = + "format=^"HB_ALL_REG"$:range=^"HB_ALL_REG"$:primaries=^"HB_ALL_REG"$:" + "matrix=^"HB_ALL_REG"$:transfer=^"HB_ALL_REG"$"; + +hb_filter_object_t hb_filter_colorspace = +{ + .id = HB_FILTER_COLORSPACE, + .enforce_order = 1, + .skip = 1, + .name = "Colorspace", + .settings = NULL, + .init = colorspace_init, + .work = hb_avfilter_null_work, + .close = hb_avfilter_alias_close, + .settings_template = colorspace_template, +}; + +static int colorspace_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; + + char * format = NULL, * range = NULL; + char * primaries = NULL, * transfer = NULL, * matrix = NULL; + + hb_dict_extract_string(&format, settings, "format"); + hb_dict_extract_string(&range, settings, "range"); + hb_dict_extract_string(&primaries, settings, "primaries"); + hb_dict_extract_string(&transfer, settings, "transfer"); + hb_dict_extract_string(&matrix, settings, "matrix"); + + if (!(format || range || primaries || transfer || matrix)) + { + return 0; + } + + hb_dict_t * avfilter = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); + + if (format) + { + hb_dict_set_string(avsettings, "format", format); + } + if (range) + { + hb_dict_set_string(avsettings, "range", range); + } + if (primaries) + { + hb_dict_set_string(avsettings, "primaries", primaries); + } + if (transfer) + { + hb_dict_set_string(avsettings, "trc", transfer); + } + if (matrix) + { + hb_dict_set_string(avsettings, "space", matrix); + } + hb_dict_set(avfilter, "colorspace", avsettings); + pv->avfilters = avfilter; + + pv->output = *init; + + return 0; +} diff --git a/libhb/cropscale.c b/libhb/cropscale.c new file mode 100644 index 000000000..38d8560e9 --- /dev/null +++ b/libhb/cropscale.c @@ -0,0 +1,194 @@ +/* cropscale.c + + Copyright (c) 2003-2015 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 "common.h" +#include "avfilter_priv.h" + +static int crop_scale_init(hb_filter_object_t * filter, + hb_filter_init_t * init); +static hb_filter_info_t * crop_scale_info( hb_filter_object_t * filter ); + +static const char crop_scale_template[] = + "width=^"HB_INT_REG"$:height=^"HB_INT_REG"$:" + "crop-top=^"HB_INT_REG"$:crop-bottom=^"HB_INT_REG"$:" + "crop-left=^"HB_INT_REG"$:crop-right=^"HB_INT_REG"$"; + +hb_filter_object_t hb_filter_crop_scale = +{ + .id = HB_FILTER_CROP_SCALE, + .enforce_order = 1, + .skip = 1, + .name = "Crop and Scale", + .settings = NULL, + .init = crop_scale_init, + .work = hb_avfilter_null_work, + .close = hb_avfilter_alias_close, + .info = crop_scale_info, + .settings_template = crop_scale_template, +}; + +static const char * color_format_range(enum AVPixelFormat format, int range) +{ + switch (format) + { + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUVJ422P: + case AV_PIX_FMT_YUVJ444P: + case AV_PIX_FMT_YUVJ440P: + return "full"; + default: + return range == AVCOL_RANGE_JPEG ? "full" : "limited"; + } +} + +/* CropScale Settings + * mode:parity + * + * width - scale width + * height - scale height + * crop-top - top crop margin + * crop-bottom - bottom crop margin + * crop-left - left crop margin + * crop-right - right crop margin + * + */ +static int crop_scale_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_value_array_t * avfilters = hb_value_array_init(); + int width, height, top, bottom, left, right; + const char * matrix; + + // Convert crop settings to 'crop' avfilter + hb_dict_extract_int(&top, settings, "crop-top"); + hb_dict_extract_int(&bottom, settings, "crop-bottom"); + hb_dict_extract_int(&left, settings, "crop-left"); + hb_dict_extract_int(&right, settings, "crop-right"); + if (top > 0 || bottom > 0 || left > 0 || right > 0) + { + hb_dict_t * avfilter = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); + + hb_dict_set_int(avsettings, "x", left); + hb_dict_set_int(avsettings, "y", top); + hb_dict_set_int(avsettings, "w", init->geometry.width - left - right); + hb_dict_set_int(avsettings, "h", init->geometry.height - top - bottom); + hb_dict_set(avfilter, "crop", avsettings); + hb_value_array_append(avfilters, avfilter); + } + + // Convert scale settings to 'scale' avfilter + hb_dict_extract_int(&width, settings, "width"); + hb_dict_extract_int(&height, settings, "height"); + + hb_dict_t * avfilter = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); + + hb_dict_set_int(avsettings, "width", width); + hb_dict_set_int(avsettings, "height", height); + hb_dict_set_string(avsettings, "flags", "lanczos+accurate_rnd"); + switch (init->color_matrix) + { + case HB_COLR_MAT_BT709: + matrix = "bt709"; + break; + case HB_COLR_MAT_FCC: + matrix = "fcc"; + break; + case HB_COLR_MAT_SMPTE240M: + matrix = "smpte240m"; + break; + case HB_COLR_MAT_BT470BG: + case HB_COLR_MAT_SMPTE170M: + matrix = "smpte170m"; + break; + case HB_COLR_MAT_BT2020_NCL: + case HB_COLR_MAT_BT2020_CL: + matrix = "bt2020"; + break; + default: + case HB_COLR_MAT_UNDEF: + matrix = NULL; + break; + + } + if (matrix != NULL) + { + hb_dict_set_string(avsettings, "in_color_matrix", matrix); + hb_dict_set_string(avsettings, "out_color_matrix", matrix); + } + hb_dict_set_string(avsettings, "in_range", + color_format_range(init->pix_fmt, init->color_range)); + hb_dict_set_string(avsettings, "out_range", "limited"); + hb_dict_set(avfilter, "scale", avsettings); + hb_value_array_append(avfilters, avfilter); + + init->crop[0] = top; + init->crop[1] = bottom; + init->crop[2] = left; + init->crop[3] = right; + init->geometry.width = width; + init->geometry.height = height; + pv->output = *init; + + pv->avfilters = avfilters; + + return 0; +} + +static hb_filter_info_t * crop_scale_info( hb_filter_object_t * filter ) +{ + hb_filter_private_t * pv = filter->private_data; + + if (pv == NULL) + { + return NULL; + } + + hb_filter_info_t * info; + hb_dict_t * settings = filter->settings; + int width, height, top, bottom, left, right; + + info = calloc(1, sizeof(hb_filter_info_t)); + if (info == NULL) + { + hb_error("crop_scale_info: allocation failure"); + return NULL; + } + info->output = pv->output; + + hb_dict_extract_int(&top, settings, "crop-top"); + hb_dict_extract_int(&bottom, settings, "crop-bottom"); + hb_dict_extract_int(&left, settings, "crop-left"); + hb_dict_extract_int(&right, settings, "crop-right"); + hb_dict_extract_int(&width, settings, "width"); + hb_dict_extract_int(&height, settings, "height"); + + int cropped_width = pv->input.geometry.width - (left + right); + int cropped_height = pv->input.geometry.height - (top + bottom); + + info->human_readable_desc = hb_strdup_printf( + "source: %d * %d, crop (%d/%d/%d/%d): %d * %d, scale: %d * %d", + pv->input.geometry.width, pv->input.geometry.height, + top, bottom, left, right, + cropped_width, cropped_height, width, height); + + return info; +} + diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index da1925303..3450082e0 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -1196,11 +1196,11 @@ int reinit_video_filters(hb_work_private_t * pv) hb_dict_set(settings, "w", hb_value_int(orig_width)); hb_dict_set(settings, "h", hb_value_int(orig_height)); hb_dict_set(settings, "flags", hb_value_string("lanczos+accurate_rnd")); - hb_append_filter_dict(filters, "scale", settings); + hb_avfilter_append_dict(filters, "scale", settings); settings = hb_dict_init(); hb_dict_set(settings, "pix_fmts", hb_value_string("yuv420p")); - hb_append_filter_dict(filters, "format", settings); + hb_avfilter_append_dict(filters, "format", settings); } if (pv->title->rotation != HB_ROTATION_0) { @@ -1209,16 +1209,16 @@ int reinit_video_filters(hb_work_private_t * pv) case HB_ROTATION_90: settings = hb_dict_init(); hb_dict_set(settings, "dir", hb_value_string("cclock")); - hb_append_filter_dict(filters, "transpose", settings); + hb_avfilter_append_dict(filters, "transpose", settings); break; case HB_ROTATION_180: - hb_append_filter_dict(filters, "hflip", hb_value_null()); - hb_append_filter_dict(filters, "vflip", hb_value_null()); + hb_avfilter_append_dict(filters, "hflip", hb_value_null()); + hb_avfilter_append_dict(filters, "vflip", hb_value_null()); break; case HB_ROTATION_270: settings = hb_dict_init(); hb_dict_set(settings, "dir", hb_value_string("clock")); - hb_append_filter_dict(filters, "transpose", settings); + hb_avfilter_append_dict(filters, "transpose", settings); break; default: hb_log("reinit_video_filters: Unknown rotation, failed"); diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c new file mode 100644 index 000000000..de91a8202 --- /dev/null +++ b/libhb/deinterlace.c @@ -0,0 +1,122 @@ +/* deinterlace.c + + Copyright (c) 2003-2015 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 "common.h" +#include "decomb.h" +#include "avfilter_priv.h" + +static int deinterlace_init(hb_filter_object_t * filter, + hb_filter_init_t * init); + +const char deint_template[] = + "mode=^"HB_INT_REG"$:parity=^([01])$"; + +hb_filter_object_t hb_filter_deinterlace = +{ + .id = HB_FILTER_DEINTERLACE, + .enforce_order = 1, + .skip = 1, + .name = "Deinterlace", + .settings = NULL, + .init = deinterlace_init, + .work = hb_avfilter_null_work, + .close = hb_avfilter_alias_close, + .settings_template = deint_template, +}; + +/* Deinterlace Settings + * mode:parity + * + * mode - yadif deinterlace mode + * parity - field parity + * + * Modes: + * 1 = Enabled + * 2 = Spatial + * 4 = Bob + * 8 = Selective + * + * Parity: + * 0 = Top Field First + * 1 = Bottom Field First + * -1 = Automatic detection of field parity + * + */ +static int deinterlace_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; + + int mode = 3, parity = -1; + + hb_dict_extract_int(&mode, settings, "mode"); + hb_dict_extract_int(&parity, settings, "parity"); + + if (!(mode & MODE_YADIF_ENABLE)) + { + return 0; + } + + hb_dict_t * avfilter = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); + + if (mode & MODE_YADIF_BOB) + { + if (mode & MODE_YADIF_SPATIAL) + { + hb_dict_set(avsettings, "mode", hb_value_string("send_field")); + } + else + { + hb_dict_set(avsettings, "mode", + hb_value_string("send_field_nospatial")); + } + } + else + { + if (mode & MODE_YADIF_SPATIAL) + { + hb_dict_set(avsettings, "mode", hb_value_string("send_frame")); + } + else + { + hb_dict_set(avsettings, "mode", + hb_value_string("send_frame_nospatial")); + } + } + + if (mode & MODE_DECOMB_SELECTIVE) + { + hb_dict_set(avsettings, "deint", hb_value_string("interlaced")); + } + if (parity == 0) + { + hb_dict_set(avsettings, "parity", hb_value_string("tff")); + } + else if (parity == 1) + { + hb_dict_set(avsettings, "parity", hb_value_string("bff")); + } + hb_dict_set(avfilter, "yadif", avsettings); + pv->avfilters = avfilter; + + pv->output = *init; + + return 0; +} diff --git a/libhb/hbavfilter.c b/libhb/hbavfilter.c new file mode 100644 index 000000000..c1b789f71 --- /dev/null +++ b/libhb/hbavfilter.c @@ -0,0 +1,282 @@ +/* avfilter.c + + Copyright (c) 2003-2015 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 "libavfilter/avfilter.h" +#include "libavfilter/buffersrc.h" +#include "libavfilter/buffersink.h" +#include "hbavfilter.h" +#include "avfilter_priv.h" + +static AVFilterContext * append_filter( hb_avfilter_graph_t * graph, + const char * name, const char * args) +{ + AVFilterContext * filter; + int result; + + result = avfilter_graph_create_filter(&filter, avfilter_get_by_name(name), + name, args, NULL, graph->avgraph); + if (result < 0) + { + return NULL; + } + if (graph->last != NULL) + { + result = avfilter_link(graph->last, 0, filter, 0); + if (result < 0) + { + avfilter_free(filter); + return NULL; + } + } + graph->last = filter; + + return filter; +} + +hb_avfilter_graph_t * +hb_avfilter_graph_init(hb_value_t * settings, hb_filter_init_t * init) +{ + hb_avfilter_graph_t * graph; + AVFilterInOut * in = NULL, * out = NULL; + AVFilterContext * avfilter; + char * settings_str; + int result; + char * filter_args; + + graph = calloc(1, sizeof(hb_avfilter_graph_t)); + if (graph == NULL) + { + return NULL; + } + + settings_str = hb_filter_settings_string(HB_FILTER_AVFILTER, settings); + if (settings_str == NULL) + { + hb_error("hb_avfilter_graph_init: no filter settings specified"); + goto fail; + } + + graph->settings = settings_str; + graph->avgraph = avfilter_graph_alloc(); + if (graph->avgraph == NULL) + { + hb_error("hb_avfilter_graph_init: avfilter_graph_alloc failed"); + goto fail; + } + + av_opt_set(graph->avgraph, "scale_sws_opts", "lanczos+accurate_rnd", 0); + + result = avfilter_graph_parse2(graph->avgraph, settings_str, &in, &out); + if (result < 0 || in == NULL || out == NULL) + { + hb_error("hb_avfilter_graph_init: avfilter_graph_parse2 failed (%s)", + settings_str); + goto fail; + } + + // Build filter input + filter_args = hb_strdup_printf( + "width=%d:height=%d:pix_fmt=%d:sar=%d/%d:" + "time_base=%d/%d:frame_rate=%d/%d", + init->geometry.width, init->geometry.height, init->pix_fmt, + init->geometry.par.num, init->geometry.par.den, + init->time_base.num, init->time_base.den, + init->vrate.num, init->vrate.den); + + avfilter = append_filter(graph, "buffer", filter_args); + free(filter_args); + if (avfilter == NULL) + { + hb_error("hb_avfilter_graph_init: failed to create buffer source filter"); + goto fail; + } + graph->input = avfilter; + + // Link input to filter chain created by avfilter_graph_parse2 + result = avfilter_link(graph->last, 0, in->filter_ctx, 0); + if (result < 0) + { + goto fail; + } + graph->last = out->filter_ctx; + + // Build filter output + avfilter = append_filter(graph, "buffersink", NULL); + if (avfilter == NULL) + { + hb_error("hb_avfilter_graph_init: failed to create buffer output filter"); + goto fail; + } +#if 0 + // Set output pix fmt to YUV420P + enum AVPixelFormat pix_fmts[2] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}; + if (av_opt_set_int_list(avfilter, "pix_fmts", pix_fmts, + AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN) < 0) + { + hb_error("hb_avfilter_graph_init: failed to set buffersink pix_fmt"); + goto fail; + } +#endif + + graph->output = avfilter; + + result = avfilter_graph_config(graph->avgraph, NULL); + if (result < 0) + { + hb_error("hb_avfilter_graph_init: failed to configure filter graph"); + goto fail; + } + + graph->frame = av_frame_alloc(); + if (graph->frame == NULL) + { + hb_error("hb_avfilter_graph_init: failed to allocate frame filter"); + goto fail; + } + + graph->out_time_base = graph->output->inputs[0]->time_base; + + avfilter_inout_free(&in); + avfilter_inout_free(&out); + + return graph; + +fail: + avfilter_inout_free(&in); + avfilter_inout_free(&out); + hb_avfilter_graph_close(&graph); + + return NULL; +} + +void hb_avfilter_graph_close(hb_avfilter_graph_t ** _g) +{ + hb_avfilter_graph_t * graph = *_g; + + if (graph == NULL) + { + return; + } + if (graph->avgraph != NULL) + { + avfilter_graph_free(&graph->avgraph); + } + free(graph->settings); + av_frame_free(&graph->frame); + free(graph); + *_g = NULL; +} + +int hb_avfilter_add_frame(hb_avfilter_graph_t * graph, AVFrame * frame) +{ + return av_buffersrc_add_frame(graph->input, frame); +} + +int hb_avfilter_get_frame(hb_avfilter_graph_t * graph, AVFrame * frame) +{ + return av_buffersink_get_frame(graph->output, frame); +} + +int hb_avfilter_add_buf(hb_avfilter_graph_t * graph, hb_buffer_t * in) +{ + if (in != NULL) + { + hb_video_buffer_to_avframe(graph->frame, in); + return av_buffersrc_add_frame(graph->input, graph->frame); + } + else + { + return av_buffersrc_add_frame(graph->input, NULL); + } +} + +hb_buffer_t * hb_avfilter_get_buf(hb_avfilter_graph_t * graph) +{ + int result; + + result = av_buffersink_get_frame(graph->output, graph->frame); + if (result >= 0) + { + return hb_avframe_to_video_buffer(graph->frame, graph->out_time_base); + } + + return NULL; +} + +void hb_avfilter_combine( hb_list_t * list) +{ + hb_filter_object_t * avfilter = NULL; + hb_value_t * settings = NULL; + int ii; + + for (ii = 0; ii < hb_list_count(list); ii++) + { + hb_filter_object_t * filter = hb_list_item(list, ii); + hb_filter_private_t * pv = filter->private_data; + switch (filter->id) + { + case HB_FILTER_AVFILTER: + { + settings = pv->avfilters; + } break; + case HB_FILTER_ROTATE: + { + settings = pv->avfilters; + } break; + case HB_FILTER_DEINTERLACE: + { + settings = pv->avfilters; + } break; + case HB_FILTER_PAD: + { + settings = pv->avfilters; + } break; + case HB_FILTER_CROP_SCALE: + { + settings = pv->avfilters; + } break; + default: + { + settings = NULL; + avfilter = NULL; + } break; + } + if (settings != NULL) + { + if (avfilter == NULL) + { + hb_filter_private_t * avpv = NULL; + avfilter = hb_filter_init(HB_FILTER_AVFILTER); + avfilter->aliased = 1; + + avpv = calloc(1, sizeof(struct hb_filter_private_s)); + avfilter->private_data = avpv; + avpv->input = pv->input; + + avfilter->settings = hb_value_array_init(); + hb_list_insert(list, ii, avfilter); + ii++; + } + + hb_value_array_concat(avfilter->settings, settings); + } + } +} + +void hb_avfilter_append_dict(hb_value_array_t * filters, + const char * name, hb_value_t * settings) +{ + hb_dict_t * filter_dict = hb_dict_init(); + + hb_dict_set(filter_dict, name, settings); + hb_value_array_append(filters, filter_dict); +} + diff --git a/libhb/hbavfilter.h b/libhb/hbavfilter.h index 2b76fcbea..c28e87ec0 100644 --- a/libhb/hbavfilter.h +++ b/libhb/hbavfilter.h @@ -10,6 +10,8 @@ #ifndef HB_AVFILTER_H #define HB_AVFILTER_H +#include "common.h" + typedef struct hb_avfilter_graph_s hb_avfilter_graph_t; hb_avfilter_graph_t * hb_avfilter_graph_init(hb_value_t * settings, @@ -21,8 +23,9 @@ int hb_avfilter_get_frame(hb_avfilter_graph_t * graph, AVFrame * frame); int hb_avfilter_add_buf(hb_avfilter_graph_t * graph, hb_buffer_t * in); hb_buffer_t * hb_avfilter_get_buf(hb_avfilter_graph_t * graph); -void hb_append_filter_dict(hb_value_array_t * filters, +void hb_avfilter_append_dict(hb_value_array_t * filters, const char * name, hb_dict_t * settings); void hb_avfilter_combine(hb_list_t * list); + #endif // HB_AVFILTER_H diff --git a/libhb/pad.c b/libhb/pad.c new file mode 100644 index 000000000..10631bffe --- /dev/null +++ b/libhb/pad.c @@ -0,0 +1,122 @@ +/* pad.c + + Copyright (c) 2003-2015 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 "common.h" +#include "colormap.h" +#include "avfilter_priv.h" + +static int pad_init(hb_filter_object_t * filter, hb_filter_init_t * init); + +const char pad_template[] = + "width=^"HB_INT_REG"$:height=^"HB_INT_REG"$:color=^"HB_ALL_REG"$:" + "x=^"HB_INT_REG"$:y=^"HB_INT_REG"$"; + +hb_filter_object_t hb_filter_pad = +{ + .id = HB_FILTER_PAD, + .enforce_order = 1, + .skip = 1, + .name = "Pad", + .settings = NULL, + .init = pad_init, + .work = hb_avfilter_null_work, + .close = hb_avfilter_alias_close, + .settings_template = pad_template, +}; + +/* Pad presets and tunes + * + * There are currently no presets and tunes for pad + * The custom pad string is converted to an avformat filter graph string + */ +static int pad_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; + + int width = -1, height = -1, rgb = 0; + int x = -1, y = -1; + char * color = NULL; + + hb_dict_extract_int(&width, settings, "width"); + hb_dict_extract_int(&height, settings, "height"); + hb_dict_extract_string(&color, settings, "color"); + hb_dict_extract_int(&x, settings, "x"); + hb_dict_extract_int(&y, settings, "y"); + + if (color != NULL) + { + char * end; + rgb = strtol(color, &end, 0); + if (end == color) + { + // Not a numeric value, lookup by name + rgb = hb_rgb_lookup_by_name(color); + } + free(color); + color = hb_strdup_printf("0x%06x", rgb); + } + + char x_str[20]; + char y_str[20]; + if (x < 0) + { + snprintf(x_str, 20, "(out_w-in_w)/2"); + } + else + { + snprintf(x_str, 20, "%d", x); + } + if (y < 0) + { + snprintf(y_str, 20, "(out_h-in_h)/2"); + } + else + { + snprintf(y_str, 20, "%d", y); + } + if (width < 0) + { + width = init->geometry.width; + } + if (height < 0) + { + height = init->geometry.height; + } + hb_dict_t * avfilter = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); + + hb_dict_set(avsettings, "width", hb_value_int(width)); + hb_dict_set(avsettings, "height", hb_value_int(height)); + hb_dict_set(avsettings, "x", hb_value_string(x_str)); + hb_dict_set(avsettings, "y", hb_value_string(y_str)); + if (color != NULL) + { + hb_dict_set(avsettings, "color", hb_value_string(color)); + free(color); + } + hb_dict_set(avfilter, "pad", avsettings); + pv->avfilters = avfilter; + + init->geometry.width = width; + init->geometry.height = height; + pv->output = *init; + + return 0; +} + diff --git a/libhb/rotate.c b/libhb/rotate.c new file mode 100644 index 000000000..7ba140514 --- /dev/null +++ b/libhb/rotate.c @@ -0,0 +1,146 @@ +/* rotate.c + + Copyright (c) 2003-2015 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 "common.h" +#include "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) + */ +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; + + int width = init->geometry.width; + int height = init->geometry.height; + const char * trans = NULL; + int angle = 0, flip = 0, hflip = 0, vflip = 0, tmp; + + 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"; + } + switch (angle) + { + case 0: + hflip = flip; + break; + case 90: + trans = clock; + tmp = width; + width = height; + height = tmp; + break; + case 180: + vflip = 1; + hflip = !flip; + break; + case 270: + trans = cclock; + tmp = width; + width = height; + height = tmp; + break; + default: + break; + } + if (trans != NULL) + { + 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); + pv->avfilters = avfilter; + } + 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 = avfilter; + } + else + { + pv->avfilters = hb_value_null(); + } + + init->geometry.width = width; + init->geometry.height = height; + pv->output = *init; + + return 0; +} |