diff options
Diffstat (limited to 'video')
42 files changed, 4238 insertions, 3417 deletions
diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c index 9888881e26..465791a1ed 100644 --- a/video/decode/dec_video.c +++ b/video/decode/dec_video.c @@ -275,7 +275,6 @@ int init_best_video_codec(sh_video_t *sh_video, char* video_decoders) } void *decode_video(sh_video_t *sh_video, struct demux_packet *packet, - unsigned char *start, int in_size, int drop_frame, double pts) { mp_image_t *mpi = NULL; @@ -311,8 +310,7 @@ void *decode_video(sh_video_t *sh_video, struct demux_packet *packet, } } - mpi = sh_video->vd_driver->decode(sh_video, packet, start, in_size, - drop_frame, &pts); + mpi = sh_video->vd_driver->decode(sh_video, packet, drop_frame, &pts); //------------------------ frame decoded. -------------------- diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h index b6b85e86f6..94bd2bce3a 100644 --- a/video/decode/dec_video.h +++ b/video/decode/dec_video.h @@ -31,8 +31,7 @@ void uninit_video(sh_video_t *sh_video); struct demux_packet; void *decode_video(sh_video_t *sh_video, struct demux_packet *packet, - unsigned char *start, int in_size, int drop_frame, - double pts); + int drop_frame, double pts); int get_video_quality_max(sh_video_t *sh_video); diff --git a/video/decode/lavc.h b/video/decode/lavc.h index d23c3e85f6..41701be1d6 100644 --- a/video/decode/lavc.h +++ b/video/decode/lavc.h @@ -5,6 +5,8 @@ #include <libavcodec/avcodec.h> +#include "config.h" + #include "demux/stheader.h" #include "video/mp_image.h" @@ -13,25 +15,25 @@ typedef struct ffmpeg_ctx { AVFrame *pic; struct hwdec *hwdec; enum PixelFormat pix_fmt; - int do_hw_dr1, do_dr1; + int do_hw_dr1; int vo_initialized; int best_csp; AVRational last_sample_aspect_ratio; enum AVDiscard skip_frame; const char *software_fallback_decoder; + + bool do_dr1; struct FramePool *dr1_buffer_pool; struct mp_image_pool *non_dr1_pool; } vd_ffmpeg_ctx; +// lavc_dr1.c int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame); void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame); - struct FrameBuffer; - void mp_buffer_ref(struct FrameBuffer *buffer); void mp_buffer_unref(struct FrameBuffer *buffer); bool mp_buffer_is_unique(struct FrameBuffer *buffer); - void mp_buffer_pool_free(struct FramePool **pool); #endif diff --git a/video/decode/vd.h b/video/decode/vd.h index c4c2b7f465..88ce4b2f59 100644 --- a/video/decode/vd.h +++ b/video/decode/vd.h @@ -34,8 +34,7 @@ typedef struct vd_functions void (*uninit)(sh_video_t *sh); int (*control)(sh_video_t *sh, int cmd, void *arg); struct mp_image *(*decode)(struct sh_video *sh, struct demux_packet *pkt, - void *data, int len, int flags, - double *reordered_pts); + int flags, double *reordered_pts); } vd_functions_t; // NULL terminated array of all drivers diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 4922f57387..8a989feea7 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -59,10 +59,9 @@ #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 int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic); -static void release_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic); +static void setup_refcounting_hw(struct AVCodecContext *s); static void draw_slice_hwdec(struct AVCodecContext *s, const AVFrame *src, int offset[4], int y, int type, int height); @@ -168,16 +167,18 @@ static int init(sh_video_t *sh, const char *decoder) } } - if (!init_avctx(sh, decoder, hwdec)) { + init_avctx(sh, decoder, 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; @@ -241,12 +242,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"; @@ -254,7 +257,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; @@ -274,17 +277,22 @@ static int init_avctx(sh_video_t *sh, const char *decoder, struct hwdec *hwdec) ctx->do_hw_dr1 = true; avctx->thread_count = 1; avctx->get_format = get_format_hwdec; - avctx->get_buffer = get_buffer_hwdec; - avctx->release_buffer = release_buffer_hwdec; + setup_refcounting_hw(avctx); if (ctx->hwdec->api == HWDEC_VDPAU) { avctx->draw_horiz_band = draw_slice_hwdec; avctx->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; } - } else if (lavc_codec->capabilities & CODEC_CAP_DR1) { - ctx->do_dr1 = true; - avctx->get_buffer = mp_codec_get_buffer; - avctx->release_buffer = mp_codec_release_buffer; + } else { +#if HAVE_AVUTIL_REFCOUNTING + avctx->refcounted_frames = 1; +#else + if (lavc_codec->capabilities & CODEC_CAP_DR1) { + ctx->do_dr1 = true; + avctx->get_buffer = mp_codec_get_buffer; + avctx->release_buffer = mp_codec_release_buffer; + } +#endif } if (avctx->thread_count == 0) { @@ -321,8 +329,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; } } @@ -352,9 +360,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) @@ -370,10 +377,12 @@ 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 mp_buffer_pool_free(&ctx->dr1_buffer_pool); +#endif } static void uninit(sh_video_t *sh) @@ -466,9 +475,8 @@ static void draw_slice_hwdec(struct AVCodecContext *s, vf->control(vf, VFCTRL_HWDEC_DECODER_RENDER, state_ptr); } -static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) +static struct mp_image *get_surface_hwdec(struct sh_video *sh, AVFrame *pic) { - sh_video_t *sh = avctx->opaque; vd_ffmpeg_ctx *ctx = sh->context; /* Decoders using ffmpeg's hwaccel architecture (everything except vdpau) @@ -484,10 +492,10 @@ static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) */ int imgfmt = pixfmt2imgfmt(pic->format); if (!IMGFMT_IS_HWACCEL(imgfmt)) - return -1; + return NULL; if (init_vo(sh, pic) < 0) - return -1; + return NULL; assert(IMGFMT_IS_HWACCEL(ctx->best_csp)); @@ -495,11 +503,52 @@ static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) struct vf_instance *vf = sh->vfilter; vf->control(vf, VFCTRL_HWDEC_ALLOC_SURFACE, &mpi); + + if (mpi) { + for (int i = 0; i < 4; i++) + pic->data[i] = mpi->planes[i]; + } + + return mpi; +} + +#if HAVE_AVUTIL_REFCOUNTING + +static void free_mpi(void *opaque, uint8_t *data) +{ + struct mp_image *mpi = opaque; + talloc_free(mpi); +} + +static int get_buffer2_hwdec(AVCodecContext *avctx, AVFrame *pic, int flags) +{ + sh_video_t *sh = avctx->opaque; + + struct mp_image *mpi = get_surface_hwdec(sh, pic); + if (!mpi) + return -1; + + pic->buf[0] = av_buffer_create(NULL, 0, free_mpi, mpi, 0); + + return 0; +} + +static void setup_refcounting_hw(AVCodecContext *avctx) +{ + avctx->get_buffer2 = get_buffer2_hwdec; + avctx->refcounted_frames = 1; +} + +#else /* HAVE_AVUTIL_REFCOUNTING */ + +static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) +{ + sh_video_t *sh = avctx->opaque; + + struct mp_image *mpi = get_surface_hwdec(sh, pic); if (!mpi) return -1; - for (int i = 0; i < 4; i++) - pic->data[i] = mpi->planes[i]; pic->opaque = mpi; pic->type = FF_BUFFER_TYPE_USER; @@ -525,6 +574,29 @@ static void release_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic) pic->data[i] = NULL; } +static void setup_refcounting_hw(AVCodecContext *avctx) +{ + avctx->get_buffer = get_buffer_hwdec; + avctx->release_buffer = release_buffer_hwdec; +} + +#endif /* HAVE_AVUTIL_REFCOUNTING */ + +#if HAVE_AVUTIL_REFCOUNTING + +static struct mp_image *image_from_decoder(struct sh_video *sh) +{ + vd_ffmpeg_ctx *ctx = sh->context; + AVFrame *pic = ctx->pic; + + struct mp_image *img = mp_image_from_av_frame(pic); + av_frame_unref(pic); + + return img; +} + +#else /* HAVE_AVUTIL_REFCOUNTING */ + static void fb_ref(void *b) { mp_buffer_ref(b); @@ -540,9 +612,35 @@ static bool fb_is_unique(void *b) return mp_buffer_is_unique(b); } -static int decode(struct sh_video *sh, struct demux_packet *packet, void *data, - int len, int flags, double *reordered_pts, - struct mp_image **out_image) +static struct mp_image *image_from_decoder(struct sh_video *sh) +{ + vd_ffmpeg_ctx *ctx = sh->context; + AVFrame *pic = ctx->pic; + + struct mp_image new = {0}; + mp_image_copy_fields_from_av_frame(&new, pic); + + struct mp_image *mpi; + if (ctx->do_hw_dr1 && pic->opaque) { + mpi = pic->opaque; // reordered frame + assert(mpi); + mpi = mp_image_new_ref(mpi); + mp_image_copy_attributes(mpi, &new); + } else if (ctx->do_dr1 && pic->opaque) { + struct FrameBuffer *fb = pic->opaque; + mp_buffer_ref(fb); // initial reference for mpi + mpi = mp_image_new_external_ref(&new, fb, fb_ref, fb_unref, + fb_is_unique, NULL); + } else { + mpi = mp_image_pool_new_copy(ctx->non_dr1_pool, &new); + } + return mpi; +} + +#endif /* HAVE_AVUTIL_REFCOUNTING */ + +static int decode(struct sh_video *sh, struct demux_packet *packet, + int flags, double *reordered_pts, struct mp_image **out_image) { int got_picture = 0; int ret; @@ -559,8 +657,8 @@ static int decode(struct sh_video *sh, struct demux_packet *packet, void *data, avctx->skip_frame = ctx->skip_frame; av_init_packet(&pkt); - pkt.data = data; - pkt.size = len; + pkt.data = packet ? packet->buffer : NULL; + pkt.size = packet ? packet->len : 0; /* Some codecs (ZeroCodec, some cases of PNG) may want keyframe info * from demuxer. */ if (packet && packet->keyframe) @@ -585,63 +683,26 @@ static int decode(struct sh_video *sh, struct demux_packet *packet, void *data, if (init_vo(sh, pic) < 0) return -1; - struct mp_image *mpi = NULL; - if (ctx->do_hw_dr1 && pic->opaque) { - mpi = pic->opaque; // reordered frame - assert(mpi); - mpi = mp_image_new_ref(mpi); - } - - if (!mpi) { - struct mp_image new = {0}; - mp_image_set_size(&new, pic->width, pic->height); - mp_image_setfmt(&new, ctx->best_csp); - for (int i = 0; i < 4; i++) { - new.planes[i] = pic->data[i]; - new.stride[i] = pic->linesize[i]; - } - if (ctx->do_dr1 && pic->opaque) { - struct FrameBuffer *fb = pic->opaque; - mp_buffer_ref(fb); // initial reference for mpi - mpi = mp_image_new_external_ref(&new, fb, fb_ref, fb_unref, - fb_is_unique); - } else { - mpi = mp_image_pool_get(ctx->non_dr1_pool, new.imgfmt, - new.w, new.h); - mp_image_copy(mpi, &new); - } - } - + struct mp_image *mpi = image_from_decoder(sh); assert(mpi->planes[0]); mpi->colorspace = sh->colorspace; mpi->levels = sh->color_range; - mpi->qscale = pic->qscale_table; - mpi->qstride = pic->qstride; - mpi->pict_type = pic->pict_type; - mpi->qscale_type = pic->qscale_type; - mpi->fields = MP_IMGFIELD_ORDERED; - if (pic->interlaced_frame) - mpi->fields |= MP_IMGFIELD_INTERLACED; - if (pic->top_field_first) - mpi->fields |= MP_IMGFIELD_TOP_FIRST; - if (pic->repeat_pict == 1) - mpi->fields |= MP_IMGFIELD_REPEAT_FIRST; *out_image = mpi; return 1; } static struct mp_image *decode_with_fallback(struct sh_video *sh, - struct demux_packet *packet, void *data, - int len, int flags, double *reordered_pts) + struct demux_packet *packet, + int flags, double *reordered_pts) { vd_ffmpeg_ctx *ctx = sh->context; if (!ctx->avctx) return NULL; struct mp_image *mpi = NULL; - int res = decode(sh, packet, data, len, flags, reordered_pts, &mpi); + int res = decode(sh, packet, flags, reordered_pts, &mpi); if (res >= 0) return mpi; @@ -653,9 +714,10 @@ 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, data, len, flags, reordered_pts, &mpi); + 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_divtc.c b/video/filter/vf_divtc.c index 5b57e5a4cb..b4718b355f 100644 --- a/video/filter/vf_divtc.c +++ b/video/filter/vf_divtc.c @@ -202,8 +202,9 @@ static int imgop(int(*planeop)(unsigned char *, unsigned char *, int sum = 0; for (int p = 0; p < dst->num_planes; p++) { sum += planeop(dst->planes[p], src ? src->planes[p] : NULL, - dst->w * (dst->fmt.bpp[p] / 8), dst->plane_h[p], - dst->stride[p], src ? src->stride[p] : 0, arg); + (dst->w * dst->fmt.bytes[p]) >> dst->fmt.xs[p], + dst->plane_h[p], dst->stride[p], + src ? src->stride[p] : 0, arg); } return sum; } 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; |