mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 02:00:33 +00:00
videodecoder: Try to invent default caps instead of setting none at all when getting a GAP event before CAPS
Otherwise we would forward the GAP event without ever providing any caps, which then would make decodebin expose a srcpad without any caps set. That's confusing for applications and can lead to all kinds of interesting bugs. Instead do the same as already is done in GstAudioDecoder, and try to invent caps based on the sinkpad caps and the caps allowed by downstream and the srcpad template caps. https://bugzilla.gnome.org/show_bug.cgi?id=747190
This commit is contained in:
parent
3570100b66
commit
f268f2be92
1 changed files with 107 additions and 0 deletions
|
@ -1027,6 +1027,101 @@ _flush_events (GstPad * pad, GList * events)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Must be called holding the GST_VIDEO_DECODER_STREAM_LOCK */
|
||||
static gboolean
|
||||
gst_video_decoder_negotiate_default_caps (GstVideoDecoder * decoder)
|
||||
{
|
||||
GstCaps *caps;
|
||||
GstVideoCodecState *state;
|
||||
GstVideoInfo info;
|
||||
gint i;
|
||||
gint caps_size;
|
||||
GstStructure *structure;
|
||||
|
||||
caps = gst_pad_get_allowed_caps (decoder->srcpad);
|
||||
if (!caps || gst_caps_is_empty (caps) || gst_caps_is_any (caps))
|
||||
goto caps_error;
|
||||
|
||||
/* before fixating, try to use whatever upstream provided */
|
||||
caps = gst_caps_make_writable (caps);
|
||||
caps_size = gst_caps_get_size (caps);
|
||||
if (decoder->priv->input_state && decoder->priv->input_state->caps) {
|
||||
GstCaps *sinkcaps = decoder->priv->input_state->caps;
|
||||
GstStructure *structure = gst_caps_get_structure (sinkcaps, 0);
|
||||
gint width, height;
|
||||
gint par_n, par_d;
|
||||
gint fps_n, fps_d;
|
||||
|
||||
if (gst_structure_get_int (structure, "width", &width)) {
|
||||
for (i = 0; i < caps_size; i++) {
|
||||
gst_structure_set (gst_caps_get_structure (caps, i), "width",
|
||||
G_TYPE_INT, width, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (gst_structure_get_int (structure, "height", &height)) {
|
||||
for (i = 0; i < caps_size; i++) {
|
||||
gst_structure_set (gst_caps_get_structure (caps, i), "height",
|
||||
G_TYPE_INT, height, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
|
||||
for (i = 0; i < caps_size; i++) {
|
||||
gst_structure_set (gst_caps_get_structure (caps, i), "framerate",
|
||||
GST_TYPE_FRACTION, fps_n, fps_d, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_n,
|
||||
&par_d)) {
|
||||
for (i = 0; i < caps_size; i++) {
|
||||
gst_structure_set (gst_caps_get_structure (caps, i),
|
||||
"pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < caps_size; i++) {
|
||||
structure = gst_caps_get_structure (caps, i);
|
||||
/* Random 1280x720@30 for fixation */
|
||||
gst_structure_fixate_field_nearest_int (structure, "width", 1280);
|
||||
gst_structure_fixate_field_nearest_int (structure, "height", 720);
|
||||
gst_structure_fixate_field_nearest_fraction (structure,
|
||||
"pixel-aspect-ratio", 1, 1);
|
||||
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
|
||||
}
|
||||
caps = gst_caps_fixate (caps);
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
if (!caps || !gst_video_info_from_caps (&info, caps))
|
||||
goto caps_error;
|
||||
|
||||
GST_INFO_OBJECT (decoder,
|
||||
"Chose default caps %" GST_PTR_FORMAT " for initial gap", caps);
|
||||
state =
|
||||
gst_video_decoder_set_output_state (decoder, info.finfo->format,
|
||||
info.width, info.height, decoder->priv->input_state);
|
||||
gst_video_codec_state_unref (state);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
if (!gst_video_decoder_negotiate (decoder)) {
|
||||
GST_INFO_OBJECT (decoder,
|
||||
"Failed to negotiate default caps for initial gap");
|
||||
gst_pad_mark_reconfigure (decoder->srcpad);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
caps_error:
|
||||
{
|
||||
if (caps)
|
||||
gst_caps_unref (caps);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_video_decoder_sink_event_default (GstVideoDecoder * decoder,
|
||||
GstEvent * event)
|
||||
|
@ -1122,6 +1217,18 @@ gst_video_decoder_sink_event_default (GstVideoDecoder * decoder,
|
|||
flow_ret = gst_video_decoder_drain_out (decoder, FALSE);
|
||||
ret = (flow_ret == GST_FLOW_OK);
|
||||
|
||||
/* Ensure we have caps before forwarding the event */
|
||||
GST_VIDEO_DECODER_STREAM_LOCK (decoder);
|
||||
if (!decoder->priv->output_state) {
|
||||
if (!gst_video_decoder_negotiate_default_caps (decoder)) {
|
||||
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
|
||||
GST_ELEMENT_ERROR (decoder, STREAM, FORMAT, (NULL),
|
||||
("Decoder output not negotiated before GAP event."));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
|
||||
|
||||
/* Forward GAP immediately. Everything is drained after
|
||||
* the GAP event and we can forward this event immediately
|
||||
* now without having buffers out of order.
|
||||
|
|
Loading…
Reference in a new issue