From 248c880fc86ee07d23d62135e002940f16364eb6 Mon Sep 17 00:00:00 2001 From: John Stebbins Date: Fri, 15 Mar 2019 11:12:38 -0600 Subject: [PATCH] avfilter: simplify internal API to avfilter Use this interface in decavcodec. Remove cropscale.c and use avfilter for crop and scale. Improve log output of filters that are aliases for avfilter. --- libhb/avfilter.c | 1022 +++++++++++++++++++++++++++++--------------- libhb/common.h | 9 +- libhb/cropscale.c | 228 ---------- libhb/decavcodec.c | 189 ++------ libhb/fifo.c | 166 ++++--- libhb/hb.c | 6 +- libhb/hbavfilter.h | 28 ++ libhb/hbffmpeg.c | 24 +- libhb/hbffmpeg.h | 9 +- libhb/internal.h | 3 +- libhb/vfr.c | 8 +- libhb/work.c | 45 +- 12 files changed, 910 insertions(+), 827 deletions(-) delete mode 100644 libhb/cropscale.c create mode 100644 libhb/hbavfilter.h diff --git a/libhb/avfilter.c b/libhb/avfilter.c index c5d65f69e..5f98f310c 100644 --- a/libhb/avfilter.c +++ b/libhb/avfilter.c @@ -9,6 +9,7 @@ #include "hb.h" #include "hbffmpeg.h" +#include "hbavfilter.h" #include "common.h" #include "libavfilter/avfilter.h" #include "libavfilter/buffersrc.h" @@ -20,44 +21,85 @@ * 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_filter_private_s +struct hb_avfilter_graph_s { - hb_buffer_list_t list; - AVFilterGraph * graph; + AVFilterGraph * avgraph; AVFilterContext * last; AVFilterContext * input; AVFilterContext * output; + char * settings; AVFrame * frame; AVRational out_time_base; - char * settings; }; -static int avfilter_init( hb_filter_object_t * filter, - hb_filter_init_t * init ); +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; +}; + +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_init( hb_filter_object_t * filter, hb_filter_init_t * init ); -static void null_close( 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 hb_filter_info_t * null_info( hb_filter_object_t * filter ); + +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); hb_filter_object_t hb_filter_avfilter = { .id = HB_FILTER_AVFILTER, .enforce_order = 0, - .name = "avfilter", + .name = "AVFilter", .settings = NULL, .init = avfilter_init, + .post_init = avfilter_post_init, .work = avfilter_work, .close = avfilter_close, .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"$"; @@ -66,12 +108,12 @@ hb_filter_object_t hb_filter_pad = { .id = HB_FILTER_PAD, .enforce_order = 1, + .skip = 1, .name = "Pad", .settings = NULL, - .init = null_init, + .init = pad_init, .work = null_work, - .close = null_close, - .info = null_info, + .close = avfilter_alias_close, .settings_template = pad_template, }; @@ -82,12 +124,12 @@ hb_filter_object_t hb_filter_rotate = { .id = HB_FILTER_ROTATE, .enforce_order = 1, + .skip = 1, .name = "Rotate", .settings = NULL, - .init = null_init, + .init = rotate_init, .work = null_work, - .close = null_close, - .info = null_info, + .close = avfilter_alias_close, .settings_template = rotate_template, }; @@ -98,27 +140,15 @@ hb_filter_object_t hb_filter_deinterlace = { .id = HB_FILTER_DEINTERLACE, .enforce_order = 1, + .skip = 1, .name = "Deinterlace", .settings = NULL, - .init = null_init, + .init = deinterlace_init, .work = null_work, - .close = null_close, - .info = null_info, + .close = avfilter_alias_close, .settings_template = deint_template, }; -static int null_init( hb_filter_object_t * filter, hb_filter_init_t * init ) -{ - hb_log("null_init: It is an error to call this function."); - return 1; -} - -static void null_close( hb_filter_object_t * filter ) -{ - hb_log("null_close: It is an error to call this function."); - return; -} - static int null_work( hb_filter_object_t * filter, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { @@ -126,81 +156,70 @@ static int null_work( hb_filter_object_t * filter, return HB_WORK_DONE; } -static hb_filter_info_t * null_info( hb_filter_object_t * filter ) -{ - hb_log("null_info: It is an error to call this function."); - return NULL; -} - - -static AVFilterContext * append_filter( hb_filter_private_t * pv, +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, pv->graph); + name, args, NULL, graph->avgraph); if (result < 0) { return NULL; } - if (pv->last != NULL) + if (graph->last != NULL) { - result = avfilter_link(pv->last, 0, filter, 0); + result = avfilter_link(graph->last, 0, filter, 0); if (result < 0) { avfilter_free(filter); return NULL; } } - pv->last = filter; + graph->last = filter; return filter; } -static int avfilter_init( hb_filter_object_t * filter, hb_filter_init_t * init ) +hb_avfilter_graph_t * +hb_avfilter_graph_init(hb_value_t * settings, hb_filter_init_t * init) { - hb_filter_private_t * pv = NULL; - char * sws_flags; + hb_avfilter_graph_t * graph; + AVFilterInOut * in = NULL, * out = NULL; AVFilterContext * avfilter; - char * filter_args; + char * settings_str; int result; - AVFilterInOut * in = NULL, * out = NULL; - char * avfilter_settings = NULL; + char * filter_args; - avfilter_settings = hb_filter_settings_string(HB_FILTER_AVFILTER, - filter->settings); - if (avfilter_settings == NULL) + graph = calloc(1, sizeof(hb_avfilter_graph_t)); + if (graph == NULL) { - hb_error("avfilter_init: no filter settings specified"); - return 1; + return NULL; } - pv = calloc(1, sizeof(struct hb_filter_private_s)); - filter->private_data = pv; + 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; + } - pv->settings = avfilter_settings; - pv->graph = avfilter_graph_alloc(); - if (pv->graph == NULL) + graph->settings = settings_str; + graph->avgraph = avfilter_graph_alloc(); + if (graph->avgraph == NULL) { - hb_error("avfilter_init: avfilter_graph_alloc failed"); + hb_error("hb_avfilter_graph_init: avfilter_graph_alloc failed"); goto fail; } - sws_flags = hb_strdup_printf("flags=%d", SWS_LANCZOS|SWS_ACCURATE_RND); - // avfilter_graph_free uses av_free to release scale_sws_opts. Due - // to the hacky implementation of av_free/av_malloc on windows, - // you must av_malloc anything that is av_free'd. - pv->graph->scale_sws_opts = av_malloc(strlen(sws_flags) + 1); - strcpy(pv->graph->scale_sws_opts, sws_flags); - free(sws_flags); + av_opt_set(graph->avgraph, "scale_sws_opts", "lanczos+accurate_rnd", 0); - result = avfilter_graph_parse2(pv->graph, avfilter_settings, &in, &out); + result = avfilter_graph_parse2(graph->avgraph, settings_str, &in, &out); if (result < 0 || in == NULL || out == NULL) { - hb_error("avfilter_init: avfilter_graph_parse2 failed (%s)", - avfilter_settings); + hb_error("hb_avfilter_graph_init: avfilter_graph_parse2 failed (%s)", + settings_str); goto fail; } @@ -210,60 +229,122 @@ static int avfilter_init( hb_filter_object_t * filter, hb_filter_init_t * init ) "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, - 1, 90000, init->vrate.num, init->vrate.den); + init->time_base.num, init->time_base.den, + init->vrate.num, init->vrate.den); - avfilter = append_filter(pv, "buffer", filter_args); + avfilter = append_filter(graph, "buffer", filter_args); free(filter_args); if (avfilter == NULL) { - hb_error("avfilter_init: failed to create buffer source filter"); + hb_error("hb_avfilter_graph_init: failed to create buffer source filter"); goto fail; } - pv->input = avfilter; + graph->input = avfilter; - avfilter = append_filter(pv, "format", "yuv420p"); + // Convert input to pix fmt YUV420P + avfilter = append_filter(graph, "format", "yuv420p"); if (avfilter == NULL) { - hb_error("avfilter_init: failed to create pix format filter"); + hb_error("hb_avfilter_graph_init: failed to create pix format filter"); goto fail; } // Link input to filter chain created by avfilter_graph_parse2 - result = avfilter_link(pv->last, 0, in->filter_ctx, 0); + result = avfilter_link(graph->last, 0, in->filter_ctx, 0); if (result < 0) { goto fail; } - pv->last = out->filter_ctx; + graph->last = out->filter_ctx; // Build filter output - avfilter = append_filter(pv, "buffersink", NULL); + avfilter = append_filter(graph, "buffersink", NULL); if (avfilter == NULL) { - hb_error("avfilter_init: failed to create buffer output filter"); + hb_error("hb_avfilter_graph_init: failed to create buffer output filter"); goto fail; } - pv->output = avfilter; +#if 0 + // Set output pix fmt to YUV420P + enum AVPixelFormat pix_fmts[2] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}; + if ((ret = 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(pv->graph, NULL); + result = avfilter_graph_config(graph->avgraph, NULL); if (result < 0) { - hb_error("avfilter_init: failed to configure filter graph"); + hb_error("hb_avfilter_graph_init: failed to configure filter graph"); goto fail; } - pv->frame = av_frame_alloc(); - if (pv->frame == NULL) + graph->frame = av_frame_alloc(); + if (graph->frame == NULL) { - hb_error("avfilter_init: failed to allocate frame filter"); + 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; + + pv = calloc(1, sizeof(struct hb_filter_private_s)); + filter->private_data = pv; + if (pv == NULL) + { + return 1; + } + pv->input = *init; + pv->initialized = 1; + + pv->graph = hb_avfilter_graph_init(filter->settings, init); + if (pv->graph == NULL) + { + goto fail; + } // Retrieve the parameters of the output filter - AVFilterLink *link = pv->output->inputs[0]; + AVFilterLink *link = pv->graph->output->inputs[0]; init->geometry.width = link->w; init->geometry.height = link->h; init->geometry.par.num = link->sample_aspect_ratio.num; @@ -276,40 +357,99 @@ static int avfilter_init( hb_filter_object_t * filter, hb_filter_init_t * init ) init->vrate.num = link->frame_rate.num; init->vrate.den = link->frame_rate.den; } - pv->out_time_base = link->time_base; + pv->output = *init; hb_buffer_list_clear(&pv->list); return 0; fail: - if (pv->input != NULL) - avfilter_free(pv->input); - if (pv->output != NULL) - avfilter_free(pv->output); - avfilter_inout_free(&in); - avfilter_inout_free(&out); - avfilter_graph_free(&pv->graph); - free(pv->settings); + hb_avfilter_graph_close(&pv->graph); + free(pv); + + return 1; +} + +static int avfilter_post_init( hb_filter_object_t * filter, hb_job_t * job ) +{ + hb_filter_private_t * pv = filter->private_data; + + if (pv == NULL) + { + return 1; + } + if (pv->initialized) + { + return 0; + } + + pv->graph = hb_avfilter_graph_init(filter->settings, &pv->input); + if (pv->graph == NULL) + { + goto fail; + } + + // Retrieve the parameters of the output filter + hb_filter_init_t * init = &pv->output; + AVFilterLink *link = pv->graph->output->inputs[0]; + *init = pv->input; + init->geometry.width = link->w; + init->geometry.height = link->h; + init->geometry.par.num = link->sample_aspect_ratio.num; + init->geometry.par.den = link->sample_aspect_ratio.den; + init->pix_fmt = link->format; + // avfilter can generate "unknown" framerates. If this happens + // just pass along the source framerate. + if (link->frame_rate.num > 0 && link->frame_rate.den > 0) + { + init->vrate.num = link->frame_rate.num; + init->vrate.den = link->frame_rate.den; + } + + hb_buffer_list_clear(&pv->list); + + return 0; + +fail: + hb_avfilter_graph_close(&pv->graph); free(pv); return 1; } -static hb_filter_info_t * avfilter_info( hb_filter_object_t * filter ) +static hb_filter_info_t * avfilter_info(hb_filter_object_t * filter) { hb_filter_private_t * pv = filter->private_data; hb_filter_info_t * info; - if( !pv ) + if (global_verbosity_level < 2) + { + // Only show this for log levels 2 and above + return NULL; + } + if (pv == NULL) + { return NULL; + } info = calloc(1, sizeof(hb_filter_info_t)); + if (info == NULL) + { + hb_error("avfilter_info: allocation failure"); + return NULL; + } + info->output = pv->output; info->human_readable_desc = malloc(1024); + if (info->human_readable_desc == NULL) + { + free(info); + hb_error("avfilter_info: allocation failure"); + return NULL; + } info->human_readable_desc[0] = 0; char * dst = info->human_readable_desc; - char * start = pv->settings; + char * start = pv->graph->settings; while (start != NULL && *start != 0) { // Find end of a filter @@ -375,66 +515,85 @@ static void avfilter_close( hb_filter_object_t * filter ) } hb_buffer_list_close(&pv->list); - av_frame_free(&pv->frame); - avfilter_graph_free(&pv->graph); - free(pv->settings); + hb_avfilter_graph_close(&pv->graph); free(pv); filter->private_data = NULL; } -static void fill_frame(hb_filter_private_t * pv, - AVFrame * frame, hb_buffer_t * buf) +static void avfilter_alias_close( hb_filter_object_t * filter ) { - frame->data[0] = buf->plane[0].data; - frame->data[1] = buf->plane[1].data; - frame->data[2] = buf->plane[2].data; - frame->linesize[0] = buf->plane[0].stride; - frame->linesize[1] = buf->plane[1].stride; - frame->linesize[2] = buf->plane[2].stride; - - frame->pts = buf->s.start; - frame->reordered_opaque = buf->s.duration; - frame->width = buf->f.width; - frame->height = buf->f.height; - frame->format = buf->f.fmt; - frame->interlaced_frame = !!buf->s.combed; - frame->top_field_first = !!(buf->s.flags & PIC_FLAG_TOP_FIELD_FIRST); + hb_filter_private_t * pv = filter->private_data; + if (pv == NULL) + { + // Already closed + return; + } + + hb_value_free(&pv->avfilters); + free(pv); + filter->private_data = NULL; } -static hb_buffer_t* filterFrame( hb_filter_private_t * pv, hb_buffer_t * in ) +int hb_avfilter_add_frame(hb_avfilter_graph_t * graph, AVFrame * frame) { - int result; - hb_buffer_list_t list; + 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) { - fill_frame(pv, pv->frame, in); - result = av_buffersrc_add_frame(pv->input, pv->frame); + hb_video_buffer_to_avframe(graph->frame, in); + return av_buffersrc_add_frame(graph->input, graph->frame); } else { - result = av_buffersrc_add_frame(pv->input, NULL); + return av_buffersrc_add_frame(graph->input, NULL); } - if (result < 0) +} + +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 NULL; + return hb_avframe_to_video_buffer(graph->frame, graph->out_time_base); } - hb_buffer_list_clear(&list); - result = av_buffersink_get_frame(pv->output, pv->frame); - while (result >= 0) + 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; + hb_buffer_t * buf, * next; + + hb_avfilter_add_buf(pv->graph, in); + buf = hb_avfilter_get_buf(pv->graph); + while (buf != NULL) { - hb_buffer_t * buf = hb_avframe_to_video_buffer(pv->frame, - pv->out_time_base); hb_buffer_list_append(&pv->list, buf); - av_frame_unref(pv->frame); - - result = av_buffersink_get_frame(pv->output, pv->frame); + buf = hb_avfilter_get_buf(pv->graph); } + + // Delay one frame so we can set the stop time of the output buffer + hb_buffer_list_clear(&list); while (hb_buffer_list_count(&pv->list) > 1) { - hb_buffer_t * buf = hb_buffer_list_rem_head(&pv->list); - hb_buffer_t * next = hb_buffer_list_head(&pv->list); + buf = hb_buffer_list_rem_head(&pv->list); + next = hb_buffer_list_head(&pv->list); buf->s.stop = next->s.start; hb_buffer_list_append(&list, buf); @@ -444,7 +603,7 @@ static hb_buffer_t* filterFrame( hb_filter_private_t * pv, hb_buffer_t * in ) } static int avfilter_work( hb_filter_object_t * filter, - hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) + hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { hb_filter_private_t * pv = filter->private_data; hb_buffer_t * in = *buf_in; @@ -469,80 +628,316 @@ static int avfilter_work( hb_filter_object_t * filter, return HB_FILTER_OK; } -/* Deinterlace Settings +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) +{ + 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 "limited"; + } +} + +/* CropScale 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 + * 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 hb_dict_t * -convert_deint_settings(const hb_dict_t * settings) +static int crop_scale_init(hb_filter_object_t * filter, hb_filter_init_t * init) { - int mode = 3, parity = -1; - - hb_dict_extract_int(&mode, settings, "mode"); - hb_dict_extract_int(&parity, settings, "parity"); + hb_filter_private_t * pv = NULL; - if (!(mode & MODE_YADIF_ENABLE)) + 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) { - return hb_value_null(); + 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); } - hb_dict_t * result = hb_dict_init(); + // 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(); - if (mode & MODE_YADIF_BOB) + 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) { - 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")); - } + case HB_COLR_MAT_BT709: + matrix = "bt709"; + break; + case HB_COLR_MAT_SMPTE170M: + matrix = "smpte170m"; + break; + case HB_COLR_MAT_SMPTE240M: + matrix = "smpte240m"; + break; + case HB_COLR_MAT_BT2020_NCL: + case HB_COLR_MAT_BT2020_CL: + matrix = "bt2020"; + break; + default: + case HB_COLR_MAT_UNDEF: + matrix = "bt601"; + break; + } - else + 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)); + hb_dict_set_string(avsettings, "out_range", + color_format_range(AV_PIX_FMT_YUV420P)); + 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) { - if (mode & MODE_YADIF_SPATIAL) - { - hb_dict_set(avsettings, "mode", hb_value_string("send_frame")); - } - else + 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) { - hb_dict_set(avsettings, "mode", - hb_value_string("send_frame_nospatial")); + // Not a numeric value, lookup by name + rgb = hb_rgb_lookup_by_name(color); } + free(color); + color = hb_strdup_printf("0x%06x", rgb); } - if (mode & MODE_DECOMB_SELECTIVE) + char x_str[20]; + char y_str[20]; + if (x < 0) { - hb_dict_set(avsettings, "deint", hb_value_string("interlaced")); + snprintf(x_str, 20, "(out_w-in_w)/2"); } - if (parity == 0) + else { - hb_dict_set(avsettings, "parity", hb_value_string("tff")); + snprintf(x_str, 20, "%d", x); } - else if (parity == 1) + if (y < 0) { - hb_dict_set(avsettings, "parity", hb_value_string("bff")); + 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_set(result, "yadif", avsettings); + hb_dict_t * avfilter = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); - return result; + 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: @@ -565,11 +960,24 @@ convert_deint_settings(const hb_dict_t * settings) * Mode 4: Rotate 90' (aka 90:0) * Mode 7: Flip horiz & vert plus Rotate 90' (aka 270:0) */ -static hb_dict_t * -convert_rotate_settings(const hb_dict_t * settings) +static int rotate_init(hb_filter_object_t * filter, hb_filter_init_t * init) { - const char * trans = NULL; - int angle = 180, flip = 0, hflip = 0, vflip = 0; + 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"); @@ -592,212 +1000,150 @@ convert_rotate_settings(const hb_dict_t * settings) hflip = flip; break; case 90: - trans = clock; + trans = clock; + tmp = width; + width = height; + height = tmp; break; case 180: vflip = 1; hflip = !flip; break; case 270: - trans = cclock; + trans = cclock; + tmp = width; + width = height; + height = tmp; break; default: break; } if (trans != NULL) { - hb_dict_t * result = hb_dict_init(); + hb_dict_t * avfilter = hb_dict_init(); hb_dict_t * avsettings = hb_dict_init(); hb_dict_set(avsettings, "dir", hb_value_string(trans)); - hb_dict_set(result, "transpose", avsettings); - - return result; + hb_dict_set(avfilter, "transpose", avsettings); + pv->avfilters = avfilter; } else if (hflip || vflip) { - hb_dict_t * result = hb_value_array_init(); - hb_dict_t * avfilter; + 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(result, avfilter); + hb_value_array_append(avfilters, avfilter); } if (hflip) { avfilter = hb_dict_init(); hb_dict_set(avfilter, "hflip", hb_value_null()); - hb_value_array_append(result, avfilter); + hb_value_array_append(avfilters, avfilter); } - return result; + pv->avfilters = avfilter; } else { - return hb_value_null(); + pv->avfilters = hb_value_null(); } + + init->geometry.width = width; + init->geometry.height = height; + pv->output = *init; + + return 0; } -/* Pad presets and tunes +/* 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 * - * There are currently no presets and tunes for pad - * The custom pad string is converted to an avformat filter graph string */ -static hb_dict_t * -convert_pad_settings(const hb_dict_t * settings) +static int deinterlace_init(hb_filter_object_t * filter, + hb_filter_init_t * init) { - int width = 0, height = 0, 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); - } + hb_filter_private_t * pv = NULL; - 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 + pv = calloc(1, sizeof(struct hb_filter_private_s)); + filter->private_data = pv; + if (pv == NULL) { - snprintf(y_str, 20, "%d", y); + return 1; } - hb_dict_t * result = hb_dict_init(); - hb_dict_t * avsettings = hb_dict_init(); + pv->input = *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)); - } - hb_dict_set(result, "pad", avsettings); + hb_dict_t * settings = filter->settings; - free(color); + int mode = 3, parity = -1; - return result; -} + hb_dict_extract_int(&mode, settings, "mode"); + hb_dict_extract_int(&parity, settings, "parity"); -static hb_dict_t * convert_settings(int filter_id, hb_dict_t * settings) -{ - switch (filter_id) - { - case HB_FILTER_ROTATE: - return convert_rotate_settings(settings); - case HB_FILTER_DEINTERLACE: - return convert_deint_settings(settings); - case HB_FILTER_PAD: - return convert_pad_settings(settings); - default: - return NULL; + if (!(mode & MODE_YADIF_ENABLE)) + { + return 0; } -} -void hb_avfilter_combine( hb_list_t * list ) -{ - hb_filter_object_t * avfilter = NULL; - hb_value_t * settings = NULL; - int ii; + hb_dict_t * avfilter = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); - for (ii = 0; ii < hb_list_count(list);) + if (mode & MODE_YADIF_BOB) { - hb_filter_object_t * filter = hb_list_item(list, ii); - switch (filter->id) + if (mode & MODE_YADIF_SPATIAL) { - case HB_FILTER_AVFILTER: - { - settings = hb_value_dup(filter->settings); - } break; - case HB_FILTER_ROTATE: - case HB_FILTER_DEINTERLACE: - case HB_FILTER_PAD: - { - settings = convert_settings(filter->id, filter->settings); - } break; - default: - avfilter = NULL; + hb_dict_set(avsettings, "mode", hb_value_string("send_field")); } - if (settings != NULL) + else { - // Some filter values can result in no filter. - // E.g. rotate angle=0:hflip=0 - if (hb_value_type(settings) == HB_VALUE_TYPE_NULL) - { - hb_list_rem(list, filter); - hb_filter_close(&filter); - hb_value_free(&settings); - continue; - } - if (avfilter == NULL) - { - avfilter = hb_filter_init(HB_FILTER_AVFILTER); - avfilter->settings = hb_value_array_init(); - hb_list_insert(list, ii, avfilter); - ii++; - } - hb_list_rem(list, filter); - hb_filter_close(&filter); - - hb_value_array_concat(avfilter->settings, settings); - hb_value_free(&settings); - continue; + hb_dict_set(avsettings, "mode", + hb_value_string("send_field_nospatial")); } - ii++; } -} - -char * hb_append_filter_string(char * graph_str, char * filter_str) -{ - char * tmp; - int size = 1, len = 0; - - if (graph_str != NULL) + else { - len = strlen(graph_str); - size += len + 1; + 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 (filter_str != NULL) + + if (mode & MODE_DECOMB_SELECTIVE) { - size += strlen(filter_str); + hb_dict_set(avsettings, "deint", hb_value_string("interlaced")); } - tmp = realloc(graph_str, size); - if (tmp == NULL) + if (parity == 0) { - return graph_str; + hb_dict_set(avsettings, "parity", hb_value_string("tff")); } - graph_str = tmp; - if (len > 0) + else if (parity == 1) { - graph_str[len++] = ','; + hb_dict_set(avsettings, "parity", hb_value_string("bff")); } - strcpy(&graph_str[len], filter_str); - return graph_str; -} + hb_dict_set(avfilter, "yadif", avsettings); + pv->avfilters = avfilter; + + pv->output = *init; + return 0; +} diff --git a/libhb/common.h b/libhb/common.h index a2a86fa83..bc65e9cbb 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -273,6 +273,7 @@ struct hb_geometry_settings_s struct hb_image_s { int format; + int max_plane; int width; int height; uint8_t *data; @@ -1250,23 +1251,29 @@ typedef struct hb_filter_init_s { hb_job_t * job; int pix_fmt; + int color_prim; + int color_transfer; + int color_matrix; hb_geometry_t geometry; int crop[4]; hb_rational_t vrate; int cfr; int grayscale; + hb_rational_t time_base; } hb_filter_init_t; typedef struct hb_filter_info_s { char * human_readable_desc; - hb_filter_init_t out; + hb_filter_init_t output; } hb_filter_info_t; struct hb_filter_object_s { int id; int enforce_order; + int skip; + int aliased; char * name; hb_dict_t * settings; diff --git a/libhb/cropscale.c b/libhb/cropscale.c deleted file mode 100644 index d6301cd61..000000000 --- a/libhb/cropscale.c +++ /dev/null @@ -1,228 +0,0 @@ -/* cropscale.c - - Copyright (c) 2003-2019 HandBrake Team - This file is part of the HandBrake source code - Homepage: . - 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 "common.h" - -struct hb_filter_private_s -{ - hb_job_t *job; - int width_in; - int height_in; - int pix_fmt; - int pix_fmt_out; - int width_out; - int height_out; - int crop[4]; - - struct SwsContext * context; -}; - -static int hb_crop_scale_init( hb_filter_object_t * filter, - hb_filter_init_t * init ); - -static int hb_crop_scale_work( hb_filter_object_t * filter, - hb_buffer_t ** buf_in, - hb_buffer_t ** buf_out ); - -static hb_filter_info_t * hb_crop_scale_info( hb_filter_object_t * filter ); - -static void hb_crop_scale_close( 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, - .name = "Crop and Scale", - .settings = NULL, - .init = hb_crop_scale_init, - .work = hb_crop_scale_work, - .close = hb_crop_scale_close, - .info = hb_crop_scale_info, - .settings_template = crop_scale_template, -}; - -static int hb_crop_scale_init( hb_filter_object_t * filter, - hb_filter_init_t * init ) -{ - filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) ); - hb_filter_private_t * pv = filter->private_data; - - // TODO: add pix format option to settings - pv->job = init->job; - pv->pix_fmt_out = init->pix_fmt; - pv->width_in = init->geometry.width; - pv->height_in = init->geometry.height; - pv->width_out = init->geometry.width - (init->crop[2] + init->crop[3]); - pv->height_out = init->geometry.height - (init->crop[0] + init->crop[1]); - - memcpy( pv->crop, init->crop, sizeof( int[4] ) ); - hb_dict_extract_int(&pv->width_out, filter->settings, "width"); - hb_dict_extract_int(&pv->height_out, filter->settings, "height"); - hb_dict_extract_int(&pv->crop[0], filter->settings, "crop-top"); - hb_dict_extract_int(&pv->crop[1], filter->settings, "crop-bottom"); - hb_dict_extract_int(&pv->crop[2], filter->settings, "crop-left"); - hb_dict_extract_int(&pv->crop[3], filter->settings, "crop-right"); - - // Set init values so the next stage in the pipline - // knows what it will be getting - init->pix_fmt = pv->pix_fmt; - init->geometry.width = pv->width_out; - init->geometry.height = pv->height_out; - memcpy( init->crop, pv->crop, sizeof( int[4] ) ); - - return 0; -} - -static hb_filter_info_t * hb_crop_scale_info( hb_filter_object_t * filter ) -{ - hb_filter_private_t * pv = filter->private_data; - hb_filter_info_t * info; - - if( !pv ) - return NULL; - - info = calloc(1, sizeof(hb_filter_info_t)); - info->human_readable_desc = malloc(128); - info->human_readable_desc[0] = 0; - - info->out.pix_fmt = pv->pix_fmt; - info->out.geometry.width = pv->width_out; - info->out.geometry.height = pv->height_out; - memcpy( info->out.crop, pv->crop, sizeof( int[4] ) ); - - int cropped_width = pv->width_in - ( pv->crop[2] + pv->crop[3] ); - int cropped_height = pv->height_in - ( pv->crop[0] + pv->crop[1] ); - - snprintf( info->human_readable_desc, 128, - "source: %d * %d, crop (%d/%d/%d/%d): %d * %d, scale: %d * %d", - pv->width_in, pv->height_in, - pv->crop[0], pv->crop[1], pv->crop[2], pv->crop[3], - cropped_width, cropped_height, pv->width_out, pv->height_out ); - - return info; -} - -static void hb_crop_scale_close( hb_filter_object_t * filter ) -{ - hb_filter_private_t * pv = filter->private_data; - - if ( !pv ) - { - return; - } - - if( pv->context ) - { - sws_freeContext( pv->context ); - } - - free( pv ); - filter->private_data = NULL; -} - -static hb_buffer_t* crop_scale( hb_filter_private_t * pv, hb_buffer_t * in ) -{ - hb_buffer_t * out; - uint8_t * crop_data[4], * out_data[4]; - int crop_stride[4], out_stride[4]; - - out = hb_video_buffer_init( pv->width_out, pv->height_out ); - hb_picture_fill(out_data, out_stride, out); - - // Crop; this alters the pointer to the data to point to the - // correct place for cropped frame - hb_picture_crop(crop_data, crop_stride, in, pv->crop[0], pv->crop[2]); - - if (pv->context == NULL || - pv->width_in != in->f.width || - pv->height_in != in->f.height || - pv->pix_fmt != in->f.fmt) - { - // Something changed, need a new scaling context. - if (pv->context != NULL) - { - sws_freeContext(pv->context); - } - - pv->context = hb_sws_get_context( - in->f.width - (pv->crop[2] + pv->crop[3]), - in->f.height - (pv->crop[0] + pv->crop[1]), - in->f.fmt, out->f.width, out->f.height, - out->f.fmt, SWS_LANCZOS|SWS_ACCURATE_RND, - hb_ff_get_colorspace(pv->job->title->color_matrix)); - pv->width_in = in->f.width; - pv->height_in = in->f.height; - pv->pix_fmt = in->f.fmt; - } - - if (pv->context == NULL) - { - hb_buffer_close(&out); - return NULL; - } - - // Scale crop into out according to the context set up above - sws_scale(pv->context, - (const uint8_t* const*)crop_data, crop_stride, - 0, in->f.height - (pv->crop[0] + pv->crop[1]), - out_data, out_stride); - - out->s = in->s; - return out; -} - -static int hb_crop_scale_work( hb_filter_object_t * filter, - hb_buffer_t ** buf_in, - hb_buffer_t ** buf_out ) -{ - hb_filter_private_t * pv = filter->private_data; - hb_buffer_t * in = *buf_in; - - if (in->s.flags & HB_BUF_FLAG_EOF) - { - *buf_out = in; - *buf_in = NULL; - return HB_FILTER_DONE; - } - - if ( !pv ) - { - *buf_out = in; - *buf_in = NULL; - return HB_FILTER_OK; - } - - // If width or height were not set, set them now based on the - // input width & height - if ( pv->width_out <= 0 || pv->height_out <= 0 ) - { - pv->width_out = in->f.width - (pv->crop[2] + pv->crop[3]); - pv->height_out = in->f.height - (pv->crop[0] + pv->crop[1]); - } - - if (!pv->crop[0] && !pv->crop[1] && !pv->crop[2] && !pv->crop[3] && - in->f.fmt == pv->pix_fmt_out && in->f.width == pv->width_out && - in->f.height == pv->height_out) - { - *buf_out = in; - *buf_in = NULL; - return HB_FILTER_OK; - } - - *buf_out = crop_scale(pv, in); - - return HB_FILTER_OK; -} diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 1a1a3ea3b..f93a24878 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -40,6 +40,7 @@ #include "hb.h" #include "hbffmpeg.h" +#include "hbavfilter.h" #include "libavfilter/avfilter.h" #include "libavfilter/buffersrc.h" #include "libavfilter/buffersink.h" @@ -98,14 +99,11 @@ struct reordered_data_s struct video_filters_s { - AVFilterGraph * graph; - AVFilterContext * last; - AVFilterContext * input; - AVFilterContext * output; - - int width; - int height; - int pix_fmt; + hb_avfilter_graph_t * graph; + + int width; + int height; + int pix_fmt; }; struct hb_work_private_s @@ -339,21 +337,7 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) **********************************************************************/ static void close_video_filters(hb_work_private_t *pv) { - if (pv->video_filters.input != NULL) - { - avfilter_free(pv->video_filters.input); - pv->video_filters.input = NULL; - } - if (pv->video_filters.output != NULL) - { - avfilter_free(pv->video_filters.output); - pv->video_filters.output = NULL; - } - if (pv->video_filters.graph != NULL) - { - avfilter_graph_free(&pv->video_filters.graph); - } - pv->video_filters.last = NULL; + hb_avfilter_graph_close(&pv->video_filters.graph); } static void closePrivData( hb_work_private_t ** ppv ) @@ -1127,42 +1111,13 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv ) return out; } -static AVFilterContext * append_filter(hb_work_private_t * pv, - const char * name, const char * args) -{ - AVFilterContext * filter; - int result; - - result = avfilter_graph_create_filter(&filter, avfilter_get_by_name(name), - name, args, NULL, - pv->video_filters.graph); - if (result < 0) - { - return NULL; - } - if (pv->video_filters.last != NULL) - { - result = avfilter_link(pv->video_filters.last, 0, filter, 0); - if (result < 0) - { - avfilter_free(filter); - return NULL; - } - } - pv->video_filters.last = filter; - - return filter; -} - int reinit_video_filters(hb_work_private_t * pv) { - char * sws_flags; - int result; - AVFilterContext * avfilter; - char * graph_str = NULL, * filter_str; - AVFilterInOut * in = NULL, * out = NULL; - int orig_width; - int orig_height; + int orig_width; + int orig_height; + hb_value_array_t * filters; + hb_dict_t * settings; + hb_filter_init_t filter_init; #ifdef USE_QSV if (pv->qsv.decode && @@ -1220,19 +1175,6 @@ int reinit_video_filters(hb_work_private_t * pv) // New filter required, create filter graph close_video_filters(pv); - pv->video_filters.graph = avfilter_graph_alloc(); - if (pv->video_filters.graph == NULL) - { - hb_log("reinit_video_filters: avfilter_graph_alloc failed"); - goto fail; - } - sws_flags = hb_strdup_printf("flags=%d", SWS_LANCZOS|SWS_ACCURATE_RND); - // avfilter_graph_free uses av_free to release scale_sws_opts. Due - // to the hacky implementation of av_free/av_malloc on windows, - // you must av_malloc anything that is av_free'd. - pv->video_filters.graph->scale_sws_opts = av_malloc(strlen(sws_flags) + 1); - strcpy(pv->video_filters.graph->scale_sws_opts, sws_flags); - free(sws_flags); int clock_min, clock_max, clock; hb_rational_t vrate; @@ -1241,100 +1183,65 @@ int reinit_video_filters(hb_work_private_t * pv) vrate.num = clock; vrate.den = pv->duration * (clock / 90000.); + filters = hb_value_array_init(); if (AV_PIX_FMT_YUV420P != pv->frame->format || orig_width != pv->frame->width || orig_height != pv->frame->height) { - filter_str = hb_strdup_printf( - "scale='w=%d:h=%d:flags=lanczos+accurate_rnd'," - "format='pix_fmts=yuv420p'", - orig_width, orig_height); - graph_str = hb_append_filter_string(graph_str, filter_str); - free(filter_str); + settings = hb_dict_init(); + 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); + + settings = hb_dict_init(); + hb_dict_set(settings, "pix_fmts", hb_value_string("yuv420p")); + hb_append_filter_dict(filters, "format", settings); } if (pv->title->rotation != HB_ROTATION_0) { switch (pv->title->rotation) { case HB_ROTATION_90: - filter_str = "transpose='dir=cclock'"; + settings = hb_dict_init(); + hb_dict_set(settings, "dir", hb_value_string("cclock")); + hb_append_filter_dict(filters, "transpose", settings); break; case HB_ROTATION_180: - filter_str = "hflip,vflip"; + hb_append_filter_dict(filters, "hflip", hb_value_null()); + hb_append_filter_dict(filters, "vflip", hb_value_null()); break; case HB_ROTATION_270: - filter_str = "transpose='dir=clock'"; + settings = hb_dict_init(); + hb_dict_set(settings, "dir", hb_value_string("clock")); + hb_append_filter_dict(filters, "transpose", settings); break; default: hb_log("reinit_video_filters: Unknown rotation, failed"); - goto fail; } - graph_str = hb_append_filter_string(graph_str, filter_str); } - // Build filter input - filter_str = hb_strdup_printf( - "width=%d:height=%d:pix_fmt=%d:sar=%d/%d:" - "time_base=%d/%d:frame_rate=%d/%d", - pv->frame->width, pv->frame->height, - pv->frame->format, - pv->frame->sample_aspect_ratio.num, - pv->frame->sample_aspect_ratio.den, - 1, 1, vrate.num, vrate.den); - - avfilter = append_filter(pv, "buffer", filter_str); - free(filter_str); - if (avfilter == NULL) - { - hb_error("reinit_video_filters: failed to create buffer source filter"); - goto fail; - } - pv->video_filters.input = avfilter; + filter_init.geometry.width = pv->frame->width; + filter_init.geometry.height = pv->frame->height; + filter_init.pix_fmt = pv->frame->format; + filter_init.geometry.par.num = pv->frame->sample_aspect_ratio.num; + filter_init.geometry.par.den = pv->frame->sample_aspect_ratio.den; + filter_init.time_base.num = 1; + filter_init.time_base.den = 1; + filter_init.vrate.num = vrate.num; + filter_init.vrate.den = vrate.den; - // Build the filter graph - result = avfilter_graph_parse2(pv->video_filters.graph, - graph_str, &in, &out); - if (result < 0 || in == NULL || out == NULL) - { - hb_error("reinit_video_filters: avfilter_graph_parse2 failed (%s)", - graph_str); - goto fail; - } - - // Link input to filter graph - result = avfilter_link(pv->video_filters.last, 0, in->filter_ctx, 0); - if (result < 0) - { - goto fail; - } - pv->video_filters.last = out->filter_ctx; - - // Build filter output and append to filter graph - avfilter = append_filter(pv, "buffersink", NULL); - if (avfilter == NULL) - { - hb_error("reinit_video_filters: failed to create buffer output filter"); - goto fail; - } - pv->video_filters.output = avfilter; - - result = avfilter_graph_config(pv->video_filters.graph, NULL); - if (result < 0) + pv->video_filters.graph = hb_avfilter_graph_init(filters, &filter_init); + if (pv->video_filters.graph == NULL) { - hb_error("reinit_video_filters: failed to configure filter graph"); + hb_error("reinit_video_filters: failed to create filter graph"); goto fail; } - free(graph_str); - avfilter_inout_free(&in); - avfilter_inout_free(&out); return 0; fail: - free(graph_str); - avfilter_inout_free(&in); - avfilter_inout_free(&out); close_video_filters(pv); return 1; @@ -1347,21 +1254,15 @@ static void filter_video(hb_work_private_t *pv) { int result; - result = av_buffersrc_add_frame(pv->video_filters.input, pv->frame); - if (result < 0) { - hb_error("filter_video: failed to add frame"); - } else { - result = av_buffersink_get_frame(pv->video_filters.output, pv->frame); - } + hb_avfilter_add_frame(pv->video_filters.graph, pv->frame); + result = hb_avfilter_get_frame(pv->video_filters.graph, pv->frame); while (result >= 0) { hb_buffer_t * buf = copy_frame(pv); hb_buffer_list_append(&pv->list, buf); av_frame_unref(pv->frame); ++pv->nframes; - - result = av_buffersink_get_frame(pv->video_filters.output, - pv->frame); + result = hb_avfilter_get_frame(pv->video_filters.graph, pv->frame); } } else diff --git a/libhb/fifo.c b/libhb/fifo.c index 63b138973..226b169e8 100644 --- a/libhb/fifo.c +++ b/libhb/fifo.c @@ -520,70 +520,52 @@ int hb_buffer_copy(hb_buffer_t * dst, const hb_buffer_t * src) return 0; } -static void hb_buffer_init_planes_internal( hb_buffer_t * b, uint8_t * has_plane ) +void hb_buffer_init_planes(hb_buffer_t * b) { - uint8_t * plane = b->data; - int p; + uint8_t * data = b->data; + int pp; - for( p = 0; p < 4; p++ ) + for( pp = 0; pp <= b->f.max_plane; pp++ ) { - if ( has_plane[p] ) - { - b->plane[p].data = plane; - b->plane[p].stride = hb_image_stride( b->f.fmt, b->f.width, p ); - b->plane[p].height_stride = hb_image_height_stride( b->f.fmt, b->f.height, p ); - b->plane[p].width = hb_image_width( b->f.fmt, b->f.width, p ); - b->plane[p].height = hb_image_height( b->f.fmt, b->f.height, p ); - b->plane[p].size = b->plane[p].stride * b->plane[p].height_stride; - plane += b->plane[p].size; - } + b->plane[pp].data = data; + b->plane[pp].stride = hb_image_stride(b->f.fmt, b->f.width, pp); + b->plane[pp].height_stride = hb_image_height_stride(b->f.fmt, + b->f.height, pp); + b->plane[pp].width = hb_image_width(b->f.fmt, b->f.width, pp); + b->plane[pp].height = hb_image_height(b->f.fmt, b->f.height, pp); + b->plane[pp].size = b->plane[pp].stride * + b->plane[pp].height_stride; + data += b->plane[pp].size; } } -void hb_buffer_init_planes( hb_buffer_t * b ) -{ - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(b->f.fmt); - int p; - - if (desc == NULL) - { - return; - } - - uint8_t has_plane[4] = {0,}; - - for( p = 0; p < 4; p++ ) - { - has_plane[desc->comp[p].plane] = 1; - } - hb_buffer_init_planes_internal( b, has_plane ); -} - // this routine gets a buffer for an uncompressed picture // with pixel format pix_fmt and dimensions width x height. hb_buffer_t * hb_frame_buffer_init( int pix_fmt, int width, int height ) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - hb_buffer_t * buf; - int p; - uint8_t has_plane[4] = {0,}; + const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get(pix_fmt); + hb_buffer_t * buf; + uint8_t has_plane[4] = {0,}; + int ii, pp, max_plane = 0; if (desc == NULL) { return NULL; } - for( p = 0; p < 4; p++ ) - { - has_plane[desc->comp[p].plane] = 1; - } int size = 0; - for( p = 0; p < 4; p++ ) + for (ii = 0; ii < desc->nb_components; ii++) { - if ( has_plane[p] ) + pp = desc->comp[ii].plane; + if (pp > max_plane) { - size += hb_image_stride( pix_fmt, width, p ) * - hb_image_height_stride( pix_fmt, height, p ); + max_plane = pp; + } + if (!has_plane[pp]) + { + has_plane[pp] = 1; + size += hb_image_stride( pix_fmt, width, pp ) * + hb_image_height_stride( pix_fmt, height, pp ); } } @@ -592,12 +574,13 @@ hb_buffer_t * hb_frame_buffer_init( int pix_fmt, int width, int height ) if( buf == NULL ) return NULL; + buf->f.max_plane = max_plane; buf->s.type = FRAME_BUF; buf->f.width = width; buf->f.height = height; buf->f.fmt = pix_fmt; - hb_buffer_init_planes_internal( buf, has_plane ); + hb_buffer_init_planes(buf); return buf; } @@ -606,7 +589,7 @@ void hb_frame_buffer_blank_stride(hb_buffer_t * buf) uint8_t * data; int pp, yy, width, height, stride, height_stride; - for (pp = 0; pp < 4; pp++) + for (pp = 0; pp <= buf->f.max_plane; pp++) { data = buf->plane[pp].data; width = buf->plane[pp].width; @@ -636,7 +619,7 @@ void hb_frame_buffer_mirror_stride(hb_buffer_t * buf) int pp, ii, yy, width, height, stride, height_stride; int pos, margin, margin_front, margin_back; - for (pp = 0; pp < 4; pp++) + for (pp = 0; pp <= buf->f.max_plane; pp++) { data = buf->plane[pp].data; width = buf->plane[pp].width; @@ -678,26 +661,29 @@ void hb_frame_buffer_mirror_stride(hb_buffer_t * buf) // with dimensions width x height. void hb_video_buffer_realloc( hb_buffer_t * buf, int width, int height ) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(buf->f.fmt); - int p; - uint8_t has_plane[4] = {0,}; + const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get(buf->f.fmt); + uint8_t has_plane[4] = {0,}; + int ii, pp; if (desc == NULL) { return; } - for( p = 0; p < 4; p++ ) - { - has_plane[desc->comp[p].plane] = 1; - } + buf->f.max_plane = 0; int size = 0; - for( p = 0; p < 4; p++ ) + for (ii = 0; ii < desc->nb_components; ii++) { - if ( has_plane[p] ) + pp = desc->comp[ii].plane; + if (pp > buf->f.max_plane) + { + buf->f.max_plane = pp; + } + if (!has_plane[pp]) { - size += hb_image_stride( buf->f.fmt, width, p ) * - hb_image_height_stride( buf->f.fmt, height, p ); + has_plane[pp] = 1; + size += hb_image_stride(buf->f.fmt, width, pp) * + hb_image_height_stride(buf->f.fmt, height, pp ); } } @@ -707,7 +693,7 @@ void hb_video_buffer_realloc( hb_buffer_t * buf, int width, int height ) buf->f.height = height; buf->size = size; - hb_buffer_init_planes_internal( buf, has_plane ); + hb_buffer_init_planes(buf); } // this routine 'moves' data from src to dst by interchanging 'data', @@ -797,34 +783,39 @@ void hb_buffer_close( hb_buffer_t ** _b ) hb_image_t * hb_image_init(int pix_fmt, int width, int height) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - int p; - uint8_t has_plane[4] = {0,}; + const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get(pix_fmt); + uint8_t has_plane[4] = {0,}; + int ii, pp; if (desc == NULL) { return NULL; } - for (p = 0; p < 4; p++) + + hb_image_t *image = calloc(1, sizeof(hb_image_t)); + if (image == NULL) { - has_plane[desc->comp[p].plane] = 1; + return NULL; } int size = 0; - for (p = 0; p < 4; p++) + for (ii = 0; ii < desc->nb_components; ii++) { - if (has_plane[p]) + // For non-planar formats, comp[ii].plane can contain the + // same value for multiple comp. + pp = desc->comp[ii].plane; + if (pp > image->max_plane) + { + image->max_plane = pp; + } + if (!has_plane[pp]) { - size += hb_image_stride( pix_fmt, width, p ) * - hb_image_height_stride( pix_fmt, height, p ); + has_plane[pp] = 1; + size += hb_image_stride( pix_fmt, width, pp ) * + hb_image_height_stride( pix_fmt, height, pp ); } } - hb_image_t *image = calloc(1, sizeof(hb_image_t)); - if (image == NULL) - { - return NULL; - } image->data = av_malloc(size); if (image->data == NULL) { @@ -836,21 +827,18 @@ hb_image_t * hb_image_init(int pix_fmt, int width, int height) image->height = height; memset(image->data, 0, size); - uint8_t * plane = image->data; - for (p = 0; p < 4; p++) + uint8_t * data = image->data; + for (pp = 0; pp <= image->max_plane; pp++) { - if (has_plane[p]) - { - image->plane[p].data = plane; - image->plane[p].stride = hb_image_stride(pix_fmt, width, p ); - image->plane[p].height_stride = - hb_image_height_stride(pix_fmt, height, p ); - image->plane[p].width = hb_image_width(pix_fmt, width, p ); - image->plane[p].height = hb_image_height(pix_fmt, height, p ); - image->plane[p].size = - image->plane[p].stride * image->plane[p].height_stride; - plane += image->plane[p].size; - } + image->plane[pp].data = data; + image->plane[pp].stride = hb_image_stride(pix_fmt, width, pp); + image->plane[pp].height_stride = + hb_image_height_stride(pix_fmt, height, pp); + image->plane[pp].width = hb_image_width(pix_fmt, width, pp); + image->plane[pp].height = hb_image_height(pix_fmt, height, pp); + image->plane[pp].size = image->plane[pp].stride * + image->plane[pp].height_stride; + data += image->plane[pp].size; } return image; } @@ -873,7 +861,7 @@ hb_image_t * hb_buffer_to_image(hb_buffer_t *buf) int p; uint8_t *data = image->data; - for (p = 0; p < 4; p++) + for (p = 0; p <= buf->f.max_plane; p++) { image->plane[p].data = data; image->plane[p].width = buf->plane[p].width; diff --git a/libhb/hb.c b/libhb/hb.c index c4ce54721..a9dc2cdc6 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -114,7 +114,7 @@ int hb_picture_fill(uint8_t *data[], int stride[], hb_buffer_t *buf) { int ret, ii; - for (ii = 0; ii < 4; ii++) + for (ii = 0; ii <= buf->f.max_plane; ii++) stride[ii] = buf->plane[ii].stride; ret = av_image_fill_pointers(data, buf->f.fmt, @@ -472,7 +472,7 @@ int hb_save_preview( hb_handle_t * h, int title, int preview, hb_buffer_t *buf ) } int pp, hh; - for( pp = 0; pp < 3; pp++ ) + for( pp = 0; pp <= buf->f.max_plane; pp++ ) { uint8_t *data = buf->plane[pp].data; int stride = buf->plane[pp].stride; @@ -705,7 +705,7 @@ int hb_detect_comb( hb_buffer_t * buf, int color_equal, int color_diff, int thre } /* One pas for Y, one pass for Cb, one pass for Cr */ - for( k = 0; k < 3; k++ ) + for( k = 0; k <= buf->f.max_plane; k++ ) { uint8_t * data = buf->plane[k].data; int width = buf->plane[k].width; diff --git a/libhb/hbavfilter.h b/libhb/hbavfilter.h new file mode 100644 index 000000000..f3c32f336 --- /dev/null +++ b/libhb/hbavfilter.h @@ -0,0 +1,28 @@ +/* hbffmpeg.h + + Copyright (c) 2003-2019 HandBrake Team + This file is part of the HandBrake source code + Homepage: . + 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_H +#define HB_AVFILTER_H + +typedef struct hb_avfilter_graph_s hb_avfilter_graph_t; + +hb_avfilter_graph_t * hb_avfilter_graph_init(hb_value_t * settings, + hb_filter_init_t * init); +void hb_avfilter_graph_close(hb_avfilter_graph_t ** _g); + +int hb_avfilter_add_frame(hb_avfilter_graph_t * graph, AVFrame * frame); +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, + const char * name, hb_dict_t * settings); + +void hb_avfilter_combine(hb_list_t * list); +#endif // HB_AVFILTER_H diff --git a/libhb/hbffmpeg.c b/libhb/hbffmpeg.c index eff7623f9..c604bf703 100644 --- a/libhb/hbffmpeg.c +++ b/libhb/hbffmpeg.c @@ -21,6 +21,24 @@ static int get_frame_type(int type) } } +void hb_video_buffer_to_avframe(AVFrame *frame, hb_buffer_t * buf) +{ + frame->data[0] = buf->plane[0].data; + frame->data[1] = buf->plane[1].data; + frame->data[2] = buf->plane[2].data; + frame->linesize[0] = buf->plane[0].stride; + frame->linesize[1] = buf->plane[1].stride; + frame->linesize[2] = buf->plane[2].stride; + + frame->pts = buf->s.start; + frame->reordered_opaque = buf->s.duration; + frame->width = buf->f.width; + frame->height = buf->f.height; + frame->format = buf->f.fmt; + frame->interlaced_frame = !!buf->s.combed; + frame->top_field_first = !!(buf->s.flags & PIC_FLAG_TOP_FIELD_FIRST); +} + void hb_avframe_set_video_buffer_flags(hb_buffer_t * buf, AVFrame *frame, AVRational time_base) { @@ -68,19 +86,19 @@ hb_buffer_t * hb_avframe_to_video_buffer(AVFrame *frame, AVRational time_base) hb_avframe_set_video_buffer_flags(buf, frame, time_base); int pp; - for (pp = 0; pp < 3; pp++) + for (pp = 0; pp <= buf->f.max_plane; pp++) { int yy; - int width = buf->plane[pp].width; int stride = buf->plane[pp].stride; int height = buf->plane[pp].height; int linesize = frame->linesize[pp]; + int size = linesize < stride ? linesize : stride; uint8_t * dst = buf->plane[pp].data; uint8_t * src = frame->data[pp]; for (yy = 0; yy < height; yy++) { - memcpy(dst, src, width); + memcpy(dst, src, size); dst += stride; src += linesize; } diff --git a/libhb/hbffmpeg.h b/libhb/hbffmpeg.h index 3b84cb03a..648089c37 100644 --- a/libhb/hbffmpeg.h +++ b/libhb/hbffmpeg.h @@ -42,9 +42,12 @@ hb_sws_get_context(int srcW, int srcH, enum AVPixelFormat srcFormat, static const char* const hb_vce_preset_names[] = { "speed", "balanced", "quality", NULL, }; -hb_buffer_t * hb_avframe_to_video_buffer(AVFrame *frame, AVRational time_base); -void hb_avframe_set_video_buffer_flags(hb_buffer_t * buf, AVFrame *frame, - AVRational time_base); +void hb_video_buffer_to_avframe(AVFrame *frame, hb_buffer_t * buf); +hb_buffer_t * hb_avframe_to_video_buffer(AVFrame *frame, + AVRational time_base); +void hb_avframe_set_video_buffer_flags(hb_buffer_t * buf, + AVFrame *frame, + AVRational time_base); int hb_av_encoder_present(int encoder); const char* const* hb_av_profile_get_names(int encoder); diff --git a/libhb/internal.h b/libhb/internal.h index 5357a3af7..fb121a9bf 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -113,6 +113,7 @@ struct hb_image_format_s int width; int height; int fmt; + int max_plane; int window_width; int window_height; }; @@ -498,8 +499,6 @@ DECLARE_MUX( webm ); DECLARE_MUX( avformat ); void hb_deinterlace(hb_buffer_t *dst, hb_buffer_t *src); -void hb_avfilter_combine( hb_list_t * list ); -char * hb_append_filter_string(char * graph_str, char * filter_str); struct hb_chapter_queue_item_s { diff --git a/libhb/vfr.c b/libhb/vfr.c index 19c5673a2..0629b90fa 100644 --- a/libhb/vfr.c +++ b/libhb/vfr.c @@ -445,7 +445,7 @@ static hb_filter_info_t * hb_vfr_info( hb_filter_object_t * filter ) info->human_readable_desc = malloc(128); info->human_readable_desc[0] = 0; - info->out.vrate = pv->input_vrate; + info->output.vrate = pv->input_vrate; if (pv->cfr == 2) { // For PFR, we want the framerate based on the source's actual @@ -456,14 +456,14 @@ static hb_filter_info_t * hb_vfr_info( hb_filter_object_t * filter ) { // peak framerate is lower than the source framerate. // so signal that the framerate will be the peak fps. - info->out.vrate = pv->vrate; + info->output.vrate = pv->vrate; } } else { - info->out.vrate = pv->vrate; + info->output.vrate = pv->vrate; } - info->out.cfr = pv->cfr; + info->output.cfr = pv->cfr; if ( pv->cfr == 0 ) { /* Ensure we're using "Same as source" FPS */ diff --git a/libhb/work.c b/libhb/work.c index 3d3b3c730..f5654b45d 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -10,6 +10,7 @@ #include "hb.h" #include "libavformat/avformat.h" #include "decomb.h" +#include "hbavfilter.h" #ifdef USE_QSV #include "qsv_common.h" @@ -444,6 +445,10 @@ void hb_display_job_info(hb_job_t *job) for( i = 0; i < hb_list_count( job->list_filter ); i++ ) { hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); + if (filter->aliased && global_verbosity_level < 2) + { + continue; + } char * settings = hb_filter_settings_string(filter->id, filter->settings); if (settings != NULL) @@ -1388,9 +1393,6 @@ static void sanitize_filter_list(hb_list_t *list) } } } - - // Combine HB_FILTER_AVFILTERs that are sequential - hb_avfilter_combine(list); } /** @@ -1459,8 +1461,13 @@ static void do_job(hb_job_t *job) sanitize_filter_list(job->list_filter); memset(&init, 0, sizeof(init)); + init.time_base.num = 1; + init.time_base.den = 90000; init.job = job; init.pix_fmt = AV_PIX_FMT_YUV420P; + init.color_prim = title->color_prim; + init.color_transfer = title->color_transfer; + init.color_matrix = title->color_matrix; init.geometry.width = title->geometry.width; init.geometry.height = title->geometry.height; @@ -1469,11 +1476,12 @@ static void do_job(hb_job_t *job) init.vrate = job->vrate; init.cfr = 0; init.grayscale = 0; + for( i = 0; i < hb_list_count( job->list_filter ); ) { hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); filter->done = &job->done; - if (filter->init(filter, &init)) + if (filter->init != NULL && filter->init(filter, &init)) { hb_log( "Failure to initialise filter '%s', disabling", filter->name ); @@ -1491,12 +1499,16 @@ static void do_job(hb_job_t *job) job->cfr = init.cfr; job->grayscale = init.grayscale; + // Combine HB_FILTER_AVFILTERs that are sequential + hb_avfilter_combine(job->list_filter); + // Perform filter post_init which informs filters of final // job configuration. e.g. rendersub filter needs to know the // final crop dimensions. for( i = 0; i < hb_list_count( job->list_filter ); ) { hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); + filter->done = &job->done; if (filter->post_init != NULL && filter->post_init(filter, job)) { hb_log( "Failure to initialise filter '%s', disabling", @@ -1696,9 +1708,12 @@ static void do_job(hb_job_t *job) for (i = 0; i < hb_list_count(job->list_filter); i++) { hb_filter_object_t * filter = hb_list_item(job->list_filter, i); - filter->fifo_in = fifo_in; - filter->fifo_out = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE ); - fifo_in = filter->fifo_out; + if (!filter->skip) + { + filter->fifo_in = fifo_in; + filter->fifo_out = hb_fifo_init(FIFO_MINI, FIFO_MINI_WAKE); + fifo_in = filter->fifo_out; + } } job->fifo_render = fifo_in; } @@ -1776,10 +1791,13 @@ static void do_job(hb_job_t *job) { hb_filter_object_t * filter = hb_list_item(job->list_filter, i); - // Filters were initialized earlier, so we just need - // to start the filter's thread - filter->thread = hb_thread_init( filter->name, filter_loop, filter, - HB_LOW_PRIORITY ); + if (!filter->skip) + { + // Filters were initialized earlier, so we just need + // to start the filter's thread + filter->thread = hb_thread_init(filter->name, filter_loop, + filter, HB_LOW_PRIORITY); + } } } @@ -1869,7 +1887,10 @@ cleanup: for (i = 0; i < hb_list_count( job->list_filter ); i++) { hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); - hb_fifo_close( &filter->fifo_out ); + if (!filter->skip) + { + hb_fifo_close( &filter->fifo_out ); + } } } -- 2.40.0