mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
Add initial support for muxing/demuxing Speex audio
Note: This is not in the Matroska spec yet Fixes bug #578310.
This commit is contained in:
parent
776b0ae8cb
commit
108774781d
3 changed files with 134 additions and 0 deletions
|
@ -3498,6 +3498,39 @@ gst_matroska_demux_push_flac_codec_priv_data (GstMatroskaDemux * demux,
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_matroska_demux_push_speex_codec_priv_data (GstMatroskaDemux * demux,
|
||||||
|
GstMatroskaTrackContext * stream)
|
||||||
|
{
|
||||||
|
GstFlowReturn ret;
|
||||||
|
guint8 *pdata;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (demux, "priv data size = %u", stream->codec_priv_size);
|
||||||
|
|
||||||
|
pdata = (guint8 *) stream->codec_priv;
|
||||||
|
|
||||||
|
/* need at least 'fLaC' marker + STREAMINFO metadata block */
|
||||||
|
if (stream->codec_priv_size < 80) {
|
||||||
|
GST_WARNING_OBJECT (demux, "not enough codec priv data for speex headers");
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp (pdata, "Speex ", 8) != 0) {
|
||||||
|
GST_WARNING_OBJECT (demux, "no Speex marker at start of stream headers");
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gst_matroska_demux_push_hdr_buf (demux, stream, pdata, 80);
|
||||||
|
if (ret != GST_FLOW_OK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (stream->codec_priv_size == 80)
|
||||||
|
return ret;
|
||||||
|
else
|
||||||
|
return gst_matroska_demux_push_hdr_buf (demux, stream, pdata + 80,
|
||||||
|
stream->codec_priv_size - 80);
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_matroska_demux_push_xiph_codec_priv_data (GstMatroskaDemux * demux,
|
gst_matroska_demux_push_xiph_codec_priv_data (GstMatroskaDemux * demux,
|
||||||
GstMatroskaTrackContext * stream)
|
GstMatroskaTrackContext * stream)
|
||||||
|
@ -4047,6 +4080,11 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
stream->send_flac_headers = FALSE;
|
stream->send_flac_headers = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stream->send_speex_headers) {
|
||||||
|
ret = gst_matroska_demux_push_speex_codec_priv_data (demux, stream);
|
||||||
|
stream->send_speex_headers = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (stream->send_dvd_event) {
|
if (stream->send_dvd_event) {
|
||||||
gst_matroska_demux_push_dvd_clut_change_event (demux, stream);
|
gst_matroska_demux_push_dvd_clut_change_event (demux, stream);
|
||||||
/* FIXME: should we send this event again after (flushing) seek ? */
|
/* FIXME: should we send this event again after (flushing) seek ? */
|
||||||
|
@ -4958,6 +4996,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
|
||||||
|
|
||||||
context->send_xiph_headers = FALSE;
|
context->send_xiph_headers = FALSE;
|
||||||
context->send_flac_headers = FALSE;
|
context->send_flac_headers = FALSE;
|
||||||
|
context->send_speex_headers = FALSE;
|
||||||
|
|
||||||
/* TODO: check if we have all codec types from matroska-ids.h
|
/* TODO: check if we have all codec types from matroska-ids.h
|
||||||
* check if we have to do more special things with codec_private
|
* check if we have to do more special things with codec_private
|
||||||
|
@ -5308,6 +5347,7 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
|
||||||
|
|
||||||
context->send_xiph_headers = FALSE;
|
context->send_xiph_headers = FALSE;
|
||||||
context->send_flac_headers = FALSE;
|
context->send_flac_headers = FALSE;
|
||||||
|
context->send_speex_headers = FALSE;
|
||||||
|
|
||||||
/* TODO: check if we have all codec types from matroska-ids.h
|
/* TODO: check if we have all codec types from matroska-ids.h
|
||||||
* check if we have to do more special things with codec_private
|
* check if we have to do more special things with codec_private
|
||||||
|
@ -5380,6 +5420,9 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
|
||||||
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_FLAC)) {
|
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_FLAC)) {
|
||||||
caps = gst_caps_new_simple ("audio/x-flac", NULL);
|
caps = gst_caps_new_simple ("audio/x-flac", NULL);
|
||||||
context->send_flac_headers = TRUE;
|
context->send_flac_headers = TRUE;
|
||||||
|
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_SPEEX)) {
|
||||||
|
caps = gst_caps_new_simple ("audio/x-speex", NULL);
|
||||||
|
context->send_speex_headers = TRUE;
|
||||||
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_ACM)) {
|
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_ACM)) {
|
||||||
gst_riff_strf_auds *auds = NULL;
|
gst_riff_strf_auds *auds = NULL;
|
||||||
|
|
||||||
|
|
|
@ -351,6 +351,8 @@
|
||||||
#define GST_MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS"
|
#define GST_MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS"
|
||||||
#define GST_MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS"
|
#define GST_MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS"
|
||||||
#define GST_MATROSKA_CODEC_ID_AUDIO_FLAC "A_FLAC"
|
#define GST_MATROSKA_CODEC_ID_AUDIO_FLAC "A_FLAC"
|
||||||
|
/* FIXME: not yet in the spec */
|
||||||
|
#define GST_MATROSKA_CODEC_ID_AUDIO_SPEEX "A_SPEEX"
|
||||||
#define GST_MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM"
|
#define GST_MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM"
|
||||||
#define GST_MATROSKA_CODEC_ID_AUDIO_TTA "A_TTA1"
|
#define GST_MATROSKA_CODEC_ID_AUDIO_TTA "A_TTA1"
|
||||||
#define GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4 "A_WAVPACK4"
|
#define GST_MATROSKA_CODEC_ID_AUDIO_WAVPACK4 "A_WAVPACK4"
|
||||||
|
@ -488,6 +490,11 @@ struct _GstMatroskaTrackContext {
|
||||||
* testing for time == 0 is not enough to detect that. Used by demuxer */
|
* testing for time == 0 is not enough to detect that. Used by demuxer */
|
||||||
gboolean send_flac_headers;
|
gboolean send_flac_headers;
|
||||||
|
|
||||||
|
/* Special flag for Speex, for which we need to reconstruct the header
|
||||||
|
* buffer from the codec_priv data before sending any data, and just
|
||||||
|
* testing for time == 0 is not enough to detect that. Used by demuxer */
|
||||||
|
gboolean send_speex_headers;
|
||||||
|
|
||||||
/* Special flag for VobSub, for which we have to send colour table info
|
/* Special flag for VobSub, for which we have to send colour table info
|
||||||
* (if available) first before sending any data, and just testing
|
* (if available) first before sending any data, and just testing
|
||||||
* for time == 0 is not enough to detect that. Used by demuxer */
|
* for time == 0 is not enough to detect that. Used by demuxer */
|
||||||
|
|
|
@ -142,6 +142,8 @@ static GstStaticPadTemplate audiosink_templ =
|
||||||
COMMON_AUDIO_CAPS "; "
|
COMMON_AUDIO_CAPS "; "
|
||||||
"audio/x-flac, "
|
"audio/x-flac, "
|
||||||
COMMON_AUDIO_CAPS "; "
|
COMMON_AUDIO_CAPS "; "
|
||||||
|
"audio/x-speex, "
|
||||||
|
COMMON_AUDIO_CAPS "; "
|
||||||
"audio/x-raw-int, "
|
"audio/x-raw-int, "
|
||||||
"width = (int) 8, "
|
"width = (int) 8, "
|
||||||
"depth = (int) 8, "
|
"depth = (int) 8, "
|
||||||
|
@ -224,6 +226,8 @@ static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
|
||||||
GstMatroskaTrackContext * context);
|
GstMatroskaTrackContext * context);
|
||||||
static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
|
static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
|
||||||
GstMatroskaTrackContext * context);
|
GstMatroskaTrackContext * context);
|
||||||
|
static gboolean speex_streamheader_to_codecdata (const GValue * streamheader,
|
||||||
|
GstMatroskaTrackContext * context);
|
||||||
static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
|
static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
|
||||||
GstMatroskaTrackContext * context);
|
GstMatroskaTrackContext * context);
|
||||||
|
|
||||||
|
@ -1140,6 +1144,69 @@ flac_streamheader_to_codecdata (const GValue * streamheader,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
speex_streamheader_to_codecdata (const GValue * streamheader,
|
||||||
|
GstMatroskaTrackContext * context)
|
||||||
|
{
|
||||||
|
GArray *bufarr;
|
||||||
|
GValue *bufval;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
|
||||||
|
if (streamheader == NULL || G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY) {
|
||||||
|
GST_WARNING ("No or invalid streamheader field in the caps");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufarr = g_value_peek_pointer (streamheader);
|
||||||
|
if (bufarr->len != 2) {
|
||||||
|
GST_WARNING ("Too few headers in streamheader field");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->xiph_headers_to_skip = bufarr->len + 1;
|
||||||
|
|
||||||
|
bufval = &g_array_index (bufarr, GValue, 0);
|
||||||
|
if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
|
||||||
|
GST_WARNING ("streamheaders array does not contain GstBuffers");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = g_value_peek_pointer (bufval);
|
||||||
|
|
||||||
|
if (GST_BUFFER_SIZE (buffer) < 80
|
||||||
|
|| memcmp (GST_BUFFER_DATA (buffer), "Speex ", 8) != 0) {
|
||||||
|
GST_WARNING ("Invalid streamheader for Speex");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->codec_priv = g_malloc (GST_BUFFER_SIZE (buffer));
|
||||||
|
context->codec_priv_size = GST_BUFFER_SIZE (buffer);
|
||||||
|
memcpy (context->codec_priv, GST_BUFFER_DATA (buffer),
|
||||||
|
GST_BUFFER_SIZE (buffer));
|
||||||
|
|
||||||
|
bufval = &g_array_index (bufarr, GValue, 1);
|
||||||
|
|
||||||
|
if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER) {
|
||||||
|
g_free (context->codec_priv);
|
||||||
|
context->codec_priv = NULL;
|
||||||
|
context->codec_priv_size = 0;
|
||||||
|
GST_WARNING ("streamheaders array does not contain GstBuffers");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = g_value_peek_pointer (bufval);
|
||||||
|
|
||||||
|
context->codec_priv =
|
||||||
|
g_realloc (context->codec_priv,
|
||||||
|
context->codec_priv_size + GST_BUFFER_SIZE (buffer));
|
||||||
|
memcpy ((guint8 *) context->codec_priv + context->codec_priv_size,
|
||||||
|
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
context->codec_priv_size =
|
||||||
|
context->codec_priv_size + GST_BUFFER_SIZE (buffer);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
aac_codec_data_to_codec_id (const GstBuffer * buf)
|
aac_codec_data_to_codec_id (const GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
@ -1382,6 +1449,23 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
} else if (!strcmp (mimetype, "audio/x-speex")) {
|
||||||
|
const GValue *streamheader;
|
||||||
|
|
||||||
|
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_SPEEX);
|
||||||
|
if (context->codec_priv != NULL) {
|
||||||
|
g_free (context->codec_priv);
|
||||||
|
context->codec_priv = NULL;
|
||||||
|
context->codec_priv_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
streamheader = gst_structure_get_value (structure, "streamheader");
|
||||||
|
if (!speex_streamheader_to_codecdata (streamheader, context)) {
|
||||||
|
GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
|
||||||
|
("speex stream headers missing or malformed"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
} else if (!strcmp (mimetype, "audio/x-ac3")) {
|
} else if (!strcmp (mimetype, "audio/x-ac3")) {
|
||||||
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
|
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue