summaryrefslogtreecommitdiffstats
path: root/video/decode/vd_lavc.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/decode/vd_lavc.c')
-rw-r--r--video/decode/vd_lavc.c212
1 files changed, 137 insertions, 75 deletions
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;
}
}