mirror of https://github.com/mpv-player/mpv
vd_lavc: use refcounting
Note that if the codec doesn't support DR1, the image has to be copied. There is no other way to guarantee that the image will be valid after decoding the next image. The only important codec that doesn't support DR1 yet is rawvideo. It's likely that ffmpeg/Libav will fix this at some time. For now, this decoder uses an evil hack and puts pointers to the packet data into the returned frame. This means the image will actually get invalid as soon as the corresponding video packet is free'd, so copying the image is the only reasonable thing anyway.
This commit is contained in:
parent
65a0b5fdc6
commit
881f82dd33
|
@ -1,6 +1,8 @@
|
|||
#ifndef MPV_LAVC_H
|
||||
#define MPV_LAVC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
#include "demux/stheader.h"
|
||||
|
@ -11,11 +13,11 @@
|
|||
typedef struct ffmpeg_ctx {
|
||||
AVCodecContext *avctx;
|
||||
AVFrame *pic;
|
||||
struct mp_image export_mpi;
|
||||
struct mp_image *last_mpi;
|
||||
struct mp_image hwdec_mpi[MAX_NUM_MPI];
|
||||
struct hwdec *hwdec;
|
||||
enum PixelFormat pix_fmt;
|
||||
int do_dr1;
|
||||
int do_hw_dr1, do_dr1;
|
||||
int vo_initialized;
|
||||
int best_csp;
|
||||
int qp_stat[32];
|
||||
|
@ -35,6 +37,7 @@ 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);
|
||||
|
||||
|
|
|
@ -190,6 +190,11 @@ void mp_buffer_unref(struct FrameBuffer *buf)
|
|||
mp_buffer_pool_free(&pool);
|
||||
}
|
||||
|
||||
bool mp_buffer_is_unique(struct FrameBuffer *buf)
|
||||
{
|
||||
return buf->refcount == 1;
|
||||
}
|
||||
|
||||
void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame)
|
||||
{
|
||||
FrameBuffer *buf = frame->opaque;
|
||||
|
|
|
@ -306,7 +306,7 @@ static int init_avctx(sh_video_t *sh, AVCodec *lavc_codec, struct hwdec *hwdec)
|
|||
if (!sh->codecname)
|
||||
sh->codecname = lavc_codec->name;
|
||||
|
||||
ctx->do_dr1 = 0;
|
||||
ctx->do_dr1 = ctx->do_hw_dr1 = 0;
|
||||
ctx->pix_fmt = PIX_FMT_NONE;
|
||||
ctx->vo_initialized = 0;
|
||||
ctx->hwdec = hwdec;
|
||||
|
@ -320,7 +320,8 @@ static int init_avctx(sh_video_t *sh, AVCodec *lavc_codec, struct hwdec *hwdec)
|
|||
avctx->thread_count = lavc_param->threads;
|
||||
|
||||
if (ctx->hwdec && ctx->hwdec->api == HWDEC_VDPAU) {
|
||||
ctx->do_dr1 = true;
|
||||
assert(lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU);
|
||||
ctx->do_hw_dr1 = true;
|
||||
avctx->thread_count = 1;
|
||||
avctx->get_format = get_format_hwdec;
|
||||
avctx->get_buffer = get_buffer_hwdec;
|
||||
|
@ -330,7 +331,8 @@ static int init_avctx(sh_video_t *sh, AVCodec *lavc_codec, struct hwdec *hwdec)
|
|||
avctx->slice_flags =
|
||||
SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
|
||||
}
|
||||
} else {
|
||||
} 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;
|
||||
}
|
||||
|
@ -475,6 +477,8 @@ static void uninit_avctx(sh_video_t *sh)
|
|||
|
||||
av_freep(&avctx);
|
||||
avcodec_free_frame(&ctx->pic);
|
||||
|
||||
mp_image_unrefp(&ctx->last_mpi);
|
||||
mp_buffer_pool_free(&ctx->dr1_buffer_pool);
|
||||
}
|
||||
|
||||
|
@ -514,6 +518,7 @@ static int init_vo(sh_video_t *sh)
|
|||
width != sh->disp_w || height != sh->disp_h ||
|
||||
avctx->pix_fmt != ctx->pix_fmt || !ctx->vo_initialized)
|
||||
{
|
||||
mp_image_unrefp(&ctx->last_mpi);
|
||||
ctx->vo_initialized = 0;
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] aspect_ratio: %f\n", aspect);
|
||||
|
||||
|
@ -658,6 +663,21 @@ static av_unused void swap_palette(void *pal)
|
|||
p[i] = le2me_32(p[i]);
|
||||
}
|
||||
|
||||
static void fb_ref(void *b)
|
||||
{
|
||||
mp_buffer_ref(b);
|
||||
}
|
||||
|
||||
static void fb_unref(void *b)
|
||||
{
|
||||
mp_buffer_unref(b);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -706,21 +726,35 @@ static int decode(struct sh_video *sh, struct demux_packet *packet, void *data,
|
|||
return -1;
|
||||
|
||||
struct mp_image *mpi = NULL;
|
||||
if (ctx->do_dr1 && pic->opaque)
|
||||
mpi = (mp_image_t *)pic->opaque;
|
||||
if (ctx->do_hw_dr1 && pic->opaque)
|
||||
mpi = pic->opaque; // reordered frame
|
||||
|
||||
if (!mpi) {
|
||||
mpi = &ctx->export_mpi;
|
||||
*mpi = (struct mp_image) {0};
|
||||
mpi->type = MP_IMGTYPE_EXPORT;
|
||||
mpi->flags = MP_IMGFLAG_PRESERVE;
|
||||
mpi->w = mpi->width = avctx->width;
|
||||
mpi->h = mpi->height = avctx->height;
|
||||
mp_image_setfmt(mpi, ctx->best_csp);
|
||||
struct mp_image new = {0};
|
||||
new.type = MP_IMGTYPE_EXPORT;
|
||||
new.flags = MP_IMGFLAG_PRESERVE;
|
||||
new.w = new.width = avctx->width;
|
||||
new.h = new.height = avctx->height;
|
||||
mp_image_setfmt(&new, ctx->best_csp);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mpi->planes[i] = pic->data[i];
|
||||
mpi->stride[i] = pic->linesize[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_image_unrefp(&ctx->last_mpi);
|
||||
mp_buffer_ref(fb); // reference for last_mpi
|
||||
ctx->last_mpi = mp_image_new_external_ref(&new, fb, fb_ref,
|
||||
fb_unref, fb_is_unique);
|
||||
} else {
|
||||
if (!ctx->last_mpi)
|
||||
ctx->last_mpi = mp_image_alloc(ctx->best_csp, new.w, new.h);
|
||||
mp_image_make_writeable(&ctx->last_mpi);
|
||||
assert(ctx->last_mpi->w == new.w && ctx->last_mpi->h == new.h);
|
||||
assert(ctx->last_mpi->imgfmt == new.imgfmt);
|
||||
mp_image_copy(ctx->last_mpi, &new);
|
||||
}
|
||||
mpi = ctx->last_mpi;
|
||||
}
|
||||
|
||||
if (!mpi->planes[0])
|
||||
|
|
Loading…
Reference in New Issue