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);
"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 \
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);
{
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);
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;
+
+ 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);
- ret =
- GST_VIDEO_DECODER_CLASS (gst_vtdec_parent_class)->decide_allocation
- (decoder, query);
- if (!ret)
- goto out;
+ return gl_context;
+}
- 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);
+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;
+ internal_format = GST_VIDEO_FORMAT_NV12;
#else
- internal_format = GST_VIDEO_FORMAT_UYVY;
+ 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");
- }
- }
- }
+ 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);
+}
-out:
- return ret;
+static gboolean
+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_output_format (GstVtdec * vtdec,
- GstVideoCodecState * input_state)
+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),
+ format, vtdec->video_info.width, vtdec->video_info.height,
+ vtdec->input_state);
+ output_state->caps = gst_video_info_to_caps (&output_state->info);
+ 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);
- output_state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (vtdec),
- output_format, vtdec->video_info.width, vtdec->video_info.height,
- input_state);
+ GST_INFO_OBJECT (vtdec, "negotiated output format %" GST_PTR_FORMAT,
+ output_state->caps);
- output_state->caps = gst_video_info_to_caps (&output_state->info);
- gst_caps_set_features (output_state->caps, 0, features);
+ 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);
- return TRUE;
+ if (!ret)
+ return ret;
+
+ return GST_VIDEO_DECODER_CLASS (gst_vtdec_parent_class)->negotiate (decoder);
}
static gboolean
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);
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;
}
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)
{
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;
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)
{
*/
/* 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);