diff options
author | Martin Herkt <lachs0r@srsfckn.biz> | 2017-02-12 01:01:56 +0100 |
---|---|---|
committer | Martin Herkt <lachs0r@srsfckn.biz> | 2017-02-12 01:01:56 +0100 |
commit | 35aa705c3ece8293652ffcf449c71fe80b96e722 (patch) | |
tree | 7c0fb34ec96204cbcd867a973b2476689919a5b4 /video/filter | |
parent | 10a005df0c981050afc35184a42173bea7ea2527 (diff) | |
parent | 3739d1318fdb658bb6037bfe06bb6cefb3b50a09 (diff) | |
download | mpv-35aa705c3ece8293652ffcf449c71fe80b96e722.tar.bz2 mpv-35aa705c3ece8293652ffcf449c71fe80b96e722.tar.xz |
Merge branch 'master' into release/current
Diffstat (limited to 'video/filter')
-rw-r--r-- | video/filter/vf.c | 17 | ||||
-rw-r--r-- | video/filter/vf.h | 7 | ||||
-rw-r--r-- | video/filter/vf_lavfi.c | 90 |
3 files changed, 79 insertions, 35 deletions
diff --git a/video/filter/vf.c b/video/filter/vf.c index 41fbe9b208..94e6760603 100644 --- a/video/filter/vf.c +++ b/video/filter/vf.c @@ -20,6 +20,7 @@ #include <string.h> #include <assert.h> #include <sys/types.h> +#include <libavutil/buffer.h> #include <libavutil/common.h> #include <libavutil/mem.h> @@ -644,14 +645,20 @@ int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params) uint8_t unused[IMGFMT_END - IMGFMT_START]; update_formats(c, c->first, unused); + AVBufferRef *hwfctx = c->in_hwframes_ref; struct vf_instance *failing = NULL; for (struct vf_instance *vf = c->first; vf; vf = vf->next) { + av_buffer_unref(&vf->in_hwframes_ref); + av_buffer_unref(&vf->out_hwframes_ref); + vf->in_hwframes_ref = hwfctx ? av_buffer_ref(hwfctx) : NULL; + vf->out_hwframes_ref = hwfctx ? av_buffer_ref(hwfctx) : NULL; r = vf_reconfig_wrapper(vf, &cur); if (r < 0) { failing = vf; break; } cur = vf->fmt_out; + hwfctx = vf->out_hwframes_ref; } c->output_params = cur; c->initialized = r < 0 ? -1 : 1; @@ -665,6 +672,13 @@ int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params) return r; } +// Hack to get mp_image.hwctx before vf_reconfig() +void vf_set_proto_frame(struct vf_chain *c, struct mp_image *img) +{ + av_buffer_unref(&c->in_hwframes_ref); + c->in_hwframes_ref = img && img->hwctx ? av_buffer_ref(img->hwctx) : NULL; +} + struct vf_instance *vf_find_by_label(struct vf_chain *c, const char *label) { struct vf_instance *vf = c->first; @@ -678,6 +692,8 @@ struct vf_instance *vf_find_by_label(struct vf_chain *c, const char *label) static void vf_uninit_filter(vf_instance_t *vf) { + av_buffer_unref(&vf->in_hwframes_ref); + av_buffer_unref(&vf->out_hwframes_ref); if (vf->uninit) vf->uninit(vf); vf_forget_frames(vf); @@ -729,6 +745,7 @@ void vf_destroy(struct vf_chain *c) { if (!c) return; + av_buffer_unref(&c->in_hwframes_ref); while (c->first) { vf_instance_t *vf = c->first; c->first = vf->next; diff --git a/video/filter/vf.h b/video/filter/vf.h index 901ccead95..241af02081 100644 --- a/video/filter/vf.h +++ b/video/filter/vf.h @@ -90,6 +90,9 @@ typedef struct vf_instance { struct mp_image_params fmt_in, fmt_out; + // This is a dirty hack. + struct AVBufferRef *in_hwframes_ref, *out_hwframes_ref; + struct mp_image_pool *out_pool; struct vf_priv_s *priv; struct mp_log *log; @@ -123,6 +126,9 @@ struct vf_chain { struct mpv_global *global; struct mp_hwdec_devices *hwdec_devs; + // This is a dirty hack. + struct AVBufferRef *in_hwframes_ref; + // Call when the filter chain wants new processing (for filters with // asynchronous behavior) - must be immutable once filters are created, // since they are supposed to call it from foreign threads. @@ -150,6 +156,7 @@ enum vf_ctrl { struct vf_chain *vf_new(struct mpv_global *global); void vf_destroy(struct vf_chain *c); +void vf_set_proto_frame(struct vf_chain *c, struct mp_image *img); int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params); int vf_control_any(struct vf_chain *c, int cmd, void *arg); int vf_control_by_label(struct vf_chain *c, int cmd, void *arg, bstr label); diff --git a/video/filter/vf_lavfi.c b/video/filter/vf_lavfi.c index a66bd2a971..d79bfd4011 100644 --- a/video/filter/vf_lavfi.c +++ b/video/filter/vf_lavfi.c @@ -26,6 +26,7 @@ #include <assert.h> #include <libavutil/avstring.h> +#include <libavutil/hwcontext.h> #include <libavutil/mem.h> #include <libavutil/mathematics.h> #include <libavutil/rational.h> @@ -44,6 +45,7 @@ #include "options/m_option.h" #include "common/tags.h" +#include "video/hwdec.h" #include "video/img_format.h" #include "video/mp_image.h" #include "video/sws_utils.h" @@ -108,7 +110,8 @@ static bool recreate_graph(struct vf_instance *vf, struct mp_image_params *fmt) { void *tmp = talloc_new(NULL); struct vf_priv_s *p = vf->priv; - AVFilterContext *in = NULL, *out = NULL, *f_format = NULL; + AVFilterContext *in = NULL, *out = NULL; + int ret; if (bstr0(p->cfg_graph).len == 0) { MP_FATAL(vf, "lavfi: no filter graph set\n"); @@ -130,53 +133,56 @@ static bool recreate_graph(struct vf_instance *vf, struct mp_image_params *fmt) if (!outputs || !inputs) goto error; - // Build list of acceptable output pixel formats. libavfilter will insert - // conversion filters if needed. - char *fmtstr = talloc_strdup(tmp, ""); - for (int n = IMGFMT_START; n < IMGFMT_END; n++) { - if (vf_next_query_format(vf, n)) { - const char *name = av_get_pix_fmt_name(imgfmt2pixfmt(n)); - if (name) { - const char *s = fmtstr[0] ? "|" : ""; - fmtstr = talloc_asprintf_append_buffer(fmtstr, "%s%s", s, name); - } - } - } - char *sws_flags = talloc_asprintf(tmp, "flags=%"PRId64, p->cfg_sws_flags); graph->scale_sws_opts = av_strdup(sws_flags); - AVRational timebase = AV_TIME_BASE_Q; - - char *src_args = talloc_asprintf(tmp, "%d:%d:%d:%d:%d:%d:%d", - fmt->w, fmt->h, imgfmt2pixfmt(fmt->imgfmt), - timebase.num, timebase.den, - fmt->p_w, fmt->p_h); + in = avfilter_graph_alloc_filter(graph, avfilter_get_by_name("buffer"), "src"); + if (!in) + goto error; - if (avfilter_graph_create_filter(&in, avfilter_get_by_name("buffer"), - "src", src_args, NULL, graph) < 0) + AVBufferSrcParameters *in_params = av_buffersrc_parameters_alloc(); + if (!in_params) goto error; - if (avfilter_graph_create_filter(&out, avfilter_get_by_name("buffersink"), - "out", NULL, NULL, graph) < 0) + in_params->format = imgfmt2pixfmt(fmt->imgfmt); + in_params->time_base = AV_TIME_BASE_Q; + in_params->width = fmt->w; + in_params->height = fmt->h; + in_params->sample_aspect_ratio.num = fmt->p_w; + in_params->sample_aspect_ratio.den = fmt->p_h; + // Assume it's ignored for non-hwaccel formats. + in_params->hw_frames_ctx = vf->in_hwframes_ref; + + ret = av_buffersrc_parameters_set(in, in_params); + av_free(in_params); + if (ret < 0) goto error; - if (avfilter_graph_create_filter(&f_format, avfilter_get_by_name("format"), - "format", fmtstr, NULL, graph) < 0) + if (avfilter_init_str(in, NULL) < 0) goto error; - if (avfilter_link(f_format, 0, out, 0) < 0) + if (avfilter_graph_create_filter(&out, avfilter_get_by_name("buffersink"), + "out", NULL, NULL, graph) < 0) goto error; outputs->name = av_strdup("in"); outputs->filter_ctx = in; inputs->name = av_strdup("out"); - inputs->filter_ctx = f_format; + inputs->filter_ctx = out; if (graph_parse(graph, p->cfg_graph, inputs, outputs, NULL) < 0) goto error; + if (vf->hwdec_devs) { + struct mp_hwdec_ctx *hwdec = hwdec_devices_get_first(vf->hwdec_devs); + for (int n = 0; n < graph->nb_filters; n++) { + AVFilterContext *filter = graph->filters[n]; + if (hwdec && hwdec->av_device_ref) + filter->hw_device_ctx = av_buffer_ref(hwdec->av_device_ref); + } + } + if (avfilter_graph_config(graph, NULL) < 0) goto error; @@ -233,17 +239,25 @@ static int reconfig(struct vf_instance *vf, struct mp_image_params *in, out->p_w = l_out->sample_aspect_ratio.num; out->p_h = l_out->sample_aspect_ratio.den; out->imgfmt = pixfmt2imgfmt(l_out->format); + av_buffer_unref(&vf->out_hwframes_ref); +#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(6, 69, 100) && \ + LIBAVFILTER_VERSION_MICRO >= 100 + AVBufferRef *hw_frames_ctx = av_buffersink_get_hw_frames_ctx(p->out); +#else + AVBufferRef *hw_frames_ctx = l_out->hw_frames_ctx; +#endif + if (hw_frames_ctx) { + AVHWFramesContext *fctx = (void *)hw_frames_ctx->data; + out->hw_subfmt = pixfmt2imgfmt(fctx->sw_format); + vf->out_hwframes_ref = av_buffer_ref(hw_frames_ctx); + } return 0; } static int query_format(struct vf_instance *vf, unsigned int fmt) { - // We accept all sws-convertable formats as inputs. Output formats are - // handled in config(). The current public libavfilter API doesn't really - // allow us to do anything more sophisticated. - // This breaks with filters which accept input pixel formats not - // supported by libswscale. - return !!mp_sws_supported_format(fmt); + // Format negotiation is not possible with libavfilter. + return 1; } static AVFrame *mp_to_av(struct vf_instance *vf, struct mp_image *img) @@ -275,7 +289,7 @@ static struct mp_image *av_to_mp(struct vf_instance *vf, AVFrame *av_frame) static void get_metadata_from_av_frame(struct vf_instance *vf, AVFrame *frame) { -#if HAVE_AVFRAME_METADATA +#if LIBAVUTIL_VERSION_MICRO >= 100 struct vf_priv_s *p = vf->priv; if (!p->metadata) p->metadata = talloc_zero(p, struct mp_tags); @@ -298,6 +312,12 @@ static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) if (!p->graph) return -1; + if (!mpi) { + if (p->eof) + return 0; + p->eof = true; + } + AVFrame *frame = mp_to_av(vf, mpi); int r = av_buffersrc_add_frame(p->in, frame) < 0 ? -1 : 0; av_frame_free(&frame); |