mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
applemedia: vtdec: improve negotiation
Rework negotiation implementing GstVideoDecoder::negotiate. Make it possible to switch texture sharing on and off at runtime. Useful to (eventually) turn texture sharing on in pipelines where glimagesink is linked only after decoding has already started (for example OWR).
This commit is contained in:
parent
8f14882b44
commit
119e09eac3
2 changed files with 111 additions and 102 deletions
|
@ -59,8 +59,7 @@ static void gst_vtdec_finalize (GObject * object);
|
|||
|
||||
static gboolean gst_vtdec_start (GstVideoDecoder * decoder);
|
||||
static gboolean gst_vtdec_stop (GstVideoDecoder * decoder);
|
||||
static gboolean gst_vtdec_decide_allocation (GstVideoDecoder * decoder,
|
||||
GstQuery * query);
|
||||
static gboolean gst_vtdec_negotiate (GstVideoDecoder * decoder);
|
||||
static gboolean gst_vtdec_set_format (GstVideoDecoder * decoder,
|
||||
GstVideoCodecState * state);
|
||||
static gboolean gst_vtdec_flush (GstVideoDecoder * decoder);
|
||||
|
@ -123,7 +122,7 @@ CFSTR ("RequireHardwareAcceleratedVideoDecoder");
|
|||
"height = " GST_VIDEO_SIZE_RANGE ", " \
|
||||
"framerate = " GST_VIDEO_FPS_RANGE ", " \
|
||||
"texture-target = (string) 2D " \
|
||||
" ; " \
|
||||
" ; " \
|
||||
GST_VIDEO_CAPS_MAKE(GST_VTDEC_VIDEO_FORMAT_STR) ";"
|
||||
#else
|
||||
#define VIDEO_SRC_CAPS \
|
||||
|
@ -156,8 +155,7 @@ gst_vtdec_class_init (GstVtdecClass * klass)
|
|||
gobject_class->finalize = gst_vtdec_finalize;
|
||||
video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_vtdec_start);
|
||||
video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vtdec_stop);
|
||||
video_decoder_class->decide_allocation =
|
||||
GST_DEBUG_FUNCPTR (gst_vtdec_decide_allocation);
|
||||
video_decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_vtdec_negotiate);
|
||||
video_decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_vtdec_set_format);
|
||||
video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vtdec_flush);
|
||||
video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_vtdec_finish);
|
||||
|
@ -199,6 +197,10 @@ gst_vtdec_stop (GstVideoDecoder * decoder)
|
|||
{
|
||||
GstVtdec *vtdec = GST_VTDEC (decoder);
|
||||
|
||||
if (vtdec->input_state)
|
||||
gst_video_codec_state_unref (vtdec->input_state);
|
||||
vtdec->input_state = NULL;
|
||||
|
||||
if (vtdec->session)
|
||||
gst_vtdec_invalidate_session (vtdec);
|
||||
|
||||
|
@ -211,112 +213,112 @@ gst_vtdec_stop (GstVideoDecoder * decoder)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vtdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
|
||||
static GstGLContext *
|
||||
query_gl_context (GstVtdec * vtdec)
|
||||
{
|
||||
gboolean ret;
|
||||
GstCaps *caps;
|
||||
GstCapsFeatures *features;
|
||||
GstVtdec *vtdec = GST_VTDEC (decoder);
|
||||
GstGLContext *gl_context = NULL;
|
||||
GstContext *context = NULL;
|
||||
GstQuery *query;
|
||||
|
||||
ret =
|
||||
GST_VIDEO_DECODER_CLASS (gst_vtdec_parent_class)->decide_allocation
|
||||
(decoder, query);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
gst_query_parse_allocation (query, &caps, NULL);
|
||||
if (caps) {
|
||||
GstGLContext *gl_context = NULL;
|
||||
features = gst_caps_get_features (caps, 0);
|
||||
|
||||
if (gst_caps_features_contains (features,
|
||||
GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
|
||||
GstContext *context = NULL;
|
||||
GstQuery *query = gst_query_new_context ("gst.gl.local_context");
|
||||
if (gst_pad_peer_query (GST_VIDEO_DECODER_SRC_PAD (decoder), query)) {
|
||||
|
||||
gst_query_parse_context (query, &context);
|
||||
if (context) {
|
||||
const GstStructure *s = gst_context_get_structure (context);
|
||||
gst_structure_get (s, "context", GST_GL_TYPE_CONTEXT, &gl_context,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
gst_query_unref (query);
|
||||
|
||||
if (context) {
|
||||
GstVideoFormat internal_format;
|
||||
GstVideoCodecState *output_state =
|
||||
gst_video_decoder_get_output_state (decoder);
|
||||
|
||||
GST_INFO_OBJECT (decoder, "pushing textures. GL context %p", context);
|
||||
if (vtdec->texture_cache)
|
||||
gst_core_video_texture_cache_free (vtdec->texture_cache);
|
||||
|
||||
#ifdef HAVE_IOS
|
||||
internal_format = GST_VIDEO_FORMAT_NV12;
|
||||
#else
|
||||
internal_format = GST_VIDEO_FORMAT_UYVY;
|
||||
#endif
|
||||
vtdec->texture_cache = gst_core_video_texture_cache_new (gl_context);
|
||||
gst_core_video_texture_cache_set_format (vtdec->texture_cache,
|
||||
internal_format, output_state->caps);
|
||||
gst_video_codec_state_unref (output_state);
|
||||
gst_object_unref (gl_context);
|
||||
} else {
|
||||
GST_WARNING_OBJECT (decoder,
|
||||
"got memory:GLMemory caps but not GL context from downstream element");
|
||||
}
|
||||
query = gst_query_new_context ("gst.gl.local_context");
|
||||
if (gst_pad_peer_query (GST_VIDEO_DECODER_SRC_PAD (vtdec), query)) {
|
||||
gst_query_parse_context (query, &context);
|
||||
if (context) {
|
||||
const GstStructure *s = gst_context_get_structure (context);
|
||||
gst_structure_get (s, "context", GST_GL_TYPE_CONTEXT, &gl_context, NULL);
|
||||
}
|
||||
}
|
||||
gst_query_unref (query);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return gl_context;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_texture_cache (GstVtdec * vtdec, GstGLContext * context)
|
||||
{
|
||||
GstVideoFormat internal_format;
|
||||
GstVideoCodecState *output_state =
|
||||
gst_video_decoder_get_output_state (GST_VIDEO_DECODER (vtdec));
|
||||
|
||||
GST_INFO_OBJECT (vtdec, "pushing textures. GL context %p", context);
|
||||
if (vtdec->texture_cache)
|
||||
gst_core_video_texture_cache_free (vtdec->texture_cache);
|
||||
|
||||
#ifdef HAVE_IOS
|
||||
internal_format = GST_VIDEO_FORMAT_NV12;
|
||||
#else
|
||||
internal_format = GST_VIDEO_FORMAT_UYVY;
|
||||
#endif
|
||||
vtdec->texture_cache = gst_core_video_texture_cache_new (context);
|
||||
gst_core_video_texture_cache_set_format (vtdec->texture_cache,
|
||||
internal_format, output_state->caps);
|
||||
gst_video_codec_state_unref (output_state);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vtdec_negotiate_output_format (GstVtdec * vtdec,
|
||||
GstVideoCodecState * input_state)
|
||||
caps_filter_out_gl_memory (GstCapsFeatures * features, GstStructure * structure,
|
||||
gpointer user_data)
|
||||
{
|
||||
return !gst_caps_features_contains (features,
|
||||
GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vtdec_negotiate (GstVideoDecoder * decoder)
|
||||
{
|
||||
GstCaps *caps = NULL, *peercaps = NULL, *templcaps;
|
||||
GstVideoFormat output_format;
|
||||
GstVideoCodecState *output_state = NULL;
|
||||
GstCapsFeatures *features;
|
||||
GstCaps *caps = NULL, *prevcaps = NULL;
|
||||
GstVideoFormat format;
|
||||
GstStructure *structure;
|
||||
const gchar *s;
|
||||
GstGLContext *context;
|
||||
GstVtdec *vtdec;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
peercaps = gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (vtdec), NULL);
|
||||
|
||||
/* Check if output supports GL caps by preference */
|
||||
templcaps = gst_pad_get_pad_template_caps (GST_VIDEO_DECODER_SRC_PAD (vtdec));
|
||||
vtdec = GST_VTDEC (decoder);
|
||||
caps =
|
||||
gst_caps_intersect_full (templcaps, peercaps, GST_CAPS_INTERSECT_FIRST);
|
||||
|
||||
gst_caps_unref (peercaps);
|
||||
gst_caps_unref (templcaps);
|
||||
gst_caps_make_writable (gst_pad_query_caps (GST_VIDEO_DECODER_SRC_PAD
|
||||
(vtdec), NULL));
|
||||
context = query_gl_context (vtdec);
|
||||
if (!context)
|
||||
gst_caps_filter_and_map_in_place (caps, caps_filter_out_gl_memory, NULL);
|
||||
|
||||
caps = gst_caps_truncate (caps);
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
s = gst_structure_get_string (structure, "format");
|
||||
output_format = gst_video_format_from_string (s);
|
||||
features = gst_caps_features_copy (gst_caps_get_features (caps, 0));
|
||||
|
||||
format = gst_video_format_from_string (s);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
if (!gst_vtdec_create_session (vtdec, output_format)) {
|
||||
gst_caps_features_free (features);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
output_state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (vtdec),
|
||||
output_format, vtdec->video_info.width, vtdec->video_info.height,
|
||||
input_state);
|
||||
|
||||
format, vtdec->video_info.width, vtdec->video_info.height,
|
||||
vtdec->input_state);
|
||||
output_state->caps = gst_video_info_to_caps (&output_state->info);
|
||||
gst_caps_set_features (output_state->caps, 0, features);
|
||||
if (output_state->info.finfo->format == GST_VIDEO_FORMAT_RGBA) {
|
||||
setup_texture_cache (vtdec, context);
|
||||
gst_caps_set_features (output_state->caps, 0,
|
||||
gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, NULL));
|
||||
}
|
||||
if (context)
|
||||
gst_object_unref (context);
|
||||
|
||||
return TRUE;
|
||||
GST_INFO_OBJECT (vtdec, "negotiated output format %" GST_PTR_FORMAT,
|
||||
output_state->caps);
|
||||
|
||||
prevcaps = gst_pad_get_current_caps (decoder->srcpad);
|
||||
if (!prevcaps || !gst_caps_is_equal (prevcaps, output_state->caps)) {
|
||||
if (vtdec->session) {
|
||||
gst_vtdec_push_frames_if_needed (vtdec, TRUE, FALSE);
|
||||
gst_vtdec_invalidate_session (vtdec);
|
||||
}
|
||||
ret = gst_vtdec_create_session (vtdec, format);
|
||||
}
|
||||
if (prevcaps)
|
||||
gst_caps_unref (prevcaps);
|
||||
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
return GST_VIDEO_DECODER_CLASS (gst_vtdec_parent_class)->negotiate (decoder);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -345,8 +347,10 @@ gst_vtdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
if (vtdec->session)
|
||||
if (vtdec->session) {
|
||||
gst_vtdec_push_frames_if_needed (vtdec, TRUE, FALSE);
|
||||
gst_vtdec_invalidate_session (vtdec);
|
||||
}
|
||||
|
||||
gst_video_info_from_caps (&vtdec->video_info, state->caps);
|
||||
|
||||
|
@ -366,8 +370,9 @@ gst_vtdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
|
|||
CFRelease (vtdec->format_description);
|
||||
vtdec->format_description = format_description;
|
||||
|
||||
if (!gst_vtdec_negotiate_output_format (vtdec, state))
|
||||
return FALSE;
|
||||
if (vtdec->input_state)
|
||||
gst_video_codec_state_unref (vtdec->input_state);
|
||||
vtdec->input_state = gst_video_codec_state_ref (state);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -444,6 +449,16 @@ error:
|
|||
goto out;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vtdec_invalidate_session (GstVtdec * vtdec)
|
||||
{
|
||||
g_return_if_fail (vtdec->session);
|
||||
|
||||
VTDecompressionSessionInvalidate (vtdec->session);
|
||||
CFRelease (vtdec->session);
|
||||
vtdec->session = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vtdec_create_session (GstVtdec * vtdec, GstVideoFormat format)
|
||||
{
|
||||
|
@ -453,6 +468,8 @@ gst_vtdec_create_session (GstVtdec * vtdec, GstVideoFormat format)
|
|||
OSStatus status;
|
||||
guint32 cv_format = 0;
|
||||
|
||||
g_return_val_if_fail (vtdec->session == NULL, FALSE);
|
||||
|
||||
switch (format) {
|
||||
case GST_VIDEO_FORMAT_NV12:
|
||||
cv_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
|
||||
|
@ -514,16 +531,6 @@ gst_vtdec_create_session (GstVtdec * vtdec, GstVideoFormat format)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vtdec_invalidate_session (GstVtdec * vtdec)
|
||||
{
|
||||
g_return_if_fail (vtdec->session);
|
||||
|
||||
VTDecompressionSessionInvalidate (vtdec->session);
|
||||
CFRelease (vtdec->session);
|
||||
vtdec->session = NULL;
|
||||
}
|
||||
|
||||
static CMFormatDescriptionRef
|
||||
create_format_description (GstVtdec * vtdec, CMVideoCodecType cm_format)
|
||||
{
|
||||
|
@ -793,8 +800,9 @@ gst_vtdec_push_frames_if_needed (GstVtdec * vtdec, gboolean drain,
|
|||
*/
|
||||
/* negotiate now so that we know whether we need to use the GL upload meta or
|
||||
* not */
|
||||
if (gst_pad_check_reconfigure (decoder->srcpad))
|
||||
if (gst_pad_check_reconfigure (decoder->srcpad)) {
|
||||
gst_video_decoder_negotiate (decoder);
|
||||
}
|
||||
|
||||
if (drain)
|
||||
VTDecompressionSessionWaitForAsynchronousFrames (vtdec->session);
|
||||
|
|
|
@ -41,6 +41,7 @@ typedef struct _GstVtdecClass GstVtdecClass;
|
|||
struct _GstVtdec
|
||||
{
|
||||
GstVideoDecoder base_vtdec;
|
||||
GstVideoCodecState *input_state;
|
||||
GstVideoInfo video_info;
|
||||
CMFormatDescriptionRef format_description;
|
||||
VTDecompressionSessionRef session;
|
||||
|
|
Loading…
Reference in a new issue