gst-plugins-mythtv/src/gstmythtvsrc.c.new
author renatofilho
Tue Apr 03 19:42:17 2007 +0100 (2007-04-03)
branchtrunk
changeset 487 ab3aa66009de
parent 10 00c73ffe40ad
permissions -rwxr-xr-x
[svn r492] created client lib
     1 /* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2 -*- */
     2 /* GStreamer MythTV Plug-in
     3  * Copyright (C) <2006> Rosfran Borges <rosfran.borges@indt.org.br>
     4  *
     5  * This library is free software; you can redistribute it and/or
     6  * modify it under the terms of the GNU Library General Public
     7  * License as published by the Free Software Foundation; either
     8  * version 2 of the License, or (at your option) any later version.
     9  *
    10  * This library is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  * Library General Public License for more 
    14  */
    15 
    16 #ifdef HAVE_CONFIG_H
    17 #include "config.h"
    18 #endif
    19 
    20 #include "gstmythtvsrc.h"
    21 #include "myth_file_transfer.h"
    22 #include "myth_livetv.h"
    23 
    24 #include <gmyth/gmyth_socket.h>
    25 #include <gmyth/gmyth_tvchain.h>
    26 
    27 #include <string.h>
    28 #include <unistd.h>
    29 
    30 GST_DEBUG_CATEGORY_STATIC (mythtvsrc_debug);
    31 #define GST_CAT_DEFAULT mythtvsrc_debug
    32 
    33 #define GST_MYTHTV_ID_NUM		1
    34 
    35 #define MYTHTV_VERSION_DEFAULT		30
    36 
    37 #define MYTHTV_TRANSFER_MAX_WAITS	100
    38 
    39 #define MYTHTV_TRANSFER_MAX_BUFFER	( 32*1024  )
    40 
    41 /* 4*1024 ??? */
    42 #define MAX_READ_SIZE                   ( 16*1024 )
    43 
    44 #define ENABLE_TIMING_POSITION		1
    45 
    46 /* stablish a maximum iteration value to the IS_RECORDING message */
    47 static guint wait_to_transfer = 0;
    48 
    49 static const GstElementDetails gst_mythtv_src_details =
    50 GST_ELEMENT_DETAILS ("MythTV client source",
    51     "Source/Network",
    52     "Control and receive data as a client over the network via raw socket connections using the MythTV protocol",
    53     "Rosfran Borges <rosfran.borges@indt.org.br>");
    54 
    55 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
    56     GST_PAD_SRC,
    57     GST_PAD_ALWAYS,
    58     GST_STATIC_CAPS_ANY);
    59 
    60 static GstTask *update_size_task = NULL;
    61 
    62 static GStaticRecMutex update_size_mutex = G_STATIC_REC_MUTEX_INIT;
    63 
    64 enum
    65 {
    66   PROP_0,
    67   PROP_LOCATION,
    68   PROP_URI,
    69 #ifndef GST_DISABLE_GST_DEBUG
    70   PROP_MYTHTV_DBG,
    71 #endif
    72   PROP_MYTHTV_VERSION,
    73   PROP_MYTHTV_LIVE,
    74   PROP_MYTHTV_LIVEID,
    75   PROP_MYTHTV_LIVE_CHAINID
    76 };
    77 
    78 static void gst_mythtv_src_finalize (GObject * gobject);
    79 
    80 static GstFlowReturn gst_mythtv_src_create (GstBaseSrc * psrc,
    81     guint64 offset, guint size, GstBuffer ** outbuf);
    82 static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc);
    83 static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc);
    84 static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size);
    85 static gboolean gst_mythtv_src_is_seekable( GstBaseSrc *base_src );
    86 
    87 static void gst_mythtv_src_set_property (GObject * object, guint prop_id,
    88     const GValue * value, GParamSpec * pspec);
    89 static void gst_mythtv_src_get_property (GObject * object, guint prop_id,
    90     GValue * value, GParamSpec * pspec);
    91 
    92 static void
    93 gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
    94 
    95 static gboolean
    96 gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event);
    97 
    98   static void
    99 _urihandler_init (GType type)
   100 {
   101   static const GInterfaceInfo urihandler_info = {
   102     gst_mythtv_src_uri_handler_init,
   103     NULL,
   104     NULL
   105   };
   106 
   107   g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
   108 
   109   GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
   110       "MythTV src");
   111 }
   112 
   113 GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstBaseSrc,
   114     GST_TYPE_BASE_SRC, _urihandler_init);
   115 
   116   static void
   117 gst_mythtv_src_base_init (gpointer g_class)
   118 {
   119   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
   120 
   121   gst_element_class_add_pad_template (element_class,
   122       gst_static_pad_template_get (&srctemplate));
   123 
   124   gst_element_class_set_details (element_class, &gst_mythtv_src_details);
   125 }
   126 
   127   static void
   128 gst_mythtv_src_class_init (GstMythtvSrcClass * klass)
   129 {
   130   GObjectClass *gobject_class;
   131   GstBaseSrcClass *gstbasesrc_class;
   132 
   133   gobject_class = (GObjectClass *) klass;
   134   gstbasesrc_class = (GstBaseSrcClass *) klass;
   135 
   136   gobject_class->set_property = gst_mythtv_src_set_property;
   137   gobject_class->get_property = gst_mythtv_src_get_property;
   138   gobject_class->finalize = gst_mythtv_src_finalize;
   139 
   140   g_object_class_install_property
   141     (gobject_class, PROP_LOCATION,
   142      g_param_spec_string ("location", "Location",
   143        "The location. In the form:"
   144        "\n\t\t\tmyth://a.com/file.nuv"
   145        "\n\t\t\tmyth://a.com:23223/file.nuv "
   146        "\n\t\t\ta.com/file.nuv - default scheme 'myth'",
   147        "", G_PARAM_READWRITE));
   148 
   149   g_object_class_install_property
   150     (gobject_class, PROP_URI,
   151      g_param_spec_string ("uri", "Uri",
   152        "The location in form of a URI (deprecated; use location)",
   153        "", G_PARAM_READWRITE));
   154 
   155   g_object_class_install_property
   156     (gobject_class, PROP_MYTHTV_VERSION,
   157      g_param_spec_int ("mythtv-version", "mythtv-version",
   158        "Change Myth TV version",
   159        26, 30, 26, G_PARAM_READWRITE));
   160 
   161   g_object_class_install_property
   162     (gobject_class, PROP_MYTHTV_LIVEID,
   163      g_param_spec_int ("mythtv-live-id", "mythtv-live-id",
   164        "Change Myth TV version",
   165        0, 200, GST_MYTHTV_ID_NUM, G_PARAM_READWRITE));
   166 
   167   g_object_class_install_property
   168     (gobject_class, PROP_MYTHTV_LIVE_CHAINID,
   169      g_param_spec_string ("mythtv-live-chainid", "mythtv-live-chainid",
   170        "Sets the Myth TV chain ID (from TV Chain)",
   171        "", G_PARAM_READWRITE));
   172 
   173   g_object_class_install_property
   174     (gobject_class, PROP_MYTHTV_LIVE,
   175      g_param_spec_boolean ("mythtv-live", "mythtv-live",
   176        "Enable MythTV Live TV content streaming",
   177        FALSE, G_PARAM_READWRITE));
   178 
   179 #ifndef GST_DISABLE_GST_DEBUG
   180   g_object_class_install_property
   181     (gobject_class, PROP_MYTHTV_DBG,
   182      g_param_spec_boolean ("mythtv-debug", "mythtv-debug",
   183        "Enable MythTV debug messages",
   184        FALSE, G_PARAM_READWRITE));
   185 #endif
   186 
   187   gstbasesrc_class->start = gst_mythtv_src_start;
   188   gstbasesrc_class->stop = gst_mythtv_src_stop;
   189   gstbasesrc_class->get_size = gst_mythtv_src_get_size;
   190   gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable;
   191 
   192   gstbasesrc_class->create = gst_mythtv_src_create;
   193 
   194   GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
   195       "MythTV Client Source");
   196 }
   197 
   198   static void
   199 gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class)
   200 {
   201   this->file_transfer = NULL;
   202 
   203   this->unique_setup = FALSE;
   204 
   205   this->mythtv_version = MYTHTV_VERSION_DEFAULT;
   206 
   207   this->bytes_read = 0;
   208 
   209   this->content_size = -1;
   210   this->read_offset = 0;
   211 
   212   this->live_tv = FALSE;
   213 
   214   this->user_agent = g_strdup ("mythtvsrc");
   215   this->mythtv_caps = NULL;    
   216 
   217   gst_base_src_set_live ( GST_BASE_SRC( this ), TRUE );
   218 
   219   gst_pad_set_event_function (GST_BASE_SRC_PAD(GST_BASE_SRC(this)),
   220       GST_DEBUG_FUNCPTR (gst_mythtv_src_handle_event));
   221 
   222 }
   223 
   224   static void
   225 gst_mythtv_src_finalize (GObject * gobject)
   226 {
   227   GstMythtvSrc *this = GST_MYTHTV_SRC (gobject);
   228 
   229   g_free (this->user_agent);
   230 
   231   if (this->mythtv_caps) {
   232     gst_caps_unref (this->mythtv_caps);
   233     this->mythtv_caps = NULL;
   234   }
   235 
   236   if (this->file_transfer) {
   237     g_object_unref (this->file_transfer);
   238     this->file_transfer = NULL;
   239   }
   240 
   241   if (this->uri_name) {
   242     g_free (this->uri_name);
   243   }
   244 
   245   if (this->user_agent) {
   246     g_free (this->user_agent);
   247   }
   248 
   249   if ( update_size_task != NULL ) {
   250 
   251     if ( GST_TASK_STATE( update_size_task ) != GST_TASK_STOPPED )
   252     	gst_task_stop( update_size_task );
   253 
   254     gst_object_unref( update_size_task );
   255 
   256     update_size_task = NULL;
   257 
   258   }
   259 
   260   G_OBJECT_CLASS (parent_class)->finalize (gobject);
   261 }
   262 
   263 #if 0
   264   static guint
   265 do_seek( GstMythtvSrc *src, guint64 offset, guint size, GstBuffer *outbuf )
   266 {
   267   guint64 off_uint64 = myth_file_transfer_seek(src->file_transfer, offset, 1);
   268 
   269   g_print( "[%s] Call MythTV SEEK with offset %llu, got a new one %llu...\n", __FUNCTION__, 
   270       offset, off_uint64 );
   271 
   272   return off_uint64;
   273 
   274 }
   275 #endif
   276 
   277   static guint
   278 do_read_request_response (GstMythtvSrc * src, guint64 offset, guint size, GstBuffer * outbuf)
   279 {
   280   guint read = 0;
   281   guint sizetoread = size; //GST_BUFFER_SIZE (outbuf);
   282 
   283   g_print( "[%s] Reading %d bytes...\n", __FUNCTION__, sizetoread ); 
   284 
   285   /* Loop sending the request:
   286    * Retry whilst authentication fails and we supply it. */
   287 
   288   ssize_t len = 0;
   289 
   290   //GST_OBJECT_LOCK(src);
   291 
   292   while ( sizetoread > 0 ) {
   293 
   294     len = myth_file_transfer_read( src->file_transfer,
   295 	GST_BUFFER_DATA (outbuf) + read, sizetoread, TRUE );
   296 
   297     if ( len > 0 ) {
   298       read += len;
   299       src->read_offset += read;
   300       sizetoread -= len;
   301     } else if ( len < 0 ) {
   302       goto done;
   303     }
   304     else if ( len == 0 ) {
   305       if ( src->live_tv == FALSE )
   306 	goto done;
   307       else
   308 	goto eos;
   309 
   310     }
   311 
   312     if ( len == sizetoread )
   313       break;
   314 
   315   }
   316 
   317   if ( read > 0 ) {
   318     src->bytes_read += read;
   319 
   320     GST_BUFFER_SIZE (outbuf) = read;
   321   } else if ( read <= 0 || len <= 0 ) {
   322     if ( src->live_tv == FALSE )
   323       goto eos;
   324     else
   325       goto done;
   326   }
   327   //GST_BUFFER_OFFSET (outbuf) = src->read_offset;
   328 
   329   g_print( "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\
   330       "OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read, 
   331       src->read_offset, src->content_size );
   332 
   333   //GST_OBJECT_UNLOCK(src);
   334 
   335   if ( len < 0 ) {
   336     read = len;
   337     if ( src->live_tv == FALSE ) 
   338       goto eos;
   339     else
   340       goto done;
   341   }
   342 
   343   if ( src->bytes_read < src->content_size )
   344     goto done;
   345 
   346 eos:
   347   //GST_OBJECT_UNLOCK(src);
   348 
   349   src->eos = TRUE;
   350 done:
   351   //GST_OBJECT_UNLOCK(src);
   352 
   353   return read;
   354 }
   355 
   356   static GstFlowReturn
   357 gst_mythtv_src_create ( GstBaseSrc * psrc, guint64 offset, 
   358     guint size, GstBuffer **outbuf )
   359 {
   360   GstMythtvSrc *src;
   361   GstFlowReturn ret = GST_FLOW_OK;
   362   guint read = 0;
   363 
   364   src = GST_MYTHTV_SRC (psrc);
   365 
   366   //src->do_start = FALSE;
   367   src->do_start = FALSE;
   368   gst_task_join ( update_size_task );
   369 
   370   g_print( "[%s]\tBUFFER OFFSET = %llu, BUFFER SIZE = %d.\n", __FUNCTION__, offset, 
   371       size );
   372 
   373   /* The caller should know the number of bytes and not read beyond EOS. */
   374   //if (G_UNLIKELY (src->eos))
   375   //  goto eos;
   376   //g_static_rec_mutex_lock( &update_size_mutex );
   377 
   378   /* Create the buffer. */
   379   ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
   380       //      GST_BUFFER_OFFSET_NONE, GST_BASE_SRC (psrc)->blocksize,
   381       offset, size,
   382       src->mythtv_caps ? src->mythtv_caps :
   383       GST_PAD_CAPS (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc))), outbuf );
   384 
   385   //if (G_UNLIKELY (ret == GST_FLOW_UNEXPECTED))
   386   //  goto eos;
   387 
   388   if (G_UNLIKELY (ret != GST_FLOW_OK))
   389     goto eos;
   390 
   391   if (G_UNLIKELY (ret == GST_FLOW_ERROR))
   392     goto read_error;
   393 
   394   read = do_read_request_response ( src, offset, size, *outbuf );
   395 
   396   //g_static_rec_mutex_unlock( &update_size_mutex );
   397 
   398   src->do_start = TRUE;
   399   gst_task_start ( update_size_task );
   400 
   401 #if 0
   402   g_static_rec_mutex_lock( &update_size_mutex );
   403   src->do_start = FALSE;  
   404   g_static_rec_mutex_unlock( &update_size_mutex );
   405   GST_TASK_SIGNAL( update_size_task );
   406 #endif
   407 
   408   //g_static_rec_mutex_unlock( &update_size_mutex );
   409 
   410 #if 0
   411 #if ENABLE_TIMING_POSITION == 1
   412   guint64 size_tmp = 0;
   413   if (src->live_tv == TRUE) {
   414     //g_usleep( 1000 );
   415 get_file_pos:
   416     //g_usleep( 100 );
   417     size_tmp = myth_file_transfer_get_file_position( src->file_transfer );
   418     if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) )
   419       src->content_size = size_tmp;
   420     else
   421       goto get_file_pos;
   422     g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", 
   423 	__FUNCTION__, size_tmp);
   424 
   425   }
   426 #endif
   427 #endif
   428 
   429   //if (G_UNLIKELY (read < 0))
   430   //  goto read_error;
   431 
   432   if (G_UNLIKELY(src->eos))
   433     goto eos;
   434   else
   435     goto done;
   436 
   437 done:
   438   return ret;
   439 eos:
   440 #if 0
   441 #if ENABLE_TIMING_POSITION == 1
   442   if ( src->live_tv == TRUE ) {
   443     //g_usleep( 1000 );
   444     guint64 size_tmp = 0;
   445 get_file_pos_eos:
   446     //g_usleep( 100 );
   447     size_tmp = myth_file_transfer_get_file_position( src->file_transfer );
   448     if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) )
   449       src->content_size = size_tmp;
   450     else
   451       goto get_file_pos_eos;
   452     g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", 
   453 	__FUNCTION__, size_tmp);
   454     goto done;
   455   } else 
   456 #endif
   457 #endif
   458   {
   459     GST_DEBUG_OBJECT (src, "EOS reached");
   460     return GST_FLOW_UNEXPECTED;
   461   }
   462   /* ERRORS */
   463 read_error:
   464   {
   465     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   466 	(NULL), ("Could not read any bytes (%i, %s)", read,
   467 	  src->uri_name));
   468     return GST_FLOW_ERROR;
   469   }
   470   #if 0
   471 need_pause:
   472   {
   473     const gchar *reason = gst_flow_get_name (ret);
   474 
   475     GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
   476     return GST_FLOW_UNEXPECTED;
   477   }
   478   #endif
   479 
   480 }
   481 
   482 #if 0
   483 /* The following two charset mangling functions were copied from gnomevfssrc.
   484  * Preserve them under the unverified assumption that they do something vaguely
   485  * worthwhile.
   486  */
   487   static char *
   488 unicodify (const char *str, int len, ...)
   489 {
   490   char *ret = NULL, *cset;
   491   va_list args;
   492   gsize bytes_read, bytes_written;
   493 
   494   if (g_utf8_validate (str, len, NULL))
   495     return g_strndup (str, len >= 0 ? len : strlen (str));
   496 
   497   va_start (args, len);
   498   while ((cset = va_arg (args, char *)) != NULL)
   499   {
   500     if (!strcmp (cset, "locale"))
   501       ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL);
   502     else
   503       ret = g_convert (str, len, "UTF-8", cset,
   504 	  &bytes_read, &bytes_written, NULL);
   505     if (ret)
   506       break;
   507   }
   508   va_end (args);
   509 
   510   return ret;
   511 }
   512 
   513   static char *
   514 gst_mythtv_src_unicodify (const char *str)
   515 {
   516   return unicodify (str, -1, "locale", "ISO-8859-1", NULL);
   517 }
   518 #endif
   519 
   520 void
   521 update_size_func( void *mythtv_data ) 
   522 {
   523   GstMythtvSrc *src;
   524 
   525   g_return_if_fail( mythtv_data != NULL );
   526 
   527   src = GST_MYTHTV_SRC ( mythtv_data );
   528   if ( src->do_start ) {
   529  #if ENABLE_TIMING_POSITION == 1
   530   guint64 size_tmp = 0;
   531   if (src->live_tv == TRUE) {
   532 get_file_pos:
   533     //g_usleep( 50 );
   534     size_tmp = myth_file_transfer_get_file_position( src->file_transfer );
   535     if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) )
   536       src->content_size = size_tmp;
   537     else
   538       goto get_file_pos;
   539     g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n",
   540 	__FUNCTION__, size_tmp );
   541   }
   542 #endif
   543 }
   544   gst_task_pause( update_size_task );
   545  // src->do_start = FALSE;
   546   //GST_TASK_SIGNAL( update_size_task );
   547 
   548 }
   549 
   550 /* create a socket for connecting to remote server */
   551   static gboolean
   552 gst_mythtv_src_start ( GstBaseSrc * bsrc )
   553 {
   554   GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
   555 
   556   GString *chain_id_local = NULL;
   557 
   558   gboolean ret = TRUE;
   559 #if 0
   560   if (src->live_tv == TRUE && src->file_transfer != NULL) {
   561     guint64 size_tmp = myth_file_transfer_get_file_position( src->file_transfer );
   562     if (size_tmp > src->content_size)
   563       src->content_size = size_tmp;
   564     g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", 
   565 	__FUNCTION__, size_tmp);
   566   }
   567 #endif
   568   if (src->unique_setup == FALSE) {
   569     src->unique_setup = TRUE;
   570   } else {
   571     goto done;
   572   }
   573 
   574   //GST_OBJECT_LOCK(src);
   575 
   576   if ( src->live_tv ) {
   577     src->spawn_livetv = myth_livetv_new( );
   578     if ( myth_livetv_setup( src->spawn_livetv ) == FALSE ) {
   579     	ret = FALSE;
   580     	goto init_failed;
   581     }
   582     /* set up the uri variable */
   583     src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str );
   584     chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain );
   585     if ( chain_id_local != NULL ) {
   586       src->live_chain_id = g_strdup( chain_id_local->str );
   587       g_print( "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id );
   588     }
   589     src->live_tv_id = src->spawn_livetv->remote_encoder->recorder_num;
   590     g_print ( "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name );
   591   }
   592 
   593   src->file_transfer = myth_file_transfer_new( src->live_tv_id, 
   594       g_string_new( src->uri_name ), -1, src->mythtv_version );
   595 
   596   if ( src->file_transfer == NULL ) {
   597     //GST_OBJECT_UNLOCK(src);
   598 
   599     goto init_failed;
   600   }
   601 
   602   if ( src->live_tv ) {
   603     g_print ( "[%s] GST MYTHTVSRC: live_chain_id = %s\n", __FUNCTION__, src->live_chain_id );
   604     /* sets the MythSocket to the FileTransfer */
   605     //ret = myth_file_transfer_livetv_setup( &(src->file_transfer), src->spawn_livetv->remote_encoder->myth_socket );
   606   }
   607   /* sets the Playback monitor connection */
   608   ret = myth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv );
   609 
   610   if ( src->live_tv == TRUE && ret == TRUE ) {
   611     /* loop finished, set the max tries variable to zero again... */
   612     wait_to_transfer = 0;
   613 
   614     while ( wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS && ( myth_file_transfer_is_recording( src->file_transfer ) == FALSE 
   615 	  /*|| ( myth_file_transfer_get_file_position( src->file_transfer ) < ( src->content_size + 327680 ) )*/ ) )
   616       g_usleep( 100 );
   617   }
   618 
   619   /* sets the FileTransfer instance connection (video/audio download) */
   620   ret = myth_file_transfer_setup( &(src->file_transfer), src->live_tv );
   621 
   622   if ( ret == FALSE ) {
   623     //GST_OBJECT_UNLOCK(src);
   624 #ifndef GST_DISABLE_GST_DEBUG  
   625     if ( src->mythtv_msgs_dbg )
   626       g_printerr( "MythTV FileTransfer request failed when setting up socket connection!\n" );  	  
   627 #endif
   628     goto begin_req_failed;
   629   }
   630 
   631   src->content_size = src->file_transfer->filesize;
   632 
   633   //GST_OBJECT_UNLOCK(src);
   634 
   635   update_size_task = gst_task_create( update_size_func, src );
   636 
   637   gst_task_set_lock( update_size_task, &update_size_mutex );
   638 
   639   g_print( "[%s] Update Size task = %s\n", __FUNCTION__, gst_task_start( update_size_task ) && 
   640   		GST_TASK_STATE( update_size_task ) == GST_TASK_STARTED ? "OK !" : "ERROR!!!" );
   641 
   642   src->do_start = TRUE;
   643 
   644 #if 0
   645   const char *str_value;
   646   gint gint_value;
   647 
   648   str_value = ne_get_response_header (src->request, "myth-metaint");
   649   if (str_value) {
   650     if ( sscanf (str_value, "%d", &gint_value) == 1 ) {
   651       if (src->myth_caps) {
   652 	gst_caps_unref (src->myth_caps);
   653 	src->myth_caps = NULL;
   654       }
   655       src->myth_metaint = gint_value;
   656 #endif
   657       //src->mythtv_caps = gst_caps_new_simple ("application/x-gst_ff-nuv", NULL);
   658       //   }
   659       // }
   660 done:
   661       return TRUE;
   662 
   663       /* ERRORS */
   664 init_failed:
   665       {
   666       	if (src->spawn_livetv != NULL )
   667 	  g_object_unref( src->spawn_livetv );
   668 
   669 	GST_ELEMENT_ERROR (src, LIBRARY, INIT,
   670 	    (NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name));
   671 	return FALSE;
   672       }
   673 begin_req_failed:
   674       {
   675 	GST_ELEMENT_ERROR (src, LIBRARY, INIT,
   676 	    (NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name));
   677 	return FALSE;
   678       }
   679 }
   680 
   681 #if 0
   682 static gboolean
   683 gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size)
   684 {
   685   GstMythtvSrc *src;
   686   gboolean ret = FALSE;
   687 
   688   src = GST_MYTHTV_SRC (bsrc);
   689 
   690   g_static_rec_mutex_lock( &update_size_mutex );
   691   src->do_start = FALSE;  
   692   g_static_rec_mutex_unlock( &update_size_mutex );
   693   GST_TASK_SIGNAL( update_size_task );
   694  
   695 
   696   while (1) {
   697 
   698     g_static_rec_mutex_lock( &update_size_mutex );
   699     if ( !src->do_start ) {
   700 
   701       g_print( "[%s] GET SIZE: do_start? == %s\n", __FUNCTION__, src->do_start ? "YES" : "NO" );
   702 
   703       GST_TASK_WAIT( update_size_task );
   704     } else {
   705       if (src->content_size <= 0) {
   706 	g_static_rec_mutex_unlock( &update_size_mutex );
   707 	goto done;
   708       }
   709 
   710       *size = src->content_size;
   711       src->do_start = FALSE;
   712 
   713       g_static_rec_mutex_unlock( &update_size_mutex );
   714 
   715       break;
   716     }
   717     g_static_rec_mutex_unlock( &update_size_mutex );
   718 
   719   } // while (1) 
   720 
   721 done:
   722   return ret;
   723 
   724 }
   725 #endif
   726 
   727 static gboolean
   728 gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size)
   729 {
   730   GstMythtvSrc *src;
   731   gboolean ret = TRUE;
   732 
   733   src = GST_MYTHTV_SRC (bsrc);
   734 
   735   if (src->content_size <= 0)
   736     ret= FALSE;
   737 
   738   *size = src->content_size;
   739 
   740   return ret;
   741 
   742 }
   743 /* close the socket and associated resources
   744  * used both to recover from errors and go to NULL state */
   745   static gboolean
   746 gst_mythtv_src_stop (GstBaseSrc * bsrc)
   747 {
   748   GstMythtvSrc *src;
   749 
   750   src = GST_MYTHTV_SRC (bsrc);
   751 
   752   if (src->uri_name) {
   753     g_free (src->uri_name);
   754     src->uri_name = NULL;
   755   }
   756 
   757   if (src->mythtv_caps) {
   758     gst_caps_unref (src->mythtv_caps);
   759     src->mythtv_caps = NULL;
   760   }
   761 
   762   src->eos = FALSE;
   763 
   764   return TRUE;
   765 }
   766 
   767   static gboolean
   768 gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event)
   769 {
   770   GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad));
   771 
   772   switch (GST_EVENT_TYPE (event)) {
   773     case GST_EVENT_FLUSH_START:
   774       src->eos = FALSE;
   775       break;
   776       //return TRUE;
   777 #if 0
   778 case GST_EVENT_FLUSH_STOP:
   779       src->do_start = TRUE;
   780       src->eos = FALSE;
   781       gst_element_set_state (GST_ELEMENT(src), GST_STATE_NULL);
   782       //gst_element_set_locked_state (GST_ELEMENT(src), TRUE);
   783       break;
   784 #endif
   785     case GST_EVENT_SEEK:  	  
   786       {
   787 	gdouble rate;
   788 	//gboolean update = TRUE;
   789 	GstFormat format;
   790 	GstSeekType cur_type, stop_type;
   791 	GstSeekFlags flags;
   792 	gint64 cur = 0, stop = 0;
   793 	gst_event_parse_seek ( event, &rate, &format,
   794 	    &flags, &cur_type, &cur,
   795 	    &stop_type, &stop );
   796 
   797 	g_print( "[%s] Got EVENT_SEEK.\n", __FUNCTION__ );
   798 	if ( !( flags & GST_SEEK_FLAG_FLUSH ) ) {
   799 	  g_print( "[%s] Could get the FLAG_FLUSH message.\n", __FUNCTION__ );
   800 	}
   801 	//gboolean ret = gst_event_parse_new_segment ( event,
   802 	//    &update, &rate, &format, &start, &stop,
   803 	//    &position );
   804 	//GstFlowReturn flow_ret = gst_mythtv_src_create (GST_BASE_SRC( GST_PAD_PARENT( psrc ) ), 
   805 	//			cur, stop - cur + 1, GstBuffer)
   806 
   807       } 
   808     default:
   809       return gst_pad_event_default (pad, event);
   810   }
   811 
   812   return gst_pad_event_default (pad, event);
   813 }
   814 
   815   static gboolean
   816 gst_mythtv_src_is_seekable( GstBaseSrc *base_src )
   817 {
   818   return TRUE;
   819 }
   820 
   821   static void
   822 gst_mythtv_src_set_property (GObject * object, guint prop_id,
   823     const GValue * value, GParamSpec * pspec)
   824 {
   825   GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
   826 
   827   GST_OBJECT_LOCK (mythtvsrc);
   828   switch (prop_id) {
   829     case PROP_URI:
   830     case PROP_LOCATION:
   831       {
   832 	if (!g_value_get_string (value)) {
   833 	  GST_WARNING ("location property cannot be NULL");
   834 	  goto done;
   835 	}
   836 
   837 	if (mythtvsrc->uri_name != NULL) {
   838 	  g_free (mythtvsrc->uri_name);
   839 	  mythtvsrc->uri_name = NULL;
   840 	}
   841 	mythtvsrc->uri_name = g_value_dup_string (value);
   842 
   843 	break;
   844       }
   845 #ifndef GST_DISABLE_GST_DEBUG
   846     case PROP_MYTHTV_DBG:
   847       {
   848 	mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value);
   849 	break;
   850       }
   851 #endif
   852     case PROP_MYTHTV_VERSION:
   853       {
   854 	mythtvsrc->mythtv_version = g_value_get_int (value);
   855 	break;
   856       }
   857     case PROP_MYTHTV_LIVEID:
   858       {
   859 	mythtvsrc->live_tv_id = g_value_get_int (value);
   860 	break;
   861       }
   862     case PROP_MYTHTV_LIVE:
   863       {
   864 	mythtvsrc->live_tv = g_value_get_boolean (value);
   865 	break;
   866       }
   867     case PROP_MYTHTV_LIVE_CHAINID:
   868       {
   869 	if (!g_value_get_string (value)) {
   870 	  GST_WARNING ("MythTV Live chainid property cannot be NULL");
   871 	  goto done;
   872 	}
   873 
   874 	if (mythtvsrc->live_chain_id != NULL) {
   875 	  g_free (mythtvsrc->live_chain_id);
   876 	  mythtvsrc->live_chain_id = NULL;
   877 	}
   878 	mythtvsrc->live_chain_id = g_value_dup_string (value);
   879 
   880 	break;
   881       }
   882 
   883     default:
   884       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   885       break;
   886   }
   887   GST_OBJECT_UNLOCK (mythtvsrc);
   888 done:
   889   return;
   890 }
   891 
   892   static void
   893 gst_mythtv_src_get_property (GObject * object, guint prop_id,
   894     GValue * value, GParamSpec * pspec)
   895 {
   896   GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
   897 
   898   GST_OBJECT_LOCK (mythtvsrc);
   899   switch (prop_id) {
   900     case PROP_URI:
   901     case PROP_LOCATION:
   902       {
   903 	gchar *str = g_strdup( "" );
   904 
   905 	if ( mythtvsrc->uri_name == NULL ) {
   906 	  g_free (mythtvsrc->uri_name);
   907 	  mythtvsrc->uri_name = NULL;
   908 	} else {
   909 	  str = g_strdup( mythtvsrc->uri_name );
   910 	}
   911 	g_value_set_string ( value, str );
   912 	break;
   913       }
   914 #ifndef GST_DISABLE_GST_DEBUG
   915     case PROP_MYTHTV_DBG:
   916       g_value_set_boolean ( value, mythtvsrc->mythtv_msgs_dbg );
   917       break;
   918 #endif
   919     case PROP_MYTHTV_VERSION:
   920       {
   921 	g_value_set_int ( value, mythtvsrc->mythtv_version );
   922 	break;
   923       }
   924     case PROP_MYTHTV_LIVEID:
   925       {
   926 	g_value_set_int ( value, mythtvsrc->live_tv_id );
   927 	break;
   928       }
   929     case PROP_MYTHTV_LIVE:
   930       g_value_set_boolean ( value, mythtvsrc->live_tv );
   931       break;
   932     case PROP_MYTHTV_LIVE_CHAINID:
   933       {
   934 	gchar *str = g_strdup( "" );
   935 
   936 	if ( mythtvsrc->live_chain_id == NULL ) {
   937 	  g_free (mythtvsrc->live_chain_id);
   938 	  mythtvsrc->live_chain_id = NULL;
   939 	} else {
   940 	  str = g_strdup( mythtvsrc->live_chain_id );
   941 	}
   942 	g_value_set_string ( value, str );
   943 	break;
   944       }
   945     default:
   946       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   947       break;
   948   }
   949   GST_OBJECT_UNLOCK (mythtvsrc);
   950 }
   951 
   952 /* entry point to initialize the plug-in
   953  * initialize the plug-in itself
   954  * register the element factories and pad templates
   955  * register the features
   956  */
   957   static gboolean
   958 plugin_init (GstPlugin * plugin)
   959 {
   960   return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE,
   961       GST_TYPE_MYTHTV_SRC);
   962 }
   963 
   964 /* this is the structure that gst-register looks for
   965  * so keep the name plugin_desc, or you cannot get your plug-in registered */
   966 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
   967     GST_VERSION_MINOR,
   968     "mythtv",
   969     "lib MythTV src",
   970     plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
   971 
   972 
   973 /*** GSTURIHANDLER INTERFACE *************************************************/
   974   static guint 
   975 gst_mythtv_src_uri_get_type (void)
   976 {
   977   return GST_URI_SRC;
   978 }
   979 
   980   static gchar **
   981 gst_mythtv_src_uri_get_protocols (void)
   982 {
   983   static gchar *protocols[] = { "myth", "myths", NULL };
   984 
   985   return protocols;
   986 }
   987 
   988   static const gchar *
   989 gst_mythtv_src_uri_get_uri (GstURIHandler * handler)
   990 {
   991   GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
   992 
   993   return src->uri_name;
   994 }
   995 
   996   static gboolean
   997 gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
   998 {
   999   GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
  1000 
  1001   gchar *protocol;
  1002 
  1003   protocol = gst_uri_get_protocol (uri);
  1004   if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) {
  1005     g_free (protocol);
  1006     return FALSE;
  1007   }
  1008   g_free (protocol);
  1009   g_object_set (src, "location", uri, NULL);
  1010 
  1011   return TRUE;
  1012 }
  1013 
  1014   static void
  1015 gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
  1016 {
  1017   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
  1018 
  1019   iface->get_type = gst_mythtv_src_uri_get_type;
  1020   iface->get_protocols = gst_mythtv_src_uri_get_protocols;
  1021   iface->get_uri = gst_mythtv_src_uri_get_uri;
  1022   iface->set_uri = gst_mythtv_src_uri_set_uri;
  1023 }
  1024 
  1025   void
  1026 size_header_handler (void *userdata, const char *value)
  1027 {
  1028   GstMythtvSrc *src = GST_MYTHTV_SRC (userdata);
  1029 
  1030   //src->content_size = g_ascii_strtoull (value, NULL, 10);
  1031 
  1032   GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size);
  1033 }