static gboolean gst_vorbis_enc_sink_event (GstAudioEncoder * enc, GstEvent * event) { GstVorbisEnc *vorbisenc; vorbisenc = GST_VORBISENC (enc); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG: if (vorbisenc->tags) { GstTagList *list; gst_event_parse_tag (event, &list); gst_tag_list_insert (vorbisenc->tags, list, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc))); } else { g_assert_not_reached (); } break; /* fall through */ default: break; } /* we only peeked, let base class handle it */ return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event); }
static gboolean gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event) { gboolean res = TRUE; GstVorbisEnc *vorbisenc; vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* Tell the library we're at end of stream so that it can handle * the last frame and mark end of stream in the output properly */ GST_DEBUG_OBJECT (vorbisenc, "EOS, clearing state and sending event on"); gst_vorbis_enc_clear (vorbisenc); res = gst_pad_push_event (vorbisenc->srcpad, event); break; case GST_EVENT_TAG: if (vorbisenc->tags) { GstTagList *list; gst_event_parse_tag (event, &list); gst_tag_list_insert (vorbisenc->tags, list, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc))); } else { g_assert_not_reached (); } res = gst_pad_push_event (vorbisenc->srcpad, event); break; default: res = gst_pad_push_event (vorbisenc->srcpad, event); break; } return res; }
static gboolean gst_a2dp_sink_handle_event (GstPad * pad, GstObject * pad_parent, GstEvent * event) { GstA2dpSink *self; GstTagList *taglist = NULL; self = GST_A2DP_SINK (pad_parent); if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) { if (self->taglist == NULL) gst_event_parse_tag (event, &self->taglist); else { gst_event_parse_tag (event, &taglist); gst_tag_list_insert (self->taglist, taglist, GST_TAG_MERGE_REPLACE); } } else if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) { GstCaps *caps = NULL; gst_event_parse_caps (event, &caps); gst_a2dp_sink_init_dynamic_elements (self, caps); } return gst_pad_event_default (pad, pad_parent, event); }
static inline void extract_and_queue_tags (GstJpegParse * parse, guint size, guint8 * data, GstTagList * (*tag_func) (const GstBuffer * buff)) { GstTagList *tags; GstBuffer *buf; buf = gst_buffer_new (); GST_BUFFER_DATA (buf) = data; GST_BUFFER_SIZE (buf) = size; tags = tag_func (buf); gst_buffer_unref (buf); if (tags) { GstTagList *taglist = parse->priv->tags; if (taglist) { gst_tag_list_insert (taglist, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_free (tags); } else { parse->priv->tags = tags; } GST_DEBUG_OBJECT (parse, "collected tags: %" GST_PTR_FORMAT, parse->priv->tags); } }
static gboolean validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data) { GMainLoop *loop = (GMainLoop *) data; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: fail_if (TRUE, "validating captured data failed"); g_main_loop_quit (loop); break; case GST_MESSAGE_EOS: g_main_loop_quit (loop); GST_DEBUG ("eos"); break; case GST_MESSAGE_TAG:{ GstTagList *tags = NULL; gst_message_parse_tag (message, &tags); if (validation_taglist) { gst_tag_list_insert (validation_taglist, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_free (tags); } else validation_taglist = tags; break; } default: break; } return TRUE; }
/* used for catching newsegment events while we don't have a sink, for * later forwarding it to the sink */ static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event) { GstA2dpSink *self; GstTagList *taglist = NULL; GstObject *parent; self = GST_A2DP_SINK(GST_PAD_PARENT(pad)); parent = gst_element_get_parent(GST_ELEMENT(self->sink)); if (GST_EVENT_TYPE(event) == GST_EVENT_NEWSEGMENT && parent != GST_OBJECT_CAST(self)) { if (self->newseg_event != NULL) gst_event_unref(self->newseg_event); self->newseg_event = gst_event_ref(event); } else if (GST_EVENT_TYPE(event) == GST_EVENT_TAG && parent != GST_OBJECT_CAST(self)) { if (self->taglist == NULL) gst_event_parse_tag(event, &self->taglist); else { gst_event_parse_tag(event, &taglist); gst_tag_list_insert(self->taglist, taglist, GST_TAG_MERGE_REPLACE); } } if (parent != NULL) gst_object_unref(GST_OBJECT(parent)); return self->ghostpad_eventfunc(GST_PAD(self->ghostpad), event); }
static inline void extract_and_queue_tags (GstJpegParse * parse, guint size, guint8 * data, GstTagList * (*tag_func) (GstBuffer * buff)) { GstTagList *tags; GstBuffer *buf; buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, data, size, 0, size, NULL, NULL); tags = tag_func (buf); gst_buffer_unref (buf); if (tags) { GstTagList *taglist = parse->priv->tags; if (taglist) { gst_tag_list_insert (taglist, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_unref (tags); } else { parse->priv->tags = tags; } GST_DEBUG_OBJECT (parse, "collected tags: %" GST_PTR_FORMAT, parse->priv->tags); } }
EXPORT_C #endif GstTagList * gst_tag_list_merge (const GstTagList * list1, const GstTagList * list2, GstTagMergeMode mode) { g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL); g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL); g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL); if (!list1 && !list2) { return NULL; } else if (!list1) { return gst_tag_list_copy (list2); } else if (!list2) { return gst_tag_list_copy (list1); } else { GstTagList *ret; ret = gst_tag_list_copy (list1); gst_tag_list_insert (ret, list2, mode); return ret; } }
static gboolean gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event) { GstSpeexEnc *enc; enc = GST_SPEEX_ENC (benc); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG: { if (enc->tags) { GstTagList *list; gst_event_parse_tag (event, &list); gst_tag_list_insert (enc->tags, list, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc))); } else { g_assert_not_reached (); } break; } default: break; } /* we only peeked, let base class handle it */ return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event); }
static gboolean gst_jpeg_parse_sink_event (GstPad * pad, GstEvent * event) { GstJpegParse *parse; gboolean res = TRUE; parse = GST_JPEG_PARSE (gst_pad_get_parent (pad)); GST_DEBUG_OBJECT (parse, "event : %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: parse->priv->next_ts = GST_CLOCK_TIME_NONE; parse->priv->duration = GST_CLOCK_TIME_NONE; parse->priv->last_offset = 0; parse->priv->last_entropy_len = 0; parse->priv->last_resync = FALSE; gst_adapter_clear (parse->priv->adapter); break; case GST_EVENT_EOS:{ /* Push the remaining data, even though it's incomplete */ guint available = gst_adapter_available (parse->priv->adapter); if (available > 0) gst_jpeg_parse_push_buffer (parse, available); res = gst_pad_push_event (parse->priv->srcpad, event); break; } case GST_EVENT_NEWSEGMENT: /* Discard any data in the adapter. There should have been an EOS before * to flush it. */ gst_adapter_clear (parse->priv->adapter); res = gst_pad_push_event (parse->priv->srcpad, event); parse->priv->new_segment = TRUE; break; case GST_EVENT_TAG:{ if (!parse->priv->new_segment) res = gst_pad_event_default (pad, event); else { GstTagList *taglist = NULL; gst_event_parse_tag (event, &taglist); /* Hold on to the tags till the srcpad caps are definitely set */ gst_tag_list_insert (get_tag_list (parse), taglist, GST_TAG_MERGE_REPLACE); GST_DEBUG ("collected tags: %" GST_PTR_FORMAT, parse->priv->tags); gst_event_unref (event); } break; } default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (parse); return res; }
void tag_list::insert(tag_list const &p_other, GstTagMergeMode const p_merge_mode) { // Safety check if (p_other.get_tag_list() == m_tag_list) return; if (m_tag_list == NULL) m_tag_list = gst_tag_list_new_empty(); gst_tag_list_insert(m_tag_list, p_other.get_tag_list(), p_merge_mode); }
static gboolean gst_shout2send_event (GstBaseSink * sink, GstEvent * event) { GstShout2send *shout2send; gboolean ret = TRUE; shout2send = GST_SHOUT2SEND (sink); GST_LOG_OBJECT (shout2send, "got %s event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG:{ /* vorbis audio doesnt need metadata setting on the icecast level, only mp3 */ if (shout2send->tags && shout2send->audio_format == SHOUT_FORMAT_MP3) { GstTagList *list; gst_event_parse_tag (event, &list); GST_DEBUG_OBJECT (shout2send, "tags=%" GST_PTR_FORMAT, list); gst_tag_list_insert (shout2send->tags, list, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (shout2send))); /* lets get the artist and song tags */ gst_tag_list_foreach ((GstTagList *) list, set_shout_metadata, shout2send); if (shout2send->songmetadata && shout2send->connected) { shout_metadata_t *pmetadata; GST_DEBUG_OBJECT (shout2send, "metadata now: %s", shout2send->songmetadata); pmetadata = shout_metadata_new (); shout_metadata_add (pmetadata, "song", shout2send->songmetadata); shout_set_metadata (shout2send->conn, pmetadata); shout_metadata_free (pmetadata); } } break; } default:{ GST_LOG_OBJECT (shout2send, "let base class handle event"); if (GST_BASE_SINK_CLASS (parent_class)->event) { event = gst_event_ref (event); ret = GST_BASE_SINK_CLASS (parent_class)->event (sink, event); } break; } } return ret; }
/* takes ownership of tag list */ static gboolean gst_icydemux_tag_found (GstICYDemux * icydemux, GstTagList * tags) { /* send the tag event if we have finished typefinding and have a src pad */ if (icydemux->srcpad) return gst_icydemux_send_tag_event (icydemux, tags); /* if we haven't a source pad yet, cache the tags */ if (!icydemux->cached_tags) { icydemux->cached_tags = tags; } else { gst_tag_list_insert (icydemux->cached_tags, tags, GST_TAG_MERGE_REPLACE_ALL); gst_tag_list_free (tags); } return TRUE; }
/** * gst_tag_setter_merge_tags: * @setter: a #GstTagSetter * @list: a tag list to merge from * @mode: the mode to merge with * * Merges the given list into the setter's list using the given mode. */ void gst_tag_setter_merge_tags (GstTagSetter * setter, const GstTagList * list, GstTagMergeMode mode) { GstTagData *data; g_return_if_fail (GST_IS_TAG_SETTER (setter)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (GST_IS_TAG_LIST (list)); data = gst_tag_setter_get_data (setter); if (data->list == NULL) { if (mode != GST_TAG_MERGE_KEEP_ALL) data->list = gst_tag_list_copy (list); } else { gst_tag_list_insert (data->list, list, mode); } }
static gboolean gst_speex_enc_sinkevent (GstPad * pad, GstEvent * event) { gboolean res = TRUE; GstSpeexEnc *enc; enc = GST_SPEEX_ENC (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: if (enc->setup) gst_speex_enc_encode (enc, TRUE); res = gst_pad_event_default (pad, event); break; case GST_EVENT_TAG: { if (enc->tags) { GstTagList *list; gst_event_parse_tag (event, &list); gst_tag_list_insert (enc->tags, list, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc))); } else { g_assert_not_reached (); } res = gst_pad_event_default (pad, event); break; } default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (enc); return res; }
static gboolean gst_tag_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstTagMux *mux; gboolean result; mux = GST_TAG_MUX (parent); result = FALSE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG:{ GstTagList *tags; gst_event_parse_tag (event, &tags); GST_INFO_OBJECT (mux, "Got tag event: %" GST_PTR_FORMAT, tags); if (mux->priv->event_tags != NULL) { gst_tag_list_insert (mux->priv->event_tags, tags, GST_TAG_MERGE_REPLACE); } else { mux->priv->event_tags = gst_tag_list_copy (tags); } GST_INFO_OBJECT (mux, "Event tags are now: %" GST_PTR_FORMAT, mux->priv->event_tags); /* just drop the event, we'll push a new tag event in render_start_tag */ gst_event_unref (event); result = TRUE; break; } case GST_EVENT_SEGMENT: { GstSegment segment; gst_event_copy_segment (event, &segment); if (segment.format != GST_FORMAT_BYTES) { GST_WARNING_OBJECT (mux, "dropping newsegment event in %s format", gst_format_get_name (segment.format)); gst_event_unref (event); /* drop it quietly, so it is not seen as a failure to push event, * which will turn into failure to push data as it is sticky */ result = TRUE; break; } if (mux->priv->render_start_tag) { /* we have not rendered the tag yet, which means that we don't know * how large it is going to be yet, so we can't adjust the offsets * here at this point and need to cache the newsegment event for now * (also, there could be tag events coming after this newsegment event * and before the first buffer). */ if (mux->priv->newsegment_ev) { GST_WARNING_OBJECT (mux, "discarding old cached newsegment event"); gst_event_unref (mux->priv->newsegment_ev); } GST_LOG_OBJECT (mux, "caching newsegment event for later"); mux->priv->newsegment_ev = event; } else { GST_DEBUG_OBJECT (mux, "got newsegment event, adjusting offsets"); gst_pad_push_event (mux->priv->srcpad, gst_tag_mux_adjust_event_offsets (mux, event)); gst_event_unref (event); mux->priv->current_offset = segment.start; mux->priv->max_offset = MAX (mux->priv->max_offset, mux->priv->current_offset); } event = NULL; result = TRUE; break; } case GST_EVENT_EOS:{ if (mux->priv->render_end_tag) { GstFlowReturn ret; GST_INFO_OBJECT (mux, "Adding tags to stream"); ret = gst_tag_mux_render_end_tag (mux); if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (mux, "flow: %s", gst_flow_get_name (ret)); return ret; } mux->priv->render_end_tag = FALSE; } /* Now forward EOS */ result = gst_pad_event_default (pad, parent, event); break; } default: result = gst_pad_event_default (pad, parent, event); break; } return result; }
static gboolean gst_tag_lib_mux_sink_event (GstPad * pad, GstEvent * event) { GstTagLibMux *mux; gboolean result; mux = GST_TAG_LIB_MUX (gst_pad_get_parent (pad)); result = FALSE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG:{ GstTagList *tags; gst_event_parse_tag (event, &tags); GST_INFO_OBJECT (mux, "Got tag event: %" GST_PTR_FORMAT, tags); if (mux->event_tags != NULL) { gst_tag_list_insert (mux->event_tags, tags, GST_TAG_MERGE_REPLACE); } else { mux->event_tags = gst_tag_list_copy (tags); } GST_INFO_OBJECT (mux, "Event tags are now: %" GST_PTR_FORMAT, mux->event_tags); /* just drop the event, we'll push a new tag event in render_tag */ gst_event_unref (event); result = TRUE; break; } case GST_EVENT_NEWSEGMENT:{ GstFormat fmt; gst_event_parse_new_segment (event, NULL, NULL, &fmt, NULL, NULL, NULL); if (fmt != GST_FORMAT_BYTES) { GST_WARNING_OBJECT (mux, "dropping newsegment event in %s format", gst_format_get_name (fmt)); gst_event_unref (event); break; } if (mux->render_tag) { /* we have not rendered the tag yet, which means that we don't know * how large it is going to be yet, so we can't adjust the offsets * here at this point and need to cache the newsegment event for now * (also, there could be tag events coming after this newsegment event * and before the first buffer). */ if (mux->newsegment_ev) { GST_WARNING_OBJECT (mux, "discarding old cached newsegment event"); gst_event_unref (mux->newsegment_ev); } GST_LOG_OBJECT (mux, "caching newsegment event for later"); mux->newsegment_ev = event; } else { GST_DEBUG_OBJECT (mux, "got newsegment event, adjusting offsets"); gst_pad_push_event (mux->srcpad, gst_tag_lib_mux_adjust_event_offsets (mux, event)); gst_event_unref (event); } event = NULL; result = TRUE; break; } default: result = gst_pad_event_default (pad, event); break; } gst_object_unref (mux); return result; }
static void gst_icydemux_parse_and_send_tags (GstICYDemux * icydemux) { GstTagList *tags = gst_tag_list_new (); const guint8 *data; int length, i; gchar *buffer; gchar **strings; gboolean found_tag = FALSE; length = gst_adapter_available (icydemux->meta_adapter); data = gst_adapter_peek (icydemux->meta_adapter, length); /* Now, copy this to a buffer where we can NULL-terminate it to make things * a bit easier, then do that parsing. */ buffer = g_malloc (length + 1); memcpy (buffer, data, length); buffer[length] = 0; strings = g_strsplit (buffer, "';", 0); for (i = 0; strings[i]; i++) { if (!g_ascii_strncasecmp (strings[i], "StreamTitle=", 12)) { char *title = gst_icydemux_unicodify (strings[i] + 13); if (title && *title) { gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, title, NULL); g_free (title); found_tag = TRUE; } } else if (!g_ascii_strncasecmp (strings[i], "StreamUrl=", 10)) { char *url = gst_icydemux_unicodify (strings[i] + 11); if (url) { /* gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_URL, url, NULL); found_tag = TRUE; */ g_free (url); } } } g_strfreev (strings); g_free (buffer); gst_adapter_clear (icydemux->meta_adapter); if (found_tag) { if (icydemux->srcpad) { gst_icydemux_send_tag_event (icydemux, tags); } else { if (!icydemux->cached_tags) { icydemux->cached_tags = gst_tag_list_new (); } gst_tag_list_insert (icydemux->cached_tags, tags, GST_TAG_MERGE_REPLACE_ALL); } } }
static gboolean gst_kate_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstKateEnc *ke = GST_KATE_ENC (parent); const GstStructure *structure; gboolean ret; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); ret = gst_kate_enc_setcaps (ke, caps); gst_event_unref (event); break; } case GST_EVENT_SEGMENT:{ GstSegment seg; GST_LOG_OBJECT (ke, "Got newsegment event"); gst_event_copy_segment (event, &seg); if (!ke->headers_sent) { if (ke->pending_segment) gst_event_unref (ke->pending_segment); ke->pending_segment = event; event = NULL; } if (ke->initialized) { GST_LOG_OBJECT (ke, "ensuring all headers are in"); if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) { GST_WARNING_OBJECT (ke, "Failed to flush headers"); } else { if (seg.format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (seg.start)) { GST_WARNING_OBJECT (ke, "No time in newsegment event %p, format %d, timestamp %" G_GINT64_FORMAT, event, (int) seg.format, seg.start); /* to be safe, we'd need to generate a keepalive anyway, but we'd have to guess at the timestamp to use; a good guess would be the last known timestamp plus the keepalive time, but if we then get a packet with a timestamp less than this, it would fail to encode, which would be Bad. If we don't encode a keepalive, we run the risk of stalling the pipeline and hanging, which is Very Bad. Oh dear. We can't exit(-1), can we ? */ } else { float t = seg.start / (double) GST_SECOND; if (ke->delayed_spu && t - ke->delayed_start / (double) GST_SECOND >= ke->default_spu_duration) { if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke, seg.start) != GST_FLOW_OK)) { GST_WARNING_OBJECT (ke, "Failed to encode delayed packet"); /* continue with new segment handling anyway */ } } GST_LOG_OBJECT (ke, "ts %f, last %f (min %f)", t, ke->last_timestamp / (double) GST_SECOND, ke->keepalive_min_time); if (ke->keepalive_min_time > 0.0f && t - ke->last_timestamp / (double) GST_SECOND >= ke->keepalive_min_time) { /* we only generate a keepalive if there is no SPU waiting, as it would mean out of sequence start times - and granulepos */ if (!ke->delayed_spu) { gst_kate_enc_generate_keepalive (ke, seg.start); } } } } } if (event) ret = gst_pad_push_event (ke->srcpad, event); else ret = TRUE; break; } case GST_EVENT_CUSTOM_DOWNSTREAM: GST_LOG_OBJECT (ke, "Got custom downstream event"); /* adapted from the dvdsubdec element */ structure = gst_event_get_structure (event); if (structure != NULL && gst_structure_has_name (structure, "application/x-gst-dvd")) { if (ke->initialized) { GST_LOG_OBJECT (ke, "ensuring all headers are in"); if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) { GST_WARNING_OBJECT (ke, "Failed to flush headers"); } else { const gchar *event_name = gst_structure_get_string (structure, "event"); if (event_name) { if (!strcmp (event_name, "dvd-spu-clut-change")) { gchar name[16]; int idx; gboolean found; gint value; GST_INFO_OBJECT (ke, "New CLUT received"); for (idx = 0; idx < 16; ++idx) { g_snprintf (name, sizeof (name), "clut%02d", idx); found = gst_structure_get_int (structure, name, &value); if (found) { ke->spu_clut[idx] = value; } else { GST_WARNING_OBJECT (ke, "DVD CLUT event did not contain %s field", name); } } } else if (!strcmp (event_name, "dvd-lang-codes")) { /* we can't know which stream corresponds to us */ } } else { GST_WARNING_OBJECT (ke, "custom downstream event with no name"); } } } } ret = gst_pad_push_event (ke->srcpad, event); break; case GST_EVENT_TAG: GST_LOG_OBJECT (ke, "Got tag event"); if (ke->tags) { GstTagList *list; gst_event_parse_tag (event, &list); gst_tag_list_insert (ke->tags, list, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke))); } else { g_assert_not_reached (); } ret = gst_pad_event_default (pad, parent, event); break; case GST_EVENT_EOS: GST_INFO_OBJECT (ke, "Got EOS event"); if (ke->initialized) { GST_LOG_OBJECT (ke, "ensuring all headers are in"); if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) { GST_WARNING_OBJECT (ke, "Failed to flush headers"); } else { kate_packet kp; int ret; GstClockTime delayed_end = ke->delayed_start + ke->default_spu_duration * GST_SECOND; if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke, delayed_end) != GST_FLOW_OK)) { GST_WARNING_OBJECT (ke, "Failed to encode delayed packet"); /* continue with EOS handling anyway */ } ret = kate_encode_finish (&ke->k, -1, &kp); if (ret < 0) { GST_WARNING_OBJECT (ke, "Failed to encode EOS packet: %s", gst_kate_util_get_error_message (ret)); } else { kate_int64_t granpos = kate_encode_get_granule (&ke->k); GST_LOG_OBJECT (ke, "EOS packet encoded"); if (gst_kate_enc_push_and_free_kate_packet (ke, &kp, granpos, ke->latest_end_time, 0, FALSE)) { GST_WARNING_OBJECT (ke, "Failed to push EOS packet"); } } } } ret = gst_pad_event_default (pad, parent, event); break; default: GST_LOG_OBJECT (ke, "Got unhandled event"); ret = gst_pad_event_default (pad, parent, event); break; } return ret; }
static GstFlowReturn gst_aiff_parse_stream_headers (GstAiffParse * aiff) { GstFlowReturn res; GstBuffer *buf; guint32 tag, size; gboolean gotdata = FALSE; gboolean done = FALSE; GstEvent **event_p; GstFormat bformat; gint64 upstream_size = 0; bformat = GST_FORMAT_BYTES; gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size); GST_DEBUG_OBJECT (aiff, "upstream size %" G_GUINT64_FORMAT, upstream_size); /* loop headers until we get data */ while (!done) { if (aiff->streaming) { if (!gst_aiff_parse_peek_chunk_info (aiff, &tag, &size)) return GST_FLOW_OK; } else { if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset, 8, &buf)) != GST_FLOW_OK) goto header_read_error; tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + 4); } GST_INFO_OBJECT (aiff, "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (tag), aiff->offset); /* We just keep reading chunks until we find the one we're interested in. */ switch (tag) { case GST_MAKE_FOURCC ('C', 'O', 'M', 'M'):{ if (aiff->streaming) { if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size)) return GST_FLOW_OK; gst_adapter_flush (aiff->adapter, 8); aiff->offset += 8; buf = gst_adapter_take_buffer (aiff->adapter, size); } else { if ((res = gst_aiff_parse_read_chunk (aiff, &aiff->offset, &tag, &buf)) != GST_FLOW_OK) return res; } if (!gst_aiff_parse_parse_comm (aiff, buf)) { gst_buffer_unref (buf); goto parse_header_error; } gst_buffer_unref (buf); /* do sanity checks of header fields */ if (aiff->channels == 0) goto no_channels; if (aiff->rate == 0) goto no_rate; GST_DEBUG_OBJECT (aiff, "creating the caps"); aiff->caps = gst_aiff_parse_create_caps (aiff); if (!aiff->caps) goto unknown_format; gst_pad_set_caps (aiff->srcpad, aiff->caps); aiff->bytes_per_sample = aiff->channels * aiff->width / 8; aiff->bps = aiff->bytes_per_sample * aiff->rate; if (aiff->bytes_per_sample <= 0) goto no_bytes_per_sample; aiff->got_comm = TRUE; break; } case GST_MAKE_FOURCC ('S', 'S', 'N', 'D'):{ GstBuffer *ssndbuf = NULL; const guint8 *ssnddata = NULL; guint32 datasize; GST_DEBUG_OBJECT (aiff, "Got 'SSND' TAG, size : %d", size); /* Now, read the 8-byte header in the SSND chunk */ if (aiff->streaming) { if (!gst_aiff_parse_peek_data (aiff, 16, &ssnddata)) return GST_FLOW_OK; } else { gst_buffer_unref (buf); if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset, 16, &ssndbuf)) != GST_FLOW_OK) goto header_read_error; ssnddata = GST_BUFFER_DATA (ssndbuf); } aiff->ssnd_offset = GST_READ_UINT32_BE (ssnddata + 8); aiff->ssnd_blocksize = GST_READ_UINT32_BE (ssnddata + 12); gotdata = TRUE; if (aiff->streaming) { gst_adapter_flush (aiff->adapter, 16); } else { gst_buffer_unref (ssndbuf); } /* 8 byte chunk header, 8 byte SSND header */ aiff->offset += 16; datasize = size - 16; aiff->datastart = aiff->offset + aiff->ssnd_offset; /* file might be truncated */ if (upstream_size) { size = MIN (datasize, (upstream_size - aiff->datastart)); } aiff->datasize = (guint64) datasize; aiff->dataleft = (guint64) datasize; aiff->end_offset = datasize + aiff->datastart; if (!aiff->streaming) { /* We will continue looking at chunks until the end - to read tags, * etc. */ aiff->offset += datasize; } GST_DEBUG_OBJECT (aiff, "datasize = %d", datasize); if (aiff->streaming) { done = TRUE; } break; } case GST_MAKE_FOURCC ('I', 'D', '3', ' '):{ GstTagList *tags; if (aiff->streaming) { if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size)) return GST_FLOW_OK; gst_adapter_flush (aiff->adapter, 8); aiff->offset += 8; buf = gst_adapter_take_buffer (aiff->adapter, size); } else { if ((res = gst_aiff_parse_read_chunk (aiff, &aiff->offset, &tag, &buf)) != GST_FLOW_OK) return res; } GST_LOG_OBJECT (aiff, "ID3 chunk of size %u", GST_BUFFER_SIZE (buf)); tags = gst_tag_list_from_id3v2_tag (buf); gst_buffer_unref (buf); GST_INFO_OBJECT (aiff, "ID3 tags: %" GST_PTR_FORMAT, tags); if (aiff->tags == NULL) { aiff->tags = tags; } else { gst_tag_list_insert (aiff->tags, tags, GST_TAG_MERGE_APPEND); gst_tag_list_free (tags); } break; } default: gst_aiff_parse_ignore_chunk (aiff, buf, tag, size); } if (upstream_size && (aiff->offset >= upstream_size)) { /* Now we have gone through the whole file */ done = TRUE; } } /* We read all the chunks (in pull mode) or reached the SSND chunk * (in push mode). We must have both COMM and SSND now; error out * otherwise. */ if (!aiff->got_comm) { GST_WARNING_OBJECT (aiff, "Failed to find COMM chunk"); goto no_header; } if (!gotdata) { GST_WARNING_OBJECT (aiff, "Failed to find SSND chunk"); goto no_data; } GST_DEBUG_OBJECT (aiff, "Finished parsing headers"); if (gst_aiff_parse_calculate_duration (aiff)) { gst_segment_init (&aiff->segment, GST_FORMAT_TIME); gst_segment_set_duration (&aiff->segment, GST_FORMAT_TIME, aiff->duration); } else { /* no bitrate, let downstream peer do the math, we'll feed it bytes. */ gst_segment_init (&aiff->segment, GST_FORMAT_BYTES); gst_segment_set_duration (&aiff->segment, GST_FORMAT_BYTES, aiff->datasize); } /* now we have all the info to perform a pending seek if any, if no * event, this will still do the right thing and it will also send * the right newsegment event downstream. */ gst_aiff_parse_perform_seek (aiff, aiff->seek_event); /* remove pending event */ event_p = &aiff->seek_event; gst_event_replace (event_p, NULL); /* we just started, we are discont */ aiff->discont = TRUE; aiff->state = AIFF_PARSE_DATA; return GST_FLOW_OK; /* ERROR */ no_header: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("Invalid AIFF header (no COMM found)")); return GST_FLOW_ERROR; } no_data: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("Invalid AIFF: no SSND found")); return GST_FLOW_ERROR; } parse_header_error: { GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL), ("Couldn't parse audio header")); return GST_FLOW_ERROR; } no_channels: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Stream claims to contain no channels - invalid data")); return GST_FLOW_ERROR; } no_rate: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Stream with sample_rate == 0 - invalid data")); return GST_FLOW_ERROR; } no_bytes_per_sample: { GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL), ("Could not caluclate bytes per sample - invalid data")); return GST_FLOW_ERROR; } unknown_format: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), ("No caps found for format 0x%x, %d channels, %d Hz", aiff->format, aiff->channels, aiff->rate)); return GST_FLOW_ERROR; } header_read_error: { GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL), ("Couldn't read in header")); return GST_FLOW_ERROR; } }