gst-plugins-mythtv/src/gstmythtvsrc.c
author rosfran
Tue Nov 28 00:53:25 2006 +0000 (2006-11-28)
branchtrunk
changeset 123 253b9171a703
parent 114 04cead6ae39b
child 124 d2d5fe1c3997
permissions -rwxr-xr-x
[svn r124] Fixes to the newly added BackendInfo issues.
     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_RESENDS	5
    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					40*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 ( GstPushSrc* psrc, GstBuffer** outbuf );
    87 
    88 static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc);
    89 static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc);
    90 static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size);
    91 static gboolean gst_mythtv_src_is_seekable( GstBaseSrc *push_src );
    92 
    93 /*
    94 static void gst_mythtv_src_get_times (GstBaseSrc * src, GstBuffer * buffer,
    95    GstClockTime * start, GstClockTime * end);
    96 */
    97 
    98 static gboolean gst_mythtv_src_do_seek( GstBaseSrc *base, GstSegment *segment );
    99 
   100 static gboolean gst_mythtv_src_next_program_chain ( GstMythtvSrc *src );
   101 
   102 static GstStateChangeReturn
   103 gst_mythtv_src_change_state (GstElement * element, GstStateChange transition);
   104 
   105 static void gst_mythtv_src_set_property (GObject * object, guint prop_id,
   106     const GValue * value, GParamSpec * pspec);
   107 static void gst_mythtv_src_get_property (GObject * object, guint prop_id,
   108     GValue * value, GParamSpec * pspec);
   109 
   110 static void gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
   111 
   112 static gboolean gst_mythtv_src_handle_query (GstPad * pad, GstQuery * query);
   113 
   114 static gboolean gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event);
   115 
   116 static gint do_read_request_response (GstMythtvSrc * src, guint size, GByteArray *data_ptr);
   117 
   118 GStaticRecMutex th_mutex = G_STATIC_REC_MUTEX_INIT;
   119 
   120 static void
   121 _urihandler_init (GType type)
   122 {
   123   static const GInterfaceInfo urihandler_info = {
   124     gst_mythtv_src_uri_handler_init,
   125     NULL,
   126     NULL
   127   };
   128 
   129   g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
   130 
   131   GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
   132       "MythTV src");
   133 }
   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->get_times = gst_mythtv_src_get_times;
   232   
   233   gstbasesrc_class->do_seek = gst_mythtv_src_do_seek;
   234   gstpushsrc_class->create = gst_mythtv_src_create;
   235     
   236   GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
   237       "MythTV Client Source");
   238 }
   239 
   240 static void
   241 gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class)
   242 {
   243   this->file_transfer = NULL;
   244 
   245   this->unique_setup = FALSE;
   246 
   247   this->mythtv_version = GMYTHTV_VERSION_DEFAULT;
   248   
   249   this->state = GST_MYTHTV_SRC_FILE_TRANSFER;
   250 
   251   this->bytes_read = 0;
   252   
   253   this->prev_content_size = 0;
   254 
   255   this->content_size = 0;
   256   this->read_offset = 0;
   257 
   258   this->content_size_last = 0;
   259 
   260   this->live_tv = FALSE;
   261   
   262   this->enable_timing_position = FALSE;
   263   this->update_prog_chain = FALSE;    
   264 
   265   this->user_agent = g_strdup ("mythtvsrc");
   266   this->mythtv_caps = NULL;
   267   this->update_prog_chain = FALSE;
   268   
   269   this->channel_num = 0;
   270   
   271   this->eos = FALSE;
   272   
   273   this->bytes_queue = NULL;
   274   
   275   this->th_mutex = NULL;
   276   
   277   gst_base_src_set_format( GST_BASE_SRC( this ), GST_FORMAT_BYTES );  
   278 
   279   /* gst_base_src_set_live ( GST_BASE_SRC( this ), TRUE ); */
   280   
   281   gst_pad_set_event_function ( GST_BASE_SRC_PAD(GST_BASE_SRC(this)),
   282       gst_mythtv_src_handle_event );
   283   gst_pad_set_query_function ( GST_BASE_SRC_PAD(GST_BASE_SRC(this)),
   284      gst_mythtv_src_handle_query );
   285 
   286 }
   287 
   288 static void
   289 gst_mythtv_src_finalize (GObject * gobject)
   290 {
   291   GstMythtvSrc *this = GST_MYTHTV_SRC (gobject);
   292 
   293   if ( this->th_read_ahead != NULL ) {
   294     gst_task_stop( this->th_read_ahead );
   295     this->th_read_ahead = NULL;
   296   }
   297 
   298   if (this->mythtv_caps) {
   299     gst_caps_unref (this->mythtv_caps);
   300     this->mythtv_caps = NULL;
   301   }
   302 
   303   if (this->file_transfer) {
   304     g_object_unref (this->file_transfer);
   305     this->file_transfer = NULL;
   306   }
   307 
   308   if (this->spawn_livetv) {
   309     g_object_unref (this->spawn_livetv);
   310     this->spawn_livetv = NULL;
   311   }
   312   
   313   if (this->backend_info) {
   314     g_object_unref (this->backend_info);
   315     this->backend_info = NULL;
   316   }
   317 
   318   if (this->uri_name) {
   319     g_free (this->uri_name);
   320   }
   321 
   322   if (this->user_agent) {
   323     g_free (this->user_agent);
   324   }
   325 
   326   if ( this->bytes_queue ) {
   327     g_byte_array_free( this->bytes_queue, TRUE );
   328     this->bytes_queue = NULL;
   329   }
   330 
   331   G_OBJECT_CLASS (parent_class)->finalize (gobject);
   332 }
   333 
   334 static gint
   335 do_read_request_response (GstMythtvSrc * src, guint size, GByteArray *data_ptr)
   336 {
   337   gint read = 0;
   338   guint sizetoread = size;
   339   guint max_iters = GMYTHTV_TRANSFER_MAX_RESENDS;
   340   
   341   GST_LOG_OBJECT( src, "Starting: [%s] Reading %d bytes...\n", __FUNCTION__, sizetoread ); 
   342 
   343   /* Loop sending the Myth File Transfer request:
   344    * Retry whilst authentication fails and we supply it. */
   345   gint len = 0;
   346   
   347   while ( sizetoread == size && --max_iters > 0) {
   348 
   349     len = gmyth_file_transfer_read( src->file_transfer,
   350 				data_ptr, 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 	} 
   370 	goto done;
   371       }
   372 
   373     }
   374 
   375     if ( read == sizetoread )
   376       goto done;
   377   }
   378 
   379   if ( ( read < 0 && !src->live_tv ) || max_iters == 0 )
   380     goto eos;
   381 
   382   goto done;
   383 
   384 eos:
   385   src->eos = TRUE;
   386 
   387 done:
   388   return read;
   389 }
   390 
   391 static GstFlowReturn
   392 gst_mythtv_src_create ( GstPushSrc* psrc, GstBuffer** outbuf )
   393 {
   394   GstMythtvSrc *src;
   395   GstFlowReturn ret = GST_FLOW_OK;
   396   gint read = -1;
   397 
   398   src = GST_MYTHTV_SRC ( psrc );
   399 
   400   /* The caller should know the number of bytes and not read beyond EOS. */
   401   if (G_UNLIKELY (src->eos))
   402     goto eos;
   403   if ( G_UNLIKELY (src->update_prog_chain) )
   404     goto change_progchain;
   405 
   406   //g_static_rec_mutex_lock( &th_mutex );
   407   GST_DEBUG_OBJECT( src, "[%s] offset = %llu, size = %d...\n", __FUNCTION__, 
   408   		src->read_offset, MAX_READ_SIZE );
   409 
   410   GST_DEBUG_OBJECT ( src, "[%s]\t\tCreate: buffer_remain: %d, buffer_size = %d.\n", __FUNCTION__, 
   411       (gint) src->buffer_remain, src->bytes_queue->len );
   412 
   413   /* just get from the byte array, no network effort... */
   414   if ( ( src->buffer_remain = src->bytes_queue->len ) < MAX_READ_SIZE ) {
   415   //if ( src->buffer_remain  ) {
   416   	guint buffer_size_inter = INTERNAL_BUFFER_SIZE - src->buffer_remain;
   417   	GByteArray *buffer = g_byte_array_new();
   418 
   419     read = do_read_request_response( src, buffer_size_inter, 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, g_memdup( buffer->data, read ), read );
   432     if ( read > buffer_size_inter )
   433     	GST_WARNING_OBJECT( src, "[%s] INCREASED buffer size! Backend sent more than we ask him... (%d)\n", 
   434     			__FUNCTION__, abs( read - buffer_size_inter ) );
   435 
   436     src->buffer_remain = src->buffer_remain + read;
   437     
   438     if ( buffer != NULL ) {
   439     	g_byte_array_free( buffer, TRUE );
   440     	buffer = NULL;    	
   441     }
   442 
   443     GST_DEBUG_OBJECT( src, "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\
   444 	"OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read, 
   445 	src->read_offset, src->content_size );
   446 	
   447   }
   448   
   449   guint buffer_size = ( src->buffer_remain < MAX_READ_SIZE) ? src->buffer_remain : MAX_READ_SIZE;
   450   
   451   /* Create the buffer. */
   452   ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
   453       src->read_offset, buffer_size,
   454       GST_PAD_CAPS (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc))), outbuf );    
   455 
   456   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
   457     if ( src->live_tv )
   458       goto change_progchain;
   459     else
   460       goto done;
   461   }
   462   
   463   /* gets the first buffer_size bytes from the byte array buffer variable */ 
   464   guint8 *buf = g_memdup( src->bytes_queue->data, buffer_size );
   465 
   466   GST_DEBUG_OBJECT( src, "[%s] read from network? %s!, buffer_remain = %d\n", __FUNCTION__, 
   467   	read == -1 ? "NO, got from buffer" : "YES, go see the backend's log file", src->buffer_remain );
   468 
   469   GST_BUFFER_SIZE (*outbuf) = buffer_size;
   470   GST_BUFFER_MALLOCDATA( *outbuf ) = g_malloc0( GST_BUFFER_SIZE (*outbuf) );
   471   GST_BUFFER_DATA( *outbuf ) = GST_BUFFER_MALLOCDATA( *outbuf );
   472   g_memmove( GST_BUFFER_DATA( (*outbuf) ), buf, GST_BUFFER_SIZE(*outbuf) );
   473   GST_BUFFER_OFFSET (*outbuf) = src->read_offset;
   474   GST_BUFFER_OFFSET_END (*outbuf) = src->read_offset + GST_BUFFER_SIZE (*outbuf);
   475 
   476   src->buffer_remain -= GST_BUFFER_SIZE (*outbuf);
   477 
   478   src->read_offset += GST_BUFFER_SIZE (*outbuf);
   479   src->bytes_read += GST_BUFFER_SIZE (*outbuf);
   480   GST_DEBUG_OBJECT( src, "[%s]\t\tBuffer output with size: %d\n", __FUNCTION__, GST_BUFFER_SIZE (*outbuf) );
   481   
   482   /* flushs the newly buffer got from byte array */
   483   src->bytes_queue = g_byte_array_remove_range( src->bytes_queue, 0, buffer_size );
   484 
   485   GST_DEBUG_OBJECT( src, "Got buffer: [%s]\t\tBUFFER --->SIZE = %d, OFFSET = %llu, "\
   486       "OFFSET_END = %llu.\n\n", __FUNCTION__, GST_BUFFER_SIZE (*outbuf), 
   487       GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf) );
   488 
   489   return ret;
   490 
   491 done:
   492   {
   493     const gchar *reason = gst_flow_get_name (ret);
   494 
   495     GST_DEBUG_OBJECT (src, "DONE task, reason %s", reason);
   496     return ret;
   497   }
   498 eos:
   499   {
   500     const gchar *reason = gst_flow_get_name (ret);
   501 
   502     GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
   503     return GST_FLOW_UNEXPECTED;
   504   }
   505   /* ERRORS */
   506 read_error:
   507   {
   508     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   509 	(NULL), ("Could not read any bytes (%i, %s)", read,
   510 		 src->uri_name));
   511     return GST_FLOW_ERROR;
   512   }
   513 change_progchain:
   514   {
   515     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   516 	(NULL), ("Seek failed, go to the next program info... (%i, %s)", read,
   517 		 src->uri_name));
   518 
   519     gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
   520 	gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
   521     // go to the next program chain
   522     src->unique_setup = FALSE;
   523     src->update_prog_chain = TRUE;
   524 
   525     gst_mythtv_src_next_program_chain( src );
   526 
   527     return GST_FLOW_ERROR_NO_DATA;
   528   }
   529 
   530 }
   531 
   532 gint64
   533 gst_mythtv_src_get_position ( GstMythtvSrc* src ) 
   534 {
   535 
   536   gint64 size_tmp = 0;
   537   guint max_tries = 2;
   538   if (src->live_tv == TRUE && ( abs( src->content_size - src->bytes_read ) < 
   539 		GMYTHTV_TRANSFER_MAX_BUFFER ) ) {
   540 
   541 get_file_pos:
   542     g_usleep( 10 );
   543     size_tmp = gmyth_recorder_get_file_position( src->spawn_livetv->recorder );
   544     if ( size_tmp > ( src->content_size + GMYTHTV_TRANSFER_MAX_BUFFER ) )
   545       src->content_size = size_tmp;
   546     else if ( size_tmp > 0 && --max_tries > 0 )
   547       goto get_file_pos;
   548     GST_LOG_OBJECT( src, "\t[%s]\tGET_POSITION: file_position = %lld\n",
   549 	__FUNCTION__, size_tmp );
   550     /* sets the last content size amount before it can be updated */
   551     src->prev_content_size = src->content_size;
   552   }
   553 
   554   return src->content_size;	
   555 
   556 }
   557 
   558 static gboolean
   559 gst_mythtv_src_do_seek( GstBaseSrc *base, GstSegment *segment )
   560 {
   561   GstMythtvSrc *src = GST_MYTHTV_SRC( base );
   562   gint64 new_offset = -1;
   563   gint64 actual_seek = segment->start;
   564   gboolean ret = TRUE;
   565 
   566   GST_LOG_OBJECT( src, "[%s]DO Seek called! (start = %lld, stop = %lld)\n", __FUNCTION__, 
   567   		segment->start, segment->stop );
   568 
   569   if ( segment->format == GST_FORMAT_TIME ) 
   570   {
   571     goto done; 
   572     //actual_seek = ( ( segment->start / 1000 ) * 28 ) * 4000;
   573   }
   574   GST_LOG_OBJECT( src, "[%s]Trying to seek at the value (actual_seek = %lld, read_offset = %lld)\n", __FUNCTION__, actual_seek, src->read_offset );
   575   /* verify if it needs to seek */
   576   if ( src->read_offset != actual_seek )
   577   {
   578 
   579     new_offset = gmyth_file_transfer_seek( src->file_transfer, segment->start, SEEK_SET );
   580 
   581     GST_LOG_OBJECT( src, "[%s] Segment offset start = %lld, SRC Offset = %lld, NEW actual backend SEEK Offset = %lld.\n",
   582 			__FUNCTION__, segment->start, src->read_offset, new_offset );
   583     if ( G_UNLIKELY (new_offset < 0 ) )
   584     {
   585       ret = FALSE;
   586       if ( src->live_tv )
   587 	goto change_progchain;
   588       else
   589 	goto eos;
   590     }
   591 
   592     src->read_offset = new_offset;
   593 
   594     if ( ret == FALSE ) {
   595       GST_INFO_OBJECT( src, "[%s] Failed to set the SEEK on segment!\n", __FUNCTION__ );
   596     }
   597 
   598   }
   599 
   600 done:
   601    return ret;
   602 
   603 eos:
   604   {
   605 
   606     GST_DEBUG_OBJECT (src, "EOS found on seeking!!!");
   607     return FALSE;
   608   }
   609 change_progchain:
   610   {
   611     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   612 	(NULL), ("Seek failed, go to the next program info... (%i, %s)", read,
   613 		 src->uri_name));
   614 
   615     gst_pad_push_event ( GST_BASE_SRC_PAD (base),
   616 	gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
   617     /* go to the next program chain */
   618     src->unique_setup = FALSE;
   619     src->update_prog_chain = TRUE;
   620 
   621     gst_mythtv_src_next_program_chain( src );
   622 
   623     return TRUE;
   624   }
   625 
   626 }
   627 
   628 /* create a socket for connecting to remote server */
   629 static gboolean
   630 gst_mythtv_src_start ( GstBaseSrc * bsrc )
   631 {
   632   GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
   633 
   634   GString *chain_id_local = NULL;
   635 
   636   gboolean ret = TRUE;
   637 
   638   if ( G_UNLIKELY (src->update_prog_chain) )
   639     goto change_progchain;
   640 
   641   if (src->unique_setup == FALSE) {
   642     src->unique_setup = TRUE;
   643   } else {
   644     goto done;
   645   }
   646 
   647   if ( src->live_tv ) {
   648   	src->backend_info = gmyth_backend_info_new_with_uri( src->uri_name );
   649     src->spawn_livetv = gmyth_livetv_new( );
   650     if ( gmyth_livetv_setup( src->spawn_livetv, src->backend_info ) == FALSE ) {
   651       ret = FALSE;
   652       goto init_failed;
   653     }    
   654 
   655     /* set up the uri variable */
   656     src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str );
   657     chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain );
   658     if ( chain_id_local != NULL ) {
   659       src->live_chain_id = g_strdup( chain_id_local->str );
   660       GST_INFO_OBJECT( src, "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id );      
   661     }
   662     //if ( src->uri_name == NULL || strlen( src->uri_name ) <= 0 )
   663     //	gmyth_context_initialize();
   664     	
   665     src->live_tv_id = src->spawn_livetv->recorder->recorder_num;
   666     GST_LOG_OBJECT( src, "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name ); 
   667   }
   668 
   669   //src->file_transfer = gmyth_file_transfer_new( src->live_tv_id, 
   670   //    g_string_new( src->uri_name ), -1, src->mythtv_version );
   671 	src->file_transfer = gmyth_file_transfer_new( );
   672 
   673   if ( src->file_transfer == NULL ) {
   674     goto init_failed;
   675   }
   676 
   677 	ret = gmyth_file_transfer_open( src->file_transfer, g_string_new( src->uri_name ) );
   678 
   679   /* sets the Playback monitor connection */
   680   //ret = gmyth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv );
   681 
   682   if ( src->live_tv == TRUE && ret == TRUE ) {
   683     /* loop finished, set the max tries variable to zero again... */
   684     wait_to_transfer = 0;
   685 
   686     while ( wait_to_transfer++ < GMYTHTV_TRANSFER_MAX_WAITS &&
   687 				( gmyth_livetv_is_recording( src->spawn_livetv ) == FALSE ) )
   688       g_usleep( 500 );
   689       
   690     /* IS_RECORDING again, just like the MythTV backend does... */
   691 	  gmyth_livetv_is_recording( src->spawn_livetv );
   692 	  
   693 	  sleep( 4 );  
   694 
   695   }
   696   /* sets the FileTransfer instance connection (video/audio download) */
   697   //ret = gmyth_file_transfer_setup( &(src->file_transfer), src->live_tv );
   698 
   699   if ( ret == FALSE ) {
   700 #ifndef GST_DISABLE_GST_DEBUG  
   701     if ( src->mythtv_msgs_dbg )
   702       GST_INFO_OBJECT( src, "MythTV FileTransfer request failed when setting up socket connection!\n" );  	  
   703 #endif
   704     goto begin_req_failed;
   705   }
   706 
   707   src->content_size = src->file_transfer->filesize;
   708 
   709   src->do_start = FALSE;
   710   
   711   /* this is used for the buffer cache */
   712   src->bytes_queue = g_byte_array_sized_new( INTERNAL_BUFFER_SIZE );
   713   src->buffer_remain = 0;
   714   
   715   //gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (src)),
   716 	//		gst_event_new_new_segment ( TRUE, 1.0, GST_FORMAT_TIME, 0, src->content_size, 0 ) );
   717 
   718 done:
   719   return TRUE;
   720 
   721   /* ERRORS */
   722 init_failed:
   723   {
   724     if (src->spawn_livetv != NULL )
   725       g_object_unref( src->spawn_livetv );
   726 
   727     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
   728 	(NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name));
   729     return FALSE;
   730   }
   731 begin_req_failed:
   732   {
   733     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
   734 	(NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name));
   735     return FALSE;
   736   }
   737 change_progchain:
   738   {
   739     GST_ELEMENT_ERROR (src, RESOURCE, READ,
   740 	(NULL), ("Seek failed, go to the next program info... (%s)",
   741 		 src->uri_name));
   742 
   743     gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (src)),
   744 	gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
   745 
   746     // go to the next program chain
   747     src->unique_setup = FALSE;
   748     src->update_prog_chain = TRUE;
   749 
   750     gst_mythtv_src_next_program_chain( src );
   751 
   752     return TRUE;
   753   }
   754 }
   755 
   756 /* create a new socket for connecting to the next program chain */
   757 static gboolean
   758 gst_mythtv_src_next_program_chain ( GstMythtvSrc *src )
   759 {
   760   GString *chain_id_local = NULL;
   761 
   762   gboolean ret = TRUE;
   763 
   764   if ( !src->live_tv )
   765     goto init_failed;
   766     
   767   if (src->unique_setup == FALSE) {
   768     src->unique_setup = TRUE;
   769   } else {
   770     goto done;
   771   }
   772   
   773 	GST_PAD_STREAM_LOCK( GST_BASE_SRC_PAD (GST_BASE_SRC (src)) );
   774 
   775   if (src->file_transfer) {
   776     g_object_unref (src->file_transfer);
   777     src->file_transfer = NULL;
   778   }
   779 
   780   if (src->uri_name) {
   781     g_free (src->uri_name);
   782   }
   783 
   784   if ( src->live_tv ) {
   785     if ( gmyth_livetv_next_program_chain( src->spawn_livetv ) == FALSE ) {
   786     	GST_INFO_OBJECT( src, "\n\n[%s]\t\tFailed to go to the next program chain!!!\n\n", __FUNCTION__ );
   787       ret = FALSE;
   788       goto init_failed;
   789     }
   790     /* set up the uri variable */
   791     src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str );
   792     chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain );
   793     if ( chain_id_local != NULL ) {
   794       src->live_chain_id = g_strdup( chain_id_local->str );
   795       GST_DEBUG_OBJECT( src, "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id );
   796     }
   797     src->live_tv_id = src->spawn_livetv->recorder->recorder_num;
   798     GST_LOG_OBJECT( src, "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name );
   799   }
   800 
   801   src->file_transfer = gmyth_file_transfer_new();
   802 
   803   if ( src->file_transfer == NULL ) {
   804     goto init_failed;
   805   }
   806   
   807 	ret = gmyth_file_transfer_open( src->file_transfer, g_string_new( src->uri_name ) );
   808 
   809   /* sets the Playback monitor connection */
   810   //ret = gmyth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv );
   811 
   812   if ( src->live_tv == TRUE && ret == TRUE ) {
   813     /* loop finished, set the max tries variable to zero again... */
   814     wait_to_transfer = 0;
   815 
   816     g_usleep( 200 );
   817 
   818     while ( wait_to_transfer++ < GMYTHTV_TRANSFER_MAX_WAITS && 
   819 				( gmyth_livetv_is_recording( src->spawn_livetv ) == FALSE ) )
   820       g_usleep( 1000 );
   821   }
   822 
   823   /* sets the FileTransfer instance connection (video/audio download) */
   824   //ret = gmyth_file_transfer_setup( &(src->file_transfer), src->live_tv );
   825 
   826   if ( ret == FALSE ) {
   827 #ifndef GST_DISABLE_GST_DEBUG  
   828     if ( src->mythtv_msgs_dbg )
   829       GST_ERROR_OBJECT( src, "MythTV FileTransfer request failed when setting up socket connection!\n" );  	  
   830 #endif
   831     goto begin_req_failed;
   832   }
   833   src->content_size_last = src->content_size;
   834 
   835   src->content_size = src->file_transfer->filesize;
   836   if ( src->live_tv ) {
   837   	wait_to_transfer = 0;
   838 	  while ( wait_to_transfer++ < GMYTHTV_TRANSFER_MAX_WAITS && src->content_size < GMYTHTV_TRANSFER_MAX_BUFFER )
   839 	    src->content_size = gst_mythtv_src_get_position( src );
   840   }
   841 
   842   src->read_offset = 0;  
   843   
   844   if ( src->bytes_queue != NULL ) {
   845   	g_byte_array_free( src->bytes_queue, TRUE );
   846   }
   847   
   848   src->bytes_queue = g_byte_array_sized_new( INTERNAL_BUFFER_SIZE );
   849   
   850   //gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (src)),
   851 	//		gst_event_new_new_segment ( TRUE, 1.0, GST_FORMAT_TIME, 0, src->content_size, 0 ) );
   852   
   853 done:
   854 	src->update_prog_chain = FALSE;
   855 	
   856 	GST_PAD_STREAM_UNLOCK( GST_BASE_SRC_PAD (GST_BASE_SRC (src)) );
   857 	
   858   return TRUE;
   859 
   860   /* ERRORS */
   861 init_failed:
   862   {
   863     if (src->spawn_livetv != NULL )
   864       g_object_unref( src->spawn_livetv );
   865 
   866     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
   867 	(NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name));
   868     return FALSE;
   869   }
   870 begin_req_failed:
   871   {
   872     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
   873 	(NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name));
   874     return FALSE;
   875   }
   876 
   877 }
   878 
   879 static gboolean
   880 gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size)
   881 {
   882   GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
   883   gboolean ret = TRUE;
   884   GST_LOG_OBJECT( src, "[%s] Differs from previous content size: %d (max.: %d)\n", __FUNCTION__, 
   885   			abs( src->content_size - src->prev_content_size ), GMYTHTV_TRANSFER_MAX_BUFFER );
   886   			
   887   if ( src->live_tv ) {
   888   	ret = FALSE;
   889 	} else if ( src->live_tv && src->enable_timing_position && ( abs( src->content_size - src->bytes_read ) < 
   890 				GMYTHTV_TRANSFER_MAX_BUFFER ) ) {
   891     
   892     gint64 new_offset = gmyth_recorder_get_file_position( src->spawn_livetv->recorder );
   893     if ( new_offset > 0 && new_offset > src->content_size ) {
   894 			src->content_size = new_offset;
   895     } else if ( new_offset < src->content_size ) {
   896 			src->update_prog_chain = TRUE;
   897 	  }
   898 
   899   }
   900 
   901   *size = src->content_size;
   902   GST_LOG_OBJECT( src, "[%s] Content size = %lld\n", __FUNCTION__, src->content_size );
   903   
   904   return ret;
   905 
   906 }
   907 
   908 /* close the socket and associated resources
   909  * used both to recover from errors and go to NULL state */
   910 static gboolean
   911 gst_mythtv_src_stop (GstBaseSrc * bsrc)
   912 {
   913   GstMythtvSrc *src;
   914 
   915   src = GST_MYTHTV_SRC (bsrc);
   916 
   917   if (src->uri_name) {
   918     g_free (src->uri_name);
   919     src->uri_name = NULL;
   920   }
   921 
   922   if (src->mythtv_caps) {
   923     gst_caps_unref (src->mythtv_caps);
   924     src->mythtv_caps = NULL;
   925   }
   926 
   927   src->eos = FALSE;
   928 
   929   return TRUE;
   930 }
   931 
   932 static gboolean
   933 gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event)
   934 {
   935   GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad));
   936   gint64 cont_size = 0;
   937   gboolean ret = FALSE;
   938 
   939   switch (GST_EVENT_TYPE (event)) {
   940     case GST_EVENT_EOS:
   941       GST_WARNING_OBJECT( src, "[%s] Got EOS event!!!\n", __FUNCTION__ );
   942 
   943       if ( src->live_tv ) {
   944 	cont_size = gst_mythtv_src_get_position (src);
   945 	if ( cont_size > src->content_size ) {
   946 	  src->content_size = cont_size;
   947 	  src->eos = FALSE;
   948 	} else {
   949 	  src->eos = TRUE;
   950 	  gst_element_set_state ( GST_ELEMENT (src), GST_STATE_NULL );
   951 	  gst_element_set_locked_state ( GST_ELEMENT (src), FALSE );
   952 	}
   953       }
   954       break;
   955     default:
   956       ret = gst_pad_event_default (pad, event);
   957   }
   958 
   959   return ret;
   960 }
   961 
   962 static gboolean
   963 gst_mythtv_src_is_seekable( GstBaseSrc *push_src )
   964 {
   965   return TRUE;
   966 }
   967 
   968 static gboolean
   969 gst_mythtv_src_handle_query (GstPad * pad, GstQuery * query)
   970 {
   971   gboolean res = FALSE;
   972   GstMythtvSrc *myth = GST_MYTHTV_SRC (gst_pad_get_parent (pad));
   973   GstFormat formt;
   974 
   975   switch (GST_QUERY_TYPE (query)) {
   976     case GST_QUERY_POSITION:
   977     {
   978     	gint64 pos = -1;
   979       gst_query_parse_position (query, &formt, &pos );
   980       res = TRUE;
   981       if ( formt == GST_FORMAT_BYTES )
   982       	GST_DEBUG_OBJECT (myth, "POS %lld (BYTES).\n", pos );
   983       else if ( formt == GST_FORMAT_TIME )
   984       	GST_DEBUG_OBJECT (myth, "POS %lld (TIME).\n", pos );
   985       break;
   986     }
   987     case GST_QUERY_DURATION:
   988     {
   989 #if 0
   990       if (myth->duration != 0) {
   991 	gint64 total;
   992 	gint64 fps;
   993 
   994 	fps = nuv->h->i_fpsn / nuv->h->i_fpsd;
   995 	total = gst_util_uint64_scale_int (GST_SECOND, nuv->h->i_video_blocks, fps);
   996       }
   997 #endif
   998 	gint64 dur = -1;
   999 	gst_query_parse_duration( query, &formt, &dur );
  1000 	//gst_query_set_duration (query, GST_FORMAT_TIME, myth->content_size);
  1001   if ( formt == GST_FORMAT_BYTES )
  1002   	GST_DEBUG_OBJECT (myth, "DURATION %lld (BYTES).\n", dur );
  1003   else if ( formt == GST_FORMAT_TIME )
  1004   	GST_DEBUG_OBJECT (myth, "DURATION %lld (TIME).\n", dur );
  1005 	res = TRUE;
  1006       break;
  1007     }
  1008     default:
  1009     {
  1010       res = FALSE;
  1011       break;
  1012     }
  1013   }
  1014 
  1015   gst_object_unref (myth);
  1016 
  1017   return res;
  1018 }
  1019 
  1020 static GstStateChangeReturn
  1021 gst_mythtv_src_change_state (GstElement * element, GstStateChange transition)
  1022 {
  1023   GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;//GST_STATE_CHANGE_NO_PREROLL;
  1024   GstMythtvSrc *src = GST_MYTHTV_SRC (element);
  1025 
  1026   switch (transition) {
  1027     case GST_STATE_CHANGE_NULL_TO_READY:
  1028       //src->do_start = TRUE;
  1029       //src->unique_setup = FALSE;
  1030       break;
  1031     case GST_STATE_CHANGE_READY_TO_PAUSED:
  1032     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
  1033       //src->eos = FALSE;
  1034       break;
  1035     default:
  1036       break;
  1037   }
  1038 
  1039   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  1040   if (ret == GST_STATE_CHANGE_FAILURE)
  1041     return ret;
  1042 
  1043   switch (transition) {
  1044     case GST_STATE_CHANGE_READY_TO_NULL:
  1045       GST_INFO_OBJECT( src, "[%s] READY to NULL called!\n", __FUNCTION__ );
  1046       break;
  1047     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
  1048       GST_INFO_OBJECT( src, "[%s] PLAYING to PAUSED called!\n", __FUNCTION__ );
  1049     case GST_STATE_CHANGE_PAUSED_TO_READY:
  1050       GST_INFO_OBJECT( src, "[%s] PAUSED to READY called!\n", __FUNCTION__ );
  1051       if ( src->live_tv && src->update_prog_chain ) {
  1052 	      if ( !gmyth_recorder_send_frontend_ready_command( src->spawn_livetv->recorder ) )
  1053 	      	GST_WARNING_OBJECT( src, "[%s] Couldn't send the FRONTEND_READY message to the backend!", __FUNCTION__ );
  1054 	      else
  1055 	      	GST_DEBUG_OBJECT( src, "[%s] Message FRONTEND_READY was sent to the backend!", __FUNCTION__ );
  1056       	
  1057       /*
  1058       	
  1059   			gst_pad_push_event ( GST_BASE_SRC_PAD (GST_BASE_SRC (src)),
  1060       			gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0 ) );
  1061 
  1062 				src->read_offset = 0;
  1063 				src->bytes_read = 0;
  1064 				src->unique_setup = FALSE;				
  1065 				gst_mythtv_src_next_program_chain( src );
  1066 				*/
  1067       }
  1068       
  1069       break;
  1070     default:
  1071       break;
  1072   }
  1073 
  1074   return ret;
  1075 }
  1076 
  1077 static void
  1078 gst_mythtv_src_set_property (GObject * object, guint prop_id,
  1079     const GValue * value, GParamSpec * pspec)
  1080 {
  1081   GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
  1082 
  1083   GST_OBJECT_LOCK (mythtvsrc);
  1084   switch (prop_id) {
  1085     case PROP_URI:
  1086     case PROP_LOCATION:
  1087       {
  1088 	if (!g_value_get_string (value)) {
  1089 	  GST_WARNING ("location property cannot be NULL");
  1090 	  goto done;
  1091 	}
  1092 
  1093 	if (mythtvsrc->uri_name != NULL) {
  1094 	  g_free (mythtvsrc->uri_name);
  1095 	  mythtvsrc->uri_name = NULL;
  1096 	}
  1097 	mythtvsrc->uri_name = g_value_dup_string (value);
  1098 
  1099 	break;
  1100       }
  1101 #ifndef GST_DISABLE_GST_DEBUG
  1102     case PROP_GMYTHTV_DBG:
  1103       {
  1104 	mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value);
  1105 	break;
  1106       }
  1107 #endif
  1108     case PROP_GMYTHTV_VERSION:
  1109       {
  1110 	mythtvsrc->mythtv_version = g_value_get_int (value);
  1111 	break;
  1112       }
  1113     case PROP_GMYTHTV_LIVEID:
  1114       {
  1115 	mythtvsrc->live_tv_id = g_value_get_int (value);
  1116 	break;
  1117       }
  1118     case PROP_GMYTHTV_LIVE:
  1119       {
  1120 	mythtvsrc->live_tv = g_value_get_boolean (value);
  1121 	break;
  1122       }
  1123     case PROP_GMYTHTV_ENABLE_TIMING_POSITION:
  1124       {
  1125 	mythtvsrc->enable_timing_position = g_value_get_boolean (value);
  1126 	break;
  1127       }      
  1128     case PROP_GMYTHTV_LIVE_CHAINID:
  1129       {
  1130 	if (!g_value_get_string (value)) {
  1131 	  GST_WARNING ("MythTV Live chainid property cannot be NULL");
  1132 	  goto done;
  1133 	}
  1134 
  1135 	if (mythtvsrc->live_chain_id != NULL) {
  1136 	  g_free (mythtvsrc->live_chain_id);
  1137 	  mythtvsrc->live_chain_id = NULL;
  1138 	}
  1139 	mythtvsrc->live_chain_id = g_value_dup_string (value);
  1140 	break;
  1141       }
  1142     case PROP_GMYTHTV_CHANNEL_NUM:
  1143       {
  1144 	mythtvsrc->channel_num = g_value_get_int (value);
  1145 	break;
  1146       }
  1147     default:
  1148       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1149       break;
  1150   }
  1151   GST_OBJECT_UNLOCK (mythtvsrc);
  1152 done:
  1153   return;
  1154 }
  1155 
  1156 static void
  1157 gst_mythtv_src_get_property (GObject * object, guint prop_id,
  1158     GValue * value, GParamSpec * pspec)
  1159 {
  1160   GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
  1161 
  1162   GST_OBJECT_LOCK (mythtvsrc);
  1163   switch (prop_id) {
  1164     case PROP_URI:
  1165     case PROP_LOCATION:
  1166       {
  1167 	gchar *str = g_strdup( "" );
  1168 
  1169 	if ( mythtvsrc->uri_name == NULL ) {
  1170 	  g_free (mythtvsrc->uri_name);
  1171 	  mythtvsrc->uri_name = NULL;
  1172 	} else {
  1173 	  str = g_strdup( mythtvsrc->uri_name );
  1174 	}
  1175 	g_value_set_string ( value, str );
  1176 	break;
  1177       }
  1178 #ifndef GST_DISABLE_GST_DEBUG
  1179     case PROP_GMYTHTV_DBG:
  1180       g_value_set_boolean ( value, mythtvsrc->mythtv_msgs_dbg );
  1181       break;
  1182 #endif
  1183     case PROP_GMYTHTV_VERSION:
  1184       {
  1185 	g_value_set_int ( value, mythtvsrc->mythtv_version );
  1186 	break;
  1187       }
  1188     case PROP_GMYTHTV_LIVEID:
  1189       {
  1190 	g_value_set_int ( value, mythtvsrc->live_tv_id );
  1191 	break;
  1192       }
  1193     case PROP_GMYTHTV_LIVE:
  1194       g_value_set_boolean ( value, mythtvsrc->live_tv );
  1195       break;
  1196     case PROP_GMYTHTV_ENABLE_TIMING_POSITION:
  1197       g_value_set_boolean ( value, mythtvsrc->enable_timing_position );
  1198       break;
  1199     case PROP_GMYTHTV_LIVE_CHAINID:
  1200       {
  1201 	gchar *str = g_strdup( "" );
  1202 
  1203 	if ( mythtvsrc->live_chain_id == NULL ) {
  1204 	  g_free (mythtvsrc->live_chain_id);
  1205 	  mythtvsrc->live_chain_id = NULL;
  1206 	} else {
  1207 	  str = g_strdup( mythtvsrc->live_chain_id );
  1208 	}
  1209 	g_value_set_string ( value, str );
  1210 	break;
  1211       }
  1212     case PROP_GMYTHTV_CHANNEL_NUM:
  1213       {
  1214 	g_value_set_int ( value, mythtvsrc->channel_num );
  1215 	break;
  1216       }
  1217     default:
  1218       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1219       break;
  1220   }
  1221   GST_OBJECT_UNLOCK (mythtvsrc);
  1222 }
  1223 
  1224 /* entry point to initialize the plug-in
  1225  * initialize the plug-in itself
  1226  * register the element factories and pad templates
  1227  * register the features
  1228  */
  1229 static gboolean
  1230 plugin_init (GstPlugin * plugin)
  1231 {
  1232   return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE,
  1233       GST_TYPE_MYTHTV_SRC);
  1234 }
  1235 
  1236 /* this is the structure that gst-register looks for
  1237  * so keep the name plugin_desc, or you cannot get your plug-in registered */
  1238 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
  1239     GST_VERSION_MINOR,
  1240     "mythtv",
  1241     "lib MythTV src",
  1242     plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
  1243 
  1244 
  1245 /*** GSTURIHANDLER INTERFACE *************************************************/
  1246   static guint 
  1247 gst_mythtv_src_uri_get_type (void)
  1248 {
  1249   return GST_URI_SRC;
  1250 }
  1251 
  1252   static gchar **
  1253 gst_mythtv_src_uri_get_protocols (void)
  1254 {
  1255   static gchar *protocols[] = { "myth", "myths", NULL };
  1256 
  1257   return protocols;
  1258 }
  1259 
  1260   static const gchar *
  1261 gst_mythtv_src_uri_get_uri (GstURIHandler * handler)
  1262 {
  1263   GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
  1264 
  1265   return src->uri_name;
  1266 }
  1267 
  1268   static gboolean
  1269 gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
  1270 {
  1271   GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
  1272 
  1273   gchar *protocol;
  1274 
  1275   protocol = gst_uri_get_protocol (uri);
  1276   if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) {
  1277     g_free (protocol);
  1278     return FALSE;
  1279   }
  1280   g_free (protocol);
  1281   g_object_set (src, "location", uri, NULL);
  1282 
  1283   return TRUE;
  1284 }
  1285 
  1286  static void
  1287 gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
  1288 {
  1289   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
  1290 
  1291   iface->get_type = gst_mythtv_src_uri_get_type;
  1292   iface->get_protocols = gst_mythtv_src_uri_get_protocols;
  1293   iface->get_uri = gst_mythtv_src_uri_get_uri;
  1294   iface->set_uri = gst_mythtv_src_uri_set_uri;
  1295 }
  1296 
  1297   void
  1298 size_header_handler (void *userdata, const char *value)
  1299 {
  1300   GstMythtvSrc *src = GST_MYTHTV_SRC (userdata);
  1301 
  1302   //src->content_size = g_ascii_strtoull (value, NULL, 10);
  1303 
  1304   GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size);
  1305 }