<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML ><HEAD ><TITLE >Writing Tags to Streams</TITLE ><META NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.79;charset=UTF-8"><LINK REL="HOME" TITLE="GStreamer Plugin Writer's Guide (0.10.36)" HREF="index.html"><LINK REL="UP" TITLE="Tagging (Metadata and Streaminfo)" HREF="chapter-advanced-tagging.html"><LINK REL="PREVIOUS" TITLE="Reading Tags from Streams" HREF="section-tagging-read.html"><LINK REL="NEXT" TITLE="Events: Seeking, Navigation and More" HREF="chapter-advanced-events.html"></HEAD ><BODY CLASS="sect1" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#840084" ALINK="#0000FF" ><DIV CLASS="NAVHEADER" ><TABLE SUMMARY="Header navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TH COLSPAN="3" ALIGN="center" ><SPAN CLASS="application" >GStreamer</SPAN > Plugin Writer's Guide (0.10.36)</TH ></TR ><TR ><TD WIDTH="10%" ALIGN="left" VALIGN="bottom" ><A HREF="section-tagging-read.html" ACCESSKEY="P" >Prev</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" >Chapter 17. Tagging (Metadata and Streaminfo)</TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="chapter-advanced-events.html" ACCESSKEY="N" >Next</A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="sect1" ><H1 CLASS="sect1" ><A NAME="section-tagging-write" >17.3. Writing Tags to Streams</A ></H1 ><P > Tag writers are the opposite of tag readers. Tag writers only take metadata tags into account, since that's the only type of tags that have to be written into a stream. Tag writers can receive tags in three ways: internal, application and pipeline. Internal tags are tags read by the element itself, which means that the tag writer is - in that case - a tag reader, too. Application tags are tags provided to the element via the TagSetter interface (which is just a layer). Pipeline tags are tags provided to the element from within the pipeline. The element receives such tags via the <CODE CLASS="symbol" >GST_EVENT_TAG</CODE > event, which means that tags writers should automatically be event aware. The tag writer is responsible for combining all these three into one list and writing them to the output stream. </P ><P > The example below will receive tags from both application and pipeline, combine them and write them to the output stream. It implements the tag setter so applications can set tags, and retrieves pipeline tags from incoming events. </P ><PRE CLASS="programlisting" > GType gst_my_filter_get_type (void) { [..] static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL }; [..] g_type_add_interface_static (my_filter_type, GST_TYPE_TAG_SETTER, &tag_setter_info); [..] } static void gst_my_filter_init (GstMyFilter *filter) { GST_FLAG_SET (filter, GST_ELEMENT_EVENT_AWARE); [..] } /* * Write one tag. */ static void gst_my_filter_write_tag (const GstTagList *taglist, const gchar *tagname, gpointer data) { GstMyFilter *filter = GST_MY_FILTER (data); GstBuffer *buffer; guint num_values = gst_tag_list_get_tag_size (list, tag_name), n; const GValue *from; GValue to = { 0 }; g_value_init (&to, G_TYPE_STRING); for (n = 0; n < num_values; n++) { from = gst_tag_list_get_value_index (taglist, tagname, n); g_value_transform (from, &to); buf = gst_buffer_new (); GST_BUFFER_DATA (buf) = g_strdup_printf ("%s:%s", tagname, g_value_get_string (&to)); GST_BUFFER_SIZE (buf) = strlen (GST_BUFFER_DATA (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); } g_value_unset (&to); } static void gst_my_filter_task_func (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); GstTagSetter *tagsetter = GST_TAG_SETTER (element); GstData *data; GstEvent *event; gboolean eos = FALSE; GstTagList *taglist = gst_tag_list_new (); while (!eos) { data = gst_pad_pull (filter->sinkpad); /* We're not very much interested in data right now */ if (GST_IS_BUFFER (data)) gst_buffer_unref (GST_BUFFER (data)); event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG: gst_tag_list_insert (taglist, gst_event_tag_get_list (event), GST_TAG_MERGE_PREPEND); gst_event_unref (event); break; case GST_EVENT_EOS: eos = TRUE; gst_event_unref (event); break; default: gst_pad_event_default (filter->sinkpad, event); break; } } /* merge tags with the ones retrieved from the application */ if ((gst_tag_setter_get_tag_list (tagsetter)) { gst_tag_list_insert (taglist, gst_tag_setter_get_tag_list (tagsetter), gst_tag_setter_get_tag_merge_mode (tagsetter)); } /* write tags */ gst_tag_list_foreach (taglist, gst_my_filter_write_tag, filter); /* signal EOS */ gst_pad_push (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); gst_element_set_eos (element); } </PRE ><P > Note that normally, elements would not read the full stream before processing tags. Rather, they would read from each sinkpad until they've received data (since tags usually come in before the first data buffer) and process that. </P ></DIV ><DIV CLASS="NAVFOOTER" ><HR ALIGN="LEFT" WIDTH="100%"><TABLE SUMMARY="Footer navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" ><A HREF="section-tagging-read.html" ACCESSKEY="P" >Prev</A ></TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="index.html" ACCESSKEY="H" >Home</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" ><A HREF="chapter-advanced-events.html" ACCESSKEY="N" >Next</A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >Reading Tags from Streams</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="chapter-advanced-tagging.html" ACCESSKEY="U" >Up</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >Events: Seeking, Navigation and More</TD ></TR ></TABLE ></DIV ></BODY ></HTML >