template<> GstTagList* refGPtr<GstTagList>(GstTagList* ptr) { if (ptr) gst_tag_list_ref(ptr); return ptr; }
GstPlayerStreamInfo * gst_player_stream_info_copy (GstPlayerStreamInfo * ref) { GstPlayerStreamInfo *info = NULL; if (!ref) return NULL; if (GST_IS_PLAYER_VIDEO_INFO (ref)) info = gst_player_video_info_copy ((GstPlayerVideoInfo *) ref); else if (GST_IS_PLAYER_AUDIO_INFO (ref)) info = gst_player_audio_info_copy ((GstPlayerAudioInfo *) ref); else info = gst_player_subtitle_info_copy ((GstPlayerSubtitleInfo *) ref); info->stream_index = ref->stream_index; if (ref->tags) info->tags = gst_tag_list_ref (ref->tags); if (ref->caps) info->caps = gst_caps_copy (ref->caps); if (ref->codec) info->codec = g_strdup (ref->codec); return info; }
GstEvent * gst_kate_util_decoder_base_get_tag_event (GstKateDecoderBase * decoder) { if (!decoder->tags) return NULL; decoder->tags_changed = FALSE; return gst_event_new_tag (gst_tag_list_ref (decoder->tags)); }
static GstFlowReturn gst_tag_mux_render_start_tag (GstTagMux * mux) { GstTagMuxClass *klass; GstBuffer *buffer; GstTagList *taglist; GstEvent *event; GstFlowReturn ret; GstSegment segment; taglist = gst_tag_mux_get_tags (mux); klass = GST_TAG_MUX_CLASS (G_OBJECT_GET_CLASS (mux)); if (klass->render_start_tag == NULL) goto no_vfunc; buffer = klass->render_start_tag (mux, taglist); /* Null buffer is ok, just means we're not outputting anything */ if (buffer == NULL) { GST_INFO_OBJECT (mux, "No start tag generated"); mux->priv->start_tag_size = 0; return GST_FLOW_OK; } mux->priv->start_tag_size = gst_buffer_get_size (buffer); GST_LOG_OBJECT (mux, "tag size = %" G_GSIZE_FORMAT " bytes", mux->priv->start_tag_size); /* Send newsegment event from byte position 0, so the tag really gets * written to the start of the file, independent of the upstream segment */ gst_segment_init (&segment, GST_FORMAT_BYTES); gst_pad_push_event (mux->priv->srcpad, gst_event_new_segment (&segment)); /* Send an event about the new tags to downstream elements */ /* gst_event_new_tag takes ownership of the list, so use a copy */ event = gst_event_new_tag (gst_tag_list_ref (taglist)); gst_pad_push_event (mux->priv->srcpad, event); GST_BUFFER_OFFSET (buffer) = 0; ret = gst_pad_push (mux->priv->srcpad, buffer); mux->priv->current_offset = mux->priv->start_tag_size; mux->priv->max_offset = MAX (mux->priv->max_offset, mux->priv->current_offset); return ret; no_vfunc: { GST_ERROR_OBJECT (mux, "Subclass does not implement " "render_start_tag vfunc!"); return GST_FLOW_ERROR; } }
/** * gst_stream_get_tags: * @stream: a #GstStream * * Retrieve the tags for @stream, if any * * Returns: (transfer full) (nullable): The #GstTagList for @stream * * Since: 1.10 */ GstTagList * gst_stream_get_tags (GstStream * stream) { GstTagList *res = NULL; GST_OBJECT_LOCK (stream); if (stream->priv->tags) res = gst_tag_list_ref (stream->priv->tags); GST_OBJECT_UNLOCK (stream); return res; }
static inline void _push_mandatory_events (GstAggregator * self) { GstAggregatorPrivate *priv = self->priv; if (g_atomic_int_get (&self->priv->send_stream_start)) { gchar s_id[32]; GST_INFO_OBJECT (self, "pushing stream start"); /* stream-start (FIXME: create id based on input ids) */ g_snprintf (s_id, sizeof (s_id), "agg-%08x", g_random_int ()); if (!gst_pad_push_event (self->srcpad, gst_event_new_stream_start (s_id))) { GST_WARNING_OBJECT (self->srcpad, "Sending stream start event failed"); } g_atomic_int_set (&self->priv->send_stream_start, FALSE); } if (self->priv->srccaps) { GST_INFO_OBJECT (self, "pushing caps: %" GST_PTR_FORMAT, self->priv->srccaps); if (!gst_pad_push_event (self->srcpad, gst_event_new_caps (self->priv->srccaps))) { GST_WARNING_OBJECT (self->srcpad, "Sending caps event failed"); } gst_caps_unref (self->priv->srccaps); self->priv->srccaps = NULL; } if (g_atomic_int_get (&self->priv->send_segment)) { if (!g_atomic_int_get (&self->priv->flush_seeking)) { GstEvent *segev = gst_event_new_segment (&self->segment); if (!self->priv->seqnum) self->priv->seqnum = gst_event_get_seqnum (segev); else gst_event_set_seqnum (segev, self->priv->seqnum); GST_DEBUG_OBJECT (self, "pushing segment %" GST_PTR_FORMAT, segev); gst_pad_push_event (self->srcpad, segev); g_atomic_int_set (&self->priv->send_segment, FALSE); } } if (priv->tags && priv->tags_changed) { gst_pad_push_event (self->srcpad, gst_event_new_tag (gst_tag_list_ref (priv->tags))); priv->tags_changed = FALSE; } }
/** * gst_toc_merge_tags: * @toc: A #GstToc instance * @tags: (allow-none): A #GstTagList or %NULL * @mode: A #GstTagMergeMode * * Merge @tags into the existing tags of @toc using @mode. */ void gst_toc_merge_tags (GstToc * toc, GstTagList * tags, GstTagMergeMode mode) { g_return_if_fail (toc != NULL); g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (toc))); if (!toc->tags) { toc->tags = gst_tag_list_ref (tags); } else { GstTagList *tmp = gst_tag_list_merge (toc->tags, tags, mode); gst_tag_list_unref (toc->tags); toc->tags = tmp; } }
/** * gst_toc_entry_merge_tags: * @entry: A #GstTocEntry instance * @tags: (allow-none): A #GstTagList or %NULL * @mode: A #GstTagMergeMode * * Merge @tags into the existing tags of @entry using @mode. */ void gst_toc_entry_merge_tags (GstTocEntry * entry, GstTagList * tags, GstTagMergeMode mode) { g_return_if_fail (entry != NULL); g_return_if_fail (gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (entry))); if (!entry->tags) { entry->tags = gst_tag_list_ref (tags); } else { GstTagList *tmp = gst_tag_list_merge (entry->tags, tags, mode); gst_tag_list_unref (entry->tags); entry->tags = tmp; } }
void gst_kate_util_decoder_base_add_tags (GstKateDecoderBase * decoder, GstTagList * tags, gboolean take_ownership_of_tags) { if (!decoder->tags) { if (!take_ownership_of_tags) tags = gst_tag_list_ref (tags); decoder->tags = tags; } else { GstTagList *old = decoder->tags; decoder->tags = gst_tag_list_merge (old, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_unref (old); if (take_ownership_of_tags) gst_tag_list_unref (tags); } decoder->tags_changed = TRUE; }
GstPlayerMediaInfo * gst_player_media_info_copy (GstPlayerMediaInfo * ref) { GList *l; GstPlayerMediaInfo *info; if (!ref) return NULL; info = gst_player_media_info_new (ref->uri); info->duration = ref->duration; info->seekable = ref->seekable; if (ref->tags) info->tags = gst_tag_list_ref (ref->tags); if (ref->title) info->title = g_strdup (ref->title); if (ref->container) info->container = g_strdup (ref->container); if (ref->image_sample) info->image_sample = gst_sample_ref (ref->image_sample); for (l = ref->stream_list; l != NULL; l = l->next) { GstPlayerStreamInfo *s; s = gst_player_stream_info_copy ((GstPlayerStreamInfo *) l->data); info->stream_list = g_list_append (info->stream_list, s); if (GST_IS_PLAYER_AUDIO_INFO (s)) info->audio_stream_list = g_list_append (info->audio_stream_list, s); else if (GST_IS_PLAYER_VIDEO_INFO (s)) info->video_stream_list = g_list_append (info->video_stream_list, s); else info->subtitle_stream_list = g_list_append (info->subtitle_stream_list, s); } return info; }
static void gst_rg_analysis_handle_eos (GstRgAnalysis * filter) { gboolean album_processing = (filter->num_tracks > 0); gboolean album_finished = (filter->num_tracks == 1); gboolean album_skipping = album_processing && filter->skip; filter->has_track_gain = FALSE; filter->has_track_peak = FALSE; if (album_finished) { filter->ignore_tags = FALSE; filter->skip = FALSE; filter->has_album_gain = FALSE; filter->has_album_peak = FALSE; } else if (!album_skipping) { filter->skip = FALSE; } /* We might have just fully processed a track because it has * incomplete tags. If we do album processing and allow skipping * (not forced), prevent switching to skipping if a later track with * full tags comes along: */ if (!filter->forced && album_processing && !album_finished) filter->ignore_tags = TRUE; if (!filter->skip) { GstTagList *tag_list = NULL; gboolean track_success; gboolean album_success = FALSE; track_success = gst_rg_analysis_track_result (filter, &tag_list); if (album_finished) album_success = gst_rg_analysis_album_result (filter, &tag_list); else if (!album_processing) rg_analysis_reset_album (filter->ctx); if (track_success || album_success) { GST_LOG_OBJECT (filter, "posting tag list with results"); gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, GST_TAG_REFERENCE_LEVEL, filter->reference_level, NULL); /* This steals our reference to the list: */ gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (GST_BASE_TRANSFORM (filter)), gst_event_new_tag (gst_tag_list_ref (tag_list))); } } if (album_processing) { filter->num_tracks--; if (!album_finished) { GST_DEBUG_OBJECT (filter, "album not finished yet (num-tracks is now %u)", filter->num_tracks); } else { GST_DEBUG_OBJECT (filter, "album finished (num-tracks is now 0)"); } } if (album_processing) g_object_notify (G_OBJECT (filter), "num-tracks"); }
static gboolean gst_wavenc_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; GstWavEnc *wavenc; GstTagList *tags; GstToc *toc; wavenc = GST_WAVENC (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); gst_wavenc_sink_setcaps (pad, caps); /* have our own src caps */ gst_event_unref (event); break; } case GST_EVENT_EOS: { GstFlowReturn flow; GST_DEBUG_OBJECT (wavenc, "got EOS"); flow = gst_wavenc_write_toc (wavenc); if (flow != GST_FLOW_OK) { GST_WARNING_OBJECT (wavenc, "error pushing toc: %s", gst_flow_get_name (flow)); } flow = gst_wavenc_write_tags (wavenc); if (flow != GST_FLOW_OK) { GST_WARNING_OBJECT (wavenc, "error pushing tags: %s", gst_flow_get_name (flow)); } /* write header with correct length values */ gst_wavenc_push_header (wavenc); /* we're done with this file */ wavenc->finished_properly = TRUE; /* and forward the EOS event */ res = gst_pad_event_default (pad, parent, event); break; } case GST_EVENT_SEGMENT: /* Just drop it, it's probably in TIME format * anyway. We'll send our own newsegment event */ gst_event_unref (event); break; case GST_EVENT_TOC: gst_event_parse_toc (event, &toc, NULL); if (toc) { if (wavenc->toc != toc) { if (wavenc->toc) gst_toc_unref (wavenc->toc); wavenc->toc = toc; } else { gst_toc_unref (toc); } } res = gst_pad_event_default (pad, parent, event); break; case GST_EVENT_TAG: gst_event_parse_tag (event, &tags); if (tags) { if (wavenc->tags != tags) { if (wavenc->tags) gst_tag_list_unref (wavenc->tags); wavenc->tags = gst_tag_list_ref (tags); } } res = gst_pad_event_default (pad, parent, event); break; default: res = gst_pad_event_default (pad, parent, event); break; } return res; }
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; GstMapInfo info; gsize header_size; guint8 header[1]; header_size = gst_buffer_extract (buf, 0, header, 1); GST_DEBUG_OBJECT (element, "got kate packet, %" G_GSIZE_FORMAT " bytes, type %02x", gst_buffer_get_size (buf), header_size == 0 ? -1 : header[0]); is_header = header_size > 0 && (header[0] & 0x80); if (!is_header && decoder->tags_changed) { /* 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_pad_push_event (tagpad, gst_kate_util_decoder_base_get_tag_event (decoder)); } if (gst_buffer_map (buf, &info, GST_MAP_READ)) { kate_packet_wrap (&kp, info.size, info.data); ret = kate_high_decode_packetin (&decoder->k, &kp, ev); gst_buffer_unmap (buf, &info); } else { GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), ("Failed to map buffer")); return GST_FLOW_ERROR; } 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 ("subpicture/x-dvd"); } else if (decoder->k.ki->text_markup_type == kate_markup_none) { *src_caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "utf8", NULL); } else { *src_caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "pango-markup", NULL); } 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 *tags = gst_tag_list_new_empty (); 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 ? */ gst_kate_util_decoder_base_add_tags (decoder, tags, TRUE); } /* 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 *list = gst_tag_list_from_vorbiscomment_buffer (buf, (const guint8 *) "\201kate\0\0\0\0", 9, &encoder); if (!list) { GST_ERROR_OBJECT (element, "failed to decode comment header"); list = gst_tag_list_new_empty (); } if (encoder) { gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder, NULL); g_free (encoder); } gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SUBTITLE_CODEC, "Kate", NULL); gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER_VERSION, decoder->k.ki->bitstream_version_major, NULL); gst_kate_util_decoder_base_add_tags (decoder, list, TRUE); if (decoder->initialized) { gst_pad_push_event (tagpad, gst_event_new_tag (gst_tag_list_ref (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 (%" G_GSIZE_FORMAT " 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, %" G_GSIZE_FORMAT " bytes) is binary, ignored", idx, tag, len); } } } gst_kate_util_decoder_base_add_tags (decoder, evtags, TRUE); gst_pad_push_event (tagpad, gst_kate_util_decoder_base_get_tag_event (decoder)); } } #endif return rflow; }