summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/csputils.c38
-rw-r--r--video/csputils.h2
-rw-r--r--video/decode/vd_lavc.c61
-rw-r--r--video/filter/vf.c4
-rw-r--r--video/filter/vf_hqdn3d.c2
-rw-r--r--video/filter/vf_lavfi.c348
-rw-r--r--video/filter/vf_rotate.c13
-rw-r--r--video/filter/vf_scale.c1
-rw-r--r--video/filter/vf_yadif.c3
-rw-r--r--video/fmt-conversion.c8
-rw-r--r--video/img_format.c9
-rw-r--r--video/img_format.h9
-rw-r--r--video/mp_image.c50
-rw-r--r--video/mp_image.h3
-rw-r--r--video/out/cocoa_common.h5
-rw-r--r--video/out/cocoa_common.m593
-rw-r--r--video/out/gl_cocoa.c8
-rw-r--r--video/out/gl_common.c27
-rw-r--r--video/out/gl_common.h15
-rw-r--r--video/out/gl_osd.c54
-rw-r--r--video/out/gl_osd.h14
-rw-r--r--video/out/gl_video.c76
-rw-r--r--video/out/gl_video.h1
-rw-r--r--video/out/gl_video_shaders.glsl8
-rw-r--r--video/out/gl_wayland.c85
-rw-r--r--video/out/vo_opengl.c72
-rw-r--r--video/out/vo_opengl_old.c5
-rw-r--r--video/out/wayland_common.c341
-rw-r--r--video/out/wayland_common.h47
-rw-r--r--video/out/x11_common.c44
-rw-r--r--video/out/x11_common.h1
31 files changed, 1251 insertions, 696 deletions
diff --git a/video/csputils.c b/video/csputils.c
index 23eb099f69..cc87725d45 100644
--- a/video/csputils.c
+++ b/video/csputils.c
@@ -40,6 +40,8 @@ char * const mp_csp_names[MP_CSP_COUNT] = {
"BT.709 (HD)",
"SMPTE-240M",
"RGB",
+ "XYZ",
+ "YCgCo",
};
char * const mp_csp_equalizer_names[MP_CSP_EQ_COUNT] = {
@@ -58,6 +60,7 @@ enum mp_csp avcol_spc_to_mp_csp(enum AVColorSpace colorspace)
case AVCOL_SPC_SMPTE170M: return MP_CSP_BT_601;
case AVCOL_SPC_SMPTE240M: return MP_CSP_SMPTE_240M;
case AVCOL_SPC_RGB: return MP_CSP_RGB;
+ case AVCOL_SPC_YCOCG: return MP_CSP_YCGCO;
default: return MP_CSP_AUTO;
}
}
@@ -78,6 +81,7 @@ enum AVColorSpace mp_csp_to_avcol_spc(enum mp_csp colorspace)
case MP_CSP_BT_601: return AVCOL_SPC_BT470BG;
case MP_CSP_SMPTE_240M: return AVCOL_SPC_SMPTE240M;
case MP_CSP_RGB: return AVCOL_SPC_RGB;
+ case MP_CSP_YCGCO: return AVCOL_SPC_YCOCG;
default: return AVCOL_SPC_UNSPECIFIED;
}
}
@@ -165,10 +169,39 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
int format = params->colorspace.format;
if (format <= MP_CSP_AUTO || format >= MP_CSP_COUNT)
format = MP_CSP_BT_601;
+ int levels_in = params->colorspace.levels_in;
+ if (levels_in <= MP_CSP_LEVELS_AUTO || levels_in >= MP_CSP_LEVELS_COUNT)
+ levels_in = MP_CSP_LEVELS_TV;
+
switch (format) {
case MP_CSP_BT_601: luma_coeffs(m, 0.299, 0.587, 0.114 ); break;
case MP_CSP_BT_709: luma_coeffs(m, 0.2126, 0.7152, 0.0722); break;
case MP_CSP_SMPTE_240M: luma_coeffs(m, 0.2122, 0.7013, 0.0865); break;
+ case MP_CSP_RGB: {
+ static const float ident[3][4] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+ memcpy(m, ident, sizeof(ident));
+ levels_in = -1;
+ break;
+ }
+ case MP_CSP_XYZ: {
+ static const float xyz_to_rgb[3][4] = {
+ {3.2404542, -1.5371385, -0.4985314},
+ {-0.9692660, 1.8760108, 0.0415560},
+ {0.0556434, -0.2040259, 1.0572252},
+ };
+ memcpy(m, xyz_to_rgb, sizeof(xyz_to_rgb));
+ levels_in = -1;
+ break;
+ }
+ case MP_CSP_YCGCO: {
+ static const float ycgco_to_rgb[3][4] = {
+ {1, -1, 1},
+ {1, 1, 0},
+ {1, -1, -1},
+ };
+ memcpy(m, ycgco_to_rgb, sizeof(ycgco_to_rgb));
+ break;
+ }
default:
abort();
};
@@ -183,9 +216,6 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
m[i][COL_V] = huesin * u + huecos * m[i][COL_V];
}
- int levels_in = params->colorspace.levels_in;
- if (levels_in <= MP_CSP_LEVELS_AUTO || levels_in >= MP_CSP_LEVELS_COUNT)
- levels_in = MP_CSP_LEVELS_TV;
assert(params->input_bits >= 8);
assert(params->texture_bits >= params->input_bits);
double s = (1 << params->input_bits-8) / ((1<<params->texture_bits)-1.);
@@ -193,10 +223,12 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
struct yuvlevels { double ymin, ymax, cmin, cmid; }
yuvlim = { 16*s, 235*s, 16*s, 128*s },
yuvfull = { 0*s, 255*s, 1*s, 128*s }, // '1' for symmetry around 128
+ anyfull = { 0*s, 255*s, -255*s/2, 0 },
yuvlev;
switch (levels_in) {
case MP_CSP_LEVELS_TV: yuvlev = yuvlim; break;
case MP_CSP_LEVELS_PC: yuvlev = yuvfull; break;
+ case -1: yuvlev = anyfull; break;
default:
abort();
}
diff --git a/video/csputils.h b/video/csputils.h
index d66bb86fa3..d11e85e38b 100644
--- a/video/csputils.h
+++ b/video/csputils.h
@@ -40,6 +40,8 @@ enum mp_csp {
MP_CSP_BT_709,
MP_CSP_SMPTE_240M,
MP_CSP_RGB,
+ MP_CSP_XYZ,
+ MP_CSP_YCGCO,
MP_CSP_COUNT
};
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index dfca042ba0..c3e9ce5860 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -59,7 +59,7 @@
#include "core/m_option.h"
-static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec);
+static void init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec);
static void uninit_avctx(sh_video_t *sh);
static void setup_refcounting_hw(struct AVCodecContext *s);
static void draw_slice_hwdec(struct AVCodecContext *s, const AVFrame *src,
@@ -101,7 +101,7 @@ enum hwdec_type {
struct hwdec {
enum hwdec_type api;
- char *codec, *hw_codec;
+ const char *codec, *hw_codec;
};
static const struct hwdec hwdec[] = {
@@ -135,6 +135,18 @@ static struct hwdec *find_hwcodec(enum hwdec_type api, const char *codec)
return NULL;
}
+static bool hwdec_codec_allowed(sh_video_t *sh, struct hwdec *hwdec)
+{
+ bstr s = bstr0(sh->opts->hwdec_codecs);
+ while (s.len) {
+ bstr item;
+ bstr_split_tok(s, ",", &item, &s);
+ if (bstr_equals0(item, "all") || bstr_equals0(item, hwdec->codec))
+ return true;
+ }
+ return false;
+}
+
static enum AVDiscard str2AVDiscard(char *str)
{
if (!str) return AVDISCARD_DEFAULT;
@@ -155,28 +167,31 @@ static int init(sh_video_t *sh, const char *decoder)
ctx->non_dr1_pool = talloc_steal(ctx, mp_image_pool_new(16));
struct hwdec *hwdec = find_hwcodec(sh->opts->hwdec_api, decoder);
- if (hwdec) {
+ struct hwdec *use_hwdec = NULL;
+ if (hwdec && hwdec_codec_allowed(sh, hwdec)) {
AVCodec *lavc_hwcodec = avcodec_find_decoder_by_name(hwdec->hw_codec);
if (lavc_hwcodec) {
ctx->software_fallback_decoder = talloc_strdup(ctx, decoder);
decoder = lavc_hwcodec->name;
+ use_hwdec = hwdec;
} else {
mp_tmsg(MSGT_DECVIDEO, MSGL_WARN, "Decoder '%s' not found in "
"libavcodec, using software decoding.\n", hwdec->hw_codec);
- hwdec = NULL;
}
}
- if (!init_avctx(sh, decoder, hwdec)) {
+ init_avctx(sh, decoder, use_hwdec);
+ if (!ctx->avctx) {
if (ctx->software_fallback_decoder) {
mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Error initializing hardware "
"decoding, falling back to software decoding.\n");
decoder = ctx->software_fallback_decoder;
ctx->software_fallback_decoder = NULL;
- if (!init_avctx(sh, decoder, NULL)) {
- uninit(sh);
- return 0;
- }
+ init_avctx(sh, decoder, NULL);
+ }
+ if (!ctx->avctx) {
+ uninit(sh);
+ return 0;
}
}
return 1;
@@ -240,12 +255,14 @@ static void set_from_bih(AVCodecContext *avctx, uint32_t format,
avctx->coded_height = bih->biHeight;
}
-static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec)
+static void init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec)
{
vd_ffmpeg_ctx *ctx = sh->context;
struct lavc_param *lavc_param = &sh->opts->lavc_param;
bool mp_rawvideo = false;
+ assert(!ctx->avctx);
+
if (strcmp(decoder, "mp-rawvideo") == 0) {
mp_rawvideo = true;
decoder = "rawvideo";
@@ -253,7 +270,7 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec)
AVCodec *lavc_codec = avcodec_find_decoder_by_name(decoder);
if (!lavc_codec)
- return 0;
+ return;
ctx->do_dr1 = ctx->do_hw_dr1 = 0;
ctx->pix_fmt = PIX_FMT_NONE;
@@ -268,6 +285,16 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec)
avctx->thread_count = lavc_param->threads;
+ // Hack to allow explicitly selecting vdpau hw decoders
+ if (!hwdec && (lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)) {
+ ctx->hwdec = talloc(ctx, struct hwdec);
+ *ctx->hwdec = (struct hwdec) {
+ .api = HWDEC_VDPAU,
+ .codec = sh->gsh->codec,
+ .hw_codec = decoder,
+ };
+ }
+
if (ctx->hwdec && ctx->hwdec->api == HWDEC_VDPAU) {
assert(lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU);
ctx->do_hw_dr1 = true;
@@ -325,8 +352,8 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec)
mp_msg(MSGT_DECVIDEO, MSGL_ERR,
"Your options /%s/ look like gibberish to me pal\n",
lavc_param->avopt);
- uninit(sh);
- return 0;
+ uninit_avctx(sh);
+ return;
}
}
@@ -356,9 +383,8 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec)
if (avcodec_open2(avctx, lavc_codec, NULL) < 0) {
mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Could not open codec.\n");
uninit_avctx(sh);
- return 0;
+ return;
}
- return 1;
}
static void uninit_avctx(sh_video_t *sh)
@@ -374,7 +400,7 @@ static void uninit_avctx(sh_video_t *sh)
av_freep(&avctx->slice_offset);
}
- av_freep(&avctx);
+ av_freep(&ctx->avctx);
avcodec_free_frame(&ctx->pic);
#if !HAVE_AVUTIL_REFCOUNTING
@@ -711,7 +737,8 @@ static struct mp_image *decode_with_fallback(struct sh_video *sh,
"decoding, falling back to software decoding.\n");
const char *decoder = ctx->software_fallback_decoder;
ctx->software_fallback_decoder = NULL;
- if (init_avctx(sh, decoder, NULL)) {
+ init_avctx(sh, decoder, NULL);
+ if (ctx->avctx) {
mpi = NULL;
decode(sh, packet, flags, reordered_pts, &mpi);
return mpi;
diff --git a/video/filter/vf.c b/video/filter/vf.c
index aa1de0848b..257d65e58b 100644
--- a/video/filter/vf.c
+++ b/video/filter/vf.c
@@ -69,6 +69,7 @@ extern const vf_info_t vf_info_sub;
extern const vf_info_t vf_info_yadif;
extern const vf_info_t vf_info_stereo3d;
extern const vf_info_t vf_info_dlopen;
+extern const vf_info_t vf_info_lavfi;
// list of available filters:
static const vf_info_t *const filter_list[] = {
@@ -85,6 +86,9 @@ static const vf_info_t *const filter_list[] = {
#ifdef CONFIG_LIBPOSTPROC
&vf_info_pp,
#endif
+#ifdef CONFIG_VF_LAVFI
+ &vf_info_lavfi,
+#endif
&vf_info_screenshot,
diff --git a/video/filter/vf_hqdn3d.c b/video/filter/vf_hqdn3d.c
index 4f49f12715..c5d99b2ace 100644
--- a/video/filter/vf_hqdn3d.c
+++ b/video/filter/vf_hqdn3d.c
@@ -62,7 +62,7 @@ static int config(struct vf_instance *vf,
unsigned int flags, unsigned int outfmt){
uninit(vf);
- vf->priv->Line = malloc(width*sizeof(int));
+ vf->priv->Line = malloc(width*sizeof(unsigned int));
return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
}
diff --git a/video/filter/vf_lavfi.c b/video/filter/vf_lavfi.c
new file mode 100644
index 0000000000..0b01e9b425
--- /dev/null
+++ b/video/filter/vf_lavfi.c
@@ -0,0 +1,348 @@
+/*
+ * This file is part of mpv.
+ *
+ * Filter graph creation code taken from Libav avplay.c (LGPL 2.1 or later)
+ *
+ * mpv is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include <libavutil/avstring.h>
+#include <libavutil/mem.h>
+#include <libavutil/mathematics.h>
+#include <libavutil/rational.h>
+#include <libavutil/pixdesc.h>
+#include <libavutil/time.h>
+#include <libswscale/swscale.h>
+#include <libavfilter/avfilter.h>
+#include <libavfilter/avfiltergraph.h>
+#include <libavfilter/buffersink.h>
+#include <libavfilter/buffersrc.h>
+
+#include "core/mp_msg.h"
+#include "core/m_option.h"
+#include "core/m_struct.h"
+
+#include "video/img_format.h"
+#include "video/mp_image.h"
+#include "video/sws_utils.h"
+#include "video/fmt-conversion.h"
+#include "vf.h"
+
+#define IS_LIBAV_FORK (LIBAVFILTER_VERSION_MICRO < 100)
+
+// FFmpeg and Libav have slightly different APIs, just enough to cause us
+// unnecessary pain. <Expletive deleted.>
+#if IS_LIBAV_FORK
+#define graph_parse(graph, filters, inputs, outputs, log_ctx) \
+ avfilter_graph_parse(graph, filters, inputs, outputs, log_ctx)
+#else
+#define graph_parse(graph, filters, inputs, outputs, log_ctx) \
+ avfilter_graph_parse(graph, filters, &(inputs), &(outputs), log_ctx)
+#endif
+
+// ":" is deprecated, but "|" doesn't work in earlier versions.
+#if (IS_LIBAV_FORK && LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(3, 7, 0)) || \
+ (!IS_LIBAV_FORK && LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(3, 50, 100))
+#define FMTSEP "|"
+#else
+#define FMTSEP ":"
+#endif
+
+struct vf_priv_s {
+ AVFilterGraph *graph;
+ AVFilterContext *in;
+ AVFilterContext *out;
+
+ AVRational timebase_in;
+ AVRational timebase_out;
+ AVRational par_in;
+
+ // options
+ char *cfg_graph;
+ int64_t cfg_sws_flags;
+};
+
+static const struct vf_priv_s vf_priv_dflt = {
+ .cfg_sws_flags = SWS_BICUBIC,
+};
+
+static void destroy_graph(struct vf_instance *vf)
+{
+ struct vf_priv_s *p = vf->priv;
+ avfilter_graph_free(&p->graph);
+ p->in = p->out = NULL;
+}
+
+static AVRational par_from_sar_dar(int width, int height,
+ int d_width, int d_height)
+{
+ return av_div_q((AVRational){d_width, d_height},
+ (AVRational){width, height});
+}
+
+static void dar_from_sar_par(int width, int height, AVRational par,
+ int *out_dw, int *out_dh)
+{
+ *out_dw = width;
+ *out_dh = height;
+ if (par.num != 0 && par.den != 0) {
+ double d = av_q2d(par);
+ if (d > 1.0) {
+ *out_dw *= d;
+ } else {
+ *out_dh /= d;
+ }
+ }
+}
+
+static bool recreate_graph(struct vf_instance *vf, int width, int height,
+ int d_width, int d_height, unsigned int fmt)
+{
+ void *tmp = talloc_new(NULL);
+ struct vf_priv_s *p = vf->priv;
+ AVFilterContext *in = NULL, *out = NULL, *f_format = NULL;
+
+ if (bstr0(p->cfg_graph).len == 0) {
+ mp_msg(MSGT_VFILTER, MSGL_FATAL, "lavfi: no filter graph set\n");
+ return false;
+ }
+
+ destroy_graph(vf);
+ mp_msg(MSGT_VFILTER, MSGL_V, "lavfi: create graph: '%s'\n", p->cfg_graph);
+
+ AVFilterGraph *graph = avfilter_graph_alloc();
+ if (!graph)
+ goto error;
+
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ AVFilterInOut *inputs = avfilter_inout_alloc();
+ 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] ? FMTSEP : "";
+ 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 par = par_from_sar_dar(width, height, d_width, d_height);
+ AVRational timebase = AV_TIME_BASE_Q;
+
+ char *src_args = talloc_asprintf(tmp, "%d:%d:%d:%d:%d:%d:%d",
+ width, height, imgfmt2pixfmt(fmt),
+ timebase.num, timebase.den,
+ par.num, par.den);
+
+ if (avfilter_graph_create_filter(&in, avfilter_get_by_name("buffer"),
+ "src", src_args, NULL, graph) < 0)
+ goto error;
+
+ if (avfilter_graph_create_filter(&out, avfilter_get_by_name("buffersink"),
+ "out", NULL, NULL, graph) < 0)
+ goto error;
+
+ if (avfilter_graph_create_filter(&f_format, avfilter_get_by_name("format"),
+ "format", fmtstr, NULL, graph) < 0)
+ goto error;
+
+ if (avfilter_link(f_format, 0, out, 0) < 0)
+ goto error;
+
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = in;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = f_format;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if (graph_parse(graph, p->cfg_graph, inputs, outputs, NULL) < 0)
+ goto error;
+
+ if (avfilter_graph_config(graph, NULL) < 0)
+ goto error;
+
+ p->in = in;
+ p->out = out;
+ p->graph = graph;
+
+ assert(out->nb_inputs == 1);
+ assert(in->nb_outputs == 1);
+
+ talloc_free(tmp);
+ return true;
+
+error:
+ mp_msg(MSGT_VFILTER, MSGL_FATAL, "Can't configure libavfilter graph.\n");
+ avfilter_graph_free(&graph);
+ talloc_free(tmp);
+ return false;
+}
+
+static int config(struct vf_instance *vf, int width, int height,
+ int d_width, int d_height, unsigned int flags,
+ unsigned int fmt)
+{
+ struct vf_priv_s *p = vf->priv;
+
+ if (!recreate_graph(vf, width, height, d_width, d_height, fmt))
+ return 0;
+
+ AVFilterLink *l_out = p->out->inputs[0];
+ AVFilterLink *l_in = p->in->outputs[0];
+
+ p->timebase_in = l_in->time_base;
+ p->timebase_out = l_out->time_base;
+
+ p->par_in = l_in->sample_aspect_ratio;
+
+ int dw, dh;
+ dar_from_sar_par(l_out->w, l_out->h, l_out->sample_aspect_ratio, &dw, &dh);
+
+ return vf_next_config(vf, l_out->w, l_out->h, dw, dh, flags,
+ pixfmt2imgfmt(l_out->format));
+
+}
+
+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) ? VFCAP_CSP_SUPPORTED : 0;
+}
+
+static AVFrame *mp_to_av(struct vf_instance *vf, struct mp_image *img)
+{
+ struct vf_priv_s *p = vf->priv;
+ uint64_t pts = img->pts == MP_NOPTS_VALUE ?
+ AV_NOPTS_VALUE : img->pts * av_q2d(av_inv_q(p->timebase_in));
+ AVFrame *frame = mp_image_to_av_frame_and_unref(img);
+ frame->pts = pts;
+ frame->sample_aspect_ratio = p->par_in;
+ return frame;
+}
+
+static struct mp_image *av_to_mp(struct vf_instance *vf, AVFrame *av_frame)
+{
+ struct vf_priv_s *p = vf->priv;
+ struct mp_image *img = mp_image_from_av_frame(av_frame);
+ img->pts = av_frame->pts == AV_NOPTS_VALUE ?
+ MP_NOPTS_VALUE : av_frame->pts * av_q2d(p->timebase_out);
+ av_frame_free(&av_frame);
+ return img;
+}
+
+static int filter_ext(struct vf_instance *vf, struct mp_image *mpi)
+{
+ struct vf_priv_s *p = vf->priv;
+
+ if (!p->graph)
+ return -1;
+
+ AVFrame *frame = mp_to_av(vf, mpi);
+ if (av_buffersrc_add_frame(p->in, frame) < 0) {
+ av_frame_free(&frame);
+ return -1;
+ }
+ av_frame_free(&frame);
+
+ for (;;) {
+ AVFrame *frame = av_frame_alloc();
+ if (av_buffersink_get_frame(p->out, frame) < 0) {
+ // Not an error situation - no more output buffers in queue.
+ av_frame_free(&frame);
+ break;
+ }
+ vf_add_output_frame(vf, av_to_mp(vf, frame));
+ }
+
+ return 0;
+}
+
+static int control(vf_instance_t *vf, int request, void *data)
+{
+ struct vf_priv_s *p = vf->priv;
+ switch (request) {
+ case VFCTRL_SEEK_RESET:
+ if (p->graph) {
+ struct vf_format *f = &vf->fmt_in;
+ recreate_graph(vf, f->w, f->h, f->dw, f->dh, f->fmt);
+ }
+ break;
+ }
+ return vf_next_control(vf, request, data);
+}
+
+static void uninit(struct vf_instance *vf)
+{
+ if (!vf->priv)
+ return;
+ destroy_graph(vf);
+ free(vf->priv);
+}
+
+static int vf_open(vf_instance_t *vf, char *args)
+{
+ vf->config = config;
+ vf->filter_ext = filter_ext;
+ vf->query_format = query_format;
+ vf->control = control;
+ vf->uninit = uninit;
+ return 1;
+}
+
+#undef ST_OFF
+#define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f)
+static const m_option_t vf_opts_fields[] = {
+ {"graph", ST_OFF(cfg_graph), CONF_TYPE_STRING, CONF_MIN, 1},
+ {"sws_flags", ST_OFF(cfg_sws_flags), CONF_TYPE_INT64},
+ {0}
+};
+
+static const m_struct_t vf_opts = {
+ "lavfi",
+ sizeof(struct vf_priv_s),
+ &vf_priv_dflt,
+ vf_opts_fields
+};
+
+const vf_info_t vf_info_lavfi = {
+ "libavfilter bridge",
+ "lavfi",
+ "",
+ "",
+ vf_open,
+ &vf_opts
+};
diff --git a/video/filter/vf_rotate.c b/video/filter/vf_rotate.c
index 9cdbafd94d..09b3d09add 100644
--- a/video/filter/vf_rotate.c
+++ b/video/filter/vf_rotate.c
@@ -52,15 +52,14 @@ static void rotate(unsigned char* dst,unsigned char* src,int dststride,int srcst
case 2:
for(x=0;x<w;x++) *((short*)(dst+x*2))=*((short*)(src+y*2+x*srcstride));
break;
- case 3:
- for(x=0;x<w;x++){
- dst[x*3+0]=src[0+y*3+x*srcstride];
- dst[x*3+1]=src[1+y*3+x*srcstride];
- dst[x*3+2]=src[2+y*3+x*srcstride];
- }
- break;
case 4:
for(x=0;x<w;x++) *((int*)(dst+x*4))=*((int*)(src+y*4+x*srcstride));
+ default:
+ for(x=0;x<w;x++){
+ for (int b=0;b<bpp;b++)
+ dst[x*bpp+b]=src[b+y*bpp+x*srcstride];
+ }
+ break;
}
dst+=dststride;
}
diff --git a/video/filter/vf_scale.c b/video/filter/vf_scale.c
index 08fb0c7ae1..92b9e71d08 100644
--- a/video/filter/vf_scale.c
+++ b/video/filter/vf_scale.c
@@ -155,6 +155,7 @@ static int preferred_conversions[][2] = {
{IMGFMT_GBRP, IMGFMT_BGR32},
{IMGFMT_GBRP, IMGFMT_RGB32},
{IMGFMT_PAL8, IMGFMT_BGR32},
+ {IMGFMT_XYZ12, IMGFMT_RGB48},
{0, 0}
};
diff --git a/video/filter/vf_yadif.c b/video/filter/vf_yadif.c
index 39e45e7e19..017e7c515c 100644
--- a/video/filter/vf_yadif.c
+++ b/video/filter/vf_yadif.c
@@ -393,7 +393,7 @@ static int config(struct vf_instance *vf,
vf->priv->stride[i]= w;
for(j=0; j<3; j++)
- vf->priv->ref[j][i]= (char *)malloc(w*h*sizeof(uint8_t))+3*w;
+ vf->priv->ref[j][i]= (char *)malloc(w*h)+3*w;
}
return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
@@ -459,6 +459,7 @@ static int continue_buffered_image(struct vf_instance *vf, struct mp_image *mpi)
filter(vf->priv, dmpi->planes, dmpi->stride, mpi->w, mpi->h, i ^ tff ^ 1, tff);
if (i < (vf->priv->mode & 1))
ret = 1; // more images to come
+ dmpi->pts = pts;
vf_add_output_frame(vf, dmpi);
break;
}
diff --git a/video/fmt-conversion.c b/video/fmt-conversion.c
index 819448772e..153b1badf3 100644
--- a/video/fmt-conversion.c
+++ b/video/fmt-conversion.c
@@ -107,7 +107,7 @@ static const struct {
{IMGFMT_420AP, PIX_FMT_YUVA420P},
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 10, 0)
+#if LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 10, 0)
{IMGFMT_422AP, PIX_FMT_YUVA422P},
{IMGFMT_444AP, PIX_FMT_YUVA444P},
@@ -133,6 +133,12 @@ static const struct {
{IMGFMT_444AP16_LE, AV_PIX_FMT_YUVA444P16LE},
#endif
+#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 25, 0)
+ // Libav added this already at 52.10.0
+ {IMGFMT_XYZ12_LE, AV_PIX_FMT_XYZ12LE},
+ {IMGFMT_XYZ12_BE, AV_PIX_FMT_XYZ12BE},
+#endif
+
// ffmpeg only
#if LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT > AV_VERSION_INT(52, 0, 0)
{IMGFMT_420P12_LE, PIX_FMT_YUV420P12LE},
diff --git a/video/img_format.c b/video/img_format.c
index dfb82d2081..c0bbce90ee 100644
--- a/video/img_format.c
+++ b/video/img_format.c
@@ -111,6 +111,7 @@ struct mp_imgfmt_entry mp_imgfmt_list[] = {
FMT_ENDIAN("gbrp12", IMGFMT_GBRP12)
FMT_ENDIAN("gbrp14", IMGFMT_GBRP14)
FMT_ENDIAN("gbrp16", IMGFMT_GBRP16)
+ FMT_ENDIAN("xyz12", IMGFMT_XYZ12)
FMT("vdpau_mpeg1", IMGFMT_VDPAU_MPEG1)
FMT("vdpau_mpeg2", IMGFMT_VDPAU_MPEG2)
FMT("vdpau_h264", IMGFMT_VDPAU_H264)
@@ -184,7 +185,7 @@ static struct mp_imgfmt_desc get_avutil_fmt(enum PixelFormat fmt)
// Packed RGB formats are the only formats that have less than 8 bits per
// component, and still require endian dependent access.
if (pd->comp[0].depth_minus1 + 1 <= 8 &