diff options
Diffstat (limited to 'video')
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 & |