nvdecoder: Move common logic to decoder helper object

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5285>
This commit is contained in:
Seungha Yang 2023-09-06 01:00:42 +09:00 committed by GStreamer Marge Bot
parent 6cf6c73712
commit f9169c5431
7 changed files with 126 additions and 290 deletions

View file

@ -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

View file

@ -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

View file

@ -23,6 +23,7 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/cuda/gstcuda.h>
#include <gst/codecs/gstcodecpicture.h>
#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);

View file

@ -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 *

View file

@ -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 *

View file

@ -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

View file

@ -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