[vlc-commits] [Git][videolan/vlc][master] 5 commits: avcodec: va: change vlc_va_Get arguments
Jean-Baptiste Kempf (@jbk)
gitlab at videolan.org
Mon Jul 12 08:48:30 UTC 2021
Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC
Commits:
e3b5b5b0 by Thomas Guillem at 2021-07-12T09:52:31+02:00
avcodec: va: change vlc_va_Get arguments
Provide the AVCodecContext and the full AVFrame. It will be used by the
new vaapi va module.
- - - - -
03b9c4bc by Thomas Guillem at 2021-07-12T09:52:31+02:00
avcodec: video: remove unused data
frame->buf[0] must be valid but doesn't have to contain data since the
data will be accessed via frame->data[] directly.
Furthermore, all va modules are only setting frame->data[3], therefore,
frame->data[0] was always NULL.
- - - - -
fe63b86f by Thomas Guillem at 2021-07-12T09:52:31+02:00
avcodec: video: also store the pic reference in opaque_ref
The future vaapi va module will create AVFrame from hwframes_ctx with a
frame->buf[0] set internally by avcodec. If this is the case, don't
override it and use opaque_ref (an user field) to keep the reference on
the VLC picture_t.
- - - - -
906ffbaa by Thomas Guillem at 2021-07-12T09:52:31+02:00
avcodec: video: fix swfmt detection when using a hw_device_ctx
- - - - -
08cbeca2 by Thomas Guillem at 2021-07-12T09:52:31+02:00
avcodec: vaapi: adapt to the hw_device_ctx API
Contrary to all other hardware decoders, vaapi can't work with a
hwaccel_context anymore. It requires a hw_device_ctx or a hw_frames_ctx
to work.
This first implementation use a hw_device_ctx and let avcodec handle its
frames pool. It is also possible to handle hw_frames_ctx ourself to get
more controls.
Note: Most of the code could be reused by other va modules if we decide
to a hw_device_ctx.
Fixes #25707
- - - - -
7 changed files:
- modules/codec/Makefile.am
- modules/codec/avcodec/d3d11va.c
- modules/codec/avcodec/dxva2.c
- modules/codec/avcodec/va.h
- modules/codec/avcodec/vaapi.c
- modules/codec/avcodec/video.c
- modules/hw/vdpau/avcodec.c
Changes:
=====================================
modules/codec/Makefile.am
=====================================
@@ -387,7 +387,7 @@ libvaapi_plugin_la_SOURCES = \
codec/avcodec/va_surface.c codec/avcodec/va_surface.h
libvaapi_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
libvaapi_plugin_la_CFLAGS = $(AM_CFLAGS) $(AVCODEC_CFLAGS)
-libvaapi_plugin_la_LIBADD = $(LIBVA_LIBS)
+libvaapi_plugin_la_LIBADD = $(LIBVA_LIBS) $(AVCODEC_LIBS)
if HAVE_AVCODEC_VAAPI
codec_LTLIBRARIES += libvaapi_plugin.la
endif
=====================================
modules/codec/avcodec/d3d11va.c
=====================================
@@ -192,8 +192,10 @@ static picture_context_t* NewSurfacePicContext(vlc_va_t *va, vlc_va_surface_t *v
return &pic_ctx->ctx.s;
}
-static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
+static int Get(vlc_va_t *va, picture_t *pic, AVCodecContext *ctx, AVFrame *frame)
{
+ (void) ctx;
+
vlc_va_sys_t *sys = va->sys;
vlc_va_surface_t *va_surface = va_pool_Get(sys->va_pool);
if (unlikely(va_surface == NULL))
@@ -204,7 +206,7 @@ static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
va_surface_Release(va_surface);
return VLC_ENOMEM;
}
- data[3] = (uint8_t*)sys->hw_surface[va_surface_GetIndex(va_surface)];
+ frame->data[3] = (uint8_t*)sys->hw_surface[va_surface_GetIndex(va_surface)];
return VLC_SUCCESS;
}
=====================================
modules/codec/avcodec/dxva2.c
=====================================
@@ -191,8 +191,9 @@ static picture_context_t* NewSurfacePicContext(vlc_va_t *va, vlc_va_surface_t *v
return &pic_ctx->ctx.s;
}
-static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
+static int Get(vlc_va_t *va, picture_t *pic, AVCodecContext *ctx, AVFrame *frame)
{
+ (void) ctx;
vlc_va_sys_t *sys = va->sys;
/* Check the device */
@@ -215,7 +216,7 @@ static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
va_surface_Release(va_surface);
return VLC_ENOITEM;
}
- data[3] = (uint8_t*)DXVA2_PICCONTEXT_FROM_PICCTX(pic->context)->ctx.picsys.surface;
+ frame->data[3] = (uint8_t*)DXVA2_PICCONTEXT_FROM_PICCTX(pic->context)->ctx.picsys.surface;
return VLC_SUCCESS;
}
=====================================
modules/codec/avcodec/va.h
=====================================
@@ -31,7 +31,7 @@ typedef struct vlc_decoder_device vlc_decoder_device;
typedef struct vlc_video_context vlc_video_context;
struct vlc_va_operations {
- int (*get)(vlc_va_t *, picture_t *pic, uint8_t **surface);
+ int (*get)(vlc_va_t *, picture_t *pic, AVCodecContext *ctx, AVFrame *frame);
void (*close)(vlc_va_t *);
};
@@ -87,15 +87,17 @@ vlc_va_t *vlc_va_New(vlc_object_t *obj, AVCodecContext *,
* AV_PIX_FMT_VAAPI - VASurfaceID
*
* @param pic pointer to VLC picture containing the surface [IN/OUT]
- * @param surface pointer to the AVFrame data[0] and data[3] pointers [OUT]
+ * @param ctx pointer to the current AVCodecContext [IN]
+ * @param frame pointer to the AVFrame [IN]
*
* @note This function needs not be reentrant.
*
* @return VLC_SUCCESS on success, otherwise an error code.
*/
-static inline int vlc_va_Get(vlc_va_t *va, picture_t *pic, uint8_t **surface)
+static inline int vlc_va_Get(vlc_va_t *va, picture_t *pic, AVCodecContext *ctx,
+ AVFrame *frame)
{
- return va->ops->get(va, pic, surface);
+ return va->ops->get(va, pic, ctx, frame);
}
/**
=====================================
modules/codec/avcodec/vaapi.c
=====================================
@@ -43,19 +43,20 @@
#endif
#include <libavcodec/avcodec.h>
#include <libavcodec/vaapi.h>
+#include <libavutil/hwcontext_vaapi.h>
#include "avcodec.h"
#include "va.h"
#include "../../hw/vaapi/vlc_vaapi.h"
#include "va_surface.h"
-typedef struct
+struct vaapi_vctx
{
- struct vaapi_context hw_ctx;
- vlc_video_context *vctx;
- va_pool_t *va_pool;
- VASurfaceID render_targets[MAX_SURFACE_COUNT];
-} vlc_va_sys_t;
+ VADisplay va_dpy;
+ AVBufferRef *hwdev_ref;
+ vlc_mutex_t lock;
+ vlc_cond_t wait;
+};
static int GetVaProfile(const AVCodecContext *ctx, const es_format_t *fmt_in,
VAProfile *va_profile, int *vlc_chroma,
@@ -127,15 +128,19 @@ static int GetVaProfile(const AVCodecContext *ctx, const es_format_t *fmt_in,
typedef struct {
struct vaapi_pic_context ctx;
- vlc_va_surface_t *va_surface;
+ AVFrame *avframe;
} vaapi_dec_pic_context;
static void vaapi_dec_pic_context_destroy(picture_context_t *context)
{
vaapi_dec_pic_context *pic_ctx = container_of(context, vaapi_dec_pic_context, ctx.s);
- struct vlc_va_surface_t *va_surface = pic_ctx->va_surface;
+ av_frame_free(&pic_ctx->avframe);
+
+ struct vaapi_vctx *vaapi_vctx =
+ vlc_video_context_GetPrivate(pic_ctx->ctx.s.vctx, VLC_VIDEO_CONTEXT_VAAPI);
+ vlc_cond_signal(&vaapi_vctx->wait);
+
free(pic_ctx);
- va_surface_Release(va_surface);
}
static picture_context_t *vaapi_dec_pic_context_copy(picture_context_t *src)
@@ -144,100 +149,76 @@ static picture_context_t *vaapi_dec_pic_context_copy(picture_context_t *src)
vaapi_dec_pic_context *pic_ctx = malloc(sizeof(*pic_ctx));
if (unlikely(pic_ctx == NULL))
return NULL;
- *pic_ctx = *src_ctx;
+
+ pic_ctx->ctx = src_ctx->ctx;
+
+ pic_ctx->avframe = av_frame_clone(src_ctx->avframe);
+ if (!pic_ctx->avframe)
+ {
+ free(pic_ctx);
+ return NULL;
+ }
+
vlc_video_context_Hold(pic_ctx->ctx.s.vctx);
- va_surface_AddRef(pic_ctx->va_surface);
return &pic_ctx->ctx.s;
}
-static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
+static int Get(vlc_va_t *va, picture_t *pic, AVCodecContext *ctx, AVFrame *frame)
{
- vlc_va_sys_t *sys = va->sys;
- vlc_va_surface_t *va_surface = va_pool_Get(sys->va_pool);
- if (unlikely(va_surface == NULL))
- return VLC_ENOITEM;
- vaapi_dec_pic_context *vaapi_ctx = malloc(sizeof(*vaapi_ctx));
- if (unlikely(vaapi_ctx == NULL))
+ vlc_video_context *vctx = va->sys;
+ struct vaapi_vctx *vaapi_vctx =
+ vlc_video_context_GetPrivate(vctx, VLC_VIDEO_CONTEXT_VAAPI);
+
+ assert(ctx->hw_frames_ctx);
+
+ int ret;
+ vlc_mutex_lock(&vaapi_vctx->lock);
+ while ((ret = av_hwframe_get_buffer(ctx->hw_frames_ctx, frame, 0)) == AVERROR(ENOMEM))
+ vlc_cond_wait(&vaapi_vctx->wait, &vaapi_vctx->lock);
+ vlc_mutex_unlock(&vaapi_vctx->lock);
+
+ if (ret)
{
- va_surface_Release(va_surface);
- return VLC_ENOMEM;
+ msg_Err(va, "vaapi_va: av_hwframe_get_buffer failed: %d\n", ret);
+ return ret;
}
- vaapi_ctx->ctx.s = (picture_context_t) {
- vaapi_dec_pic_context_destroy, vaapi_dec_pic_context_copy,
- sys->vctx,
+
+ vaapi_dec_pic_context *vaapi_pic_ctx = malloc(sizeof(*vaapi_pic_ctx));
+ if (unlikely(vaapi_pic_ctx == NULL))
+ return VLC_ENOMEM;
+ vaapi_pic_ctx->ctx.s = (picture_context_t) {
+ vaapi_dec_pic_context_destroy, vaapi_dec_pic_context_copy, vctx,
};
- vaapi_ctx->ctx.surface = sys->render_targets[va_surface_GetIndex(va_surface)];
- vaapi_ctx->ctx.va_dpy = sys->hw_ctx.display;
- vaapi_ctx->va_surface = va_surface;
- vlc_vaapi_PicSetContext(pic, &vaapi_ctx->ctx);
- data[3] = (void *) (uintptr_t) vaapi_ctx->ctx.surface;
+
+ vaapi_pic_ctx->ctx.surface = (uintptr_t) frame->data[3];
+ vaapi_pic_ctx->ctx.va_dpy = vaapi_vctx->va_dpy;
+ vaapi_pic_ctx->avframe = av_frame_clone(frame);
+ vlc_vaapi_PicSetContext(pic, &vaapi_pic_ctx->ctx);
return VLC_SUCCESS;
}
static void Delete(vlc_va_t *va)
{
- vlc_va_sys_t *sys = va->sys;
-
- vlc_video_context_Release(sys->vctx);
- va_pool_Close(sys->va_pool);
+ vlc_video_context_Release(va->sys);
}
-static const struct vlc_va_operations ops = { Get, Delete, };
-
-static int VAAPICreateDevice(vlc_va_t *va)
+static void vaapi_ctx_destroy(void *priv)
{
- VLC_UNUSED(va);
- return VLC_SUCCESS;
-}
+ struct vaapi_vctx *vaapi_vctx = priv;
-static void VAAPIDestroyDevice(void *opaque)
-{
- vlc_va_sys_t *sys = opaque;
- if (sys->hw_ctx.context_id != VA_INVALID_ID)
- vlc_vaapi_DestroyContext(NULL, sys->hw_ctx.display, sys->hw_ctx.context_id);
- if (sys->hw_ctx.config_id != VA_INVALID_ID)
- vlc_vaapi_DestroyConfig(NULL, sys->hw_ctx.display, sys->hw_ctx.config_id);
- free(sys);
+ av_buffer_unref(&vaapi_vctx->hwdev_ref);
}
-static int VAAPICreateDecoderSurfaces(vlc_va_t *va, int codec_id,
- const video_format_t *fmt,
- size_t count)
-{
- VLC_UNUSED(codec_id);
- vlc_va_sys_t *sys = va->sys;
-
- unsigned va_rt_format;
- int va_fourcc;
- vlc_chroma_to_vaapi(fmt->i_chroma, &va_rt_format, &va_fourcc);
-
- VASurfaceAttrib fourcc_attribs[1] = {
- {
- .type = VASurfaceAttribPixelFormat,
- .flags = VA_SURFACE_ATTRIB_SETTABLE,
- .value.type = VAGenericValueTypeInteger,
- .value.value.i = va_fourcc,
- }
- };
-
- VA_CALL(VLC_OBJECT(va), vaCreateSurfaces, sys->hw_ctx.display, va_rt_format,
- fmt->i_visible_width, fmt->i_visible_height,
- sys->render_targets, count,
- fourcc_attribs, 1);
-
- return VLC_SUCCESS;
-error:
- return VLC_EGENERIC;
-}
+static const struct vlc_va_operations ops = { Get, Delete, };
-static void VAAPISetupAVCodecContext(void *opaque, AVCodecContext *avctx)
+static const struct vlc_video_context_operations vaapi_ctx_ops =
{
- vlc_va_sys_t *sys = opaque;
- avctx->hwaccel_context = &sys->hw_ctx;
-}
+ .destroy = vaapi_ctx_destroy,
+};
-static int Create(vlc_va_t *va, AVCodecContext *ctx, enum AVPixelFormat hwfmt, const AVPixFmtDescriptor *desc,
+static int Create(vlc_va_t *va, AVCodecContext *ctx, enum AVPixelFormat hwfmt,
+ const AVPixFmtDescriptor *desc,
const es_format_t *fmt_in, vlc_decoder_device *dec_device,
video_format_t *fmt_out, vlc_video_context **vtcx_out)
{
@@ -246,77 +227,54 @@ static int Create(vlc_va_t *va, AVCodecContext *ctx, enum AVPixelFormat hwfmt, c
dec_device->type != VLC_DECODER_DEVICE_VAAPI)
return VLC_EGENERIC;
- vlc_va_sys_t *sys = malloc(sizeof *sys);
- if (unlikely(sys == NULL))
- return VLC_ENOMEM;
- memset(sys, 0, sizeof (*sys));
-
- vlc_object_t *o = VLC_OBJECT(va);
-
- int ret = VLC_EGENERIC;
-
- VADisplay va_dpy = dec_device->opaque;
-
VAProfile i_profile;
unsigned count;
int i_vlc_chroma;
if (GetVaProfile(ctx, fmt_in, &i_profile, &i_vlc_chroma, &count) != VLC_SUCCESS)
- goto error;
+ return VLC_EGENERIC;
- /* */
- sys->hw_ctx.display = va_dpy;
- sys->hw_ctx.config_id = VA_INVALID_ID;
- sys->hw_ctx.context_id = VA_INVALID_ID;
- va->sys = sys;
-
- struct va_pool_cfg pool_cfg = {
- VAAPICreateDevice,
- VAAPIDestroyDevice,
- VAAPICreateDecoderSurfaces,
- VAAPISetupAVCodecContext,
- sys,
- };
- sys->va_pool = va_pool_Create(va, &pool_cfg);
- if (sys->va_pool == NULL)
- goto error;
+ VADisplay va_dpy = dec_device->opaque;
- fmt_out->i_chroma = i_vlc_chroma;
- int err = va_pool_SetupDecoder(va, sys->va_pool, ctx, fmt_out, count);
- if (err != VLC_SUCCESS)
+ AVBufferRef *hwdev_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
+ if (hwdev_ref == NULL)
goto error;
- VASurfaceID *render_targets = sys->render_targets;
+ AVHWDeviceContext *hwdev_ctx = (void *) hwdev_ref->data;
+ AVVAAPIDeviceContext *vadev_ctx = hwdev_ctx->hwctx;
+ vadev_ctx->display = va_dpy;
- sys->hw_ctx.config_id =
- vlc_vaapi_CreateConfigChecked(o, sys->hw_ctx.display, i_profile,
- VAEntrypointVLD, i_vlc_chroma);
- if (sys->hw_ctx.config_id == VA_INVALID_ID)
+ if (av_hwdevice_ctx_init(hwdev_ref) < 0)
goto error;
- /* Create a context */
- sys->hw_ctx.context_id =
- vlc_vaapi_CreateContext(o, sys->hw_ctx.display, sys->hw_ctx.config_id,
- ctx->coded_width, ctx->coded_height, VA_PROGRESSIVE,
- render_targets, count);
- if (sys->hw_ctx.context_id == VA_INVALID_ID)
+ vlc_video_context *vctx =
+ vlc_video_context_Create(dec_device, VLC_VIDEO_CONTEXT_VAAPI,
+ sizeof(struct vaapi_vctx), &vaapi_ctx_ops);
+ if (vctx == NULL)
goto error;
- msg_Info(va, "Using %s", vaQueryVendorString(sys->hw_ctx.display));
+ struct vaapi_vctx *vaapi_vctx =
+ vlc_video_context_GetPrivate(vctx, VLC_VIDEO_CONTEXT_VAAPI);
- sys->vctx = vlc_video_context_Create( dec_device, VLC_VIDEO_CONTEXT_VAAPI, 0, NULL );
- if (sys->vctx == NULL)
- goto error;
+ vaapi_vctx->va_dpy = va_dpy;
+ vaapi_vctx->hwdev_ref = hwdev_ref;
+ vlc_mutex_init(&vaapi_vctx->lock);
+ vlc_cond_init(&vaapi_vctx->wait);
+
+ msg_Info(va, "Using %s", vaQueryVendorString(va_dpy));
+
+ fmt_out->i_chroma = i_vlc_chroma;
+
+ ctx->hw_device_ctx = hwdev_ref;
va->ops = &ops;
- *vtcx_out = sys->vctx;
+ va->sys = vctx;
+ *vtcx_out = vctx;
return VLC_SUCCESS;
error:
- if (sys->va_pool != NULL)
- va_pool_Close(sys->va_pool);
- else
- free(sys);
- return ret;
+ if (hwdev_ref != NULL)
+ av_buffer_unref(&hwdev_ref);
+ return VLC_EGENERIC;
}
vlc_module_begin ()
=====================================
modules/codec/avcodec/video.c
=====================================
@@ -1395,20 +1395,26 @@ static int lavc_va_GetFrame(struct AVCodecContext *ctx, AVFrame *frame)
return -1;
/* data[3] will contains the format-specific surface handle. */
- if (vlc_va_Get(va, pic, &frame->data[0]))
+ if (vlc_va_Get(va, pic, ctx, frame))
{
msg_Err(dec, "hardware acceleration picture allocation failed");
picture_Release(pic);
return -1;
}
- frame->buf[0] = av_buffer_create(frame->data[0], 0, lavc_ReleaseFrame, pic, 0);
- if (unlikely(frame->buf[0] == NULL))
+ AVBufferRef *buf = av_buffer_create(NULL, 0, lavc_ReleaseFrame, pic, 0);
+ if (unlikely(buf == NULL))
{
- lavc_ReleaseFrame(pic, frame->data[0]);
+ lavc_ReleaseFrame(pic, NULL);
return -1;
}
+ /* frame->buf[0] must be valid but can be previously set by the VA module. */
+ if (frame->buf[0] == NULL)
+ frame->buf[0] = buf;
+ else
+ frame->opaque_ref = buf;
+
frame->opaque = pic;
return 0;
}
@@ -1550,7 +1556,8 @@ static enum AVPixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
video_format_t fmt;
/* Enumerate available formats */
- enum AVPixelFormat swfmt = avcodec_default_get_format(p_context, pi_fmt);
+ enum AVPixelFormat defaultfmt = avcodec_default_get_format(p_context, pi_fmt);
+ enum AVPixelFormat swfmt = AV_PIX_FMT_NONE;
bool can_hwaccel = false;
for (size_t i = 0; pi_fmt[i] != AV_PIX_FMT_NONE; i++)
@@ -1563,9 +1570,23 @@ static enum AVPixelFormat ffmpeg_GetFormat( AVCodecContext *p_context,
msg_Dbg( p_dec, "available %sware decoder output format %d (%s)",
hwaccel ? "hard" : "soft", pi_fmt[i], dsc->name );
if (hwaccel)
+ {
+ /* The default fmt is a hw format, it can happen with some va
+ * implementations (when using a hw_device_ctx). */
+ if (defaultfmt == pi_fmt[i])
+ defaultfmt = AV_PIX_FMT_NONE;
+
can_hwaccel = true;
+ }
+ else if (swfmt == AV_PIX_FMT_NONE)
+ swfmt = pi_fmt[i];
}
+ /* Use the default fmt in priority of any sw fmt if the default fmt is a hw
+ * one */
+ if (defaultfmt != AV_PIX_FMT_NONE)
+ swfmt = defaultfmt;
+
if (p_sys->pix_fmt == AV_PIX_FMT_NONE)
goto no_reuse;
=====================================
modules/hw/vdpau/avcodec.c
=====================================
@@ -109,8 +109,10 @@ static vlc_vdp_video_field_t *Get(vlc_va_sys_t *sys)
return field;
}
-static int Lock(vlc_va_t *va, picture_t *pic, uint8_t **data)
+static int Lock(vlc_va_t *va, picture_t *pic, AVCodecContext *ctx, AVFrame *frame)
{
+ (void) ctx;
+
vlc_va_sys_t *sys = va->sys;
vlc_vdp_video_field_t *field = Get(sys);
if (field == NULL)
@@ -120,7 +122,7 @@ static int Lock(vlc_va_t *va, picture_t *pic, uint8_t **data)
field->context.vctx = vlc_video_context_Hold(sys->vctx);
pic->context = &field->context;
- data[3] = (void *)(uintptr_t)field->frame->surface;
+ frame->data[3] = (void *)(uintptr_t)field->frame->surface;
return VLC_SUCCESS;
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/2721256e9bee998db4d4fd880987be225e246078...08cbeca2b732d8dcd3ae698a378cdfee5071a0c3
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/2721256e9bee998db4d4fd880987be225e246078...08cbeca2b732d8dcd3ae698a378cdfee5071a0c3
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list