summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/vorbis/gstvorbisdec.c111
-rw-r--r--ext/vorbis/gstvorbisdec.h2
2 files changed, 106 insertions, 7 deletions
diff --git a/ext/vorbis/gstvorbisdec.c b/ext/vorbis/gstvorbisdec.c
index c4b92e35a..f4e563c13 100644
--- a/ext/vorbis/gstvorbisdec.c
+++ b/ext/vorbis/gstvorbisdec.c
@@ -159,6 +159,10 @@ vorbis_dec_stop (GstAudioDecoder * dec)
vorbis_dsp_clear (&vd->vd);
vorbis_comment_clear (&vd->vc);
vorbis_info_clear (&vd->vi);
+ if (vd->pending_headers) {
+ g_list_free_full (vd->pending_headers, (GDestroyNotify) gst_buffer_unref);
+ vd->pending_headers = NULL;
+ }
return TRUE;
}
@@ -547,6 +551,92 @@ wrong_samples:
}
static GstFlowReturn
+check_pending_headers (GstVorbisDec * vd)
+{
+ GstBuffer *buffer1, *buffer3, *buffer5;
+ GstMapInfo map;
+ gboolean isvalid;
+ GList *tmp = vd->pending_headers;
+ GstFlowReturn result = GST_FLOW_OK;
+
+ if (g_list_length (vd->pending_headers) < MIN_NUM_HEADERS)
+ goto not_enough;
+
+ buffer1 = (GstBuffer *) tmp->data;
+ tmp = tmp->next;
+ buffer3 = (GstBuffer *) tmp->data;
+ tmp = tmp->next;
+ buffer5 = (GstBuffer *) tmp->data;
+
+ /* Start checking the headers */
+ gst_buffer_map (buffer1, &map, GST_MAP_READ);
+ isvalid = map.size >= 1 && map.data[0] == 0x01;
+ gst_buffer_unmap (buffer1, &map);
+ if (!isvalid) {
+ GST_WARNING_OBJECT (vd, "Pending first header was invalid");
+ goto cleanup;
+ }
+
+ gst_buffer_map (buffer3, &map, GST_MAP_READ);
+ isvalid = map.size >= 1 && map.data[0] == 0x03;
+ gst_buffer_unmap (buffer3, &map);
+ if (!isvalid) {
+ GST_WARNING_OBJECT (vd, "Pending second header was invalid");
+ goto cleanup;
+ }
+
+ gst_buffer_map (buffer5, &map, GST_MAP_READ);
+ isvalid = map.size >= 1 && map.data[0] == 0x05;
+ gst_buffer_unmap (buffer5, &map);
+ if (!isvalid) {
+ GST_WARNING_OBJECT (vd, "Pending third header was invalid");
+ goto cleanup;
+ }
+
+ /* Discard any other pending headers */
+ if (tmp->next) {
+ GST_DEBUG_OBJECT (vd, "Discarding extra headers");
+ g_list_free_full (tmp->next, (GDestroyNotify) gst_buffer_unref);
+ tmp->next = NULL;
+ }
+ g_list_free (vd->pending_headers);
+ vd->pending_headers = NULL;
+
+ GST_DEBUG_OBJECT (vd, "Resetting and processing new headers");
+
+ /* All good, let's reset ourselves and process the headers */
+ vorbis_dec_reset ((GstAudioDecoder *) vd);
+ result = vorbis_dec_handle_header_buffer (vd, buffer1);
+ if (result != GST_FLOW_OK) {
+ gst_buffer_unref (buffer3);
+ gst_buffer_unref (buffer5);
+ return result;
+ }
+ result = vorbis_dec_handle_header_buffer (vd, buffer3);
+ if (result != GST_FLOW_OK) {
+ gst_buffer_unref (buffer5);
+ return result;
+ }
+ result = vorbis_dec_handle_header_buffer (vd, buffer5);
+
+ return result;
+
+ /* ERRORS */
+cleanup:
+ {
+ g_list_free_full (vd->pending_headers, (GDestroyNotify) gst_buffer_unref);
+ vd->pending_headers = NULL;
+ return result;
+ }
+not_enough:
+ {
+ GST_LOG_OBJECT (vd,
+ "Not enough pending headers to properly reset, ignoring them");
+ goto cleanup;
+ }
+}
+
+static GstFlowReturn
vorbis_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
{
ogg_packet *packet;
@@ -582,13 +672,15 @@ vorbis_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
/* switch depending on packet type */
if ((gst_ogg_packet_data (packet))[0] & 1) {
- /* If we get a new initialization packet, reset the decoder.
- * The vorbis_info struct should have a rate of 0 if it hasn't been
- * initialized yet. */
- if ((vd->initialized || (vd->vi.rate != 0)) &&
- (gst_ogg_packet_data (packet))[0] == 0x01) {
- GST_INFO_OBJECT (vd, "already initialized, re-init");
- vorbis_dec_reset (dec);
+ /* If we get a new initialization packet after being initialized,
+ * store it.
+ * When the next non-header buffer comes in, we will check whether
+ * those pending headers are correct and if so reset ourselves */
+ if (vd->initialized) {
+ GST_LOG_OBJECT (vd, "storing header for later analyzis");
+ vd->pending_headers =
+ g_list_append (vd->pending_headers, gst_buffer_ref (buffer));
+ goto done;
}
result = vorbis_handle_header_packet (vd, packet);
if (result != GST_FLOW_OK)
@@ -598,6 +690,11 @@ vorbis_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
} else {
GstClockTime timestamp, duration;
+ if (vd->pending_headers)
+ result = check_pending_headers (vd);
+ if (G_UNLIKELY (result != GST_FLOW_OK))
+ goto done;
+
timestamp = GST_BUFFER_TIMESTAMP (buffer);
duration = GST_BUFFER_DURATION (buffer);
diff --git a/ext/vorbis/gstvorbisdec.h b/ext/vorbis/gstvorbisdec.h
index 78d275fda..917d9046c 100644
--- a/ext/vorbis/gstvorbisdec.h
+++ b/ext/vorbis/gstvorbisdec.h
@@ -65,6 +65,8 @@ struct _GstVorbisDec {
GstAudioInfo info;
CopySampleFunc copy_samples;
+
+ GList *pending_headers;
};
struct _GstVorbisDecClass {