1 /* GStreamer
2 * Copyright (C) 2008 Stefan Kost <ensonic@users.sf.net>
3 *
4 * gsttaginject.c:
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21 /**
22 * SECTION:element-taginject
23 * @title: taginject
24 *
25 * Element that injects new metadata tags, but passes incoming data through
26 * unmodified.
27 *
28 * ## Example launch lines
29 * |[
30 * gst-launch-1.0 audiotestsrc num-buffers=100 ! taginject tags="title=testsrc,artist=gstreamer" ! vorbisenc ! oggmux ! filesink location=test.ogg
31 * ]| set title and artist
32 * |[
33 * gst-launch-1.0 audiotestsrc num-buffers=100 ! taginject tags="keywords=\{\"testone\",\"audio\"\},title=\"audio\ testtone\"" ! vorbisenc ! oggmux ! filesink location=test.ogg
34 * ]| set keywords and title demonstrating quoting of special chars and handling lists
35 *
36 */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <stdlib.h>
43
44 #include "gstdebugutilselements.h"
45 #include "gsttaginject.h"
46
47 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
48 GST_PAD_SINK,
49 GST_PAD_ALWAYS,
50 GST_STATIC_CAPS_ANY);
51
52 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
53 GST_PAD_SRC,
54 GST_PAD_ALWAYS,
55 GST_STATIC_CAPS_ANY);
56
57 GST_DEBUG_CATEGORY_STATIC (gst_tag_inject_debug);
58 #define GST_CAT_DEFAULT gst_tag_inject_debug
59
60 enum
61 {
62 PROP_TAGS = 1
63 };
64
65
66 #define gst_tag_inject_parent_class parent_class
67 G_DEFINE_TYPE (GstTagInject, gst_tag_inject, GST_TYPE_BASE_TRANSFORM);
68 GST_ELEMENT_REGISTER_DEFINE (taginject, "taginject",
69 GST_RANK_NONE, gst_tag_inject_get_type ());
70
71 static void gst_tag_inject_finalize (GObject * object);
72 static void gst_tag_inject_set_property (GObject * object, guint prop_id,
73 const GValue * value, GParamSpec * pspec);
74 static void gst_tag_inject_get_property (GObject * object, guint prop_id,
75 GValue * value, GParamSpec * pspec);
76
77 static GstFlowReturn gst_tag_inject_transform_ip (GstBaseTransform * trans,
78 GstBuffer * buf);
79 static gboolean gst_tag_inject_start (GstBaseTransform * trans);
80
81
82 static void
gst_tag_inject_finalize(GObject * object)83 gst_tag_inject_finalize (GObject * object)
84 {
85 GstTagInject *self = GST_TAG_INJECT (object);
86
87 if (self->tags) {
88 gst_tag_list_unref (self->tags);
89 self->tags = NULL;
90 }
91
92 G_OBJECT_CLASS (parent_class)->finalize (object);
93 }
94
95 static void
gst_tag_inject_class_init(GstTagInjectClass * klass)96 gst_tag_inject_class_init (GstTagInjectClass * klass)
97 {
98 GObjectClass *gobject_class;
99 GstElementClass *gstelement_class;
100 GstBaseTransformClass *gstbasetrans_class;
101
102 gobject_class = G_OBJECT_CLASS (klass);
103 gstelement_class = GST_ELEMENT_CLASS (klass);
104 gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
105
106 GST_DEBUG_CATEGORY_INIT (gst_tag_inject_debug, "taginject", 0,
107 "tag inject element");
108
109 gobject_class->set_property = gst_tag_inject_set_property;
110 gobject_class->get_property = gst_tag_inject_get_property;
111
112 g_object_class_install_property (gobject_class, PROP_TAGS,
113 g_param_spec_string ("tags", "taglist",
114 "List of tags to inject into the target file",
115 NULL, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
116
117 gobject_class->finalize = gst_tag_inject_finalize;
118
119 gst_element_class_set_static_metadata (gstelement_class,
120 "TagInject",
121 "Generic", "inject metadata tags", "Stefan Kost <ensonic@users.sf.net>");
122 gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
123 gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
124
125 gstbasetrans_class->transform_ip =
126 GST_DEBUG_FUNCPTR (gst_tag_inject_transform_ip);
127
128 gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_tag_inject_start);
129 }
130
131 static void
gst_tag_inject_init(GstTagInject * self)132 gst_tag_inject_init (GstTagInject * self)
133 {
134 GstBaseTransform *trans = GST_BASE_TRANSFORM (self);
135
136 gst_base_transform_set_gap_aware (trans, TRUE);
137
138 self->tags = NULL;
139 }
140
141 static GstFlowReturn
gst_tag_inject_transform_ip(GstBaseTransform * trans,GstBuffer * buf)142 gst_tag_inject_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
143 {
144 GstTagInject *self = GST_TAG_INJECT (trans);
145
146 if (G_UNLIKELY (!self->tags_sent)) {
147 self->tags_sent = TRUE;
148 /* send tags */
149 if (self->tags && !gst_tag_list_is_empty (self->tags)) {
150 GST_DEBUG ("tag event :%" GST_PTR_FORMAT, self->tags);
151 gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (trans),
152 gst_event_new_tag (gst_tag_list_ref (self->tags)));
153 }
154 }
155
156 return GST_FLOW_OK;
157 }
158
159 static void
gst_tag_inject_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)160 gst_tag_inject_set_property (GObject * object, guint prop_id,
161 const GValue * value, GParamSpec * pspec)
162 {
163 GstTagInject *self = GST_TAG_INJECT (object);
164
165 switch (prop_id) {
166 case PROP_TAGS:{
167 gchar *structure =
168 g_strdup_printf ("taglist,%s", g_value_get_string (value));
169 if (!(self->tags = gst_tag_list_new_from_string (structure))) {
170 GST_WARNING ("unparsable taglist = '%s'", structure);
171 }
172
173 /* make sure that tags will be send */
174 self->tags_sent = FALSE;
175 g_free (structure);
176 break;
177 }
178 default:
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
180 break;
181 }
182 }
183
184 static void
gst_tag_inject_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)185 gst_tag_inject_get_property (GObject * object, guint prop_id, GValue * value,
186 GParamSpec * pspec)
187 {
188 /*GstTagInject *self = GST_TAG_INJECT (object); */
189
190 switch (prop_id) {
191 default:
192 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
193 break;
194 }
195 }
196
197 static gboolean
gst_tag_inject_start(GstBaseTransform * trans)198 gst_tag_inject_start (GstBaseTransform * trans)
199 {
200 GstTagInject *self = GST_TAG_INJECT (trans);
201
202 /* we need to sent tags _transform_ip() once */
203 self->tags_sent = FALSE;
204
205 return TRUE;
206 }
207