mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 15:08:53 +00:00
decoder: maintain decoded frames as GstVideoCodecFrame objects.
Maintain decoded surfaces as GstVideoCodecFrame objects instead of GstVaapiSurfaceProxy objects. The latter will tend to be reduced to the strict minimum: a context and a surface.
This commit is contained in:
parent
039eb3bb6c
commit
8c2d9bcd24
5 changed files with 87 additions and 66 deletions
|
@ -304,29 +304,32 @@ decode_step(GstVaapiDecoder *decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
push_surface(GstVaapiDecoder *decoder, GstVaapiSurfaceProxy *proxy)
|
push_frame(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame)
|
||||||
{
|
{
|
||||||
GstVaapiDecoderPrivate * const priv = decoder->priv;
|
GstVaapiDecoderPrivate * const priv = decoder->priv;
|
||||||
GstVideoInfo * const vi = &priv->codec_state->info;
|
|
||||||
GstClockTime duration;
|
|
||||||
|
|
||||||
GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
|
GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
|
||||||
GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy)));
|
GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(
|
||||||
|
frame->user_data)));
|
||||||
|
|
||||||
if (vi->fps_n && vi->fps_d) {
|
g_queue_push_tail(priv->frames, frame);
|
||||||
/* Actual field duration is computed in vaapipostproc */
|
|
||||||
duration = gst_util_uint64_scale(GST_SECOND, vi->fps_d, vi->fps_n);
|
|
||||||
gst_vaapi_surface_proxy_set_duration(proxy, duration);
|
|
||||||
}
|
|
||||||
g_queue_push_tail(priv->surfaces, proxy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline GstVaapiSurfaceProxy *
|
static inline GstVideoCodecFrame *
|
||||||
pop_surface(GstVaapiDecoder *decoder)
|
pop_frame(GstVaapiDecoder *decoder)
|
||||||
{
|
{
|
||||||
GstVaapiDecoderPrivate * const priv = decoder->priv;
|
GstVaapiDecoderPrivate * const priv = decoder->priv;
|
||||||
|
GstVideoCodecFrame *frame;
|
||||||
|
|
||||||
return g_queue_pop_head(priv->surfaces);
|
frame = g_queue_pop_head(priv->frames);
|
||||||
|
if (!frame)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
GST_DEBUG("dequeue decoded surface %" GST_VAAPI_ID_FORMAT,
|
||||||
|
GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(
|
||||||
|
frame->user_data)));
|
||||||
|
|
||||||
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -387,11 +390,11 @@ gst_vaapi_decoder_finalize(GObject *object)
|
||||||
priv->buffers = NULL;
|
priv->buffers = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->surfaces) {
|
if (priv->frames) {
|
||||||
clear_queue(priv->surfaces, (GDestroyNotify)
|
clear_queue(priv->frames, (GDestroyNotify)
|
||||||
gst_vaapi_surface_proxy_unref);
|
gst_video_codec_frame_unref);
|
||||||
g_queue_free(priv->surfaces);
|
g_queue_free(priv->frames);
|
||||||
priv->surfaces = NULL;
|
priv->frames = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_clear_object(&priv->context);
|
g_clear_object(&priv->context);
|
||||||
|
@ -507,7 +510,7 @@ gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
|
||||||
priv->codec = 0;
|
priv->codec = 0;
|
||||||
priv->codec_state = codec_state;
|
priv->codec_state = codec_state;
|
||||||
priv->buffers = g_queue_new();
|
priv->buffers = g_queue_new();
|
||||||
priv->surfaces = g_queue_new();
|
priv->frames = g_queue_new();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -605,7 +608,7 @@ GstVaapiDecoderStatus
|
||||||
gst_vaapi_decoder_get_surface(GstVaapiDecoder *decoder,
|
gst_vaapi_decoder_get_surface(GstVaapiDecoder *decoder,
|
||||||
GstVaapiSurfaceProxy **out_proxy_ptr)
|
GstVaapiSurfaceProxy **out_proxy_ptr)
|
||||||
{
|
{
|
||||||
GstVaapiSurfaceProxy *proxy;
|
GstVideoCodecFrame *frame;
|
||||||
GstVaapiDecoderStatus status;
|
GstVaapiDecoderStatus status;
|
||||||
|
|
||||||
g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder),
|
g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder),
|
||||||
|
@ -613,20 +616,24 @@ gst_vaapi_decoder_get_surface(GstVaapiDecoder *decoder,
|
||||||
g_return_val_if_fail(out_proxy_ptr != NULL,
|
g_return_val_if_fail(out_proxy_ptr != NULL,
|
||||||
GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
|
GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
|
||||||
|
|
||||||
proxy = pop_surface(decoder);
|
frame = pop_frame(decoder);
|
||||||
if (!proxy) {
|
if (!frame) {
|
||||||
do {
|
do {
|
||||||
status = decode_step(decoder);
|
status = decode_step(decoder);
|
||||||
} while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
|
} while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
|
||||||
proxy = pop_surface(decoder);
|
frame = pop_frame(decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxy)
|
if (frame) {
|
||||||
|
*out_proxy_ptr = gst_vaapi_surface_proxy_ref(frame->user_data);
|
||||||
|
gst_video_codec_frame_unref(frame);
|
||||||
status = GST_VAAPI_DECODER_STATUS_SUCCESS;
|
status = GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||||
else if (status == GST_VAAPI_DECODER_STATUS_SUCCESS)
|
}
|
||||||
status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
else {
|
||||||
|
*out_proxy_ptr = NULL;
|
||||||
*out_proxy_ptr = proxy;
|
if (status == GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||||
|
status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,9 +642,11 @@ gst_vaapi_decoder_get_surface(GstVaapiDecoder *decoder,
|
||||||
* @decoder: a #GstVaapiDecoder
|
* @decoder: a #GstVaapiDecoder
|
||||||
* @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame
|
* @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame
|
||||||
*
|
*
|
||||||
* Returns the next frame available in the list of decoded frames.
|
* On successful return, *@out_frame_ptr contains the next decoded
|
||||||
* @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is returned if there is no
|
* frame available as a #GstVideoCodecFrame. The caller owns this
|
||||||
* decoded frame pending in the queue.
|
* object, so gst_video_codec_frame_unref() shall be called after
|
||||||
|
* usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is
|
||||||
|
* returned if no decoded frame is available.
|
||||||
*
|
*
|
||||||
* The actual surface is available as a #GstVaapiSurfaceProxy attached
|
* The actual surface is available as a #GstVaapiSurfaceProxy attached
|
||||||
* to the user-data anchor of the output frame. Ownership of the proxy
|
* to the user-data anchor of the output frame. Ownership of the proxy
|
||||||
|
@ -649,7 +658,6 @@ GstVaapiDecoderStatus
|
||||||
gst_vaapi_decoder_get_frame(GstVaapiDecoder *decoder,
|
gst_vaapi_decoder_get_frame(GstVaapiDecoder *decoder,
|
||||||
GstVideoCodecFrame **out_frame_ptr)
|
GstVideoCodecFrame **out_frame_ptr)
|
||||||
{
|
{
|
||||||
GstVaapiSurfaceProxy *proxy;
|
|
||||||
GstVideoCodecFrame *out_frame;
|
GstVideoCodecFrame *out_frame;
|
||||||
|
|
||||||
g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder),
|
g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder),
|
||||||
|
@ -657,20 +665,10 @@ gst_vaapi_decoder_get_frame(GstVaapiDecoder *decoder,
|
||||||
g_return_val_if_fail(out_frame_ptr != NULL,
|
g_return_val_if_fail(out_frame_ptr != NULL,
|
||||||
GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
|
GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
|
||||||
|
|
||||||
proxy = pop_surface(decoder);
|
out_frame = pop_frame(decoder);
|
||||||
if (!proxy || !(out_frame = gst_vaapi_surface_proxy_get_user_data(proxy)))
|
if (!out_frame)
|
||||||
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||||
|
|
||||||
gst_video_codec_frame_set_user_data(out_frame,
|
|
||||||
proxy, (GDestroyNotify)gst_vaapi_mini_object_unref);
|
|
||||||
|
|
||||||
out_frame->pts = GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy);
|
|
||||||
out_frame->duration = GST_VAAPI_SURFACE_PROXY_DURATION(proxy);
|
|
||||||
|
|
||||||
if (GST_VAAPI_SURFACE_PROXY_TFF(proxy))
|
|
||||||
GST_VIDEO_CODEC_FRAME_FLAG_SET(out_frame,
|
|
||||||
GST_VIDEO_CODEC_FRAME_FLAG_TFF);
|
|
||||||
|
|
||||||
*out_frame_ptr = out_frame;
|
*out_frame_ptr = out_frame;
|
||||||
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -809,12 +807,10 @@ gst_vaapi_decoder_ensure_context(
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_vaapi_decoder_push_surface_proxy(
|
gst_vaapi_decoder_push_frame(GstVaapiDecoder *decoder,
|
||||||
GstVaapiDecoder *decoder,
|
GstVideoCodecFrame *frame)
|
||||||
GstVaapiSurfaceProxy *proxy
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
push_surface(decoder, proxy);
|
push_frame(decoder, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
GstVaapiDecoderStatus
|
GstVaapiDecoderStatus
|
||||||
|
|
|
@ -84,6 +84,11 @@ gst_vaapi_picture_destroy(GstVaapiPicture *picture)
|
||||||
|
|
||||||
vaapi_destroy_buffer(GET_VA_DISPLAY(picture), &picture->param_id);
|
vaapi_destroy_buffer(GET_VA_DISPLAY(picture), &picture->param_id);
|
||||||
picture->param = NULL;
|
picture->param = NULL;
|
||||||
|
|
||||||
|
if (picture->frame) {
|
||||||
|
gst_video_codec_frame_unref(picture->frame);
|
||||||
|
picture->frame = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
@ -164,9 +169,8 @@ gst_vaapi_picture_create(
|
||||||
if (!picture->slices)
|
if (!picture->slices)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
gst_vaapi_mini_object_set_user_data(
|
picture->frame = gst_video_codec_frame_ref(
|
||||||
GST_VAAPI_MINI_OBJECT(picture->proxy),
|
GST_VAAPI_DECODER_CODEC_FRAME(GET_DECODER(picture)));
|
||||||
GST_VAAPI_DECODER_CODEC_FRAME(GET_DECODER(picture)), NULL);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,21 +308,40 @@ gboolean
|
||||||
gst_vaapi_picture_output(GstVaapiPicture *picture)
|
gst_vaapi_picture_output(GstVaapiPicture *picture)
|
||||||
{
|
{
|
||||||
GstVaapiSurfaceProxy *proxy;
|
GstVaapiSurfaceProxy *proxy;
|
||||||
|
GstVideoCodecFrame *out_frame;
|
||||||
|
|
||||||
g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
|
g_return_val_if_fail(GST_VAAPI_IS_PICTURE(picture), FALSE);
|
||||||
|
|
||||||
if (!picture->proxy)
|
if (!picture->proxy)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (!GST_VAAPI_PICTURE_IS_SKIPPED(picture)) {
|
out_frame = gst_video_codec_frame_ref(picture->frame);
|
||||||
proxy = gst_vaapi_surface_proxy_ref(picture->proxy);
|
|
||||||
gst_vaapi_surface_proxy_set_timestamp(proxy, picture->pts);
|
proxy = gst_vaapi_surface_proxy_ref(picture->proxy);
|
||||||
if (GST_VAAPI_PICTURE_IS_INTERLACED(picture))
|
gst_video_codec_frame_set_user_data(out_frame,
|
||||||
gst_vaapi_surface_proxy_set_interlaced(proxy, TRUE);
|
proxy, (GDestroyNotify)gst_vaapi_mini_object_unref);
|
||||||
if (GST_VAAPI_PICTURE_IS_TFF(picture))
|
|
||||||
gst_vaapi_surface_proxy_set_tff(proxy, TRUE);
|
if (!GST_CLOCK_TIME_IS_VALID(out_frame->pts))
|
||||||
gst_vaapi_decoder_push_surface_proxy(GET_DECODER(picture), proxy);
|
out_frame->pts = picture->pts;
|
||||||
}
|
if (GST_VAAPI_PICTURE_IS_SKIPPED(picture))
|
||||||
|
GST_VIDEO_CODEC_FRAME_FLAG_SET(out_frame,
|
||||||
|
GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
|
||||||
|
if (GST_VAAPI_PICTURE_IS_TFF(picture))
|
||||||
|
GST_VIDEO_CODEC_FRAME_FLAG_SET(out_frame,
|
||||||
|
GST_VIDEO_CODEC_FRAME_FLAG_TFF);
|
||||||
|
|
||||||
|
/* XXX: to be removed later */
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID(out_frame->pts))
|
||||||
|
gst_vaapi_surface_proxy_set_timestamp(proxy, out_frame->pts);
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID(out_frame->duration))
|
||||||
|
gst_vaapi_surface_proxy_set_duration(proxy, out_frame->duration);
|
||||||
|
if (GST_VAAPI_PICTURE_IS_INTERLACED(picture))
|
||||||
|
gst_vaapi_surface_proxy_set_interlaced(proxy, TRUE);
|
||||||
|
if (GST_VAAPI_PICTURE_IS_TFF(picture))
|
||||||
|
gst_vaapi_surface_proxy_set_tff(proxy, TRUE);
|
||||||
|
|
||||||
|
gst_vaapi_decoder_push_frame(GET_DECODER(picture), out_frame);
|
||||||
|
|
||||||
GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_OUTPUT);
|
GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_OUTPUT);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ enum {
|
||||||
struct _GstVaapiPicture {
|
struct _GstVaapiPicture {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
GstVaapiCodecObject parent_instance;
|
GstVaapiCodecObject parent_instance;
|
||||||
|
GstVideoCodecFrame *frame;
|
||||||
GstVaapiSurface *surface;
|
GstVaapiSurface *surface;
|
||||||
GstVaapiSurfaceProxy *proxy;
|
GstVaapiSurfaceProxy *proxy;
|
||||||
VABufferID param_id;
|
VABufferID param_id;
|
||||||
|
|
|
@ -163,7 +163,7 @@ struct _GstVaapiDecoderPrivate {
|
||||||
GstVaapiCodec codec;
|
GstVaapiCodec codec;
|
||||||
GstVideoCodecState *codec_state;
|
GstVideoCodecState *codec_state;
|
||||||
GQueue *buffers;
|
GQueue *buffers;
|
||||||
GQueue *surfaces;
|
GQueue *frames;
|
||||||
GstVaapiParserState parser_state;
|
GstVaapiParserState parser_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -209,10 +209,8 @@ gst_vaapi_decoder_ensure_context(
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
void
|
void
|
||||||
gst_vaapi_decoder_push_surface_proxy(
|
gst_vaapi_decoder_push_frame(GstVaapiDecoder *decoder,
|
||||||
GstVaapiDecoder *decoder,
|
GstVideoCodecFrame *frame);
|
||||||
GstVaapiSurfaceProxy *proxy
|
|
||||||
);
|
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
GstVaapiDecoderStatus
|
GstVaapiDecoderStatus
|
||||||
|
|
|
@ -234,6 +234,7 @@ gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
|
||||||
ret = gst_video_decoder_finish_frame(vdec, out_frame);
|
ret = gst_video_decoder_finish_frame(vdec, out_frame);
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
goto error_commit_buffer;
|
goto error_commit_buffer;
|
||||||
|
gst_video_codec_frame_unref(out_frame);
|
||||||
};
|
};
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
@ -269,12 +270,14 @@ error_create_buffer:
|
||||||
"surface %" GST_VAAPI_ID_FORMAT,
|
"surface %" GST_VAAPI_ID_FORMAT,
|
||||||
GST_VAAPI_ID_ARGS(surface_id));
|
GST_VAAPI_ID_ARGS(surface_id));
|
||||||
gst_video_decoder_drop_frame(vdec, out_frame);
|
gst_video_decoder_drop_frame(vdec, out_frame);
|
||||||
|
gst_video_codec_frame_unref(out_frame);
|
||||||
return GST_FLOW_UNEXPECTED;
|
return GST_FLOW_UNEXPECTED;
|
||||||
}
|
}
|
||||||
error_commit_buffer:
|
error_commit_buffer:
|
||||||
{
|
{
|
||||||
GST_DEBUG("video sink rejected the video buffer (error %d)", ret);
|
GST_DEBUG("video sink rejected the video buffer (error %d)", ret);
|
||||||
gst_video_decoder_drop_frame(vdec, out_frame);
|
gst_video_decoder_drop_frame(vdec, out_frame);
|
||||||
|
gst_video_codec_frame_unref(out_frame);
|
||||||
return GST_FLOW_UNEXPECTED;
|
return GST_FLOW_UNEXPECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue