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; } }
/** * gst_toc_copy: * @toc: #GstToc to copy. * * Copy #GstToc with all subentries (deep copy). * * Returns: newly allocated #GstToc in case of success, NULL otherwise; * free it when done with gst_toc_unref(). */ static GstToc * gst_toc_copy (const GstToc * toc) { GstToc *ret; GstTocEntry *entry; GList *cur; GstTagList *list; g_return_val_if_fail (toc != NULL, NULL); ret = gst_toc_new (toc->scope); if (GST_IS_TAG_LIST (toc->tags)) { list = gst_tag_list_copy (toc->tags); gst_tag_list_unref (ret->tags); ret->tags = list; } cur = toc->entries; while (cur != NULL) { entry = gst_toc_entry_copy (cur->data); if (entry != NULL) ret->entries = g_list_prepend (ret->entries, entry); cur = cur->next; } ret->entries = g_list_reverse (ret->entries); return ret; }
static gboolean gst_icydemux_handle_event (GstPad * pad, GstEvent * event) { GstICYDemux *icydemux = GST_ICYDEMUX (GST_PAD_PARENT (pad)); gboolean result; if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) { GstTagList *tags; gst_event_parse_tag (event, &tags); result = gst_icydemux_tag_found (icydemux, gst_tag_list_copy (tags)); gst_event_unref (event); return result; } if (icydemux->typefinding) { switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: g_list_foreach (icydemux->cached_events, (GFunc) gst_mini_object_unref, NULL); g_list_free (icydemux->cached_events); icydemux->cached_events = NULL; return gst_pad_event_default (pad, event); default: icydemux->cached_events = g_list_append (icydemux->cached_events, event); return TRUE; } } else { return gst_pad_event_default (pad, event); } }
tag_list::tag_list(tag_list const &p_src) { if (p_src.m_tag_list != nullptr) m_tag_list = gst_tag_list_copy(p_src.m_tag_list); else m_tag_list = nullptr; }
static gboolean gst_mpeg_demux_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) { GstMPEGDemux *demux = GST_MPEG_DEMUX (mpeg_parse); guint8 *buf; parent_class->parse_packhead (mpeg_parse, buffer); buf = GST_BUFFER_DATA (buffer); /* do something useful here */ if (demux->pending_tags) { GstMPEGStream **streams; guint i, num; streams = demux->audio_stream; num = GST_MPEG_DEMUX_NUM_AUDIO_STREAMS; for (i = 0; i < num; ++i) { if (streams[i] != NULL && streams[i]->tags != NULL) gst_pad_push_event (streams[i]->pad, gst_event_new_tag (gst_tag_list_copy (streams[i]->tags))); } demux->pending_tags = FALSE; } return TRUE; }
/** * gst_toc_entry_copy: * @entry: #GstTocEntry to copy. * * Copy #GstTocEntry with all subentries (deep copy). * * Returns: newly allocated #GstTocEntry in case of success, NULL otherwise; * free it when done with gst_toc_entry_unref(). */ static GstTocEntry * gst_toc_entry_copy (const GstTocEntry * entry) { GstTocEntry *ret, *sub; GstTagList *list; GList *cur; g_return_val_if_fail (entry != NULL, NULL); ret = gst_toc_entry_new (entry->type, entry->uid); ret->start = entry->start; ret->stop = entry->stop; if (GST_IS_TAG_LIST (entry->tags)) { list = gst_tag_list_copy (entry->tags); if (ret->tags) gst_tag_list_unref (ret->tags); ret->tags = list; } cur = entry->subentries; while (cur != NULL) { sub = gst_toc_entry_copy (cur->data); if (sub != NULL) ret->subentries = g_list_prepend (ret->subentries, sub); cur = cur->next; } ret->subentries = g_list_reverse (ret->subentries); return ret; }
tag_list& tag_list::operator = (tag_list const &p_src) { if (m_tag_list != nullptr) gst_tag_list_unref(m_tag_list); if (p_src.m_tag_list != nullptr) m_tag_list = gst_tag_list_copy(p_src.m_tag_list); else m_tag_list = nullptr; return *this; }
static void bt_song_info_get_property (GObject * const object, const guint property_id, GValue * const value, GParamSpec * const pspec) { const BtSongInfo *const self = BT_SONG_INFO (object); return_if_disposed (); switch (property_id) { case SONG_INFO_SONG: g_value_set_object (value, self->priv->song); break; case SONG_INFO_TAGLIST: g_value_set_pointer (value, gst_tag_list_copy (self->priv->taglist)); break; case SONG_INFO_FILE_NAME: g_value_set_string (value, self->priv->file_name); break; case SONG_INFO_INFO: g_value_set_string (value, self->priv->info); break; case SONG_INFO_NAME: g_value_set_string (value, self->priv->name); break; case SONG_INFO_GENRE: g_value_set_string (value, self->priv->genre); break; case SONG_INFO_AUTHOR: g_value_set_string (value, self->priv->author); break; case SONG_INFO_BPM: g_value_set_ulong (value, self->priv->beats_per_minute); break; case SONG_INFO_TPB: g_value_set_ulong (value, self->priv->ticks_per_beat); break; case SONG_INFO_BARS: g_value_set_ulong (value, self->priv->bars); break; case SONG_INFO_CREATE_DTS: g_value_set_string (value, self->priv->create_dts); break; case SONG_INFO_CHANGE_DTS: g_value_set_string (value, self->priv->change_dts); break; case SONG_INFO_TICK_DURATION: g_value_set_uint64 (value, self->priv->tick_duration); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
/* takes ownership of tag list */ static gboolean gst_icydemux_send_tag_event (GstICYDemux * icydemux, GstTagList * tags) { GstEvent *event; gst_element_post_message (GST_ELEMENT (icydemux), gst_message_new_tag (GST_OBJECT (icydemux), gst_tag_list_copy (tags))); event = gst_event_new_tag (tags); GST_EVENT_TIMESTAMP (event) = 0; GST_DEBUG_OBJECT (icydemux, "Sending tag event on src pad"); return gst_pad_push_event (icydemux->srcpad, event); }
static void nemo_preview_cover_art_fetcher_set_taglist (NemoPreviewCoverArtFetcher *self, GstTagList *taglist) { NemoPreviewCoverArtFetcherPrivate *priv = NEMO_PREVIEW_COVER_ART_FETCHER_GET_PRIVATE (self); g_clear_object (&priv->cover); if (priv->taglist != NULL) { gst_tag_list_free (priv->taglist); priv->taglist = NULL; } priv->taglist = gst_tag_list_copy (taglist); try_fetch_from_tags (self); }
static GstFlowReturn gst_tag_inject_transform_ip (GstBaseTransform * trans, GstBuffer * buf) { GstTagInject *self = GST_TAG_INJECT (trans); if (G_UNLIKELY (!self->tags_sent)) { self->tags_sent = TRUE; /* send tags */ if (self->tags && !gst_tag_list_is_empty (self->tags)) { GST_DEBUG ("tag event :%" GST_PTR_FORMAT, self->tags); gst_element_found_tags (GST_ELEMENT (trans), gst_tag_list_copy (self->tags)); } } return GST_FLOW_OK; }
static GstDiscovererStreamInfo * gst_discoverer_info_copy_int (GstDiscovererStreamInfo * info, GHashTable * stream_map) { GstDiscovererStreamInfo *ret; GType ltyp; g_return_val_if_fail (info != NULL, NULL); ltyp = G_TYPE_FROM_INSTANCE (info); if (ltyp == GST_TYPE_DISCOVERER_CONTAINER_INFO) { ret = (GstDiscovererStreamInfo *) gst_stream_container_info_copy_int ( (GstDiscovererContainerInfo *) info, stream_map); } else if (ltyp == GST_TYPE_DISCOVERER_AUDIO_INFO) { ret = (GstDiscovererStreamInfo *) gst_discoverer_audio_info_copy_int ((GstDiscovererAudioInfo *) info); } else if (ltyp == GST_TYPE_DISCOVERER_VIDEO_INFO) { ret = (GstDiscovererStreamInfo *) gst_discoverer_video_info_copy_int ((GstDiscovererVideoInfo *) info); } else ret = gst_discoverer_stream_info_new (); if (info->next) { ret->next = gst_discoverer_info_copy_int (info->next, stream_map); ret->next->previous = ret; } if (info->caps) ret->caps = gst_caps_copy (info->caps); if (info->tags) ret->tags = gst_tag_list_copy (info->tags); if (info->misc) ret->misc = gst_structure_copy (info->misc); if (stream_map) g_hash_table_insert (stream_map, info, ret); return ret; }
/** * 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 void avrcp_metadata_cb (GstAvrcpConnection * avrcp, GstTagList * taglist, gpointer user_data) { GstAvdtpSrc *src = GST_AVDTP_SRC (user_data); guint64 duration; if (gst_tag_list_get_uint64 (taglist, GST_TAG_DURATION, &duration)) { src->duration = duration; gst_element_post_message (GST_ELEMENT (src), gst_message_new_duration_changed (GST_OBJECT (src))); } gst_pad_push_event (GST_BASE_SRC_PAD (src), gst_event_new_tag (gst_tag_list_copy (taglist))); gst_element_post_message (GST_ELEMENT (src), gst_message_new_tag (GST_OBJECT (src), taglist)); }
GstDiscovererInfo * gst_discoverer_info_copy (GstDiscovererInfo * ptr) { GstDiscovererInfo *ret; GHashTable *stream_map = g_hash_table_new (g_direct_hash, NULL); GList *tmp; g_return_val_if_fail (ptr != NULL, NULL); ret = gst_discoverer_info_new (); ret->uri = g_strdup (ptr->uri); if (ptr->stream_info) { ret->stream_info = gst_discoverer_info_copy_int (ptr->stream_info, stream_map); } ret->duration = ptr->duration; if (ptr->misc) ret->misc = gst_structure_copy (ptr->misc); /* We need to set up the new list of streams to correspond to old one. The * list just contains a set of pointers to streams in the stream_info tree, * so we keep a map of old stream info objects to the corresponding new * ones and use that to figure out correspondence in stream_list. */ for (tmp = ptr->stream_list; tmp; tmp = tmp->next) { GstDiscovererStreamInfo *old_stream = (GstDiscovererStreamInfo *) tmp->data; GstDiscovererStreamInfo *new_stream = g_hash_table_lookup (stream_map, old_stream); g_assert (new_stream != NULL); ret->stream_list = g_list_append (ret->stream_list, new_stream); } if (ptr->tags) ret->tags = gst_tag_list_copy (ptr->tags); g_hash_table_destroy (stream_map); return ret; }
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; }
GstFlowReturn gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, GstElement * element, GstPad * pad, GstBuffer * buf, GstPad * srcpad, GstPad * tagpad, GstCaps ** src_caps, const kate_event ** ev) { kate_packet kp; int ret; GstFlowReturn rflow = GST_FLOW_OK; gboolean is_header; guint8 *data; gsize size; guint8 header[1]; size = gst_buffer_extract (buf, 0, header, 1); GST_DEBUG_OBJECT (element, "got kate packet, %u bytes, type %02x", gst_buffer_get_size (buf), size == 0 ? -1 : header[0]); is_header = size > 0 && (header[0] & 0x80); if (!is_header && decoder->tags) { /* after we've processed headers, send any tags before processing the data packet */ GST_DEBUG_OBJECT (element, "Not a header, sending tags for pad %s:%s", GST_DEBUG_PAD_NAME (tagpad)); gst_element_found_tags_for_pad (element, tagpad, decoder->tags); decoder->tags = NULL; } data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); kate_packet_wrap (&kp, size, data); ret = kate_high_decode_packetin (&decoder->k, &kp, ev); gst_buffer_unmap (buf, data, size); if (G_UNLIKELY (ret < 0)) { GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), ("Failed to decode Kate packet: %s", gst_kate_util_get_error_message (ret))); return GST_FLOW_ERROR; } if (G_UNLIKELY (ret > 0)) { GST_DEBUG_OBJECT (element, "kate_high_decode_packetin has received EOS packet"); } /* headers may be interesting to retrieve information from */ if (G_UNLIKELY (is_header)) { switch (header[0]) { case 0x80: /* ID header */ GST_INFO_OBJECT (element, "Parsed ID header: language %s, category %s", decoder->k.ki->language, decoder->k.ki->category); if (src_caps) { if (*src_caps) { gst_caps_unref (*src_caps); *src_caps = NULL; } if (strcmp (decoder->k.ki->category, "K-SPU") == 0 || strcmp (decoder->k.ki->category, "spu-subtitles") == 0) { *src_caps = gst_caps_new_empty_simple ("video/x-dvd-subpicture"); } else if (decoder->k.ki->text_markup_type == kate_markup_none) { *src_caps = gst_caps_new_empty_simple ("text/plain"); } else { *src_caps = gst_caps_new_empty_simple ("text/x-pango-markup"); } GST_INFO_OBJECT (srcpad, "Setting caps: %" GST_PTR_FORMAT, *src_caps); if (!gst_pad_set_caps (srcpad, *src_caps)) { GST_ERROR_OBJECT (srcpad, "Failed to set caps %" GST_PTR_FORMAT, *src_caps); } } if (decoder->k.ki->language && *decoder->k.ki->language) { GstTagList *old = decoder->tags, *tags = gst_tag_list_new_empty (); if (tags) { gchar *lang_code; /* en_GB -> en */ lang_code = g_ascii_strdown (decoder->k.ki->language, -1); g_strdelimit (lang_code, NULL, '\0'); gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_LANGUAGE_CODE, lang_code, NULL); g_free (lang_code); /* TODO: category - where should it go ? */ decoder->tags = gst_tag_list_merge (decoder->tags, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_free (tags); if (old) gst_tag_list_free (old); } } /* update properties */ if (decoder->language) g_free (decoder->language); decoder->language = g_strdup (decoder->k.ki->language); if (decoder->category) g_free (decoder->category); decoder->category = g_strdup (decoder->k.ki->category); decoder->original_canvas_width = decoder->k.ki->original_canvas_width; decoder->original_canvas_height = decoder->k.ki->original_canvas_height; /* we can now send away any event we've delayed, as the src pad now has caps */ gst_kate_util_decoder_base_drain_event_queue (decoder); break; case 0x81: /* Vorbis comments header */ GST_INFO_OBJECT (element, "Parsed comments header"); { gchar *encoder = NULL; GstTagList *old = decoder->tags, *list = gst_tag_list_from_vorbiscomment_buffer (buf, (const guint8 *) "\201kate\0\0\0\0", 9, &encoder); if (list) { decoder->tags = gst_tag_list_merge (decoder->tags, list, GST_TAG_MERGE_REPLACE); gst_tag_list_free (list); } if (!decoder->tags) { GST_ERROR_OBJECT (element, "failed to decode comment header"); decoder->tags = gst_tag_list_new_empty (); } if (encoder) { gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder, NULL); g_free (encoder); } gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE, GST_TAG_SUBTITLE_CODEC, "Kate", NULL); gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER_VERSION, decoder->k.ki->bitstream_version_major, NULL); if (old) gst_tag_list_free (old); if (decoder->initialized) { gst_element_found_tags_for_pad (element, tagpad, decoder->tags); decoder->tags = NULL; } else { /* Only push them as messages for the time being. * * They will be pushed on the pad once the decoder is initialized */ gst_element_post_message (element, gst_message_new_tag (GST_OBJECT (element), gst_tag_list_copy (decoder->tags))); } } break; default: break; } } #if ((KATE_VERSION_MAJOR<<16)|(KATE_VERSION_MINOR<<8)|KATE_VERSION_PATCH) >= 0x000400 else if (*ev && (*ev)->meta) { int count = kate_meta_query_count ((*ev)->meta); if (count > 0) { GstTagList *evtags = gst_tag_list_new_empty (); int idx; GST_DEBUG_OBJECT (decoder, "Kate event has %d attached metadata", count); for (idx = 0; idx < count; ++idx) { const char *tag, *value; size_t len; if (kate_meta_query ((*ev)->meta, idx, &tag, &value, &len) < 0) { GST_WARNING_OBJECT (decoder, "Failed to retrieve metadata %d", idx); } else { if (gst_kate_util_is_utf8_string (value, len)) { gchar *compound = g_strdup_printf ("%s=%s", tag, value); GST_DEBUG_OBJECT (decoder, "Metadata %d: %s=%s (%zu bytes)", idx, tag, value, len); gst_tag_list_add (evtags, GST_TAG_MERGE_APPEND, GST_TAG_EXTENDED_COMMENT, compound, NULL); g_free (compound); } else { GST_INFO_OBJECT (decoder, "Metadata %d, (%s, %zu bytes) is binary, ignored", idx, tag, len); } } } if (gst_tag_list_is_empty (evtags)) gst_tag_list_free (evtags); else gst_element_found_tags_for_pad (element, tagpad, evtags); } } #endif return rflow; }
static GstFlowReturn vorbis_handle_comment_packet (GstVorbisDec * vd, ogg_packet * packet) { guint bitrate = 0; gchar *encoder = NULL; GstTagList *list, *old_list; GstBuffer *buf; GST_DEBUG_OBJECT (vd, "parsing comment packet"); buf = gst_buffer_new (); GST_BUFFER_DATA (buf) = gst_ogg_packet_data (packet); GST_BUFFER_SIZE (buf) = gst_ogg_packet_size (packet); list = gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\003vorbis", 7, &encoder); old_list = vd->taglist; vd->taglist = gst_tag_list_merge (vd->taglist, list, GST_TAG_MERGE_REPLACE); if (old_list) gst_tag_list_free (old_list); gst_tag_list_free (list); gst_buffer_unref (buf); if (!vd->taglist) { GST_ERROR_OBJECT (vd, "couldn't decode comments"); vd->taglist = gst_tag_list_new (); } if (encoder) { if (encoder[0]) gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder, NULL); g_free (encoder); } gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER_VERSION, vd->vi.version, GST_TAG_AUDIO_CODEC, "Vorbis", NULL); if (vd->vi.bitrate_nominal > 0 && vd->vi.bitrate_nominal <= 0x7FFFFFFF) { gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE, (guint) vd->vi.bitrate_nominal, NULL); bitrate = vd->vi.bitrate_nominal; } if (vd->vi.bitrate_upper > 0 && vd->vi.bitrate_upper <= 0x7FFFFFFF) { gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE, (guint) vd->vi.bitrate_upper, NULL); if (!bitrate) bitrate = vd->vi.bitrate_upper; } if (vd->vi.bitrate_lower > 0 && vd->vi.bitrate_lower <= 0x7FFFFFFF) { gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_MINIMUM_BITRATE, (guint) vd->vi.bitrate_lower, NULL); if (!bitrate) bitrate = vd->vi.bitrate_lower; } if (bitrate) { gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, (guint) bitrate, NULL); } if (vd->initialized) { gst_element_found_tags_for_pad (GST_ELEMENT_CAST (vd), vd->srcpad, vd->taglist); vd->taglist = NULL; } else { /* Only post them as messages for the time being. * * They will be pushed on the pad once the decoder is initialized */ gst_element_post_message (GST_ELEMENT_CAST (vd), gst_message_new_tag (GST_OBJECT (vd), gst_tag_list_copy (vd->taglist))); } return GST_FLOW_OK; }
static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event) { gboolean res = TRUE; gboolean forward = TRUE; RsnStreamSelector *sel; RsnSelectorPad *selpad; GstPad *active_sinkpad; sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad)); selpad = GST_SELECTOR_PAD_CAST (pad); /* only forward if we are dealing with the active sinkpad */ active_sinkpad = rsn_stream_selector_get_active (sel, pad); forward = (active_sinkpad == pad); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: gst_selector_pad_reset (selpad); break; case GST_EVENT_NEWSEGMENT: { gboolean update; GstFormat format; gdouble rate, arate; gint64 start, stop, time; gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, &start, &stop, &time); GST_DEBUG_OBJECT (selpad, "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, " "format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT, update, rate, arate, format, start, stop, time); gst_segment_set_newsegment_full (&selpad->segment, update, rate, arate, format, start, stop, time); /* if we are not going to forward the segment, mark the segment as * pending */ if (!forward) selpad->segment_pending = TRUE; break; } case GST_EVENT_TAG: { GstTagList *tags; GST_OBJECT_LOCK (selpad); if (selpad->tags) gst_tag_list_free (selpad->tags); gst_event_parse_tag (event, &tags); if (tags) tags = gst_tag_list_copy (tags); selpad->tags = tags; GST_DEBUG_OBJECT (sel, "received tags %" GST_PTR_FORMAT, selpad->tags); GST_OBJECT_UNLOCK (selpad); break; } case GST_EVENT_CUSTOM_DOWNSTREAM: { const GstStructure *structure = gst_event_get_structure (event); if (structure != NULL && gst_structure_has_name (structure, "application/x-gst-dvd")) { const char *type = gst_structure_get_string (structure, "event"); if (strcmp (type, "select-pad") == 0) { rsn_stream_selector_set_active (sel, pad); forward = FALSE; } } } case GST_EVENT_EOS: selpad->eos = TRUE; break; default: break; } if (forward) res = gst_pad_push_event (sel->srcpad, event); else gst_event_unref (event); gst_object_unref (sel); return res; }
static gboolean start_play_tune (GstNsfDec * nsfdec) { gboolean res; nsfdec->nsf = nsf_load (NULL, GST_BUFFER_DATA (nsfdec->tune_buffer), GST_BUFFER_SIZE (nsfdec->tune_buffer)); if (!nsfdec->nsf) goto could_not_load; if (!nsfdec_negotiate (nsfdec)) goto could_not_negotiate; nsfdec->taglist = gst_tag_list_new (); gst_tag_list_add (nsfdec->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, "NES Sound Format", NULL); if (nsfdec->nsf->artist_name) gst_tag_list_add (nsfdec->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_ARTIST, nsfdec->nsf->artist_name, NULL); if (nsfdec->nsf->song_name) gst_tag_list_add (nsfdec->taglist, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, nsfdec->nsf->song_name, NULL); gst_element_post_message (GST_ELEMENT_CAST (nsfdec), gst_message_new_tag (GST_OBJECT (nsfdec), gst_tag_list_copy (nsfdec->taglist))); nsf_playtrack (nsfdec->nsf, nsfdec->tune_number, nsfdec->frequency, nsfdec->bits, nsfdec->stereo); nsf_setfilter (nsfdec->nsf, nsfdec->filter); nsfdec->bps = (nsfdec->bits >> 3) * nsfdec->channels; /* calculate the number of bytes we need to output after each call to * nsf_frame(). */ nsfdec->blocksize = nsfdec->bps * nsfdec->frequency / nsfdec->nsf->playback_rate; gst_pad_push_event (nsfdec->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); res = gst_pad_start_task (nsfdec->srcpad, (GstTaskFunction) play_loop, nsfdec->srcpad, NULL); return res; /* ERRORS */ could_not_load: { GST_ELEMENT_ERROR (nsfdec, LIBRARY, INIT, ("Could not load tune"), ("Could not load tune")); return FALSE; } could_not_negotiate: { GST_ELEMENT_ERROR (nsfdec, CORE, NEGOTIATION, ("Could not negotiate format"), ("Could not negotiate format")); return FALSE; } }
static GstFlowReturn gst_flac_tag_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstFlacTag *tag; GstFlowReturn ret; GstMapInfo map; gsize size; ret = GST_FLOW_OK; tag = GST_FLAC_TAG (parent); gst_adapter_push (tag->adapter, buffer); /* Initial state, we don't even know if we are dealing with a flac file */ if (tag->state == GST_FLAC_TAG_STATE_INIT) { GstBuffer *id_buffer; if (gst_adapter_available (tag->adapter) < sizeof (FLAC_MAGIC)) goto cleanup; id_buffer = gst_adapter_take_buffer (tag->adapter, FLAC_MAGIC_SIZE); GST_DEBUG_OBJECT (tag, "looking for " FLAC_MAGIC " identifier"); if (gst_buffer_memcmp (id_buffer, 0, FLAC_MAGIC, FLAC_MAGIC_SIZE) == 0) { GST_DEBUG_OBJECT (tag, "pushing " FLAC_MAGIC " identifier buffer"); ret = gst_pad_push (tag->srcpad, id_buffer); if (ret != GST_FLOW_OK) goto cleanup; tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS; } else { /* FIXME: does that work well with FLAC files containing ID3v2 tags ? */ gst_buffer_unref (id_buffer); GST_ELEMENT_ERROR (tag, STREAM, WRONG_TYPE, (NULL), (NULL)); ret = GST_FLOW_ERROR; } } /* The fLaC magic string has been skipped, try to detect the beginning * of a metadata block */ if (tag->state == GST_FLAC_TAG_STATE_METADATA_BLOCKS) { guint type; gboolean is_last; const guint8 *block_header; g_assert (tag->metadata_block_size == 0); g_assert (tag->metadata_last_block == FALSE); /* The header of a flac metadata block is 4 bytes long: * 1st bit: indicates whether this is the last metadata info block * 7 next bits: 4 if vorbis comment block * 24 next bits: size of the metadata to follow (big endian) */ if (gst_adapter_available (tag->adapter) < 4) goto cleanup; block_header = gst_adapter_map (tag->adapter, 4); is_last = ((block_header[0] & 0x80) == 0x80); type = block_header[0] & 0x7F; size = (block_header[1] << 16) | (block_header[2] << 8) | block_header[3]; gst_adapter_unmap (tag->adapter); /* The 4 bytes long header isn't included in the metadata size */ tag->metadata_block_size = size + 4; tag->metadata_last_block = is_last; GST_DEBUG_OBJECT (tag, "got metadata block: %" G_GSIZE_FORMAT " bytes, type %d, " "is vorbiscomment: %d, is last: %d", size, type, (type == 0x04), is_last); /* Metadata blocks of type 4 are vorbis comment blocks */ if (type == 0x04) { tag->state = GST_FLAC_TAG_STATE_VC_METADATA_BLOCK; } else { tag->state = GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK; } } /* Reads a metadata block */ if ((tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) || (tag->state == GST_FLAC_TAG_STATE_VC_METADATA_BLOCK)) { GstBuffer *metadata_buffer; if (gst_adapter_available (tag->adapter) < tag->metadata_block_size) goto cleanup; metadata_buffer = gst_adapter_take_buffer (tag->adapter, tag->metadata_block_size); /* clear the is-last flag, as the last metadata block will * be the vorbis comment block which we will build ourselves. */ gst_buffer_map (metadata_buffer, &map, GST_MAP_READWRITE); map.data[0] &= (~0x80); gst_buffer_unmap (metadata_buffer, &map); if (tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) { GST_DEBUG_OBJECT (tag, "pushing metadata block buffer"); ret = gst_pad_push (tag->srcpad, metadata_buffer); if (ret != GST_FLOW_OK) goto cleanup; } else { tag->vorbiscomment = metadata_buffer; } tag->metadata_block_size = 0; tag->state = GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK; } /* This state is mainly used to be able to stop as soon as we read * a vorbiscomment block from the flac file if we are in an only output * tags mode */ if (tag->state == GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK) { /* Check if in the previous iteration we read a vorbis comment metadata * block, and stop now if the user only wants to read tags */ if (tag->vorbiscomment != NULL) { guint8 id_data[4]; /* We found some tags, try to parse them and notify the other elements * that we encountered some tags */ GST_DEBUG_OBJECT (tag, "emitting vorbiscomment tags"); gst_buffer_extract (tag->vorbiscomment, 0, id_data, 4); tag->tags = gst_tag_list_from_vorbiscomment_buffer (tag->vorbiscomment, id_data, 4, NULL); if (tag->tags != NULL) { gst_pad_push_event (tag->srcpad, gst_event_new_tag (gst_tag_list_copy (tag->tags))); } gst_buffer_unref (tag->vorbiscomment); tag->vorbiscomment = NULL; } /* Skip to next state */ if (tag->metadata_last_block == FALSE) { tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS; } else { tag->state = GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT; } } /* Creates a vorbis comment block from the metadata which was set * on the gstreamer element, and add it to the flac stream */ if (tag->state == GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT) { GstBuffer *buffer; const GstTagList *user_tags; GstTagList *merged_tags; /* merge the tag lists */ user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tag)); if (user_tags != NULL) { merged_tags = gst_tag_list_merge (user_tags, tag->tags, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tag))); } else { merged_tags = gst_tag_list_copy (tag->tags); } if (merged_tags == NULL) { /* If we get a NULL list of tags, we must generate a padding block * which is marked as the last metadata block, otherwise we'll * end up with a corrupted flac file. */ GST_WARNING_OBJECT (tag, "No tags found"); buffer = gst_buffer_new_and_alloc (12); if (buffer == NULL) goto no_buffer; gst_buffer_map (buffer, &map, GST_MAP_WRITE); memset (map.data, 0, map.size); map.data[0] = 0x81; /* 0x80 = Last metadata block, * 0x01 = padding block */ gst_buffer_unmap (buffer, &map); } else { guchar header[4]; guint8 fbit[1]; memset (header, 0, sizeof (header)); header[0] = 0x84; /* 0x80 = Last metadata block, * 0x04 = vorbiscomment block */ buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header, sizeof (header), NULL); GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags); gst_tag_list_free (merged_tags); if (buffer == NULL) goto no_comment; size = gst_buffer_get_size (buffer); if ((size < 4) || ((size - 4) > 0xFFFFFF)) goto comment_too_long; fbit[0] = 1; /* Get rid of the framing bit at the end of the vorbiscomment buffer * if it exists since libFLAC seems to lose sync because of this * bit in gstflacdec */ if (gst_buffer_memcmp (buffer, size - 1, fbit, 1) == 0) { buffer = gst_buffer_make_writable (buffer); gst_buffer_resize (buffer, 0, size - 1); } } /* The 4 byte metadata block header isn't accounted for in the total * size of the metadata block */ gst_buffer_map (buffer, &map, GST_MAP_WRITE); map.data[1] = (((map.size - 4) & 0xFF0000) >> 16); map.data[2] = (((map.size - 4) & 0x00FF00) >> 8); map.data[3] = ((map.size - 4) & 0x0000FF); gst_buffer_unmap (buffer, &map); GST_DEBUG_OBJECT (tag, "pushing %" G_GSIZE_FORMAT " byte vorbiscomment " "buffer", map.size); ret = gst_pad_push (tag->srcpad, buffer); if (ret != GST_FLOW_OK) { goto cleanup; } tag->state = GST_FLAC_TAG_STATE_AUDIO_DATA; }
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; }
GstFlowReturn gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, GstElement * element, GstPad * pad, GstBuffer * buf, GstPad * srcpad, const kate_event ** ev) { kate_packet kp; int ret; GstFlowReturn rflow = GST_FLOW_OK; GST_DEBUG_OBJECT (element, "got kate packet, %u bytes, type %02x", GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (buf) == 0 ? -1 : GST_BUFFER_DATA (buf)[0]); kate_packet_wrap (&kp, GST_BUFFER_SIZE (buf), GST_BUFFER_DATA (buf)); ret = kate_high_decode_packetin (&decoder->k, &kp, ev); if (G_UNLIKELY (ret < 0)) { GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), ("Failed to decode Kate packet: %d", ret)); return GST_FLOW_ERROR; } else if (G_UNLIKELY (ret > 0)) { GST_DEBUG_OBJECT (element, "kate_high_decode_packetin has received EOS packet"); return GST_FLOW_OK; } /* headers may be interesting to retrieve information from */ if (G_LIKELY (GST_BUFFER_SIZE (buf) > 0)) switch (GST_BUFFER_DATA (buf)[0]) { GstCaps *caps; case 0x80: /* ID header */ GST_INFO_OBJECT (element, "Parsed ID header: language %s, category %s", decoder->k.ki->language, decoder->k.ki->category); caps = gst_caps_new_simple ("text/x-pango-markup", NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); if (decoder->k.ki->language && *decoder->k.ki->language) { GstTagList *old = decoder->tags, *tags = gst_tag_list_new (); if (tags) { gchar *lang_code; /* en_GB -> en */ lang_code = g_ascii_strdown (decoder->k.ki->language, -1); g_strdelimit (lang_code, NULL, '\0'); gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_LANGUAGE_CODE, lang_code, NULL); g_free (lang_code); /* TODO: category - where should it go ? */ decoder->tags = gst_tag_list_merge (decoder->tags, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_free (tags); if (old) gst_tag_list_free (old); } } /* update properties */ if (decoder->language) g_free (decoder->language); decoder->language = g_strdup (decoder->k.ki->language); if (decoder->category) g_free (decoder->category); decoder->category = g_strdup (decoder->k.ki->category); decoder->original_canvas_width = decoder->k.ki->original_canvas_width; decoder->original_canvas_height = decoder->k.ki->original_canvas_height; break; case 0x81: /* Vorbis comments header */ GST_INFO_OBJECT (element, "Parsed comments header"); { gchar *encoder = NULL; GstTagList *old = decoder->tags, *list = gst_tag_list_from_vorbiscomment_buffer (buf, (const guint8 *) "\201kate\0\0\0\0", 9, &encoder); if (list) { decoder->tags = gst_tag_list_merge (decoder->tags, list, GST_TAG_MERGE_REPLACE); gst_tag_list_free (list); } if (!decoder->tags) { GST_ERROR_OBJECT (element, "failed to decode comment header"); decoder->tags = gst_tag_list_new (); } if (encoder) { gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder, NULL); g_free (encoder); } gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE, GST_TAG_SUBTITLE_CODEC, "Kate", NULL); gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER_VERSION, decoder->k.ki->bitstream_version_major, NULL); if (old) gst_tag_list_free (old); if (decoder->initialized) { gst_element_found_tags_for_pad (element, srcpad, decoder->tags); decoder->tags = NULL; } else { /* Only push them as messages for the time being. * * They will be pushed on the pad once the decoder is initialized */ gst_element_post_message (element, gst_message_new_tag (GST_OBJECT (element), gst_tag_list_copy (decoder->tags))); } } break; default: break; } return rflow; }
TagMessagePtr TagMessage::create(const ObjectPtr & source, const TagList & taglist) { GstMessage *m = gst_message_new_tag(source, gst_tag_list_copy(taglist)); return TagMessagePtr::wrap(m, false); }