gst_plugins_base/tests/examples/seek/seek.c
changeset 2 5505e8908944
parent 0 0e761a78d257
equal deleted inserted replaced
1:4c282e7dd6d3 2:5505e8908944
       
     1 /* GStreamer
       
     2  *
       
     3  * seek.c: seeking sample application
       
     4  *
       
     5  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
       
     6  *               2006 Stefan Kost <ensonic@users.sf.net>
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Library General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Library General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Library General Public
       
    19  * License along with this library; if not, write to the
       
    20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    21  * Boston, MA 02111-1307, USA.
       
    22  */
       
    23 /* FIXME: remove #if 0 code
       
    24  *
       
    25  */
       
    26 #include <stdlib.h>
       
    27 #include <glib.h>
       
    28 #include <gtk/gtk.h>
       
    29 #include <gst/gst.h>
       
    30 #include <string.h>
       
    31 
       
    32 GST_DEBUG_CATEGORY_STATIC (seek_debug);
       
    33 #define GST_CAT_DEFAULT (seek_debug)
       
    34 
       
    35 /* configuration */
       
    36 
       
    37 //#define SOURCE "filesrc"
       
    38 #define SOURCE "gnomevfssrc"
       
    39 
       
    40 #define ASINK "alsasink"
       
    41 //#define ASINK "osssink"
       
    42 
       
    43 #define VSINK "xvimagesink"
       
    44 //#define VSINK "sdlvideosink"
       
    45 //#define VSINK "ximagesink"
       
    46 //#define VSINK "aasink"
       
    47 //#define VSINK "cacasink"
       
    48 
       
    49 //#define UPDATE_INTERVAL 500
       
    50 //#define UPDATE_INTERVAL 100
       
    51 #define UPDATE_INTERVAL 10
       
    52 
       
    53 /* number of milliseconds to play for after a seek */
       
    54 #define SCRUB_TIME 100
       
    55 
       
    56 /* timeout for gst_element_get_state() after a seek */
       
    57 #define SEEK_TIMEOUT 40 * GST_MSECOND
       
    58 
       
    59 
       
    60 static GList *seekable_pads = NULL;
       
    61 static GList *rate_pads = NULL;
       
    62 static GList *seekable_elements = NULL;
       
    63 
       
    64 static gboolean accurate_seek = FALSE;
       
    65 static gboolean keyframe_seek = FALSE;
       
    66 static gboolean loop_seek = FALSE;
       
    67 static gboolean flush_seek = TRUE;
       
    68 static gboolean scrub = TRUE;
       
    69 static gboolean play_scrub = FALSE;
       
    70 static gdouble rate = 1.0;
       
    71 
       
    72 static GstElement *pipeline;
       
    73 static gint pipeline_type;
       
    74 static const gchar *pipeline_spec;
       
    75 static gint64 position = -1;
       
    76 static gint64 duration = -1;
       
    77 static GtkAdjustment *adjustment;
       
    78 static GtkWidget *hscale;
       
    79 static gboolean stats = FALSE;
       
    80 static gboolean elem_seek = FALSE;
       
    81 static gboolean verbose = FALSE;
       
    82 
       
    83 static GstState state = GST_STATE_NULL;
       
    84 static guint update_id = 0;
       
    85 static guint seek_timeout_id = 0;
       
    86 static gulong changed_id;
       
    87 
       
    88 static gint n_video = 0, n_audio = 0, n_text = 0;
       
    89 static gboolean need_streams = TRUE;
       
    90 static GtkWidget *video_combo, *audio_combo, *text_combo, *vis_combo;
       
    91 static GtkWidget *vis_checkbox, *video_checkbox, *audio_checkbox;
       
    92 static GtkWidget *text_checkbox, *mute_checkbox, *volume_spinbutton;
       
    93 
       
    94 /* we keep an array of the visualisation entries so that we can easily switch
       
    95  * with the combo box index. */
       
    96 typedef struct
       
    97 {
       
    98   GstElementFactory *factory;
       
    99 } VisEntry;
       
   100 
       
   101 static GArray *vis_entries;
       
   102 
       
   103 static void clear_streams (GstElement * pipeline);
       
   104 
       
   105 /* pipeline construction */
       
   106 
       
   107 typedef struct
       
   108 {
       
   109   const gchar *padname;
       
   110   GstPad *target;
       
   111   GstElement *bin;
       
   112 }
       
   113 dyn_link;
       
   114 
       
   115 static GstElement *
       
   116 gst_element_factory_make_or_warn (gchar * type, gchar * name)
       
   117 {
       
   118   GstElement *element = gst_element_factory_make (type, name);
       
   119 
       
   120   if (!element) {
       
   121     g_warning ("Failed to create element %s of type %s", name, type);
       
   122   }
       
   123 
       
   124   return element;
       
   125 }
       
   126 
       
   127 static void
       
   128 dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
       
   129 {
       
   130   gchar *padname;
       
   131   dyn_link *connect = (dyn_link *) data;
       
   132 
       
   133   padname = gst_pad_get_name (newpad);
       
   134 
       
   135   if (connect->padname == NULL || !strcmp (padname, connect->padname)) {
       
   136     if (connect->bin)
       
   137       gst_bin_add (GST_BIN (pipeline), connect->bin);
       
   138     gst_pad_link (newpad, connect->target);
       
   139 
       
   140     //seekable_pads = g_list_prepend (seekable_pads, newpad);
       
   141     rate_pads = g_list_prepend (rate_pads, newpad);
       
   142   }
       
   143   g_free (padname);
       
   144 }
       
   145 
       
   146 static void
       
   147 setup_dynamic_link (GstElement * element, const gchar * padname,
       
   148     GstPad * target, GstElement * bin)
       
   149 {
       
   150   dyn_link *connect;
       
   151 
       
   152   connect = g_new0 (dyn_link, 1);
       
   153   connect->padname = g_strdup (padname);
       
   154   connect->target = target;
       
   155   connect->bin = bin;
       
   156 
       
   157   g_signal_connect (G_OBJECT (element), "pad-added", G_CALLBACK (dynamic_link),
       
   158       connect);
       
   159 }
       
   160 
       
   161 static GstElement *
       
   162 make_mod_pipeline (const gchar * location)
       
   163 {
       
   164   GstElement *pipeline;
       
   165   GstElement *src, *decoder, *audiosink;
       
   166   GstPad *seekable;
       
   167 
       
   168   pipeline = gst_pipeline_new ("app");
       
   169 
       
   170   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   171   decoder = gst_element_factory_make_or_warn ("modplug", "decoder");
       
   172   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
       
   173   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
       
   174 
       
   175   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   176 
       
   177   gst_bin_add (GST_BIN (pipeline), src);
       
   178   gst_bin_add (GST_BIN (pipeline), decoder);
       
   179   gst_bin_add (GST_BIN (pipeline), audiosink);
       
   180 
       
   181   gst_element_link (src, decoder);
       
   182   gst_element_link (decoder, audiosink);
       
   183 
       
   184   seekable = gst_element_get_pad (decoder, "src");
       
   185   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   186   rate_pads = g_list_prepend (rate_pads, seekable);
       
   187   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
       
   188 
       
   189   return pipeline;
       
   190 }
       
   191 
       
   192 static GstElement *
       
   193 make_dv_pipeline (const gchar * location)
       
   194 {
       
   195   GstElement *pipeline;
       
   196   GstElement *src, *demux, *decoder, *audiosink, *videosink;
       
   197   GstElement *a_queue, *v_queue;
       
   198   GstPad *seekable;
       
   199 
       
   200   pipeline = gst_pipeline_new ("app");
       
   201 
       
   202   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   203   demux = gst_element_factory_make_or_warn ("dvdemux", "demuxer");
       
   204   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
       
   205   decoder = gst_element_factory_make_or_warn ("ffdec_dvvideo", "decoder");
       
   206   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
       
   207   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
       
   208   audiosink = gst_element_factory_make_or_warn ("alsasink", "a_sink");
       
   209 
       
   210   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   211 
       
   212   gst_bin_add (GST_BIN (pipeline), src);
       
   213   gst_bin_add (GST_BIN (pipeline), demux);
       
   214   gst_bin_add (GST_BIN (pipeline), a_queue);
       
   215   gst_bin_add (GST_BIN (pipeline), audiosink);
       
   216   gst_bin_add (GST_BIN (pipeline), v_queue);
       
   217   gst_bin_add (GST_BIN (pipeline), decoder);
       
   218   gst_bin_add (GST_BIN (pipeline), videosink);
       
   219 
       
   220   gst_element_link (src, demux);
       
   221   gst_element_link (a_queue, audiosink);
       
   222   gst_element_link (v_queue, decoder);
       
   223   gst_element_link (decoder, videosink);
       
   224 
       
   225   setup_dynamic_link (demux, "video", gst_element_get_pad (v_queue, "sink"),
       
   226       NULL);
       
   227   setup_dynamic_link (demux, "audio", gst_element_get_pad (a_queue, "sink"),
       
   228       NULL);
       
   229 
       
   230   seekable = gst_element_get_pad (decoder, "src");
       
   231   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   232   rate_pads = g_list_prepend (rate_pads, seekable);
       
   233 
       
   234   return pipeline;
       
   235 }
       
   236 
       
   237 static GstElement *
       
   238 make_wav_pipeline (const gchar * location)
       
   239 {
       
   240   GstElement *pipeline;
       
   241   GstElement *src, *decoder, *audiosink;
       
   242 
       
   243   pipeline = gst_pipeline_new ("app");
       
   244 
       
   245   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   246   decoder = gst_element_factory_make_or_warn ("wavparse", "decoder");
       
   247   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
       
   248 
       
   249   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   250 
       
   251   gst_bin_add (GST_BIN (pipeline), src);
       
   252   gst_bin_add (GST_BIN (pipeline), decoder);
       
   253   gst_bin_add (GST_BIN (pipeline), audiosink);
       
   254 
       
   255   gst_element_link (src, decoder);
       
   256 
       
   257   setup_dynamic_link (decoder, "src", gst_element_get_pad (audiosink, "sink"),
       
   258       NULL);
       
   259 
       
   260   seekable_elements = g_list_prepend (seekable_elements, audiosink);
       
   261 
       
   262   /* force element seeking on this pipeline */
       
   263   elem_seek = TRUE;
       
   264 
       
   265   return pipeline;
       
   266 }
       
   267 
       
   268 static GstElement *
       
   269 make_flac_pipeline (const gchar * location)
       
   270 {
       
   271   GstElement *pipeline;
       
   272   GstElement *src, *decoder, *audiosink;
       
   273   GstPad *seekable;
       
   274 
       
   275   pipeline = gst_pipeline_new ("app");
       
   276 
       
   277   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   278   decoder = gst_element_factory_make_or_warn ("flacdec", "decoder");
       
   279   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
       
   280   g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
       
   281 
       
   282   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   283 
       
   284   gst_bin_add (GST_BIN (pipeline), src);
       
   285   gst_bin_add (GST_BIN (pipeline), decoder);
       
   286   gst_bin_add (GST_BIN (pipeline), audiosink);
       
   287 
       
   288   gst_element_link (src, decoder);
       
   289   gst_element_link (decoder, audiosink);
       
   290 
       
   291   seekable = gst_element_get_pad (decoder, "src");
       
   292   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   293   rate_pads = g_list_prepend (rate_pads, seekable);
       
   294   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
       
   295 
       
   296   return pipeline;
       
   297 }
       
   298 
       
   299 static GstElement *
       
   300 make_sid_pipeline (const gchar * location)
       
   301 {
       
   302   GstElement *pipeline;
       
   303   GstElement *src, *decoder, *audiosink;
       
   304   GstPad *seekable;
       
   305 
       
   306   pipeline = gst_pipeline_new ("app");
       
   307 
       
   308   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   309   decoder = gst_element_factory_make_or_warn ("siddec", "decoder");
       
   310   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
       
   311   //g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
       
   312 
       
   313   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   314 
       
   315   gst_bin_add (GST_BIN (pipeline), src);
       
   316   gst_bin_add (GST_BIN (pipeline), decoder);
       
   317   gst_bin_add (GST_BIN (pipeline), audiosink);
       
   318 
       
   319   gst_element_link (src, decoder);
       
   320   gst_element_link (decoder, audiosink);
       
   321 
       
   322   seekable = gst_element_get_pad (decoder, "src");
       
   323   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   324   rate_pads = g_list_prepend (rate_pads, seekable);
       
   325   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
       
   326 
       
   327   return pipeline;
       
   328 }
       
   329 
       
   330 static GstElement *
       
   331 make_parse_pipeline (const gchar * location)
       
   332 {
       
   333   GstElement *pipeline;
       
   334   GstElement *src, *parser, *fakesink;
       
   335   GstPad *seekable;
       
   336 
       
   337   pipeline = gst_pipeline_new ("app");
       
   338 
       
   339   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   340   parser = gst_element_factory_make_or_warn ("mpegparse", "parse");
       
   341   fakesink = gst_element_factory_make_or_warn ("fakesink", "sink");
       
   342   g_object_set (G_OBJECT (fakesink), "silent", TRUE, NULL);
       
   343   g_object_set (G_OBJECT (fakesink), "sync", TRUE, NULL);
       
   344 
       
   345   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   346 
       
   347   gst_bin_add (GST_BIN (pipeline), src);
       
   348   gst_bin_add (GST_BIN (pipeline), parser);
       
   349   gst_bin_add (GST_BIN (pipeline), fakesink);
       
   350 
       
   351   gst_element_link (src, parser);
       
   352   gst_element_link (parser, fakesink);
       
   353 
       
   354   seekable = gst_element_get_pad (parser, "src");
       
   355   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   356   rate_pads = g_list_prepend (rate_pads, seekable);
       
   357   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (parser, "sink"));
       
   358 
       
   359   return pipeline;
       
   360 }
       
   361 
       
   362 static GstElement *
       
   363 make_vorbis_pipeline (const gchar * location)
       
   364 {
       
   365   GstElement *pipeline, *audio_bin;
       
   366   GstElement *src, *demux, *decoder, *convert, *audiosink;
       
   367   GstPad *pad, *seekable;
       
   368 
       
   369   pipeline = gst_pipeline_new ("app");
       
   370 
       
   371   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   372   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
       
   373   decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
       
   374   convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
       
   375   audiosink = gst_element_factory_make_or_warn (ASINK, "sink");
       
   376   g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
       
   377 
       
   378   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   379 
       
   380   audio_bin = gst_bin_new ("a_decoder_bin");
       
   381 
       
   382   gst_bin_add (GST_BIN (pipeline), src);
       
   383   gst_bin_add (GST_BIN (pipeline), demux);
       
   384   gst_bin_add (GST_BIN (audio_bin), decoder);
       
   385   gst_bin_add (GST_BIN (audio_bin), convert);
       
   386   gst_bin_add (GST_BIN (audio_bin), audiosink);
       
   387   gst_bin_add (GST_BIN (pipeline), audio_bin);
       
   388 
       
   389   gst_element_link (src, demux);
       
   390   gst_element_link (decoder, convert);
       
   391   gst_element_link (convert, audiosink);
       
   392 
       
   393   pad = gst_element_get_pad (decoder, "sink");
       
   394   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
       
   395   gst_object_unref (pad);
       
   396 
       
   397   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
       
   398       NULL);
       
   399 
       
   400   seekable = gst_element_get_pad (decoder, "src");
       
   401   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   402   rate_pads = g_list_prepend (rate_pads, seekable);
       
   403   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
       
   404 
       
   405   return pipeline;
       
   406 }
       
   407 
       
   408 static GstElement *
       
   409 make_theora_pipeline (const gchar * location)
       
   410 {
       
   411   GstElement *pipeline, *video_bin;
       
   412   GstElement *src, *demux, *decoder, *convert, *videosink;
       
   413   GstPad *pad, *seekable;
       
   414 
       
   415   pipeline = gst_pipeline_new ("app");
       
   416 
       
   417   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   418   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
       
   419   decoder = gst_element_factory_make_or_warn ("theoradec", "decoder");
       
   420   convert = gst_element_factory_make_or_warn ("ffmpegcolorspace", "convert");
       
   421   videosink = gst_element_factory_make_or_warn (VSINK, "sink");
       
   422 
       
   423   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   424 
       
   425   video_bin = gst_bin_new ("v_decoder_bin");
       
   426 
       
   427   gst_bin_add (GST_BIN (pipeline), src);
       
   428   gst_bin_add (GST_BIN (pipeline), demux);
       
   429   gst_bin_add (GST_BIN (video_bin), decoder);
       
   430   gst_bin_add (GST_BIN (video_bin), convert);
       
   431   gst_bin_add (GST_BIN (video_bin), videosink);
       
   432   gst_bin_add (GST_BIN (pipeline), video_bin);
       
   433 
       
   434   gst_element_link (src, demux);
       
   435   gst_element_link (decoder, convert);
       
   436   gst_element_link (convert, videosink);
       
   437 
       
   438   pad = gst_element_get_pad (decoder, "sink");
       
   439   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
       
   440   gst_object_unref (pad);
       
   441 
       
   442   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
       
   443       NULL);
       
   444 
       
   445   seekable = gst_element_get_pad (decoder, "src");
       
   446   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   447   rate_pads = g_list_prepend (rate_pads, seekable);
       
   448   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
       
   449 
       
   450   return pipeline;
       
   451 }
       
   452 
       
   453 static GstElement *
       
   454 make_vorbis_theora_pipeline (const gchar * location)
       
   455 {
       
   456   GstElement *pipeline, *audio_bin, *video_bin;
       
   457   GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
       
   458   GstElement *audiosink, *videosink;
       
   459   GstElement *a_queue, *v_queue, *v_scale;
       
   460   GstPad *seekable;
       
   461   GstPad *pad;
       
   462 
       
   463   pipeline = gst_pipeline_new ("app");
       
   464 
       
   465   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   466   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   467 
       
   468   demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
       
   469 
       
   470   gst_bin_add (GST_BIN (pipeline), src);
       
   471   gst_bin_add (GST_BIN (pipeline), demux);
       
   472   gst_element_link (src, demux);
       
   473 
       
   474   audio_bin = gst_bin_new ("a_decoder_bin");
       
   475   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
       
   476   a_decoder = gst_element_factory_make_or_warn ("vorbisdec", "a_dec");
       
   477   a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
       
   478   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
       
   479 
       
   480   gst_bin_add (GST_BIN (pipeline), audio_bin);
       
   481 
       
   482   gst_bin_add (GST_BIN (audio_bin), a_queue);
       
   483   gst_bin_add (GST_BIN (audio_bin), a_decoder);
       
   484   gst_bin_add (GST_BIN (audio_bin), a_convert);
       
   485   gst_bin_add (GST_BIN (audio_bin), audiosink);
       
   486 
       
   487   gst_element_link (a_queue, a_decoder);
       
   488   gst_element_link (a_decoder, a_convert);
       
   489   gst_element_link (a_convert, audiosink);
       
   490 
       
   491   pad = gst_element_get_pad (a_queue, "sink");
       
   492   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
       
   493   gst_object_unref (pad);
       
   494 
       
   495   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
       
   496       NULL);
       
   497 
       
   498   video_bin = gst_bin_new ("v_decoder_bin");
       
   499   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
       
   500   v_decoder = gst_element_factory_make_or_warn ("theoradec", "v_dec");
       
   501   v_convert =
       
   502       gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
       
   503   v_scale = gst_element_factory_make_or_warn ("videoscale", "v_scale");
       
   504   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
       
   505 
       
   506   gst_bin_add (GST_BIN (pipeline), video_bin);
       
   507 
       
   508   gst_bin_add (GST_BIN (video_bin), v_queue);
       
   509   gst_bin_add (GST_BIN (video_bin), v_decoder);
       
   510   gst_bin_add (GST_BIN (video_bin), v_convert);
       
   511   gst_bin_add (GST_BIN (video_bin), v_scale);
       
   512   gst_bin_add (GST_BIN (video_bin), videosink);
       
   513 
       
   514   gst_element_link_many (v_queue, v_decoder, v_convert, v_scale, videosink,
       
   515       NULL);
       
   516 
       
   517   pad = gst_element_get_pad (v_queue, "sink");
       
   518   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
       
   519   gst_object_unref (pad);
       
   520 
       
   521   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
       
   522       NULL);
       
   523 
       
   524   seekable = gst_element_get_pad (a_decoder, "src");
       
   525   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   526   rate_pads = g_list_prepend (rate_pads, seekable);
       
   527   rate_pads =
       
   528       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
       
   529 
       
   530   return pipeline;
       
   531 }
       
   532 
       
   533 static GstElement *
       
   534 make_avi_msmpeg4v3_mp3_pipeline (const gchar * location)
       
   535 {
       
   536   GstElement *pipeline, *audio_bin, *video_bin;
       
   537   GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
       
   538   GstElement *audiosink, *videosink;
       
   539   GstElement *a_queue, *v_queue;
       
   540   GstPad *seekable, *pad;
       
   541 
       
   542   pipeline = gst_pipeline_new ("app");
       
   543 
       
   544   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   545   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   546 
       
   547   demux = gst_element_factory_make_or_warn ("avidemux", "demux");
       
   548 
       
   549   gst_bin_add (GST_BIN (pipeline), src);
       
   550   gst_bin_add (GST_BIN (pipeline), demux);
       
   551   gst_element_link (src, demux);
       
   552 
       
   553   audio_bin = gst_bin_new ("a_decoder_bin");
       
   554   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
       
   555   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
       
   556   a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
       
   557   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
       
   558 
       
   559   gst_bin_add (GST_BIN (audio_bin), a_queue);
       
   560   gst_bin_add (GST_BIN (audio_bin), a_decoder);
       
   561   gst_bin_add (GST_BIN (audio_bin), a_convert);
       
   562   gst_bin_add (GST_BIN (audio_bin), audiosink);
       
   563 
       
   564   gst_element_link (a_queue, a_decoder);
       
   565   gst_element_link (a_decoder, a_convert);
       
   566   gst_element_link (a_convert, audiosink);
       
   567 
       
   568   gst_bin_add (GST_BIN (pipeline), audio_bin);
       
   569 
       
   570   pad = gst_element_get_pad (a_queue, "sink");
       
   571   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
       
   572   gst_object_unref (pad);
       
   573 
       
   574   setup_dynamic_link (demux, NULL, gst_element_get_pad (audio_bin, "sink"),
       
   575       NULL);
       
   576 
       
   577   video_bin = gst_bin_new ("v_decoder_bin");
       
   578   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
       
   579   v_decoder = gst_element_factory_make_or_warn ("ffdec_msmpeg4", "v_dec");
       
   580   v_convert =
       
   581       gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
       
   582   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
       
   583 
       
   584   gst_bin_add (GST_BIN (video_bin), v_queue);
       
   585   gst_bin_add (GST_BIN (video_bin), v_decoder);
       
   586   gst_bin_add (GST_BIN (video_bin), v_convert);
       
   587   gst_bin_add (GST_BIN (video_bin), videosink);
       
   588 
       
   589   gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
       
   590 
       
   591   gst_bin_add (GST_BIN (pipeline), video_bin);
       
   592 
       
   593   pad = gst_element_get_pad (v_queue, "sink");
       
   594   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
       
   595   gst_object_unref (pad);
       
   596 
       
   597   setup_dynamic_link (demux, NULL, gst_element_get_pad (video_bin, "sink"),
       
   598       NULL);
       
   599 
       
   600   seekable = gst_element_get_pad (a_decoder, "src");
       
   601   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   602   rate_pads = g_list_prepend (rate_pads, seekable);
       
   603   rate_pads =
       
   604       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
       
   605 
       
   606   return pipeline;
       
   607 }
       
   608 
       
   609 static GstElement *
       
   610 make_mp3_pipeline (const gchar * location)
       
   611 {
       
   612   GstElement *pipeline;
       
   613   GstElement *src, *decoder, *osssink, *queue;
       
   614   GstPad *seekable;
       
   615 
       
   616   pipeline = gst_pipeline_new ("app");
       
   617 
       
   618   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   619   decoder = gst_element_factory_make_or_warn ("mad", "dec");
       
   620   queue = gst_element_factory_make_or_warn ("queue", "queue");
       
   621   osssink = gst_element_factory_make_or_warn (ASINK, "sink");
       
   622 
       
   623   seekable_elements = g_list_prepend (seekable_elements, osssink);
       
   624 
       
   625   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   626   //g_object_set (G_OBJECT (osssink), "fragment", 0x00180008, NULL);
       
   627 
       
   628   gst_bin_add (GST_BIN (pipeline), src);
       
   629   gst_bin_add (GST_BIN (pipeline), decoder);
       
   630   gst_bin_add (GST_BIN (pipeline), queue);
       
   631   gst_bin_add (GST_BIN (pipeline), osssink);
       
   632 
       
   633   gst_element_link (src, decoder);
       
   634   gst_element_link (decoder, queue);
       
   635   gst_element_link (queue, osssink);
       
   636 
       
   637   seekable = gst_element_get_pad (queue, "src");
       
   638   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   639   rate_pads = g_list_prepend (rate_pads, seekable);
       
   640   rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
       
   641 
       
   642   return pipeline;
       
   643 }
       
   644 
       
   645 static GstElement *
       
   646 make_avi_pipeline (const gchar * location)
       
   647 {
       
   648   GstElement *pipeline, *audio_bin, *video_bin;
       
   649   GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
       
   650   GstElement *a_queue = NULL, *v_queue = NULL;
       
   651   GstPad *seekable;
       
   652 
       
   653   pipeline = gst_pipeline_new ("app");
       
   654 
       
   655   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   656   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   657 
       
   658   demux = gst_element_factory_make_or_warn ("avidemux", "demux");
       
   659   seekable_elements = g_list_prepend (seekable_elements, demux);
       
   660 
       
   661   gst_bin_add (GST_BIN (pipeline), src);
       
   662   gst_bin_add (GST_BIN (pipeline), demux);
       
   663   gst_element_link (src, demux);
       
   664 
       
   665   audio_bin = gst_bin_new ("a_decoder_bin");
       
   666   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
       
   667   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
       
   668   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
       
   669   gst_element_link (a_decoder, a_queue);
       
   670   gst_element_link (a_queue, audiosink);
       
   671   gst_bin_add (GST_BIN (audio_bin), a_decoder);
       
   672   gst_bin_add (GST_BIN (audio_bin), a_queue);
       
   673   gst_bin_add (GST_BIN (audio_bin), audiosink);
       
   674   gst_element_set_state (audio_bin, GST_STATE_PAUSED);
       
   675 
       
   676   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
       
   677           "sink"), audio_bin);
       
   678 
       
   679   seekable = gst_element_get_pad (a_queue, "src");
       
   680   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   681   rate_pads = g_list_prepend (rate_pads, seekable);
       
   682   rate_pads =
       
   683       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
       
   684 
       
   685   video_bin = gst_bin_new ("v_decoder_bin");
       
   686   v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
       
   687   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
       
   688   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
       
   689   gst_element_link (v_decoder, v_queue);
       
   690   gst_element_link (v_queue, videosink);
       
   691   gst_bin_add (GST_BIN (video_bin), v_decoder);
       
   692   gst_bin_add (GST_BIN (video_bin), v_queue);
       
   693   gst_bin_add (GST_BIN (video_bin), videosink);
       
   694 
       
   695   gst_element_set_state (video_bin, GST_STATE_PAUSED);
       
   696 
       
   697   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
       
   698           "sink"), video_bin);
       
   699 
       
   700   seekable = gst_element_get_pad (v_queue, "src");
       
   701   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   702   rate_pads = g_list_prepend (rate_pads, seekable);
       
   703   rate_pads =
       
   704       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
       
   705 
       
   706   return pipeline;
       
   707 }
       
   708 
       
   709 static GstElement *
       
   710 make_mpeg_pipeline (const gchar * location)
       
   711 {
       
   712   GstElement *pipeline, *audio_bin, *video_bin;
       
   713   GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
       
   714   GstElement *audiosink, *videosink;
       
   715   GstElement *a_queue, *v_queue;
       
   716   GstPad *seekable;
       
   717   GstPad *pad;
       
   718 
       
   719   pipeline = gst_pipeline_new ("app");
       
   720 
       
   721   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   722   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   723 
       
   724   //demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
       
   725   demux = gst_element_factory_make_or_warn ("flupsdemux", "demux");
       
   726 
       
   727   gst_bin_add (GST_BIN (pipeline), src);
       
   728   gst_bin_add (GST_BIN (pipeline), demux);
       
   729   gst_element_link (src, demux);
       
   730 
       
   731   audio_bin = gst_bin_new ("a_decoder_bin");
       
   732   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
       
   733   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
       
   734   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
       
   735   gst_bin_add (GST_BIN (audio_bin), a_decoder);
       
   736   gst_bin_add (GST_BIN (audio_bin), a_queue);
       
   737   gst_bin_add (GST_BIN (audio_bin), audiosink);
       
   738 
       
   739   gst_element_link (a_decoder, a_queue);
       
   740   gst_element_link (a_queue, audiosink);
       
   741 
       
   742   gst_bin_add (GST_BIN (pipeline), audio_bin);
       
   743 
       
   744   pad = gst_element_get_pad (a_decoder, "sink");
       
   745   gst_element_add_pad (audio_bin, gst_ghost_pad_new ("sink", pad));
       
   746   gst_object_unref (pad);
       
   747 
       
   748   setup_dynamic_link (demux, "audio_c0", gst_element_get_pad (audio_bin,
       
   749           "sink"), NULL);
       
   750 
       
   751   video_bin = gst_bin_new ("v_decoder_bin");
       
   752   v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
       
   753   v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
       
   754   v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
       
   755   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
       
   756 
       
   757   gst_bin_add (GST_BIN (video_bin), v_decoder);
       
   758   gst_bin_add (GST_BIN (video_bin), v_queue);
       
   759   gst_bin_add (GST_BIN (video_bin), v_filter);
       
   760   gst_bin_add (GST_BIN (video_bin), videosink);
       
   761 
       
   762   gst_element_link (v_decoder, v_queue);
       
   763   gst_element_link (v_queue, v_filter);
       
   764   gst_element_link (v_filter, videosink);
       
   765 
       
   766   gst_bin_add (GST_BIN (pipeline), video_bin);
       
   767 
       
   768   pad = gst_element_get_pad (v_decoder, "sink");
       
   769   gst_element_add_pad (video_bin, gst_ghost_pad_new ("sink", pad));
       
   770   gst_object_unref (pad);
       
   771 
       
   772   setup_dynamic_link (demux, "video_e0", gst_element_get_pad (video_bin,
       
   773           "sink"), NULL);
       
   774 
       
   775   seekable = gst_element_get_pad (v_filter, "src");
       
   776   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   777   rate_pads = g_list_prepend (rate_pads, seekable);
       
   778   rate_pads =
       
   779       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
       
   780 
       
   781   return pipeline;
       
   782 }
       
   783 
       
   784 static GstElement *
       
   785 make_mpegnt_pipeline (const gchar * location)
       
   786 {
       
   787   GstElement *pipeline, *audio_bin, *video_bin;
       
   788   GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
       
   789   GstElement *audiosink, *videosink;
       
   790   GstElement *a_queue;
       
   791   GstPad *seekable;
       
   792 
       
   793   pipeline = gst_pipeline_new ("app");
       
   794 
       
   795   src = gst_element_factory_make_or_warn (SOURCE, "src");
       
   796   g_object_set (G_OBJECT (src), "location", location, NULL);
       
   797 
       
   798   demux = gst_element_factory_make_or_warn ("mpegdemux", "demux");
       
   799   //g_object_set (G_OBJECT (demux), "sync", TRUE, NULL);
       
   800 
       
   801   seekable_elements = g_list_prepend (seekable_elements, demux);
       
   802 
       
   803   gst_bin_add (GST_BIN (pipeline), src);
       
   804   gst_bin_add (GST_BIN (pipeline), demux);
       
   805   gst_element_link (src, demux);
       
   806 
       
   807   audio_bin = gst_bin_new ("a_decoder_bin");
       
   808   a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
       
   809   a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
       
   810   audiosink = gst_element_factory_make_or_warn (ASINK, "a_sink");
       
   811   //g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
       
   812   g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
       
   813   gst_element_link (a_decoder, a_queue);
       
   814   gst_element_link (a_queue, audiosink);
       
   815   gst_bin_add (GST_BIN (audio_bin), a_decoder);
       
   816   gst_bin_add (GST_BIN (audio_bin), a_queue);
       
   817   gst_bin_add (GST_BIN (audio_bin), audiosink);
       
   818 
       
   819   setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
       
   820           "sink"), audio_bin);
       
   821 
       
   822   seekable = gst_element_get_pad (a_queue, "src");
       
   823   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   824   rate_pads = g_list_prepend (rate_pads, seekable);
       
   825   rate_pads =
       
   826       g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
       
   827 
       
   828   video_bin = gst_bin_new ("v_decoder_bin");
       
   829   v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
       
   830   v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
       
   831   videosink = gst_element_factory_make_or_warn (VSINK, "v_sink");
       
   832   gst_element_link_many (v_decoder, v_filter, videosink, NULL);
       
   833 
       
   834   gst_bin_add_many (GST_BIN (video_bin), v_decoder, v_filter, videosink, NULL);
       
   835 
       
   836   setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
       
   837           "sink"), video_bin);
       
   838 
       
   839   seekable = gst_element_get_pad (v_decoder, "src");
       
   840   seekable_pads = g_list_prepend (seekable_pads, seekable);
       
   841   rate_pads = g_list_prepend (rate_pads, seekable);
       
   842   rate_pads =
       
   843       g_list_prepend (rate_pads, gst_element_get_pad (v_decoder, "sink"));
       
   844 
       
   845   return pipeline;
       
   846 }
       
   847 
       
   848 static GstElement *
       
   849 make_playerbin_pipeline (const gchar * location)
       
   850 {
       
   851   GstElement *player;
       
   852 
       
   853   player = gst_element_factory_make ("playbin", "player");
       
   854   g_assert (player);
       
   855 
       
   856   g_object_set (G_OBJECT (player), "uri", location, NULL);
       
   857 
       
   858   seekable_elements = g_list_prepend (seekable_elements, player);
       
   859 
       
   860   /* force element seeking on this pipeline */
       
   861   elem_seek = TRUE;
       
   862 
       
   863   return player;
       
   864 }
       
   865 
       
   866 static GstElement *
       
   867 make_playerbin2_pipeline (const gchar * location)
       
   868 {
       
   869   GstElement *player;
       
   870 
       
   871   player = gst_element_factory_make ("playbin2", "player");
       
   872   g_assert (player);
       
   873 
       
   874   g_object_set (G_OBJECT (player), "uri", location, NULL);
       
   875 
       
   876   seekable_elements = g_list_prepend (seekable_elements, player);
       
   877 
       
   878   /* force element seeking on this pipeline */
       
   879   elem_seek = TRUE;
       
   880 
       
   881   return player;
       
   882 }
       
   883 
       
   884 #ifndef GST_DISABLE_PARSE
       
   885 static GstElement *
       
   886 make_parselaunch_pipeline (const gchar * description)
       
   887 {
       
   888   GstElement *pipeline;
       
   889   GError *error;
       
   890 
       
   891   pipeline = gst_parse_launch (description, &error);
       
   892 
       
   893   seekable_elements = g_list_prepend (seekable_elements, pipeline);
       
   894 
       
   895   elem_seek = TRUE;
       
   896 
       
   897   return pipeline;
       
   898 }
       
   899 #endif
       
   900 
       
   901 typedef struct
       
   902 {
       
   903   gchar *name;
       
   904   GstElement *(*func) (const gchar * location);
       
   905 }
       
   906 Pipeline;
       
   907 
       
   908 static Pipeline pipelines[] = {
       
   909   {"mp3", make_mp3_pipeline},
       
   910   {"avi", make_avi_pipeline},
       
   911   {"mpeg1", make_mpeg_pipeline},
       
   912   {"mpegparse", make_parse_pipeline},
       
   913   {"vorbis", make_vorbis_pipeline},
       
   914   {"theora", make_theora_pipeline},
       
   915   {"ogg/v/t", make_vorbis_theora_pipeline},
       
   916   {"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
       
   917   {"sid", make_sid_pipeline},
       
   918   {"flac", make_flac_pipeline},
       
   919   {"wav", make_wav_pipeline},
       
   920   {"mod", make_mod_pipeline},
       
   921   {"dv", make_dv_pipeline},
       
   922   {"mpeg1nothreads", make_mpegnt_pipeline},
       
   923   {"playerbin", make_playerbin_pipeline},
       
   924 #ifndef GST_DISABLE_PARSE
       
   925   {"parse-launch", make_parselaunch_pipeline},
       
   926 #endif
       
   927   {"playerbin2", make_playerbin2_pipeline},
       
   928   {NULL, NULL},
       
   929 };
       
   930 
       
   931 #define NUM_TYPES       ((sizeof (pipelines) / sizeof (Pipeline)) - 1)
       
   932 
       
   933 /* ui callbacks and helpers */
       
   934 
       
   935 static gchar *
       
   936 format_value (GtkScale * scale, gdouble value)
       
   937 {
       
   938   gint64 real;
       
   939   gint64 seconds;
       
   940   gint64 subseconds;
       
   941 
       
   942   real = value * duration / 100;
       
   943   seconds = (gint64) real / GST_SECOND;
       
   944   subseconds = (gint64) real / (GST_SECOND / 100);
       
   945 
       
   946   return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
       
   947       G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
       
   948 }
       
   949 
       
   950 typedef struct
       
   951 {
       
   952   const gchar *name;
       
   953   const GstFormat format;
       
   954 }
       
   955 seek_format;
       
   956 
       
   957 static seek_format seek_formats[] = {
       
   958   {"tim", GST_FORMAT_TIME},
       
   959   {"byt", GST_FORMAT_BYTES},
       
   960   {"buf", GST_FORMAT_BUFFERS},
       
   961   {"def", GST_FORMAT_DEFAULT},
       
   962   {NULL, 0},
       
   963 };
       
   964 
       
   965 G_GNUC_UNUSED static void
       
   966 query_rates (void)
       
   967 {
       
   968   GList *walk = rate_pads;
       
   969 
       
   970   while (walk) {
       
   971     GstPad *pad = GST_PAD (walk->data);
       
   972     gint i = 0;
       
   973 
       
   974     g_print ("rate/sec  %8.8s: ", GST_PAD_NAME (pad));
       
   975     while (seek_formats[i].name) {
       
   976       gint64 value;
       
   977       GstFormat format;
       
   978 
       
   979       format = seek_formats[i].format;
       
   980 
       
   981       if (gst_pad_query_convert (pad, GST_FORMAT_TIME, GST_SECOND, &format,
       
   982               &value)) {
       
   983         g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
       
   984       } else {
       
   985         g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
       
   986       }
       
   987 
       
   988       i++;
       
   989     }
       
   990     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
       
   991 
       
   992     walk = g_list_next (walk);
       
   993   }
       
   994 }
       
   995 
       
   996 G_GNUC_UNUSED static void
       
   997 query_positions_elems (void)
       
   998 {
       
   999   GList *walk = seekable_elements;
       
  1000 
       
  1001   while (walk) {
       
  1002     GstElement *element = GST_ELEMENT (walk->data);
       
  1003     gint i = 0;
       
  1004 
       
  1005     g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
       
  1006     while (seek_formats[i].name) {
       
  1007       gint64 position, total;
       
  1008       GstFormat format;
       
  1009 
       
  1010       format = seek_formats[i].format;
       
  1011 
       
  1012       if (gst_element_query_position (element, &format, &position) &&
       
  1013           gst_element_query_duration (element, &format, &total)) {
       
  1014         g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
       
  1015             seek_formats[i].name, position, total);
       
  1016       } else {
       
  1017         g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
       
  1018             "*NA*");
       
  1019       }
       
  1020       i++;
       
  1021     }
       
  1022     g_print (" %s\n", GST_ELEMENT_NAME (element));
       
  1023 
       
  1024     walk = g_list_next (walk);
       
  1025   }
       
  1026 }
       
  1027 
       
  1028 G_GNUC_UNUSED static void
       
  1029 query_positions_pads (void)
       
  1030 {
       
  1031   GList *walk = seekable_pads;
       
  1032 
       
  1033   while (walk) {
       
  1034     GstPad *pad = GST_PAD (walk->data);
       
  1035     gint i = 0;
       
  1036 
       
  1037     g_print ("positions %8.8s: ", GST_PAD_NAME (pad));
       
  1038     while (seek_formats[i].name) {
       
  1039       GstFormat format;
       
  1040       gint64 position, total;
       
  1041 
       
  1042       format = seek_formats[i].format;
       
  1043 
       
  1044       if (gst_pad_query_position (pad, &format, &position) &&
       
  1045           gst_pad_query_duration (pad, &format, &total)) {
       
  1046         g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
       
  1047             seek_formats[i].name, position, total);
       
  1048       } else {
       
  1049         g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
       
  1050             "*NA*");
       
  1051       }
       
  1052 
       
  1053       i++;
       
  1054     }
       
  1055     g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
       
  1056 
       
  1057     walk = g_list_next (walk);
       
  1058   }
       
  1059 }
       
  1060 
       
  1061 static gboolean start_seek (GtkWidget * widget, GdkEventButton * event,
       
  1062     gpointer user_data);
       
  1063 static gboolean stop_seek (GtkWidget * widget, GdkEventButton * event,
       
  1064     gpointer user_data);
       
  1065 static void seek_cb (GtkWidget * widget);
       
  1066 
       
  1067 static void
       
  1068 set_scale (gdouble value)
       
  1069 {
       
  1070   g_signal_handlers_block_by_func (hscale, (void *) start_seek,
       
  1071       (void *) pipeline);
       
  1072   g_signal_handlers_block_by_func (hscale, (void *) stop_seek,
       
  1073       (void *) pipeline);
       
  1074   g_signal_handlers_block_by_func (hscale, (void *) seek_cb, (void *) pipeline);
       
  1075   gtk_adjustment_set_value (adjustment, value);
       
  1076   g_signal_handlers_unblock_by_func (hscale, (void *) start_seek,
       
  1077       (void *) pipeline);
       
  1078   g_signal_handlers_unblock_by_func (hscale, (void *) stop_seek,
       
  1079       (void *) pipeline);
       
  1080   g_signal_handlers_unblock_by_func (hscale, (void *) seek_cb,
       
  1081       (void *) pipeline);
       
  1082   gtk_widget_queue_draw (hscale);
       
  1083 }
       
  1084 
       
  1085 static gboolean
       
  1086 update_scale (gpointer data)
       
  1087 {
       
  1088   GstFormat format = GST_FORMAT_TIME;
       
  1089 
       
  1090   //position = 0;
       
  1091   //duration = 0;
       
  1092 
       
  1093   if (elem_seek) {
       
  1094     if (seekable_elements) {
       
  1095       GstElement *element = GST_ELEMENT (seekable_elements->data);
       
  1096 
       
  1097       gst_element_query_position (element, &format, &position);
       
  1098       gst_element_query_duration (element, &format, &duration);
       
  1099     }
       
  1100   } else {
       
  1101     if (seekable_pads) {
       
  1102       GstPad *pad = GST_PAD (seekable_pads->data);
       
  1103 
       
  1104       gst_pad_query_position (pad, &format, &position);
       
  1105       gst_pad_query_duration (pad, &format, &duration);
       
  1106     }
       
  1107   }
       
  1108 
       
  1109   if (stats) {
       
  1110     if (elem_seek) {
       
  1111       query_positions_elems ();
       
  1112     } else {
       
  1113       query_positions_pads ();
       
  1114     }
       
  1115     query_rates ();
       
  1116   }
       
  1117   if (position >= duration)
       
  1118     duration = position;
       
  1119 
       
  1120   if (duration > 0) {
       
  1121     set_scale (position * 100.0 / duration);
       
  1122   }
       
  1123 
       
  1124   return TRUE;
       
  1125 }
       
  1126 
       
  1127 static void do_seek (GtkWidget * widget);
       
  1128 static void connect_bus_signals (GstElement * pipeline);
       
  1129 static void set_update_scale (gboolean active);
       
  1130 
       
  1131 static gboolean
       
  1132 end_scrub (GtkWidget * widget)
       
  1133 {
       
  1134   GST_DEBUG ("end scrub, PAUSE");
       
  1135   gst_element_set_state (pipeline, GST_STATE_PAUSED);
       
  1136   seek_timeout_id = 0;
       
  1137 
       
  1138   return FALSE;
       
  1139 }
       
  1140 
       
  1141 static gboolean
       
  1142 send_event (GstEvent * event)
       
  1143 {
       
  1144   gboolean res = FALSE;
       
  1145 
       
  1146   if (!elem_seek) {
       
  1147     GList *walk = seekable_pads;
       
  1148 
       
  1149     while (walk) {
       
  1150       GstPad *seekable = GST_PAD (walk->data);
       
  1151 
       
  1152       GST_DEBUG ("send event on pad %s:%s", GST_DEBUG_PAD_NAME (seekable));
       
  1153 
       
  1154       gst_event_ref (event);
       
  1155       res = gst_pad_send_event (seekable, event);
       
  1156 
       
  1157       walk = g_list_next (walk);
       
  1158     }
       
  1159   } else {
       
  1160     GList *walk = seekable_elements;
       
  1161 
       
  1162     while (walk) {
       
  1163       GstElement *seekable = GST_ELEMENT (walk->data);
       
  1164 
       
  1165       GST_DEBUG ("send event on element %s", GST_ELEMENT_NAME (seekable));
       
  1166 
       
  1167       gst_event_ref (event);
       
  1168       res = gst_element_send_event (seekable, event);
       
  1169 
       
  1170       walk = g_list_next (walk);
       
  1171     }
       
  1172   }
       
  1173   gst_event_unref (event);
       
  1174   return res;
       
  1175 }
       
  1176 
       
  1177 static void
       
  1178 do_seek (GtkWidget * widget)
       
  1179 {
       
  1180   gint64 real;
       
  1181   gboolean res = FALSE;
       
  1182   GstEvent *s_event;
       
  1183   GstSeekFlags flags;
       
  1184 
       
  1185   real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
       
  1186 
       
  1187   flags = 0;
       
  1188   if (flush_seek)
       
  1189     flags |= GST_SEEK_FLAG_FLUSH;
       
  1190   if (accurate_seek)
       
  1191     flags |= GST_SEEK_FLAG_ACCURATE;
       
  1192   if (keyframe_seek)
       
  1193     flags |= GST_SEEK_FLAG_KEY_UNIT;
       
  1194   if (loop_seek)
       
  1195     flags |= GST_SEEK_FLAG_SEGMENT;
       
  1196 
       
  1197   if (rate >= 0) {
       
  1198     s_event = gst_event_new_seek (rate,
       
  1199         GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_SET, -1);
       
  1200     GST_DEBUG ("seek with rate %lf to %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT,
       
  1201         rate, GST_TIME_ARGS (real), GST_TIME_ARGS (duration));
       
  1202   } else {
       
  1203     s_event = gst_event_new_seek (rate,
       
  1204         GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
       
  1205         GST_SEEK_TYPE_SET, real);
       
  1206     GST_DEBUG ("seek with rate %lf to %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT,
       
  1207         rate, GST_TIME_ARGS (0), GST_TIME_ARGS (real));
       
  1208   }
       
  1209 
       
  1210   res = send_event (s_event);
       
  1211 
       
  1212   if (res) {
       
  1213     if (flush_seek) {
       
  1214       gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
       
  1215     } else {
       
  1216       set_update_scale (TRUE);
       
  1217     }
       
  1218   } else {
       
  1219     g_print ("seek failed\n");
       
  1220     set_update_scale (TRUE);
       
  1221   }
       
  1222 }
       
  1223 
       
  1224 static void
       
  1225 seek_cb (GtkWidget * widget)
       
  1226 {
       
  1227   /* If the timer hasn't expired yet, then the pipeline is running */
       
  1228   if (play_scrub && seek_timeout_id != 0) {
       
  1229     GST_DEBUG ("do scrub seek, PAUSED");
       
  1230     gst_element_set_state (pipeline, GST_STATE_PAUSED);
       
  1231   }
       
  1232 
       
  1233   GST_DEBUG ("do seek");
       
  1234   do_seek (widget);
       
  1235 
       
  1236   if (play_scrub) {
       
  1237     GST_DEBUG ("do scrub seek, PLAYING");
       
  1238     gst_element_set_state (pipeline, GST_STATE_PLAYING);
       
  1239 
       
  1240     if (seek_timeout_id == 0) {
       
  1241       seek_timeout_id =
       
  1242           g_timeout_add (SCRUB_TIME, (GSourceFunc) end_scrub, widget);
       
  1243     }
       
  1244   }
       
  1245 }
       
  1246 
       
  1247 static void
       
  1248 set_update_scale (gboolean active)
       
  1249 {
       
  1250 
       
  1251   GST_DEBUG ("update scale is %d", active);
       
  1252 
       
  1253   if (active) {
       
  1254     if (update_id == 0) {
       
  1255       update_id =
       
  1256           g_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
       
  1257     }
       
  1258   } else {
       
  1259     if (update_id) {
       
  1260       g_source_remove (update_id);
       
  1261       update_id = 0;
       
  1262     }
       
  1263   }
       
  1264 }
       
  1265 
       
  1266 static gboolean
       
  1267 start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
       
  1268 {
       
  1269   if (event->type != GDK_BUTTON_PRESS)
       
  1270     return FALSE;
       
  1271 
       
  1272   set_update_scale (FALSE);
       
  1273 
       
  1274   if (state == GST_STATE_PLAYING && flush_seek && scrub) {
       
  1275     GST_DEBUG ("start scrub seek, PAUSE");
       
  1276     gst_element_set_state (pipeline, GST_STATE_PAUSED);
       
  1277   }
       
  1278 
       
  1279   if (changed_id == 0 && flush_seek && scrub) {
       
  1280     changed_id = gtk_signal_connect (GTK_OBJECT (hscale),
       
  1281         "value_changed", G_CALLBACK (seek_cb), pipeline);
       
  1282   }
       
  1283 
       
  1284   return FALSE;
       
  1285 }
       
  1286 
       
  1287 static gboolean
       
  1288 stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
       
  1289 {
       
  1290   if (changed_id) {
       
  1291     g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
       
  1292     changed_id = 0;
       
  1293   }
       
  1294 
       
  1295   if (!flush_seek || !scrub) {
       
  1296     GST_DEBUG ("do final seek");
       
  1297     do_seek (widget);
       
  1298   }
       
  1299 
       
  1300   if (seek_timeout_id != 0) {
       
  1301     g_source_remove (seek_timeout_id);
       
  1302     seek_timeout_id = 0;
       
  1303     /* Still scrubbing, so the pipeline is playing, see if we need PAUSED
       
  1304      * instead. */
       
  1305     if (state == GST_STATE_PAUSED) {
       
  1306       GST_DEBUG ("stop scrub seek, PAUSED");
       
  1307       gst_element_set_state (pipeline, GST_STATE_PAUSED);
       
  1308     }
       
  1309   } else {
       
  1310     if (state == GST_STATE_PLAYING) {
       
  1311       GST_DEBUG ("stop scrub seek, PLAYING");
       
  1312       gst_element_set_state (pipeline, GST_STATE_PLAYING);
       
  1313     }
       
  1314   }
       
  1315 
       
  1316   return FALSE;
       
  1317 }
       
  1318 
       
  1319 static void
       
  1320 play_cb (GtkButton * button, gpointer data)
       
  1321 {
       
  1322   GstStateChangeReturn ret;
       
  1323 
       
  1324   if (state != GST_STATE_PLAYING) {
       
  1325     g_print ("PLAY pipeline\n");
       
  1326     ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
       
  1327     if (ret == GST_STATE_CHANGE_FAILURE)
       
  1328       goto failed;
       
  1329     //do_seek(hscale);
       
  1330 
       
  1331     state = GST_STATE_PLAYING;
       
  1332   }
       
  1333   return;
       
  1334 
       
  1335 failed:
       
  1336   {
       
  1337     g_print ("PLAY failed\n");
       
  1338   }
       
  1339 }
       
  1340 
       
  1341 static void
       
  1342 pause_cb (GtkButton * button, gpointer data)
       
  1343 {
       
  1344   if (state != GST_STATE_PAUSED) {
       
  1345     GstStateChangeReturn ret;
       
  1346 
       
  1347     g_print ("PAUSE pipeline\n");
       
  1348     ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
       
  1349     if (ret == GST_STATE_CHANGE_FAILURE)
       
  1350       goto failed;
       
  1351 
       
  1352     state = GST_STATE_PAUSED;
       
  1353   }
       
  1354   return;
       
  1355 
       
  1356 failed:
       
  1357   {
       
  1358     g_print ("PAUSE failed\n");
       
  1359   }
       
  1360 }
       
  1361 
       
  1362 static void
       
  1363 stop_cb (GtkButton * button, gpointer data)
       
  1364 {
       
  1365   if (state != GST_STATE_READY) {
       
  1366     GstStateChangeReturn ret;
       
  1367 
       
  1368     g_print ("READY pipeline\n");
       
  1369     ret = gst_element_set_state (pipeline, GST_STATE_READY);
       
  1370     if (ret == GST_STATE_CHANGE_FAILURE)
       
  1371       goto failed;
       
  1372 
       
  1373     state = GST_STATE_READY;
       
  1374 
       
  1375     set_update_scale (FALSE);
       
  1376     set_scale (0.0);
       
  1377 
       
  1378     if (pipeline_type == 16)
       
  1379       clear_streams (pipeline);
       
  1380 
       
  1381     /* if one uses parse_launch, play, stop and play again it fails as all the
       
  1382      * pads after the demuxer can't be reconnected
       
  1383      */
       
  1384     if (!strcmp (pipelines[pipeline_type].name, "parse-launch")) {
       
  1385       gst_element_set_state (pipeline, GST_STATE_NULL);
       
  1386       gst_object_unref (pipeline);
       
  1387 
       
  1388       pipeline = pipelines[pipeline_type].func (pipeline_spec);
       
  1389       g_assert (pipeline);
       
  1390       gst_element_set_state (pipeline, GST_STATE_READY);
       
  1391       connect_bus_signals (pipeline);
       
  1392     }
       
  1393   }
       
  1394   return;
       
  1395 
       
  1396 failed:
       
  1397   {
       
  1398     g_print ("STOP failed\n");
       
  1399   }
       
  1400 }
       
  1401 
       
  1402 static void
       
  1403 accurate_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1404 {
       
  1405   accurate_seek = gtk_toggle_button_get_active (button);
       
  1406 }
       
  1407 
       
  1408 static void
       
  1409 key_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1410 {
       
  1411   keyframe_seek = gtk_toggle_button_get_active (button);
       
  1412 }
       
  1413 
       
  1414 static void
       
  1415 loop_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1416 {
       
  1417   loop_seek = gtk_toggle_button_get_active (button);
       
  1418   if (state == GST_STATE_PLAYING) {
       
  1419     do_seek (hscale);
       
  1420   }
       
  1421 }
       
  1422 
       
  1423 static void
       
  1424 flush_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1425 {
       
  1426   flush_seek = gtk_toggle_button_get_active (button);
       
  1427 }
       
  1428 
       
  1429 static void
       
  1430 scrub_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1431 {
       
  1432   scrub = gtk_toggle_button_get_active (button);
       
  1433 }
       
  1434 
       
  1435 static void
       
  1436 play_scrub_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1437 {
       
  1438   play_scrub = gtk_toggle_button_get_active (button);
       
  1439 }
       
  1440 
       
  1441 static void
       
  1442 rate_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline)
       
  1443 {
       
  1444   gboolean res = FALSE;
       
  1445   GstEvent *s_event;
       
  1446   GstSeekFlags flags;
       
  1447 
       
  1448   rate = gtk_spin_button_get_value (button);
       
  1449 
       
  1450   flags = 0;
       
  1451   if (flush_seek)
       
  1452     flags |= GST_SEEK_FLAG_FLUSH;
       
  1453   if (loop_seek)
       
  1454     flags |= GST_SEEK_FLAG_SEGMENT;
       
  1455   if (accurate_seek)
       
  1456     flags |= GST_SEEK_FLAG_ACCURATE;
       
  1457   if (keyframe_seek)
       
  1458     flags |= GST_SEEK_FLAG_KEY_UNIT;
       
  1459 
       
  1460   if (rate >= 0) {
       
  1461     s_event = gst_event_new_seek (rate,
       
  1462         GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, position,
       
  1463         GST_SEEK_TYPE_SET, -1);
       
  1464   } else {
       
  1465     s_event = gst_event_new_seek (rate,
       
  1466         GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
       
  1467         GST_SEEK_TYPE_SET, position);
       
  1468   }
       
  1469 
       
  1470   GST_DEBUG ("rate changed to %lf", rate);
       
  1471 
       
  1472   res = send_event (s_event);
       
  1473 
       
  1474   if (res) {
       
  1475     if (flush_seek) {
       
  1476       gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
       
  1477     }
       
  1478   } else
       
  1479     g_print ("seek failed\n");
       
  1480 }
       
  1481 
       
  1482 static void
       
  1483 update_flag (GstPipeline * pipeline, gint num, gboolean state)
       
  1484 {
       
  1485   gint flags;
       
  1486 
       
  1487   g_object_get (pipeline, "flags", &flags, NULL);
       
  1488   if (state)
       
  1489     flags |= (1 << num);
       
  1490   else
       
  1491     flags &= ~(1 << num);
       
  1492   g_object_set (pipeline, "flags", flags, NULL);
       
  1493 }
       
  1494 
       
  1495 static void
       
  1496 vis_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1497 {
       
  1498   gboolean state;
       
  1499 
       
  1500   state = gtk_toggle_button_get_active (button);
       
  1501   update_flag (pipeline, 3, state);
       
  1502   gtk_widget_set_sensitive (vis_combo, state);
       
  1503 }
       
  1504 
       
  1505 static void
       
  1506 audio_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1507 {
       
  1508   update_flag (pipeline, 1, gtk_toggle_button_get_active (button));
       
  1509 }
       
  1510 
       
  1511 static void
       
  1512 video_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1513 {
       
  1514   update_flag (pipeline, 0, gtk_toggle_button_get_active (button));
       
  1515 }
       
  1516 
       
  1517 static void
       
  1518 text_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1519 {
       
  1520   update_flag (pipeline, 2, gtk_toggle_button_get_active (button));
       
  1521 }
       
  1522 
       
  1523 static void
       
  1524 mute_toggle_cb (GtkToggleButton * button, GstPipeline * pipeline)
       
  1525 {
       
  1526   gboolean mute;
       
  1527 
       
  1528   mute = gtk_toggle_button_get_active (button);
       
  1529   g_object_set (pipeline, "mute", mute, NULL);
       
  1530 }
       
  1531 
       
  1532 static void
       
  1533 clear_streams (GstElement * pipeline)
       
  1534 {
       
  1535   gint i;
       
  1536 
       
  1537   /* remove previous info */
       
  1538   for (i = 0; i < n_video; i++)
       
  1539     gtk_combo_box_remove_text (GTK_COMBO_BOX (video_combo), 0);
       
  1540   for (i = 0; i < n_audio; i++)
       
  1541     gtk_combo_box_remove_text (GTK_COMBO_BOX (audio_combo), 0);
       
  1542   for (i = 0; i < n_text; i++)
       
  1543     gtk_combo_box_remove_text (GTK_COMBO_BOX (text_combo), 0);
       
  1544 
       
  1545   n_audio = n_video = n_text = 0;
       
  1546   gtk_widget_set_sensitive (video_combo, FALSE);
       
  1547   gtk_widget_set_sensitive (audio_combo, FALSE);
       
  1548   gtk_widget_set_sensitive (text_combo, FALSE);
       
  1549 
       
  1550   need_streams = TRUE;
       
  1551 }
       
  1552 
       
  1553 static void
       
  1554 update_streams (GstPipeline * pipeline)
       
  1555 {
       
  1556   gint i;
       
  1557 
       
  1558   if (pipeline_type == 16 && need_streams) {
       
  1559     GstTagList *tags;
       
  1560     gchar *name;
       
  1561     gint active_idx;
       
  1562 
       
  1563     /* remove previous info */
       
  1564     clear_streams (GST_ELEMENT_CAST (pipeline));
       
  1565 
       
  1566     /* here we get and update the different streams detected by playbin2 */
       
  1567     g_object_get (pipeline, "n-video", &n_video, NULL);
       
  1568     g_object_get (pipeline, "n-audio", &n_audio, NULL);
       
  1569     g_object_get (pipeline, "n-text", &n_text, NULL);
       
  1570 
       
  1571     g_print ("video %d, audio %d, text %d\n", n_video, n_audio, n_text);
       
  1572 
       
  1573     active_idx = 0;
       
  1574     for (i = 0; i < n_video; i++) {
       
  1575       g_signal_emit_by_name (pipeline, "get-video-tags", i, &tags);
       
  1576       /* find good name for the label */
       
  1577       name = g_strdup_printf ("video %d", i + 1);
       
  1578       gtk_combo_box_append_text (GTK_COMBO_BOX (video_combo), name);
       
  1579       g_free (name);
       
  1580     }
       
  1581     gtk_widget_set_sensitive (video_combo, n_video > 0);
       
  1582     gtk_combo_box_set_active (GTK_COMBO_BOX (video_combo), active_idx);
       
  1583 
       
  1584     active_idx = 0;
       
  1585     for (i = 0; i < n_audio; i++) {
       
  1586       g_signal_emit_by_name (pipeline, "get-audio-tags", i, &tags);
       
  1587       /* find good name for the label */
       
  1588       name = g_strdup_printf ("audio %d", i + 1);
       
  1589       gtk_combo_box_append_text (GTK_COMBO_BOX (audio_combo), name);
       
  1590       g_free (name);
       
  1591     }
       
  1592     gtk_widget_set_sensitive (audio_combo, n_audio > 0);
       
  1593     gtk_combo_box_set_active (GTK_COMBO_BOX (audio_combo), active_idx);
       
  1594 
       
  1595     active_idx = 0;
       
  1596     for (i = 0; i < n_text; i++) {
       
  1597       g_signal_emit_by_name (pipeline, "get-text-tags", i, &tags);
       
  1598       /* find good name for the label */
       
  1599       name = g_strdup_printf ("text %d", i + 1);
       
  1600       gtk_combo_box_append_text (GTK_COMBO_BOX (text_combo), name);
       
  1601       g_free (name);
       
  1602     }
       
  1603     gtk_widget_set_sensitive (text_combo, n_text > 0);
       
  1604     gtk_combo_box_set_active (GTK_COMBO_BOX (text_combo), active_idx);
       
  1605 
       
  1606     need_streams = FALSE;
       
  1607   }
       
  1608 }
       
  1609 
       
  1610 static void
       
  1611 video_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
       
  1612 {
       
  1613   g_object_set (pipeline, "current-video", gtk_combo_box_get_active (combo),
       
  1614       NULL);
       
  1615 }
       
  1616 
       
  1617 static void
       
  1618 audio_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
       
  1619 {
       
  1620   g_object_set (pipeline, "current-audio", gtk_combo_box_get_active (combo),
       
  1621       NULL);
       
  1622 }
       
  1623 
       
  1624 static void
       
  1625 text_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
       
  1626 {
       
  1627   g_object_set (pipeline, "current-text", gtk_combo_box_get_active (combo),
       
  1628       NULL);
       
  1629 }
       
  1630 
       
  1631 static gboolean
       
  1632 filter_features (GstPluginFeature * feature, gpointer data)
       
  1633 {
       
  1634   GstElementFactory *f;
       
  1635 
       
  1636   if (!GST_IS_ELEMENT_FACTORY (feature))
       
  1637     return FALSE;
       
  1638   f = GST_ELEMENT_FACTORY (feature);
       
  1639   if (!g_strrstr (gst_element_factory_get_klass (f), "Visualization"))
       
  1640     return FALSE;
       
  1641 
       
  1642   return TRUE;
       
  1643 }
       
  1644 
       
  1645 static void
       
  1646 init_visualization_features (void)
       
  1647 {
       
  1648   GList *list, *walk;
       
  1649 
       
  1650   vis_entries = g_array_new (FALSE, FALSE, sizeof (VisEntry));
       
  1651 
       
  1652   list = gst_registry_feature_filter (gst_registry_get_default (),
       
  1653       filter_features, FALSE, NULL);
       
  1654 
       
  1655   for (walk = list; walk; walk = g_list_next (walk)) {
       
  1656     VisEntry entry;
       
  1657     const gchar *name;
       
  1658 
       
  1659     entry.factory = GST_ELEMENT_FACTORY (walk->data);
       
  1660     name = gst_element_factory_get_longname (entry.factory);
       
  1661 
       
  1662     g_array_append_val (vis_entries, entry);
       
  1663     gtk_combo_box_append_text (GTK_COMBO_BOX (vis_combo), name);
       
  1664   }
       
  1665   gtk_combo_box_set_active (GTK_COMBO_BOX (vis_combo), 0);
       
  1666 }
       
  1667 
       
  1668 static void
       
  1669 vis_combo_cb (GtkComboBox * combo, GstPipeline * pipeline)
       
  1670 {
       
  1671   guint index;
       
  1672   VisEntry *entry;
       
  1673   GstElement *element;
       
  1674 
       
  1675   /* get the selected index and get the factory for this index */
       
  1676   index = gtk_combo_box_get_active (GTK_COMBO_BOX (vis_combo));
       
  1677   entry = &g_array_index (vis_entries, VisEntry, index);
       
  1678   /* create an instance of the element from the factory */
       
  1679   element = gst_element_factory_create (entry->factory, NULL);
       
  1680   if (!element)
       
  1681     return;
       
  1682 
       
  1683   /* set vis plugin for playbin2 */
       
  1684   g_object_set (pipeline, "vis-plugin", element, NULL);
       
  1685 }
       
  1686 
       
  1687 static void
       
  1688 volume_spinbutton_changed_cb (GtkSpinButton * button, GstPipeline * pipeline)
       
  1689 {
       
  1690   gdouble volume;
       
  1691 
       
  1692   volume = gtk_spin_button_get_value (button);
       
  1693 
       
  1694   g_object_set (pipeline, "volume", volume, NULL);
       
  1695 }
       
  1696 
       
  1697 static void
       
  1698 shot_cb (GtkButton * button, gpointer data)
       
  1699 {
       
  1700   GstBuffer *buffer;
       
  1701   GstCaps *caps;
       
  1702 
       
  1703   /* convert to our desired format (RGB24) */
       
  1704   caps = gst_caps_new_simple ("video/x-raw-rgb",
       
  1705       "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24,
       
  1706       /* Note: we don't ask for a specific width/height here, so that
       
  1707        * videoscale can adjust dimensions from a non-1/1 pixel aspect
       
  1708        * ratio to a 1/1 pixel-aspect-ratio */
       
  1709       "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
       
  1710       "endianness", G_TYPE_INT, G_BIG_ENDIAN,
       
  1711       "red_mask", G_TYPE_INT, 0xff0000,
       
  1712       "green_mask", G_TYPE_INT, 0x00ff00,
       
  1713       "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
       
  1714 
       
  1715   /* convert the latest frame to the requested format */
       
  1716   g_signal_emit_by_name (pipeline, "convert-frame", caps, &buffer);
       
  1717   gst_caps_unref (caps);
       
  1718 
       
  1719   if (buffer) {
       
  1720     GstCaps *caps;
       
  1721     GstStructure *s;
       
  1722     gboolean res;
       
  1723     gint width, height;
       
  1724     GdkPixbuf *pixbuf;
       
  1725     GError *error = NULL;
       
  1726 
       
  1727     /* get the snapshot buffer format now. We set the caps on the appsink so
       
  1728      * that it can only be an rgb buffer. The only thing we have not specified
       
  1729      * on the caps is the height, which is dependant on the pixel-aspect-ratio
       
  1730      * of the source material */
       
  1731     caps = GST_BUFFER_CAPS (buffer);
       
  1732     if (!caps) {
       
  1733       g_warning ("could not get snapshot format\n");
       
  1734       goto done;
       
  1735     }
       
  1736     s = gst_caps_get_structure (caps, 0);
       
  1737 
       
  1738     /* we need to get the final caps on the buffer to get the size */
       
  1739     res = gst_structure_get_int (s, "width", &width);
       
  1740     res |= gst_structure_get_int (s, "height", &height);
       
  1741     if (!res) {
       
  1742       g_warning ("could not get snapshot dimension\n");
       
  1743       goto done;
       
  1744     }
       
  1745 
       
  1746     /* create pixmap from buffer and save, gstreamer video buffers have a stride
       
  1747      * that is rounded up to the nearest multiple of 4 */
       
  1748     pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
       
  1749         GDK_COLORSPACE_RGB, FALSE, 8, width, height,
       
  1750         GST_ROUND_UP_4 (width * 3), NULL, NULL);
       
  1751 
       
  1752     /* save the pixbuf */
       
  1753     gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
       
  1754 
       
  1755   done:
       
  1756     gst_buffer_unref (buffer);
       
  1757   }
       
  1758 }
       
  1759 
       
  1760 static void
       
  1761 message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
       
  1762 {
       
  1763   const GstStructure *s;
       
  1764 
       
  1765   s = gst_message_get_structure (message);
       
  1766   g_print ("message from \"%s\" (%s): ",
       
  1767       GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
       
  1768       gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
       
  1769   if (s) {
       
  1770     gchar *sstr;
       
  1771 
       
  1772     sstr = gst_structure_to_string (s);
       
  1773     g_print ("%s\n", sstr);
       
  1774     g_free (sstr);
       
  1775   } else {
       
  1776     g_print ("no message details\n");
       
  1777   }
       
  1778 }
       
  1779 
       
  1780 static void
       
  1781 msg_async_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
       
  1782 {
       
  1783   GST_DEBUG ("async done");
       
  1784   /* when we get ASYNC_DONE we can query position, duration and other
       
  1785    * properties */
       
  1786   update_scale (pipeline);
       
  1787 
       
  1788   /* update the available streams */
       
  1789   update_streams (pipeline);
       
  1790 }
       
  1791 
       
  1792 static void
       
  1793 msg_state_changed (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
       
  1794 {
       
  1795   const GstStructure *s;
       
  1796 
       
  1797   s = gst_message_get_structure (message);
       
  1798 
       
  1799   /* We only care about state changed on the pipeline */
       
  1800   if (s && GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) {
       
  1801     GstState old, new, pending;
       
  1802 
       
  1803     gst_message_parse_state_changed (message, &old, &new, &pending);
       
  1804 
       
  1805     /* When state of the pipeline changes to paused or playing we start updating scale */
       
  1806     if (new == GST_STATE_PLAYING) {
       
  1807       set_update_scale (TRUE);
       
  1808     } else {
       
  1809       set_update_scale (FALSE);
       
  1810     }
       
  1811   }
       
  1812 }
       
  1813 
       
  1814 static void
       
  1815 msg_segment_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
       
  1816 {
       
  1817   GstEvent *s_event;
       
  1818   GstSeekFlags flags;
       
  1819   gboolean res;
       
  1820   GstFormat format;
       
  1821 
       
  1822   GST_DEBUG ("position is %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
       
  1823   gst_message_parse_segment_done (message, &format, &position);
       
  1824   GST_DEBUG ("end of segment at %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
       
  1825 
       
  1826   flags = 0;
       
  1827   /* in the segment-done callback we never flush as this would not make sense
       
  1828    * for seamless playback. */
       
  1829   if (loop_seek)
       
  1830     flags = GST_SEEK_FLAG_SEGMENT;
       
  1831 
       
  1832   s_event = gst_event_new_seek (rate,
       
  1833       GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
       
  1834       GST_SEEK_TYPE_SET, duration);
       
  1835 
       
  1836   GST_DEBUG ("restart loop with rate %lf to 0 / %" GST_TIME_FORMAT,
       
  1837       rate, GST_TIME_ARGS (duration));
       
  1838 
       
  1839   res = send_event (s_event);
       
  1840   if (!res)
       
  1841     g_print ("segment seek failed\n");
       
  1842 }
       
  1843 
       
  1844 static void
       
  1845 connect_bus_signals (GstElement * pipeline)
       
  1846 {
       
  1847   GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
       
  1848 
       
  1849   gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
       
  1850 
       
  1851   g_signal_connect (bus, "message::state-changed",
       
  1852       (GCallback) msg_state_changed, pipeline);
       
  1853   g_signal_connect (bus, "message::segment-done", (GCallback) msg_segment_done,
       
  1854       pipeline);
       
  1855   g_signal_connect (bus, "message::async-done", (GCallback) msg_async_done,
       
  1856       pipeline);
       
  1857 
       
  1858   g_signal_connect (bus, "message::new-clock", (GCallback) message_received,
       
  1859       pipeline);
       
  1860   g_signal_connect (bus, "message::error", (GCallback) message_received,
       
  1861       pipeline);
       
  1862   g_signal_connect (bus, "message::warning", (GCallback) message_received,
       
  1863       pipeline);
       
  1864   g_signal_connect (bus, "message::eos", (GCallback) message_received,
       
  1865       pipeline);
       
  1866   g_signal_connect (bus, "message::tag", (GCallback) message_received,
       
  1867       pipeline);
       
  1868   g_signal_connect (bus, "message::element", (GCallback) message_received,
       
  1869       pipeline);
       
  1870   g_signal_connect (bus, "message::segment-done", (GCallback) message_received,
       
  1871       pipeline);
       
  1872 
       
  1873   gst_object_unref (bus);
       
  1874 }
       
  1875 
       
  1876 static void
       
  1877 print_usage (int argc, char **argv)
       
  1878 {
       
  1879   gint i;
       
  1880 
       
  1881   g_print ("usage: %s <type> <filename>\n", argv[0]);
       
  1882   g_print ("   possible types:\n");
       
  1883 
       
  1884   for (i = 0; i < NUM_TYPES; i++) {
       
  1885     g_print ("     %d = %s\n", i, pipelines[i].name);
       
  1886   }
       
  1887 }
       
  1888 
       
  1889 int
       
  1890 main (int argc, char **argv)
       
  1891 {
       
  1892   GtkWidget *window, *hbox, *vbox, *panel, *boxes, *flagtable, *boxes2;
       
  1893   GtkWidget *play_button, *pause_button, *stop_button, *shot_button;
       
  1894   GtkWidget *accurate_checkbox, *key_checkbox, *loop_checkbox, *flush_checkbox;
       
  1895   GtkWidget *scrub_checkbox, *play_scrub_checkbox, *rate_spinbutton;
       
  1896   GtkWidget *rate_label;
       
  1897   GtkTooltips *tips;
       
  1898   GOptionEntry options[] = {
       
  1899     {"stats", 's', 0, G_OPTION_ARG_NONE, &stats,
       
  1900         "Show pad stats", NULL},
       
  1901     {"elem", 'e', 0, G_OPTION_ARG_NONE, &elem_seek,
       
  1902         "Seek on elements instead of pads", NULL},
       
  1903     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
       
  1904         "Verbose properties", NULL},
       
  1905     {NULL}
       
  1906   };
       
  1907   GOptionContext *ctx;
       
  1908   GError *err = NULL;
       
  1909 
       
  1910   if (!g_thread_supported ())
       
  1911     g_thread_init (NULL);
       
  1912 
       
  1913   ctx = g_option_context_new ("- test seeking in gsteamer");
       
  1914   g_option_context_add_main_entries (ctx, options, NULL);
       
  1915   g_option_context_add_group (ctx, gst_init_get_option_group ());
       
  1916 
       
  1917   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
       
  1918     g_print ("Error initializing: %s\n", err->message);
       
  1919     exit (1);
       
  1920   }
       
  1921 
       
  1922   GST_DEBUG_CATEGORY_INIT (seek_debug, "seek", 0, "seek example");
       
  1923 
       
  1924   gtk_init (&argc, &argv);
       
  1925 
       
  1926   if (argc != 3) {
       
  1927     print_usage (argc, argv);
       
  1928     exit (-1);
       
  1929   }
       
  1930 
       
  1931   pipeline_type = atoi (argv[1]);
       
  1932 
       
  1933   if (pipeline_type < 0 || pipeline_type >= NUM_TYPES) {
       
  1934     print_usage (argc, argv);
       
  1935     exit (-1);
       
  1936   }
       
  1937 
       
  1938   pipeline_spec = argv[2];
       
  1939 
       
  1940   pipeline = pipelines[pipeline_type].func (pipeline_spec);
       
  1941   g_assert (pipeline);
       
  1942 
       
  1943   /* initialize gui elements ... */
       
  1944   tips = gtk_tooltips_new ();
       
  1945   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
       
  1946   hbox = gtk_hbox_new (FALSE, 0);
       
  1947   vbox = gtk_vbox_new (FALSE, 0);
       
  1948   flagtable = gtk_table_new (4, 2, FALSE);
       
  1949   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
       
  1950 
       
  1951   /* media controls */
       
  1952   play_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
       
  1953   pause_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PAUSE);
       
  1954   stop_button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_STOP);
       
  1955 
       
  1956   /* seek flags */
       
  1957   accurate_checkbox = gtk_check_button_new_with_label ("Accurate Seek");
       
  1958   key_checkbox = gtk_check_button_new_with_label ("Key-unit Seek");
       
  1959   loop_checkbox = gtk_check_button_new_with_label ("Loop");
       
  1960   flush_checkbox = gtk_check_button_new_with_label ("Flush");
       
  1961   scrub_checkbox = gtk_check_button_new_with_label ("Scrub");
       
  1962   play_scrub_checkbox = gtk_check_button_new_with_label ("Play Scrub");
       
  1963   rate_spinbutton = gtk_spin_button_new_with_range (-100, 100, 0.1);
       
  1964   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (rate_spinbutton), 3);
       
  1965   rate_label = gtk_label_new ("Rate");
       
  1966 
       
  1967   gtk_tooltips_set_tip (tips, accurate_checkbox,
       
  1968       "accurate position is requested, this might be considerably slower for some formats",
       
  1969       NULL);
       
  1970   gtk_tooltips_set_tip (tips, key_checkbox,
       
  1971       "seek to the nearest keyframe. This might be faster but less accurate",
       
  1972       NULL);
       
  1973   gtk_tooltips_set_tip (tips, loop_checkbox, "loop playback", NULL);
       
  1974   gtk_tooltips_set_tip (tips, flush_checkbox, "flush pipeline after seeking",
       
  1975       NULL);
       
  1976   gtk_tooltips_set_tip (tips, rate_spinbutton, "define the playback rate, "
       
  1977       "negative value trigger reverse playback", NULL);
       
  1978   gtk_tooltips_set_tip (tips, scrub_checkbox, "show images while seeking",
       
  1979       NULL);
       
  1980   gtk_tooltips_set_tip (tips, play_scrub_checkbox, "play video while seeking",
       
  1981       NULL);
       
  1982 
       
  1983   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (flush_checkbox), TRUE);
       
  1984   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scrub_checkbox), TRUE);
       
  1985 
       
  1986   gtk_spin_button_set_value (GTK_SPIN_BUTTON (rate_spinbutton), rate);
       
  1987 
       
  1988   /* seek bar */
       
  1989   adjustment =
       
  1990       GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
       
  1991   hscale = gtk_hscale_new (adjustment);
       
  1992   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
       
  1993 #if GTK_CHECK_VERSION(2,12,0)
       
  1994   gtk_range_set_show_fill_level (GTK_RANGE (hscale), TRUE);
       
  1995   gtk_range_set_fill_level (GTK_RANGE (hscale), 100.0);
       
  1996 #endif
       
  1997   gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
       
  1998 
       
  1999   gtk_signal_connect (GTK_OBJECT (hscale),
       
  2000       "button_press_event", G_CALLBACK (start_seek), pipeline);
       
  2001   gtk_signal_connect (GTK_OBJECT (hscale),
       
  2002       "button_release_event", G_CALLBACK (stop_seek), pipeline);
       
  2003   gtk_signal_connect (GTK_OBJECT (hscale),
       
  2004       "format_value", G_CALLBACK (format_value), pipeline);
       
  2005 
       
  2006   if (pipeline_type == 16) {
       
  2007     /* the playbin2 panel controls for the video/audio/subtitle tracks */
       
  2008     panel = gtk_hbox_new (FALSE, 0);
       
  2009     video_combo = gtk_combo_box_new_text ();
       
  2010     audio_combo = gtk_combo_box_new_text ();
       
  2011     text_combo = gtk_combo_box_new_text ();
       
  2012     gtk_widget_set_sensitive (video_combo, FALSE);
       
  2013     gtk_widget_set_sensitive (audio_combo, FALSE);
       
  2014     gtk_widget_set_sensitive (text_combo, FALSE);
       
  2015     gtk_box_pack_start (GTK_BOX (panel), video_combo, TRUE, TRUE, 2);
       
  2016     gtk_box_pack_start (GTK_BOX (panel), audio_combo, TRUE, TRUE, 2);
       
  2017     gtk_box_pack_start (GTK_BOX (panel), text_combo, TRUE, TRUE, 2);
       
  2018     g_signal_connect (G_OBJECT (video_combo), "changed",
       
  2019         G_CALLBACK (video_combo_cb), pipeline);
       
  2020     g_signal_connect (G_OBJECT (audio_combo), "changed",
       
  2021         G_CALLBACK (audio_combo_cb), pipeline);
       
  2022     g_signal_connect (G_OBJECT (text_combo), "changed",
       
  2023         G_CALLBACK (text_combo_cb), pipeline);
       
  2024     /* playbin2 panel for flag checkboxes and volume/mute */
       
  2025     boxes = gtk_hbox_new (FALSE, 0);
       
  2026     vis_checkbox = gtk_check_button_new_with_label ("Vis");
       
  2027     video_checkbox = gtk_check_button_new_with_label ("Video");
       
  2028     audio_checkbox = gtk_check_button_new_with_label ("Audio");
       
  2029     text_checkbox = gtk_check_button_new_with_label ("Text");
       
  2030     mute_checkbox = gtk_check_button_new_with_label ("Mute");
       
  2031     volume_spinbutton = gtk_spin_button_new_with_range (0, 10.0, 0.1);
       
  2032     gtk_spin_button_set_value (GTK_SPIN_BUTTON (volume_spinbutton), 1.0);
       
  2033     gtk_box_pack_start (GTK_BOX (boxes), vis_checkbox, TRUE, TRUE, 2);
       
  2034     gtk_box_pack_start (GTK_BOX (boxes), audio_checkbox, TRUE, TRUE, 2);
       
  2035     gtk_box_pack_start (GTK_BOX (boxes), video_checkbox, TRUE, TRUE, 2);
       
  2036     gtk_box_pack_start (GTK_BOX (boxes), text_checkbox, TRUE, TRUE, 2);
       
  2037     gtk_box_pack_start (GTK_BOX (boxes), mute_checkbox, TRUE, TRUE, 2);
       
  2038     gtk_box_pack_start (GTK_BOX (boxes), volume_spinbutton, TRUE, TRUE, 2);
       
  2039     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (vis_checkbox), FALSE);
       
  2040     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (audio_checkbox), TRUE);
       
  2041     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (video_checkbox), TRUE);
       
  2042     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_checkbox), TRUE);
       
  2043     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mute_checkbox), FALSE);
       
  2044     g_signal_connect (G_OBJECT (vis_checkbox), "toggled",
       
  2045         G_CALLBACK (vis_toggle_cb), pipeline);
       
  2046     g_signal_connect (G_OBJECT (audio_checkbox), "toggled",
       
  2047         G_CALLBACK (audio_toggle_cb), pipeline);
       
  2048     g_signal_connect (G_OBJECT (video_checkbox), "toggled",
       
  2049         G_CALLBACK (video_toggle_cb), pipeline);
       
  2050     g_signal_connect (G_OBJECT (text_checkbox), "toggled",
       
  2051         G_CALLBACK (text_toggle_cb), pipeline);
       
  2052     g_signal_connect (G_OBJECT (mute_checkbox), "toggled",
       
  2053         G_CALLBACK (mute_toggle_cb), pipeline);
       
  2054     g_signal_connect (G_OBJECT (volume_spinbutton), "value_changed",
       
  2055         G_CALLBACK (volume_spinbutton_changed_cb), pipeline);
       
  2056     /* playbin2 panel for snapshot */
       
  2057     boxes2 = gtk_hbox_new (FALSE, 0);
       
  2058     shot_button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
       
  2059     gtk_tooltips_set_tip (tips, shot_button,
       
  2060         "save a screenshot .png in the current directory", NULL);
       
  2061     g_signal_connect (G_OBJECT (shot_button), "clicked", G_CALLBACK (shot_cb),
       
  2062         pipeline);
       
  2063     vis_combo = gtk_combo_box_new_text ();
       
  2064     g_signal_connect (G_OBJECT (vis_combo), "changed",
       
  2065         G_CALLBACK (vis_combo_cb), pipeline);
       
  2066     gtk_widget_set_sensitive (vis_combo, FALSE);
       
  2067     gtk_box_pack_start (GTK_BOX (boxes2), shot_button, TRUE, TRUE, 2);
       
  2068     gtk_box_pack_start (GTK_BOX (boxes2), vis_combo, TRUE, TRUE, 2);
       
  2069 
       
  2070     /* fill the vis combo box and the array of factories */
       
  2071     init_visualization_features ();
       
  2072   } else {
       
  2073     panel = boxes = boxes2 = NULL;
       
  2074   }
       
  2075 
       
  2076   /* do the packing stuff ... */
       
  2077   gtk_window_set_default_size (GTK_WINDOW (window), 250, 96);
       
  2078   gtk_container_add (GTK_CONTAINER (window), vbox);
       
  2079   gtk_container_add (GTK_CONTAINER (vbox), hbox);
       
  2080   gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
       
  2081   gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
       
  2082   gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
       
  2083   gtk_box_pack_start (GTK_BOX (hbox), flagtable, FALSE, FALSE, 2);
       
  2084   gtk_table_attach_defaults (GTK_TABLE (flagtable), accurate_checkbox, 0, 1, 0,
       
  2085       1);
       
  2086   gtk_table_attach_defaults (GTK_TABLE (flagtable), flush_checkbox, 1, 2, 0, 1);
       
  2087   gtk_table_attach_defaults (GTK_TABLE (flagtable), loop_checkbox, 2, 3, 0, 1);
       
  2088   gtk_table_attach_defaults (GTK_TABLE (flagtable), key_checkbox, 0, 1, 1, 2);
       
  2089   gtk_table_attach_defaults (GTK_TABLE (flagtable), scrub_checkbox, 1, 2, 1, 2);
       
  2090   gtk_table_attach_defaults (GTK_TABLE (flagtable), play_scrub_checkbox, 2, 3,
       
  2091       1, 2);
       
  2092   gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_label, 3, 4, 0, 1);
       
  2093   gtk_table_attach_defaults (GTK_TABLE (flagtable), rate_spinbutton, 3, 4, 1,
       
  2094       2);
       
  2095   if (panel && boxes && boxes2) {
       
  2096     gtk_box_pack_start (GTK_BOX (vbox), panel, TRUE, TRUE, 2);
       
  2097     gtk_box_pack_start (GTK_BOX (vbox), boxes, TRUE, TRUE, 2);
       
  2098     gtk_box_pack_start (GTK_BOX (vbox), boxes2, TRUE, TRUE, 2);
       
  2099   }
       
  2100   gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
       
  2101 
       
  2102   /* connect things ... */
       
  2103   g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
       
  2104       pipeline);
       
  2105   g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
       
  2106       pipeline);
       
  2107   g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
       
  2108       pipeline);
       
  2109   g_signal_connect (G_OBJECT (accurate_checkbox), "toggled",
       
  2110       G_CALLBACK (accurate_toggle_cb), pipeline);
       
  2111   g_signal_connect (G_OBJECT (key_checkbox), "toggled",
       
  2112       G_CALLBACK (key_toggle_cb), pipeline);
       
  2113   g_signal_connect (G_OBJECT (loop_checkbox), "toggled",
       
  2114       G_CALLBACK (loop_toggle_cb), pipeline);
       
  2115   g_signal_connect (G_OBJECT (flush_checkbox), "toggled",
       
  2116       G_CALLBACK (flush_toggle_cb), pipeline);
       
  2117   g_signal_connect (G_OBJECT (scrub_checkbox), "toggled",
       
  2118       G_CALLBACK (scrub_toggle_cb), pipeline);
       
  2119   g_signal_connect (G_OBJECT (play_scrub_checkbox), "toggled",
       
  2120       G_CALLBACK (play_scrub_toggle_cb), pipeline);
       
  2121   g_signal_connect (G_OBJECT (rate_spinbutton), "value_changed",
       
  2122       G_CALLBACK (rate_spinbutton_changed_cb), pipeline);
       
  2123 
       
  2124   g_signal_connect (G_OBJECT (window), "delete-event", gtk_main_quit, NULL);
       
  2125 
       
  2126   /* show the gui. */
       
  2127   gtk_widget_show_all (window);
       
  2128 
       
  2129   if (verbose) {
       
  2130     g_signal_connect (pipeline, "deep_notify",
       
  2131         G_CALLBACK (gst_object_default_deep_notify), NULL);
       
  2132   }
       
  2133 
       
  2134   connect_bus_signals (pipeline);
       
  2135   gtk_main ();
       
  2136 
       
  2137   g_print ("NULL pipeline\n");
       
  2138   gst_element_set_state (pipeline, GST_STATE_NULL);
       
  2139 
       
  2140   g_print ("free pipeline\n");
       
  2141   gst_object_unref (pipeline);
       
  2142 
       
  2143   return 0;
       
  2144 }