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