diff options
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; +} |