49 * </listitem> |
51 * </listitem> |
50 * <listitem> |
52 * <listitem> |
51 * buffering when playing streams over a network |
53 * buffering when playing streams over a network |
52 * </listitem> |
54 * </listitem> |
53 * <listitem> |
55 * <listitem> |
54 * volume control |
56 * volume control with mute option |
55 * </listitem> |
57 * </listitem> |
56 * </itemizedlist> |
58 * </itemizedlist> |
57 * </para> |
59 * |
|
60 * <refsect2> |
58 * <title>Usage</title> |
61 * <title>Usage</title> |
59 * <para> |
62 * <para> |
60 * A playbin element can be created just like any other element using |
63 * A playbin element can be created just like any other element using |
61 * gst_element_factory_make(). The file/URI to play should be set via the "uri" |
64 * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin2:uri |
62 * property. This must be an absolute URI, relative file paths are not allowed. |
65 * property. This must be an absolute URI, relative file paths are not allowed. |
63 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg |
66 * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg |
64 * </para> |
67 * |
65 * <para> |
|
66 * Playbin is a #GstPipeline. It will notify the application of everything |
68 * Playbin is a #GstPipeline. It will notify the application of everything |
67 * that's happening (errors, end of stream, tags found, state changes, etc.) |
69 * that's happening (errors, end of stream, tags found, state changes, etc.) |
68 * by posting messages on its #GstBus. The application needs to watch the |
70 * by posting messages on its #GstBus. The application needs to watch the |
69 * bus. |
71 * bus. |
70 * </para> |
72 * |
71 * <para> |
|
72 * Playback can be initiated by setting the element to PLAYING state using |
73 * Playback can be initiated by setting the element to PLAYING state using |
73 * gst_element_set_state(). Note that the state change will take place in |
74 * gst_element_set_state(). Note that the state change will take place in |
74 * the background in a separate thread, when the function returns playback |
75 * the background in a separate thread, when the function returns playback |
75 * is probably not happening yet and any errors might not have occured yet. |
76 * is probably not happening yet and any errors might not have occured yet. |
76 * Applications using playbin should ideally be written to deal with things |
77 * Applications using playbin should ideally be written to deal with things |
77 * completely asynchroneous. |
78 * completely asynchroneous. |
78 * </para> |
79 * |
79 * <para> |
|
80 * 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) |
81 * 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 |
82 * 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 |
83 * READY or NULL state, then the "uri" property should be set to the new |
83 * READY or NULL state, then the #GstPlayBin2:uri property should be set to the |
84 * location and then playbin be set to PLAYING state again. |
84 * new location and then playbin be set to PLAYING state again. |
85 * </para> |
85 * |
86 * <para> |
|
87 * Seeking can be done using gst_element_seek_simple() or gst_element_seek() |
86 * Seeking can be done using gst_element_seek_simple() or gst_element_seek() |
88 * on the playbin element. Again, the seek will not be executed |
87 * on the playbin element. Again, the seek will not be executed |
89 * instantaneously, but will be done in a background thread. When the seek |
88 * instantaneously, but will be done in a background thread. When the seek |
90 * call returns the seek will most likely still be in process. An application |
89 * call returns the seek will most likely still be in process. An application |
91 * may wait for the seek to finish (or fail) using gst_element_get_state() with |
90 * may wait for the seek to finish (or fail) using gst_element_get_state() with |
92 * -1 as the timeout, but this will block the user interface and is not |
91 * -1 as the timeout, but this will block the user interface and is not |
93 * recommended at all. |
92 * recommended at all. |
94 * </para> |
93 * |
95 * <para> |
|
96 * Applications may query the current position and duration of the stream |
94 * Applications may query the current position and duration of the stream |
97 * via gst_element_query_position() and gst_element_query_duration() and |
95 * via gst_element_query_position() and gst_element_query_duration() and |
98 * setting the format passed to GST_FORMAT_TIME. If the query was successful, |
96 * setting the format passed to GST_FORMAT_TIME. If the query was successful, |
99 * the duration or position will have been returned in units of nanoseconds. |
97 * the duration or position will have been returned in units of nanoseconds. |
100 * </para> |
98 * </para> |
|
99 * </refsect2> |
|
100 * <refsect2> |
101 * <title>Advanced Usage: specifying the audio and video sink</title> |
101 * <title>Advanced Usage: specifying the audio and video sink</title> |
102 * <para> |
102 * <para> |
103 * 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 |
104 * "audio-sink" or "video-sink" property, playbin will use the autoaudiosink |
104 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property, playbin will use the autoaudiosink |
105 * and autovideosink elements to find the first-best available output method. |
105 * and autovideosink elements to find the first-best available output method. |
106 * 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 |
107 * 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 |
108 * for audio and video output. |
108 * for audio and video output. |
109 * </para> |
109 * |
110 * <para> |
|
111 * If the application wants more control over how audio or video should be |
110 * If the application wants more control over how audio or video should be |
112 * output, it may create the audio/video sink elements itself (for example |
111 * output, it may create the audio/video sink elements itself (for example |
113 * using gst_element_factory_make()) and provide them to playbin using the |
112 * using gst_element_factory_make()) and provide them to playbin using the |
114 * "audio-sink" or "video-sink" property. |
113 * #GstPlayBin2:audio-sink or #GstPlayBin2:video-sink property. |
115 * </para> |
114 * |
116 * <para> |
|
117 * GNOME-based applications, for example, will usually want to create |
115 * GNOME-based applications, for example, will usually want to create |
118 * gconfaudiosink and gconfvideosink elements and make playbin use those, |
116 * gconfaudiosink and gconfvideosink elements and make playbin use those, |
119 * so that output happens to whatever the user has configured in the GNOME |
117 * so that output happens to whatever the user has configured in the GNOME |
120 * Multimedia System Selector confinguration dialog. |
118 * Multimedia System Selector configuration dialog. |
121 * </para> |
119 * |
122 * <para> |
|
123 * The sink elements do not necessarily need to be ready-made sinks. It is |
120 * The sink elements do not necessarily need to be ready-made sinks. It is |
124 * possible to create container elements that look like a sink to playbin, |
121 * possible to create container elements that look like a sink to playbin, |
125 * but in reality contain a number of custom elements linked together. This |
122 * but in reality contain a number of custom elements linked together. This |
126 * can be achieved by creating a #GstBin and putting elements in there and |
123 * can be achieved by creating a #GstBin and putting elements in there and |
127 * linking them, and then creating a sink #GstGhostPad for the bin and pointing |
124 * linking them, and then creating a sink #GstGhostPad for the bin and pointing |
128 * it to the sink pad of the first element within the bin. This can be used |
125 * it to the sink pad of the first element within the bin. This can be used |
129 * for a number of purposes, for example to force output to a particular |
126 * for a number of purposes, for example to force output to a particular |
130 * format or to modify or observe the data before it is output. |
127 * format or to modify or observe the data before it is output. |
131 * </para> |
128 * |
132 * <para> |
|
133 * It is also possible to 'suppress' audio and/or video output by using |
129 * It is also possible to 'suppress' audio and/or video output by using |
134 * 'fakesink' elements (or capture it from there using the fakesink element's |
130 * 'fakesink' elements (or capture it from there using the fakesink element's |
135 * "handoff" signal, which, nota bene, is fired from the streaming thread!). |
131 * "handoff" signal, which, nota bene, is fired from the streaming thread!). |
136 * </para> |
132 * </para> |
|
133 * </refsect2> |
|
134 * <refsect2> |
137 * <title>Retrieving Tags and Other Meta Data</title> |
135 * <title>Retrieving Tags and Other Meta Data</title> |
138 * <para> |
136 * <para> |
139 * Most of the common meta data (artist, title, etc.) can be retrieved by |
137 * Most of the common meta data (artist, title, etc.) can be retrieved by |
140 * watching for TAG messages on the pipeline's bus (see above). |
138 * watching for TAG messages on the pipeline's bus (see above). |
141 * </para> |
139 * |
142 * <para> |
|
143 * Other more specific meta information like width/height/framerate of video |
140 * Other more specific meta information like width/height/framerate of video |
144 * streams or samplerate/number of channels of audio streams can be obtained |
141 * streams or samplerate/number of channels of audio streams can be obtained |
145 * using the "stream-info" property, which will return a GList of stream info |
142 * from the negotiated caps on the sink pads of the sinks. |
146 * objects, one for each stream. These are opaque objects that can only be |
|
147 * accessed via the standard GObject property interface, ie. g_object_get(). |
|
148 * Each stream info object has the following properties: |
|
149 * <itemizedlist> |
|
150 * <listitem>"object" (GstObject) (the decoder source pad usually)</listitem> |
|
151 * <listitem>"type" (enum) (if this is an audio/video/subtitle stream)</listitem> |
|
152 * <listitem>"decoder" (string) (name of decoder used to decode this stream)</listitem> |
|
153 * <listitem>"mute" (boolean) (to mute or unmute this stream)</listitem> |
|
154 * <listitem>"caps" (GstCaps) (caps of the decoded stream)</listitem> |
|
155 * <listitem>"language-code" (string) (ISO-639 language code for this stream, mostly used for audio/subtitle streams)</listitem> |
|
156 * <listitem>"codec" (string) (format this stream was encoded in)</listitem> |
|
157 * </itemizedlist> |
|
158 * Stream information from the stream-info properties is best queried once |
|
159 * playbin has changed into PAUSED or PLAYING state (which can be detected |
|
160 * via a state-changed message on the bus where old_state=READY and |
|
161 * new_state=PAUSED), since before that the list might not be complete yet or |
|
162 * not contain all available information (like language-codes). |
|
163 * </para> |
143 * </para> |
|
144 * </refsect2> |
|
145 * <refsect2> |
164 * <title>Buffering</title> |
146 * <title>Buffering</title> |
165 * <para> |
|
166 * Playbin handles buffering automatically for the most part, but applications |
147 * Playbin handles buffering automatically for the most part, but applications |
167 * need to handle parts of the buffering process as well. Whenever playbin is |
148 * need to handle parts of the buffering process as well. Whenever playbin is |
168 * buffering, it will post BUFFERING messages on the bus with a percentage |
149 * buffering, it will post BUFFERING messages on the bus with a percentage |
169 * value that shows the progress of the buffering process. Applications need |
150 * value that shows the progress of the buffering process. Applications need |
170 * to set playbin to PLAYING or PAUSED state in response to these messages. |
151 * to set playbin to PLAYING or PAUSED state in response to these messages. |
171 * They may also want to convey the buffering progress to the user in some |
152 * They may also want to convey the buffering progress to the user in some |
172 * way. Here is how to extract the percentage information from the message |
153 * way. Here is how to extract the percentage information from the message |
173 * (requires GStreamer >= 0.10.11): |
154 * (requires GStreamer >= 0.10.11): |
174 * </para> |
155 * |[ |
175 * <para> |
|
176 * <programlisting> |
|
177 * switch (GST_MESSAGE_TYPE (msg)) { |
156 * switch (GST_MESSAGE_TYPE (msg)) { |
178 * case GST_MESSAGE_BUFFERING: { |
157 * case GST_MESSAGE_BUFFERING: { |
179 * gint percent = 0; |
158 * gint percent = 0; |
180 * gst_message_parse_buffering (msg, &percent); |
159 * gst_message_parse_buffering (msg, &percent); |
181 * g_print ("Buffering (%%u percent done)", percent); |
160 * g_print ("Buffering (%%u percent done)", percent); |
182 * break; |
161 * break; |
183 * } |
162 * } |
184 * ... |
163 * ... |
185 * } |
164 * } |
186 * </programlisting> |
165 * ]| |
187 * Note that applications should keep/set the pipeline in the PAUSED state when |
166 * Note that applications should keep/set the pipeline in the PAUSED state when |
188 * a BUFFERING message is received with a buffer percent value < 100 and set |
167 * a BUFFERING message is received with a buffer percent value < 100 and set |
189 * the pipeline back to PLAYING state when a BUFFERING message with a value |
168 * the pipeline back to PLAYING state when a BUFFERING message with a value |
190 * of 100 percent is received (if PLAYING is the desired state, that is). |
169 * of 100 percent is received (if PLAYING is the desired state, that is). |
191 * </para> |
170 * </refsect2> |
|
171 * <refsect2> |
192 * <title>Embedding the video window in your application</title> |
172 * <title>Embedding the video window in your application</title> |
193 * <para> |
|
194 * By default, playbin (or rather the video sinks used) will create their own |
173 * By default, playbin (or rather the video sinks used) will create their own |
195 * window. Applications will usually want to force output to a window of their |
174 * window. Applications will usually want to force output to a window of their |
196 * own, however. This can be done using the GstXOverlay interface, which most |
175 * own, however. This can be done using the #GstXOverlay interface, which most |
197 * video sinks implement. See the documentation there for more details. |
176 * video sinks implement. See the documentation there for more details. |
198 * </para> |
177 * </refsect2> |
|
178 * <refsect2> |
199 * <title>Specifying which CD/DVD device to use</title> |
179 * <title>Specifying which CD/DVD device to use</title> |
200 * <para> |
|
201 * The device to use for CDs/DVDs needs to be set on the source element |
180 * The device to use for CDs/DVDs needs to be set on the source element |
202 * playbin creates before it is opened. The only way to do this at the moment |
181 * playbin creates before it is opened. The only way to do this at the moment |
203 * is to connect to playbin's "notify::source" signal, which will be emitted |
182 * is to connect to playbin's "notify::source" signal, which will be emitted |
204 * by playbin when it has created the source element for a particular URI. |
183 * by playbin when it has created the source element for a particular URI. |
205 * In the signal callback you can check if the source element has a "device" |
184 * In the signal callback you can check if the source element has a "device" |
206 * property and set it appropriately. In future ways might be added to specify |
185 * property and set it appropriately. In future ways might be added to specify |
207 * the device as part of the URI, but at the time of writing this is not |
186 * the device as part of the URI, but at the time of writing this is not |
208 * possible yet. |
187 * possible yet. |
|
188 * </refsect2> |
|
189 * <refsect2> |
|
190 * <title>Handling redirects</title> |
|
191 * <para> |
|
192 * Some elements may post 'redirect' messages on the bus to tell the |
|
193 * application to open another location. These are element messages containing |
|
194 * a structure named 'redirect' along with a 'new-location' field of string |
|
195 * type. The new location may be a relative or an absolute URI. Examples |
|
196 * for such redirects can be found in many quicktime movie trailers. |
209 * </para> |
197 * </para> |
|
198 * </refsect2> |
|
199 * <refsect2> |
210 * <title>Examples</title> |
200 * <title>Examples</title> |
211 * <para> |
201 * |[ |
212 * Here is a simple pipeline to play back a video or audio file: |
|
213 * <programlisting> |
|
214 * gst-launch -v playbin uri=file:///path/to/somefile.avi |
202 * gst-launch -v playbin uri=file:///path/to/somefile.avi |
215 * </programlisting> |
203 * ]| This will play back the given AVI video file, given that the video and |
216 * This will play back the given AVI video file, given that the video and |
|
217 * audio decoders required to decode the content are installed. Since no |
204 * audio decoders required to decode the content are installed. Since no |
218 * special audio sink or video sink is supplied (not possible via gst-launch), |
205 * special audio sink or video sink is supplied (not possible via gst-launch), |
219 * playbin will try to find a suitable audio and video sink automatically |
206 * playbin will try to find a suitable audio and video sink automatically |
220 * using the autoaudiosink and autovideosink elements. |
207 * using the autoaudiosink and autovideosink elements. |
221 * </para> |
208 * |[ |
222 * <para> |
|
223 * Here is a another pipeline to play track 4 of an audio CD: |
|
224 * <programlisting> |
|
225 * gst-launch -v playbin uri=cdda://4 |
209 * gst-launch -v playbin uri=cdda://4 |
226 * </programlisting> |
210 * ]| This will play back track 4 on an audio CD in your disc drive (assuming |
227 * This will play back track 4 on an audio CD in your disc drive (assuming |
|
228 * the drive is detected automatically by the plugin). |
211 * the drive is detected automatically by the plugin). |
229 * </para> |
212 * |[ |
230 * <para> |
|
231 * Here is a another pipeline to play title 1 of a DVD: |
|
232 * <programlisting> |
|
233 * gst-launch -v playbin uri=dvd://1 |
213 * gst-launch -v playbin uri=dvd://1 |
234 * </programlisting> |
214 * ]| This will play back title 1 of a DVD in your disc drive (assuming |
235 * This will play back title 1 of a DVD in your disc drive (assuming |
|
236 * the drive is detected automatically by the plugin). |
215 * the drive is detected automatically by the plugin). |
237 * </para> |
|
238 * </refsect2> |
216 * </refsect2> |
239 */ |
217 */ |
240 |
218 |
241 #ifdef HAVE_CONFIG_H |
219 #ifdef HAVE_CONFIG_H |
242 #include "config.h" |
220 #include "config.h" |
276 typedef struct _GstSourceSelect GstSourceSelect; |
250 typedef struct _GstSourceSelect GstSourceSelect; |
277 |
251 |
278 /* has the info for a selector and provides the link to the sink */ |
252 /* has the info for a selector and provides the link to the sink */ |
279 struct _GstSourceSelect |
253 struct _GstSourceSelect |
280 { |
254 { |
281 const gchar *media; /* the media type of the selector */ |
255 const gchar *media_list[3]; /* the media types for the selector */ |
282 GstPlaySinkType type; /* the sink pad type of the selector */ |
256 GstPlaySinkType type; /* the sink pad type of the selector */ |
283 |
257 |
284 GstElement *selector; /* the selector */ |
258 GstElement *selector; /* the selector */ |
285 GPtrArray *channels; |
259 GPtrArray *channels; |
286 GstPad *srcpad; /* the source pad of the selector */ |
260 GstPad *srcpad; /* the source pad of the selector */ |
287 GstPad *sinkpad; /* the sinkpad of the sink when the selector is linked */ |
261 GstPad *sinkpad; /* the sinkpad of the sink when the selector is linked */ |
288 }; |
262 }; |
289 |
263 |
|
264 #define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock) |
|
265 #define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group))) |
|
266 #define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group))) |
|
267 |
290 /* a structure to hold the objects for decoding a uri and the subtitle uri |
268 /* a structure to hold the objects for decoding a uri and the subtitle uri |
291 */ |
269 */ |
292 struct _GstSourceGroup |
270 struct _GstSourceGroup |
293 { |
271 { |
294 GstPlayBin *playbin; |
272 GstPlayBin *playbin; |
|
273 |
|
274 GMutex *lock; |
295 |
275 |
296 gboolean valid; /* the group has valid info to start playback */ |
276 gboolean valid; /* the group has valid info to start playback */ |
297 gboolean active; /* the group is active */ |
277 gboolean active; /* the group is active */ |
298 |
278 |
299 /* properties */ |
279 /* properties */ |
300 gchar *uri; |
280 gchar *uri; |
301 gchar *suburi; |
281 gchar *suburi; |
302 GValueArray *streaminfo; |
282 GValueArray *streaminfo; |
303 GstElement *source; |
283 GstElement *source; |
304 gchar *subencoding; /* encoding to propagate to the subtitle elements */ |
|
305 |
284 |
306 GPtrArray *video_channels; /* links to selector pads */ |
285 GPtrArray *video_channels; /* links to selector pads */ |
307 GPtrArray *audio_channels; /* links to selector pads */ |
286 GPtrArray *audio_channels; /* links to selector pads */ |
308 GPtrArray *text_channels; /* links to selector pads */ |
287 GPtrArray *text_channels; /* links to selector pads */ |
|
288 GPtrArray *subp_channels; /* links to selector pads */ |
|
289 |
|
290 GstElement *audio_sink; /* autoplugged audio and video sinks */ |
|
291 GstElement *video_sink; |
309 |
292 |
310 /* uridecodebins for uri and subtitle uri */ |
293 /* uridecodebins for uri and subtitle uri */ |
311 GstElement *uridecodebin; |
294 GstElement *uridecodebin; |
312 GstElement *suburidecodebin; |
295 GstElement *suburidecodebin; |
|
296 gint pending; |
|
297 |
|
298 gulong pad_added_id; |
|
299 gulong pad_removed_id; |
|
300 gulong no_more_pads_id; |
|
301 gulong notify_source_id; |
|
302 gulong drained_id; |
|
303 gulong autoplug_factories_id; |
|
304 gulong autoplug_select_id; |
|
305 |
|
306 gulong sub_pad_added_id; |
|
307 gulong sub_pad_removed_id; |
|
308 gulong sub_no_more_pads_id; |
313 |
309 |
314 /* selectors for different streams */ |
310 /* selectors for different streams */ |
315 GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST]; |
311 GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST]; |
316 }; |
312 }; |
317 |
313 |
|
314 #define GST_PLAY_BIN_GET_LOCK(bin) (((GstPlayBin*)(bin))->lock) |
|
315 #define GST_PLAY_BIN_LOCK(bin) (g_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin))) |
|
316 #define GST_PLAY_BIN_UNLOCK(bin) (g_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin))) |
|
317 |
|
318 /* lock to protect dynamic callbacks, like no-more-pads */ |
|
319 #define GST_PLAY_BIN_DYN_LOCK(bin) g_mutex_lock ((bin)->dyn_lock) |
|
320 #define GST_PLAY_BIN_DYN_UNLOCK(bin) g_mutex_unlock ((bin)->dyn_lock) |
|
321 |
|
322 /* lock for shutdown */ |
|
323 #define GST_PLAY_BIN_SHUTDOWN_LOCK(bin,label) \ |
|
324 G_STMT_START { \ |
|
325 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \ |
|
326 goto label; \ |
|
327 GST_PLAY_BIN_DYN_LOCK (bin); \ |
|
328 if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \ |
|
329 GST_PLAY_BIN_DYN_UNLOCK (bin); \ |
|
330 goto label; \ |
|
331 } \ |
|
332 } G_STMT_END |
|
333 |
|
334 /* unlock for shutdown */ |
|
335 #define GST_PLAY_BIN_SHUTDOWN_UNLOCK(bin) \ |
|
336 GST_PLAY_BIN_DYN_UNLOCK (bin); \ |
|
337 |
|
338 /** |
|
339 * GstPlayBin2: |
|
340 * |
|
341 * playbin element structure |
|
342 */ |
318 struct _GstPlayBin |
343 struct _GstPlayBin |
319 { |
344 { |
320 GstPipeline parent; |
345 GstPipeline parent; |
|
346 |
|
347 GMutex *lock; /* to protect group switching */ |
321 |
348 |
322 /* the groups, we use a double buffer to switch between current and next */ |
349 /* the groups, we use a double buffer to switch between current and next */ |
323 GstSourceGroup groups[2]; /* array with group info */ |
350 GstSourceGroup groups[2]; /* array with group info */ |
324 GstSourceGroup *curr_group; /* pointer to the currently playing group */ |
351 GstSourceGroup *curr_group; /* pointer to the currently playing group */ |
325 GstSourceGroup *next_group; /* pointer to the next group */ |
352 GstSourceGroup *next_group; /* pointer to the next group */ |
326 |
|
327 gboolean about_to_finish; /* the about-to-finish signal is emited */ |
|
328 |
353 |
329 /* properties */ |
354 /* properties */ |
330 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */ |
355 guint connection_speed; /* connection speed in bits/sec (0 = unknown) */ |
331 gint current_video; /* the currently selected stream */ |
356 gint current_video; /* the currently selected stream */ |
332 gint current_audio; /* the currently selected stream */ |
357 gint current_audio; /* the currently selected stream */ |
333 gint current_text; /* the currently selected stream */ |
358 gint current_text; /* the currently selected stream */ |
|
359 gchar *encoding; /* subtitle encoding */ |
|
360 |
|
361 guint64 buffer_duration; /* When buffering, the max buffer duration (ns) */ |
|
362 guint buffer_size; /* When buffering, the max buffer size (bytes) */ |
334 |
363 |
335 /* our play sink */ |
364 /* our play sink */ |
336 GstPlaySink *playsink; |
365 GstPlaySink *playsink; |
337 |
366 |
|
367 /* the last activated source */ |
|
368 GstElement *source; |
|
369 |
|
370 /* lock protecting dynamic adding/removing */ |
|
371 GMutex *dyn_lock; |
|
372 /* if we are shutting down or not */ |
|
373 gint shutdown; |
|
374 |
338 GValueArray *elements; /* factories we can use for selecting elements */ |
375 GValueArray *elements; /* factories we can use for selecting elements */ |
|
376 |
|
377 gboolean have_selector; /* set to FALSE when we fail to create an |
|
378 * input-selector, so that we only post a |
|
379 * warning once */ |
|
380 |
|
381 GstElement *audio_sink; /* configured audio sink, or NULL */ |
|
382 GstElement *video_sink; /* configured video sink, or NULL */ |
|
383 GstElement *subpic_sink; /* configured subpicture sink, or NULL */ |
|
384 GstElement *text_sink; /* configured text sink, or NULL */ |
339 }; |
385 }; |
340 |
386 |
341 struct _GstPlayBinClass |
387 struct _GstPlayBinClass |
342 { |
388 { |
343 GstPipelineClass parent_class; |
389 GstPipelineClass parent_class; |
530 gobject_klass->get_property = gst_play_bin_get_property; |
606 gobject_klass->get_property = gst_play_bin_get_property; |
531 |
607 |
532 gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_bin_finalize); |
608 gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_bin_finalize); |
533 |
609 |
534 /** |
610 /** |
535 * GstPlayBin:uri |
611 * GstPlayBin2:uri |
536 * |
612 * |
537 * Set the next URI that playbin will play. This property can be set from the |
613 * Set the next URI that playbin will play. This property can be set from the |
538 * about-to-finish signal to queue the next media file. |
614 * about-to-finish signal to queue the next media file. |
539 */ |
615 */ |
540 g_object_class_install_property (gobject_klass, PROP_URI, |
616 g_object_class_install_property (gobject_klass, PROP_URI, |
541 g_param_spec_string ("uri", "URI", "URI of the media to play", |
617 g_param_spec_string ("uri", "URI", "URI of the media to play", |
542 NULL, G_PARAM_READWRITE)); |
618 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
543 |
619 |
544 /** |
620 /** |
545 * GstPlayBin:suburi |
621 * GstPlayBin2:suburi |
546 * |
622 * |
547 * Set the next subtitle URI that playbin will play. This property can be |
623 * Set the next subtitle URI that playbin will play. This property can be |
548 * set from the about-to-finish signal to queue the next subtitle media file. |
624 * set from the about-to-finish signal to queue the next subtitle media file. |
549 */ |
625 */ |
550 g_object_class_install_property (gobject_klass, PROP_SUBURI, |
626 g_object_class_install_property (gobject_klass, PROP_SUBURI, |
551 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle", |
627 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle", |
552 NULL, G_PARAM_READWRITE)); |
628 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
553 |
629 |
554 g_object_class_install_property (gobject_klass, PROP_SOURCE, |
630 g_object_class_install_property (gobject_klass, PROP_SOURCE, |
555 g_param_spec_object ("source", "Source", "Source element", |
631 g_param_spec_object ("source", "Source", "Source element", |
556 GST_TYPE_ELEMENT, G_PARAM_READABLE)); |
632 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
557 |
|
558 |
633 |
559 /** |
634 /** |
560 * GstPlayBin:flags |
635 * GstPlayBin2:flags |
561 * |
636 * |
562 * Control the behaviour of playbin. |
637 * Control the behaviour of playbin. |
563 */ |
638 */ |
564 g_object_class_install_property (gobject_klass, PROP_FLAGS, |
639 g_object_class_install_property (gobject_klass, PROP_FLAGS, |
565 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour", |
640 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour", |
566 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS, G_PARAM_READWRITE)); |
641 GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS, |
|
642 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
567 |
643 |
568 /** |
644 /** |
569 * GstPlayBin:n-video |
645 * GstPlayBin2:n-video |
570 * |
646 * |
571 * Get the total number of available video streams. |
647 * Get the total number of available video streams. |
572 */ |
648 */ |
573 g_object_class_install_property (gobject_klass, PROP_N_VIDEO, |
649 g_object_class_install_property (gobject_klass, PROP_N_VIDEO, |
574 g_param_spec_int ("n-video", "Number Video", |
650 g_param_spec_int ("n-video", "Number Video", |
575 "Total number of video streams", 0, G_MAXINT, 0, G_PARAM_READABLE)); |
651 "Total number of video streams", 0, G_MAXINT, 0, |
|
652 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
576 /** |
653 /** |
577 * GstPlayBin:current-video |
654 * GstPlayBin2:current-video |
578 * |
655 * |
579 * Get or set the currently playing video stream. By default the first video |
656 * Get or set the currently playing video stream. By default the first video |
580 * stream with data is played. |
657 * stream with data is played. |
581 */ |
658 */ |
582 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO, |
659 g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO, |
583 g_param_spec_int ("current-video", "Current Video", |
660 g_param_spec_int ("current-video", "Current Video", |
584 "Currently playing video stream (-1 = auto)", |
661 "Currently playing video stream (-1 = auto)", |
585 -1, G_MAXINT, -1, G_PARAM_READWRITE)); |
662 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
586 /** |
663 /** |
587 * GstPlayBin:n-audio |
664 * GstPlayBin2:n-audio |
588 * |
665 * |
589 * Get the total number of available audio streams. |
666 * Get the total number of available audio streams. |
590 */ |
667 */ |
591 g_object_class_install_property (gobject_klass, PROP_N_AUDIO, |
668 g_object_class_install_property (gobject_klass, PROP_N_AUDIO, |
592 g_param_spec_int ("n-audio", "Number Audio", |
669 g_param_spec_int ("n-audio", "Number Audio", |
593 "Total number of audio streams", 0, G_MAXINT, 0, G_PARAM_READABLE)); |
670 "Total number of audio streams", 0, G_MAXINT, 0, |
|
671 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
594 /** |
672 /** |
595 * GstPlayBin:current-audio |
673 * GstPlayBin2:current-audio |
596 * |
674 * |
597 * Get or set the currently playing audio stream. By default the first audio |
675 * Get or set the currently playing audio stream. By default the first audio |
598 * stream with data is played. |
676 * stream with data is played. |
599 */ |
677 */ |
600 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO, |
678 g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO, |
601 g_param_spec_int ("current-audio", "Current audio", |
679 g_param_spec_int ("current-audio", "Current audio", |
602 "Currently playing audio stream (-1 = auto)", |
680 "Currently playing audio stream (-1 = auto)", |
603 -1, G_MAXINT, -1, G_PARAM_READWRITE)); |
681 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
604 /** |
682 /** |
605 * GstPlayBin:n-text |
683 * GstPlayBin2:n-text |
606 * |
684 * |
607 * Get the total number of available subtitle streams. |
685 * Get the total number of available subtitle streams. |
608 */ |
686 */ |
609 g_object_class_install_property (gobject_klass, PROP_N_TEXT, |
687 g_object_class_install_property (gobject_klass, PROP_N_TEXT, |
610 g_param_spec_int ("n-text", "Number Text", |
688 g_param_spec_int ("n-text", "Number Text", |
611 "Total number of text streams", 0, G_MAXINT, 0, G_PARAM_READABLE)); |
689 "Total number of text streams", 0, G_MAXINT, 0, |
|
690 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
612 /** |
691 /** |
613 * GstPlayBin:current-text |
692 * GstPlayBin2:current-text: |
614 * |
693 * |
615 * Get or set the currently playing subtitle stream. By default the first |
694 * Get or set the currently playing subtitle stream. By default the first |
616 * subtitle stream with data is played. |
695 * subtitle stream with data is played. |
617 */ |
696 */ |
618 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT, |
697 g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT, |
619 g_param_spec_int ("current-text", "Current Text", |
698 g_param_spec_int ("current-text", "Current Text", |
620 "Currently playing text stream (-1 = auto)", |
699 "Currently playing text stream (-1 = auto)", |
621 -1, G_MAXINT, -1, G_PARAM_READWRITE)); |
700 -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
622 |
701 |
623 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING, |
702 g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING, |
624 g_param_spec_string ("subtitle-encoding", "subtitle encoding", |
703 g_param_spec_string ("subtitle-encoding", "subtitle encoding", |
625 "Encoding to assume if input subtitles are not in UTF-8 encoding. " |
704 "Encoding to assume if input subtitles are not in UTF-8 encoding. " |
626 "If not set, the GST_SUBTITLE_ENCODING environment variable will " |
705 "If not set, the GST_SUBTITLE_ENCODING environment variable will " |
627 "be checked for an encoding to use. If that is not set either, " |
706 "be checked for an encoding to use. If that is not set either, " |
628 "ISO-8859-15 will be assumed.", NULL, G_PARAM_READWRITE)); |
707 "ISO-8859-15 will be assumed.", NULL, |
|
708 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
629 |
709 |
630 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK, |
710 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK, |
631 g_param_spec_object ("video-sink", "Video Sink", |
711 g_param_spec_object ("video-sink", "Video Sink", |
632 "the video output element to use (NULL = default sink)", |
712 "the video output element to use (NULL = default sink)", |
633 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
713 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
634 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK, |
714 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK, |
635 g_param_spec_object ("audio-sink", "Audio Sink", |
715 g_param_spec_object ("audio-sink", "Audio Sink", |
636 "the audio output element to use (NULL = default sink)", |
716 "the audio output element to use (NULL = default sink)", |
637 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
717 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
638 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN, |
718 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN, |
639 g_param_spec_object ("vis-plugin", "Vis plugin", |
719 g_param_spec_object ("vis-plugin", "Vis plugin", |
640 "the visualization element to use (NULL = none)", |
720 "the visualization element to use (NULL = default)", |
641 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
721 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
722 g_object_class_install_property (gobject_klass, PROP_TEXT_SINK, |
|
723 g_param_spec_object ("text-sink", "Text plugin", |
|
724 "the text output element to use (NULL = default textoverlay)", |
|
725 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
726 g_object_class_install_property (gobject_klass, PROP_SUBPIC_SINK, |
|
727 g_param_spec_object ("subpic-sink", "Subpicture plugin", |
|
728 "the subpicture output element to use (NULL = default dvdspu)", |
|
729 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
642 |
730 |
643 g_object_class_install_property (gobject_klass, PROP_VOLUME, |
731 g_object_class_install_property (gobject_klass, PROP_VOLUME, |
644 g_param_spec_double ("volume", "Volume", "The audio volume", |
732 g_param_spec_double ("volume", "Volume", "The audio volume, 1.0=100%", |
645 0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE)); |
733 0.0, VOLUME_MAX_DOUBLE, 1.0, |
|
734 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
646 g_object_class_install_property (gobject_klass, PROP_MUTE, |
735 g_object_class_install_property (gobject_klass, PROP_MUTE, |
647 g_param_spec_boolean ("mute", "Mute", |
736 g_param_spec_boolean ("mute", "Mute", |
648 "Mute the audio channel without changing the volume", FALSE, |
737 "Mute the audio channel without changing the volume", FALSE, |
649 G_PARAM_READWRITE)); |
738 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
650 |
739 |
651 /** |
740 /** |
652 * GstPlayBin::frame |
741 * GstPlayBin2:frame: |
653 * @playbin: a #GstPlayBin |
742 * @playbin: a #GstPlayBin2 |
654 * |
743 * |
655 * Get the currently rendered or prerolled frame in the sink. |
744 * Get the currently rendered or prerolled frame in the sink. |
656 * The #GstCaps on the buffer will describe the format of the buffer. |
745 * The #GstCaps on the buffer will describe the format of the buffer. |
657 */ |
746 */ |
658 g_object_class_install_property (gobject_klass, PROP_FRAME, |
747 g_object_class_install_property (gobject_klass, PROP_FRAME, |
659 gst_param_spec_mini_object ("frame", "Frame", |
748 gst_param_spec_mini_object ("frame", "Frame", |
660 "The last frame (NULL = no video available)", |
749 "The last frame (NULL = no video available)", |
661 GST_TYPE_BUFFER, G_PARAM_READABLE)); |
750 GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
662 g_object_class_install_property (gobject_klass, PROP_FONT_DESC, |
751 g_object_class_install_property (gobject_klass, PROP_FONT_DESC, |
663 g_param_spec_string ("subtitle-font-desc", |
752 g_param_spec_string ("subtitle-font-desc", |
664 "Subtitle font description", |
753 "Subtitle font description", |
665 "Pango font description of font " |
754 "Pango font description of font " |
666 "to be used for subtitle rendering", NULL, G_PARAM_WRITABLE)); |
755 "to be used for subtitle rendering", NULL, |
|
756 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); |
667 |
757 |
668 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED, |
758 g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED, |
669 g_param_spec_uint ("connection-speed", "Connection Speed", |
759 g_param_spec_uint ("connection-speed", "Connection Speed", |
670 "Network connection speed in kbps (0 = unknown)", |
760 "Network connection speed in kbps (0 = unknown)", |
671 0, G_MAXUINT, DEFAULT_CONNECTION_SPEED, G_PARAM_READWRITE)); |
761 0, G_MAXUINT / 1000, DEFAULT_CONNECTION_SPEED, |
|
762 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
763 |
|
764 g_object_class_install_property (gobject_klass, PROP_BUFFER_SIZE, |
|
765 g_param_spec_int ("buffer-size", "Buffer size (bytes)", |
|
766 "Buffer size when buffering network streams", |
|
767 -1, G_MAXINT, DEFAULT_BUFFER_SIZE, |
|
768 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
769 g_object_class_install_property (gobject_klass, PROP_BUFFER_DURATION, |
|
770 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)", |
|
771 "Buffer duration when buffering network streams", |
|
772 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION, |
|
773 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
774 |
672 /** |
775 /** |
673 * GstPlayBin::about-to-finish: |
776 * GstPlayBin2::about-to-finish |
674 * @playbin: a #GstPlayBin |
777 * @playbin: a #GstPlayBin2 |
675 * |
778 * |
676 * This signal is emitted when the current uri is about to finish. You can |
779 * This signal is emitted when the current uri is about to finish. You can |
677 * set the next-uri and next-suburi to make sure that playback continues. |
780 * set the uri and suburi to make sure that playback continues. |
678 */ |
781 */ |
679 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] = |
782 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] = |
680 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass), |
783 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass), |
681 G_SIGNAL_RUN_LAST, |
784 G_SIGNAL_RUN_LAST, |
682 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL, |
785 G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL, |
683 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); |
786 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); |
684 |
787 |
685 /** |
788 /** |
686 * GstPlayBin::video-changed |
789 * GstPlayBin2::video-changed |
687 * @playbin: a #GstPlayBin |
790 * @playbin: a #GstPlayBin2 |
688 * |
791 * |
689 * This signal is emited whenever the number or order of the video |
792 * This signal is emitted whenever the number or order of the video |
690 * streams has changed. The application will most likely want to select |
793 * streams has changed. The application will most likely want to select |
691 * a new video stream. |
794 * a new video stream. |
692 */ |
795 */ |
693 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] = |
796 gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] = |
694 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass), |
797 g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass), |
695 G_SIGNAL_RUN_LAST, |
798 G_SIGNAL_RUN_LAST, |
696 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL, |
799 G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL, |
697 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); |
800 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); |
698 /** |
801 /** |
699 * GstPlayBin::audio-changed |
802 * GstPlayBin2::audio-changed |
700 * @playbin: a #GstPlayBin |
803 * @playbin: a #GstPlayBin2 |
701 * |
804 * |
702 * This signal is emited whenever the number or order of the audio |
805 * This signal is emitted whenever the number or order of the audio |
703 * streams has changed. The application will most likely want to select |
806 * streams has changed. The application will most likely want to select |
704 * a new audio stream. |
807 * a new audio stream. |
705 */ |
808 */ |
706 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] = |
809 gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] = |
707 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass), |
810 g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass), |
708 G_SIGNAL_RUN_LAST, |
811 G_SIGNAL_RUN_LAST, |
709 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL, |
812 G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL, |
710 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); |
813 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); |
711 /** |
814 /** |
712 * GstPlayBin::text-changed |
815 * GstPlayBin2::text-changed |
713 * @playbin: a #GstPlayBin |
816 * @playbin: a #GstPlayBin2 |
714 * |
817 * |
715 * This signal is emited whenever the number or order of the text |
818 * This signal is emitted whenever the number or order of the text |
716 * streams has changed. The application will most likely want to select |
819 * streams has changed. The application will most likely want to select |
717 * a new text stream. |
820 * a new text stream. |
718 */ |
821 */ |
719 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] = |
822 gst_play_bin_signals[SIGNAL_TEXT_CHANGED] = |
720 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass), |
823 g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass), |
721 G_SIGNAL_RUN_LAST, |
824 G_SIGNAL_RUN_LAST, |
722 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL, |
825 G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL, |
723 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); |
826 gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); |
724 |
827 |
725 /** |
828 /** |
726 * GstPlayBin::get-video-tags |
829 * GstPlayBin2::video-tags-changed |
727 * @playbin: a #GstPlayBin |
830 * @playbin: a #GstPlayBin2 |
|
831 * @stream: stream index with changed tags |
|
832 * |
|
833 * This signal is emitted whenever the tags of a video stream have changed. |
|
834 * The application will most likely want to get the new tags. |
|
835 * |
|
836 * Since: 0.10.24 |
|
837 */ |
|
838 gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] = |
|
839 g_signal_new ("video-tags-changed", G_TYPE_FROM_CLASS (klass), |
|
840 G_SIGNAL_RUN_LAST, |
|
841 G_STRUCT_OFFSET (GstPlayBinClass, video_tags_changed), NULL, NULL, |
|
842 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); |
|
843 |
|
844 /** |
|
845 * GstPlayBin2::audio-tags-changed |
|
846 * @playbin: a #GstPlayBin2 |
|
847 * @stream: stream index with changed tags |
|
848 * |
|
849 * This signal is emitted whenever the tags of an audio stream have changed. |
|
850 * The application will most likely want to get the new tags. |
|
851 * |
|
852 * Since: 0.10.24 |
|
853 */ |
|
854 gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] = |
|
855 g_signal_new ("audio-tags-changed", G_TYPE_FROM_CLASS (klass), |
|
856 G_SIGNAL_RUN_LAST, |
|
857 G_STRUCT_OFFSET (GstPlayBinClass, audio_tags_changed), NULL, NULL, |
|
858 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); |
|
859 |
|
860 /** |
|
861 * GstPlayBin2::text-tags-changed |
|
862 * @playbin: a #GstPlayBin2 |
|
863 * @stream: stream index with changed tags |
|
864 * |
|
865 * This signal is emitted whenever the tags of a text stream have changed. |
|
866 * The application will most likely want to get the new tags. |
|
867 * |
|
868 * Since: 0.10.24 |
|
869 */ |
|
870 gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] = |
|
871 g_signal_new ("text-tags-changed", G_TYPE_FROM_CLASS (klass), |
|
872 G_SIGNAL_RUN_LAST, |
|
873 G_STRUCT_OFFSET (GstPlayBinClass, text_tags_changed), NULL, NULL, |
|
874 gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); |
|
875 |
|
876 /** |
|
877 * GstPlayBin2::get-video-tags |
|
878 * @playbin: a #GstPlayBin2 |
728 * @stream: a video stream number |
879 * @stream: a video stream number |
729 * |
880 * |
730 * Action signal to retrieve the tags of a specific video stream number. |
881 * Action signal to retrieve the tags of a specific video stream number. |
731 * This information can be used to select a stream. |
882 * This information can be used to select a stream. |
732 * |
883 * |
1193 switch (prop_id) { |
1635 switch (prop_id) { |
1194 case PROP_URI: |
1636 case PROP_URI: |
1195 { |
1637 { |
1196 GstSourceGroup *group; |
1638 GstSourceGroup *group; |
1197 |
1639 |
1198 GST_OBJECT_LOCK (playbin); |
1640 GST_PLAY_BIN_LOCK (playbin); |
1199 group = get_group (playbin); |
1641 group = get_group (playbin); |
1200 g_value_set_string (value, group->uri); |
1642 g_value_set_string (value, group->uri); |
1201 GST_OBJECT_UNLOCK (playbin); |
1643 GST_PLAY_BIN_UNLOCK (playbin); |
1202 break; |
1644 break; |
1203 } |
1645 } |
1204 case PROP_SUBURI: |
1646 case PROP_SUBURI: |
1205 { |
1647 { |
1206 GstSourceGroup *group; |
1648 GstSourceGroup *group; |
1207 |
1649 |
1208 GST_OBJECT_LOCK (playbin); |
1650 GST_PLAY_BIN_LOCK (playbin); |
1209 group = get_group (playbin); |
1651 group = get_group (playbin); |
1210 g_value_set_string (value, group->suburi); |
1652 g_value_set_string (value, group->suburi); |
1211 GST_OBJECT_UNLOCK (playbin); |
1653 GST_PLAY_BIN_UNLOCK (playbin); |
1212 break; |
1654 break; |
1213 } |
1655 } |
1214 case PROP_SOURCE: |
1656 case PROP_SOURCE: |
1215 break; |
1657 { |
|
1658 GST_OBJECT_LOCK (playbin); |
|
1659 g_value_set_object (value, playbin->source); |
|
1660 GST_OBJECT_UNLOCK (playbin); |
|
1661 break; |
|
1662 } |
1216 case PROP_FLAGS: |
1663 case PROP_FLAGS: |
1217 g_value_set_flags (value, gst_play_sink_get_flags (playbin->playsink)); |
1664 g_value_set_flags (value, gst_play_bin_get_flags (playbin)); |
1218 break; |
1665 break; |
1219 case PROP_N_VIDEO: |
1666 case PROP_N_VIDEO: |
1220 { |
1667 { |
1221 GstSourceGroup *group; |
1668 GstSourceGroup *group; |
1222 gint n_video; |
1669 gint n_video; |
1223 |
1670 |
1224 GST_OBJECT_LOCK (playbin); |
1671 GST_PLAY_BIN_LOCK (playbin); |
1225 group = get_group (playbin); |
1672 group = get_group (playbin); |
1226 n_video = (group->video_channels ? group->video_channels->len : 0); |
1673 n_video = (group->video_channels ? group->video_channels->len : 0); |
1227 g_value_set_int (value, n_video); |
1674 g_value_set_int (value, n_video); |
1228 GST_OBJECT_UNLOCK (playbin); |
1675 GST_PLAY_BIN_UNLOCK (playbin); |
1229 break; |
1676 break; |
1230 } |
1677 } |
1231 case PROP_CURRENT_VIDEO: |
1678 case PROP_CURRENT_VIDEO: |
1232 GST_OBJECT_LOCK (playbin); |
1679 GST_PLAY_BIN_LOCK (playbin); |
1233 g_value_set_int (value, playbin->current_video); |
1680 g_value_set_int (value, playbin->current_video); |
1234 GST_OBJECT_UNLOCK (playbin); |
1681 GST_PLAY_BIN_UNLOCK (playbin); |
1235 break; |
1682 break; |
1236 case PROP_N_AUDIO: |
1683 case PROP_N_AUDIO: |
1237 { |
1684 { |
1238 GstSourceGroup *group; |
1685 GstSourceGroup *group; |
1239 gint n_audio; |
1686 gint n_audio; |
1240 |
1687 |
1241 GST_OBJECT_LOCK (playbin); |
1688 GST_PLAY_BIN_LOCK (playbin); |
1242 group = get_group (playbin); |
1689 group = get_group (playbin); |
1243 n_audio = (group->audio_channels ? group->audio_channels->len : 0); |
1690 n_audio = (group->audio_channels ? group->audio_channels->len : 0); |
1244 g_value_set_int (value, n_audio); |
1691 g_value_set_int (value, n_audio); |
1245 GST_OBJECT_UNLOCK (playbin); |
1692 GST_PLAY_BIN_UNLOCK (playbin); |
1246 break; |
1693 break; |
1247 } |
1694 } |
1248 case PROP_CURRENT_AUDIO: |
1695 case PROP_CURRENT_AUDIO: |
1249 GST_OBJECT_LOCK (playbin); |
1696 GST_PLAY_BIN_LOCK (playbin); |
1250 g_value_set_int (value, playbin->current_audio); |
1697 g_value_set_int (value, playbin->current_audio); |
1251 GST_OBJECT_UNLOCK (playbin); |
1698 GST_PLAY_BIN_UNLOCK (playbin); |
1252 break; |
1699 break; |
1253 case PROP_N_TEXT: |
1700 case PROP_N_TEXT: |
1254 { |
1701 { |
1255 GstSourceGroup *group; |
1702 GstSourceGroup *group; |
1256 gint n_text; |
1703 gint n_text; |
1257 |
1704 |
1258 GST_OBJECT_LOCK (playbin); |
1705 GST_PLAY_BIN_LOCK (playbin); |
1259 group = get_group (playbin); |
1706 group = get_group (playbin); |
1260 n_text = (group->text_channels ? group->text_channels->len : 0); |
1707 n_text = (group->text_channels ? group->text_channels->len : 0); |
1261 g_value_set_int (value, n_text); |
1708 g_value_set_int (value, n_text); |
1262 GST_OBJECT_UNLOCK (playbin); |
1709 GST_PLAY_BIN_UNLOCK (playbin); |
1263 break; |
1710 break; |
1264 } |
1711 } |
1265 case PROP_CURRENT_TEXT: |
1712 case PROP_CURRENT_TEXT: |
1266 GST_OBJECT_LOCK (playbin); |
1713 GST_PLAY_BIN_LOCK (playbin); |
1267 g_value_set_int (value, playbin->current_text); |
1714 g_value_set_int (value, playbin->current_text); |
1268 GST_OBJECT_UNLOCK (playbin); |
1715 GST_PLAY_BIN_UNLOCK (playbin); |
1269 break; |
1716 break; |
1270 case PROP_SUBTITLE_ENCODING: |
1717 case PROP_SUBTITLE_ENCODING: |
|
1718 GST_PLAY_BIN_LOCK (playbin); |
|
1719 g_value_set_string (value, playbin->encoding); |
|
1720 GST_PLAY_BIN_UNLOCK (playbin); |
1271 break; |
1721 break; |
1272 case PROP_VIDEO_SINK: |
1722 case PROP_VIDEO_SINK: |
|
1723 g_value_set_object (value, |
|
1724 gst_play_bin_get_current_sink (playbin, &playbin->video_sink, |
|
1725 "video", GST_PLAY_SINK_TYPE_VIDEO)); |
1273 break; |
1726 break; |
1274 case PROP_AUDIO_SINK: |
1727 case PROP_AUDIO_SINK: |
|
1728 g_value_set_object (value, |
|
1729 gst_play_bin_get_current_sink (playbin, &playbin->audio_sink, |
|
1730 "audio", GST_PLAY_SINK_TYPE_AUDIO)); |
1275 break; |
1731 break; |
1276 case PROP_VIS_PLUGIN: |
1732 case PROP_VIS_PLUGIN: |
|
1733 g_value_set_object (value, |
|
1734 gst_play_sink_get_vis_plugin (playbin->playsink)); |
|
1735 break; |
|
1736 case PROP_TEXT_SINK: |
|
1737 g_value_set_object (value, |
|
1738 gst_play_bin_get_current_sink (playbin, &playbin->text_sink, |
|
1739 "text", GST_PLAY_SINK_TYPE_TEXT)); |
|
1740 break; |
|
1741 case PROP_SUBPIC_SINK: |
|
1742 g_value_set_object (value, |
|
1743 gst_play_bin_get_current_sink (playbin, &playbin->subpic_sink, |
|
1744 "subpicture", GST_PLAY_SINK_TYPE_SUBPIC)); |
1277 break; |
1745 break; |
1278 case PROP_VOLUME: |
1746 case PROP_VOLUME: |
1279 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink)); |
1747 g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink)); |
1280 break; |
1748 break; |
1281 case PROP_MUTE: |
1749 case PROP_MUTE: |
1349 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p", |
1940 "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p", |
1350 GST_DEBUG_PAD_NAME (pad), caps, group); |
1941 GST_DEBUG_PAD_NAME (pad), caps, group); |
1351 |
1942 |
1352 /* major type of the pad, this determines the selector to use */ |
1943 /* major type of the pad, this determines the selector to use */ |
1353 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
1944 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
1354 if (g_str_has_prefix (name, group->selector[i].media)) { |
1945 if (array_has_value (group->selector[i].media_list, name)) { |
1355 select = &group->selector[i]; |
1946 select = &group->selector[i]; |
1356 break; |
1947 break; |
1357 } |
1948 } |
1358 } |
1949 } |
1359 /* no selector found for the media type, don't bother linking it to a |
1950 /* no selector found for the media type, don't bother linking it to a |
1360 * selector. This will leave the pad unlinked and thus ignored. */ |
1951 * selector. This will leave the pad unlinked and thus ignored. */ |
1361 if (select == NULL) |
1952 if (select == NULL) |
1362 goto unknown_type; |
1953 goto unknown_type; |
1363 |
1954 |
1364 if (select->selector == NULL) { |
1955 GST_SOURCE_GROUP_LOCK (group); |
|
1956 if (select->selector == NULL && playbin->have_selector) { |
1365 /* no selector, create one */ |
1957 /* no selector, create one */ |
1366 GST_DEBUG_OBJECT (playbin, "creating new selector"); |
1958 GST_DEBUG_OBJECT (playbin, "creating new selector"); |
1367 select->selector = g_object_new (GST_TYPE_STREAM_SELECTOR, NULL); |
1959 select->selector = g_object_new (GST_TYPE_INPUT_SELECTOR, NULL); |
1368 if (select->selector == NULL) |
1960 /* the above can't fail, but we keep the error handling around for when |
1369 goto no_selector; |
1961 * the selector plugin has moved to -base or -good and we stop using an |
1370 |
1962 * internal copy of input-selector */ |
1371 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector); |
1963 if (select->selector == NULL) { |
1372 gst_bin_add (GST_BIN_CAST (playbin), select->selector); |
1964 /* post the missing selector message only once */ |
1373 gst_element_set_state (select->selector, GST_STATE_PAUSED); |
1965 playbin->have_selector = FALSE; |
1374 |
1966 gst_element_post_message (GST_ELEMENT_CAST (playbin), |
1375 /* save source pad */ |
1967 gst_missing_element_message_new (GST_ELEMENT_CAST (playbin), |
1376 select->srcpad = gst_element_get_pad (select->selector, "src"); |
1968 "input-selector")); |
|
1969 GST_ELEMENT_WARNING (playbin, CORE, MISSING_PLUGIN, |
|
1970 (_("Missing element '%s' - check your GStreamer installation."), |
|
1971 "input-selector"), (NULL)); |
|
1972 } else { |
|
1973 g_signal_connect (select->selector, "notify::active-pad", |
|
1974 G_CALLBACK (selector_active_pad_changed), playbin); |
|
1975 |
|
1976 GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector); |
|
1977 gst_bin_add (GST_BIN_CAST (playbin), select->selector); |
|
1978 gst_element_set_state (select->selector, GST_STATE_PAUSED); |
|
1979 } |
|
1980 } |
|
1981 |
|
1982 if (select->srcpad == NULL) { |
|
1983 if (select->selector) { |
|
1984 /* save source pad of the selector */ |
|
1985 select->srcpad = gst_element_get_static_pad (select->selector, "src"); |
|
1986 } else { |
|
1987 /* no selector, use the pad as the source pad then */ |
|
1988 select->srcpad = gst_object_ref (pad); |
|
1989 } |
|
1990 /* block the selector srcpad. It's possible that multiple decodebins start |
|
1991 * pushing data into the selectors before we have a chance to collect all |
|
1992 * streams and connect the sinks, resulting in not-linked errors. After we |
|
1993 * configured the sinks we will unblock them all. */ |
|
1994 gst_pad_set_blocked_async (select->srcpad, TRUE, selector_blocked, NULL); |
1377 } |
1995 } |
1378 |
1996 |
1379 /* get sinkpad for the new stream */ |
1997 /* get sinkpad for the new stream */ |
1380 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) { |
1998 if (select->selector) { |
1381 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector", |
1999 if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) { |
1382 GST_DEBUG_PAD_NAME (sinkpad)); |
2000 gulong notify_tags_handler = 0; |
1383 |
2001 NotifyTagsData *ntdata; |
1384 /* store the selector for the pad */ |
2002 |
1385 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select); |
2003 GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector", |
1386 |
2004 GST_DEBUG_PAD_NAME (sinkpad)); |
1387 /* store the pad in the array */ |
2005 |
1388 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad); |
2006 /* store the selector for the pad */ |
1389 g_ptr_array_add (select->channels, sinkpad); |
2007 g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select); |
1390 |
2008 |
1391 res = gst_pad_link (pad, sinkpad); |
2009 /* connect to the notify::tags signal for our |
1392 if (GST_PAD_LINK_FAILED (res)) |
2010 * own *-tags-changed signals |
1393 goto link_failed; |
2011 */ |
1394 |
2012 ntdata = g_new0 (NotifyTagsData, 1); |
1395 /* store selector pad so we can release it */ |
2013 ntdata->playbin = playbin; |
1396 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad); |
2014 ntdata->stream_id = select->channels->len; |
1397 } |
2015 ntdata->type = select->type; |
1398 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p", |
2016 |
1399 GST_DEBUG_PAD_NAME (pad), select->selector); |
2017 notify_tags_handler = |
1400 |
2018 g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags", |
|
2019 G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free, |
|
2020 (GConnectFlags) 0); |
|
2021 g_object_set_data (G_OBJECT (sinkpad), "playbin2.notify_tags_handler", |
|
2022 (gpointer) notify_tags_handler); |
|
2023 |
|
2024 /* store the pad in the array */ |
|
2025 GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad); |
|
2026 g_ptr_array_add (select->channels, sinkpad); |
|
2027 |
|
2028 res = gst_pad_link (pad, sinkpad); |
|
2029 if (GST_PAD_LINK_FAILED (res)) |
|
2030 goto link_failed; |
|
2031 |
|
2032 /* store selector pad so we can release it */ |
|
2033 g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad); |
|
2034 |
|
2035 changed = TRUE; |
|
2036 GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p", |
|
2037 GST_DEBUG_PAD_NAME (pad), select->selector); |
|
2038 } |
|
2039 } else { |
|
2040 /* no selector, don't configure anything, we'll link the new pad directly to |
|
2041 * the sink. */ |
|
2042 changed = FALSE; |
|
2043 sinkpad = NULL; |
|
2044 } |
|
2045 GST_SOURCE_GROUP_UNLOCK (group); |
|
2046 |
|
2047 if (changed) { |
|
2048 int signal; |
|
2049 switch (select->type) { |
|
2050 case GST_PLAY_SINK_TYPE_VIDEO: |
|
2051 case GST_PLAY_SINK_TYPE_VIDEO_RAW: |
|
2052 /* we want to return NOT_LINKED for unselected pads but only for audio |
|
2053 * and video pads because text pads might come from an external file. */ |
|
2054 g_object_set (sinkpad, "always-ok", FALSE, NULL); |
|
2055 signal = SIGNAL_VIDEO_CHANGED; |
|
2056 break; |
|
2057 case GST_PLAY_SINK_TYPE_AUDIO: |
|
2058 case GST_PLAY_SINK_TYPE_AUDIO_RAW: |
|
2059 g_object_set (sinkpad, "always-ok", FALSE, NULL); |
|
2060 signal = SIGNAL_AUDIO_CHANGED; |
|
2061 break; |
|
2062 case GST_PLAY_SINK_TYPE_TEXT: |
|
2063 signal = SIGNAL_TEXT_CHANGED; |
|
2064 break; |
|
2065 case GST_PLAY_SINK_TYPE_SUBPIC: |
|
2066 default: |
|
2067 signal = -1; |
|
2068 } |
|
2069 |
|
2070 if (signal >= 0) |
|
2071 g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL); |
|
2072 } |
|
2073 |
|
2074 done: |
|
2075 gst_caps_unref (caps); |
1401 return; |
2076 return; |
1402 |
2077 |
1403 /* ERRORS */ |
2078 /* ERRORS */ |
1404 unknown_type: |
2079 unknown_type: |
1405 { |
2080 { |
1406 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s", |
2081 GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s", |
1407 name, GST_DEBUG_PAD_NAME (pad)); |
2082 name, GST_DEBUG_PAD_NAME (pad)); |
1408 return; |
2083 goto done; |
1409 } |
|
1410 no_selector: |
|
1411 { |
|
1412 GST_ERROR_OBJECT (playbin, "could not create selector for pad %s:%s", |
|
1413 GST_DEBUG_PAD_NAME (pad)); |
|
1414 return; |
|
1415 } |
2084 } |
1416 link_failed: |
2085 link_failed: |
1417 { |
2086 { |
1418 GST_ERROR_OBJECT (playbin, |
2087 GST_ERROR_OBJECT (playbin, |
1419 "failed to link pad %s:%s to selector, reason %d", |
2088 "failed to link pad %s:%s to selector, reason %d", |
1420 GST_DEBUG_PAD_NAME (pad), res); |
2089 GST_DEBUG_PAD_NAME (pad), res); |
1421 return; |
2090 GST_SOURCE_GROUP_UNLOCK (group); |
1422 } |
2091 goto done; |
1423 } |
2092 } |
1424 |
2093 } |
1425 /* called when a pad is removed form the uridecodebin. We unlink the pad from |
2094 |
|
2095 /* called when a pad is removed from the uridecodebin. We unlink the pad from |
1426 * the selector. This will make the selector select a new pad. */ |
2096 * the selector. This will make the selector select a new pad. */ |
1427 static void |
2097 static void |
1428 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) |
2098 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group) |
1429 { |
2099 { |
1430 GstPlayBin *playbin; |
2100 GstPlayBin *playbin; |
1490 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group) |
2176 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group) |
1491 { |
2177 { |
1492 GstPlayBin *playbin; |
2178 GstPlayBin *playbin; |
1493 GstPadLinkReturn res; |
2179 GstPadLinkReturn res; |
1494 gint i; |
2180 gint i; |
|
2181 gboolean configure; |
1495 |
2182 |
1496 playbin = group->playbin; |
2183 playbin = group->playbin; |
1497 |
2184 |
1498 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group); |
2185 GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group); |
1499 |
2186 |
|
2187 GST_PLAY_BIN_SHUTDOWN_LOCK (playbin, shutdown); |
|
2188 |
|
2189 GST_SOURCE_GROUP_LOCK (group); |
1500 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
2190 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
1501 GstSourceSelect *select = &group->selector[i]; |
2191 GstSourceSelect *select = &group->selector[i]; |
1502 |
2192 |
1503 if (select->selector) { |
2193 /* check if the specific media type was detected and thus has a selector |
|
2194 * created for it. If there is the media type, get a sinkpad from the sink |
|
2195 * and link it. We only do this if we have not yet requested the sinkpad |
|
2196 * before. */ |
|
2197 if (select->srcpad && select->sinkpad == NULL) { |
|
2198 GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", select->type); |
1504 select->sinkpad = |
2199 select->sinkpad = |
1505 gst_play_sink_request_pad (playbin->playsink, select->type); |
2200 gst_play_sink_request_pad (playbin->playsink, select->type); |
1506 res = gst_pad_link (select->srcpad, select->sinkpad); |
2201 res = gst_pad_link (select->srcpad, select->sinkpad); |
1507 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d", select->media, |
2202 GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d", |
1508 res); |
2203 select->media_list[0], res); |
|
2204 if (res != GST_PAD_LINK_OK) { |
|
2205 GST_ELEMENT_ERROR (playbin, CORE, PAD, |
|
2206 ("Internal playbin error."), |
|
2207 ("Failed to link selector to sink. Error %d", res)); |
|
2208 } |
1509 } |
2209 } |
1510 } |
2210 } |
1511 /* configure the modes now */ |
2211 GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending, |
1512 gst_play_sink_reconfigure (playbin->playsink); |
2212 group->pending - 1); |
1513 } |
2213 |
1514 |
2214 if (group->pending > 0) |
1515 /* send an EOS event to all of the selectors */ |
2215 group->pending--; |
1516 static void |
2216 |
1517 perform_eos (GstPlayBin * playbin, GstSourceGroup * group) |
2217 if (group->pending == 0) { |
1518 { |
2218 /* we are the last group to complete, we will configure the output and then |
1519 GstEvent *event; |
2219 * signal the other waiters. */ |
1520 gint i; |
2220 GST_LOG_OBJECT (playbin, "last group complete"); |
1521 |
2221 configure = TRUE; |
1522 GST_DEBUG_OBJECT (playbin, "doing EOS in group %p", group); |
2222 } else { |
1523 |
2223 GST_LOG_OBJECT (playbin, "have more pending groups"); |
1524 event = gst_event_new_eos (); |
2224 configure = FALSE; |
1525 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
2225 } |
1526 GstSourceSelect *select = &group->selector[i]; |
2226 GST_SOURCE_GROUP_UNLOCK (group); |
1527 |
2227 |
1528 if (select->selector) { |
2228 if (configure) { |
1529 GST_DEBUG_OBJECT (playbin, "send EOS in selector %s", select->media); |
2229 /* if we have custom sinks, configure them now */ |
1530 gst_event_ref (event); |
2230 GST_SOURCE_GROUP_LOCK (group); |
1531 gst_pad_push_event (select->srcpad, event); |
2231 if (group->audio_sink) { |
|
2232 GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT, |
|
2233 group->audio_sink); |
|
2234 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO, |
|
2235 group->audio_sink); |
|
2236 } else { |
|
2237 GST_INFO_OBJECT (playbin, "setting default audio sink %" GST_PTR_FORMAT, |
|
2238 playbin->audio_sink); |
|
2239 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO, |
|
2240 playbin->audio_sink); |
1532 } |
2241 } |
1533 } |
2242 if (group->video_sink) { |
1534 gst_event_unref (event); |
2243 GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT, |
|
2244 group->video_sink); |
|
2245 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO, |
|
2246 group->video_sink); |
|
2247 } else { |
|
2248 GST_INFO_OBJECT (playbin, "setting default video sink %" GST_PTR_FORMAT, |
|
2249 playbin->video_sink); |
|
2250 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO, |
|
2251 playbin->video_sink); |
|
2252 } |
|
2253 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT, |
|
2254 playbin->text_sink); |
|
2255 gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_SUBPIC, |
|
2256 playbin->subpic_sink); |
|
2257 GST_SOURCE_GROUP_UNLOCK (group); |
|
2258 |
|
2259 GST_LOG_OBJECT (playbin, "reconfigure sink"); |
|
2260 /* we configure the modes if we were the last decodebin to complete. */ |
|
2261 gst_play_sink_reconfigure (playbin->playsink); |
|
2262 |
|
2263 /* signal the other decodebins that they can continue now. */ |
|
2264 GST_SOURCE_GROUP_LOCK (group); |
|
2265 /* unblock all selectors */ |
|
2266 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
|
2267 GstSourceSelect *select = &group->selector[i]; |
|
2268 |
|
2269 if (select->srcpad) { |
|
2270 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT, |
|
2271 select->srcpad); |
|
2272 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked, |
|
2273 NULL); |
|
2274 } |
|
2275 } |
|
2276 GST_SOURCE_GROUP_UNLOCK (group); |
|
2277 } |
|
2278 |
|
2279 GST_PLAY_BIN_SHUTDOWN_UNLOCK (playbin); |
|
2280 |
|
2281 return; |
|
2282 |
|
2283 shutdown: |
|
2284 { |
|
2285 GST_DEBUG ("ignoring, we are shutting down"); |
|
2286 /* Request a flushing pad from playsink that we then link to the selector. |
|
2287 * Then we unblock the selectors so that they stop with a WRONG_STATE |
|
2288 * instead of a NOT_LINKED error. |
|
2289 */ |
|
2290 GST_SOURCE_GROUP_LOCK (group); |
|
2291 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
|
2292 GstSourceSelect *select = &group->selector[i]; |
|
2293 |
|
2294 if (select->srcpad) { |
|
2295 if (select->sinkpad == NULL) { |
|
2296 GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad"); |
|
2297 select->sinkpad = |
|
2298 gst_play_sink_request_pad (playbin->playsink, |
|
2299 GST_PLAY_SINK_TYPE_FLUSHING); |
|
2300 res = gst_pad_link (select->srcpad, select->sinkpad); |
|
2301 GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res); |
|
2302 } |
|
2303 GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT, |
|
2304 select->srcpad); |
|
2305 gst_pad_set_blocked_async (select->srcpad, FALSE, selector_blocked, |
|
2306 NULL); |
|
2307 } |
|
2308 } |
|
2309 GST_SOURCE_GROUP_UNLOCK (group); |
|
2310 return; |
|
2311 } |
1535 } |
2312 } |
1536 |
2313 |
1537 static void |
2314 static void |
1538 drained_cb (GstElement * decodebin, GstSourceGroup * group) |
2315 drained_cb (GstElement * decodebin, GstSourceGroup * group) |
1539 { |
2316 { |
1540 GstPlayBin *playbin; |
2317 GstPlayBin *playbin; |
1541 |
2318 |
1542 playbin = group->playbin; |
2319 playbin = group->playbin; |
1543 |
2320 |
1544 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group); |
2321 GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group); |
1545 |
|
1546 /* mark use as sending out the about-to-finish signal. When the app sets a URI |
|
1547 * when this signal is emited, we're marking it as next-uri */ |
|
1548 playbin->about_to_finish = TRUE; |
|
1549 |
2322 |
1550 /* after this call, we should have a next group to activate or we EOS */ |
2323 /* after this call, we should have a next group to activate or we EOS */ |
1551 g_signal_emit (G_OBJECT (playbin), |
2324 g_signal_emit (G_OBJECT (playbin), |
1552 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL); |
2325 gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL); |
1553 |
2326 |
1554 playbin->about_to_finish = FALSE; |
2327 /* now activate the next group. If the app did not set a uri, this will |
1555 |
|
1556 /* now activate the next group. If the app did not set a next-uri, this will |
|
1557 * fail and we can do EOS */ |
2328 * fail and we can do EOS */ |
1558 if (!setup_next_source (playbin)) { |
2329 setup_next_source (playbin, GST_STATE_PAUSED); |
1559 perform_eos (playbin, group); |
|
1560 } |
|
1561 } |
2330 } |
1562 |
2331 |
1563 /* Called when we must provide a list of factories to plug to @pad with @caps. |
2332 /* Called when we must provide a list of factories to plug to @pad with @caps. |
1564 * We first check if we have a sink that can handle the format and if we do, we |
2333 * We first check if we have a sink that can handle the format and if we do, we |
1565 * return NULL, to expose the pad. If we have no sink (or the sink does not |
2334 * return NULL, to expose the pad. If we have no sink (or the sink does not |
1627 GST_ELEMENT_NAME (element)); |
2436 GST_ELEMENT_NAME (element)); |
1628 gst_object_unref (element); |
2437 gst_object_unref (element); |
1629 return GST_AUTOPLUG_SELECT_SKIP; |
2438 return GST_AUTOPLUG_SELECT_SKIP; |
1630 } |
2439 } |
1631 |
2440 |
1632 /* at this point, we have the sink working, configure it in playsink */ |
2441 /* remember the sink in the group now, the element is floating, we take |
1633 klass = gst_element_factory_get_klass (factory); |
2442 * ownership now */ |
1634 |
2443 GST_SOURCE_GROUP_LOCK (group); |
1635 /* get klass to figure out if it's audio or video */ |
2444 if (*sinkp == NULL) { |
1636 if (strstr (klass, "Audio")) { |
2445 /* store the sink in the group, we will configure it later when we |
1637 GST_DEBUG_OBJECT (playbin, "configure audio sink"); |
2446 * reconfigure the sink */ |
1638 gst_play_sink_set_audio_sink (playbin->playsink, element); |
2447 GST_DEBUG_OBJECT (playbin, "remember sink"); |
1639 } else if (strstr (klass, "Video")) { |
2448 gst_object_ref (element); |
1640 GST_DEBUG_OBJECT (playbin, "configure video sink"); |
2449 gst_object_sink (element); |
1641 gst_play_sink_set_video_sink (playbin->playsink, element); |
2450 *sinkp = element; |
1642 } else { |
2451 } else { |
1643 GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass); |
2452 /* some other thread configured a sink while we were testing the sink, set |
1644 } |
2453 * the sink back to NULL and assume we can use the other sink */ |
|
2454 GST_DEBUG_OBJECT (playbin, "another sink was found, expose pad"); |
|
2455 gst_element_set_state (element, GST_STATE_NULL); |
|
2456 gst_object_unref (element); |
|
2457 } |
|
2458 GST_SOURCE_GROUP_UNLOCK (group); |
1645 |
2459 |
1646 /* tell decodebin to expose the pad because we are going to use this |
2460 /* tell decodebin to expose the pad because we are going to use this |
1647 * sink */ |
2461 * sink */ |
1648 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad"); |
2462 GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad"); |
1649 |
2463 |
1650 return GST_AUTOPLUG_SELECT_EXPOSE; |
2464 return GST_AUTOPLUG_SELECT_EXPOSE; |
1651 } |
2465 } |
1652 |
2466 |
|
2467 static void |
|
2468 notify_source_cb (GstElement * uridecodebin, GParamSpec * pspec, |
|
2469 GstSourceGroup * group) |
|
2470 { |
|
2471 GstPlayBin *playbin; |
|
2472 GstElement *source; |
|
2473 |
|
2474 playbin = group->playbin; |
|
2475 |
|
2476 g_object_get (group->uridecodebin, "source", &source, NULL); |
|
2477 |
|
2478 GST_OBJECT_LOCK (playbin); |
|
2479 if (playbin->source) |
|
2480 gst_object_unref (playbin->source); |
|
2481 playbin->source = source; |
|
2482 GST_OBJECT_UNLOCK (playbin); |
|
2483 |
|
2484 g_object_notify (G_OBJECT (playbin), "source"); |
|
2485 } |
|
2486 |
|
2487 /* must be called with the group lock */ |
1653 static gboolean |
2488 static gboolean |
1654 activate_group (GstPlayBin * playbin, GstSourceGroup * group) |
2489 group_set_locked_state_unlocked (GstPlayBin * playbin, GstSourceGroup * group, |
|
2490 gboolean locked) |
|
2491 { |
|
2492 GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group); |
|
2493 |
|
2494 if (group->uridecodebin) |
|
2495 gst_element_set_locked_state (group->uridecodebin, locked); |
|
2496 if (group->suburidecodebin) |
|
2497 gst_element_set_locked_state (group->suburidecodebin, locked); |
|
2498 |
|
2499 return TRUE; |
|
2500 } |
|
2501 |
|
2502 #define REMOVE_SIGNAL(obj,id) \ |
|
2503 if (id) { \ |
|
2504 g_signal_handler_disconnect (obj, id); \ |
|
2505 id = 0; \ |
|
2506 } |
|
2507 |
|
2508 /* must be called with PLAY_BIN_LOCK */ |
|
2509 static gboolean |
|
2510 activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target) |
1655 { |
2511 { |
1656 GstElement *uridecodebin; |
2512 GstElement *uridecodebin; |
|
2513 GstElement *suburidecodebin = NULL; |
1657 |
2514 |
1658 g_return_val_if_fail (group->valid, FALSE); |
2515 g_return_val_if_fail (group->valid, FALSE); |
1659 g_return_val_if_fail (!group->active, FALSE); |
2516 g_return_val_if_fail (!group->active, FALSE); |
1660 |
2517 |
|
2518 GST_DEBUG_OBJECT (playbin, "activating group %p", group); |
|
2519 |
|
2520 GST_SOURCE_GROUP_LOCK (group); |
1661 if (group->uridecodebin) { |
2521 if (group->uridecodebin) { |
|
2522 GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin"); |
|
2523 REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id); |
|
2524 REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id); |
|
2525 REMOVE_SIGNAL (group->uridecodebin, group->no_more_pads_id); |
|
2526 REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id); |
|
2527 REMOVE_SIGNAL (group->uridecodebin, group->drained_id); |
|
2528 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id); |
|
2529 REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id); |
1662 gst_element_set_state (group->uridecodebin, GST_STATE_NULL); |
2530 gst_element_set_state (group->uridecodebin, GST_STATE_NULL); |
1663 gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin); |
2531 uridecodebin = group->uridecodebin; |
1664 group->uridecodebin = NULL; |
2532 } else { |
1665 } |
2533 GST_DEBUG_OBJECT (playbin, "making new uridecodebin"); |
1666 |
2534 uridecodebin = gst_element_factory_make ("uridecodebin", NULL); |
1667 uridecodebin = gst_element_factory_make ("uridecodebin", NULL); |
2535 if (!uridecodebin) |
1668 if (!uridecodebin) |
2536 goto no_decodebin; |
1669 goto no_decodebin; |
2537 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin); |
|
2538 group->uridecodebin = uridecodebin; |
|
2539 } |
1670 |
2540 |
1671 /* configure connection speed */ |
2541 /* configure connection speed */ |
1672 g_object_set (uridecodebin, "connection-speed", playbin->connection_speed, |
2542 g_object_set (uridecodebin, "connection-speed", |
1673 NULL); |
2543 playbin->connection_speed / 1000, NULL); |
|
2544 if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_DOWNLOAD) |
|
2545 g_object_set (uridecodebin, "download", TRUE, NULL); |
|
2546 else |
|
2547 g_object_set (uridecodebin, "download", FALSE, NULL); |
|
2548 /* configure subtitle encoding */ |
|
2549 g_object_set (uridecodebin, "subtitle-encoding", playbin->encoding, NULL); |
1674 /* configure uri */ |
2550 /* configure uri */ |
1675 g_object_set (uridecodebin, "uri", group->uri, NULL); |
2551 g_object_set (uridecodebin, "uri", group->uri, NULL); |
|
2552 g_object_set (uridecodebin, "buffer-duration", playbin->buffer_duration, |
|
2553 NULL); |
|
2554 g_object_set (uridecodebin, "buffer-size", playbin->buffer_size, NULL); |
1676 |
2555 |
1677 /* connect pads and other things */ |
2556 /* connect pads and other things */ |
1678 g_signal_connect (uridecodebin, "pad-added", G_CALLBACK (pad_added_cb), |
2557 group->pad_added_id = g_signal_connect (uridecodebin, "pad-added", |
1679 group); |
2558 G_CALLBACK (pad_added_cb), group); |
1680 g_signal_connect (uridecodebin, "pad-removed", G_CALLBACK (pad_removed_cb), |
2559 group->pad_removed_id = g_signal_connect (uridecodebin, "pad-removed", |
1681 group); |
2560 G_CALLBACK (pad_removed_cb), group); |
1682 g_signal_connect (uridecodebin, "no-more-pads", G_CALLBACK (no_more_pads_cb), |
2561 group->no_more_pads_id = g_signal_connect (uridecodebin, "no-more-pads", |
1683 group); |
2562 G_CALLBACK (no_more_pads_cb), group); |
|
2563 group->notify_source_id = g_signal_connect (uridecodebin, "notify::source", |
|
2564 G_CALLBACK (notify_source_cb), group); |
|
2565 /* we have 1 pending no-more-pads */ |
|
2566 group->pending = 1; |
|
2567 |
1684 /* is called when the uridecodebin is out of data and we can switch to the |
2568 /* is called when the uridecodebin is out of data and we can switch to the |
1685 * next uri */ |
2569 * next uri */ |
1686 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb), group); |
2570 group->drained_id = |
|
2571 g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb), |
|
2572 group); |
1687 |
2573 |
1688 /* will be called when a new media type is found. We return a list of decoders |
2574 /* will be called when a new media type is found. We return a list of decoders |
1689 * including sinks for decodebin to try */ |
2575 * including sinks for decodebin to try */ |
1690 g_signal_connect (uridecodebin, "autoplug-factories", |
2576 group->autoplug_factories_id = |
|
2577 g_signal_connect (uridecodebin, "autoplug-factories", |
1691 G_CALLBACK (autoplug_factories_cb), group); |
2578 G_CALLBACK (autoplug_factories_cb), group); |
1692 |
2579 group->autoplug_select_id = g_signal_connect (uridecodebin, "autoplug-select", |
1693 g_signal_connect (uridecodebin, "autoplug-select", |
|
1694 G_CALLBACK (autoplug_select_cb), group); |
2580 G_CALLBACK (autoplug_select_cb), group); |
1695 |
2581 |
1696 /* */ |
2582 if (group->suburi) { |
1697 gst_bin_add (GST_BIN_CAST (playbin), uridecodebin); |
2583 /* subtitles */ |
1698 group->uridecodebin = uridecodebin; |
2584 if (group->suburidecodebin) { |
1699 |
2585 GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin"); |
1700 gst_element_set_state (uridecodebin, GST_STATE_PAUSED); |
2586 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_added_id); |
1701 |
2587 REMOVE_SIGNAL (group->suburidecodebin, group->sub_pad_removed_id); |
|
2588 REMOVE_SIGNAL (group->suburidecodebin, group->sub_no_more_pads_id); |
|
2589 gst_element_set_state (group->suburidecodebin, GST_STATE_NULL); |
|
2590 suburidecodebin = group->suburidecodebin; |
|
2591 } else { |
|
2592 GST_DEBUG_OBJECT (playbin, "making new suburidecodebin"); |
|
2593 suburidecodebin = gst_element_factory_make ("uridecodebin", NULL); |
|
2594 if (!suburidecodebin) |
|
2595 goto no_decodebin; |
|
2596 |
|
2597 gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin); |
|
2598 group->suburidecodebin = suburidecodebin; |
|
2599 } |
|
2600 |
|
2601 /* configure connection speed */ |
|
2602 g_object_set (suburidecodebin, "connection-speed", |
|
2603 playbin->connection_speed, NULL); |
|
2604 /* configure subtitle encoding */ |
|
2605 g_object_set (suburidecodebin, "subtitle-encoding", playbin->encoding, |
|
2606 NULL); |
|
2607 /* configure uri */ |
|
2608 g_object_set (suburidecodebin, "uri", group->suburi, NULL); |
|
2609 |
|
2610 /* connect pads and other things */ |
|
2611 group->sub_pad_added_id = g_signal_connect (suburidecodebin, "pad-added", |
|
2612 G_CALLBACK (pad_added_cb), group); |
|
2613 group->sub_pad_removed_id = g_signal_connect (suburidecodebin, |
|
2614 "pad-removed", G_CALLBACK (pad_removed_cb), group); |
|
2615 group->sub_no_more_pads_id = g_signal_connect (suburidecodebin, |
|
2616 "no-more-pads", G_CALLBACK (no_more_pads_cb), group); |
|
2617 |
|
2618 /* we have 2 pending no-more-pads */ |
|
2619 group->pending = 2; |
|
2620 } |
|
2621 |
|
2622 /* release the group lock before setting the state of the decodebins, they |
|
2623 * might fire signals in this thread that we need to handle with the |
|
2624 * group_lock taken. */ |
|
2625 GST_SOURCE_GROUP_UNLOCK (group); |
|
2626 |
|
2627 if (suburidecodebin) { |
|
2628 if (gst_element_set_state (suburidecodebin, |
|
2629 target) == GST_STATE_CHANGE_FAILURE) |
|
2630 goto suburidecodebin_failure; |
|
2631 } |
|
2632 if (gst_element_set_state (uridecodebin, target) == GST_STATE_CHANGE_FAILURE) |
|
2633 goto uridecodebin_failure; |
|
2634 |
|
2635 GST_SOURCE_GROUP_LOCK (group); |
|
2636 /* alow state changes of the playbin2 affect the group elements now */ |
|
2637 group_set_locked_state_unlocked (playbin, group, FALSE); |
1702 group->active = TRUE; |
2638 group->active = TRUE; |
|
2639 GST_SOURCE_GROUP_UNLOCK (group); |
1703 |
2640 |
1704 return TRUE; |
2641 return TRUE; |
1705 |
2642 |
1706 /* ERRORS */ |
2643 /* ERRORS */ |
1707 no_decodebin: |
2644 no_decodebin: |
1708 { |
2645 { |
|
2646 GST_SOURCE_GROUP_UNLOCK (group); |
1709 return FALSE; |
2647 return FALSE; |
1710 } |
2648 } |
1711 } |
2649 suburidecodebin_failure: |
1712 |
2650 { |
1713 /* unlink a group of uridecodebins from the sink */ |
2651 GST_DEBUG_OBJECT (playbin, "failed state change of subtitle uridecodebin"); |
|
2652 return FALSE; |
|
2653 } |
|
2654 uridecodebin_failure: |
|
2655 { |
|
2656 GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin"); |
|
2657 return FALSE; |
|
2658 } |
|
2659 } |
|
2660 |
|
2661 /* unlink a group of uridecodebins from the sink. |
|
2662 * must be called with PLAY_BIN_LOCK */ |
1714 static gboolean |
2663 static gboolean |
1715 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group) |
2664 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group) |
1716 { |
2665 { |
1717 gint i; |
2666 gint i; |
1718 |
2667 |
1719 g_return_val_if_fail (group->valid, FALSE); |
2668 g_return_val_if_fail (group->valid, FALSE); |
1720 g_return_val_if_fail (group->active, FALSE); |
2669 g_return_val_if_fail (group->active, FALSE); |
1721 |
2670 |
1722 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group); |
2671 GST_DEBUG_OBJECT (playbin, "unlinking group %p", group); |
1723 |
2672 |
|
2673 GST_SOURCE_GROUP_LOCK (group); |
|
2674 group->active = FALSE; |
1724 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
2675 for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) { |
1725 GstSourceSelect *select = &group->selector[i]; |
2676 GstSourceSelect *select = &group->selector[i]; |
1726 |
2677 |
1727 if (!select->selector) |
2678 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media_list[0]); |
1728 continue; |
2679 |
1729 |
2680 if (select->srcpad) { |
1730 GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media); |
2681 if (select->sinkpad) { |
1731 gst_pad_unlink (select->srcpad, select->sinkpad); |
2682 GST_LOG_OBJECT (playbin, "unlinking from sink"); |
1732 |
2683 gst_pad_unlink (select->srcpad, select->sinkpad); |
1733 /* release back */ |
2684 |
1734 gst_play_sink_release_pad (playbin->playsink, select->sinkpad); |
2685 /* release back */ |
1735 select->sinkpad = NULL; |
2686 GST_LOG_OBJECT (playbin, "release sink pad"); |
1736 |
2687 gst_play_sink_release_pad (playbin->playsink, select->sinkpad); |
1737 gst_object_unref (select->srcpad); |
2688 select->sinkpad = NULL; |
1738 select->srcpad = NULL; |
2689 } |
1739 |
2690 gst_object_unref (select->srcpad); |
1740 gst_element_set_state (select->selector, GST_STATE_NULL); |
2691 select->srcpad = NULL; |
1741 gst_bin_remove (GST_BIN_CAST (playbin), select->selector); |
2692 } |
1742 select->selector = NULL; |
2693 |
1743 } |
2694 if (select->selector) { |
1744 group->active = FALSE; |
2695 gst_element_set_state (select->selector, GST_STATE_NULL); |
|
2696 gst_bin_remove (GST_BIN_CAST (playbin), select->selector); |
|
2697 select->selector = NULL; |
|
2698 } |
|
2699 } |
|
2700 /* delete any custom sinks we might have */ |
|
2701 if (group->audio_sink) |
|
2702 gst_object_unref (group->audio_sink); |
|
2703 group->audio_sink = NULL; |
|
2704 if (group->video_sink) |
|
2705 gst_object_unref (group->video_sink); |
|
2706 group->video_sink = NULL; |
|
2707 /* we still have the decodebins added to the playbin2 but we can't remove them |
|
2708 * yet or change their state because this function might be called from the |
|
2709 * streaming threads, instead block the state so that state changes on the |
|
2710 * playbin2 don't affect us anymore */ |
|
2711 group_set_locked_state_unlocked (playbin, group, TRUE); |
|
2712 GST_SOURCE_GROUP_UNLOCK (group); |
1745 |
2713 |
1746 return TRUE; |
2714 return TRUE; |
1747 } |
2715 } |
1748 |
2716 |
1749 /* setup the next group to play, this assumes the next_group is valid and |
2717 /* setup the next group to play, this assumes the next_group is valid and |
1750 * configured. It swaps out the current_group and activates the valid |
2718 * configured. It swaps out the current_group and activates the valid |
1751 * next_group. */ |
2719 * next_group. */ |
1752 static gboolean |
2720 static gboolean |
1753 setup_next_source (GstPlayBin * playbin) |
2721 setup_next_source (GstPlayBin * playbin, GstState target) |
1754 { |
2722 { |
1755 GstSourceGroup *new_group, *old_group; |
2723 GstSourceGroup *new_group, *old_group; |
1756 |
2724 |
1757 GST_DEBUG_OBJECT (playbin, "setup sources"); |
2725 GST_DEBUG_OBJECT (playbin, "setup sources"); |
1758 |
2726 |
1759 /* see if there is a next group */ |
2727 /* see if there is a next group */ |
|
2728 GST_PLAY_BIN_LOCK (playbin); |
1760 new_group = playbin->next_group; |
2729 new_group = playbin->next_group; |
1761 if (!new_group || !new_group->valid) |
2730 if (!new_group || !new_group->valid) |
1762 goto no_next_group; |
2731 goto no_next_group; |
1763 |
2732 |
1764 /* first unlink the current source, if any */ |
2733 /* first unlink the current source, if any */ |