From f9169c54314f777ecb2c4773d6b07fd993817d81 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Wed, 6 Sep 2023 01:00:42 +0900 Subject: [PATCH] nvdecoder: Move common logic to decoder helper object Part-of: --- .../sys/nvcodec/gstnvav1dec.cpp | 43 +---- .../sys/nvcodec/gstnvdecoder.cpp | 173 ++++++++++-------- .../sys/nvcodec/gstnvdecoder.h | 13 +- .../sys/nvcodec/gstnvh264dec.cpp | 56 +----- .../sys/nvcodec/gstnvh265dec.cpp | 45 +---- .../sys/nvcodec/gstnvvp8dec.cpp | 43 +---- .../sys/nvcodec/gstnvvp9dec.cpp | 43 +---- 7 files changed, 126 insertions(+), 290 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.cpp index 8779cd0d35..72c5597f84 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.cpp @@ -583,20 +583,9 @@ gst_nv_av1_dec_new_picture (GstAV1Decoder * decoder, GstVideoCodecFrame * frame, GstAV1Picture * picture) { GstNvAV1Dec *self = GST_NV_AV1_DEC (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret; - ret = gst_nv_decoder_acquire_surface (self->decoder, &surface); - if (ret != GST_FLOW_OK) - return ret; - - GST_LOG_OBJECT (self, - "New decoder surface %p (index %d)", surface, surface->index); - - gst_av1_picture_set_user_data (picture, - surface, (GDestroyNotify) gst_nv_dec_surface_unref); - - return GST_FLOW_OK; + return gst_nv_decoder_new_picture (self->decoder, + GST_CODEC_PICTURE (picture)); } static GstNvDecSurface * @@ -1019,33 +1008,9 @@ gst_nv_av1_dec_output_picture (GstAV1Decoder * decoder, GstVideoCodecFrame * frame, GstAV1Picture * picture) { GstNvAV1Dec *self = GST_NV_AV1_DEC (decoder); - GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret = GST_FLOW_ERROR; - GST_LOG_OBJECT (self, "Outputting picture %p", picture); - - surface = (GstNvDecSurface *) gst_av1_picture_get_user_data (picture); - if (!surface) { - GST_ERROR_OBJECT (self, "No decoder frame in picture %p", picture); - goto error; - } - - ret = gst_nv_decoder_finish_surface (self->decoder, - vdec, GST_CODEC_PICTURE (picture)->discont_state, surface, - &frame->output_buffer); - if (ret != GST_FLOW_OK) - goto error; - - gst_av1_picture_unref (picture); - - return gst_video_decoder_finish_frame (vdec, frame); - -error: - gst_video_decoder_drop_frame (vdec, frame); - gst_av1_picture_unref (picture); - - return ret; + return gst_nv_decoder_output_picture (self->decoder, + GST_VIDEO_DECODER (decoder), frame, GST_CODEC_PICTURE (picture), 0); } static guint diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.cpp index e1aa44f4ab..d98511d4e7 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.cpp @@ -361,9 +361,11 @@ gst_nv_decoder_configure (GstNvDecoder * decoder, cudaVideoCodec codec, } GstFlowReturn -gst_nv_decoder_acquire_surface (GstNvDecoder * decoder, - GstNvDecSurface ** surface) +gst_nv_decoder_new_picture (GstNvDecoder * decoder, GstCodecPicture * picture) { + GstNvDecSurface *surface; + GstFlowReturn ret; + g_return_val_if_fail (GST_IS_NV_DECODER (decoder), GST_FLOW_ERROR); if (!decoder->object) { @@ -394,7 +396,14 @@ gst_nv_decoder_acquire_surface (GstNvDecoder * decoder, } } - return gst_nv_dec_object_acquire_surface (decoder->object, surface); + ret = gst_nv_dec_object_acquire_surface (decoder->object, &surface); + if (ret != GST_FLOW_OK) + return ret; + + gst_codec_picture_set_user_data (picture, + surface, (GDestroyNotify) gst_nv_dec_surface_unref); + + return GST_FLOW_OK; } gboolean @@ -710,38 +719,39 @@ done: } GstFlowReturn -gst_nv_decoder_finish_surface (GstNvDecoder * decoder, - GstVideoDecoder * videodec, GstVideoCodecState * input_state, - GstNvDecSurface * surface, GstBuffer ** buffer) +gst_nv_decoder_output_picture (GstNvDecoder * decoder, + GstVideoDecoder * videodec, GstVideoCodecFrame * frame, + GstCodecPicture * picture, guint buffer_flags) { - GstBuffer *outbuf = nullptr; - gboolean ret = FALSE; + GstFlowReturn ret = GST_FLOW_OK; + GstNvDecSurface *surface; GstCudaStream *stream; - GstFlowReturn flow_ret; - g_return_val_if_fail (GST_IS_NV_DECODER (decoder), GST_FLOW_ERROR); - g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), GST_FLOW_ERROR); - g_return_val_if_fail (decoder->object != nullptr, GST_FLOW_ERROR); - g_return_val_if_fail (surface != nullptr, GST_FLOW_ERROR); - g_return_val_if_fail (buffer != nullptr, GST_FLOW_ERROR); - - if (input_state) { - if (!gst_nv_decoder_negotiate (decoder, videodec, input_state)) { + if (picture->discont_state) { + if (!gst_nv_decoder_negotiate (decoder, videodec, picture->discont_state)) { GST_ERROR_OBJECT (videodec, "Couldn't re-negotiate with updated state"); - return GST_FLOW_NOT_NEGOTIATED; + ret = GST_FLOW_NOT_NEGOTIATED; + goto error; } } + surface = (GstNvDecSurface *) gst_codec_picture_get_user_data (picture); + if (!surface) { + GST_ERROR_OBJECT (decoder, "No decoder frame in picture %p", picture); + goto error; + } + if (!gst_cuda_context_push (decoder->context)) { GST_ERROR_OBJECT (decoder, "Couldn't push context"); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto error; } stream = decoder->stream; - flow_ret = gst_nv_dec_object_map_surface (decoder->object, surface, stream); - if (flow_ret != GST_FLOW_OK) { + ret = gst_nv_dec_object_map_surface (decoder->object, surface, stream); + if (ret != GST_FLOW_OK) { gst_cuda_context_pop (nullptr); - return flow_ret; + goto error; } if (decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_CUDA && @@ -752,13 +762,14 @@ gst_nv_decoder_finish_surface (GstNvDecoder * decoder, GstBuffer *buf; GstVideoInfo *info = &decoder->info; - flow_ret = gst_nv_dec_object_export_surface (decoder->object, + ret = gst_nv_dec_object_export_surface (decoder->object, surface, stream, &mem); - if (flow_ret != GST_FLOW_OK) { + if (ret != GST_FLOW_OK) { GST_WARNING_OBJECT (decoder, "Couldn't export surface"); gst_nv_dec_object_unmap_surface (decoder->object, surface); gst_cuda_context_pop (nullptr); - return flow_ret; + + goto error; } gst_cuda_context_pop (nullptr); @@ -776,67 +787,77 @@ gst_nv_decoder_finish_surface (GstNvDecoder * decoder, GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info), cmem->info.offset, cmem->info.stride); - *buffer = buf; - return GST_FLOW_OK; - } + frame->output_buffer = buf; + } else { + gboolean copy_ret = FALSE; + + frame->output_buffer = gst_video_decoder_allocate_output_buffer (videodec); + if (!frame->output_buffer) { + GST_ERROR_OBJECT (videodec, "Couldn't allocate output buffer"); + gst_nv_dec_object_unmap_surface (decoder->object, surface); + gst_cuda_context_pop (nullptr); + ret = GST_FLOW_ERROR; + goto error; + } + + switch (decoder->output_type) { + case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM: + copy_ret = gst_nv_decoder_copy_frame_to_system (decoder, + surface, frame->output_buffer); + break; +#ifdef HAVE_CUDA_GST_GL + case GST_NV_DECODER_OUTPUT_TYPE_GL: + g_assert (decoder->gl_context != nullptr); + + copy_ret = gst_nv_decoder_copy_frame_to_gl (decoder, + GST_GL_CONTEXT (decoder->gl_context), surface, + frame->output_buffer); + break; +#endif + case GST_NV_DECODER_OUTPUT_TYPE_CUDA: + copy_ret = gst_nv_decoder_copy_frame_to_cuda (decoder, + surface, frame->output_buffer, stream); + break; + default: + g_assert_not_reached (); + gst_nv_dec_object_unmap_surface (decoder->object, surface); + gst_cuda_context_pop (nullptr); + ret = GST_FLOW_ERROR; + goto error; + } + + /* FIXME: This is the case where OpenGL context of downstream glbufferpool + * belongs to non-nvidia (or different device). + * There should be enhancement to ensure nvdec has compatible OpenGL context + */ + if (!copy_ret && decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL) { + GST_WARNING_OBJECT (videodec, + "Couldn't copy frame to GL memory, fallback to system memory"); + decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM; + + copy_ret = gst_nv_decoder_copy_frame_to_system (decoder, surface, + frame->output_buffer); + } - outbuf = gst_video_decoder_allocate_output_buffer (videodec); - if (!outbuf) { - GST_ERROR_OBJECT (videodec, "Couldn't allocate output buffer"); gst_nv_dec_object_unmap_surface (decoder->object, surface); gst_cuda_context_pop (nullptr); - return GST_FLOW_ERROR; - } - switch (decoder->output_type) { - case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM: - ret = gst_nv_decoder_copy_frame_to_system (decoder, surface, outbuf); - break; -#ifdef HAVE_CUDA_GST_GL - case GST_NV_DECODER_OUTPUT_TYPE_GL: - g_assert (decoder->gl_context != nullptr); - - ret = gst_nv_decoder_copy_frame_to_gl (decoder, - GST_GL_CONTEXT (decoder->gl_context), surface, outbuf); - break; -#endif - case GST_NV_DECODER_OUTPUT_TYPE_CUDA: - ret = gst_nv_decoder_copy_frame_to_cuda (decoder, - surface, outbuf, stream); - break; - default: - g_assert_not_reached (); + if (!copy_ret) { + GST_WARNING_OBJECT (videodec, "Failed to copy frame"); goto error; + } } - /* FIXME: This is the case where OpenGL context of downstream glbufferpool - * belongs to non-nvidia (or different device). - * There should be enhancement to ensure nvdec has compatible OpenGL context - */ - if (!ret && decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL) { - GST_WARNING_OBJECT (videodec, - "Couldn't copy frame to GL memory, fallback to system memory"); - decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM; + GST_BUFFER_FLAG_SET (frame->output_buffer, buffer_flags); + gst_codec_picture_unref (picture); - ret = gst_nv_decoder_copy_frame_to_system (decoder, surface, outbuf); - } - - gst_nv_dec_object_unmap_surface (decoder->object, surface); - gst_cuda_context_pop (nullptr); - - if (!ret) { - GST_WARNING_OBJECT (videodec, "Failed to copy frame"); - goto error; - } - - *buffer = outbuf; - - return GST_FLOW_OK; + return gst_video_decoder_finish_frame (videodec, frame); error: - gst_nv_dec_object_unmap_surface (decoder->object, surface); - gst_clear_buffer (&outbuf); - return GST_FLOW_ERROR; + gst_codec_picture_unref (picture); + gst_video_decoder_release_frame (videodec, frame); + + return ret; } typedef enum diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h index b79fbf95fa..0ad05d3768 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "gstcuvidloader.h" #include "gstnvdecobject.h" @@ -57,17 +58,17 @@ gboolean gst_nv_decoder_configure (GstNvDecoder * decoder, guint init_max_width, guint init_max_height); -GstFlowReturn gst_nv_decoder_acquire_surface (GstNvDecoder * decoder, - GstNvDecSurface ** surface); +GstFlowReturn gst_nv_decoder_new_picture (GstNvDecoder * decoder, + GstCodecPicture * picture); gboolean gst_nv_decoder_decode (GstNvDecoder * decoder, CUVIDPICPARAMS * params); -GstFlowReturn gst_nv_decoder_finish_surface (GstNvDecoder * decoder, +GstFlowReturn gst_nv_decoder_output_picture (GstNvDecoder * decoder, GstVideoDecoder * videodec, - GstVideoCodecState * input_state, - GstNvDecSurface *surface, - GstBuffer ** buffer); + GstVideoCodecFrame * frame, + GstCodecPicture * picture, + guint buffer_flags); void gst_nv_decoder_set_flushing (GstNvDecoder * decoder, gboolean flushing); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.cpp index 2e06c76ba2..f181cee23b 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.cpp @@ -694,20 +694,9 @@ gst_nv_h264_dec_new_picture (GstH264Decoder * decoder, GstVideoCodecFrame * frame, GstH264Picture * picture) { GstNvH264Dec *self = GST_NV_H264_DEC (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret; - ret = gst_nv_decoder_acquire_surface (self->decoder, &surface); - if (ret != GST_FLOW_OK) - return ret; - - GST_LOG_OBJECT (self, - "New decoder surface %p (index %d)", surface, surface->index); - - gst_h264_picture_set_user_data (picture, - surface, (GDestroyNotify) gst_nv_dec_surface_unref); - - return GST_FLOW_OK; + return gst_nv_decoder_new_picture (self->decoder, + GST_CODEC_PICTURE (picture)); } static GstFlowReturn @@ -736,45 +725,10 @@ gst_nv_h264_dec_output_picture (GstH264Decoder * decoder, GstVideoCodecFrame * frame, GstH264Picture * picture) { GstNvH264Dec *self = GST_NV_H264_DEC (decoder); - GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret = GST_FLOW_ERROR; - GST_LOG_OBJECT (self, - "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt); - - surface = (GstNvDecSurface *) gst_h264_picture_get_user_data (picture); - if (!surface) { - GST_ERROR_OBJECT (self, "No decoder surface in picture %p", picture); - goto error; - } - - ret = gst_nv_decoder_finish_surface (self->decoder, - vdec, GST_CODEC_PICTURE (picture)->discont_state, surface, - &frame->output_buffer); - if (ret != GST_FLOW_OK) - goto error; - - if (picture->buffer_flags != 0) { - gboolean interlaced = - (picture->buffer_flags & GST_VIDEO_BUFFER_FLAG_INTERLACED) != 0; - gboolean tff = (picture->buffer_flags & GST_VIDEO_BUFFER_FLAG_TFF) != 0; - - GST_TRACE_OBJECT (self, - "apply buffer flags 0x%x (interlaced %d, top-field-first %d)", - picture->buffer_flags, interlaced, tff); - GST_BUFFER_FLAG_SET (frame->output_buffer, picture->buffer_flags); - } - - gst_h264_picture_unref (picture); - - return gst_video_decoder_finish_frame (vdec, frame); - -error: - gst_h264_picture_unref (picture); - gst_video_decoder_release_frame (vdec, frame); - - return ret; + return gst_nv_decoder_output_picture (self->decoder, + GST_VIDEO_DECODER (decoder), frame, GST_CODEC_PICTURE (picture), + picture->buffer_flags); } static GstNvDecSurface * diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.cpp index 169fa996f7..4957fdc2a2 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.cpp @@ -647,20 +647,9 @@ gst_nv_h265_dec_new_picture (GstH265Decoder * decoder, GstVideoCodecFrame * cframe, GstH265Picture * picture) { GstNvH265Dec *self = GST_NV_H265_DEC (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret; - ret = gst_nv_decoder_acquire_surface (self->decoder, &surface); - if (ret != GST_FLOW_OK) - return ret; - - GST_LOG_OBJECT (self, "New decoder surface %p (index %d)", - surface, surface->index); - - gst_h265_picture_set_user_data (picture, - surface, (GDestroyNotify) gst_nv_dec_surface_unref); - - return GST_FLOW_OK; + return gst_nv_decoder_new_picture (self->decoder, + GST_CODEC_PICTURE (picture)); } static GstFlowReturn @@ -668,34 +657,10 @@ gst_nv_h265_dec_output_picture (GstH265Decoder * decoder, GstVideoCodecFrame * frame, GstH265Picture * picture) { GstNvH265Dec *self = GST_NV_H265_DEC (decoder); - GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret = GST_FLOW_ERROR; - GST_LOG_OBJECT (self, - "Outputting picture %p (poc %d)", picture, picture->pic_order_cnt); - - surface = (GstNvDecSurface *) gst_h265_picture_get_user_data (picture); - if (!surface) { - GST_ERROR_OBJECT (self, "No decoder surface in picture %p", picture); - goto error; - } - - ret = gst_nv_decoder_finish_surface (self->decoder, - vdec, GST_CODEC_PICTURE (picture)->discont_state, surface, - &frame->output_buffer); - if (ret != GST_FLOW_OK) - goto error; - - gst_h265_picture_unref (picture); - - return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); - -error: - gst_video_decoder_drop_frame (vdec, frame); - gst_h265_picture_unref (picture); - - return ret; + return gst_nv_decoder_output_picture (self->decoder, + GST_VIDEO_DECODER (decoder), frame, GST_CODEC_PICTURE (picture), + picture->buffer_flags); } static GstNvDecSurface * diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.cpp index 301446020e..42dafdf496 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.cpp @@ -516,20 +516,9 @@ gst_nv_vp8_dec_new_picture (GstVp8Decoder * decoder, GstVideoCodecFrame * frame, GstVp8Picture * picture) { GstNvVp8Dec *self = GST_NV_VP8_DEC (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret; - ret = gst_nv_decoder_acquire_surface (self->decoder, &surface); - if (ret != GST_FLOW_OK) - return ret; - - GST_LOG_OBJECT (self, - "New decoder frame %p (index %d)", surface, surface->index); - - gst_vp8_picture_set_user_data (picture, - surface, (GDestroyNotify) gst_nv_dec_surface_unref); - - return GST_FLOW_OK; + return gst_nv_decoder_new_picture (self->decoder, + GST_CODEC_PICTURE (picture)); } static GstNvDecSurface * @@ -635,33 +624,9 @@ gst_nv_vp8_dec_output_picture (GstVp8Decoder * decoder, GstVideoCodecFrame * frame, GstVp8Picture * picture) { GstNvVp8Dec *self = GST_NV_VP8_DEC (decoder); - GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret = GST_FLOW_ERROR; - GST_LOG_OBJECT (self, "Outputting picture %p", picture); - - surface = (GstNvDecSurface *) gst_vp8_picture_get_user_data (picture); - if (!surface) { - GST_ERROR_OBJECT (self, "No decoder frame in picture %p", picture); - goto error; - } - - ret = gst_nv_decoder_finish_surface (self->decoder, - vdec, GST_CODEC_PICTURE (picture)->discont_state, surface, - &frame->output_buffer); - if (ret != GST_FLOW_OK) - goto error; - - gst_vp8_picture_unref (picture); - - return gst_video_decoder_finish_frame (vdec, frame); - -error: - gst_video_decoder_drop_frame (vdec, frame); - gst_vp8_picture_unref (picture); - - return ret; + return gst_nv_decoder_output_picture (self->decoder, + GST_VIDEO_DECODER (decoder), frame, GST_CODEC_PICTURE (picture), 0); } static guint diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.cpp index 5a3b7146df..b26ff66af5 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.cpp @@ -525,20 +525,9 @@ gst_nv_vp9_dec_new_picture (GstVp9Decoder * decoder, GstVideoCodecFrame * frame, GstVp9Picture * picture) { GstNvVp9Dec *self = GST_NV_VP9_DEC (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret; - ret = gst_nv_decoder_acquire_surface (self->decoder, &surface); - if (ret != GST_FLOW_OK) - return ret; - - GST_LOG_OBJECT (self, - "New decoder frame %p (index %d)", surface, surface->index); - - gst_vp9_picture_set_user_data (picture, - surface, (GDestroyNotify) gst_nv_dec_surface_unref); - - return GST_FLOW_OK; + return gst_nv_decoder_new_picture (self->decoder, + GST_CODEC_PICTURE (picture)); } static GstNvDecSurface * @@ -731,33 +720,9 @@ gst_nv_vp9_dec_output_picture (GstVp9Decoder * decoder, GstVideoCodecFrame * frame, GstVp9Picture * picture) { GstNvVp9Dec *self = GST_NV_VP9_DEC (decoder); - GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder); - GstNvDecSurface *surface; - GstFlowReturn ret = GST_FLOW_ERROR; - GST_LOG_OBJECT (self, "Outputting picture %p", picture); - - surface = (GstNvDecSurface *) gst_vp9_picture_get_user_data (picture); - if (!surface) { - GST_ERROR_OBJECT (self, "No decoder frame in picture %p", picture); - goto error; - } - - ret = gst_nv_decoder_finish_surface (self->decoder, - vdec, GST_CODEC_PICTURE (picture)->discont_state, surface, - &frame->output_buffer); - if (ret != GST_FLOW_OK) - goto error; - - gst_vp9_picture_unref (picture); - - return gst_video_decoder_finish_frame (vdec, frame); - -error: - gst_video_decoder_drop_frame (vdec, frame); - gst_vp9_picture_unref (picture); - - return ret; + return gst_nv_decoder_output_picture (self->decoder, + GST_VIDEO_DECODER (decoder), frame, GST_CODEC_PICTURE (picture), 0); } static guint