mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-22 23:28:16 +00:00
matroska: mux/demux the OpusHead header
This is meant to be so (https://wiki.xiph.org/MatroskaOpus - while it is marked as a draft, this part was confirmed to be correct on IRC), and allows one to determine whether a demuxed stream is multistream or not, and thus set the multistream caps field accordingly. In turn, this means downstream does not have to guess. https://bugzilla.gnome.org/show_bug.cgi?id=740744
This commit is contained in:
parent
d18b893d28
commit
b7413279d9
4 changed files with 109 additions and 0 deletions
|
@ -5278,6 +5278,18 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
|
|||
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_OPUS)) {
|
||||
caps = gst_caps_new_empty_simple ("audio/x-opus");
|
||||
*codec_name = g_strdup ("Opus");
|
||||
context->stream_headers =
|
||||
gst_matroska_parse_opus_stream_headers (context->codec_priv,
|
||||
context->codec_priv_size);
|
||||
if (context->stream_headers) {
|
||||
/* There was a valid header. Multistream headers are more than
|
||||
* 19 bytes, as they include an extra channel mapping table. */
|
||||
gboolean multistream = (context->codec_priv_size > 19);
|
||||
gst_caps_set_simple (caps, "multistream", G_TYPE_BOOLEAN, multistream,
|
||||
NULL);
|
||||
}
|
||||
/* FIXME: mark stream as broken and skip if there are no stream headers */
|
||||
context->send_stream_headers = TRUE;
|
||||
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_ACM)) {
|
||||
gst_riff_strf_auds auds;
|
||||
|
||||
|
|
|
@ -220,6 +220,36 @@ gst_matroska_parse_speex_stream_headers (gpointer codec_data,
|
|||
return list;
|
||||
}
|
||||
|
||||
GstBufferList *
|
||||
gst_matroska_parse_opus_stream_headers (gpointer codec_data,
|
||||
gsize codec_data_size)
|
||||
{
|
||||
GstBufferList *list = NULL;
|
||||
GstBuffer *hdr;
|
||||
guint8 *pdata = codec_data;
|
||||
|
||||
GST_MEMDUMP ("opus codec data", codec_data, codec_data_size);
|
||||
|
||||
if (codec_data == NULL || codec_data_size < 19) {
|
||||
GST_WARNING ("not enough codec priv data for opus headers");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (memcmp (pdata, "OpusHead", 8) != 0) {
|
||||
GST_WARNING ("no OpusHead marker at start of stream headers");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list = gst_buffer_list_new ();
|
||||
|
||||
hdr =
|
||||
gst_buffer_new_wrapped (g_memdup (pdata, codec_data_size),
|
||||
codec_data_size);
|
||||
gst_buffer_list_add (list, hdr);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
GstBufferList *
|
||||
gst_matroska_parse_flac_stream_headers (gpointer codec_data,
|
||||
gsize codec_data_size)
|
||||
|
|
|
@ -640,6 +640,9 @@ GstBufferList * gst_matroska_parse_xiph_stream_headers (gpointer codec_data,
|
|||
GstBufferList * gst_matroska_parse_speex_stream_headers (gpointer codec_data,
|
||||
gsize codec_data_size);
|
||||
|
||||
GstBufferList * gst_matroska_parse_opus_stream_headers (gpointer codec_data,
|
||||
gsize codec_data_size);
|
||||
|
||||
GstBufferList * gst_matroska_parse_flac_stream_headers (gpointer codec_data,
|
||||
gsize codec_data_size);
|
||||
void gst_matroska_track_free (GstMatroskaTrackContext * track);
|
||||
|
|
|
@ -1583,6 +1583,58 @@ speex_streamheader_to_codecdata (const GValue * streamheader,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
opus_streamheader_to_codecdata (const GValue * streamheader,
|
||||
GstMatroskaTrackContext * context)
|
||||
{
|
||||
GArray *bufarr;
|
||||
GValue *bufval;
|
||||
GstBuffer *buf;
|
||||
|
||||
if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
|
||||
goto wrong_type;
|
||||
|
||||
bufarr = g_value_peek_pointer (streamheader);
|
||||
if (bufarr->len <= 0 || bufarr->len > 255) /* one header, and count stored in a byte */
|
||||
goto wrong_count;
|
||||
if (bufarr->len != 1 && bufarr->len != 2)
|
||||
goto wrong_count;
|
||||
|
||||
context->xiph_headers_to_skip = bufarr->len;
|
||||
|
||||
bufval = &g_array_index (bufarr, GValue, 0);
|
||||
if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
|
||||
goto wrong_content_type;
|
||||
}
|
||||
buf = g_value_peek_pointer (bufval);
|
||||
|
||||
gst_matroska_mux_free_codec_priv (context);
|
||||
|
||||
context->codec_priv_size = gst_buffer_get_size (buf);
|
||||
context->codec_priv = g_malloc0 (context->codec_priv_size);
|
||||
gst_buffer_extract (buf, 0, context->codec_priv, -1);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
wrong_type:
|
||||
{
|
||||
GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
|
||||
G_VALUE_TYPE_NAME (streamheader));
|
||||
return FALSE;
|
||||
}
|
||||
wrong_count:
|
||||
{
|
||||
GST_WARNING ("got %u streamheaders, not 1 or 2 as expected", bufarr->len);
|
||||
return FALSE;
|
||||
}
|
||||
wrong_content_type:
|
||||
{
|
||||
GST_WARNING ("streamheaders array does not contain GstBuffers");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
aac_codec_data_to_codec_id (GstBuffer * buf)
|
||||
{
|
||||
|
@ -1834,7 +1886,19 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
goto refuse_caps;
|
||||
}
|
||||
} else if (!strcmp (mimetype, "audio/x-opus")) {
|
||||
const GValue *streamheader;
|
||||
|
||||
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_OPUS);
|
||||
|
||||
streamheader = gst_structure_get_value (structure, "streamheader");
|
||||
if (streamheader) {
|
||||
gst_matroska_mux_free_codec_priv (context);
|
||||
if (!opus_streamheader_to_codecdata (streamheader, context)) {
|
||||
GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
|
||||
("opus stream headers missing or malformed"));
|
||||
goto refuse_caps;
|
||||
}
|
||||
}
|
||||
} else if (!strcmp (mimetype, "audio/x-ac3")) {
|
||||
gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_AC3);
|
||||
} else if (!strcmp (mimetype, "audio/x-eac3")) {
|
||||
|
|
Loading…
Reference in a new issue