summaryrefslogtreecommitdiff
path: root/ext/mad/gstmad.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mad/gstmad.c')
-rw-r--r--ext/mad/gstmad.c209
1 files changed, 93 insertions, 116 deletions
diff --git a/ext/mad/gstmad.c b/ext/mad/gstmad.c
index 1dd0493cc7..703967be3e 100644
--- a/ext/mad/gstmad.c
+++ b/ext/mad/gstmad.c
@@ -165,7 +165,8 @@ static gboolean gst_mad_convert_sink (GstPad * pad, GstFormat src_format,
static gboolean gst_mad_convert_src (GstPad * pad, GstFormat src_format,
gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
-static void gst_mad_chain (GstPad * pad, GstData * _data);
+static gboolean gst_mad_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_mad_chain (GstPad * pad, GstBuffer * buffer);
static GstElementStateReturn gst_mad_change_state (GstElement * element);
@@ -324,6 +325,8 @@ gst_mad_init (GstMad * mad)
(&mad_sink_template_factory), "sink");
gst_element_add_pad (GST_ELEMENT (mad), mad->sinkpad);
gst_pad_set_chain_function (mad->sinkpad, GST_DEBUG_FUNCPTR (gst_mad_chain));
+ gst_pad_set_event_function (mad->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_mad_sink_event));
gst_pad_set_convert_function (mad->sinkpad,
GST_DEBUG_FUNCPTR (gst_mad_convert_sink));
gst_pad_set_formats_function (mad->sinkpad,
@@ -345,7 +348,6 @@ gst_mad_init (GstMad * mad)
GST_DEBUG_FUNCPTR (gst_mad_convert_src));
gst_pad_set_formats_function (mad->srcpad,
GST_DEBUG_FUNCPTR (gst_mad_get_formats));
- gst_pad_use_explicit_caps (mad->srcpad);
mad->tempbuffer = g_malloc (MAD_BUFFER_MDLEN * 3);
mad->tempsize = 0;
@@ -365,7 +367,6 @@ gst_mad_init (GstMad * mad)
mad->half = FALSE;
mad->ignore_crc = TRUE;
mad->check_for_xing = TRUE;
- GST_FLAG_SET (mad, GST_ELEMENT_EVENT_AWARE);
}
static void
@@ -435,7 +436,7 @@ gst_mad_convert_sink (GstPad * pad, GstFormat src_format, gint64 src_value,
gboolean res = TRUE;
GstMad *mad;
- mad = GST_MAD (gst_pad_get_parent (pad));
+ mad = GST_MAD (GST_PAD_PARENT (pad));
if (mad->vbr_average == 0)
return FALSE;
@@ -476,7 +477,7 @@ gst_mad_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
gint bytes_per_sample;
GstMad *mad;
- mad = GST_MAD (gst_pad_get_parent (pad));
+ mad = GST_MAD (GST_PAD_PARENT (pad));
bytes_per_sample = MAD_NCHANNELS (&mad->frame.header) << 1;
@@ -553,7 +554,7 @@ gst_mad_src_query (GstPad * pad, GstQueryType type,
gboolean res = TRUE;
GstMad *mad;
- mad = GST_MAD (gst_pad_get_parent (pad));
+ mad = GST_MAD (GST_PAD_PARENT (pad));
switch (type) {
case GST_QUERY_TOTAL:
@@ -739,30 +740,15 @@ gst_mad_src_event (GstPad * pad, GstEvent * event)
gboolean res = TRUE;
GstMad *mad;
- mad = GST_MAD (gst_pad_get_parent (pad));
+ mad = GST_MAD (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK_SEGMENT:
- GST_DEBUG ("forwarding seek event to sink pad");
- gst_event_ref (event);
- if (gst_pad_send_event (GST_PAD_PEER (mad->sinkpad), event)) {
- /* seek worked, we're done, loop will exit */
- res = TRUE;
- }
- break;
/* the all-formats seek logic */
case GST_EVENT_SEEK:
- GST_DEBUG ("forwarding seek event to sink pad");
- gst_event_ref (event);
- if (gst_pad_send_event (GST_PAD_PEER (mad->sinkpad), event)) {
- /* seek worked, we're done, loop will exit */
- res = TRUE;
- } else {
- if (mad->index)
- res = index_seek (mad, pad, event);
- else
- res = normal_seek (mad, pad, event);
- }
+ if (mad->index)
+ res = index_seek (mad, pad, event);
+ else
+ res = normal_seek (mad, pad, event);
break;
default:
@@ -887,18 +873,17 @@ G_STMT_START{ \
GST_TAG_LAYER, mad->header.layer,
GST_TAG_MODE, mode->value_nick,
GST_TAG_EMPHASIS, emphasis->value_nick, NULL);
- gst_element_found_tags (GST_ELEMENT (mad), list);
- gst_tag_list_free (list);
+ gst_element_post_message (GST_ELEMENT (mad),
+ gst_message_new_tag (GST_OBJECT (mad), list));
}
#undef CHECK_HEADER
}
-static void
-gst_mad_handle_event (GstPad * pad, GstBuffer * buffer)
+static gboolean
+gst_mad_sink_event (GstPad * pad, GstEvent * event)
{
- GstEvent *event = GST_EVENT (buffer);
- GstMad *mad = GST_MAD (gst_pad_get_parent (pad));
+ GstMad *mad = GST_MAD (GST_PAD_PARENT (pad));
GST_DEBUG ("handling event %d", GST_EVENT_TYPE (event));
switch (GST_EVENT_TYPE (event)) {
@@ -916,7 +901,9 @@ gst_mad_handle_event (GstPad * pad, GstBuffer * buffer)
if (gst_formats_contains (formats, GST_EVENT_DISCONT_OFFSET (event,
i).format)) {
- gint64 value = GST_EVENT_DISCONT_OFFSET (event, i).value;
+ gint64 start_value = GST_EVENT_DISCONT_OFFSET (event, i).start_value;
+
+ //gint64 end_value = GST_EVENT_DISCONT_OFFSET (event, i).end_value;
gint64 time;
GstFormat format;
GstEvent *discont;
@@ -926,11 +913,11 @@ gst_mad_handle_event (GstPad * pad, GstBuffer * buffer)
format = GST_FORMAT_TIME;
if (!gst_pad_convert (pad,
GST_EVENT_DISCONT_OFFSET (event, i).format,
- value, &format, &time)) {
+ start_value, &format, &time)) {
continue;
}
} else {
- time = value;
+ time = start_value;
}
/* for now, this is the best we can do to get the total number
@@ -946,7 +933,7 @@ gst_mad_handle_event (GstPad * pad, GstBuffer * buffer)
if (GST_PAD_IS_USABLE (mad->srcpad)) {
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
time, NULL);
- gst_pad_push (mad->srcpad, GST_DATA (discont));
+ gst_pad_push_event (mad->srcpad, discont);
}
gst_event_unref (event);
goto done;
@@ -969,6 +956,7 @@ gst_mad_handle_event (GstPad * pad, GstBuffer * buffer)
gst_pad_event_default (pad, event);
break;
}
+ return TRUE;
}
static gboolean
@@ -1133,7 +1121,7 @@ mpg123_parse_xing_header (struct mad_header *header,
/* internal function to check if the header has changed and thus the
* caps need to be reset. Only call during normal mode, not resyncing */
-static gboolean
+static void
gst_mad_check_caps_reset (GstMad * mad)
{
guint nchannels;
@@ -1146,12 +1134,6 @@ gst_mad_check_caps_reset (GstMad * mad)
#else
rate = mad->frame.header.samplerate;
#endif
- if (mad->stream.options & MAD_OPTION_HALFSAMPLERATE) {
- GST_INFO_OBJECT (mad,
- "MAD_OPTION_HALFSAMPLERATE is set, adapting rate from %u to %u", rate,
- rate >> 1);
- rate >>= 1;
- }
/* rate and channels are not supposed to change in a continuous stream,
* so check this first before doing anything */
@@ -1170,10 +1152,8 @@ gst_mad_check_caps_reset (GstMad * mad)
mad->pending_channels = nchannels;
mad->pending_rate = rate;
}
- /* Now, we already have a valid caps set and will continue to use
- * that for a while longer, so we cans afely return TRUE here. */
if (++mad->times_pending < 3)
- return TRUE;
+ return;
}
}
gst_mad_update_info (mad);
@@ -1181,6 +1161,11 @@ gst_mad_check_caps_reset (GstMad * mad)
if (mad->channels != nchannels || mad->rate != rate) {
GstCaps *caps;
+ if (mad->stream.options & MAD_OPTION_HALFSAMPLERATE)
+ rate >>= 1;
+
+ /* FIXME see if peer can accept the caps */
+
/* we set the caps even when the pad is not connected so they
* can be gotten for streaminfo */
caps = gst_caps_new_simple ("audio/x-raw-int",
@@ -1190,39 +1175,27 @@ gst_mad_check_caps_reset (GstMad * mad)
"depth", G_TYPE_INT, 16,
"rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, nchannels, NULL);
- if (gst_pad_set_explicit_caps (mad->srcpad, caps)) {
- mad->caps_set = TRUE; /* set back to FALSE on discont */
- mad->channels = nchannels;
- mad->rate = rate;
- } else {
- GST_ELEMENT_ERROR (mad, CORE, NEGOTIATION, (NULL),
- ("Failed to negotiate %d Hz, %d channels", rate, nchannels));
- return FALSE;
- }
- gst_caps_free (caps);
+ gst_pad_set_caps (mad->srcpad, caps);
+ mad->caps_set = TRUE; /* set back to FALSE on discont */
+ mad->channels = nchannels;
+ mad->rate = rate;
}
-
- return TRUE;
}
-static void
-gst_mad_chain (GstPad * pad, GstData * _data)
+static GstFlowReturn
+gst_mad_chain (GstPad * pad, GstBuffer * buffer)
{
- GstBuffer *buffer = GST_BUFFER (_data);
GstMad *mad;
gchar *data;
glong size;
gboolean new_pts = FALSE;
GstClockTime timestamp;
+ GstFlowReturn result = GST_FLOW_OK;
- mad = GST_MAD (gst_pad_get_parent (pad));
- g_return_if_fail (GST_IS_MAD (mad));
+ mad = GST_MAD (GST_PAD_PARENT (pad));
+ g_return_val_if_fail (GST_IS_MAD (mad), GST_FLOW_ERROR);
- /* handle events */
- if (GST_IS_EVENT (buffer)) {
- gst_mad_handle_event (pad, buffer);
- return;
- }
+ GST_STREAM_LOCK (pad);
/* restarts happen on discontinuities, ie. seek, flush, PAUSED to PLAYING */
if (gst_mad_check_restart (mad))
@@ -1266,7 +1239,8 @@ gst_mad_chain (GstPad * pad, GstData * _data)
GST_ELEMENT_ERROR (mad, STREAM, DECODE, (NULL),
("mad claims to need more data than %u bytes, we don't have that much",
MAD_BUFFER_MDLEN * 3));
- return;
+ result = GST_FLOW_ERROR;
+ goto end;
}
/* append the chunk to process to our internal temporary buffer */
@@ -1287,7 +1261,7 @@ gst_mad_chain (GstPad * pad, GstData * _data)
guint nsamples;
guint64 time_offset;
guint64 time_duration;
- gboolean resync = TRUE;
+ unsigned char const *before_sync, *after_sync;
mad->in_error = FALSE;
@@ -1295,6 +1269,12 @@ gst_mad_chain (GstPad * pad, GstData * _data)
/* added separate header decoding to catch errors earlier, also fixes
* some weird decoding errors... */
+ GST_LOG ("decoding the header now");
+ if (mad_header_decode (&mad->frame.header, &mad->stream) == -1) {
+ GST_DEBUG ("mad_frame_decode had an error: %s",
+ mad_stream_errorstr (&mad->stream));
+ }
+
GST_LOG ("decoding one frame now");
if (mad_frame_decode (&mad->frame, &mad->stream) == -1) {
@@ -1317,7 +1297,8 @@ gst_mad_chain (GstPad * pad, GstData * _data)
mad_stream_errorstr (&mad->stream));
if (!MAD_RECOVERABLE (mad->stream.error)) {
GST_ELEMENT_ERROR (mad, STREAM, DECODE, (NULL), (NULL));
- return;
+ result = GST_FLOW_ERROR;
+ goto end;
} else if (mad->stream.error == MAD_ERROR_LOSTSYNC) {
/* lost sync, force a resync */
signed long tagsize;
@@ -1341,9 +1322,6 @@ gst_mad_chain (GstPad * pad, GstData * _data)
* id3 tags, so we need to flush one byte less than the tagsize */
mad_stream_skip (&mad->stream, tagsize - 1);
- /* When we skip, we don't want to call sync */
- resync = FALSE;
-
tag = id3_tag_parse (data, tagsize);
if (tag) {
GstTagList *list;
@@ -1351,47 +1329,39 @@ gst_mad_chain (GstPad * pad, GstData * _data)
list = gst_mad_id3_to_tag_list (tag);
id3_tag_delete (tag);
GST_DEBUG ("found tag");
- gst_element_found_tags (GST_ELEMENT (mad), list);
+ gst_element_post_message (GST_ELEMENT (mad),
+ gst_message_new_tag (GST_OBJECT (mad),
+ gst_tag_list_copy (list)));
if (mad->tags) {
gst_tag_list_insert (mad->tags, list, GST_TAG_MERGE_PREPEND);
} else {
mad->tags = gst_tag_list_copy (list);
}
if (GST_PAD_IS_USABLE (mad->srcpad)) {
- gst_pad_push (mad->srcpad, GST_DATA (gst_event_new_tag (list)));
+ gst_pad_push_event (mad->srcpad, gst_event_new_tag (list));
} else {
gst_tag_list_free (list);
}
}
}
}
- //Should not sync here if mad_skip has been used before, the offset
- //is "pending" inside mad and will be applied on next call to decode.
- if (resync) {
- unsigned char const *before_sync, *after_sync;
-
- before_sync = mad->stream.ptr.byte;
- if (mad_stream_sync (&mad->stream) != 0) {
- consumed = MAD_BUFFER_GUARD < mad->tempsize ?
- mad->tempsize - MAD_BUFFER_GUARD : 0;
- GST_DEBUG_OBJECT (mad,
- "mad_stream_sync failed, skipping all %u bytes we have",
- consumed);
- } else {
- after_sync = mad->stream.ptr.byte;
- /* a succesful resync should make us drop bytes as consumed, so
- calculate from the byte pointers before and after resync */
- consumed = after_sync - before_sync;
- GST_DEBUG_OBJECT (mad, "resynchronization consumes %d bytes",
- consumed);
- GST_DEBUG_OBJECT (mad, "synced to data: 0x%0x 0x%0x",
- *mad->stream.ptr.byte, *(mad->stream.ptr.byte + 1));
-
- /* recoverable errors pass */
- }
- resync = FALSE;
- }
+ mad_frame_mute (&mad->frame);
+ mad_synth_mute (&mad->synth);
+ before_sync = mad->stream.ptr.byte;
+ if (mad_stream_sync (&mad->stream) != 0)
+ GST_WARNING ("mad_stream_sync failed");
+ after_sync = mad->stream.ptr.byte;
+ /* a succesful resync should make us drop bytes as consumed, so
+ calculate from the byte pointers before and after resync */
+ consumed = after_sync - before_sync;
+ GST_DEBUG ("resynchronization consumes %d bytes", consumed);
+ GST_DEBUG ("synced to data: 0x%0x 0x%0x", *mad->stream.ptr.byte,
+ *(mad->stream.ptr.byte + 1));
+
+
+ mad_stream_sync (&mad->stream);
+ /* recoverable errors pass */
goto next;
}
@@ -1407,9 +1377,10 @@ gst_mad_chain (GstPad * pad, GstData * _data)
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
GST_TAG_DURATION, (gint64) time * 1000 * 1000 * 1000,
GST_TAG_BITRATE, bitrate, NULL);
- gst_element_found_tags (GST_ELEMENT (mad), list);
+ gst_element_post_message (GST_ELEMENT (mad),
+ gst_message_new_tag (GST_OBJECT (mad), gst_tag_list_copy (list)));
if (GST_PAD_IS_USABLE (mad->srcpad)) {
- gst_pad_push (mad->srcpad, GST_DATA (gst_event_new_tag (list)));
+ gst_pad_push_event (mad->srcpad, gst_event_new_tag (list));
} else {
gst_tag_list_free (list);
}
@@ -1420,10 +1391,8 @@ gst_mad_chain (GstPad * pad, GstData * _data)
}
/* if we're not resyncing/in error, check if caps need to be set again */
- if (!mad->in_error) {
- if (!gst_mad_check_caps_reset (mad))
- goto end;
- }
+ if (!mad->in_error)
+ gst_mad_check_caps_reset (mad);
nsamples = MAD_NSBSAMPLES (&mad->frame.header) *
(mad->stream.options & MAD_OPTION_HALFSAMPLERATE ? 16 : 32);
@@ -1441,9 +1410,8 @@ gst_mad_chain (GstPad * pad, GstData * _data)
&mad->total_samples);
mad->last_ts = GST_CLOCK_TIME_NONE;
}
- time_offset =
- mad->total_samples * GST_SECOND / mad->frame.header.samplerate;
- time_duration = (nsamples * GST_SECOND / mad->frame.header.samplerate);
+ time_offset = mad->total_samples * GST_SECOND / mad->rate;
+ time_duration = (nsamples * GST_SECOND / mad->rate);
}
if (mad->index) {
@@ -1468,7 +1436,10 @@ gst_mad_chain (GstPad * pad, GstData * _data)
left_ch = mad->synth.pcm.samples[0];
right_ch = mad->synth.pcm.samples[1];
- outbuffer = gst_buffer_new_and_alloc (nsamples * mad->channels * 2);
+ /* will attach the caps to the buffer */
+ outbuffer =
+ gst_pad_alloc_buffer (mad->srcpad, 0, nsamples * mad->channels * 2,
+ GST_PAD_CAPS (mad->srcpad));
outdata = (gint16 *) GST_BUFFER_DATA (outbuffer);
GST_BUFFER_TIMESTAMP (outbuffer) = time_offset;
@@ -1491,7 +1462,10 @@ gst_mad_chain (GstPad * pad, GstData * _data)
}
}
- gst_pad_push (mad->srcpad, GST_DATA (outbuffer));
+ result = gst_pad_push (mad->srcpad, outbuffer);
+ if (result != GST_FLOW_OK) {
+ goto end;
+ }
}
mad->total_samples += nsamples;
@@ -1517,21 +1491,22 @@ gst_mad_chain (GstPad * pad, GstData * _data)
if (consumed == 0)
consumed = mad->stream.next_frame - mad_input_buffer;
- if (mad->stream.skiplen > consumed)
- consumed = mad->stream.skiplen;
GST_LOG ("mad consumed %d bytes", consumed);
/* move out pointer to where mad want the next data */
mad_input_buffer += consumed;
mad->tempsize -= consumed;
mad->bytes_consumed += consumed;
- mad->stream.skiplen = 0;
}
/* we only get here from breaks, tempsize never actually drops below 0 */
memmove (mad->tempbuffer, mad_input_buffer, mad->tempsize);
}
+ result = GST_FLOW_OK;
end:
+ GST_STREAM_UNLOCK (pad);
gst_buffer_unref (buffer);
+
+ return result;
}
static GstElementStateReturn
@@ -1577,6 +1552,7 @@ gst_mad_change_state (GstElement * element)
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
+ GST_STREAM_LOCK (mad->sinkpad);
mad_synth_finish (&mad->synth);
mad_frame_finish (&mad->frame);
mad_stream_finish (&mad->stream);
@@ -1585,6 +1561,7 @@ gst_mad_change_state (GstElement * element)
gst_tag_list_free (mad->tags);
mad->tags = NULL;
}
+ GST_STREAM_UNLOCK (mad->sinkpad);
break;
case GST_STATE_READY_TO_NULL:
break;