summaryrefslogtreecommitdiffstats
path: root/libhb
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 /libhb
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.
Diffstat (limited to 'libhb')
-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 );
+ }
}
}