• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2011 David Schleef <ds@entropywave.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17  * Boston, MA 02110-1335, USA.
18  */
19 /**
20  * SECTION:element-intersubsrc
21  * @title: gstintersubsrc
22  *
23  * The intersubsrc element is a subtitle source element.  It is used
24  * in connection with a intersubsink element in a different pipeline,
25  * similar to interaudiosink and interaudiosrc.
26  *
27  * ## Example launch line
28  * |[
29  * gst-launch-1.0 -v intersubsrc ! kateenc ! oggmux ! filesink location=out.ogv
30  * ]|
31  *
32  * The intersubsrc element cannot be used effectively with gst-launch-1.0,
33  * as it requires a second pipeline in the application to send subtitles.
34  * See the gstintertest.c example in the gst-plugins-bad source code for
35  * more details.
36  *
37  */
38 
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 
43 #include <gst/gst.h>
44 #include <gst/base/gstbasesrc.h>
45 #include "gstintersubsrc.h"
46 
47 GST_DEBUG_CATEGORY_STATIC (gst_inter_sub_src_debug_category);
48 #define GST_CAT_DEFAULT gst_inter_sub_src_debug_category
49 
50 /* prototypes */
51 static void gst_inter_sub_src_set_property (GObject * object,
52     guint property_id, const GValue * value, GParamSpec * pspec);
53 static void gst_inter_sub_src_get_property (GObject * object,
54     guint property_id, GValue * value, GParamSpec * pspec);
55 static void gst_inter_sub_src_finalize (GObject * object);
56 
57 static gboolean gst_inter_sub_src_start (GstBaseSrc * src);
58 static gboolean gst_inter_sub_src_stop (GstBaseSrc * src);
59 static void
60 gst_inter_sub_src_get_times (GstBaseSrc * src, GstBuffer * buffer,
61     GstClockTime * start, GstClockTime * end);
62 static GstFlowReturn
63 gst_inter_sub_src_create (GstBaseSrc * src, guint64 offset, guint size,
64     GstBuffer ** buf);
65 
66 enum
67 {
68   PROP_0,
69   PROP_CHANNEL
70 };
71 
72 #define DEFAULT_CHANNEL ("default")
73 
74 /* pad templates */
75 static GstStaticPadTemplate gst_inter_sub_src_src_template =
76 GST_STATIC_PAD_TEMPLATE ("src",
77     GST_PAD_SRC,
78     GST_PAD_ALWAYS,
79     GST_STATIC_CAPS ("application/unknown")
80     );
81 
82 /* class initialization */
83 #define parent_class gst_inter_sub_src_parent_class
84 G_DEFINE_TYPE (GstInterSubSrc, gst_inter_sub_src, GST_TYPE_BASE_SRC);
85 GST_ELEMENT_REGISTER_DEFINE (intersubsrc, "intersubsrc", GST_RANK_NONE,
86     GST_TYPE_INTER_SUB_SRC);
87 
88 static void
gst_inter_sub_src_class_init(GstInterSubSrcClass * klass)89 gst_inter_sub_src_class_init (GstInterSubSrcClass * klass)
90 {
91   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
92   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
93   GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass);
94 
95   GST_DEBUG_CATEGORY_INIT (gst_inter_sub_src_debug_category, "intersubsrc", 0,
96       "debug category for intersubsrc element");
97 
98   gst_element_class_add_static_pad_template (element_class,
99       &gst_inter_sub_src_src_template);
100 
101   gst_element_class_set_static_metadata (element_class,
102       "Internal subtitle source",
103       "Source/Subtitle",
104       "Virtual subtitle source for internal process communication",
105       "David Schleef <ds@schleef.org>");
106 
107   gobject_class->set_property = gst_inter_sub_src_set_property;
108   gobject_class->get_property = gst_inter_sub_src_get_property;
109   gobject_class->finalize = gst_inter_sub_src_finalize;
110   base_src_class->start = GST_DEBUG_FUNCPTR (gst_inter_sub_src_start);
111   base_src_class->stop = GST_DEBUG_FUNCPTR (gst_inter_sub_src_stop);
112   base_src_class->get_times = GST_DEBUG_FUNCPTR (gst_inter_sub_src_get_times);
113   base_src_class->create = GST_DEBUG_FUNCPTR (gst_inter_sub_src_create);
114 
115   g_object_class_install_property (gobject_class, PROP_CHANNEL,
116       g_param_spec_string ("channel", "Channel",
117           "Channel name to match inter src and sink elements",
118           DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
119 }
120 
121 static void
gst_inter_sub_src_init(GstInterSubSrc * intersubsrc)122 gst_inter_sub_src_init (GstInterSubSrc * intersubsrc)
123 {
124   gst_base_src_set_format (GST_BASE_SRC (intersubsrc), GST_FORMAT_TIME);
125   gst_base_src_set_live (GST_BASE_SRC (intersubsrc), TRUE);
126 
127   intersubsrc->channel = g_strdup (DEFAULT_CHANNEL);
128 }
129 
130 void
gst_inter_sub_src_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)131 gst_inter_sub_src_set_property (GObject * object, guint property_id,
132     const GValue * value, GParamSpec * pspec)
133 {
134   GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object);
135 
136   switch (property_id) {
137     case PROP_CHANNEL:
138       g_free (intersubsrc->channel);
139       intersubsrc->channel = g_value_dup_string (value);
140       break;
141     default:
142       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
143       break;
144   }
145 }
146 
147 void
gst_inter_sub_src_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)148 gst_inter_sub_src_get_property (GObject * object, guint property_id,
149     GValue * value, GParamSpec * pspec)
150 {
151   GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object);
152 
153   switch (property_id) {
154     case PROP_CHANNEL:
155       g_value_set_string (value, intersubsrc->channel);
156       break;
157     default:
158       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
159       break;
160   }
161 }
162 
163 static void
gst_inter_sub_src_finalize(GObject * object)164 gst_inter_sub_src_finalize (GObject * object)
165 {
166   GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (object);
167 
168   g_free (intersubsrc->channel);
169   intersubsrc->channel = NULL;
170 
171   G_OBJECT_CLASS (parent_class)->finalize (object);
172 }
173 
174 static gboolean
gst_inter_sub_src_start(GstBaseSrc * src)175 gst_inter_sub_src_start (GstBaseSrc * src)
176 {
177   GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
178 
179   GST_DEBUG_OBJECT (intersubsrc, "start");
180 
181   intersubsrc->surface = gst_inter_surface_get (intersubsrc->channel);
182 
183   return TRUE;
184 }
185 
186 static gboolean
gst_inter_sub_src_stop(GstBaseSrc * src)187 gst_inter_sub_src_stop (GstBaseSrc * src)
188 {
189   GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
190 
191   GST_DEBUG_OBJECT (intersubsrc, "stop");
192 
193   gst_inter_surface_unref (intersubsrc->surface);
194   intersubsrc->surface = NULL;
195 
196   return TRUE;
197 }
198 
199 static void
gst_inter_sub_src_get_times(GstBaseSrc * src,GstBuffer * buffer,GstClockTime * start,GstClockTime * end)200 gst_inter_sub_src_get_times (GstBaseSrc * src, GstBuffer * buffer,
201     GstClockTime * start, GstClockTime * end)
202 {
203   GST_DEBUG_OBJECT (src, "get_times");
204 
205   /* for live sources, sync on the timestamp of the buffer */
206   if (gst_base_src_is_live (src)) {
207     GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
208 
209     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
210       /* get duration to calculate end time */
211       GstClockTime duration = GST_BUFFER_DURATION (buffer);
212 
213       if (GST_CLOCK_TIME_IS_VALID (duration)) {
214         *end = timestamp + duration;
215       }
216       *start = timestamp;
217     }
218   } else {
219     *start = -1;
220     *end = -1;
221   }
222 }
223 
224 static GstFlowReturn
gst_inter_sub_src_create(GstBaseSrc * src,guint64 offset,guint size,GstBuffer ** buf)225 gst_inter_sub_src_create (GstBaseSrc * src, guint64 offset, guint size,
226     GstBuffer ** buf)
227 {
228   GstInterSubSrc *intersubsrc = GST_INTER_SUB_SRC (src);
229   GstBuffer *buffer;
230 
231   GST_DEBUG_OBJECT (intersubsrc, "create");
232 
233   buffer = NULL;
234 
235   g_mutex_lock (&intersubsrc->surface->mutex);
236   if (intersubsrc->surface->sub_buffer) {
237     buffer = gst_buffer_ref (intersubsrc->surface->sub_buffer);
238     //intersubsrc->surface->sub_buffer_count++;
239     //if (intersubsrc->surface->sub_buffer_count >= 30) {
240     gst_buffer_unref (intersubsrc->surface->sub_buffer);
241     intersubsrc->surface->sub_buffer = NULL;
242     //}
243   }
244   g_mutex_unlock (&intersubsrc->surface->mutex);
245 
246   if (buffer == NULL) {
247     GstMapInfo map;
248 
249     buffer = gst_buffer_new_and_alloc (1);
250 
251     gst_buffer_map (buffer, &map, GST_MAP_WRITE);
252     map.data[0] = 0;
253     gst_buffer_unmap (buffer, &map);
254   }
255 
256   buffer = gst_buffer_make_writable (buffer);
257 
258   /* FIXME: does this make sense? Rate is always 0 */
259 #if 0
260   GST_BUFFER_TIMESTAMP (buffer) =
261       gst_util_uint64_scale_int (GST_SECOND, intersubsrc->n_frames,
262       intersubsrc->rate);
263   GST_DEBUG_OBJECT (intersubsrc, "create ts %" GST_TIME_FORMAT,
264       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
265   GST_BUFFER_DURATION (buffer) =
266       gst_util_uint64_scale_int (GST_SECOND, (intersubsrc->n_frames + 1),
267       intersubsrc->rate) - GST_BUFFER_TIMESTAMP (buffer);
268 #endif
269   GST_BUFFER_OFFSET (buffer) = intersubsrc->n_frames;
270   GST_BUFFER_OFFSET_END (buffer) = -1;
271   GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
272   if (intersubsrc->n_frames == 0) {
273     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
274   }
275   intersubsrc->n_frames++;
276 
277   *buf = buffer;
278 
279   return GST_FLOW_OK;
280 }
281