summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Stebbins <[email protected]>2019-03-15 11:12:38 -0600
committerJohn Stebbins <[email protected]>2019-04-08 07:44:09 -0600
commit248c880fc86ee07d23d62135e002940f16364eb6 (patch)
tree7d0e2fa275cf8acf9cf678af457a1e93bb0afc1b
parent80aa72096148c8bd84e2abb677a57dcadfe03e1c (diff)
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.
-rw-r--r--libhb/avfilter.c1022
-rw-r--r--libhb/common.h9
-rw-r--r--libhb/cropscale.c228
-rw-r--r--libhb/decavcodec.c189
-rw-r--r--libhb/fifo.c166
-rw-r--r--libhb/hb.c6
-rw-r--r--libhb/hbavfilter.h28
-rw-r--r--libhb/hbffmpeg.c24
-rw-r--r--libhb/hbffmpeg.h9
-rw-r--r--libhb/internal.h3
-rw-r--r--libhb/vfr.c8
-rw-r--r--libhb/work.c45
12 files changed, 910 insertions, 827 deletions
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 hb_filter_info_t * avfilter_info( hb_filter_object_t * filter )
+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)
{
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;
}
- hb_dict_set(result, "yadif", avsettings);
+ if (height < 0)
+ {
+ height = init->geometry.height;
+ }
+ 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: <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 "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: <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_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 );
+ }
}
}