gst-plugins-mythtv/src/gstmythtvsrc.c
author rosfran
Thu Nov 16 21:30:58 2006 +0000 (2006-11-16)
branchtrunk
changeset 89 edcd63c2ac77
parent 81 56e39289fa96
child 90 f6a9705509a1
permissions -rwxr-xr-x
[svn r90] Fixes to the read on "FileTransfer".
     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 <gmyth/gmyth_file_transfer.h>
    22 #include <gmyth/gmyth_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_GMYTHTV_ID_NUM					1
    34 
    35 #define GST_GMYTHTV_CHANNEL_NUM			1000
    36 
    37 #define GMYTHTV_VERSION_DEFAULT			30
    38  
    39 #define GMYTHTV_TRANSFER_MAX_WAITS	100
    40 
    41 #define GMYTHTV_TRANSFER_MAX_BUFFER	128*1024
    42 //( 32*1024  )
    43 
    44 /* 4*1024 ??? */
    45 #define MAX_READ_SIZE              	2*1024
    46 //( 32*1024 )
    47 
    48 #define GST_FLOW_ERROR_NO_DATA  		-101
    49 
    50 /* stablish a maximum iteration value to the IS_RECORDING message */
    51 static guint wait_to_transfer = 0;
    52 
    53 static const GstElementDetails gst_mythtv_src_details =
    54 GST_ELEMENT_DETAILS ( "MythTV client source",
    55     "Source/Network",
    56     "Control and receive data as a client over the network via raw socket connections using the MythTV protocol",
    57     "Rosfran Borges <rosfran.borges@indt.org.br>" );
    58 
    59 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ( "src",
    60     GST_PAD_SRC,
    61     GST_PAD_ALWAYS,
    62     GST_STATIC_CAPS ("video/x-nuv") );
    63     
    64 enum
    65 {
    66   PROP_0,
    67   PROP_LOCATION,
    68   PROP_URI,
    69 #ifndef GST_DISABLE_GST_DEBUG
    70   PROP_GMYTHTV_DBG,
    71 #endif
    72   PROP_GMYTHTV_VERSION,
    73   PROP_GMYTHTV_LIVE,
    74   PROP_GMYTHTV_LIVEID,
    75   PROP_GMYTHTV_LIVE_CHAINID,
    76   PROP_GMYTHTV_ENABLE_TIMING_POSITION,
    77   PROP_GMYTHTV_CHANNEL_NUM
    78 };
    79 
    80 static void gst_mythtv_src_finalize (GObject * gobject);
    81 
    82 /*
    83 static GstFlowReturn gst_mythtv_src_create (GstBaseSrc * psrc, guint64 offset, 
    84 	guint size, GstBuffer ** outbuf);
    85 */
    86 
    87 //static GstFlowReturn gst_mythtv_src_chain ( GstPad* pad, GstBuffer* outbuf );
    88 static GstFlowReturn gst_mythtv_src_create ( GstPushSrc* psrc, GstBuffer** outbuf );
    89 
    90 static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc);
    91 static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc);
    92 static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size);
    93 static gboolean gst_mythtv_src_is_seekable( GstBaseSrc *push_src );
    94 
    95 static gboolean gst_mythtv_src_do_seek( GstBaseSrc *base, GstSegment *segment );
    96 
    97 static gboolean gst_mythtv_src_next_program_chain ( GstMythtvSrc *src );
    98 
    99 static GstStateChangeReturn
   100 gst_mythtv_src_change_state (GstElement * element, GstStateChange transition);
   101 
   102 static void gst_mythtv_src_set_property (GObject * object, guint prop_id,
   103     const GValue * value, GParamSpec * pspec);
   104 static void gst_mythtv_src_get_property (GObject * object, guint prop_id,
   105     GValue * value, GParamSpec * pspec);
   106 
   107 static void gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
   108 
   109 static gboolean gst_mythtv_src_handle_query (GstPad * pad, GstQuery * query);
   110 
   111 //static gboolean gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event);
   112 //static gboolean gst_mythtv_src_query ( GstPad * pad, GstQuery * query );
   113 
   114 static gint do_read_request_response (GstMythtvSrc *src, guint64 offset, 
   115 		guint size, GstBuffer **outbuf);
   116 
   117 static void
   118 _urihandler_init (GType type)
   119 {
   120   static const GInterfaceInfo urihandler_info = {
   121     gst_mythtv_src_uri_handler_init,
   122     NULL,
   123     NULL
   124   };
   125 
   126   g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
   127 
   128   GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
   129       "MythTV src");
   130 }
   131 
   132 //GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstBaseSrc,
   133 //    GST_TYPE_BASE_SRC, _urihandler_init)
   134     
   135 GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstPushSrc,
   136     GST_TYPE_PUSH_SRC, _urihandler_init)
   137     
   138 static void
   139 gst_mythtv_src_base_init (gpointer g_class)
   140 {
   141   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
   142 
   143   gst_element_class_add_pad_template (element_class,
   144       gst_static_pad_template_get (&srctemplate));
   145       
   146   gst_element_class_set_details (element_class, &gst_mythtv_src_details);
   147   
   148   element_class->change_state = gst_mythtv_src_change_state;
   149   
   150 }
   151 
   152 static void
   153 gst_mythtv_src_class_init (GstMythtvSrcClass * klass)
   154 {
   155   GObjectClass *gobject_class; 
   156   GstPushSrcClass *gstpushsrc_class;
   157   GstBaseSrcClass *gstbasesrc_class;
   158 
   159   gobject_class = (GObjectClass *) klass;
   160   gstbasesrc_class = (GstBaseSrcClass *) klass;
   161   gstpushsrc_class = (GstPushSrcClass *) klass;
   162 
   163   gobject_class->set_property = gst_mythtv_src_set_property;
   164   gobject_class->get_property = gst_mythtv_src_get_property;
   165   gobject_class->finalize = gst_mythtv_src_finalize;
   166 
   167   g_object_class_install_property
   168     (gobject_class, PROP_LOCATION,
   169      g_param_spec_string ("location", "Location",
   170        "The location. In the form:"
   171        "\n\t\t\tmyth://a.com/file.nuv"
   172        "\n\t\t\tmyth://a.com:23223/file.nuv "
   173        "\n\t\t\ta.com/file.nuv - default scheme 'myth'",
   174        "", G_PARAM_READWRITE));
   175 
   176   g_object_class_install_property
   177     (gobject_class, PROP_URI,
   178      g_param_spec_string ("uri", "Uri",
   179        "The location in form of a URI (deprecated; use location)",
   180        "", G_PARAM_READWRITE));
   181 
   182   g_object_class_install_property
   183     (gobject_class, PROP_GMYTHTV_VERSION,
   184      g_param_spec_int ("mythtv-version", "mythtv-version",
   185        "Change MythTV version",
   186        26, 30, 26, G_PARAM_READWRITE));
   187 
   188   g_object_class_install_property
   189     (gobject_class, PROP_GMYTHTV_LIVEID,
   190      g_param_spec_int ("mythtv-live-id", "mythtv-live-id",
   191        "Change MythTV version",
   192        0, 200, GST_GMYTHTV_ID_NUM, G_PARAM_READWRITE));
   193 
   194   g_object_class_install_property
   195     (gobject_class, PROP_GMYTHTV_LIVE_CHAINID,
   196      g_param_spec_string ("mythtv-live-chainid", "mythtv-live-chainid",
   197        "Sets the MythTV chain ID (from TV Chain)",
   198        "", G_PARAM_READWRITE));
   199 
   200   g_object_class_install_property
   201     (gobject_class, PROP_GMYTHTV_LIVE,
   202      g_param_spec_boolean ("mythtv-live", "mythtv-live",
   203        "Enable MythTV Live TV content streaming",
   204        FALSE, G_PARAM_READWRITE));
   205 
   206   g_object_class_install_property
   207     (gobject_class, PROP_GMYTHTV_ENABLE_TIMING_POSITION,
   208      g_param_spec_boolean ("mythtv-enable-timing-position", "mythtv-enable-timing-position",
   209        "Enable MythTV Live TV content size continuous updating",
   210        FALSE, G_PARAM_READWRITE));
   211        
   212   g_object_class_install_property
   213     (gobject_class, PROP_GMYTHTV_CHANNEL_NUM,
   214      g_param_spec_int ("mythtv-channel", "mythtv-channel",
   215        "Change MythTV channel number",
   216        0, 99999, GST_GMYTHTV_CHANNEL_NUM, G_PARAM_READWRITE));
   217 
   218 #ifndef GST_DISABLE_GST_DEBUG
   219   g_object_class_install_property
   220     (gobject_class, PROP_GMYTHTV_DBG,
   221      g_param_spec_boolean ("mythtv-debug", "mythtv-debug",
   222        "Enable MythTV debug messages",
   223        FALSE, G_PARAM_READWRITE));
   224 #endif
   225 
   226   gstbasesrc_class->start = gst_mythtv_src_start;
   227   gstbasesrc_class->stop = gst_mythtv_src_stop;
   228   gstbasesrc_class->get_size = gst_mythtv_src_get_size;
   229   gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable;
   230   
   231   gstbasesrc_class->do_seek = gst_mythtv_src_do_seek;
   232   gstpushsrc_class->create = gst_mythtv_src_create;
   233     
   234   GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
   235       "MythTV Client Source");
   236 }
   237 
   238 static void
   239 gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class)
   240 {
   241   this->file_transfer = NULL;
   242 
   243   this->unique_setup = FALSE;
   244 
   245   this->mythtv_version = GMYTHTV_VERSION_DEFAULT;
   246   
   247   this->state = GST_MYTHTV_SRC_FILE_TRANSFER;
   248 
   249   this->bytes_read = 0;
   250   
   251   this->prev_content_size = 0;
   252 
   253   this->content_size = 0;
   254   this->read_offset = 0;
   255 
   256   this->content_size_last = 0;
   257 
   258   this->live_tv = FALSE;
   259   
   260   this->enable_timing_position = FALSE;
   261   this->update_prog_chain = FALSE;    
   262 
   263   this->user_agent = g_strdup ("mythtvsrc");
   264   this->mythtv_caps = NULL;
   265   this->update_prog_chain = FALSE;
   266   
   267   this->channel_num = 0;
   268   
   269   this->eos = FALSE;
   270   
   271   this->adapter = NULL;
   272   
   273   //this->th_read_ahead = NULL;
   274   
   275   this->th_mutex = NULL;
   276   
   277   this->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
   278   gst_element_add_pad (GST_ELEMENT (this), this->srcpad);
   279   
   280   gst_base_src_set_format( GST_BASE_SRC( this ), GST_FORMAT_BYTES );  
   281 
   282   //gst_base_src_set_live ( GST_BASE_SRC( this ), TRUE );
   283   
   284  // gst_pad_set_event_function ( GST_BASE_SRC_PAD(GST_BASE_SRC(this)),
   285   //    gst_mythtv_src_handle_event );
   286   gst_pad_set_query_function ( GST_BASE_SRC_PAD(GST_BASE_SRC(this)),
   287      gst_mythtv_src_handle_query );
   288 
   289 }
   290 
   291 static void
   292 gst_mythtv_src_finalize (GObject * gobject)
   293 {
   294   GstMythtvSrc *this = GST_MYTHTV_SRC (gobject);
   295   
   296   if ( this->th_mutex != NULL ) {
   297   	g_static_rec_mutex_free( this->th_mutex );
   298   	this->th_mutex = NULL;
   299   }
   300 
   301   if ( this->th_read_ahead != NULL ) {
   302   	gst_task_stop( this->th_read_ahead );
   303   	this->th_read_ahead = NULL;
   304   }
   305 
   306   if (this->mythtv_caps) {
   307     gst_caps_unref (this->mythtv_caps);
   308     this->mythtv_caps = NULL;
   309   }
   310 
   311   if (this->file_transfer) {
   312     g_object_unref (this->file_transfer);
   313     this->file_transfer = NULL;
   314   }
   315 
   316 	if (this->spawn_livetv) {
   317     g_object_unref (this->spawn_livetv);
   318     this->spawn_livetv = NULL;
   319   }
   320 
   321   if (this->uri_name) {
   322     g_free (this->uri_name);
   323   }
   324 
   325   if (this->user_agent) {
   326     g_free (this->user_agent);
   327   }
   328 
   329   G_OBJECT_CLASS (parent_class)->finalize (gobject);
   330 }
   331 
   332 static gint
   333 do_read_request_response (GstMythtvSrc * src, guint64 offset, guint size, GstBuffer **outbuf)
   334 {
   335   gint read = 0;
   336   guint sizetoread = size;
   337 
   338   g_print( "Starting: [%s] Reading %d bytes...\n", __FUNCTION__, sizetoread ); 
   339 
   340   /* Loop sending the Myth File Transfer request:
   341    * Retry whilst authentication fails and we supply it. */
   342   gint len = 0;
   343   gint8 *data_ptr = g_malloc0( size );
   344   
   345   GST_OBJECT_LOCK(src);
   346 
   347   while ( sizetoread > 0 ) {
   348 
   349     len = gmyth_file_transfer_read( src->file_transfer,
   350 						data_ptr + read, sizetoread, TRUE );
   351 
   352     if ( len > 0 ) {
   353       read += len;
   354       sizetoread -= len;
   355     } 
   356     else if ( len <= 0 )
   357     {
   358     	read = -1;
   359 
   360       if ( src->live_tv == FALSE ) 
   361       {
   362 				goto eos;
   363       } 
   364       else  
   365       {
   366 				if ( len == GMYTHTV_FILE_TRANSFER_READ_ERROR ) { /* -314 */
   367 				  src->update_prog_chain = TRUE;
   368 					goto done;	  	
   369 				} else 
   370 				  if ( abs( src->content_size - src->bytes_read ) < GMYTHTV_TRANSFER_MAX_BUFFER ) {
   371 				    src->update_prog_chain = TRUE;
   372 				    if ( src->enable_timing_position ) {
   373 				      gint64 size_tmp = 0;
   374 			get_file_pos:
   375 					size_tmp = gmyth_file_transfer_get_file_position( src->file_transfer );
   376 					if ( size_tmp > ( src->content_size + GMYTHTV_TRANSFER_MAX_BUFFER ) )
   377 					  src->content_size = size_tmp;
   378 					else if ( size_tmp > 0 )
   379 					  goto get_file_pos;
   380 					g_print( "\t[%s]\tGET_POSITION: file_position = %lld\n",
   381 					    __FUNCTION__, size_tmp );
   382 				    } /*else {				      
   383 				      gint64 new_offset = gmyth_file_transfer_get_file_position( src->file_transfer );
   384 				      if ( new_offset > 0 && src->content_size <= new_offset ) {
   385 								  src->content_size = new_offset;
   386 				      } else {
   387 								src->update_prog_chain = TRUE;
   388 				      }
   389 				      src->prev_content_size = src->content_size;
   390 				    }*/
   391 				  }
   392 			goto done;
   393     }
   394 
   395     }
   396 
   397     if ( read == sizetoread )
   398       break;
   399   }
   400 
   401   if ( read > 0 ) {
   402     src->read_offset += read;
   403     src->bytes_read += read;
   404 
   405     g_print( "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\
   406 			"OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read, 
   407 			src->read_offset, src->content_size );
   408 
   409     GST_BUFFER_SIZE (*outbuf) = read; //GST_BUFFER_SIZE (buffer) = read;
   410     GST_BUFFER_MALLOCDATA( *outbuf ) = g_malloc0( GST_BUFFER_SIZE (*outbuf) );
   411     GST_BUFFER_DATA( *outbuf ) = GST_BUFFER_MALLOCDATA( *outbuf );
   412     g_memmove( GST_BUFFER_DATA( *outbuf ), data_ptr, read );
   413     GST_BUFFER_OFFSET (*outbuf) = offset; //GST_BUFFER_OFFSET (buffer) = offset;
   414     GST_BUFFER_OFFSET_END (*outbuf) = offset + read;//GST_BUFFER_OFFSET_END (buffer) = offset + read;
   415 
   416     g_print( "Got buffer: [%s]\t\tBUFFER --->SIZE = %d, OFFSET = %llu, "\
   417 			"OFFSET_END = %llu.\n\n", __FUNCTION__, GST_BUFFER_SIZE (*outbuf), 
   418 			GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf) );
   419 
   420   } else if ( !src->live_tv )
   421     goto eos;
   422 
   423   goto done;
   424 
   425 eos:
   426   src->eos = TRUE;
   427 
   428 done:
   429   GST_OBJECT_UNLOCK(src);
   430 
   431   return read;
   432 }
   433 
   434 #if 0
   435 static GstFlowReturn
   436 gst_mythtv_src_create ( GstBaseSrc * psrc, guint64 offset, guint size, GstBuffer **outbuf)
   437 {
   438   GstMythtvSrc *src;
   439   GstFlowReturn ret = GST_FLOW_OK;
   440   gint read = -1;
   441   gint adapter_size = -1;
   442   
   443   guint max_adapter_rep = 40;
   444   
   445   src = GST_MYTHTV_SRC (psrc);
   446   
   447   /* The caller should know the number of bytes and not read beyond EOS. */
   448   if (G_UNLIKELY (src->eos))
   449     goto eos;
   450   if ( G_UNLIKELY (src->update_prog_chain) )
   451     goto change_progchain;
   452 
   453   g_static_rec_mutex_lock( src->th_mutex );
   454   
   455   while ( ( ( adapter_size = gst_adapter_available_fast( src->adapter ) ) < size ) &&
   456   		--max_adapter_rep > 0 )
   457   {
   458   	g_print ( "[%s] %d - Waiting for read_ahead task...\n", __FUNCTION__, max_adapter_rep );
   459   	GST_TASK_WAIT( src->th_read_ahead );
   460   }
   461   	
   462   g_static_rec_mutex_unlock( src->th_mutex );
   463 
   464 	gint64 new_offset = -1;
   465 	/* just get from the adapter, no network effort... */
   466 	if ( offset > src->adapter_offset && size <= adapter_size )	
   467 	{
   468 		
   469 		GstBuffer *buf = gst_adapter_take_buffer( src->adapter, size );
   470 		*outbuf = gst_buffer_create_sub( buf, offset, size );
   471 		src->read_offset = new_offset = offset;
   472 		read = size;
   473 		
   474 		gst_adapter_flush( src->adapter, size );
   475 		
   476 	} else {
   477 		/* no data on adapter... do all these mythtv network calls! */
   478 		
   479 		/* verify if it needs to seek */
   480 		if ( src->read_offset != offset ) 
   481   	{
   482 		
   483 	  	new_offset = gmyth_file_transfer_seek( src->file_transfer, offset, SEEK_SET );
   484 	  	
   485 	    g_print( "[%s] SRC Offset = %lld, NEW actual backend SEEK Offset = %lld.\n",
   486 	    	__FUNCTION__, src->read_offset, new_offset );
   487 	    if ( G_UNLIKELY (new_offset < 0 ) )
   488 	    {
   489 	      if ( src->live_tv )
   490 	      	goto change_progchain;
   491 	      else
   492 	      	goto eos;
   493 	    }
   494 	    
   495   	}
   496 	
   497     src->read_offset = offset;
   498   	
   499 	  /* Create the buffer. */
   500 	  ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
   501 	      src->read_offset, size,
   502 	      GST_PAD_CAPS ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)) ), outbuf);
   503 	
   504 	  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
   505 	    if ( src->live_tv )
   506 	    	goto change_progchain;
   507 	    else
   508 	    	goto done;
   509 	  }
   510 	  
   511 	  read = do_read_request_response ( src, src->read_offset, size, outbuf ); 
   512   	
   513 	}
   514 
   515   if (G_UNLIKELY (src->update_prog_chain) )
   516     goto change_progchain;
   517 
   518   if (G_UNLIKELY (read <= 0) || *outbuf == NULL) {
   519   	if ( src->live_tv )
   520     	goto change_progchain;
   521     else
   522     	goto read_error;
   523   }
   524   
   525   if ( read > 0 ) {
   526     src->read_offset += read;
   527     src->bytes_read += read;
   528     
   529     #if 0
   530     g_print( "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\
   531 			"OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read, 
   532 			src->read_offset, src->content_size );
   533 
   534     GST_BUFFER_SIZE (*outbuf) = read; //GST_BUFFER_SIZE (buffer) = read;
   535     //GST_BUFFER_MALLOCDATA( *outbuf ) = g_malloc0( GST_BUFFER_SIZE (*outbuf) );
   536     //GST_BUFFER_DATA( *outbuf ) = GST_BUFFER_MALLOCDATA( *outbuf );
   537     //g_memmove( GST_BUFFER_DATA( *outbuf ), data_ptr, read );
   538     GST_BUFFER_OFFSET (*outbuf) = offset; //GST_BUFFER_OFFSET (buffer) = offset;
   539     GST_BUFFER_OFFSET_END (*outbuf) = offset + read;//GST_BUFFER_OFFSET_END (buffer) = offset + read;
   540 
   541     g_print( "Got buffer: [%s]\t\tBUFFER --->SIZE = %d, OFFSET = %llu, "\
   542 			"OFFSET_END = %llu.\n\n", __FUNCTION__, GST_BUFFER_SIZE (*outbuf), 
   543 			GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf) );
   544 		#endif
   545 			
   546   }
   547 
   548 done:
   549  {
   550     const gchar *reason = gst_flow_get_name (ret);
   551 
   552     GST_DEBUG_OBJECT (src, "DONE task, reason %s", reason);
   553   	return ret;
   554  }
   555 eos:
   556   {
   557     const gchar *reason = gst_flow_get_name (ret);
   558 
   559     GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
   560     return GST_FLOW_UNEXPECTED;
   561   }
   562   /* ERRORS */
   563 read_error:
   564   {
   565     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   566 	(NULL), ("Could not read any bytes (%i, %s)", read,
   567 	  src->uri_name));
   568     return GST_FLOW_ERROR;
   569   }
   570 change_progchain:
   571   {
   572     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   573 		(NULL), ("Seek failed, go to the next program info... (%i, %s)", read,
   574 		  src->uri_name));
   575 		  
   576 		gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (src)),
   577   			gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
   578 		// go to the next program chain
   579 		src->unique_setup = FALSE;
   580 		src->update_prog_chain = TRUE;
   581 		
   582 		gst_mythtv_src_next_program_chain( src );
   583 		
   584     return GST_FLOW_ERROR_NO_DATA;
   585   }
   586 
   587 }
   588 #endif
   589 
   590 static GstFlowReturn
   591 gst_mythtv_src_create ( GstPushSrc* psrc, GstBuffer** outbuf )
   592 {
   593   GstMythtvSrc *src;
   594   GstFlowReturn ret = GST_FLOW_OK;
   595   gint read = -1;
   596   
   597   src = GST_MYTHTV_SRC ( psrc );
   598   
   599   /* The caller should know the number of bytes and not read beyond EOS. */
   600   if (G_UNLIKELY (src->eos))
   601     goto eos;
   602   if ( G_UNLIKELY (src->update_prog_chain) )
   603     goto change_progchain;
   604 
   605   /* just get from the adapter, no network effort... */
   606   /* Create the buffer. */
   607   ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
   608       src->read_offset /*GST_BUFFER_OFFSET_NONE*/, MAX_READ_SIZE,
   609       GST_PAD_CAPS (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc))), outbuf );
   610 
   611   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
   612     if ( src->live_tv )
   613     	goto change_progchain;
   614     else
   615     	goto done;
   616   }
   617   
   618   read = do_read_request_response ( src, src->read_offset, MAX_READ_SIZE, outbuf );	  
   619   
   620   if ( G_UNLIKELY (src->update_prog_chain) )
   621     goto change_progchain;
   622 
   623   if (G_UNLIKELY (read <= 0) || *outbuf == NULL) {
   624   	if ( src->live_tv )
   625     	goto change_progchain;
   626     else
   627     	goto read_error;
   628   }
   629 
   630 done:
   631  {
   632     const gchar *reason = gst_flow_get_name (ret);
   633 
   634     GST_DEBUG_OBJECT (src, "DONE task, reason %s", reason);
   635   	return ret;
   636  }
   637 eos:
   638   {
   639     const gchar *reason = gst_flow_get_name (ret);
   640 
   641     GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
   642     return GST_FLOW_UNEXPECTED;
   643   }
   644   /* ERRORS */
   645 read_error:
   646   {
   647     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   648 	(NULL), ("Could not read any bytes (%i, %s)", read,
   649 	  src->uri_name));
   650     return GST_FLOW_ERROR;
   651   }
   652 change_progchain:
   653   {
   654     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   655 		(NULL), ("Seek failed, go to the next program info... (%i, %s)", read,
   656 		  src->uri_name));
   657 		  
   658 		gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
   659   			gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
   660 		// go to the next program chain
   661 		src->unique_setup = FALSE;
   662 		src->update_prog_chain = TRUE;
   663 		
   664 		gst_mythtv_src_next_program_chain( src );
   665 		
   666     return GST_FLOW_ERROR_NO_DATA;
   667   }
   668 
   669 }
   670 
   671 gint64
   672 gst_mythtv_src_get_position ( GstMythtvSrc* src ) 
   673 {
   674 
   675   gint64 size_tmp = 0;
   676   guint max_tries = 2;
   677   if (src->live_tv == TRUE && ( abs( src->content_size - src->bytes_read ) < 
   678 		GMYTHTV_TRANSFER_MAX_BUFFER ) ) {
   679 
   680 get_file_pos:
   681     g_usleep( 10 );
   682     size_tmp = gmyth_file_transfer_get_file_position( src->file_transfer );
   683     if ( size_tmp > ( src->content_size + GMYTHTV_TRANSFER_MAX_BUFFER ) )
   684       src->content_size = size_tmp;
   685     else if ( size_tmp > 0 && --max_tries > 0 )
   686       goto get_file_pos;
   687     g_print( "\t[%s]\tGET_POSITION: file_position = %lld\n",
   688 	__FUNCTION__, size_tmp );
   689     /* sets the last content size amount before it can be updated */
   690     src->prev_content_size = src->content_size;
   691   }
   692 
   693   return src->content_size;	
   694 
   695 }
   696 
   697 static gboolean
   698 gst_mythtv_src_do_seek( GstBaseSrc *base, GstSegment *segment )
   699 {
   700   GstMythtvSrc *src = GST_MYTHTV_SRC( base );
   701   gint64 new_offset = 0;
   702   gboolean ret = TRUE;
   703 
   704   g_print( "[%s]DO Seek called! (start = %lld, stop = %lld)\n", __FUNCTION__, segment->start, segment->stop );
   705 
   706   /* verify if it needs to seek */
   707   if ( src->read_offset != segment->start ) 
   708   {
   709 
   710     new_offset = gmyth_file_transfer_seek( src->file_transfer, segment->start, SEEK_SET );
   711 
   712     g_print( "[%s] Segment offset start = %lld, SRC Offset = %lld, NEW actual backend SEEK Offset = %lld.\n",
   713 	__FUNCTION__, segment->start, src->read_offset, new_offset );
   714     if ( G_UNLIKELY (new_offset < 0 ) )
   715     {
   716       ret = FALSE;
   717       if ( src->live_tv )
   718 	goto change_progchain;
   719       else
   720 	goto eos;
   721     }
   722 
   723     src->read_offset = new_offset;
   724 
   725   }
   726   
   727    return ret;
   728 
   729 eos:
   730   {
   731 
   732     GST_DEBUG_OBJECT (src, "EOS found on seeking!!!");
   733     gst_object_unref( src );
   734     return FALSE;
   735   }
   736 change_progchain:
   737   {
   738     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   739 	(NULL), ("Seek failed, go to the next program info... (%i, %s)", read,
   740 		 src->uri_name));
   741 
   742     gst_pad_push_event ( GST_BASE_SRC_PAD (base),
   743 	gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
   744     /* go to the next program chain */
   745     src->unique_setup = FALSE;
   746     src->update_prog_chain = TRUE;
   747 
   748     gst_mythtv_src_next_program_chain( src );
   749 
   750     return TRUE;
   751   }
   752 
   753 }
   754 
   755 #if 0
   756 static void 
   757 gst_mythtv_src_read_ahead ( void *data ) {
   758 	
   759 	GstMythtvSrc *src = NULL;
   760 	
   761 	GstBuffer *buffer = NULL;
   762 	
   763 	guint size = 512;
   764 	
   765 	gint read = 0;
   766 	
   767 	src = GST_MYTHTV_SRC( data );
   768 	
   769 	GST_PAD_STREAM_TRYLOCK( GST_BASE_SRC_PAD (GST_BASE_SRC (src)) );
   770 	
   771 	/*if ( gst_adapter_available( src->adapter ) ) && ( read < MAX_READ_SIZE )) */
   772 	do {
   773 		buffer = gst_buffer_new_and_alloc( size );
   774 
   775 		read += do_read_request_response ( src, src->adapter_offset, size, &buffer );
   776 		
   777 		gst_adapter_push( src->adapter, buffer );
   778 		
   779 		//gst_buffer_unref( buffer );		
   780 	} while ( read < MAX_READ_SIZE );
   781 	
   782 	GST_PAD_BLOCK_SIGNAL( GST_BASE_SRC_PAD (GST_BASE_SRC (src)) );
   783 	
   784 	GST_PAD_STREAM_UNLOCK( GST_BASE_SRC_PAD (GST_BASE_SRC (src)) );
   785 	
   786 	gst_object_unref( src );
   787 	
   788 	return;	
   789 }
   790 #endif
   791 
   792 /* create a socket for connecting to remote server */
   793 static gboolean
   794 gst_mythtv_src_start ( GstBaseSrc * bsrc )
   795 {
   796   GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
   797 
   798   GString *chain_id_local = NULL;
   799 
   800   gboolean ret = TRUE;
   801   
   802   if ( G_UNLIKELY (src->update_prog_chain) )
   803     goto change_progchain;
   804 
   805   if (src->unique_setup == FALSE) {
   806     src->unique_setup = TRUE;
   807   } else {
   808     goto done;
   809   }
   810 
   811   //GST_OBJECT_LOCK(src);
   812 
   813   if ( src->live_tv ) {
   814     src->spawn_livetv = gmyth_livetv_new( );
   815     if ( gmyth_livetv_setup( src->spawn_livetv ) == FALSE ) {
   816       ret = FALSE;
   817       //GST_OBJECT_UNLOCK( src );
   818       goto init_failed;
   819     }    
   820 
   821     /* set up the uri variable */
   822     src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str );
   823     chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain );
   824     if ( chain_id_local != NULL ) {
   825       src->live_chain_id = g_strdup( chain_id_local->str );
   826       g_print( "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id );
   827     }
   828     src->live_tv_id = src->spawn_livetv->recorder->recorder_num;
   829     g_print ( "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name ); 
   830   }
   831 
   832   src->file_transfer = gmyth_file_transfer_new( src->live_tv_id, 
   833       g_string_new( src->uri_name ), -1, src->mythtv_version );
   834 
   835   if ( src->file_transfer == NULL ) {
   836     //GST_OBJECT_UNLOCK(src);
   837 
   838     goto init_failed;
   839   }
   840 
   841   /* sets the Playback monitor connection */
   842   ret = gmyth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv );
   843 
   844   if ( src->live_tv == TRUE && ret == TRUE ) {
   845     /* loop finished, set the max tries variable to zero again... */
   846     wait_to_transfer = 0;
   847 
   848     while ( wait_to_transfer++ < GMYTHTV_TRANSFER_MAX_WAITS &&
   849     		( gmyth_file_transfer_is_recording( src->file_transfer ) == FALSE 
   850 	  /*|| ( gmyth_file_transfer_get_file_position( src->file_transfer ) < ( src->content_size + 327680 ) )*/ ) )
   851       g_usleep( 100 );
   852   }
   853 
   854   /* sets the FileTransfer instance connection (video/audio download) */
   855   ret = gmyth_file_transfer_setup( &(src->file_transfer), src->live_tv );
   856 
   857   if ( ret == FALSE ) {
   858     //GST_OBJECT_UNLOCK(src);
   859 #ifndef GST_DISABLE_GST_DEBUG  
   860     if ( src->mythtv_msgs_dbg )
   861       g_printerr( "MythTV FileTransfer request failed when setting up socket connection!\n" );  	  
   862 #endif
   863     goto begin_req_failed;
   864   }
   865 
   866   src->content_size = src->file_transfer->filesize;
   867 
   868   src->do_start = FALSE;
   869   
   870   if ( src->live_tv ) {
   871   	//src->adapter = gst_adapter_new();
   872   	//g_static_rec_mutex_init( src->th_mutex );
   873   	//src->th_read_ahead = gst_task_create( (GstTaskFunction)gst_mythtv_src_read_ahead, src );
   874   }
   875   //gst_pad_push_event ( GST_BASE_SRC_PAD (bsrc),
   876   //	gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES, 0, src->content_size, 0 ) );
   877 
   878   //GST_OBJECT_UNLOCK(src);
   879 
   880 done:
   881   return TRUE;
   882 
   883   /* ERRORS */
   884 init_failed:
   885   {
   886     if (src->spawn_livetv != NULL )
   887       g_object_unref( src->spawn_livetv );
   888 
   889     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
   890 	(NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name));
   891     return FALSE;
   892   }
   893 begin_req_failed:
   894   {
   895     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
   896 	(NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name));
   897     return FALSE;
   898   }
   899 change_progchain:
   900   {
   901     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   902 		(NULL), ("Seek failed, go to the next program info... (%s)",
   903 		  src->uri_name));
   904 		  
   905 		gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (src)),
   906   			gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
   907   			
   908 		// go to the next program chain
   909 		src->unique_setup = FALSE;
   910 		src->update_prog_chain = TRUE;
   911 		
   912 		gst_mythtv_src_next_program_chain( src );
   913 		
   914     return TRUE;
   915   }
   916 }
   917 
   918 /* create a new socket for connecting to the next program chain */
   919 static gboolean
   920 gst_mythtv_src_next_program_chain ( GstMythtvSrc *src )
   921 {
   922   GString *chain_id_local = NULL;
   923 
   924   gboolean ret = TRUE;
   925 
   926   if ( !src->live_tv )
   927     goto init_failed;
   928     
   929   if (src->unique_setup == FALSE) {
   930     src->unique_setup = TRUE;
   931   } else {
   932     goto done;
   933   }
   934   
   935 	GST_PAD_STREAM_LOCK( GST_BASE_SRC_PAD (GST_BASE_SRC (src)) );
   936 
   937   if (src->file_transfer) {
   938     g_object_unref (src->file_transfer);
   939     src->file_transfer = NULL;
   940   }
   941 
   942   if (src->uri_name) {
   943     g_free (src->uri_name);
   944   }
   945 
   946   if ( src->live_tv ) {
   947     if ( gmyth_livetv_next_program_chain( src->spawn_livetv ) == FALSE ) {
   948     	g_print( "\n\n[%s]\t\tFailed to go to the next program chain!!!\n\n", __FUNCTION__ );
   949       ret = FALSE;
   950       goto init_failed;
   951     }
   952     /* set up the uri variable */
   953     src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str );
   954     chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain );
   955     if ( chain_id_local != NULL ) {
   956       src->live_chain_id = g_strdup( chain_id_local->str );
   957       g_print( "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id );
   958     }
   959     src->live_tv_id = src->spawn_livetv->recorder->recorder_num;
   960     g_print ( "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name );
   961   }
   962 
   963   src->file_transfer = gmyth_file_transfer_new( src->live_tv_id, 
   964       g_string_new( src->uri_name ), -1, src->mythtv_version );
   965 
   966   if ( src->file_transfer == NULL ) {
   967     goto init_failed;
   968   }
   969 
   970   /* sets the Playback monitor connection */
   971   ret = gmyth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv );
   972 
   973   if ( src->live_tv == TRUE && ret == TRUE ) {
   974     /* loop finished, set the max tries variable to zero again... */
   975     wait_to_transfer = 0;
   976 
   977     g_usleep( 200 );
   978 
   979     while ( wait_to_transfer++ < GMYTHTV_TRANSFER_MAX_WAITS && 
   980 				( gmyth_file_transfer_is_recording( src->file_transfer ) == FALSE ) )
   981       g_usleep( 1000 );
   982   }
   983 
   984   /* sets the FileTransfer instance connection (video/audio download) */
   985   ret = gmyth_file_transfer_setup( &(src->file_transfer), src->live_tv );
   986 
   987   if ( ret == FALSE ) {
   988 #ifndef GST_DISABLE_GST_DEBUG  
   989     if ( src->mythtv_msgs_dbg )
   990       g_printerr( "MythTV FileTransfer request failed when setting up socket connection!\n" );  	  
   991 #endif
   992     goto begin_req_failed;
   993   }
   994   src->content_size_last = src->content_size;
   995 
   996 #if 0
   997   if ( src->content_size < src->file_transfer->filesize ) {
   998     src->content_size = src->file_transfer->filesize;
   999   } else {
  1000     //gint64 pos = gst_mythtv_src_get_position(src);
  1001     //if ( pos > src->file_transfer->filesize )
  1002     //	src->content_size = pos;  	
  1003 
  1004   }
  1005 #endif
  1006 
  1007   src->content_size = src->file_transfer->filesize;
  1008   if ( src->live_tv ) {
  1009   	wait_to_transfer = 0;
  1010 	  while ( wait_to_transfer++ < GMYTHTV_TRANSFER_MAX_WAITS && src->content_size < GMYTHTV_TRANSFER_MAX_BUFFER )
  1011 	    src->content_size = gst_mythtv_src_get_position( src );
  1012   }
  1013 
  1014   src->read_offset = 0;  
  1015   
  1016 done:
  1017 	src->update_prog_chain = FALSE;
  1018 	
  1019 	GST_PAD_STREAM_UNLOCK( GST_BASE_SRC_PAD (GST_BASE_SRC (src)) );
  1020 	
  1021   return TRUE;
  1022 
  1023   /* ERRORS */
  1024 init_failed:
  1025   {
  1026     if (src->spawn_livetv != NULL )
  1027       g_object_unref( src->spawn_livetv );
  1028 
  1029     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
  1030 	(NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name));
  1031     return FALSE;
  1032   }
  1033 begin_req_failed:
  1034   {
  1035     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
  1036 	(NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name));
  1037     return FALSE;
  1038   }
  1039 
  1040 }
  1041 
  1042 static gboolean
  1043 gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size)
  1044 {
  1045   GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
  1046   gboolean ret = TRUE;
  1047   g_print( "[%s] Differs from previous content size: %d (max.: %d)\n", __FUNCTION__, 
  1048   			abs( src->content_size - src->prev_content_size ), GMYTHTV_TRANSFER_MAX_BUFFER );
  1049 
  1050   if (src->content_size == -1) {
  1051     //ret= FALSE;
  1052   } else if ( src->live_tv && ( abs( src->content_size - src->bytes_read ) < 
  1053 				GMYTHTV_TRANSFER_MAX_BUFFER ) ) {
  1054     //g_static_mutex_lock( &update_size_mutex );
  1055     //GST_OBJECT_LOCK(src);
  1056     
  1057     gint64 new_offset = gmyth_file_transfer_get_file_position( src->file_transfer );
  1058     if ( new_offset > 0 && new_offset > src->content_size ) {
  1059 			src->content_size = new_offset;
  1060     } else if ( new_offset < src->content_size ) {
  1061 			src->update_prog_chain = TRUE;
  1062 	  }
  1063 
  1064     if ( src->enable_timing_position ) {
  1065       gint64 size_tmp = 0;
  1066       if (src->live_tv == TRUE) {
  1067 get_file_pos:
  1068 	g_usleep( 5 );
  1069 	size_tmp = gmyth_file_transfer_get_file_position( src->file_transfer );
  1070 	if ( size_tmp > ( src->content_size + GMYTHTV_TRANSFER_MAX_BUFFER ) )
  1071 	  src->content_size = size_tmp;
  1072 	else if ( size_tmp > 0  )
  1073 	  goto get_file_pos;
  1074 	g_print( "\t[%s]\tGET_POSITION: file_position = %lld\n",
  1075 	    __FUNCTION__, size_tmp );
  1076       }
  1077     }
  1078     
  1079     src->prev_content_size = src->content_size;
  1080     
  1081     //GST_OBJECT_UNLOCK(src);
  1082     //g_static_mutex_unlock( &update_size_mutex );
  1083   }
  1084 
  1085   *size = src->content_size;
  1086   g_print( "[%s] Content size = %lld\n", __FUNCTION__, src->content_size );
  1087   
  1088   return ret;
  1089 
  1090 }
  1091 
  1092 /* close the socket and associated resources
  1093  * used both to recover from errors and go to NULL state */
  1094 static gboolean
  1095 gst_mythtv_src_stop (GstBaseSrc * bsrc)
  1096 {
  1097   GstMythtvSrc *src;
  1098 
  1099   src = GST_MYTHTV_SRC (bsrc);
  1100 
  1101   if (src->uri_name) {
  1102     g_free (src->uri_name);
  1103     src->uri_name = NULL;
  1104   }
  1105 
  1106   if (src->mythtv_caps) {
  1107     gst_caps_unref (src->mythtv_caps);
  1108     src->mythtv_caps = NULL;
  1109   }
  1110 
  1111   src->eos = FALSE;
  1112 
  1113   return TRUE;
  1114 }
  1115 
  1116 #if 0
  1117 static gboolean
  1118 gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event)
  1119 {
  1120   GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad));
  1121   gint64 cont_size = 0;
  1122 
  1123   switch (GST_EVENT_TYPE (event)) {
  1124 #if 0
  1125     case GST_EVENT_FLUSH_START:
  1126       //src->eos = FALSE;
  1127       g_print( "\n\n\n[%s]\t\tGot FLUSH_START event!!!\n\n\n", __FUNCTION__ );
  1128       cont_size = gst_mythtv_src_get_position (src);
  1129       if ( !src->live_tv ) {
  1130 	if ( cont_size > src->content_size ) {
  1131 	  src->content_size = cont_size;
  1132 	  src->eos = FALSE;
  1133 	} else {
  1134 	  src->eos = TRUE;
  1135 	  gst_element_set_state ( GST_ELEMENT (src), GST_STATE_NULL );
  1136 	  gst_element_set_locked_state ( GST_ELEMENT (src), FALSE );
  1137 	}
  1138       } else {
  1139 	if ( cont_size <= 0 ) {
  1140 	  src->update_prog_chain = TRUE;
  1141 	  src->eos = TRUE;
  1142 	  src->unique_setup = FALSE;
  1143 	  src->do_start = TRUE;		  				  		
  1144 	}		  	
  1145       }
  1146       break;
  1147     case GST_EVENT_FLUSH_STOP:
  1148       src->do_start = TRUE;
  1149       src->eos = FALSE;
  1150       gst_element_set_state (GST_ELEMENT(src), GST_STATE_NULL);
  1151       //gst_element_set_locked_state (GST_ELEMENT(src), TRUE);
  1152       break;
  1153 #endif
  1154     case GST_EVENT_EOS:
  1155       g_print( "[%s] Got EOS event!!!\n", __FUNCTION__ );
  1156 
  1157       if ( src->live_tv ) {
  1158 	cont_size = gst_mythtv_src_get_position (src);
  1159 	if ( cont_size > src->content_size ) {
  1160 	  src->content_size = cont_size;
  1161 	  src->eos = FALSE;
  1162 	} else {
  1163 	  src->eos = TRUE;
  1164 	  gst_element_set_state ( GST_ELEMENT (src), GST_STATE_NULL );
  1165 	  gst_element_set_locked_state ( GST_ELEMENT (src), FALSE );
  1166 	}
  1167       } else 
  1168 	src->eos = TRUE;
  1169       break;
  1170 #if 0
  1171     case GST_EVENT_NEWSEGMENT:
  1172       g_print( "[%s] Got NEWSEGMENT!!!\n", __FUNCTION__ );
  1173       src->eos = FALSE;
  1174       break;
  1175     case GST_EVENT_SEEK:  	  
  1176       {
  1177 	g_print( "[%s] Got EVENT_SEEK!!!\n", __FUNCTION__ );
  1178 	gdouble rate;
  1179 	//gboolean update = TRUE;
  1180 	GstFormat format;
  1181 	GstSeekType cur_type, stop_type;
  1182 	GstSeekFlags flags;
  1183 	gint64 cur = 0, stop = 0;
  1184 	gst_event_parse_seek ( event, &rate, &format,
  1185 	    &flags, &cur_type, &cur,
  1186 	    &stop_type, &stop );
  1187 
  1188 	g_print( "[%s] Got EVENT_SEEK.\n", __FUNCTION__ );
  1189 	if ( !( flags & GST_SEEK_FLAG_FLUSH ) ) {
  1190 	  g_print( "[%s] Could get the FLAG_FLUSH message.\n", __FUNCTION__ );
  1191 	}
  1192 	//gboolean ret = gst_event_parse_new_segment ( event,
  1193 	//    &update, &rate, &format, &start, &stop,
  1194 	//    &position );
  1195 	//GstFlowReturn flow_ret = gst_mythtv_src_create (GST_BASE_SRC( GST_PAD_PARENT( psrc ) ), 
  1196 	//			cur, stop - cur + 1, GstBuffer)
  1197       }
  1198 #endif
  1199     default:
  1200       return gst_pad_event_default (pad, event);
  1201   }
  1202 
  1203   return gst_pad_event_default (pad, event);
  1204 }
  1205 #endif
  1206 
  1207 static gboolean
  1208 gst_mythtv_src_is_seekable( GstBaseSrc *push_src )
  1209 {
  1210   return TRUE;
  1211 }
  1212 
  1213 static gboolean
  1214 gst_mythtv_src_handle_query (GstPad * pad, GstQuery * query)
  1215 {
  1216   gboolean res = FALSE;
  1217   GstMythtvSrc *myth = GST_MYTHTV_SRC (gst_pad_get_parent (pad));
  1218 
  1219   switch (GST_QUERY_TYPE (query)) {
  1220     case GST_QUERY_POSITION:
  1221       gst_query_set_position (query, GST_FORMAT_BYTES,
  1222 	  myth->read_offset );
  1223       res = TRUE;
  1224       GST_DEBUG_OBJECT (myth, "POS %d", myth->read_offset);
  1225       break;
  1226     case GST_QUERY_DURATION:
  1227 #if 0
  1228       if (myth->duration != 0) {
  1229 	gint64 total;
  1230 	gint64 fps;
  1231 
  1232 	fps = nuv->h->i_fpsn / nuv->h->i_fpsd;
  1233 	total = gst_util_uint64_scale_int (GST_SECOND, nuv->h->i_video_blocks, fps);
  1234 #endif
  1235 	//gst_query_set_duration (query, GST_FORMAT_TIME, myth->content_size);
  1236 	GST_DEBUG_OBJECT (myth, "DURATION %d", myth->content_size);
  1237 	res = FALSE;
  1238       break;
  1239     default:
  1240       res = FALSE;
  1241       break;
  1242   }
  1243 
  1244   gst_object_unref (myth);
  1245 
  1246   return res;
  1247 }
  1248 
  1249 static GstStateChangeReturn
  1250 gst_mythtv_src_change_state (GstElement * element, GstStateChange transition)
  1251 {
  1252   GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;//GST_STATE_CHANGE_NO_PREROLL;
  1253   GstMythtvSrc *src = GST_MYTHTV_SRC (element);
  1254 
  1255   switch (transition) {
  1256     case GST_STATE_CHANGE_NULL_TO_READY:
  1257       //src->do_start = TRUE;
  1258       //src->unique_setup = FALSE;
  1259       break;
  1260     case GST_STATE_CHANGE_READY_TO_PAUSED:
  1261     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
  1262       //src->eos = FALSE;
  1263       break;
  1264     default:
  1265       break;
  1266   }
  1267 
  1268   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  1269   if (ret == GST_STATE_CHANGE_FAILURE)
  1270     return ret;
  1271 
  1272   switch (transition) {
  1273     case GST_STATE_CHANGE_READY_TO_NULL:
  1274       g_print( "[%s] READY to NULL called!\n", __FUNCTION__ );
  1275       break;
  1276     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
  1277       g_print( "[%s] PLAYING to PAUSED called!\n", __FUNCTION__ );
  1278     case GST_STATE_CHANGE_PAUSED_TO_READY:
  1279       g_print( "[%s] PAUSED to READY called!\n", __FUNCTION__ );
  1280       if ( src->live_tv && src->update_prog_chain ) {
  1281       	
  1282   			gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (src)),
  1283       			gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
  1284 
  1285 				src->read_offset = 0;
  1286 				src->bytes_read = 0;
  1287 				src->unique_setup = FALSE;				
  1288 				gst_mythtv_src_next_program_chain( src );
  1289       }
  1290       break;
  1291     default:
  1292       break;
  1293   }
  1294 
  1295   return ret;
  1296 }
  1297 
  1298 static void
  1299 gst_mythtv_src_set_property (GObject * object, guint prop_id,
  1300     const GValue * value, GParamSpec * pspec)
  1301 {
  1302   GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
  1303 
  1304   GST_OBJECT_LOCK (mythtvsrc);
  1305   switch (prop_id) {
  1306     case PROP_URI:
  1307     case PROP_LOCATION:
  1308       {
  1309 	if (!g_value_get_string (value)) {
  1310 	  GST_WARNING ("location property cannot be NULL");
  1311 	  goto done;
  1312 	}
  1313 
  1314 	if (mythtvsrc->uri_name != NULL) {
  1315 	  g_free (mythtvsrc->uri_name);
  1316 	  mythtvsrc->uri_name = NULL;
  1317 	}
  1318 	mythtvsrc->uri_name = g_value_dup_string (value);
  1319 
  1320 	break;
  1321       }
  1322 #ifndef GST_DISABLE_GST_DEBUG
  1323     case PROP_GMYTHTV_DBG:
  1324       {
  1325 	mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value);
  1326 	break;
  1327       }
  1328 #endif
  1329     case PROP_GMYTHTV_VERSION:
  1330       {
  1331 	mythtvsrc->mythtv_version = g_value_get_int (value);
  1332 	break;
  1333       }
  1334     case PROP_GMYTHTV_LIVEID:
  1335       {
  1336 	mythtvsrc->live_tv_id = g_value_get_int (value);
  1337 	break;
  1338       }
  1339     case PROP_GMYTHTV_LIVE:
  1340       {
  1341 	mythtvsrc->live_tv = g_value_get_boolean (value);
  1342 	break;
  1343       }
  1344     case PROP_GMYTHTV_ENABLE_TIMING_POSITION:
  1345       {
  1346 	mythtvsrc->enable_timing_position = g_value_get_boolean (value);
  1347 	break;
  1348       }      
  1349     case PROP_GMYTHTV_LIVE_CHAINID:
  1350       {
  1351 	if (!g_value_get_string (value)) {
  1352 	  GST_WARNING ("MythTV Live chainid property cannot be NULL");
  1353 	  goto done;
  1354 	}
  1355 
  1356 	if (mythtvsrc->live_chain_id != NULL) {
  1357 	  g_free (mythtvsrc->live_chain_id);
  1358 	  mythtvsrc->live_chain_id = NULL;
  1359 	}
  1360 	mythtvsrc->live_chain_id = g_value_dup_string (value);
  1361 	break;
  1362       }
  1363     case PROP_GMYTHTV_CHANNEL_NUM:
  1364       {
  1365 	mythtvsrc->channel_num = g_value_get_int (value);
  1366 	break;
  1367       }
  1368     default:
  1369       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1370       break;
  1371   }
  1372   GST_OBJECT_UNLOCK (mythtvsrc);
  1373 done:
  1374   return;
  1375 }
  1376 
  1377   static void
  1378 gst_mythtv_src_get_property (GObject * object, guint prop_id,
  1379     GValue * value, GParamSpec * pspec)
  1380 {
  1381   GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
  1382 
  1383   GST_OBJECT_LOCK (mythtvsrc);
  1384   switch (prop_id) {
  1385     case PROP_URI:
  1386     case PROP_LOCATION:
  1387       {
  1388 	gchar *str = g_strdup( "" );
  1389 
  1390 	if ( mythtvsrc->uri_name == NULL ) {
  1391 	  g_free (mythtvsrc->uri_name);
  1392 	  mythtvsrc->uri_name = NULL;
  1393 	} else {
  1394 	  str = g_strdup( mythtvsrc->uri_name );
  1395 	}
  1396 	g_value_set_string ( value, str );
  1397 	break;
  1398       }
  1399 #ifndef GST_DISABLE_GST_DEBUG
  1400     case PROP_GMYTHTV_DBG:
  1401       g_value_set_boolean ( value, mythtvsrc->mythtv_msgs_dbg );
  1402       break;
  1403 #endif
  1404     case PROP_GMYTHTV_VERSION:
  1405       {
  1406 	g_value_set_int ( value, mythtvsrc->mythtv_version );
  1407 	break;
  1408       }
  1409     case PROP_GMYTHTV_LIVEID:
  1410       {
  1411 	g_value_set_int ( value, mythtvsrc->live_tv_id );
  1412 	break;
  1413       }
  1414     case PROP_GMYTHTV_LIVE:
  1415       g_value_set_boolean ( value, mythtvsrc->live_tv );
  1416       break;
  1417     case PROP_GMYTHTV_ENABLE_TIMING_POSITION:
  1418       g_value_set_boolean ( value, mythtvsrc->enable_timing_position );
  1419       break;
  1420     case PROP_GMYTHTV_LIVE_CHAINID:
  1421       {
  1422 	gchar *str = g_strdup( "" );
  1423 
  1424 	if ( mythtvsrc->live_chain_id == NULL ) {
  1425 	  g_free (mythtvsrc->live_chain_id);
  1426 	  mythtvsrc->live_chain_id = NULL;
  1427 	} else {
  1428 	  str = g_strdup( mythtvsrc->live_chain_id );
  1429 	}
  1430 	g_value_set_string ( value, str );
  1431 	break;
  1432       }
  1433     case PROP_GMYTHTV_CHANNEL_NUM:
  1434       {
  1435 	g_value_set_int ( value, mythtvsrc->channel_num );
  1436 	break;
  1437       }
  1438     default:
  1439       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1440       break;
  1441   }
  1442   GST_OBJECT_UNLOCK (mythtvsrc);
  1443 }
  1444 
  1445 /* entry point to initialize the plug-in
  1446  * initialize the plug-in itself
  1447  * register the element factories and pad templates
  1448  * register the features
  1449  */
  1450 static gboolean
  1451 plugin_init (GstPlugin * plugin)
  1452 {
  1453   return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE,
  1454       GST_TYPE_MYTHTV_SRC);
  1455 }
  1456 
  1457 /* this is the structure that gst-register looks for
  1458  * so keep the name plugin_desc, or you cannot get your plug-in registered */
  1459 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
  1460     GST_VERSION_MINOR,
  1461     "mythtv",
  1462     "lib MythTV src",
  1463     plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
  1464 
  1465 
  1466 /*** GSTURIHANDLER INTERFACE *************************************************/
  1467   static guint 
  1468 gst_mythtv_src_uri_get_type (void)
  1469 {
  1470   return GST_URI_SRC;
  1471 }
  1472 
  1473   static gchar **
  1474 gst_mythtv_src_uri_get_protocols (void)
  1475 {
  1476   static gchar *protocols[] = { "myth", "myths", NULL };
  1477 
  1478   return protocols;
  1479 }
  1480 
  1481   static const gchar *
  1482 gst_mythtv_src_uri_get_uri (GstURIHandler * handler)
  1483 {
  1484   GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
  1485 
  1486   return src->uri_name;
  1487 }
  1488 
  1489   static gboolean
  1490 gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
  1491 {
  1492   GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
  1493 
  1494   gchar *protocol;
  1495 
  1496   protocol = gst_uri_get_protocol (uri);
  1497   if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) {
  1498     g_free (protocol);
  1499     return FALSE;
  1500   }
  1501   g_free (protocol);
  1502   g_object_set (src, "location", uri, NULL);
  1503 
  1504   return TRUE;
  1505 }
  1506 
  1507  static void
  1508 gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
  1509 {
  1510   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
  1511 
  1512   iface->get_type = gst_mythtv_src_uri_get_type;
  1513   iface->get_protocols = gst_mythtv_src_uri_get_protocols;
  1514   iface->get_uri = gst_mythtv_src_uri_get_uri;
  1515   iface->set_uri = gst_mythtv_src_uri_set_uri;
  1516 }
  1517 
  1518   void
  1519 size_header_handler (void *userdata, const char *value)
  1520 {
  1521   GstMythtvSrc *src = GST_MYTHTV_SRC (userdata);
  1522 
  1523   //src->content_size = g_ascii_strtoull (value, NULL, 10);
  1524 
  1525   GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size);
  1526 }