summaryrefslogtreecommitdiffstats
path: root/video/filter
diff options
context:
space:
mode:
authorMartin Herkt <lachs0r@srsfckn.biz>2017-02-12 01:01:56 +0100
committerMartin Herkt <lachs0r@srsfckn.biz>2017-02-12 01:01:56 +0100
commit35aa705c3ece8293652ffcf449c71fe80b96e722 (patch)
tree7c0fb34ec96204cbcd867a973b2476689919a5b4 /video/filter
parent10a005df0c981050afc35184a42173bea7ea2527 (diff)
parent3739d1318fdb658bb6037bfe06bb6cefb3b50a09 (diff)
downloadmpv-35aa705c3ece8293652ffcf449c71fe80b96e722.tar.bz2
mpv-35aa705c3ece8293652ffcf449c71fe80b96e722.tar.xz
Merge branch 'master' into release/current
Diffstat (limited to 'video/filter')
-rw-r--r--video/filter/vf.c17
-rw-r--r--video/filter/vf.h7
-rw-r--r--video/filter/vf_lavfi.c90
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);