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-intersubsink
21 * @title: gstintersubsink
22 *
23 * The intersubsink element is a subtitle sink element. It is used
24 * in connection with a intersubsrc element in a different pipeline.
25 *
26 * ## Example launch line
27 * |[
28 * gst-launch-1.0 -v ... ! intersubsink
29 * ]|
30 *
31 * The intersubsink element cannot be used effectively with gst-launch-1.0,
32 * as it requires a second pipeline in the application to send audio.
33 * See the gstintertest.c example in the gst-plugins-bad source code for
34 * more details.
35 *
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <gst/gst.h>
43 #include <gst/base/gstbasesink.h>
44 #include "gstintersubsink.h"
45
46 GST_DEBUG_CATEGORY_STATIC (gst_inter_sub_sink_debug_category);
47 #define GST_CAT_DEFAULT gst_inter_sub_sink_debug_category
48
49 /* prototypes */
50 static void gst_inter_sub_sink_set_property (GObject * object,
51 guint property_id, const GValue * value, GParamSpec * pspec);
52 static void gst_inter_sub_sink_get_property (GObject * object,
53 guint property_id, GValue * value, GParamSpec * pspec);
54 static void gst_inter_sub_sink_finalize (GObject * object);
55
56 static void gst_inter_sub_sink_get_times (GstBaseSink * sink,
57 GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
58 static gboolean gst_inter_sub_sink_start (GstBaseSink * sink);
59 static gboolean gst_inter_sub_sink_stop (GstBaseSink * sink);
60 static GstFlowReturn
61 gst_inter_sub_sink_render (GstBaseSink * sink, GstBuffer * buffer);
62
63 enum
64 {
65 PROP_0,
66 PROP_CHANNEL
67 };
68
69 #define DEFAULT_CHANNEL ("default")
70
71 /* pad templates */
72 static GstStaticPadTemplate gst_inter_sub_sink_sink_template =
73 GST_STATIC_PAD_TEMPLATE ("sink",
74 GST_PAD_SINK,
75 GST_PAD_ALWAYS,
76 GST_STATIC_CAPS ("text/plain")
77 );
78
79
80 /* class initialization */
81 #define parent_class gst_inter_sub_sink_parent_class
82 G_DEFINE_TYPE (GstInterSubSink, gst_inter_sub_sink, GST_TYPE_BASE_SINK);
83 GST_ELEMENT_REGISTER_DEFINE (intersubsink, "intersubsink", GST_RANK_NONE,
84 GST_TYPE_INTER_SUB_SINK);
85
86 static void
gst_inter_sub_sink_class_init(GstInterSubSinkClass * klass)87 gst_inter_sub_sink_class_init (GstInterSubSinkClass * klass)
88 {
89 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
90 GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS (klass);
91 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
92
93 GST_DEBUG_CATEGORY_INIT (gst_inter_sub_sink_debug_category, "intersubsink", 0,
94 "debug category for intersubsink element");
95
96 gst_element_class_add_static_pad_template (element_class,
97 &gst_inter_sub_sink_sink_template);
98
99 gst_element_class_set_static_metadata (element_class,
100 "Internal subtitle sink",
101 "Sink/Subtitle",
102 "Virtual subtitle sink for internal process communication",
103 "David Schleef <ds@schleef.org>");
104
105 gobject_class->set_property = gst_inter_sub_sink_set_property;
106 gobject_class->get_property = gst_inter_sub_sink_get_property;
107 gobject_class->finalize = gst_inter_sub_sink_finalize;
108 base_sink_class->get_times = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_get_times);
109 base_sink_class->start = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_start);
110 base_sink_class->stop = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_stop);
111 base_sink_class->render = GST_DEBUG_FUNCPTR (gst_inter_sub_sink_render);
112
113 g_object_class_install_property (gobject_class, PROP_CHANNEL,
114 g_param_spec_string ("channel", "Channel",
115 "Channel name to match inter src and sink elements",
116 DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
117 }
118
119 static void
gst_inter_sub_sink_init(GstInterSubSink * intersubsink)120 gst_inter_sub_sink_init (GstInterSubSink * intersubsink)
121 {
122 intersubsink->channel = g_strdup (DEFAULT_CHANNEL);
123
124 intersubsink->fps_n = 1;
125 intersubsink->fps_d = 1;
126 }
127
128 void
gst_inter_sub_sink_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)129 gst_inter_sub_sink_set_property (GObject * object, guint property_id,
130 const GValue * value, GParamSpec * pspec)
131 {
132 GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object);
133
134 switch (property_id) {
135 case PROP_CHANNEL:
136 g_free (intersubsink->channel);
137 intersubsink->channel = g_value_dup_string (value);
138 break;
139 default:
140 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
141 break;
142 }
143 }
144
145 void
gst_inter_sub_sink_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)146 gst_inter_sub_sink_get_property (GObject * object, guint property_id,
147 GValue * value, GParamSpec * pspec)
148 {
149 GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object);
150
151 switch (property_id) {
152 case PROP_CHANNEL:
153 g_value_set_string (value, intersubsink->channel);
154 break;
155 default:
156 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
157 break;
158 }
159 }
160
161 static void
gst_inter_sub_sink_finalize(GObject * object)162 gst_inter_sub_sink_finalize (GObject * object)
163 {
164 GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (object);
165
166 g_free (intersubsink->channel);
167 intersubsink->channel = NULL;
168
169 G_OBJECT_CLASS (parent_class)->finalize (object);
170 }
171
172 static void
gst_inter_sub_sink_get_times(GstBaseSink * sink,GstBuffer * buffer,GstClockTime * start,GstClockTime * end)173 gst_inter_sub_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
174 GstClockTime * start, GstClockTime * end)
175 {
176 GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (sink);
177
178 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
179 *start = GST_BUFFER_TIMESTAMP (buffer);
180 if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
181 *end = *start + GST_BUFFER_DURATION (buffer);
182 } else {
183 if (intersubsink->fps_n > 0) {
184 *end = *start +
185 gst_util_uint64_scale_int (GST_SECOND, intersubsink->fps_d,
186 intersubsink->fps_n);
187 }
188 }
189 }
190 }
191
192 static gboolean
gst_inter_sub_sink_start(GstBaseSink * sink)193 gst_inter_sub_sink_start (GstBaseSink * sink)
194 {
195 GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (sink);
196
197 intersubsink->surface = gst_inter_surface_get (intersubsink->channel);
198
199 return TRUE;
200 }
201
202 static gboolean
gst_inter_sub_sink_stop(GstBaseSink * sink)203 gst_inter_sub_sink_stop (GstBaseSink * sink)
204 {
205 GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (sink);
206
207 g_mutex_lock (&intersubsink->surface->mutex);
208 if (intersubsink->surface->sub_buffer) {
209 gst_buffer_unref (intersubsink->surface->sub_buffer);
210 }
211 intersubsink->surface->sub_buffer = NULL;
212 g_mutex_unlock (&intersubsink->surface->mutex);
213
214 gst_inter_surface_unref (intersubsink->surface);
215 intersubsink->surface = NULL;
216
217 return TRUE;
218 }
219
220 static GstFlowReturn
gst_inter_sub_sink_render(GstBaseSink * sink,GstBuffer * buffer)221 gst_inter_sub_sink_render (GstBaseSink * sink, GstBuffer * buffer)
222 {
223 GstInterSubSink *intersubsink = GST_INTER_SUB_SINK (sink);
224
225 g_mutex_lock (&intersubsink->surface->mutex);
226 if (intersubsink->surface->sub_buffer) {
227 gst_buffer_unref (intersubsink->surface->sub_buffer);
228 }
229 intersubsink->surface->sub_buffer = gst_buffer_ref (buffer);
230 //intersubsink->surface->sub_buffer_count = 0;
231 g_mutex_unlock (&intersubsink->surface->mutex);
232
233 return GST_FLOW_OK;
234 }
235