nvdecoder: Add support for reconfiguration

Instead of creating new decoder instance per new sequence,
re-use configured decoder instance via cuvidReconfigureDecoder()
API. It will make output surface reusable without re-allocation.
Also, in order for application to be able to reserve higher resolution
output surface, "init-max-width" and "init-max-height" properties are
added to each decoder.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3884>
This commit is contained in:
Seungha Yang 2023-02-13 21:59:05 +09:00 committed by GStreamer Marge Bot
parent eb0fca4180
commit f831b92540
11 changed files with 565 additions and 33 deletions

View file

@ -56,6 +56,8 @@ typedef struct _GstnvdecCuvidVTable
unsigned int reserved_flags); unsigned int reserved_flags);
CUresult (CUDAAPI * CuvidCreateDecoder) (CUvideodecoder * phDecoder, CUresult (CUDAAPI * CuvidCreateDecoder) (CUvideodecoder * phDecoder,
CUVIDDECODECREATEINFO * pdci); CUVIDDECODECREATEINFO * pdci);
CUresult (CUDAAPI * CuvidReconfigureDecoder) (CUvideodecoder phDecoder,
CUVIDRECONFIGUREDECODERINFO * pDecReconfigParams);
CUresult (CUDAAPI * CuvidDestroyDecoder) (CUvideodecoder hDecoder); CUresult (CUDAAPI * CuvidDestroyDecoder) (CUvideodecoder hDecoder);
CUresult (CUDAAPI * CuvidDecodePicture) (CUvideodecoder hDecoder, CUresult (CUDAAPI * CuvidDecodePicture) (CUvideodecoder hDecoder,
CUVIDPICPARAMS * pPicParams); CUVIDPICPARAMS * pPicParams);
@ -97,6 +99,7 @@ gst_cuvid_load_library (guint api_major_ver, guint api_minor_ver)
LOAD_SYMBOL (cuvidCtxLock, CuvidCtxLock, TRUE); LOAD_SYMBOL (cuvidCtxLock, CuvidCtxLock, TRUE);
LOAD_SYMBOL (cuvidCtxUnlock, CuvidCtxUnlock, TRUE); LOAD_SYMBOL (cuvidCtxUnlock, CuvidCtxUnlock, TRUE);
LOAD_SYMBOL (cuvidCreateDecoder, CuvidCreateDecoder, TRUE); LOAD_SYMBOL (cuvidCreateDecoder, CuvidCreateDecoder, TRUE);
LOAD_SYMBOL (cuvidReconfigureDecoder, CuvidReconfigureDecoder, FALSE);
LOAD_SYMBOL (cuvidDestroyDecoder, CuvidDestroyDecoder, TRUE); LOAD_SYMBOL (cuvidDestroyDecoder, CuvidDestroyDecoder, TRUE);
LOAD_SYMBOL (cuvidDecodePicture, CuvidDecodePicture, TRUE); LOAD_SYMBOL (cuvidDecodePicture, CuvidDecodePicture, TRUE);
LOAD_SYMBOL (cuvidCreateVideoParser, CuvidCreateVideoParser, TRUE); LOAD_SYMBOL (cuvidCreateVideoParser, CuvidCreateVideoParser, TRUE);
@ -142,6 +145,15 @@ gst_cuvid_can_get_decoder_caps (void)
return FALSE; return FALSE;
} }
gboolean
gst_cuvid_can_reconfigure (void)
{
if (gst_cuvid_vtable.CuvidReconfigureDecoder)
return TRUE;
return FALSE;
}
CUresult CUDAAPI CUresult CUDAAPI
CuvidCtxLockCreate (CUvideoctxlock * pLock, CUcontext ctx) CuvidCtxLockCreate (CUvideoctxlock * pLock, CUcontext ctx)
{ {
@ -182,6 +194,16 @@ CuvidCreateDecoder (CUvideodecoder * phDecoder, CUVIDDECODECREATEINFO * pdci)
return gst_cuvid_vtable.CuvidCreateDecoder (phDecoder, pdci); return gst_cuvid_vtable.CuvidCreateDecoder (phDecoder, pdci);
} }
CUresult CUDAAPI
CuvidReconfigureDecoder (CUvideodecoder hDecoder,
CUVIDRECONFIGUREDECODERINFO * pDecReconfigParams)
{
g_assert (gst_cuvid_vtable.CuvidReconfigureDecoder != NULL);
return gst_cuvid_vtable.CuvidReconfigureDecoder (hDecoder,
pDecReconfigParams);
}
CUresult CUDAAPI CUresult CUDAAPI
CuvidDestroyDecoder (CUvideodecoder hDecoder) CuvidDestroyDecoder (CUvideodecoder hDecoder)
{ {

View file

@ -35,6 +35,8 @@ gboolean gst_cuvid_get_api_version (guint * api_major_ver,
gboolean gst_cuvid_can_get_decoder_caps (void); gboolean gst_cuvid_can_get_decoder_caps (void);
gboolean gst_cuvid_can_reconfigure (void);
CUresult CUDAAPI CuvidCtxLockCreate (CUvideoctxlock * pLock, CUresult CUDAAPI CuvidCtxLockCreate (CUvideoctxlock * pLock,
CUcontext ctx); CUcontext ctx);
@ -49,6 +51,9 @@ CUresult CUDAAPI CuvidCtxUnlock (CUvideoctxlock lck,
CUresult CUDAAPI CuvidCreateDecoder (CUvideodecoder * phDecoder, CUresult CUDAAPI CuvidCreateDecoder (CUvideodecoder * phDecoder,
CUVIDDECODECREATEINFO * pdci); CUVIDDECODECREATEINFO * pdci);
CUresult CUDAAPI CuvidReconfigureDecoder (CUvideodecoder hDecoder,
CUVIDRECONFIGUREDECODERINFO * pDecReconfigParams);
CUresult CUDAAPI CuvidDestroyDecoder (CUvideodecoder hDecoder); CUresult CUDAAPI CuvidDestroyDecoder (CUvideodecoder hDecoder);
CUresult CUDAAPI CuvidDecodePicture (CUvideodecoder hDecoder, CUresult CUDAAPI CuvidDecodePicture (CUvideodecoder hDecoder,

View file

@ -71,12 +71,16 @@ typedef struct _GstNvAV1Dec
guint8 film_grain_params_present; guint8 film_grain_params_present;
guint num_output_surfaces; guint num_output_surfaces;
guint init_max_width;
guint init_max_height;
} GstNvAV1Dec; } GstNvAV1Dec;
typedef struct _GstNvAV1DecClass typedef struct _GstNvAV1DecClass
{ {
GstAV1DecoderClass parent_class; GstAV1DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
guint max_width;
guint max_height;
} GstNvAV1DecClass; } GstNvAV1DecClass;
enum enum
@ -84,6 +88,8 @@ enum
PROP_0, PROP_0,
PROP_CUDA_DEVICE_ID, PROP_CUDA_DEVICE_ID,
PROP_NUM_OUTPUT_SURFACES, PROP_NUM_OUTPUT_SURFACES,
PROP_INIT_MAX_WIDTH,
PROP_INIT_MAX_HEIGHT,
}; };
#define DEFAULT_NUM_OUTPUT_SURFACES 0 #define DEFAULT_NUM_OUTPUT_SURFACES 0
@ -163,6 +169,38 @@ gst_nv_av1_dec_class_init (GstNvAV1DecClass * klass,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | (GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS))); G_PARAM_STATIC_STRINGS)));
/**
* GstNvAV1Dec:init-max-width:
*
* Initial CUVIDDECODECREATEINFO.ulMaxWidth value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_WIDTH,
g_param_spec_uint ("init-max-width", "Initial Maximum Width",
"Expected maximum coded width of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_width, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
/**
* GstNvAV1Dec:init-max-height:
*
* Initial CUVIDDECODECREATEINFO.ulMaxHeight value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_HEIGHT,
g_param_spec_uint ("init-max-height", "Initial Maximum Height",
"Expected maximum coded height of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_height, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_av1_dec_set_context); element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_av1_dec_set_context);
parent_class = (GTypeClass *) g_type_class_peek_parent (klass); parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
@ -204,6 +242,8 @@ gst_nv_av1_dec_class_init (GstNvAV1DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_av1_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_av1_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height;
gst_caps_unref (cdata->sink_caps); gst_caps_unref (cdata->sink_caps);
gst_caps_unref (cdata->src_caps); gst_caps_unref (cdata->src_caps);
@ -226,6 +266,12 @@ gst_nv_av1_dec_set_property (GObject * object, guint prop_id,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
self->num_output_surfaces = g_value_get_uint (value); self->num_output_surfaces = g_value_get_uint (value);
break; break;
case PROP_INIT_MAX_WIDTH:
self->init_max_width = g_value_get_uint (value);
break;
case PROP_INIT_MAX_HEIGHT:
self->init_max_height = g_value_get_uint (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -246,6 +292,12 @@ gst_nv_av1_dec_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
g_value_set_uint (value, self->num_output_surfaces); g_value_set_uint (value, self->num_output_surfaces);
break; break;
case PROP_INIT_MAX_WIDTH:
g_value_set_uint (value, self->init_max_width);
break;
case PROP_INIT_MAX_HEIGHT:
g_value_set_uint (value, self->init_max_height);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -421,6 +473,7 @@ gst_nv_av1_dec_new_sequence (GstAV1Decoder * decoder,
const GstAV1SequenceHeaderOBU * seq_hdr, gint max_dpb_size) const GstAV1SequenceHeaderOBU * seq_hdr, gint max_dpb_size)
{ {
GstNvAV1Dec *self = GST_NV_AV1_DEC (decoder); GstNvAV1Dec *self = GST_NV_AV1_DEC (decoder);
GstNvAV1DecClass *klass = GST_NV_AV1_DEC_GET_CLASS (self);
gboolean modified = FALSE; gboolean modified = FALSE;
guint max_width, max_height; guint max_width, max_height;
@ -480,10 +533,15 @@ gst_nv_av1_dec_new_sequence (GstAV1Decoder * decoder,
out_format, GST_ROUND_UP_2 (self->max_width), out_format, GST_ROUND_UP_2 (self->max_width),
GST_ROUND_UP_2 (self->max_height)); GST_ROUND_UP_2 (self->max_height));
max_width = gst_nv_decoder_get_max_output_size (self->max_width,
self->init_max_width, klass->max_width);
max_height = gst_nv_decoder_get_max_output_size (self->max_height,
self->init_max_height, klass->max_height);
if (!gst_nv_decoder_configure (self->decoder, cudaVideoCodec_AV1, if (!gst_nv_decoder_configure (self->decoder, cudaVideoCodec_AV1,
&info, self->max_width, self->max_height, self->bitdepth, &info, self->max_width, self->max_height, self->bitdepth,
max_dpb_size, self->film_grain_params_present ? TRUE : FALSE, max_dpb_size, self->film_grain_params_present ? TRUE : FALSE,
self->num_output_surfaces)) { self->num_output_surfaces, max_width, max_height)) {
GST_ERROR_OBJECT (self, "Failed to create decoder"); GST_ERROR_OBJECT (self, "Failed to create decoder");
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
@ -985,6 +1043,8 @@ gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id, guint rank,
gchar *type_name; gchar *type_name;
gchar *feature_name; gchar *feature_name;
guint index = 0; guint index = 0;
const GValue *value;
GstStructure *s;
GTypeInfo type_info = { GTypeInfo type_info = {
sizeof (GstNvAV1DecClass), sizeof (GstNvAV1DecClass),
nullptr, nullptr,
@ -1001,6 +1061,14 @@ gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id, guint rank,
GST_DEBUG_CATEGORY_INIT (gst_nv_av1_dec_debug, "nvav1dec", 0, "nvav1dec"); GST_DEBUG_CATEGORY_INIT (gst_nv_av1_dec_debug, "nvav1dec", 0, "nvav1dec");
cdata = g_new0 (GstNvDecoderClassData, 1); cdata = g_new0 (GstNvDecoderClassData, 1);
s = gst_caps_get_structure (sink_caps, 0);
value = gst_structure_get_value (s, "width");
cdata->max_width = (guint) gst_value_get_int_range_max (value);
value = gst_structure_get_value (s, "height");
cdata->max_height = (guint) gst_value_get_int_range_max (value);
cdata->sink_caps = gst_caps_ref (sink_caps); cdata->sink_caps = gst_caps_ref (sink_caps);
cdata->src_caps = gst_caps_ref (src_caps); cdata->src_caps = gst_caps_ref (src_caps);
cdata->cuda_device_id = device_id; cdata->cuda_device_id = device_id;

View file

@ -38,13 +38,14 @@ extern "C"
#define GST_CAT_DEFAULT gst_nv_decoder_debug #define GST_CAT_DEFAULT gst_nv_decoder_debug
GST_DEFINE_MINI_OBJECT_TYPE (GstNvDecSurface, gst_nv_dec_surface); GST_DEFINE_MINI_OBJECT_TYPE (GstNvDecSurface, gst_nv_dec_surface);
static GstNvDecSurface *gst_nv_dec_surface_new (void); static GstNvDecSurface *gst_nv_dec_surface_new (guint seq_num);
/* *INDENT-OFF* */ /* *INDENT-OFF* */
struct GstNvDecOutput struct GstNvDecOutput
{ {
GstNvDecObject *self = nullptr; GstNvDecObject *self = nullptr;
CUdeviceptr devptr = 0; CUdeviceptr devptr = 0;
guint seq_num = 0;
}; };
struct GstNvDecObjectPrivate struct GstNvDecObjectPrivate
@ -76,6 +77,8 @@ struct _GstNvDecObject
guint pool_size; guint pool_size;
guint num_mapped; guint num_mapped;
gboolean alloc_aux_frame; gboolean alloc_aux_frame;
guint plane_height;
guint seq_num;
}; };
static void gst_nv_dec_object_finalize (GObject * object); static void gst_nv_dec_object_finalize (GObject * object);
@ -160,9 +163,10 @@ gst_nv_dec_object_new (GstCudaContext * context,
self->create_info = *create_info; self->create_info = *create_info;
self->video_info = *video_info; self->video_info = *video_info;
self->pool_size = pool_size; self->pool_size = pool_size;
self->plane_height = create_info->ulTargetHeight;
for (guint i = 0; i < pool_size; i++) { for (guint i = 0; i < pool_size; i++) {
GstNvDecSurface *surf = gst_nv_dec_surface_new (); GstNvDecSurface *surf = gst_nv_dec_surface_new (0);
surf->index = i; surf->index = i;
@ -180,6 +184,73 @@ gst_nv_dec_object_new (GstCudaContext * context,
return self; return self;
} }
gboolean
gst_nv_dec_object_reconfigure (GstNvDecObject * object,
CUVIDRECONFIGUREDECODERINFO * reconfigure_info,
const GstVideoInfo * video_info, gboolean alloc_aux_frame)
{
GstNvDecObjectPrivate *priv = object->priv;
CUresult ret;
guint pool_size;
if (!gst_cuvid_can_reconfigure ())
return FALSE;
pool_size = reconfigure_info->ulNumDecodeSurfaces;
if (alloc_aux_frame)
pool_size /= 2;
std::lock_guard < std::mutex > lk (priv->lock);
if (!gst_cuda_context_push (object->context)) {
GST_ERROR_OBJECT (object, "Couldn't push context");
return FALSE;
}
ret = CuvidReconfigureDecoder (object->handle, reconfigure_info);
gst_cuda_context_pop (nullptr);
if (!gst_cuda_result (ret)) {
GST_ERROR_OBJECT (object, "Couldn't reconfigure decoder");
return FALSE;
}
if ((guint) priv->surface_queue.size () != object->pool_size) {
GST_WARNING_OBJECT (object, "Unused surfaces %u != pool size %u",
(guint) priv->surface_queue.size (), object->pool_size);
}
/* Release old surfaces and create new ones */
/* *INDENT-OFF* */
for (auto it : priv->surface_queue)
gst_nv_dec_surface_unref (it);
/* *INDENT-ON* */
priv->surface_queue.clear ();
object->pool_size = pool_size;
object->video_info = *video_info;
object->seq_num++;
object->plane_height = reconfigure_info->ulTargetHeight;
for (guint i = 0; i < pool_size; i++) {
GstNvDecSurface *surf = gst_nv_dec_surface_new (object->seq_num);
surf->index = i;
/* [0, pool_size - 1]: output picture
* [pool_size, pool_size * 2 - 1]: decoder output without film-grain,
* used for reference picture */
if (alloc_aux_frame)
surf->decode_frame_index = i + pool_size;
else
surf->decode_frame_index = i;
object->priv->surface_queue.push_back (surf);
}
return TRUE;
}
void void
gst_nv_dec_object_set_flushing (GstNvDecObject * object, gboolean flushing) gst_nv_dec_object_set_flushing (GstNvDecObject * object, gboolean flushing)
{ {
@ -381,7 +452,7 @@ gst_nv_dec_object_export_surface (GstNvDecObject * object,
GST_LOG_OBJECT (object, "Exporting surface %d", surface->index); GST_LOG_OBJECT (object, "Exporting surface %d", surface->index);
offset = surface->pitch * object->create_info.ulTargetHeight; offset = surface->pitch * object->plane_height;
info = object->video_info; info = object->video_info;
switch (GST_VIDEO_INFO_FORMAT (&info)) { switch (GST_VIDEO_INFO_FORMAT (&info)) {
@ -431,11 +502,21 @@ gst_nv_dec_object_export_surface (GstNvDecObject * object,
GST_LOG_OBJECT (object, "Waiting for output release"); GST_LOG_OBJECT (object, "Waiting for output release");
priv->cond.wait (lk); priv->cond.wait (lk);
} while (true); } while (true);
output = (GstNvDecOutput *)
gst_cuda_memory_get_user_data (GST_CUDA_MEMORY_CAST (mem));
if (output->seq_num != object->seq_num) {
GST_DEBUG_OBJECT (object,
"output belongs to previous sequence, need new memory");
gst_memory_unref (mem);
mem = nullptr;
}
} }
if (!mem) { if (!mem) {
output = new GstNvDecOutput (); output = new GstNvDecOutput ();
output->devptr = surface->devptr; output->devptr = surface->devptr;
output->seq_num = object->seq_num;
GST_LOG_OBJECT (object, "New output, allocating memory"); GST_LOG_OBJECT (object, "New output, allocating memory");
@ -469,6 +550,7 @@ gst_nv_dec_surface_dispose (GstNvDecSurface * surf)
{ {
GstNvDecObject *object; GstNvDecObject *object;
GstNvDecObjectPrivate *priv; GstNvDecObjectPrivate *priv;
gboolean ret = FALSE;
if (!surf->object) if (!surf->object)
return TRUE; return TRUE;
@ -476,34 +558,44 @@ gst_nv_dec_surface_dispose (GstNvDecSurface * surf)
object = (GstNvDecObject *) g_steal_pointer (&surf->object); object = (GstNvDecObject *) g_steal_pointer (&surf->object);
priv = object->priv; priv = object->priv;
/* Back to surface queue */
gst_nv_dec_surface_ref (surf);
/* *INDENT-OFF* */ /* *INDENT-OFF* */
{ {
std::lock_guard < std::mutex > lk (priv->lock); std::lock_guard < std::mutex > lk (priv->lock);
/* Keep sorted order */
priv->surface_queue.insert ( if (surf->seq_num == object->seq_num) {
std::upper_bound (priv->surface_queue.begin (), /* Back to surface queue */
priv->surface_queue.end(), surf, gst_nv_dec_surface_ref (surf);
[] (const GstNvDecSurface * a, const GstNvDecSurface * b)
{ /* Keep sorted order */
return a->index < b->index; priv->surface_queue.insert (
}), surf); std::upper_bound (priv->surface_queue.begin (),
priv->cond.notify_all (); priv->surface_queue.end(), surf,
[] (const GstNvDecSurface * a, const GstNvDecSurface * b)
{
return a->index < b->index;
}), surf);
priv->cond.notify_all ();
} else {
GST_WARNING_OBJECT (object, "Releasing surface %p of previous sequence",
surf);
/* Shouldn't happen (e.g., surfaces were not flushed before reconfigure) */
ret = TRUE;
}
} }
/* *INDENT-ON* */ /* *INDENT-ON* */
gst_object_unref (object); gst_object_unref (object);
return FALSE; return ret;
} }
static GstNvDecSurface * static GstNvDecSurface *
gst_nv_dec_surface_new (void) gst_nv_dec_surface_new (guint seq_num)
{ {
GstNvDecSurface *surf = g_new0 (GstNvDecSurface, 1); GstNvDecSurface *surf = g_new0 (GstNvDecSurface, 1);
surf->seq_num = seq_num;
gst_mini_object_init (GST_MINI_OBJECT_CAST (surf), gst_mini_object_init (GST_MINI_OBJECT_CAST (surf),
0, GST_TYPE_NV_DEC_SURFACE, nullptr, 0, GST_TYPE_NV_DEC_SURFACE, nullptr,
(GstMiniObjectDisposeFunction) gst_nv_dec_surface_dispose, (GstMiniObjectDisposeFunction) gst_nv_dec_surface_dispose,

View file

@ -44,6 +44,8 @@ struct _GstNvDecSurface
CUdeviceptr devptr; CUdeviceptr devptr;
guint pitch; guint pitch;
guint seq_num;
}; };
GstNvDecObject * gst_nv_dec_object_new (GstCudaContext * context, GstNvDecObject * gst_nv_dec_object_new (GstCudaContext * context,
@ -51,6 +53,11 @@ GstNvDecObject * gst_nv_dec_object_new (GstCudaContext * context,
const GstVideoInfo * video_info, const GstVideoInfo * video_info,
gboolean alloc_aux_frame); gboolean alloc_aux_frame);
gboolean gst_nv_dec_object_reconfigure (GstNvDecObject * object,
CUVIDRECONFIGUREDECODERINFO * reconfigure_info,
const GstVideoInfo * video_info,
gboolean alloc_aux_frame);
void gst_nv_dec_object_set_flushing (GstNvDecObject * object, void gst_nv_dec_object_set_flushing (GstNvDecObject * object,
gboolean flushing); gboolean flushing);

View file

@ -242,10 +242,10 @@ gboolean
gst_nv_decoder_configure (GstNvDecoder * decoder, cudaVideoCodec codec, gst_nv_decoder_configure (GstNvDecoder * decoder, cudaVideoCodec codec,
GstVideoInfo * info, gint coded_width, gint coded_height, GstVideoInfo * info, gint coded_width, gint coded_height,
guint coded_bitdepth, guint pool_size, gboolean alloc_aux_frame, guint coded_bitdepth, guint pool_size, gboolean alloc_aux_frame,
guint num_output_surfaces) guint num_output_surfaces, guint init_max_width, guint init_max_height)
{ {
CUVIDDECODECREATEINFO create_info = { 0, }; CUVIDDECODECREATEINFO create_info = { 0, };
GstVideoFormat format; GstVideoFormat format, prev_format = GST_VIDEO_FORMAT_UNKNOWN;
guint alloc_size; guint alloc_size;
g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE); g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE);
@ -256,15 +256,9 @@ gst_nv_decoder_configure (GstNvDecoder * decoder, cudaVideoCodec codec,
g_return_val_if_fail (coded_bitdepth >= 8, FALSE); g_return_val_if_fail (coded_bitdepth >= 8, FALSE);
g_return_val_if_fail (pool_size > 0, FALSE); g_return_val_if_fail (pool_size > 0, FALSE);
g_mutex_lock (&decoder->lock);
gst_nv_decoder_reset_unlocked (decoder);
g_mutex_unlock (&decoder->lock);
decoder->info = *info;
gst_video_info_set_format (&decoder->coded_info, GST_VIDEO_INFO_FORMAT (info),
coded_width, coded_height);
format = GST_VIDEO_INFO_FORMAT (info); format = GST_VIDEO_INFO_FORMAT (info);
if (decoder->info.finfo)
prev_format = GST_VIDEO_INFO_FORMAT (&decoder->info);
/* Additional 2 frame margin */ /* Additional 2 frame margin */
pool_size += 2; pool_size += 2;
@ -278,6 +272,56 @@ gst_nv_decoder_configure (GstNvDecoder * decoder, cudaVideoCodec codec,
alloc_size = pool_size; alloc_size = pool_size;
} }
decoder->info = *info;
gst_video_info_set_format (&decoder->coded_info, format,
coded_width, coded_height);
g_mutex_lock (&decoder->lock);
if (decoder->object) {
GST_DEBUG_OBJECT (decoder,
"Configured max resolution %ux%u %s (bit-depth %u), "
"new resolution %ux%u %s (bit-depth %u)",
(guint) decoder->create_info.ulMaxWidth,
(guint) decoder->create_info.ulMaxHeight,
gst_video_format_to_string (prev_format),
(guint) decoder->create_info.bitDepthMinus8 + 8,
(guint) coded_width, (guint) coded_height,
gst_video_format_to_string (format), coded_bitdepth);
if (format == prev_format &&
(guint) coded_width <= decoder->create_info.ulMaxWidth &&
(guint) coded_height <= decoder->create_info.ulMaxHeight &&
coded_bitdepth == (guint) decoder->create_info.bitDepthMinus8 + 8) {
CUVIDRECONFIGUREDECODERINFO reconfig_info = { 0, };
reconfig_info.ulWidth = GST_VIDEO_INFO_WIDTH (&decoder->coded_info);
reconfig_info.ulHeight = GST_VIDEO_INFO_HEIGHT (&decoder->coded_info);
reconfig_info.ulTargetWidth = GST_VIDEO_INFO_WIDTH (info);
reconfig_info.ulTargetHeight = GST_VIDEO_INFO_HEIGHT (info);
reconfig_info.ulNumDecodeSurfaces = alloc_size;
reconfig_info.display_area.right = GST_VIDEO_INFO_WIDTH (info);
reconfig_info.display_area.bottom = GST_VIDEO_INFO_HEIGHT (info);
reconfig_info.target_rect.right = GST_VIDEO_INFO_WIDTH (info);
reconfig_info.target_rect.bottom = GST_VIDEO_INFO_HEIGHT (info);
if (gst_nv_dec_object_reconfigure (decoder->object,
&reconfig_info, info, alloc_aux_frame)) {
GST_DEBUG_OBJECT (decoder, "Reconfigured");
decoder->configured = TRUE;
g_mutex_unlock (&decoder->lock);
return TRUE;
} else {
GST_WARNING_OBJECT (decoder,
"Couldn't reconfigure decoder, creating new decoder instance");
}
} else {
GST_DEBUG_OBJECT (decoder, "Need new decoder instance");
}
}
gst_nv_decoder_reset_unlocked (decoder);
g_mutex_unlock (&decoder->lock);
decoder->num_output_surfaces = num_output_surfaces; decoder->num_output_surfaces = num_output_surfaces;
create_info.ulWidth = GST_VIDEO_INFO_WIDTH (&decoder->coded_info); create_info.ulWidth = GST_VIDEO_INFO_WIDTH (&decoder->coded_info);
@ -306,6 +350,9 @@ gst_nv_decoder_configure (GstNvDecoder * decoder, cudaVideoCodec codec,
create_info.target_rect.right = GST_VIDEO_INFO_WIDTH (info); create_info.target_rect.right = GST_VIDEO_INFO_WIDTH (info);
create_info.target_rect.bottom = GST_VIDEO_INFO_HEIGHT (info); create_info.target_rect.bottom = GST_VIDEO_INFO_HEIGHT (info);
create_info.ulMaxWidth = MAX (create_info.ulWidth, init_max_width);
create_info.ulMaxHeight = MAX (create_info.ulHeight, init_max_height);
decoder->create_info = create_info; decoder->create_info = create_info;
decoder->configured = TRUE; decoder->configured = TRUE;
@ -1609,3 +1656,15 @@ gst_nv_decoder_reset (GstNvDecoder * decoder)
gst_nv_decoder_reset_unlocked (decoder); gst_nv_decoder_reset_unlocked (decoder);
g_mutex_unlock (&decoder->lock); g_mutex_unlock (&decoder->lock);
} }
guint
gst_nv_decoder_get_max_output_size (guint coded_size, guint user_requested,
guint device_max)
{
if (user_requested <= coded_size)
return coded_size;
user_requested = GST_ROUND_UP_16 (user_requested);
return MIN (user_requested, device_max);
}

View file

@ -37,6 +37,8 @@ typedef struct _GstNvDecoderClassData
GstCaps *sink_caps; GstCaps *sink_caps;
GstCaps *src_caps; GstCaps *src_caps;
guint cuda_device_id; guint cuda_device_id;
guint max_width;
guint max_height;
} GstNvDecoderClassData; } GstNvDecoderClassData;
GstNvDecoder * gst_nv_decoder_new (GstCudaContext * context); GstNvDecoder * gst_nv_decoder_new (GstCudaContext * context);
@ -51,7 +53,9 @@ gboolean gst_nv_decoder_configure (GstNvDecoder * decoder,
guint coded_bitdepth, guint coded_bitdepth,
guint pool_size, guint pool_size,
gboolean alloc_aux_frame, gboolean alloc_aux_frame,
guint num_output_surfaces); guint num_output_surfaces,
guint init_max_width,
guint init_max_height);
GstFlowReturn gst_nv_decoder_acquire_surface (GstNvDecoder * decoder, GstFlowReturn gst_nv_decoder_acquire_surface (GstNvDecoder * decoder,
GstNvDecSurface ** surface); GstNvDecSurface ** surface);
@ -95,6 +99,10 @@ gboolean gst_nv_decoder_decide_allocation (GstNvDecoder * decoder,
GstVideoDecoder * videodec, GstVideoDecoder * videodec,
GstQuery * query); GstQuery * query);
guint gst_nv_decoder_get_max_output_size (guint coded_size,
guint user_requested,
guint device_max);
G_END_DECLS G_END_DECLS
#endif /* __GST_NV_DECODER_H__ */ #endif /* __GST_NV_DECODER_H__ */

View file

@ -127,12 +127,16 @@ typedef struct _GstNvH264Dec
GArray *ref_list; GArray *ref_list;
guint num_output_surfaces; guint num_output_surfaces;
guint init_max_width;
guint init_max_height;
} GstNvH264Dec; } GstNvH264Dec;
typedef struct _GstNvH264DecClass typedef struct _GstNvH264DecClass
{ {
GstH264DecoderClass parent_class; GstH264DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
guint max_width;
guint max_height;
} GstNvH264DecClass; } GstNvH264DecClass;
enum enum
@ -140,6 +144,8 @@ enum
PROP_0, PROP_0,
PROP_CUDA_DEVICE_ID, PROP_CUDA_DEVICE_ID,
PROP_NUM_OUTPUT_SURFACES, PROP_NUM_OUTPUT_SURFACES,
PROP_INIT_MAX_WIDTH,
PROP_INIT_MAX_HEIGHT,
}; };
#define DEFAULT_NUM_OUTPUT_SURFACES 0 #define DEFAULT_NUM_OUTPUT_SURFACES 0
@ -232,6 +238,38 @@ gst_nv_h264_dec_class_init (GstNvH264DecClass * klass,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | (GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS))); G_PARAM_STATIC_STRINGS)));
/**
* GstNvH264SLDec:init-max-width:
*
* Initial CUVIDDECODECREATEINFO.ulMaxWidth value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_WIDTH,
g_param_spec_uint ("init-max-width", "Initial Maximum Width",
"Expected maximum coded width of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_width, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
/**
* GstNvH264SLDec:init-max-height:
*
* Initial CUVIDDECODECREATEINFO.ulMaxHeight value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_HEIGHT,
g_param_spec_uint ("init-max-height", "Initial Maximum Height",
"Expected maximum coded height of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_height, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_h264_dec_set_context); element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_h264_dec_set_context);
parent_class = (GTypeClass *) g_type_class_peek_parent (klass); parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
@ -274,6 +312,8 @@ gst_nv_h264_dec_class_init (GstNvH264DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_h264_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_h264_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height;
gst_caps_unref (cdata->sink_caps); gst_caps_unref (cdata->sink_caps);
gst_caps_unref (cdata->src_caps); gst_caps_unref (cdata->src_caps);
@ -311,6 +351,12 @@ gst_nv_h264_dec_set_property (GObject * object, guint prop_id,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
self->num_output_surfaces = g_value_get_uint (value); self->num_output_surfaces = g_value_get_uint (value);
break; break;
case PROP_INIT_MAX_WIDTH:
self->init_max_width = g_value_get_uint (value);
break;
case PROP_INIT_MAX_HEIGHT:
self->init_max_height = g_value_get_uint (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -331,6 +377,12 @@ gst_nv_h264_dec_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
g_value_set_uint (value, self->num_output_surfaces); g_value_set_uint (value, self->num_output_surfaces);
break; break;
case PROP_INIT_MAX_WIDTH:
g_value_set_uint (value, self->init_max_width);
break;
case PROP_INIT_MAX_HEIGHT:
g_value_set_uint (value, self->init_max_height);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -507,9 +559,11 @@ gst_nv_h264_dec_new_sequence (GstH264Decoder * decoder, const GstH264SPS * sps,
gint max_dpb_size) gint max_dpb_size)
{ {
GstNvH264Dec *self = GST_NV_H264_DEC (decoder); GstNvH264Dec *self = GST_NV_H264_DEC (decoder);
GstNvH264DecClass *klass = GST_NV_H264_DEC_GET_CLASS (self);
guint crop_width, crop_height; guint crop_width, crop_height;
gboolean modified = FALSE; gboolean modified = FALSE;
gboolean interlaced; gboolean interlaced;
guint max_width, max_height;
GST_LOG_OBJECT (self, "new sequence"); GST_LOG_OBJECT (self, "new sequence");
@ -587,10 +641,16 @@ gst_nv_h264_dec_new_sequence (GstH264Decoder * decoder, const GstH264SPS * sps,
GST_VIDEO_INFO_INTERLACE_MODE (&info) = GST_VIDEO_INTERLACE_MODE_MIXED; GST_VIDEO_INFO_INTERLACE_MODE (&info) = GST_VIDEO_INTERLACE_MODE_MIXED;
self->max_dpb_size = max_dpb_size; self->max_dpb_size = max_dpb_size;
max_width = gst_nv_decoder_get_max_output_size (self->coded_width,
self->init_max_width, klass->max_width);
max_height = gst_nv_decoder_get_max_output_size (self->coded_height,
self->init_max_height, klass->max_height);
/* FIXME: add support cudaVideoCodec_H264_SVC and cudaVideoCodec_H264_MVC */ /* FIXME: add support cudaVideoCodec_H264_SVC and cudaVideoCodec_H264_MVC */
if (!gst_nv_decoder_configure (self->decoder, if (!gst_nv_decoder_configure (self->decoder,
cudaVideoCodec_H264, &info, self->coded_width, self->coded_height, cudaVideoCodec_H264, &info, self->coded_width, self->coded_height,
self->bitdepth, max_dpb_size, FALSE, self->num_output_surfaces)) { self->bitdepth, max_dpb_size, FALSE, self->num_output_surfaces,
max_width, max_height)) {
GST_ERROR_OBJECT (self, "Failed to configure decoder"); GST_ERROR_OBJECT (self, "Failed to configure decoder");
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
@ -1064,9 +1124,11 @@ gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id, guint rank,
s = gst_caps_get_structure (sink_caps, 0); s = gst_caps_get_structure (sink_caps, 0);
value = gst_structure_get_value (s, "width"); value = gst_structure_get_value (s, "width");
cdata->max_width = (guint) gst_value_get_int_range_max (value);
gst_caps_set_value (cdata->sink_caps, "width", value); gst_caps_set_value (cdata->sink_caps, "width", value);
value = gst_structure_get_value (s, "height"); value = gst_structure_get_value (s, "height");
cdata->max_height = (guint) gst_value_get_int_range_max (value);
gst_caps_set_value (cdata->sink_caps, "height", value); gst_caps_set_value (cdata->sink_caps, "height", value);
GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps, GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,

View file

@ -123,12 +123,16 @@ typedef struct _GstNvH265Dec
guint chroma_format_idc; guint chroma_format_idc;
guint num_output_surfaces; guint num_output_surfaces;
guint init_max_width;
guint init_max_height;
} GstNvH265Dec; } GstNvH265Dec;
typedef struct _GstNvH265DecClass typedef struct _GstNvH265DecClass
{ {
GstH265DecoderClass parent_class; GstH265DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
guint max_width;
guint max_height;
} GstNvH265DecClass; } GstNvH265DecClass;
enum enum
@ -136,6 +140,8 @@ enum
PROP_0, PROP_0,
PROP_CUDA_DEVICE_ID, PROP_CUDA_DEVICE_ID,
PROP_NUM_OUTPUT_SURFACES, PROP_NUM_OUTPUT_SURFACES,
PROP_INIT_MAX_WIDTH,
PROP_INIT_MAX_HEIGHT,
}; };
#define DEFAULT_NUM_OUTPUT_SURFACES 0 #define DEFAULT_NUM_OUTPUT_SURFACES 0
@ -223,6 +229,38 @@ gst_nv_h265_dec_class_init (GstNvH265DecClass * klass,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | (GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS))); G_PARAM_STATIC_STRINGS)));
/**
* GstNvH265SLDec:init-max-width:
*
* Initial CUVIDDECODECREATEINFO.ulMaxWidth value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_WIDTH,
g_param_spec_uint ("init-max-width", "Initial Maximum Width",
"Expected maximum coded width of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_width, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
/**
* GstNvH265SLDec:init-max-height:
*
* Initial CUVIDDECODECREATEINFO.ulMaxHeight value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_HEIGHT,
g_param_spec_uint ("init-max-height", "Initial Maximum Height",
"Expected maximum coded height of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_height, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_h265_dec_set_context); element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_h265_dec_set_context);
parent_class = (GTypeClass *) g_type_class_peek_parent (klass); parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
@ -263,6 +301,8 @@ gst_nv_h265_dec_class_init (GstNvH265DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_h265_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_h265_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height;
gst_caps_unref (cdata->sink_caps); gst_caps_unref (cdata->sink_caps);
gst_caps_unref (cdata->src_caps); gst_caps_unref (cdata->src_caps);
@ -285,6 +325,12 @@ gst_nv_h265_dec_set_property (GObject * object, guint prop_id,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
self->num_output_surfaces = g_value_get_uint (value); self->num_output_surfaces = g_value_get_uint (value);
break; break;
case PROP_INIT_MAX_WIDTH:
self->init_max_width = g_value_get_uint (value);
break;
case PROP_INIT_MAX_HEIGHT:
self->init_max_height = g_value_get_uint (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -305,6 +351,12 @@ gst_nv_h265_dec_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
g_value_set_uint (value, self->num_output_surfaces); g_value_set_uint (value, self->num_output_surfaces);
break; break;
case PROP_INIT_MAX_WIDTH:
g_value_set_uint (value, self->init_max_width);
break;
case PROP_INIT_MAX_HEIGHT:
g_value_set_uint (value, self->init_max_height);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -465,8 +517,10 @@ gst_nv_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
gint max_dpb_size) gint max_dpb_size)
{ {
GstNvH265Dec *self = GST_NV_H265_DEC (decoder); GstNvH265Dec *self = GST_NV_H265_DEC (decoder);
GstNvH265DecClass *klass = GST_NV_H265_DEC_GET_CLASS (self);
guint crop_width, crop_height; guint crop_width, crop_height;
gboolean modified = FALSE; gboolean modified = FALSE;
guint max_width, max_height;
GST_LOG_OBJECT (self, "new sequence"); GST_LOG_OBJECT (self, "new sequence");
@ -541,9 +595,15 @@ gst_nv_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps,
gst_video_info_set_format (&info, out_format, GST_ROUND_UP_2 (self->width), gst_video_info_set_format (&info, out_format, GST_ROUND_UP_2 (self->width),
GST_ROUND_UP_2 (self->height)); GST_ROUND_UP_2 (self->height));
max_width = gst_nv_decoder_get_max_output_size (self->coded_width,
self->init_max_width, klass->max_width);
max_height = gst_nv_decoder_get_max_output_size (self->coded_height,
self->init_max_height, klass->max_height);
if (!gst_nv_decoder_configure (self->decoder, if (!gst_nv_decoder_configure (self->decoder,
cudaVideoCodec_HEVC, &info, self->coded_width, self->coded_height, cudaVideoCodec_HEVC, &info, self->coded_width, self->coded_height,
self->bitdepth, max_dpb_size, FALSE, self->num_output_surfaces)) { self->bitdepth, max_dpb_size, FALSE, self->num_output_surfaces,
max_width, max_height)) {
GST_ERROR_OBJECT (self, "Failed to configure decoder"); GST_ERROR_OBJECT (self, "Failed to configure decoder");
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
@ -1081,6 +1141,8 @@ gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, guint rank,
gint index = 0; gint index = 0;
GValue value_list = G_VALUE_INIT; GValue value_list = G_VALUE_INIT;
GValue value = G_VALUE_INIT; GValue value = G_VALUE_INIT;
GstStructure *s;
const GValue *res_val;
GTypeInfo type_info = { GTypeInfo type_info = {
sizeof (GstNvH265DecClass), sizeof (GstNvH265DecClass),
nullptr, nullptr,
@ -1098,6 +1160,13 @@ gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, guint rank,
cdata = g_new0 (GstNvDecoderClassData, 1); cdata = g_new0 (GstNvDecoderClassData, 1);
cdata->sink_caps = gst_caps_copy (sink_caps); cdata->sink_caps = gst_caps_copy (sink_caps);
s = gst_caps_get_structure (sink_caps, 0);
res_val = gst_structure_get_value (s, "width");
cdata->max_width = (guint) gst_value_get_int_range_max (res_val);
res_val = gst_structure_get_value (s, "height");
cdata->max_height = (guint) gst_value_get_int_range_max (res_val);
/* Update stream-format since we support packetized format as well */ /* Update stream-format since we support packetized format as well */
g_value_init (&value_list, GST_TYPE_LIST); g_value_init (&value_list, GST_TYPE_LIST);
g_value_init (&value, G_TYPE_STRING); g_value_init (&value, G_TYPE_STRING);

View file

@ -55,12 +55,16 @@ typedef struct _GstNvVp8Dec
guint width, height; guint width, height;
guint num_output_surfaces; guint num_output_surfaces;
guint init_max_width;
guint init_max_height;
} GstNvVp8Dec; } GstNvVp8Dec;
typedef struct _GstNvVp8DecClass typedef struct _GstNvVp8DecClass
{ {
GstVp8DecoderClass parent_class; GstVp8DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
guint max_width;
guint max_height;
} GstNvVp8DecClass; } GstNvVp8DecClass;
enum enum
@ -68,6 +72,8 @@ enum
PROP_0, PROP_0,
PROP_CUDA_DEVICE_ID, PROP_CUDA_DEVICE_ID,
PROP_NUM_OUTPUT_SURFACES, PROP_NUM_OUTPUT_SURFACES,
PROP_INIT_MAX_WIDTH,
PROP_INIT_MAX_HEIGHT,
}; };
#define DEFAULT_NUM_OUTPUT_SURFACES 0 #define DEFAULT_NUM_OUTPUT_SURFACES 0
@ -149,6 +155,38 @@ gst_nv_vp8_dec_class_init (GstNvVp8DecClass * klass,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | (GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS))); G_PARAM_STATIC_STRINGS)));
/**
* GstNvVp8SLDec:init-max-width:
*
* Initial CUVIDDECODECREATEINFO.ulMaxWidth value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_WIDTH,
g_param_spec_uint ("init-max-width", "Initial Maximum Width",
"Expected maximum coded width of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_width, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
/**
* GstNvVp8SLDec:init-max-height:
*
* Initial CUVIDDECODECREATEINFO.ulMaxHeight value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_HEIGHT,
g_param_spec_uint ("init-max-height", "Initial Maximum Height",
"Expected maximum coded height of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_height, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_set_context); element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_set_context);
parent_class = (GTypeClass *) g_type_class_peek_parent (klass); parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
@ -185,6 +223,8 @@ gst_nv_vp8_dec_class_init (GstNvVp8DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height;
gst_caps_unref (cdata->sink_caps); gst_caps_unref (cdata->sink_caps);
gst_caps_unref (cdata->src_caps); gst_caps_unref (cdata->src_caps);
@ -207,6 +247,12 @@ gst_nv_vp8_dec_set_property (GObject * object, guint prop_id,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
self->num_output_surfaces = g_value_get_uint (value); self->num_output_surfaces = g_value_get_uint (value);
break; break;
case PROP_INIT_MAX_WIDTH:
self->init_max_width = g_value_get_uint (value);
break;
case PROP_INIT_MAX_HEIGHT:
self->init_max_height = g_value_get_uint (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -227,6 +273,12 @@ gst_nv_vp8_dec_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
g_value_set_uint (value, self->num_output_surfaces); g_value_set_uint (value, self->num_output_surfaces);
break; break;
case PROP_INIT_MAX_WIDTH:
g_value_set_uint (value, self->init_max_width);
break;
case PROP_INIT_MAX_HEIGHT:
g_value_set_uint (value, self->init_max_height);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -381,7 +433,9 @@ gst_nv_vp8_dec_new_sequence (GstVp8Decoder * decoder,
const GstVp8FrameHdr * frame_hdr, gint max_dpb_size) const GstVp8FrameHdr * frame_hdr, gint max_dpb_size)
{ {
GstNvVp8Dec *self = GST_NV_VP8_DEC (decoder); GstNvVp8Dec *self = GST_NV_VP8_DEC (decoder);
GstNvVp8DecClass *klass = GST_NV_VP8_DEC_GET_CLASS (self);
gboolean modified = FALSE; gboolean modified = FALSE;
guint max_width, max_height;
GST_LOG_OBJECT (self, "new sequence"); GST_LOG_OBJECT (self, "new sequence");
@ -404,9 +458,15 @@ gst_nv_vp8_dec_new_sequence (GstVp8Decoder * decoder,
GST_VIDEO_FORMAT_NV12, GST_ROUND_UP_2 (self->width), GST_VIDEO_FORMAT_NV12, GST_ROUND_UP_2 (self->width),
GST_ROUND_UP_2 (self->height)); GST_ROUND_UP_2 (self->height));
max_width = gst_nv_decoder_get_max_output_size (self->width,
self->init_max_width, klass->max_width);
max_height = gst_nv_decoder_get_max_output_size (self->height,
self->init_max_height, klass->max_height);
if (!gst_nv_decoder_configure (self->decoder, if (!gst_nv_decoder_configure (self->decoder,
cudaVideoCodec_VP8, &info, self->width, self->height, 8, cudaVideoCodec_VP8, &info, self->width, self->height, 8,
max_dpb_size, FALSE, self->num_output_surfaces)) { max_dpb_size, FALSE, self->num_output_surfaces, max_width,
max_height)) {
GST_ERROR_OBJECT (self, "Failed to configure decoder"); GST_ERROR_OBJECT (self, "Failed to configure decoder");
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
@ -600,6 +660,8 @@ gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id, guint rank,
gchar *feature_name; gchar *feature_name;
GstNvDecoderClassData *cdata; GstNvDecoderClassData *cdata;
gint index = 0; gint index = 0;
const GValue *value;
GstStructure *s;
GTypeInfo type_info = { GTypeInfo type_info = {
sizeof (GstNvVp8DecClass), sizeof (GstNvVp8DecClass),
nullptr, nullptr,
@ -615,6 +677,14 @@ gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id, guint rank,
GST_DEBUG_CATEGORY_INIT (gst_nv_vp8_dec_debug, "nvvp8dec", 0, "nvvp8dec"); GST_DEBUG_CATEGORY_INIT (gst_nv_vp8_dec_debug, "nvvp8dec", 0, "nvvp8dec");
cdata = g_new0 (GstNvDecoderClassData, 1); cdata = g_new0 (GstNvDecoderClassData, 1);
s = gst_caps_get_structure (sink_caps, 0);
value = gst_structure_get_value (s, "width");
cdata->max_width = (guint) gst_value_get_int_range_max (value);
value = gst_structure_get_value (s, "height");
cdata->max_height = (guint) gst_value_get_int_range_max (value);
cdata->sink_caps = gst_caps_ref (sink_caps); cdata->sink_caps = gst_caps_ref (sink_caps);
cdata->src_caps = gst_caps_ref (src_caps); cdata->src_caps = gst_caps_ref (src_caps);
cdata->cuda_device_id = device_id; cdata->cuda_device_id = device_id;

View file

@ -56,12 +56,16 @@ typedef struct _GstNvVp9Dec
GstVP9Profile profile; GstVP9Profile profile;
guint num_output_surfaces; guint num_output_surfaces;
guint init_max_width;
guint init_max_height;
} GstNvVp9Dec; } GstNvVp9Dec;
typedef struct _GstNvVp9DecClass typedef struct _GstNvVp9DecClass
{ {
GstVp9DecoderClass parent_class; GstVp9DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
guint max_width;
guint max_height;
} GstNvVp9DecClass; } GstNvVp9DecClass;
enum enum
@ -69,6 +73,8 @@ enum
PROP_0, PROP_0,
PROP_CUDA_DEVICE_ID, PROP_CUDA_DEVICE_ID,
PROP_NUM_OUTPUT_SURFACES, PROP_NUM_OUTPUT_SURFACES,
PROP_INIT_MAX_WIDTH,
PROP_INIT_MAX_HEIGHT,
}; };
#define DEFAULT_NUM_OUTPUT_SURFACES 0 #define DEFAULT_NUM_OUTPUT_SURFACES 0
@ -152,6 +158,38 @@ gst_nv_vp9_dec_class_init (GstNvVp9DecClass * klass,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | (GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS))); G_PARAM_STATIC_STRINGS)));
/**
* GstNvVp9SLDec:init-max-width:
*
* Initial CUVIDDECODECREATEINFO.ulMaxWidth value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_WIDTH,
g_param_spec_uint ("init-max-width", "Initial Maximum Width",
"Expected maximum coded width of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_width, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
/**
* GstNvVp9SLDec:init-max-height:
*
* Initial CUVIDDECODECREATEINFO.ulMaxHeight value
*
* Since: 1.24
*/
g_object_class_install_property (object_class, PROP_INIT_MAX_HEIGHT,
g_param_spec_uint ("init-max-height", "Initial Maximum Height",
"Expected maximum coded height of stream. This value is used to "
"pre-allocate higher dimension of output surfaces than "
"that of input stream, in order to help decoder reconfiguration",
0, cdata->max_height, 0,
(GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)));
element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_set_context); element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_set_context);
parent_class = (GTypeClass *) g_type_class_peek_parent (klass); parent_class = (GTypeClass *) g_type_class_peek_parent (klass);
@ -190,6 +228,8 @@ gst_nv_vp9_dec_class_init (GstNvVp9DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height;
gst_caps_unref (cdata->sink_caps); gst_caps_unref (cdata->sink_caps);
gst_caps_unref (cdata->src_caps); gst_caps_unref (cdata->src_caps);
@ -212,6 +252,12 @@ gst_nv_vp9_dec_set_property (GObject * object, guint prop_id,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
self->num_output_surfaces = g_value_get_uint (value); self->num_output_surfaces = g_value_get_uint (value);
break; break;
case PROP_INIT_MAX_WIDTH:
self->init_max_width = g_value_get_uint (value);
break;
case PROP_INIT_MAX_HEIGHT:
self->init_max_height = g_value_get_uint (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -232,6 +278,12 @@ gst_nv_vp9_dec_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_NUM_OUTPUT_SURFACES: case PROP_NUM_OUTPUT_SURFACES:
g_value_set_uint (value, self->num_output_surfaces); g_value_set_uint (value, self->num_output_surfaces);
break; break;
case PROP_INIT_MAX_WIDTH:
g_value_set_uint (value, self->init_max_width);
break;
case PROP_INIT_MAX_HEIGHT:
g_value_set_uint (value, self->init_max_height);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -391,8 +443,10 @@ gst_nv_vp9_dec_new_sequence (GstVp9Decoder * decoder,
const GstVp9FrameHeader * frame_hdr, gint max_dpb_size) const GstVp9FrameHeader * frame_hdr, gint max_dpb_size)
{ {
GstNvVp9Dec *self = GST_NV_VP9_DEC (decoder); GstNvVp9Dec *self = GST_NV_VP9_DEC (decoder);
GstNvVp9DecClass *klass = GST_NV_VP9_DEC_GET_CLASS (self);
GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN; GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN;
GstVideoInfo info; GstVideoInfo info;
guint max_width, max_height;
GST_LOG_OBJECT (self, "new sequence"); GST_LOG_OBJECT (self, "new sequence");
@ -417,10 +471,16 @@ gst_nv_vp9_dec_new_sequence (GstVp9Decoder * decoder,
gst_video_info_set_format (&info, out_format, GST_ROUND_UP_2 (self->width), gst_video_info_set_format (&info, out_format, GST_ROUND_UP_2 (self->width),
GST_ROUND_UP_2 (self->height)); GST_ROUND_UP_2 (self->height));
max_width = gst_nv_decoder_get_max_output_size (self->width,
self->init_max_width, klass->max_width);
max_height = gst_nv_decoder_get_max_output_size (self->height,
self->init_max_height, klass->max_height);
if (!gst_nv_decoder_configure (self->decoder, if (!gst_nv_decoder_configure (self->decoder,
cudaVideoCodec_VP9, &info, self->width, self->height, cudaVideoCodec_VP9, &info, self->width, self->height,
frame_hdr->bit_depth, max_dpb_size, FALSE, frame_hdr->bit_depth, max_dpb_size, FALSE,
self->num_output_surfaces)) { self->num_output_surfaces, max_width, max_height)) {
GST_ERROR_OBJECT (self, "Failed to configure decoder"); GST_ERROR_OBJECT (self, "Failed to configure decoder");
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
@ -696,6 +756,8 @@ gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, guint rank,
gchar *feature_name; gchar *feature_name;
GstNvDecoderClassData *cdata; GstNvDecoderClassData *cdata;
gint index = 0; gint index = 0;
const GValue *value;
GstStructure *s;
GTypeInfo type_info = { GTypeInfo type_info = {
sizeof (GstNvVp9DecClass), sizeof (GstNvVp9DecClass),
nullptr, nullptr,
@ -711,6 +773,14 @@ gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, guint rank,
GST_DEBUG_CATEGORY_INIT (gst_nv_vp9_dec_debug, "nvvp9dec", 0, "nvvp9dec"); GST_DEBUG_CATEGORY_INIT (gst_nv_vp9_dec_debug, "nvvp9dec", 0, "nvvp9dec");
cdata = g_new0 (GstNvDecoderClassData, 1); cdata = g_new0 (GstNvDecoderClassData, 1);
s = gst_caps_get_structure (sink_caps, 0);
value = gst_structure_get_value (s, "width");
cdata->max_width = (guint) gst_value_get_int_range_max (value);
value = gst_structure_get_value (s, "height");
cdata->max_height = (guint) gst_value_get_int_range_max (value);
cdata->sink_caps = gst_caps_copy (sink_caps); cdata->sink_caps = gst_caps_copy (sink_caps);
gst_caps_set_simple (cdata->sink_caps, gst_caps_set_simple (cdata->sink_caps,
"alignment", G_TYPE_STRING, "frame", nullptr); "alignment", G_TYPE_STRING, "frame", nullptr);