static gboolean gst_ogg_avi_parse_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstOggAviParse *ogg; gboolean ret; ogg = GST_OGG_AVI_PARSE (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); ret = gst_ogg_avi_parse_setcaps (pad, caps); gst_event_unref (event); break; } case GST_EVENT_FLUSH_START: ret = gst_pad_push_event (ogg->srcpad, event); break; case GST_EVENT_FLUSH_STOP: ogg_sync_reset (&ogg->sync); ogg_stream_reset (&ogg->stream); ogg->discont = TRUE; ret = gst_pad_push_event (ogg->srcpad, event); break; default: ret = gst_pad_push_event (ogg->srcpad, event); break; } return ret; }
static void gst_ogg_avi_parse_finalize (GObject * object) { GstOggAviParse *ogg = GST_OGG_AVI_PARSE (object); GST_LOG_OBJECT (ogg, "Disposing of object %p", ogg); ogg_sync_clear (&ogg->sync); ogg_stream_clear (&ogg->stream); G_OBJECT_CLASS (parent_class)->finalize (object); }
static GstStateChangeReturn gst_ogg_avi_parse_change_state (GstElement * element, GstStateChange transition) { GstOggAviParse *ogg; GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; ogg = GST_OGG_AVI_PARSE (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: ogg_sync_init (&ogg->sync); break; case GST_STATE_CHANGE_READY_TO_PAUSED: ogg_sync_reset (&ogg->sync); ogg_stream_reset (&ogg->stream); ogg->serial = -1; ogg->discont = TRUE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } result = parent_class->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: break; case GST_STATE_CHANGE_READY_TO_NULL: ogg_sync_clear (&ogg->sync); break; default: break; } return result; }
static gboolean gst_ogg_avi_parse_event (GstPad * pad, GstEvent * event) { GstOggAviParse *ogg; gboolean ret; ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: ret = gst_pad_push_event (ogg->srcpad, event); break; case GST_EVENT_FLUSH_STOP: ogg_sync_reset (&ogg->sync); ogg_stream_reset (&ogg->stream); ogg->discont = TRUE; ret = gst_pad_push_event (ogg->srcpad, event); break; default: ret = gst_pad_push_event (ogg->srcpad, event); break; } return ret; }
static GstFlowReturn gst_ogg_avi_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstFlowReturn result = GST_FLOW_OK; GstOggAviParse *ogg; guint size; gchar *oggbuf; gint ret = -1; ogg = GST_OGG_AVI_PARSE (parent); size = gst_buffer_get_size (buffer); GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d", size); if (GST_BUFFER_IS_DISCONT (buffer)) { ogg_sync_reset (&ogg->sync); ogg->discont = TRUE; } /* write data to sync layer */ oggbuf = ogg_sync_buffer (&ogg->sync, size); gst_buffer_extract (buffer, 0, oggbuf, size); ogg_sync_wrote (&ogg->sync, size); gst_buffer_unref (buffer); /* try to get as many packets out of the stream as possible */ do { ogg_page page; /* try to swap out a page */ ret = ogg_sync_pageout (&ogg->sync, &page); if (ret == 0) { GST_DEBUG_OBJECT (ogg, "need more data"); break; } else if (ret == -1) { GST_DEBUG_OBJECT (ogg, "discont in pages"); ogg->discont = TRUE; } else { /* new unknown stream, init the ogg stream with the serial number of the * page. */ if (ogg->serial == -1) { ogg->serial = ogg_page_serialno (&page); ogg_stream_init (&ogg->stream, ogg->serial); } /* submit page */ if (ogg_stream_pagein (&ogg->stream, &page) != 0) { GST_WARNING_OBJECT (ogg, "ogg stream choked on page resetting stream"); ogg_sync_reset (&ogg->sync); ogg->discont = TRUE; continue; } /* try to get as many packets as possible out of the page */ do { ogg_packet packet; ret = ogg_stream_packetout (&ogg->stream, &packet); GST_LOG_OBJECT (ogg, "packetout gave %d", ret); switch (ret) { case 0: break; case -1: /* out of sync, We mark a DISCONT. */ ogg->discont = TRUE; break; case 1: result = gst_ogg_avi_parse_push_packet (ogg, &packet); if (result != GST_FLOW_OK) goto done; break; default: GST_WARNING_OBJECT (ogg, "invalid return value %d for ogg_stream_packetout, resetting stream", ret); break; } } while (ret != 0); } } while (ret != 0); done: return result; }
static gboolean gst_ogg_avi_parse_setcaps (GstPad * pad, GstCaps * caps) { GstOggAviParse *ogg; GstStructure *structure; const GValue *codec_data; GstBuffer *buffer; GstMapInfo map; guint8 *ptr; gsize left; guint32 sizes[3]; GstCaps *outcaps; gint i, offs; ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad)); structure = gst_caps_get_structure (caps, 0); /* take codec data */ codec_data = gst_structure_get_value (structure, "codec_data"); if (codec_data == NULL) goto no_data; /* only buffers are valid */ if (G_VALUE_TYPE (codec_data) != GST_TYPE_BUFFER) goto wrong_format; /* Now parse the data */ buffer = gst_value_get_buffer (codec_data); /* first 22 bytes are bits_per_sample, channel_mask, GUID * Then we get 3 LE guint32 with the 3 header sizes * then we get the bytes of the 3 headers. */ gst_buffer_map (buffer, &map, GST_MAP_READ); ptr = map.data; left = map.size; GST_LOG_OBJECT (ogg, "configuring codec_data of size %" G_GSIZE_FORMAT, left); /* skip headers */ ptr += 22; left -= 22; /* we need at least 12 bytes for the packet sizes of the 3 headers */ if (left < 12) goto buffer_too_small; /* read sizes of the 3 headers */ sizes[0] = GST_READ_UINT32_LE (ptr); sizes[1] = GST_READ_UINT32_LE (ptr + 4); sizes[2] = GST_READ_UINT32_LE (ptr + 8); GST_DEBUG_OBJECT (ogg, "header sizes: %u %u %u", sizes[0], sizes[1], sizes[2]); left -= 12; /* and we need at least enough data for all the headers */ if (left < sizes[0] + sizes[1] + sizes[2]) goto buffer_too_small; /* set caps */ outcaps = gst_caps_new_empty_simple ("audio/x-vorbis"); gst_pad_set_caps (ogg->srcpad, outcaps); gst_caps_unref (outcaps); /* copy header data */ offs = 34; for (i = 0; i < 3; i++) { GstBuffer *out; /* now output the raw vorbis header packets */ out = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offs, sizes[i]); gst_pad_push (ogg->srcpad, out); offs += sizes[i]; } gst_buffer_unmap (buffer, &map); return TRUE; /* ERRORS */ no_data: { GST_DEBUG_OBJECT (ogg, "no codec_data found in caps"); return FALSE; } wrong_format: { GST_DEBUG_OBJECT (ogg, "codec_data is not a buffer"); return FALSE; } buffer_too_small: { GST_DEBUG_OBJECT (ogg, "codec_data is too small"); gst_buffer_unmap (buffer, &map); return FALSE; } }