nvdecoder: Copy output frame if needed

Even if decoder is negotiated with CUDA memory feature, if downstream
proposed no buffer pool, assume that the pool size is unknown.
And disable zero-copy if there's no more free output surface.
Or, in case of reverse playback, always copy frames.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5338>
This commit is contained in:
Seungha Yang 2023-09-16 23:26:27 +09:00
parent c5a5dcdf18
commit bd25c2738e
3 changed files with 38 additions and 1 deletions

View file

@ -547,6 +547,18 @@ gst_nv_dec_object_export_surface (GstNvDecObject * object,
return GST_FLOW_OK; return GST_FLOW_OK;
} }
guint
gst_nv_dec_object_get_num_free_surfaces (GstNvDecObject * object)
{
GstNvDecObjectPrivate *priv = object->priv;
std::lock_guard < std::mutex > lk (priv->lock);
if (object->num_mapped >= object->create_info.ulNumOutputSurfaces)
return 0;
return object->create_info.ulNumOutputSurfaces - object->num_mapped;
}
static gboolean static gboolean
gst_nv_dec_surface_dispose (GstNvDecSurface * surf) gst_nv_dec_surface_dispose (GstNvDecSurface * surf)
{ {

View file

@ -79,6 +79,8 @@ GstFlowReturn gst_nv_dec_object_export_surface (GstNvDecObject * object,
GstCudaStream * stream, GstCudaStream * stream,
GstMemory ** memory); GstMemory ** memory);
guint gst_nv_dec_object_get_num_free_surfaces (GstNvDecObject * object);
GType gst_nv_dec_surface_get_type (void); GType gst_nv_dec_surface_get_type (void);
static inline GstNvDecSurface * static inline GstNvDecSurface *

View file

@ -91,6 +91,7 @@ struct _GstNvDecoder
gboolean configured; gboolean configured;
guint downstream_min_buffers; guint downstream_min_buffers;
guint num_output_surfaces; guint num_output_surfaces;
gboolean wait_on_pool_full;
GMutex lock; GMutex lock;
@ -726,6 +727,7 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder,
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
GstNvDecSurface *surface; GstNvDecSurface *surface;
GstCudaStream *stream; GstCudaStream *stream;
gboolean can_export = FALSE;
if (picture->discont_state) { if (picture->discont_state) {
if (!gst_nv_decoder_negotiate (decoder, videodec, picture->discont_state)) { if (!gst_nv_decoder_negotiate (decoder, videodec, picture->discont_state)) {
@ -754,14 +756,32 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder,
goto error; goto error;
} }
if (decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_CUDA && if (videodec->input_segment.rate > 0 &&
decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_CUDA &&
(guint) decoder->create_info.ulNumOutputSurfaces >= (guint) decoder->create_info.ulNumOutputSurfaces >=
decoder->downstream_min_buffers) { decoder->downstream_min_buffers) {
if (decoder->wait_on_pool_full) {
can_export = TRUE;
} else {
guint num_free_surfaces =
gst_nv_dec_object_get_num_free_surfaces (decoder->object);
/* If downstream didn't propose pool but we have free surfaces */
if (num_free_surfaces > 0)
can_export = TRUE;
else
GST_LOG_OBJECT (decoder, "No more free output surface, need copy");
}
}
if (can_export) {
GstMemory *mem; GstMemory *mem;
GstCudaMemory *cmem; GstCudaMemory *cmem;
GstBuffer *buf; GstBuffer *buf;
GstVideoInfo *info = &decoder->info; GstVideoInfo *info = &decoder->info;
GST_LOG_OBJECT (decoder, "Exporting output surface without copy");
ret = gst_nv_dec_object_export_surface (decoder->object, ret = gst_nv_dec_object_export_surface (decoder->object,
surface, stream, &mem); surface, stream, &mem);
if (ret != GST_FLOW_OK) { if (ret != GST_FLOW_OK) {
@ -1542,6 +1562,9 @@ gst_nv_decoder_ensure_cuda_pool (GstNvDecoder * decoder, GstQuery * query)
if (outcaps) if (outcaps)
gst_video_info_from_caps (&vinfo, outcaps); gst_video_info_from_caps (&vinfo, outcaps);
size = (guint) vinfo.size; size = (guint) vinfo.size;
decoder->wait_on_pool_full = FALSE;
} else {
decoder->wait_on_pool_full = TRUE;
} }
config = gst_buffer_pool_get_config (pool); config = gst_buffer_pool_get_config (pool);