• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2011 David A. Schleef <ds@schleef.org>
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-intervideosink
21  * @title: gstintervideosink
22  *
23  * The intervideosink element is a video sink element.  It is used
24  * in connection with an intervideosrc element in a different pipeline,
25  * similar to interaudiosink and interaudiosrc.
26  *
27  * ## Example launch line
28  * |[
29  * gst-launch-1.0 -v videotestsrc ! intervideosink
30  * ]|
31  *
32  * The intervideosink element cannot be used effectively with gst-launch-1.0,
33  * as it requires a second pipeline in the application to send video to.
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 "gstintervideosink.h"
44 
45 #include <string.h>
46 
47 GST_DEBUG_CATEGORY_STATIC (gst_inter_video_sink_debug_category);
48 #define GST_CAT_DEFAULT gst_inter_video_sink_debug_category
49 
50 /* prototypes */
51 static void gst_inter_video_sink_set_property (GObject * object,
52     guint property_id, const GValue * value, GParamSpec * pspec);
53 static void gst_inter_video_sink_get_property (GObject * object,
54     guint property_id, GValue * value, GParamSpec * pspec);
55 static void gst_inter_video_sink_finalize (GObject * object);
56 
57 static void gst_inter_video_sink_get_times (GstBaseSink * sink,
58     GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
59 static gboolean gst_inter_video_sink_start (GstBaseSink * sink);
60 static gboolean gst_inter_video_sink_stop (GstBaseSink * sink);
61 static gboolean gst_inter_video_sink_set_caps (GstBaseSink * sink,
62     GstCaps * caps);
63 static GstFlowReturn gst_inter_video_sink_show_frame (GstVideoSink * sink,
64     GstBuffer * buffer);
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_video_sink_sink_template =
76 GST_STATIC_PAD_TEMPLATE ("sink",
77     GST_PAD_SINK,
78     GST_PAD_ALWAYS,
79     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL))
80     );
81 
82 
83 /* class initialization */
84 G_DEFINE_TYPE (GstInterVideoSink, gst_inter_video_sink, GST_TYPE_VIDEO_SINK);
85 GST_ELEMENT_REGISTER_DEFINE (intervideosink, "intervideosink",
86     GST_RANK_NONE, GST_TYPE_INTER_VIDEO_SINK);
87 
88 static void
gst_inter_video_sink_class_init(GstInterVideoSinkClass * klass)89 gst_inter_video_sink_class_init (GstInterVideoSinkClass * klass)
90 {
91   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
92   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
93   GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS (klass);
94   GstVideoSinkClass *video_sink_class = GST_VIDEO_SINK_CLASS (klass);
95 
96   GST_DEBUG_CATEGORY_INIT (gst_inter_video_sink_debug_category,
97       "intervideosink", 0, "debug category for intervideosink element");
98 
99   gst_element_class_add_static_pad_template (element_class,
100       &gst_inter_video_sink_sink_template);
101 
102   gst_element_class_set_static_metadata (element_class,
103       "Internal video sink",
104       "Sink/Video",
105       "Virtual video sink for internal process communication",
106       "David Schleef <ds@schleef.org>");
107 
108   gobject_class->set_property = gst_inter_video_sink_set_property;
109   gobject_class->get_property = gst_inter_video_sink_get_property;
110   gobject_class->finalize = gst_inter_video_sink_finalize;
111   base_sink_class->get_times =
112       GST_DEBUG_FUNCPTR (gst_inter_video_sink_get_times);
113   base_sink_class->start = GST_DEBUG_FUNCPTR (gst_inter_video_sink_start);
114   base_sink_class->stop = GST_DEBUG_FUNCPTR (gst_inter_video_sink_stop);
115   base_sink_class->set_caps = GST_DEBUG_FUNCPTR (gst_inter_video_sink_set_caps);
116   video_sink_class->show_frame =
117       GST_DEBUG_FUNCPTR (gst_inter_video_sink_show_frame);
118 
119   g_object_class_install_property (gobject_class, PROP_CHANNEL,
120       g_param_spec_string ("channel", "Channel",
121           "Channel name to match inter src and sink elements",
122           DEFAULT_CHANNEL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
123 }
124 
125 static void
gst_inter_video_sink_init(GstInterVideoSink * intervideosink)126 gst_inter_video_sink_init (GstInterVideoSink * intervideosink)
127 {
128   intervideosink->channel = g_strdup (DEFAULT_CHANNEL);
129 }
130 
131 void
gst_inter_video_sink_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)132 gst_inter_video_sink_set_property (GObject * object, guint property_id,
133     const GValue * value, GParamSpec * pspec)
134 {
135   GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object);
136 
137   switch (property_id) {
138     case PROP_CHANNEL:
139       g_free (intervideosink->channel);
140       intervideosink->channel = g_value_dup_string (value);
141       break;
142     default:
143       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
144       break;
145   }
146 }
147 
148 void
gst_inter_video_sink_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)149 gst_inter_video_sink_get_property (GObject * object, guint property_id,
150     GValue * value, GParamSpec * pspec)
151 {
152   GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object);
153 
154   switch (property_id) {
155     case PROP_CHANNEL:
156       g_value_set_string (value, intervideosink->channel);
157       break;
158     default:
159       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
160       break;
161   }
162 }
163 
164 void
gst_inter_video_sink_finalize(GObject * object)165 gst_inter_video_sink_finalize (GObject * object)
166 {
167   GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (object);
168 
169   /* clean up object here */
170   g_free (intervideosink->channel);
171 
172   G_OBJECT_CLASS (gst_inter_video_sink_parent_class)->finalize (object);
173 }
174 
175 
176 static void
gst_inter_video_sink_get_times(GstBaseSink * sink,GstBuffer * buffer,GstClockTime * start,GstClockTime * end)177 gst_inter_video_sink_get_times (GstBaseSink * sink, GstBuffer * buffer,
178     GstClockTime * start, GstClockTime * end)
179 {
180   GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (sink);
181 
182   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
183     *start = GST_BUFFER_TIMESTAMP (buffer);
184     if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
185       *end = *start + GST_BUFFER_DURATION (buffer);
186     } else {
187       if (intervideosink->info.fps_n > 0) {
188         *end = *start +
189             gst_util_uint64_scale_int (GST_SECOND, intervideosink->info.fps_d,
190             intervideosink->info.fps_n);
191       }
192     }
193   }
194 }
195 
196 static gboolean
gst_inter_video_sink_start(GstBaseSink * sink)197 gst_inter_video_sink_start (GstBaseSink * sink)
198 {
199   GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (sink);
200 
201   intervideosink->surface = gst_inter_surface_get (intervideosink->channel);
202   g_mutex_lock (&intervideosink->surface->mutex);
203   memset (&intervideosink->surface->video_info, 0, sizeof (GstVideoInfo));
204   g_mutex_unlock (&intervideosink->surface->mutex);
205 
206   return TRUE;
207 }
208 
209 static gboolean
gst_inter_video_sink_stop(GstBaseSink * sink)210 gst_inter_video_sink_stop (GstBaseSink * sink)
211 {
212   GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (sink);
213 
214   g_mutex_lock (&intervideosink->surface->mutex);
215   if (intervideosink->surface->video_buffer) {
216     gst_buffer_unref (intervideosink->surface->video_buffer);
217   }
218   intervideosink->surface->video_buffer = NULL;
219   memset (&intervideosink->surface->video_info, 0, sizeof (GstVideoInfo));
220   g_mutex_unlock (&intervideosink->surface->mutex);
221 
222   gst_inter_surface_unref (intervideosink->surface);
223   intervideosink->surface = NULL;
224 
225   return TRUE;
226 }
227 
228 static gboolean
gst_inter_video_sink_set_caps(GstBaseSink * sink,GstCaps * caps)229 gst_inter_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
230 {
231   GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (sink);
232   GstVideoInfo info;
233 
234   if (!gst_video_info_from_caps (&info, caps)) {
235     GST_ERROR_OBJECT (sink, "Failed to parse caps %" GST_PTR_FORMAT, caps);
236     return FALSE;
237   }
238 
239   g_mutex_lock (&intervideosink->surface->mutex);
240   intervideosink->surface->video_info = info;
241   intervideosink->info = info;
242   g_mutex_unlock (&intervideosink->surface->mutex);
243 
244   return TRUE;
245 }
246 
247 static GstFlowReturn
gst_inter_video_sink_show_frame(GstVideoSink * sink,GstBuffer * buffer)248 gst_inter_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buffer)
249 {
250   GstInterVideoSink *intervideosink = GST_INTER_VIDEO_SINK (sink);
251 
252   GST_DEBUG_OBJECT (intervideosink, "render ts %" GST_TIME_FORMAT,
253       GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
254 
255   g_mutex_lock (&intervideosink->surface->mutex);
256   if (intervideosink->surface->video_buffer) {
257     gst_buffer_unref (intervideosink->surface->video_buffer);
258   }
259   intervideosink->surface->video_buffer = gst_buffer_ref (buffer);
260   intervideosink->surface->video_buffer_count = 0;
261   g_mutex_unlock (&intervideosink->surface->mutex);
262 
263   return GST_FLOW_OK;
264 }
265