branch | RCL_3 |
changeset 30 | 7e817e7e631c |
parent 29 | 567bb019e3e3 |
29:567bb019e3e3 | 30:7e817e7e631c |
---|---|
18 */ |
18 */ |
19 |
19 |
20 /** |
20 /** |
21 * SECTION:element-playbin |
21 * SECTION:element-playbin |
22 * |
22 * |
23 * <refsect2> |
|
24 * <para> |
|
23 * Playbin provides a stand-alone everything-in-one abstraction for an |
25 * Playbin provides a stand-alone everything-in-one abstraction for an |
24 * audio and/or video player. |
26 * audio and/or video player. |
25 * |
27 * </para> |
28 * <para> |
|
26 * It can handle both audio and video files and features |
29 * It can handle both audio and video files and features |
27 * <itemizedlist> |
30 * <itemizedlist> |
28 * <listitem> |
31 * <listitem> |
29 * automatic file type recognition and based on that automatic |
32 * automatic file type recognition and based on that automatic |
30 * selection and usage of the right audio/video/subtitle demuxers/decoders |
33 * selection and usage of the right audio/video/subtitle demuxers/decoders |
49 * </listitem> |
52 * </listitem> |
50 * <listitem> |
53 * <listitem> |
51 * volume control |
54 * volume control |
52 * </listitem> |
55 * </listitem> |
53 * </itemizedlist> |
56 * </itemizedlist> |
54 * |
57 * </para> |
55 * <refsect2> |
|
56 * <title>Usage</title> |
58 * <title>Usage</title> |
57 * <para> |
59 * <para> |
58 * A playbin element can be created just like any other element using |
60 * A playbin element can be created just like any other element using |
59 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin:uri |
61 * gst_element_factory_make(). The file/URI to play should be set via the "uri" |
60 * property. This must be an absolute URI, relative file paths are not allowed. |
62 * property. This must be an absolute URI, relative file paths are not allowed. |
61 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg |
63 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg |
62 * |
64 * </para> |
65 * <para> |
|
63 * Playbin is a #GstPipeline. It will notify the application of everything |
66 * Playbin is a #GstPipeline. It will notify the application of everything |
64 * that's happening (errors, end of stream, tags found, state changes, etc.) |
67 * that's happening (errors, end of stream, tags found, state changes, etc.) |
65 * by posting messages on its #GstBus. The application needs to watch the |
68 * by posting messages on its #GstBus. The application needs to watch the |
66 * bus. |
69 * bus. |
67 * |
70 * </para> |
71 * <para> |
|
68 * Playback can be initiated by setting the element to PLAYING state using |
72 * Playback can be initiated by setting the element to PLAYING state using |
69 * gst_element_set_state(). Note that the state change will take place in |
73 * gst_element_set_state(). Note that the state change will take place in |
70 * the background in a separate thread, when the function returns playback |
74 * the background in a separate thread, when the function returns playback |
71 * is probably not happening yet and any errors might not have occured yet. |
75 * is probably not happening yet and any errors might not have occured yet. |
72 * Applications using playbin should ideally be written to deal with things |
76 * Applications using playbin should ideally be written to deal with things |
73 * completely asynchroneous. |
77 * completely asynchroneous. |
74 * |
78 * </para> |
79 * <para> |
|
75 * When playback has finished (an EOS message has been received on the bus) |
80 * When playback has finished (an EOS message has been received on the bus) |
76 * or an error has occured (an ERROR message has been received on the bus) or |
81 * or an error has occured (an ERROR message has been received on the bus) or |
77 * the user wants to play a different track, playbin should be set back to |
82 * the user wants to play a different track, playbin should be set back to |
78 * READY or NULL state, then the #GstPlayBin:uri property should be set to the |
83 * READY or NULL state, then the "uri" property should be set to the new |
79 * new location and then playbin be set to PLAYING state again. |
84 * location and then playbin be set to PLAYING state again. |
80 * |
85 * </para> |
86 * <para> |
|
81 * Seeking can be done using gst_element_seek_simple() or gst_element_seek() |
87 * Seeking can be done using gst_element_seek_simple() or gst_element_seek() |
82 * on the playbin element. Again, the seek will not be executed |
88 * on the playbin element. Again, the seek will not be executed |
83 * instantaneously, but will be done in a background thread. When the seek |
89 * instantaneously, but will be done in a background thread. When the seek |
84 * call returns the seek will most likely still be in process. An application |
90 * call returns the seek will most likely still be in process. An application |
85 * may wait for the seek to finish (or fail) using gst_element_get_state() with |
91 * may wait for the seek to finish (or fail) using gst_element_get_state() with |
86 * -1 as the timeout, but this will block the user interface and is not |
92 * -1 as the timeout, but this will block the user interface and is not |
87 * recommended at all. |
93 * recommended at all. |
88 * |
94 * </para> |
95 * <para> |
|
89 * Applications may query the current position and duration of the stream |
96 * Applications may query the current position and duration of the stream |
90 * via gst_element_query_position() and gst_element_query_duration() and |
97 * via gst_element_query_position() and gst_element_query_duration() and |
91 * setting the format passed to GST_FORMAT_TIME. If the query was successful, |
98 * setting the format passed to GST_FORMAT_TIME. If the query was successful, |
92 * the duration or position will have been returned in units of nanoseconds. |
99 * the duration or position will have been returned in units of nanoseconds. |
93 * </para> |
100 * </para> |
94 * </refsect2> |
|
95 * <refsect2> |
|
96 * <title>Advanced Usage: specifying the audio and video sink</title> |
101 * <title>Advanced Usage: specifying the audio and video sink</title> |
97 * <para> |
102 * <para> |
98 * By default, if no audio sink or video sink has been specified via the |
103 * By default, if no audio sink or video sink has been specified via the |
99 * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property, playbin will use |
104 * "audio-sink" or "video-sink" property, playbin will use the autoaudiosink |
100 * the autoaudiosink and autovideosink elements to find the first-best |
105 * and autovideosink elements to find the first-best available output method. |
101 * available output method. |
|
102 * This should work in most cases, but is not always desirable. Often either |
106 * This should work in most cases, but is not always desirable. Often either |
103 * the user or application might want to specify more explicitly what to use |
107 * the user or application might want to specify more explicitly what to use |
104 * for audio and video output. |
108 * for audio and video output. |
105 * |
109 * </para> |
110 * <para> |
|
106 * If the application wants more control over how audio or video should be |
111 * If the application wants more control over how audio or video should be |
107 * output, it may create the audio/video sink elements itself (for example |
112 * output, it may create the audio/video sink elements itself (for example |
108 * using gst_element_factory_make()) and provide them to playbin using the |
113 * using gst_element_factory_make()) and provide them to playbin using the |
109 * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property. |
114 * "audio-sink" or "video-sink" property. |
110 * |
115 * </para> |
116 * <para> |
|
111 * GNOME-based applications, for example, will usually want to create |
117 * GNOME-based applications, for example, will usually want to create |
112 * gconfaudiosink and gconfvideosink elements and make playbin use those, |
118 * gconfaudiosink and gconfvideosink elements and make playbin use those, |
113 * so that output happens to whatever the user has configured in the GNOME |
119 * so that output happens to whatever the user has configured in the GNOME |
114 * Multimedia System Selector confinguration dialog. |
120 * Multimedia System Selector confinguration dialog. |
115 * |
121 * </para> |
122 * <para> |
|
116 * The sink elements do not necessarily need to be ready-made sinks. It is |
123 * The sink elements do not necessarily need to be ready-made sinks. It is |
117 * possible to create container elements that look like a sink to playbin, |
124 * possible to create container elements that look like a sink to playbin, |
118 * but in reality contain a number of custom elements linked together. This |
125 * but in reality contain a number of custom elements linked together. This |
119 * can be achieved by creating a #GstBin and putting elements in there and |
126 * can be achieved by creating a #GstBin and putting elements in there and |
120 * linking them, and then creating a sink #GstGhostPad for the bin and pointing |
127 * linking them, and then creating a sink #GstGhostPad for the bin and pointing |
121 * it to the sink pad of the first element within the bin. This can be used |
128 * it to the sink pad of the first element within the bin. This can be used |
122 * for a number of purposes, for example to force output to a particular |
129 * for a number of purposes, for example to force output to a particular |
123 * format or to modify or observe the data before it is output. |
130 * format or to modify or observe the data before it is output. |
124 * |
131 * </para> |
132 * <para> |
|
125 * It is also possible to 'suppress' audio and/or video output by using |
133 * It is also possible to 'suppress' audio and/or video output by using |
126 * 'fakesink' elements (or capture it from there using the fakesink element's |
134 * 'fakesink' elements (or capture it from there using the fakesink element's |
127 * "handoff" signal, which, nota bene, is fired from the streaming thread!). |
135 * "handoff" signal, which, nota bene, is fired from the streaming thread!). |
128 * </para> |
136 * </para> |
129 * </refsect2> |
|
130 * <refsect2> |
|
131 * <title>Retrieving Tags and Other Meta Data</title> |
137 * <title>Retrieving Tags and Other Meta Data</title> |
132 * <para> |
138 * <para> |
133 * Most of the common meta data (artist, title, etc.) can be retrieved by |
139 * Most of the common meta data (artist, title, etc.) can be retrieved by |
134 * watching for TAG messages on the pipeline's bus (see above). |
140 * watching for TAG messages on the pipeline's bus (see above). |
135 * |
141 * </para> |
142 * <para> |
|
136 * Other more specific meta information like width/height/framerate of video |
143 * Other more specific meta information like width/height/framerate of video |
137 * streams or samplerate/number of channels of audio streams can be obtained |
144 * streams or samplerate/number of channels of audio streams can be obtained |
138 * using the #GstPlayBaseBin:stream-info property, which will return a GList of |
145 * using the "stream-info" property, which will return a GList of stream info |
139 * stream info objects, one for each stream. These are opaque objects that can |
146 * objects, one for each stream. These are opaque objects that can only be |
140 * only be accessed via the standard GObject property interface, ie. g_object_get(). |
147 * accessed via the standard GObject property interface, ie. g_object_get(). |
141 * Each stream info object has the following properties: |
148 * Each stream info object has the following properties: |
142 * <itemizedlist> |
149 * <itemizedlist> |
143 * <listitem>"object" (GstObject) (the decoder source pad usually)</listitem> |
150 * <listitem>"object" (GstObject) (the decoder source pad usually)</listitem> |
144 * <listitem>"type" (enum) (if this is an audio/video/subtitle stream)</listitem> |
151 * <listitem>"type" (enum) (if this is an audio/video/subtitle stream)</listitem> |
145 * <listitem>"decoder" (string) (name of decoder used to decode this stream)</listitem> |
152 * <listitem>"decoder" (string) (name of decoder used to decode this stream)</listitem> |
146 * <listitem>"mute" (boolean) (to mute or unmute this stream)</listitem> |
153 * <listitem>"mute" (boolean) (to mute or unmute this stream)</listitem> |
147 * <listitem>"caps" (GstCaps) (caps of the decoded stream)</listitem> |
154 * <listitem>"caps" (GstCaps) (caps of the decoded stream)</listitem> |
148 * <listitem>"language-code" (string) (ISO-639 language code for this stream, mostly used for audio/subtitle streams)</listitem> |
155 * <listitem>"language-code" (string) (ISO-639 language code for this stream, mostly used for audio/subtitle streams)</listitem> |
149 * <listitem>"codec" (string) (format this stream was encoded in)</listitem> |
156 * <listitem>"codec" (string) (format this stream was encoded in)</listitem> |
150 * </itemizedlist> |
157 * </itemizedlist> |
151 * Stream information from the #GstPlayBaseBin:stream-info property is best queried once |
158 * Stream information from the stream-info properties is best queried once |
152 * playbin has changed into PAUSED or PLAYING state (which can be detected |
159 * playbin has changed into PAUSED or PLAYING state (which can be detected |
153 * via a state-changed message on the #GstBus where old_state=READY and |
160 * via a state-changed message on the bus where old_state=READY and |
154 * new_state=PAUSED), since before that the list might not be complete yet or |
161 * new_state=PAUSED), since before that the list might not be complete yet or |
155 * not contain all available information (like language-codes). |
162 * not contain all available information (like language-codes). |
156 * </para> |
163 * </para> |
157 * </refsect2> |
|
158 * <refsect2> |
|
159 * <title>Buffering</title> |
164 * <title>Buffering</title> |
165 * <para> |
|
160 * Playbin handles buffering automatically for the most part, but applications |
166 * Playbin handles buffering automatically for the most part, but applications |
161 * need to handle parts of the buffering process as well. Whenever playbin is |
167 * need to handle parts of the buffering process as well. Whenever playbin is |
162 * buffering, it will post BUFFERING messages on the bus with a percentage |
168 * buffering, it will post BUFFERING messages on the bus with a percentage |
163 * value that shows the progress of the buffering process. Applications need |
169 * value that shows the progress of the buffering process. Applications need |
164 * to set playbin to PLAYING or PAUSED state in response to these messages. |
170 * to set playbin to PLAYING or PAUSED state in response to these messages. |
165 * They may also want to convey the buffering progress to the user in some |
171 * They may also want to convey the buffering progress to the user in some |
166 * way. Here is how to extract the percentage information from the message |
172 * way. Here is how to extract the percentage information from the message |
167 * (requires GStreamer >= 0.10.11): |
173 * (requires GStreamer >= 0.10.11): |
168 * |[ |
174 * </para> |
175 * <para> |
|
176 * <programlisting> |
|
169 * switch (GST_MESSAGE_TYPE (msg)) { |
177 * switch (GST_MESSAGE_TYPE (msg)) { |
170 * case GST_MESSAGE_BUFFERING: { |
178 * case GST_MESSAGE_BUFFERING: { |
171 * gint percent = 0; |
179 * gint percent = 0; |
172 * gst_message_parse_buffering (msg, &percent); |
180 * gst_message_parse_buffering (msg, &percent); |
173 * g_print ("Buffering (%%u percent done)", percent); |
181 * g_print ("Buffering (%%u percent done)", percent); |
174 * break; |
182 * break; |
175 * } |
183 * } |
176 * ... |
184 * ... |
177 * } |
185 * } |
178 * ]| |
186 * </programlisting> |
179 * Note that applications should keep/set the pipeline in the PAUSED state when |
187 * Note that applications should keep/set the pipeline in the PAUSED state when |
180 * a BUFFERING message is received with a buffer percent value < 100 and set |
188 * a BUFFERING message is received with a buffer percent value < 100 and set |
181 * the pipeline back to PLAYING state when a BUFFERING message with a value |
189 * the pipeline back to PLAYING state when a BUFFERING message with a value |
182 * of 100 percent is received (if PLAYING is the desired state, that is). |
190 * of 100 percent is received (if PLAYING is the desired state, that is). |
183 * </refsect2> |
191 * </para> |
184 * <refsect2> |
|
185 * <title>Embedding the video window in your application</title> |
192 * <title>Embedding the video window in your application</title> |
193 * <para> |
|
186 * By default, playbin (or rather the video sinks used) will create their own |
194 * By default, playbin (or rather the video sinks used) will create their own |
187 * window. Applications will usually want to force output to a window of their |
195 * window. Applications will usually want to force output to a window of their |
188 * own, however. This can be done using the #GstXOverlay interface, which most |
196 * own, however. This can be done using the GstXOverlay interface, which most |
189 * video sinks implement. See the documentation there for more details. |
197 * video sinks implement. See the documentation there for more details. |
190 * </refsect2> |
198 * </para> |
191 * <refsect2> |
|
192 * <title>Specifying which CD/DVD device to use</title> |
199 * <title>Specifying which CD/DVD device to use</title> |
200 * <para> |
|
193 * The device to use for CDs/DVDs needs to be set on the source element |
201 * The device to use for CDs/DVDs needs to be set on the source element |
194 * playbin creates before it is opened. The only way to do this at the moment |
202 * playbin creates before it is opened. The only way to do this at the moment |
195 * is to connect to playbin's "notify::source" signal, which will be emitted |
203 * is to connect to playbin's "notify::source" signal, which will be emitted |
196 * by playbin when it has created the source element for a particular URI. |
204 * by playbin when it has created the source element for a particular URI. |
197 * In the signal callback you can check if the source element has a "device" |
205 * In the signal callback you can check if the source element has a "device" |
198 * property and set it appropriately. In future ways might be added to specify |
206 * property and set it appropriately. In future ways might be added to specify |
199 * the device as part of the URI, but at the time of writing this is not |
207 * the device as part of the URI, but at the time of writing this is not |
200 * possible yet. |
208 * possible yet. |
201 * </refsect2> |
209 * </para> |
202 * <refsect2> |
|
203 * <title>Examples</title> |
210 * <title>Examples</title> |
204 * |[ |
211 * <para> |
212 * Here is a simple pipeline to play back a video or audio file: |
|
213 * <programlisting> |
|
205 * gst-launch -v playbin uri=file:///path/to/somefile.avi |
214 * gst-launch -v playbin uri=file:///path/to/somefile.avi |
206 * ]| This will play back the given AVI video file, given that the video and |
215 * </programlisting> |
216 * This will play back the given AVI video file, given that the video and |
|
207 * audio decoders required to decode the content are installed. Since no |
217 * audio decoders required to decode the content are installed. Since no |
208 * special audio sink or video sink is supplied (not possible via gst-launch), |
218 * special audio sink or video sink is supplied (not possible via gst-launch), |
209 * playbin will try to find a suitable audio and video sink automatically |
219 * playbin will try to find a suitable audio and video sink automatically |
210 * using the autoaudiosink and autovideosink elements. |
220 * using the autoaudiosink and autovideosink elements. |
211 * |[ |
221 * </para> |
222 * <para> |
|
223 * Here is a another pipeline to play track 4 of an audio CD: |
|
224 * <programlisting> |
|
212 * gst-launch -v playbin uri=cdda://4 |
225 * gst-launch -v playbin uri=cdda://4 |
213 * ]| This will play back track 4 on an audio CD in your disc drive (assuming |
226 * </programlisting> |
227 * This will play back track 4 on an audio CD in your disc drive (assuming |
|
214 * the drive is detected automatically by the plugin). |
228 * the drive is detected automatically by the plugin). |
215 * |[ |
229 * </para> |
230 * <para> |
|
231 * Here is a another pipeline to play title 1 of a DVD: |
|
232 * <programlisting> |
|
216 * gst-launch -v playbin uri=dvd://1 |
233 * gst-launch -v playbin uri=dvd://1 |
217 * ]| This will play back title 1 of a DVD in your disc drive (assuming |
234 * </programlisting> |
235 * This will play back title 1 of a DVD in your disc drive (assuming |
|
218 * the drive is detected automatically by the plugin). |
236 * the drive is detected automatically by the plugin). |
237 * </para> |
|
219 * </refsect2> |
238 * </refsect2> |
220 */ |
239 */ |
221 |
240 |
222 #ifdef HAVE_CONFIG_H |
241 #ifdef HAVE_CONFIG_H |
223 #include "config.h" |
242 #include "config.h" |
228 |
247 |
229 #include <gst/gst-i18n-plugin.h> |
248 #include <gst/gst-i18n-plugin.h> |
230 #include <gst/pbutils/pbutils.h> |
249 #include <gst/pbutils/pbutils.h> |
231 |
250 |
232 #include "gstplaybasebin.h" |
251 #include "gstplaybasebin.h" |
252 |
|
253 #ifdef __SYMBIAN32__ |
|
254 #include <glib_global.h> |
|
255 #endif |
|
233 |
256 |
234 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug); |
257 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug); |
235 #define GST_CAT_DEFAULT gst_play_bin_debug |
258 #define GST_CAT_DEFAULT gst_play_bin_debug |
236 |
259 |
237 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type()) |
260 #define GST_TYPE_PLAY_BIN (gst_play_bin_get_type()) |
243 #define VOLUME_MAX_DOUBLE 10.0 |
266 #define VOLUME_MAX_DOUBLE 10.0 |
244 |
267 |
245 typedef struct _GstPlayBin GstPlayBin; |
268 typedef struct _GstPlayBin GstPlayBin; |
246 typedef struct _GstPlayBinClass GstPlayBinClass; |
269 typedef struct _GstPlayBinClass GstPlayBinClass; |
247 |
270 |
248 /** |
|
249 * GstPlayBin: |
|
250 * |
|
251 * High-level player element |
|
252 */ |
|
253 struct _GstPlayBin |
271 struct _GstPlayBin |
254 { |
272 { |
255 GstPlayBaseBin parent; |
273 GstPlayBaseBin parent; |
256 |
274 |
257 /* the configurable elements */ |
275 /* the configurable elements */ |
260 GstElement *video_sink; |
278 GstElement *video_sink; |
261 GstElement *visualisation; |
279 GstElement *visualisation; |
262 GstElement *pending_visualisation; |
280 GstElement *pending_visualisation; |
263 GstElement *volume_element; |
281 GstElement *volume_element; |
264 GstElement *textoverlay_element; |
282 GstElement *textoverlay_element; |
265 GstElement *spu_element; |
|
266 gfloat volume; |
283 gfloat volume; |
267 |
284 |
268 /* these are the currently active sinks */ |
285 /* these are the currently active sinks */ |
269 GList *sinks; |
286 GList *sinks; |
270 |
287 |
311 static gboolean setup_sinks (GstPlayBaseBin * play_base_bin, |
328 static gboolean setup_sinks (GstPlayBaseBin * play_base_bin, |
312 GstPlayBaseGroup * group); |
329 GstPlayBaseGroup * group); |
313 static void remove_sinks (GstPlayBin * play_bin); |
330 static void remove_sinks (GstPlayBin * play_bin); |
314 static void playbin_set_subtitles_visible (GstPlayBaseBin * play_base_bin, |
331 static void playbin_set_subtitles_visible (GstPlayBaseBin * play_base_bin, |
315 gboolean visible); |
332 gboolean visible); |
316 static void playbin_set_audio_mute (GstPlayBaseBin * play_base_bin, |
|
317 gboolean mute); |
|
318 |
333 |
319 static void gst_play_bin_set_property (GObject * object, guint prop_id, |
334 static void gst_play_bin_set_property (GObject * object, guint prop_id, |
320 const GValue * value, GParamSpec * spec); |
335 const GValue * value, GParamSpec * spec); |
321 static void gst_play_bin_get_property (GObject * object, guint prop_id, |
336 static void gst_play_bin_get_property (GObject * object, guint prop_id, |
322 GValue * value, GParamSpec * spec); |
337 GValue * value, GParamSpec * spec); |
383 gobject_klass->get_property = gst_play_bin_get_property; |
398 gobject_klass->get_property = gst_play_bin_get_property; |
384 |
399 |
385 g_object_class_install_property (gobject_klass, ARG_VIDEO_SINK, |
400 g_object_class_install_property (gobject_klass, ARG_VIDEO_SINK, |
386 g_param_spec_object ("video-sink", "Video Sink", |
401 g_param_spec_object ("video-sink", "Video Sink", |
387 "the video output element to use (NULL = default sink)", |
402 "the video output element to use (NULL = default sink)", |
388 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
403 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
389 g_object_class_install_property (gobject_klass, ARG_AUDIO_SINK, |
404 g_object_class_install_property (gobject_klass, ARG_AUDIO_SINK, |
390 g_param_spec_object ("audio-sink", "Audio Sink", |
405 g_param_spec_object ("audio-sink", "Audio Sink", |
391 "the audio output element to use (NULL = default sink)", |
406 "the audio output element to use (NULL = default sink)", |
392 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
407 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
393 g_object_class_install_property (gobject_klass, ARG_VIS_PLUGIN, |
408 g_object_class_install_property (gobject_klass, ARG_VIS_PLUGIN, |
394 g_param_spec_object ("vis-plugin", "Vis plugin", |
409 g_param_spec_object ("vis-plugin", "Vis plugin", |
395 "the visualization element to use (NULL = none)", |
410 "the visualization element to use (NULL = none)", |
396 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
411 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
397 g_object_class_install_property (gobject_klass, ARG_VOLUME, |
412 g_object_class_install_property (gobject_klass, ARG_VOLUME, |
398 g_param_spec_double ("volume", "volume", "volume", |
413 g_param_spec_double ("volume", "volume", "volume", |
399 0.0, VOLUME_MAX_DOUBLE, 1.0, |
414 0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE)); |
400 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
401 g_object_class_install_property (gobject_klass, ARG_FRAME, |
415 g_object_class_install_property (gobject_klass, ARG_FRAME, |
402 gst_param_spec_mini_object ("frame", "Frame", |
416 gst_param_spec_mini_object ("frame", "Frame", |
403 "The last frame (NULL = no video available)", GST_TYPE_BUFFER, |
417 "The last frame (NULL = no video available)", |
404 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
418 GST_TYPE_BUFFER, G_PARAM_READABLE)); |
405 g_object_class_install_property (gobject_klass, ARG_FONT_DESC, |
419 g_object_class_install_property (gobject_klass, ARG_FONT_DESC, |
406 g_param_spec_string ("subtitle-font-desc", "Subtitle font description", |
420 g_param_spec_string ("subtitle-font-desc", |
407 "Pango font description of font " "to be used for subtitle rendering", |
421 "Subtitle font description", |
408 NULL, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); |
422 "Pango font description of font " |
423 "to be used for subtitle rendering", NULL, G_PARAM_WRITABLE)); |
|
409 |
424 |
410 gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_bin_dispose); |
425 gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_bin_dispose); |
411 |
426 |
412 gst_element_class_set_details (gstelement_klass, &gst_play_bin_details); |
427 gst_element_class_set_details (gstelement_klass, &gst_play_bin_details); |
413 |
428 |
418 gstbin_klass->handle_message = |
433 gstbin_klass->handle_message = |
419 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message); |
434 GST_DEBUG_FUNCPTR (gst_play_bin_handle_message); |
420 |
435 |
421 playbasebin_klass->setup_output_pads = setup_sinks; |
436 playbasebin_klass->setup_output_pads = setup_sinks; |
422 playbasebin_klass->set_subtitles_visible = playbin_set_subtitles_visible; |
437 playbasebin_klass->set_subtitles_visible = playbin_set_subtitles_visible; |
423 playbasebin_klass->set_audio_mute = playbin_set_audio_mute; |
|
424 } |
438 } |
425 |
439 |
426 static void |
440 static void |
427 gst_play_bin_init (GstPlayBin * play_bin) |
441 gst_play_bin_init (GstPlayBin * play_bin) |
428 { |
442 { |
430 play_bin->audio_sink = NULL; |
444 play_bin->audio_sink = NULL; |
431 play_bin->visualisation = NULL; |
445 play_bin->visualisation = NULL; |
432 play_bin->pending_visualisation = NULL; |
446 play_bin->pending_visualisation = NULL; |
433 play_bin->volume_element = NULL; |
447 play_bin->volume_element = NULL; |
434 play_bin->textoverlay_element = NULL; |
448 play_bin->textoverlay_element = NULL; |
435 play_bin->spu_element = NULL; |
|
436 play_bin->volume = 1.0; |
449 play_bin->volume = 1.0; |
437 play_bin->sinks = NULL; |
450 play_bin->sinks = NULL; |
438 play_bin->frame = NULL; |
451 play_bin->frame = NULL; |
439 play_bin->font_desc = NULL; |
452 play_bin->font_desc = NULL; |
440 play_bin->cache = g_hash_table_new_full (g_str_hash, g_str_equal, |
453 play_bin->cache = g_hash_table_new_full (g_str_hash, g_str_equal, |
476 } |
489 } |
477 if (play_bin->textoverlay_element != NULL) { |
490 if (play_bin->textoverlay_element != NULL) { |
478 gst_object_unref (play_bin->textoverlay_element); |
491 gst_object_unref (play_bin->textoverlay_element); |
479 play_bin->textoverlay_element = NULL; |
492 play_bin->textoverlay_element = NULL; |
480 } |
493 } |
481 if (play_bin->spu_element != NULL) { |
|
482 gst_object_unref (play_bin->spu_element); |
|
483 play_bin->spu_element = NULL; |
|
484 } |
|
485 g_free (play_bin->font_desc); |
494 g_free (play_bin->font_desc); |
486 play_bin->font_desc = NULL; |
495 play_bin->font_desc = NULL; |
487 |
496 |
488 G_OBJECT_CLASS (parent_class)->dispose (object); |
497 G_OBJECT_CLASS (parent_class)->dispose (object); |
489 } |
498 } |
527 |
536 |
528 if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) { |
537 if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) { |
529 goto beach; |
538 goto beach; |
530 } |
539 } |
531 |
540 |
532 vis_src_pad = gst_element_get_static_pad (play_bin->visualisation, "src"); |
541 vis_src_pad = gst_element_get_pad (play_bin->visualisation, "src"); |
533 vis_sink_pad = gst_pad_get_peer (tee_pad); |
542 vis_sink_pad = gst_pad_get_peer (tee_pad); |
534 |
543 |
535 /* Can be fakesink */ |
544 /* Can be fakesink */ |
536 if (GST_IS_PAD (vis_src_pad)) { |
545 if (GST_IS_PAD (vis_src_pad)) { |
537 vqueue_pad = gst_pad_get_peer (vis_src_pad); |
546 vqueue_pad = gst_pad_get_peer (vis_src_pad); |
570 /* Add the new one */ |
579 /* Add the new one */ |
571 gst_bin_add (vis_bin, pending_visualisation); |
580 gst_bin_add (vis_bin, pending_visualisation); |
572 /* Synchronizing state */ |
581 /* Synchronizing state */ |
573 gst_element_set_state (pending_visualisation, bin_state); |
582 gst_element_set_state (pending_visualisation, bin_state); |
574 |
583 |
575 vis_sink_pad = gst_element_get_static_pad (pending_visualisation, "sink"); |
584 vis_sink_pad = gst_element_get_pad (pending_visualisation, "sink"); |
576 vis_src_pad = gst_element_get_static_pad (pending_visualisation, "src"); |
585 vis_src_pad = gst_element_get_pad (pending_visualisation, "src"); |
577 |
586 |
578 if (!GST_IS_PAD (vis_sink_pad) || !GST_IS_PAD (vis_src_pad)) { |
587 if (!GST_IS_PAD (vis_sink_pad) || !GST_IS_PAD (vis_src_pad)) { |
579 goto beach; |
588 goto beach; |
580 } |
589 } |
581 |
590 |
671 /* Check if the visualisation is already in a bin */ |
680 /* Check if the visualisation is already in a bin */ |
672 if (GST_IS_BIN (vis_bin)) { |
681 if (GST_IS_BIN (vis_bin)) { |
673 GstPad *vis_sink_pad = NULL, *tee_pad = NULL; |
682 GstPad *vis_sink_pad = NULL, *tee_pad = NULL; |
674 |
683 |
675 /* Now get tee pad and block it async */ |
684 /* Now get tee pad and block it async */ |
676 vis_sink_pad = gst_element_get_static_pad (play_bin->visualisation, |
685 vis_sink_pad = gst_element_get_pad (play_bin->visualisation, |
677 "sink"); |
686 "sink"); |
678 if (!GST_IS_PAD (vis_sink_pad)) { |
687 if (!GST_IS_PAD (vis_sink_pad)) { |
679 goto beach; |
688 goto beach; |
680 } |
689 } |
681 tee_pad = gst_pad_get_peer (vis_sink_pad); |
690 tee_pad = gst_pad_get_peer (vis_sink_pad); |
770 /* applications need to know the buffer caps, |
779 /* applications need to know the buffer caps, |
771 * make sure they are always set on the frame */ |
780 * make sure they are always set on the frame */ |
772 if (GST_BUFFER_CAPS (frame) == NULL) { |
781 if (GST_BUFFER_CAPS (frame) == NULL) { |
773 GstPad *pad; |
782 GstPad *pad; |
774 |
783 |
775 if ((pad = gst_element_get_static_pad (identity, "sink"))) { |
784 if ((pad = gst_element_get_pad (identity, "sink"))) { |
776 gst_buffer_set_caps (frame, GST_PAD_CAPS (pad)); |
785 gst_buffer_set_caps (frame, GST_PAD_CAPS (pad)); |
777 gst_object_unref (pad); |
786 gst_object_unref (pad); |
778 } |
787 } |
779 } |
788 } |
780 |
789 |
859 /* be more careful with the pad from the custom sink element, it might not |
868 /* be more careful with the pad from the custom sink element, it might not |
860 * be named 'sink' */ |
869 * be named 'sink' */ |
861 if (!gst_element_link_pads (scale, "src", sink, NULL)) |
870 if (!gst_element_link_pads (scale, "src", sink, NULL)) |
862 goto link_failed; |
871 goto link_failed; |
863 |
872 |
864 pad = gst_element_get_static_pad (identity, "sink"); |
873 pad = gst_element_get_pad (identity, "sink"); |
865 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
874 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
866 gst_object_unref (pad); |
875 gst_object_unref (pad); |
867 |
876 |
868 gst_element_set_state (element, GST_STATE_READY); |
877 gst_element_set_state (element, GST_STATE_READY); |
869 |
878 |
915 * |
924 * |
916 * +--------------------------------------------------+ |
925 * +--------------------------------------------------+ |
917 * | tbin +-------------+ | |
926 * | tbin +-------------+ | |
918 * | +-----+ | textoverlay | +------+ | |
927 * | +-----+ | textoverlay | +------+ | |
919 * | | csp | +--video_sink | | vbin | | |
928 * | | csp | +--video_sink | | vbin | | |
920 * video_sink-sink src+ +-text_sink src---sink | | |
929 * video_sink-sink src+ +-text_sink src-sink | | |
921 * | +-----+ | +-------------+ +------+ | |
930 * | +-----+ | +-------------+ +------+ | |
922 * text_sink-------------+ | |
931 * text_sink-------------+ | |
923 * +--------------------------------------------------+ |
932 * +--------------------------------------------------+ |
924 * |
933 * |
925 * If there is no subtitle renderer this function will simply return the |
934 * If there is no subtitle renderer this function will simply return the |
926 * videosink without the text_sink pad. |
935 * videosink without the text_sink pad. |
927 */ |
936 */ |
928 static GstElement * |
937 static GstElement * |
929 add_text_element (GstPlayBin * play_bin, GstElement * vbin) |
938 gen_text_element (GstPlayBin * play_bin) |
930 { |
939 { |
931 GstElement *element, *csp, *overlay; |
940 GstElement *element, *csp, *overlay, *vbin; |
932 GstPad *pad; |
941 GstPad *pad; |
942 |
|
943 /* Create the video rendering bin, error is posted when this fails. */ |
|
944 vbin = gen_video_element (play_bin); |
|
945 if (!vbin) |
|
946 return NULL; |
|
933 |
947 |
934 /* Text overlay */ |
948 /* Text overlay */ |
935 overlay = gst_element_factory_make ("textoverlay", "overlay"); |
949 overlay = gst_element_factory_make ("textoverlay", "overlay"); |
936 |
950 |
937 /* If no overlay return the video bin without subtitle support. */ |
951 /* If no overlay return the video bin without subtitle support. */ |
960 /* Link */ |
974 /* Link */ |
961 gst_element_link_pads (csp, "src", overlay, "video_sink"); |
975 gst_element_link_pads (csp, "src", overlay, "video_sink"); |
962 gst_element_link_pads (overlay, "src", vbin, "sink"); |
976 gst_element_link_pads (overlay, "src", vbin, "sink"); |
963 |
977 |
964 /* Add ghost pads on the subtitle bin */ |
978 /* Add ghost pads on the subtitle bin */ |
965 pad = gst_element_get_static_pad (overlay, "text_sink"); |
979 pad = gst_element_get_pad (overlay, "text_sink"); |
966 gst_element_add_pad (element, gst_ghost_pad_new ("text_sink", pad)); |
980 gst_element_add_pad (element, gst_ghost_pad_new ("text_sink", pad)); |
967 gst_object_unref (pad); |
981 gst_object_unref (pad); |
968 |
982 |
969 pad = gst_element_get_static_pad (csp, "sink"); |
983 pad = gst_element_get_pad (csp, "sink"); |
970 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
984 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
971 gst_object_unref (pad); |
985 gst_object_unref (pad); |
972 |
|
973 /* If the vbin provides a subpicture sink pad, ghost it too */ |
|
974 pad = gst_element_get_static_pad (vbin, "subpicture_sink"); |
|
975 if (pad) { |
|
976 gst_element_add_pad (element, gst_ghost_pad_new ("subpicture_sink", pad)); |
|
977 gst_object_unref (pad); |
|
978 } |
|
979 |
986 |
980 /* Set state to READY */ |
987 /* Set state to READY */ |
981 gst_element_set_state (element, GST_STATE_READY); |
988 gst_element_set_state (element, GST_STATE_READY); |
982 |
989 |
983 return element; |
990 return element; |
986 no_overlay: |
993 no_overlay: |
987 { |
994 { |
988 post_missing_element_message (play_bin, "textoverlay"); |
995 post_missing_element_message (play_bin, "textoverlay"); |
989 GST_WARNING_OBJECT (play_bin, |
996 GST_WARNING_OBJECT (play_bin, |
990 "No overlay (pango) element, subtitles disabled"); |
997 "No overlay (pango) element, subtitles disabled"); |
991 return vbin; |
|
992 } |
|
993 } |
|
994 |
|
995 /* make an element for rendering DVD subpictures onto output video |
|
996 * |
|
997 * +---------------------------------------------+ |
|
998 * | tbin +--------+ | |
|
999 * | +-----+ | | +------+ | |
|
1000 * | | csp | src-videosink | | vbin | | |
|
1001 * video_sink-sink src+ | src-sink | | |
|
1002 * | +-----+ +subpicture | +------+ | |
|
1003 * subpicture_pad--------+ +--------+ | |
|
1004 * +---------- ----------------------------------+ |
|
1005 * |
|
1006 */ |
|
1007 static GstElement * |
|
1008 add_spu_element (GstPlayBin * play_bin, GstElement * vbin) |
|
1009 { |
|
1010 GstElement *element, *csp, *overlay; |
|
1011 GstPad *pad; |
|
1012 |
|
1013 /* DVD spu overlay */ |
|
1014 GST_DEBUG_OBJECT (play_bin, "Attempting to insert DVD SPU element"); |
|
1015 |
|
1016 overlay = gst_element_factory_make ("dvdspu", "overlay"); |
|
1017 |
|
1018 /* If no overlay return the video bin without subpicture support. */ |
|
1019 if (!overlay) |
|
1020 goto no_overlay; |
|
1021 |
|
1022 /* Create our bin */ |
|
1023 element = gst_bin_new ("spubin"); |
|
1024 |
|
1025 /* Take a ref */ |
|
1026 play_bin->spu_element = GST_ELEMENT_CAST (gst_object_ref (overlay)); |
|
1027 |
|
1028 /* we know this will succeed, as the video bin already created one before */ |
|
1029 csp = gst_element_factory_make ("ffmpegcolorspace", "spucsp"); |
|
1030 |
|
1031 /* Add our elements */ |
|
1032 gst_bin_add_many (GST_BIN_CAST (element), csp, overlay, vbin, NULL); |
|
1033 |
|
1034 /* Link */ |
|
1035 gst_element_link_pads (csp, "src", overlay, "video"); |
|
1036 gst_element_link_pads (overlay, "src", vbin, "sink"); |
|
1037 |
|
1038 /* Add ghost pad on the subpicture bin so it looks like vbin */ |
|
1039 pad = gst_element_get_static_pad (csp, "sink"); |
|
1040 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
|
1041 gst_object_unref (pad); |
|
1042 |
|
1043 pad = gst_element_get_static_pad (overlay, "subpicture"); |
|
1044 gst_element_add_pad (element, gst_ghost_pad_new ("subpicture_sink", pad)); |
|
1045 gst_object_unref (pad); |
|
1046 |
|
1047 /* Set state to READY */ |
|
1048 gst_element_set_state (element, GST_STATE_READY); |
|
1049 |
|
1050 return element; |
|
1051 |
|
1052 /* ERRORS */ |
|
1053 no_overlay: |
|
1054 { |
|
1055 post_missing_element_message (play_bin, "dvdspu"); |
|
1056 GST_WARNING_OBJECT (play_bin, |
|
1057 "No DVD overlay (dvdspu) element. " |
|
1058 "menu highlight/subtitles unavailable"); |
|
1059 return vbin; |
998 return vbin; |
1060 } |
999 } |
1061 } |
1000 } |
1062 |
1001 |
1063 /* make the element (bin) that contains the elements needed to perform |
1002 /* make the element (bin) that contains the elements needed to perform |
1117 |
1056 |
1118 scale = gst_element_factory_make ("audioresample", "aresample"); |
1057 scale = gst_element_factory_make ("audioresample", "aresample"); |
1119 if (scale == NULL) |
1058 if (scale == NULL) |
1120 goto no_audioresample; |
1059 goto no_audioresample; |
1121 gst_bin_add (GST_BIN_CAST (element), scale); |
1060 gst_bin_add (GST_BIN_CAST (element), scale); |
1122 |
1061 #ifndef __SYMBIAN32__ |
1123 volume = gst_element_factory_make ("volume", "volume"); |
1062 volume = gst_element_factory_make ("volume", "volume"); |
1124 if (volume == NULL) |
1063 if (volume == NULL) |
1125 goto no_volume; |
1064 goto no_volume; |
1126 g_object_set (G_OBJECT (volume), "volume", play_bin->volume, NULL); |
1065 g_object_set (G_OBJECT (volume), "volume", play_bin->volume, NULL); |
1127 play_bin->volume_element = volume; |
1066 play_bin->volume_element = volume; |
1128 gst_bin_add (GST_BIN_CAST (element), volume); |
1067 gst_bin_add (GST_BIN_CAST (element), volume); |
1068 #endif |
|
1129 |
1069 |
1130 res = gst_element_link_pads (conv, "src", scale, "sink"); |
1070 res = gst_element_link_pads (conv, "src", scale, "sink"); |
1071 #ifndef __SYMBIAN32__ |
|
1131 res &= gst_element_link_pads (scale, "src", volume, "sink"); |
1072 res &= gst_element_link_pads (scale, "src", volume, "sink"); |
1073 #else |
|
1074 res &= gst_element_link_pads (scale, "src", sink, NULL); |
|
1075 #endif |
|
1076 #ifndef __SYMBIAN32__ |
|
1132 res &= gst_element_link_pads (volume, "src", sink, NULL); |
1077 res &= gst_element_link_pads (volume, "src", sink, NULL); |
1078 #endif |
|
1133 if (!res) |
1079 if (!res) |
1134 goto link_failed; |
1080 goto link_failed; |
1135 |
1081 |
1136 pad = gst_element_get_static_pad (conv, "sink"); |
1082 pad = gst_element_get_pad (conv, "sink"); |
1137 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
1083 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
1138 gst_object_unref (pad); |
1084 gst_object_unref (pad); |
1139 |
1085 |
1140 gst_element_set_state (element, GST_STATE_READY); |
1086 gst_element_set_state (element, GST_STATE_READY); |
1141 |
1087 |
1281 res &= gst_element_link_pads (conv2, "src", vis, "sink"); |
1227 res &= gst_element_link_pads (conv2, "src", vis, "sink"); |
1282 res &= gst_element_link_pads (vis, "src", vsink, "sink"); |
1228 res &= gst_element_link_pads (vis, "src", vsink, "sink"); |
1283 if (!res) |
1229 if (!res) |
1284 goto link_failed; |
1230 goto link_failed; |
1285 |
1231 |
1286 pad = gst_element_get_static_pad (aqueue, "sink"); |
1232 pad = gst_element_get_pad (aqueue, "sink"); |
1287 rpad = gst_element_get_request_pad (tee, "src%d"); |
1233 rpad = gst_element_get_request_pad (tee, "src%d"); |
1288 gst_pad_link (rpad, pad); |
1234 gst_pad_link (rpad, pad); |
1289 gst_object_unref (rpad); |
1235 gst_object_unref (rpad); |
1290 gst_object_unref (pad); |
1236 gst_object_unref (pad); |
1291 gst_element_link_pads (aqueue, "src", asink, "sink"); |
1237 gst_element_link_pads (aqueue, "src", asink, "sink"); |
1292 |
1238 |
1293 pad = gst_element_get_static_pad (vqueue, "sink"); |
1239 pad = gst_element_get_pad (vqueue, "sink"); |
1294 rpad = gst_element_get_request_pad (tee, "src%d"); |
1240 rpad = gst_element_get_request_pad (tee, "src%d"); |
1295 gst_pad_link (rpad, pad); |
1241 gst_pad_link (rpad, pad); |
1296 gst_object_unref (rpad); |
1242 gst_object_unref (rpad); |
1297 gst_object_unref (pad); |
1243 gst_object_unref (pad); |
1298 |
1244 |
1299 pad = gst_element_get_static_pad (tee, "sink"); |
1245 pad = gst_element_get_pad (tee, "sink"); |
1300 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
1246 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
1301 gst_object_unref (pad); |
1247 gst_object_unref (pad); |
1302 |
1248 |
1303 return element; |
1249 return element; |
1304 |
1250 |
1362 play_bin->sinks = g_list_remove (play_bin->sinks, element); |
1308 play_bin->sinks = g_list_remove (play_bin->sinks, element); |
1363 gst_element_set_state (element, GST_STATE_NULL); |
1309 gst_element_set_state (element, GST_STATE_NULL); |
1364 gst_bin_remove (GST_BIN_CAST (parent), element); |
1310 gst_bin_remove (GST_BIN_CAST (parent), element); |
1365 gst_object_unref (parent); |
1311 gst_object_unref (parent); |
1366 } |
1312 } |
1367 pad = gst_element_get_static_pad (element, "sink"); |
1313 pad = gst_element_get_pad (element, "sink"); |
1368 if (pad != NULL) { |
1314 if (pad != NULL) { |
1369 peer = gst_pad_get_peer (pad); |
1315 peer = gst_pad_get_peer (pad); |
1370 if (peer != NULL) { |
1316 if (peer != NULL) { |
1371 gst_pad_unlink (peer, pad); |
1317 gst_pad_unlink (peer, pad); |
1372 gst_object_unref (peer); |
1318 gst_object_unref (peer); |
1381 play_bin->sinks = g_list_remove (play_bin->sinks, element); |
1327 play_bin->sinks = g_list_remove (play_bin->sinks, element); |
1382 gst_element_set_state (element, GST_STATE_NULL); |
1328 gst_element_set_state (element, GST_STATE_NULL); |
1383 gst_bin_remove (GST_BIN_CAST (parent), element); |
1329 gst_bin_remove (GST_BIN_CAST (parent), element); |
1384 gst_object_unref (parent); |
1330 gst_object_unref (parent); |
1385 } |
1331 } |
1386 pad = gst_element_get_static_pad (element, "sink"); |
1332 pad = gst_element_get_pad (element, "sink"); |
1387 if (pad != NULL) { |
1333 if (pad != NULL) { |
1388 peer = gst_pad_get_peer (pad); |
1334 peer = gst_pad_get_peer (pad); |
1389 if (peer != NULL) { |
1335 if (peer != NULL) { |
1390 gst_pad_unlink (peer, pad); |
1336 gst_pad_unlink (peer, pad); |
1391 gst_object_unref (peer); |
1337 gst_object_unref (peer); |
1397 for (sinks = play_bin->sinks; sinks; sinks = g_list_next (sinks)) { |
1343 for (sinks = play_bin->sinks; sinks; sinks = g_list_next (sinks)) { |
1398 GstElement *element = GST_ELEMENT_CAST (sinks->data); |
1344 GstElement *element = GST_ELEMENT_CAST (sinks->data); |
1399 GstPad *pad; |
1345 GstPad *pad; |
1400 GstPad *peer; |
1346 GstPad *peer; |
1401 |
1347 |
1402 pad = gst_element_get_static_pad (element, "sink"); |
1348 pad = gst_element_get_pad (element, "sink"); |
1403 |
1349 |
1404 GST_LOG ("removing sink %p", element); |
1350 GST_LOG ("removing sink %p", element); |
1405 |
1351 |
1406 peer = gst_pad_get_peer (pad); |
1352 peer = gst_pad_get_peer (pad); |
1407 if (peer) { |
1353 if (peer) { |
1481 stateret = gst_element_set_state (sink, state); |
1427 stateret = gst_element_set_state (sink, state); |
1482 if (stateret == GST_STATE_CHANGE_FAILURE) |
1428 if (stateret == GST_STATE_CHANGE_FAILURE) |
1483 goto state_failed; |
1429 goto state_failed; |
1484 |
1430 |
1485 /* we found a sink for this stream, now try to install it */ |
1431 /* we found a sink for this stream, now try to install it */ |
1486 sinkpad = gst_element_get_static_pad (sink, "sink"); |
1432 sinkpad = gst_element_get_pad (sink, "sink"); |
1487 linkres = gst_pad_link (srcpad, sinkpad); |
1433 linkres = gst_pad_link (srcpad, sinkpad); |
1488 gst_object_unref (sinkpad); |
1434 gst_object_unref (sinkpad); |
1489 |
1435 |
1490 /* try to link the pad of the sink to the stream */ |
1436 /* try to link the pad of the sink to the stream */ |
1491 if (GST_PAD_LINK_FAILED (linkres)) |
1437 if (GST_PAD_LINK_FAILED (linkres)) |
1492 goto link_failed; |
1438 goto link_failed; |
1493 |
1439 |
1494 if (GST_IS_PAD (subtitle_pad)) { |
1440 if (GST_IS_PAD (subtitle_pad)) { |
1495 sinkpad = gst_element_get_static_pad (sink, "text_sink"); |
1441 sinkpad = gst_element_get_pad (sink, "text_sink"); |
1496 linkres = gst_pad_link (subtitle_pad, sinkpad); |
1442 linkres = gst_pad_link (subtitle_pad, sinkpad); |
1497 gst_object_unref (sinkpad); |
1443 gst_object_unref (sinkpad); |
1498 } |
1444 } |
1499 |
1445 |
1500 /* try to link the subtitle pad of the sink to the stream, this is not |
1446 /* try to link the subtitle pad of the sink to the stream, this is not |
1557 |
1503 |
1558 static gboolean |
1504 static gboolean |
1559 setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group) |
1505 setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group) |
1560 { |
1506 { |
1561 GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin); |
1507 GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin); |
1562 gboolean have_video = FALSE; |
1508 GList *streaminfo = NULL, *s; |
1563 gboolean need_vis = FALSE; |
1509 gboolean need_vis = FALSE; |
1564 gboolean need_text = FALSE; |
1510 gboolean need_text = FALSE; |
1565 gboolean need_spu = FALSE; |
|
1566 GstPad *textsrcpad = NULL, *pad = NULL, *origtextsrcpad = NULL; |
1511 GstPad *textsrcpad = NULL, *pad = NULL, *origtextsrcpad = NULL; |
1567 GstElement *sink; |
1512 GstElement *sink; |
1568 gboolean res = TRUE; |
1513 gboolean res = TRUE; |
1569 |
1514 |
1570 /* get rid of existing sinks */ |
1515 /* get rid of existing sinks */ |
1572 remove_sinks (play_bin); |
1517 remove_sinks (play_bin); |
1573 } |
1518 } |
1574 GST_DEBUG_OBJECT (play_base_bin, "setupsinks"); |
1519 GST_DEBUG_OBJECT (play_base_bin, "setupsinks"); |
1575 |
1520 |
1576 /* find out what to do */ |
1521 /* find out what to do */ |
1577 have_video = (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0); |
1522 if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0 && |
1578 need_spu = (group->type[GST_STREAM_TYPE_SUBPICTURE - 1].npads != 0); |
1523 group->type[GST_STREAM_TYPE_TEXT - 1].npads > 0) { |
1579 |
|
1580 if (have_video && group->type[GST_STREAM_TYPE_TEXT - 1].npads > 0) { |
|
1581 need_text = TRUE; |
1524 need_text = TRUE; |
1582 } else if (!have_video && |
1525 } else if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads == 0 && |
1583 group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0 && |
1526 group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0 && |
1584 play_bin->visualisation != NULL) { |
1527 play_bin->visualisation != NULL) { |
1585 need_vis = TRUE; |
1528 need_vis = TRUE; |
1586 } |
1529 } |
1587 |
1530 |
1588 /* now actually connect everything */ |
1531 /* now actually connect everything */ |
1532 g_object_get (G_OBJECT (play_base_bin), "stream-info", &streaminfo, NULL); |
|
1533 for (s = streaminfo; s; s = g_list_next (s)) { |
|
1534 GObject *obj = G_OBJECT (s->data); |
|
1535 gint type; |
|
1536 GstObject *object; |
|
1537 |
|
1538 g_object_get (obj, "type", &type, NULL); |
|
1539 g_object_get (obj, "object", &object, NULL); |
|
1540 } |
|
1589 |
1541 |
1590 /* link audio */ |
1542 /* link audio */ |
1591 if (group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0) { |
1543 if (group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0) { |
1592 if (need_vis) { |
1544 if (need_vis) { |
1593 sink = gen_vis_element (play_bin); |
1545 sink = gen_vis_element (play_bin); |
1595 sink = gen_audio_element (play_bin); |
1547 sink = gen_audio_element (play_bin); |
1596 } |
1548 } |
1597 if (!sink) |
1549 if (!sink) |
1598 return FALSE; |
1550 return FALSE; |
1599 |
1551 |
1600 pad = |
1552 pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_AUDIO - 1].preroll, |
1601 gst_element_get_static_pad (group->type[GST_STREAM_TYPE_AUDIO - |
1553 "src"); |
1602 1].preroll, "src"); |
|
1603 res = add_sink (play_bin, sink, pad, NULL); |
1554 res = add_sink (play_bin, sink, pad, NULL); |
1604 gst_object_unref (pad); |
1555 gst_object_unref (pad); |
1605 } |
1556 } |
1606 |
1557 |
1607 /* link video */ |
1558 /* link video */ |
1608 if (have_video) { |
1559 if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0) { |
1609 /* Create the video rendering bin, error is posted when this fails. */ |
|
1610 sink = gen_video_element (play_bin); |
|
1611 if (!sink) |
|
1612 return FALSE; |
|
1613 if (need_spu) { |
|
1614 sink = add_spu_element (play_bin, sink); |
|
1615 } |
|
1616 |
|
1617 if (need_text) { |
1560 if (need_text) { |
1618 GstObject *parent = NULL, *grandparent = NULL; |
1561 GstObject *parent = NULL, *grandparent = NULL; |
1619 GstPad *ghost = NULL; |
1562 GstPad *ghost = NULL; |
1620 |
1563 |
1621 /* Add the subtitle overlay element into the video sink */ |
1564 sink = gen_text_element (play_bin); |
1622 sink = add_text_element (play_bin, sink); |
|
1623 |
|
1624 /* Link the incoming subtitle stream into the output bin */ |
|
1625 textsrcpad = |
1565 textsrcpad = |
1626 gst_element_get_static_pad (group->type[GST_STREAM_TYPE_TEXT - |
1566 gst_element_get_pad (group->type[GST_STREAM_TYPE_TEXT - 1].preroll, |
1627 1].preroll, "src"); |
1567 "src"); |
1628 |
1568 |
1629 /* This pad is from subtitle-bin, we need to create a ghost pad to have |
1569 /* This pad is from subtitle-bin, we need to create a ghost pad to have |
1630 common grandparents */ |
1570 common grandparents */ |
1631 parent = gst_object_get_parent (GST_OBJECT_CAST (textsrcpad)); |
1571 parent = gst_object_get_parent (GST_OBJECT_CAST (textsrcpad)); |
1632 if (!parent) { |
1572 if (!parent) { |
1682 "no changes to hierarchy needed"); |
1622 "no changes to hierarchy needed"); |
1683 } |
1623 } |
1684 |
1624 |
1685 gst_object_unref (parent); |
1625 gst_object_unref (parent); |
1686 gst_object_unref (grandparent); |
1626 gst_object_unref (grandparent); |
1627 } else { |
|
1628 sink = gen_video_element (play_bin); |
|
1687 } |
1629 } |
1688 beach: |
1630 beach: |
1689 if (!sink) |
1631 if (!sink) |
1690 return FALSE; |
1632 return FALSE; |
1691 pad = |
1633 pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_VIDEO - 1].preroll, |
1692 gst_element_get_static_pad (group->type[GST_STREAM_TYPE_VIDEO - |
1634 "src"); |
1693 1].preroll, "src"); |
|
1694 res = add_sink (play_bin, sink, pad, textsrcpad); |
1635 res = add_sink (play_bin, sink, pad, textsrcpad); |
1695 gst_object_unref (pad); |
1636 gst_object_unref (pad); |
1696 if (textsrcpad) |
1637 if (textsrcpad) |
1697 gst_object_unref (textsrcpad); |
1638 gst_object_unref (textsrcpad); |
1698 if (origtextsrcpad) { |
1639 if (origtextsrcpad) { |
1699 gst_pad_set_blocked_async (origtextsrcpad, FALSE, dummy_blocked_cb, NULL); |
1640 gst_pad_set_blocked_async (origtextsrcpad, FALSE, dummy_blocked_cb, NULL); |
1700 gst_object_unref (origtextsrcpad); |
1641 gst_object_unref (origtextsrcpad); |
1701 } |
1642 } |
1702 |
|
1703 /* If we have a DVD subpicture stream, link it to the SPU now */ |
|
1704 if (need_spu) { |
|
1705 GstPad *subpic_pad; |
|
1706 GstPad *spu_sink_pad; |
|
1707 |
|
1708 subpic_pad = |
|
1709 gst_element_get_static_pad (group->type[GST_STREAM_TYPE_SUBPICTURE |
|
1710 - 1].preroll, "src"); |
|
1711 spu_sink_pad = gst_element_get_static_pad (sink, "subpicture_sink"); |
|
1712 if (subpic_pad && spu_sink_pad) { |
|
1713 GST_LOG_OBJECT (play_bin, "Linking DVD subpicture stream onto SPU"); |
|
1714 gst_pad_set_blocked_async (subpic_pad, TRUE, dummy_blocked_cb, NULL); |
|
1715 if (gst_pad_link (subpic_pad, spu_sink_pad) != GST_PAD_LINK_OK) { |
|
1716 GST_WARNING_OBJECT (play_bin, |
|
1717 "Failed to link DVD subpicture stream onto SPU"); |
|
1718 } |
|
1719 gst_pad_set_blocked_async (subpic_pad, FALSE, dummy_blocked_cb, NULL); |
|
1720 } |
|
1721 if (subpic_pad) |
|
1722 gst_object_unref (subpic_pad); |
|
1723 if (spu_sink_pad) |
|
1724 gst_object_unref (spu_sink_pad); |
|
1725 } |
|
1726 } |
1643 } |
1727 |
1644 |
1728 /* remove the sinks now, pipeline get_state will now wait for the |
1645 /* remove the sinks now, pipeline get_state will now wait for the |
1729 * sinks to preroll */ |
1646 * sinks to preroll */ |
1730 if (play_bin->fakesink) { |
1647 if (play_bin->fakesink) { |
1745 * before textoverlay is set up (which is probably okay, since playbasebin |
1662 * before textoverlay is set up (which is probably okay, since playbasebin |
1746 * will just select the first subtitle stream as active stream regardless) */ |
1663 * will just select the first subtitle stream as active stream regardless) */ |
1747 if (playbin->textoverlay_element != NULL) { |
1664 if (playbin->textoverlay_element != NULL) { |
1748 GST_LOG_OBJECT (playbin, "setting subtitle visibility to %d", visible); |
1665 GST_LOG_OBJECT (playbin, "setting subtitle visibility to %d", visible); |
1749 g_object_set (playbin->textoverlay_element, "silent", !visible, NULL); |
1666 g_object_set (playbin->textoverlay_element, "silent", !visible, NULL); |
1750 } |
|
1751 } |
|
1752 |
|
1753 static void |
|
1754 playbin_set_audio_mute (GstPlayBaseBin * play_base_bin, gboolean mute) |
|
1755 { |
|
1756 GstPlayBin *playbin = GST_PLAY_BIN (play_base_bin); |
|
1757 |
|
1758 if (playbin->volume_element) { |
|
1759 g_object_set (G_OBJECT (playbin->volume_element), "mute", mute, NULL); |
|
1760 } |
1667 } |
1761 } |
1668 } |
1762 |
1669 |
1763 /* Send an event to our sinks until one of them works; don't then send to the |
1670 /* Send an event to our sinks until one of them works; don't then send to the |
1764 * remaining sinks (unlike GstBin) |
1671 * remaining sinks (unlike GstBin) |