2 * Copyright (C) 2008 Rov Juvano <rovjuvano@users.sourceforge.net>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "demo-player.h"
22 #define G_LOG_DOMAIN "demo-player"
28 SIGNAL_PLAYING_STARTED
,
29 SIGNAL_PLAYING_PAUSED
,
33 static guint demo_player_signals
[LAST_SIGNAL
] = { 0 };
45 typedef struct _DemoPlayerPrivate
48 GstElement
*scaletempo
;
51 GstElement
*scaletempo_line
;
52 GstElement
*scalerate_line
;
53 gboolean ignore_state_change
;
56 #define DEMO_PLAYER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEMO_TYPE_PLAYER, DemoPlayerPrivate))
60 no_pipeline (DemoPlayer
*player
)
62 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
63 if (!priv
->pipeline
) {
64 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "No media loaded");
71 demo_player_event_listener (GstElement
*host
,
75 DemoPlayer
*player
= DEMO_PLAYER (data
);
76 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
78 if (GST_EVENT_TYPE (event
) == GST_EVENT_NEWSEGMENT
) {
79 gdouble rate
, applied_rate
;
80 gst_event_parse_new_segment_full (event
, NULL
, &rate
, &applied_rate
, NULL
, NULL
, NULL
, NULL
);
81 gdouble new_rate
= rate
* applied_rate
;
82 if (priv
->rate
!= new_rate
) {
83 priv
->rate
= new_rate
;
84 g_signal_emit (player
, demo_player_signals
[SIGNAL_RATE_CHANGE
], 0, new_rate
);
92 demo_player_state_changed_cb (GstBus
*bus
,
96 DemoPlayer
*player
= DEMO_PLAYER (data
);
97 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
99 if ( GST_ELEMENT (GST_MESSAGE_SRC (message
)) != priv
->pipeline
)
102 GstState old
, new, pending
;
103 gst_message_parse_state_changed (message
, &old
, &new, &pending
);
105 if (pending
== GST_STATE_VOID_PENDING
) {
106 if (priv
->ignore_state_change
) {
107 priv
->ignore_state_change
= FALSE
;
108 } else if (new == GST_STATE_PAUSED
) {
109 g_signal_emit (player
, demo_player_signals
[SIGNAL_PLAYING_PAUSED
], 0);
110 } else if (new == GST_STATE_PLAYING
) {
111 g_signal_emit (player
, demo_player_signals
[SIGNAL_PLAYING_STARTED
], 0);
117 demo_player_eos_cb (GstBus
*bus
,
121 DemoPlayer
*player
= DEMO_PLAYER (data
);
122 g_signal_emit (player
, demo_player_signals
[SIGNAL_PLAYING_ENDED
], 0);
125 #define MAKE_ELEMENT(line, var, type, name) \
126 if ( !(var = gst_element_factory_make (type, name) ) ) { \
127 g_print ("element could not be created: %s/%s\n", type, name); \
130 if (line) gst_bin_add (GST_BIN (line), var);
132 #define LINK_ELEMENTS(src, sink) \
133 if (!gst_element_link (src, sink)) { \
134 g_warning ("Failed to link elements: %s -> %s", \
135 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink) ); \
140 demo_player_build_pipeline (DemoPlayer
*player
)
142 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
143 priv
->pipeline
= NULL
;
144 if (!priv
->scaletempo
) {
147 GstElement
*filter
= priv
->scaletempo
;
149 GstElement
*playbin
, *vsink
;
151 MAKE_ELEMENT (NULL
, playbin
, "playbin", "playbin");
153 GstPlugin
*gconf
= gst_default_registry_find_plugin ("gconfelements");
154 gboolean has_gconf
= (gconf
!= NULL
);
155 gst_object_unref (gconf
);
158 MAKE_ELEMENT (NULL
, vsink
, "gconfvideosink", "vsink");
159 g_object_set (G_OBJECT (playbin
), "video_sink", vsink
, NULL
);
161 const gchar
*audiosink_name
= has_gconf
? "gconfaudiosink" : "autoaudiosink";
163 GstElement
*audioline
= gst_bin_new ("audioline");
164 GstElement
*format
, *resample
, *asink
;
165 gst_bin_add (GST_BIN (audioline
), filter
);
166 MAKE_ELEMENT (audioline
, format
, "audioconvert", "format");
167 MAKE_ELEMENT (audioline
, resample
, "audioresample", "resample");
168 MAKE_ELEMENT (audioline
, asink
, audiosink_name
, "audio_sink");
169 LINK_ELEMENTS (filter
, format
);
170 LINK_ELEMENTS (format
, resample
);
171 LINK_ELEMENTS (resample
, asink
);
173 gst_pad_add_event_probe (gst_element_get_pad (asink
, "sink"), G_CALLBACK (demo_player_event_listener
), player
);
175 GstPad
*ghostpad
= gst_element_get_pad (filter
, "sink");
176 gst_element_add_pad (audioline
, gst_ghost_pad_new ("sink", ghostpad
));
177 gst_object_unref (ghostpad
);
178 g_object_set (G_OBJECT (playbin
), "audio-sink", audioline
, NULL
);
180 GstBus
*bus
= gst_pipeline_get_bus (GST_PIPELINE (playbin
));
181 gst_bus_add_signal_watch (bus
);
182 g_signal_connect (bus
, "message::state-changed", G_CALLBACK (demo_player_state_changed_cb
), player
);
183 g_signal_connect (bus
, "message::eos", G_CALLBACK (demo_player_eos_cb
), player
);
184 gst_object_unref (bus
);
186 priv
->scaletempo
= filter
;
187 priv
->pipeline
= playbin
;
189 priv
->scaletempo_line
= audioline
;
190 MAKE_ELEMENT (NULL
, priv
->scalerate_line
, "gconfaudiosink", "scaling_audio_sink");
191 gst_pad_add_event_probe (gst_element_get_pad (priv
->scalerate_line
, "sink"),
192 G_CALLBACK (demo_player_event_listener
), player
);
193 g_object_ref (priv
->scaletempo_line
);
194 g_object_ref (priv
->scalerate_line
);
198 /* method implementations */
200 _set_rate (DemoPlayer
*player
,
205 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Cannot set playback to zero. Pausing instead.");
206 demo_player_pause (player
);
209 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
212 GstSeekType seek_type
;
214 GstFormat fmt
= GST_FORMAT_TIME
;
215 seek_type
= GST_SEEK_TYPE_SET
;
216 if ( !gst_element_query_position (priv
->pipeline
, &fmt
, &pos
) ) {
217 // This should be the default but too many upstream elements seek anyway
218 pos
= GST_CLOCK_TIME_NONE
;
219 seek_type
= GST_SEEK_TYPE_NONE
;
222 seek_type
= GST_SEEK_TYPE_SET
;
223 pos
= second
* GST_SECOND
;
226 if (!gst_element_seek (priv
->pipeline
, new_rate
,
227 GST_FORMAT_TIME
, GST_SEEK_FLAG_FLUSH
| GST_SEEK_FLAG_ACCURATE
,
229 GST_SEEK_TYPE_NONE
, GST_CLOCK_TIME_NONE
)) {
230 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Unable to change playback rate");
232 priv
->ignore_state_change
= TRUE
;
237 demo_player_scale_rate_func (DemoPlayer
*player
,
240 if (no_pipeline (player
)) return;
242 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
245 g_message ("Scaling Rate by: %3.2f", scale
);
246 _set_rate (player
, priv
->rate
* scale
, -1);
251 demo_player_set_rate_func (DemoPlayer
*player
,
254 if (no_pipeline (player
)) return;
256 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
258 if (priv
->rate
!= new_rate
) {
259 g_message ("Setting Rate to: %3.2f", new_rate
);
260 _set_rate (player
, new_rate
, -1);
265 _set_state_and_wait (DemoPlayer
*player
,
267 GstClockTime timeout
,
268 const gchar
* error_msg
)
270 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
271 GstStateChangeReturn ret
= gst_element_set_state (priv
->pipeline
, new_state
);
272 if (ret
== GST_STATE_CHANGE_ASYNC
) {
273 ret
= gst_element_get_state (priv
->pipeline
, NULL
, NULL
, timeout
);
275 if (ret
!= GST_STATE_CHANGE_SUCCESS
) {
276 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, error_msg
);
283 demo_player_load_uri_func (DemoPlayer
*player
,
286 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
287 if (!priv
->pipeline
) {
288 demo_player_build_pipeline (player
);
289 if (!priv
->pipeline
) {
290 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Could not build player");
294 if (!g_str_has_prefix (uri
, "file:///")) {
296 if (g_path_is_absolute (uri
)) {
297 uri
= g_filename_to_uri (uri
, NULL
, &err
);
299 gchar
*curdir
= g_get_current_dir ();
300 gchar
*absolute_path
= g_strconcat (curdir
, G_DIR_SEPARATOR_S
, uri
, NULL
);
301 uri
= g_filename_to_uri (absolute_path
, NULL
, &err
);
302 g_free (absolute_path
);
306 gchar
*msg
= g_strconcat ("Could not load uri: ", err
->message
, NULL
);
307 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, msg
);
312 g_message ("Loading URI: %s", uri
);
314 GstState end_state
= (GST_STATE (priv
->pipeline
) == GST_STATE_PLAYING
) ? GST_STATE_PLAYING
: GST_STATE_PAUSED
;
315 if (!_set_state_and_wait (player
, GST_STATE_NULL
, 10 * GST_SECOND
, "Unable to load uri"))
318 g_object_set (G_OBJECT (priv
->pipeline
), "uri", uri
, NULL
);
320 gdouble rate
= priv
->rate
;
321 if (rate
&& rate
!= 1.0) {
322 _set_state_and_wait (player
, GST_STATE_PAUSED
, 10 * GST_SECOND
, "Unable to keep playback rate");
323 _set_rate (player
, rate
, -1);
326 gst_element_set_state (priv
->pipeline
, end_state
);
330 demo_player_play_func (DemoPlayer
*player
)
332 if (no_pipeline (player
)) return;
334 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
336 if (GST_STATE (priv
->pipeline
) == GST_STATE_PLAYING
) {
337 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Already playing");
341 g_debug ("Starting to Play");
342 GstStateChangeReturn ret
= gst_element_set_state (priv
->pipeline
, GST_STATE_PLAYING
);
343 if (ret
== GST_STATE_CHANGE_FAILURE
) {
344 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Unable to start playback");
350 demo_player_pause_func (DemoPlayer
*player
)
352 if (no_pipeline (player
)) return;
354 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
356 if (GST_STATE (priv
->pipeline
) == GST_STATE_PAUSED
) {
357 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Already paused");
361 g_debug ("Starting to Pause");
362 GstStateChangeReturn ret
= gst_element_set_state (priv
->pipeline
, GST_STATE_PAUSED
);
363 if (ret
== GST_STATE_CHANGE_FAILURE
) {
364 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Unable to pause playback");
370 _seek_to (DemoPlayer
*player
,
373 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
374 if (!gst_element_seek (priv
->pipeline
, priv
->rate
,
375 GST_FORMAT_TIME
, GST_SEEK_FLAG_FLUSH
,
376 GST_SEEK_TYPE_SET
, new_second
* GST_SECOND
,
377 GST_SEEK_TYPE_NONE
, GST_CLOCK_TIME_NONE
)) {
378 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Seek failed");
382 priv
->ignore_state_change
= TRUE
;
386 demo_player_seek_by_func (DemoPlayer
*player
,
389 if (no_pipeline (player
)) return;
391 g_debug ("Seeking by: %i", seconds
);
393 gint pos
= demo_player_get_position (player
);
395 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Seek-by failed: could not determine position");
399 _seek_to (player
, MAX (0, pos
+ seconds
));
403 demo_player_seek_to_func (DemoPlayer
*player
,
406 if (no_pipeline (player
)) return;
408 g_debug ("Seeking to: %i", second
);
413 gint dur
= demo_player_get_duration (player
);
415 g_signal_emit (player
, demo_player_signals
[SIGNAL_ERROR
], 0, "Seek-to failed: could not determine duration");
418 new_second
= MAX (0, dur
+ second
);
423 _seek_to (player
, new_second
);
427 demo_player_get_position_func (DemoPlayer
*player
)
429 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
430 if (!priv
->pipeline
) return -1;
433 GstFormat fmt
= GST_FORMAT_TIME
;
434 if ( !gst_element_query_position (priv
->pipeline
, &fmt
, &pos
) || pos
< 0) {
438 return (gint
)(pos
/ GST_SECOND
);
442 demo_player_get_duration_func (DemoPlayer
*player
)
444 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
445 if (!priv
->pipeline
) return -1;
448 GstFormat fmt
= GST_FORMAT_TIME
;
449 if ( !gst_element_query_duration (priv
->pipeline
, &fmt
, &dur
) || dur
< 0) {
453 return (gint
)(dur
/ GST_SECOND
);
457 /* Method wrappers */
459 demo_player_scale_rate (DemoPlayer
*player
,
462 g_return_if_fail (DEMO_IS_PLAYER (player
));
464 DEMO_PLAYER_GET_CLASS (player
)->scale_rate (player
, scale
);
468 demo_player_set_rate (DemoPlayer
*player
,
471 g_return_if_fail (DEMO_IS_PLAYER (player
));
473 DEMO_PLAYER_GET_CLASS (player
)->set_rate (player
, new_rate
);
477 demo_player_load_uri (DemoPlayer
*player
,
480 g_return_if_fail (DEMO_IS_PLAYER (player
));
482 DEMO_PLAYER_GET_CLASS (player
)->load_uri (player
, uri
);
486 demo_player_play (DemoPlayer
*player
)
488 g_return_if_fail (DEMO_IS_PLAYER (player
));
490 DEMO_PLAYER_GET_CLASS (player
)->play (player
);
494 demo_player_pause (DemoPlayer
*player
)
496 g_return_if_fail (DEMO_IS_PLAYER (player
));
498 DEMO_PLAYER_GET_CLASS (player
)->pause (player
);
502 demo_player_seek_by (DemoPlayer
*player
,
505 g_return_if_fail (DEMO_IS_PLAYER (player
));
507 DEMO_PLAYER_GET_CLASS (player
)->seek_by (player
, seconds
);
511 demo_player_seek_to (DemoPlayer
*player
,
514 g_return_if_fail (DEMO_IS_PLAYER (player
));
516 DEMO_PLAYER_GET_CLASS (player
)->seek_to (player
, second
);
520 demo_player_get_position (DemoPlayer
*player
)
522 g_return_val_if_fail (DEMO_IS_PLAYER (player
), -1);
524 return DEMO_PLAYER_GET_CLASS (player
)->get_position (player
);
528 demo_player_get_duration (DemoPlayer
*player
)
530 g_return_val_if_fail (DEMO_IS_PLAYER (player
), -1);
532 return DEMO_PLAYER_GET_CLASS (player
)->get_duration (player
);
535 /* GObject overrides */
537 demo_player_get_property (GObject
*object
,
542 DemoPlayer
*player
= DEMO_PLAYER (object
);
543 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
544 switch (property_id
) {
546 g_value_set_double (value
, priv
->rate
);
549 g_object_get_property (G_OBJECT (priv
->scaletempo
), "stride", value
);
552 g_object_get_property (G_OBJECT (priv
->scaletempo
), "overlap", value
);
555 g_object_get_property (G_OBJECT (priv
->scaletempo
), "search", value
);
558 g_value_set_boolean (value
, priv
->is_disabled
);
561 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
567 demo_player_set_property (GObject
*object
,
572 DemoPlayer
*player
= DEMO_PLAYER (object
);
573 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
574 switch (property_id
) {
576 g_object_set_property (G_OBJECT (priv
->scaletempo
), "stride", value
);
579 g_object_set_property (G_OBJECT (priv
->scaletempo
), "overlap", value
);
582 g_object_set_property (G_OBJECT (priv
->scaletempo
), "search", value
);
584 case PROP_DISABLED
: {
585 priv
->is_disabled
= g_value_get_boolean (value
);
586 g_debug ("Scaletempo: %s", priv
->is_disabled
? "disabled" : "enabled");
588 gdouble rate
= priv
->rate
;
589 gint pos
= demo_player_get_position (player
);
591 GstState end_state
= (GST_STATE (priv
->pipeline
) == GST_STATE_PLAYING
) ? GST_STATE_PLAYING
: GST_STATE_PAUSED
;
592 if (!_set_state_and_wait (player
, GST_STATE_NULL
, 10 * GST_SECOND
, "Unable to disable"))
595 GstElement
*new_sink
= (priv
->is_disabled
) ? priv
->scalerate_line
: priv
->scaletempo_line
;
596 g_object_set (G_OBJECT (priv
->pipeline
), "audio-sink", new_sink
, NULL
);
598 if (pos
> 0 || (rate
&& rate
!= 1.0)) {
599 _set_state_and_wait (player
, GST_STATE_PAUSED
, 10 * GST_SECOND
, "Unable to keep playback position and rate");
600 _set_rate (player
, rate
, pos
);
603 gst_element_set_state (priv
->pipeline
, end_state
);
607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
613 /* GTypeInfo functions */
615 demo_player_init (GTypeInstance
*instance
,
618 DemoPlayer
*player
= (DemoPlayer
*)instance
;
619 DemoPlayerPrivate
*priv
= DEMO_PLAYER_GET_PRIVATE (player
);
620 priv
->scaletempo
= gst_element_factory_make ("scaletempo", "scaletempo");
621 if (!priv
->scaletempo
) {
622 g_error ("Unable to make scaletempo element.");
625 priv
->pipeline
= NULL
;
626 priv
->ignore_state_change
= FALSE
;
627 priv
->is_disabled
= FALSE
;
631 demo_player_class_init (gpointer klass
,
634 g_type_class_add_private (klass
, sizeof (DemoPlayerPrivate
));
637 DemoPlayerClass
*player_class
= (DemoPlayerClass
*)klass
;
638 player_class
->scale_rate
= demo_player_scale_rate_func
;
639 player_class
->set_rate
= demo_player_set_rate_func
;
640 player_class
->load_uri
= demo_player_load_uri_func
;
641 player_class
->play
= demo_player_play_func
;
642 player_class
->pause
= demo_player_pause_func
;
643 player_class
->seek_by
= demo_player_seek_by_func
;
644 player_class
->seek_to
= demo_player_seek_to_func
;
645 player_class
->get_position
= demo_player_get_position_func
;
646 player_class
->get_duration
= demo_player_get_duration_func
;
649 GObjectClass
*as_object_class
= G_OBJECT_CLASS (klass
);
650 as_object_class
->get_property
= demo_player_get_property
;
651 as_object_class
->set_property
= demo_player_set_property
;
654 g_object_class_install_property (as_object_class
, PROP_RATE
,
655 g_param_spec_double ("rate", "Rate", "Current playback rate",
656 -128, 128, 1.0, G_PARAM_READABLE
));
658 g_object_class_install_property (as_object_class
, PROP_STRIDE
,
659 g_param_spec_uint ("stride", "Stride Length", "Length in milliseconds to output each stride",
660 1, 10000, 60, G_PARAM_READWRITE
));
662 g_object_class_install_property (as_object_class
, PROP_OVERLAP
,
663 g_param_spec_double ("overlap", "Overlap Length", "Percentage of stride to overlap",
664 0, 1, .2, G_PARAM_READWRITE
));
666 g_object_class_install_property (as_object_class
, PROP_SEARCH
,
667 g_param_spec_uint ("search", "Search Length", "Length in milliseconds to search for best overlap position",
668 0, 10000, 14, G_PARAM_READWRITE
));
670 g_object_class_install_property (as_object_class
, PROP_DISABLED
,
671 g_param_spec_boolean ("disabled", "disable scaletempo", "Disable scaletempo and scale bothe tempo and pitch",
672 FALSE
, G_PARAM_READWRITE
));
675 GType type
= G_TYPE_FROM_CLASS (klass
);
676 demo_player_signals
[SIGNAL_ERROR
] = g_signal_new ("error", type
,
677 G_SIGNAL_RUN_FIRST
, 0, NULL
, NULL
,
678 g_cclosure_marshal_VOID__STRING
, G_TYPE_NONE
, 1, G_TYPE_STRING
);
680 demo_player_signals
[SIGNAL_RATE_CHANGE
] = g_signal_new ("rate-changed", type
,
681 G_SIGNAL_RUN_FIRST
, 0, NULL
, NULL
,
682 g_cclosure_marshal_VOID__DOUBLE
, G_TYPE_NONE
, 1, G_TYPE_DOUBLE
);
684 demo_player_signals
[SIGNAL_PLAYING_STARTED
] = g_signal_new ("playing-started", type
,
685 G_SIGNAL_RUN_FIRST
, 0, NULL
, NULL
,
686 g_cclosure_marshal_VOID__VOID
, G_TYPE_NONE
, 0);
688 demo_player_signals
[SIGNAL_PLAYING_PAUSED
] = g_signal_new ("playing-paused", type
,
689 G_SIGNAL_RUN_FIRST
, 0, NULL
, NULL
,
690 g_cclosure_marshal_VOID__VOID
, G_TYPE_NONE
, 0);
692 demo_player_signals
[SIGNAL_PLAYING_ENDED
] = g_signal_new ("playing-ended", type
,
693 G_SIGNAL_RUN_FIRST
, 0, NULL
, NULL
,
694 g_cclosure_marshal_VOID__VOID
, G_TYPE_NONE
, 0);
698 demo_player_get_type (void)
700 static GType type
= 0;
701 if (G_UNLIKELY (type
== 0)) {
702 static const GTypeInfo info
= {
703 sizeof /* Class */ (DemoPlayerClass
),
704 (GBaseInitFunc
) NULL
,
705 (GBaseFinalizeFunc
) NULL
,
706 (GClassInitFunc
) demo_player_class_init
,
707 (GClassFinalizeFunc
) NULL
,
708 (gconstpointer
) NULL
, /* class_data */
709 sizeof /* Instance */ (DemoPlayer
),
711 (GInstanceInitFunc
) demo_player_init
,
712 (const GTypeValueTable
*) NULL
714 type
= g_type_register_static (G_TYPE_OBJECT
, "DemoPlayer", &info
, 0);