decoder: fix possible leak of VA surfaces.

Under some circumstances, we could have leaked a surface, thus not
releasing it to the pool of available surfaces in the VA context.
The strategy is now to use a proxy earlier and automatically ref/unref
whenever necessary. In particular, during the lifetime needed for FFmpeg.
This commit is contained in:
Gwenole Beauchesne 2012-01-05 17:09:35 +01:00
parent 4e72aa587c
commit 3e1d235c1a
3 changed files with 45 additions and 19 deletions

View file

@ -127,19 +127,14 @@ decode_step(GstVaapiDecoder *decoder)
static gboolean static gboolean
push_surface( push_surface(
GstVaapiDecoder *decoder, GstVaapiDecoder *decoder,
GstVaapiSurface *surface, GstVaapiSurfaceProxy *proxy,
GstClockTime timestamp GstClockTime timestamp
) )
{ {
GstVaapiDecoderPrivate * const priv = decoder->priv; GstVaapiDecoderPrivate * const priv = decoder->priv;
GstVaapiSurfaceProxy *proxy;
GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT, GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface))); GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy)));
proxy = gst_vaapi_surface_proxy_new(priv->context, surface);
if (!proxy)
return FALSE;
gst_vaapi_surface_proxy_set_timestamp(proxy, timestamp); gst_vaapi_surface_proxy_set_timestamp(proxy, timestamp);
g_queue_push_tail(priv->surfaces, proxy); g_queue_push_tail(priv->surfaces, proxy);
@ -560,5 +555,21 @@ gst_vaapi_decoder_push_surface(
GstClockTime timestamp GstClockTime timestamp
) )
{ {
return push_surface(decoder, surface, timestamp); GstVaapiDecoderPrivate * const priv = decoder->priv;
GstVaapiSurfaceProxy *proxy;
proxy = gst_vaapi_surface_proxy_new(priv->context, surface);
if (!proxy)
return FALSE;
return push_surface(decoder, proxy, timestamp);
}
gboolean
gst_vaapi_decoder_push_surface_proxy(
GstVaapiDecoder *decoder,
GstVaapiSurfaceProxy *proxy,
GstClockTime timestamp
)
{
return push_surface(decoder, g_object_ref(proxy), timestamp);
} }

View file

@ -260,6 +260,7 @@ gst_vaapi_decoder_ffmpeg_get_buffer(AVCodecContext *avctx, AVFrame *pic)
GstVaapiContextFfmpeg * const vactx = avctx->hwaccel_context; GstVaapiContextFfmpeg * const vactx = avctx->hwaccel_context;
GstVaapiContext *context; GstVaapiContext *context;
GstVaapiSurface *surface; GstVaapiSurface *surface;
GstVaapiSurfaceProxy *proxy;
GstVaapiID surface_id; GstVaapiID surface_id;
context = get_context(avctx); context = get_context(avctx);
@ -272,12 +273,19 @@ gst_vaapi_decoder_ffmpeg_get_buffer(AVCodecContext *avctx, AVFrame *pic)
return -1; return -1;
} }
proxy = gst_vaapi_surface_proxy_new(context, surface);
if (!proxy) {
GST_DEBUG("failed to create proxy surface");
gst_vaapi_context_put_surface(context, surface);
return -1;
}
surface_id = GST_VAAPI_OBJECT_ID(surface); surface_id = GST_VAAPI_OBJECT_ID(surface);
GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id)); GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id));
pic->type = FF_BUFFER_TYPE_USER; pic->type = FF_BUFFER_TYPE_USER;
pic->age = 1; pic->age = 1;
pic->data[0] = (uint8_t *)surface; pic->data[0] = (uint8_t *)proxy;
pic->data[1] = NULL; pic->data[1] = NULL;
pic->data[2] = NULL; pic->data[2] = NULL;
pic->data[3] = (uint8_t *)(uintptr_t)surface_id; pic->data[3] = (uint8_t *)(uintptr_t)surface_id;
@ -301,10 +309,13 @@ gst_vaapi_decoder_ffmpeg_reget_buffer(AVCodecContext *avctx, AVFrame *pic)
static void static void
gst_vaapi_decoder_ffmpeg_release_buffer(AVCodecContext *avctx, AVFrame *pic) gst_vaapi_decoder_ffmpeg_release_buffer(AVCodecContext *avctx, AVFrame *pic)
{ {
GstVaapiSurfaceProxy * const proxy = GST_VAAPI_SURFACE_PROXY(pic->data[0]);
GstVaapiID surface_id = GST_VAAPI_ID(GPOINTER_TO_UINT(pic->data[3])); GstVaapiID surface_id = GST_VAAPI_ID(GPOINTER_TO_UINT(pic->data[3]));
GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id)); GST_DEBUG("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(surface_id));
g_object_unref(proxy);
pic->data[0] = NULL; pic->data[0] = NULL;
pic->data[1] = NULL; pic->data[1] = NULL;
pic->data[2] = NULL; pic->data[2] = NULL;
@ -477,7 +488,7 @@ decode_frame(GstVaapiDecoderFfmpeg *ffdecoder, guchar *buf, guint buf_size)
{ {
GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv; GstVaapiDecoderFfmpegPrivate * const priv = ffdecoder->priv;
GstVaapiDisplay * const display = GST_VAAPI_DECODER_DISPLAY(ffdecoder); GstVaapiDisplay * const display = GST_VAAPI_DECODER_DISPLAY(ffdecoder);
GstVaapiSurface *surface; GstVaapiSurfaceProxy *proxy;
int bytes_read, got_picture = 0; int bytes_read, got_picture = 0;
AVPacket pkt; AVPacket pkt;
@ -498,15 +509,12 @@ decode_frame(GstVaapiDecoderFfmpeg *ffdecoder, guchar *buf, guint buf_size)
if (bytes_read < 0) if (bytes_read < 0)
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
surface = gst_vaapi_context_find_surface_by_id( proxy = GST_VAAPI_SURFACE_PROXY(priv->frame->data[0]);
GST_VAAPI_DECODER_CONTEXT(ffdecoder), if (!proxy)
GPOINTER_TO_UINT(priv->frame->data[3])
);
if (!surface)
return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE; return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE;
if (!gst_vaapi_decoder_push_surface(GST_VAAPI_DECODER_CAST(ffdecoder), if (!gst_vaapi_decoder_push_surface_proxy(GST_VAAPI_DECODER_CAST(ffdecoder),
surface, priv->frame->pts)) proxy, priv->frame->pts))
return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
return GST_VAAPI_DECODER_STATUS_SUCCESS; return GST_VAAPI_DECODER_STATUS_SUCCESS;
} }

View file

@ -169,6 +169,13 @@ gst_vaapi_decoder_push_surface(
GstClockTime timestamp GstClockTime timestamp
) attribute_hidden; ) attribute_hidden;
gboolean
gst_vaapi_decoder_push_surface_proxy(
GstVaapiDecoder *decoder,
GstVaapiSurfaceProxy *proxy,
GstClockTime timestamp
) attribute_hidden;
G_END_DECLS G_END_DECLS
#endif /* GST_VAAPI_DECODER_PRIV_H */ #endif /* GST_VAAPI_DECODER_PRIV_H */