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;
}
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
gst_nv_dec_surface_dispose (GstNvDecSurface * surf)
{

View file

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

View file

@ -91,6 +91,7 @@ struct _GstNvDecoder
gboolean configured;
guint downstream_min_buffers;
guint num_output_surfaces;
gboolean wait_on_pool_full;
GMutex lock;
@ -726,6 +727,7 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder,
GstFlowReturn ret = GST_FLOW_OK;
GstNvDecSurface *surface;
GstCudaStream *stream;
gboolean can_export = FALSE;
if (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;
}
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 >=
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;
GstCudaMemory *cmem;
GstBuffer *buf;
GstVideoInfo *info = &decoder->info;
GST_LOG_OBJECT (decoder, "Exporting output surface without copy");
ret = gst_nv_dec_object_export_surface (decoder->object,
surface, stream, &mem);
if (ret != GST_FLOW_OK) {
@ -1542,6 +1562,9 @@ gst_nv_decoder_ensure_cuda_pool (GstNvDecoder * decoder, GstQuery * query)
if (outcaps)
gst_video_info_from_caps (&vinfo, outcaps);
size = (guint) vinfo.size;
decoder->wait_on_pool_full = FALSE;
} else {
decoder->wait_on_pool_full = TRUE;
}
config = gst_buffer_pool_get_config (pool);