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