gst-gmyth/mythsrc/gstmythtvsrc.c
author renatofilho
Thu Jun 14 18:21:53 2007 +0100 (2007-06-14)
branchtrunk
changeset 752 b7f71ba285da
parent 725 a102805611e7
child 754 cb885ee44618
permissions -rwxr-xr-x
[svn r758] fixed indent using GNU Style
     1 /* GStreamer MythTV Plug-in
     2  * Copyright (C) <2006> Rosfran Borges <rosfran.borges@indt.org.br>
     3  *
     4  * This library is free software; you can redistribute it and/or
     5  * modify it under the terms of the GNU Library General Public
     6  * License as published by the Free Software Foundation; either
     7  * version 2 of the License, or (at your option) any later version.
     8  *
     9  * This library is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    12  * Library General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU Library General Public
    15  * License along with this library; if not, write to the
    16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    17  * Boston, MA 02111-1307, USA.
    18  */
    19 /**
    20  * SECTION:element-mythtvsrc
    21  *
    22  * <refsect2>
    23  * <para>
    24  * MythTVSrc allows to access a remote MythTV backend streaming Video/Audio server,
    25  * and to render audio and video content through a TCP/IP connection to a specific
    26  * port on this server, and based on a known MythTV protocol that is based on 
    27  * some message passing, such as REQUEST_BLOCK on a specified number of bytes, to get
    28  * some chunk of remote file data.
    29  * You should pass the information aboute the remote MythTV backend server 
    30  * through the <link linkend="GstMythTVSrc--location">location</link> property.
    31  * </para>
    32  * <title>Examples</title>
    33  * <para>
    34  * If you want to get the LiveTV content (set channel, TV tuner, RemoteEncoder, 
    35  * Recorder),
    36  * put the following URI:
    37  * 
    38  * <programlisting> 
    39  *  myth://xxx.xxx.xxx.xxx:6543/livetv?channel=BBC
    40  * </programlisting>
    41  *
    42  * This URI will say to the gmyth library to configure the Recorder instance (used to
    43  * change the channel, start the TV multimedia content transmition, etc.), using
    44  * the IP address (xxx.xxx.xxx.xxx) and port number (6543) of the MythTV backend 
    45  * server, and setting the channel name to "BBC". 
    46  * 
    47  * To get a already recorded the MythTV NUV file, put the following URI:
    48  * 
    49  * <programlisting>
    50  *  myth://xxx.xxx.xxx.xxx:6543/filename.nuv
    51  * </programlisting>
    52  *
    53  * This URI will say to the gmyth library to configure the Recorder instance (used to
    54  * change the channel, start the TV multimedia content transmition, etc.), using
    55  * the IP address (xxx.xxx.xxx.xxx) and port number (6543) of the MythTV backend 
    56  * server, and setting the channel name to "BBC".
    57  * 
    58  * Another possible way to use the LiveTV content, and just in the case you want to 
    59  * use the mysql database, put the location URI in the following format:
    60  * 
    61  * <programlisting> 
    62  *  myth://mythtv:mythtv@xxx.xxx.xxx.xxx:6543/?mythconverg&channel=9
    63  * </programlisting>
    64  * 
    65  * Where the first field is the protocol (myth), the second and third are user 
    66  * name (mythtv) and password (mythtv), then backend host name and port number, 
    67  * and the last field is the database name (mythconverg).
    68  * </para>
    69  * </refsect2>
    70  */
    71 #ifdef HAVE_CONFIG_H
    72 #include "config.h"
    73 #endif
    74 
    75 #include "gstmythtvsrc.h"
    76 #include <gmyth/gmyth_file.h>
    77 #include <gmyth/gmyth_file_transfer.h>
    78 #include <gmyth/gmyth_file_local.h>
    79 #include <gmyth/gmyth_livetv.h>
    80 
    81 #include <gmyth/gmyth_socket.h>
    82 #include <gmyth/gmyth_tvchain.h>
    83 
    84 #include <string.h>
    85 #include <unistd.h>
    86 
    87 GST_DEBUG_CATEGORY_STATIC(mythtvsrc_debug);
    88 #define GST_CAT_DEFAULT mythtvsrc_debug
    89 
    90 #define GST_GMYTHTV_ID_NUM                  1
    91 
    92 #define GST_GMYTHTV_CHANNEL_DEFAULT_NUM     (-1)
    93 
    94 #define GMYTHTV_VERSION_DEFAULT			        30
    95 
    96 #define GMYTHTV_TRANSFER_MAX_WAITS          100
    97 
    98 #define GMYTHTV_TRANSFER_MAX_RESENDS        2
    99 
   100 #define GMYTHTV_TRANSFER_MAX_BUFFER         (128*1024)
   101 
   102 #define MAX_READ_SIZE                       (4*1024)
   103 
   104 #define GST_FLOW_ERROR_NO_DATA              (-101)
   105 
   106 #define REQUEST_MAX_SIZE                    (64*1024)
   107 
   108 #define INTERNAL_BUFFER_SIZE                (90*1024)
   109 
   110 static const GstElementDetails gst_mythtv_src_details =
   111 GST_ELEMENT_DETAILS("MythTV client source",
   112 					"Source/Network",
   113 					"Control and receive data as a client over the network "
   114 					"via raw socket connections using the MythTV protocol",
   115 					"Rosfran Borges <rosfran.borges@indt.org.br>");
   116 
   117 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE("src",
   118 																  GST_PAD_SRC,
   119 																  GST_PAD_ALWAYS,
   120 																  GST_STATIC_CAPS_ANY);
   121 	/* GST_STATIC_CAPS ("video/x-nuv")); */
   122 
   123 enum
   124 {
   125   PROP_0,
   126   PROP_LOCATION,
   127 #ifndef GST_DISABLE_GST_DEBUG
   128   PROP_GMYTHTV_DBG,
   129 #endif
   130   PROP_GMYTHTV_VERSION,
   131   PROP_GMYTHTV_LIVE,
   132   PROP_GMYTHTV_LIVEID,
   133   PROP_GMYTHTV_LIVE_CHAINID,
   134   PROP_GMYTHTV_ENABLE_TIMING_POSITION,
   135   PROP_GMYTHTV_CHANNEL_NUM,
   136   PROP_GMYTHTV_MAX_TRY
   137 };
   138 
   139 static void gst_mythtv_src_clear(GstMythtvSrc * mythtv_src);
   140 
   141 static void gst_mythtv_src_finalize(GObject * gobject);
   142 
   143 static GstFlowReturn gst_mythtv_src_create(GstPushSrc * psrc,
   144 										   GstBuffer ** outbuf);
   145 
   146 static gboolean gst_mythtv_src_start(GstBaseSrc * bsrc);
   147 static gboolean gst_mythtv_src_stop(GstBaseSrc * bsrc);
   148 static gboolean gst_mythtv_src_get_size(GstBaseSrc * bsrc, guint64 * size);
   149 static gboolean gst_mythtv_src_is_seekable(GstBaseSrc * push_src);
   150 
   151 static gboolean gst_mythtv_src_do_seek(GstBaseSrc * base,
   152 									   GstSegment * segment);
   153 
   154 static GstStateChangeReturn
   155 gst_mythtv_src_change_state(GstElement * element, GstStateChange transition);
   156 
   157 static void gst_mythtv_src_set_property(GObject * object, guint prop_id,
   158 										const GValue * value,
   159 										GParamSpec * pspec);
   160 static void gst_mythtv_src_get_property(GObject * object, guint prop_id,
   161 										GValue * value, GParamSpec * pspec);
   162 
   163 static void gst_mythtv_src_uri_handler_init(gpointer g_iface,
   164 											gpointer iface_data);
   165 
   166 static gboolean gst_mythtv_src_handle_query(GstPad * pad, GstQuery * query);
   167 
   168 static gboolean gst_mythtv_src_handle_event(GstPad * pad, GstEvent * event);
   169 
   170 static GMythFileReadResult do_read_request_response(GstMythtvSrc * src,
   171 													guint size,
   172 													GByteArray * data_ptr);
   173 
   174 static void
   175 _urihandler_init(GType type)
   176 {
   177   static const GInterfaceInfo urihandler_info = {
   178 	gst_mythtv_src_uri_handler_init,
   179 	NULL,
   180 	NULL
   181   };
   182 
   183   g_type_add_interface_static(type, GST_TYPE_URI_HANDLER, &urihandler_info);
   184 
   185   GST_DEBUG_CATEGORY_INIT(mythtvsrc_debug, "mythtvsrc", 0, "MythTV src");
   186 }
   187 
   188 GST_BOILERPLATE_FULL(GstMythtvSrc, gst_mythtv_src, GstPushSrc,
   189 					 GST_TYPE_PUSH_SRC, _urihandler_init)
   190 	 static void gst_mythtv_src_base_init(gpointer g_class)
   191 {
   192   GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
   193 
   194   gst_element_class_add_pad_template(element_class,
   195 									 gst_static_pad_template_get
   196 									 (&srctemplate));
   197 
   198   gst_element_class_set_details(element_class, &gst_mythtv_src_details);
   199 
   200   element_class->change_state = gst_mythtv_src_change_state;
   201 
   202 }
   203 
   204 static void
   205 gst_mythtv_src_class_init(GstMythtvSrcClass * klass)
   206 {
   207   GObjectClass *gobject_class;
   208   GstPushSrcClass *gstpushsrc_class;
   209   GstBaseSrcClass *gstbasesrc_class;
   210 
   211   gobject_class = (GObjectClass *) klass;
   212   gstbasesrc_class = (GstBaseSrcClass *) klass;
   213   gstpushsrc_class = (GstPushSrcClass *) klass;
   214 
   215   gobject_class->set_property = gst_mythtv_src_set_property;
   216   gobject_class->get_property = gst_mythtv_src_get_property;
   217   gobject_class->finalize = gst_mythtv_src_finalize;
   218 
   219   g_object_class_install_property
   220 	(gobject_class, PROP_LOCATION,
   221 	 g_param_spec_string("location", "Location",
   222 						 "The location. In the form:"
   223 						 "\n\t\t\tmyth://a.com/file.nuv"
   224 						 "\n\t\t\tmyth://a.com:23223/file.nuv "
   225 						 "\n\t\t\ta.com/file.nuv - default scheme 'myth'",
   226 						 "", G_PARAM_READWRITE));
   227 
   228   g_object_class_install_property
   229 	(gobject_class, PROP_GMYTHTV_VERSION,
   230 	 g_param_spec_int("mythtv-version", "mythtv-version",
   231 					  "Change MythTV version", 26, 30, 26,
   232 					  G_PARAM_READWRITE));
   233 
   234   g_object_class_install_property
   235 	(gobject_class, PROP_GMYTHTV_LIVEID,
   236 	 g_param_spec_int("mythtv-live-id", "mythtv-live-id",
   237 					  "Change MythTV version",
   238 					  0, 200, GST_GMYTHTV_ID_NUM, G_PARAM_READWRITE));
   239 
   240   g_object_class_install_property
   241 	(gobject_class, PROP_GMYTHTV_LIVE_CHAINID,
   242 	 g_param_spec_string("mythtv-live-chainid", "mythtv-live-chainid",
   243 						 "Sets the MythTV chain ID (from TV Chain)", "",
   244 						 G_PARAM_READWRITE));
   245 
   246   g_object_class_install_property
   247 	(gobject_class, PROP_GMYTHTV_LIVE,
   248 	 g_param_spec_boolean("mythtv-live", "mythtv-live",
   249 						  "Enable MythTV Live TV content streaming", FALSE,
   250 						  G_PARAM_READWRITE));
   251 
   252   g_object_class_install_property
   253 	(gobject_class, PROP_GMYTHTV_ENABLE_TIMING_POSITION,
   254 	 g_param_spec_boolean("mythtv-enable-timing-position",
   255 						  "mythtv-enable-timing-position",
   256 						  "Enable MythTV Live TV content size continuous updating",
   257 						  FALSE, G_PARAM_READWRITE));
   258 
   259   g_object_class_install_property
   260 	(gobject_class, PROP_GMYTHTV_CHANNEL_NUM,
   261 	 g_param_spec_string("mythtv-channel", "mythtv-channel",
   262 						 "Change MythTV channel number",
   263 						 "", G_PARAM_READWRITE));
   264 
   265   g_object_class_install_property
   266 	(gobject_class, PROP_GMYTHTV_MAX_TRY,
   267 	 g_param_spec_int("max-try", "max-try",
   268 					  "Set the max try for get MythTV free recorder",
   269 					  0, G_MAXINT, 10, G_PARAM_READWRITE));
   270 
   271 
   272 #ifndef GST_DISABLE_GST_DEBUG
   273   g_object_class_install_property
   274 	(gobject_class, PROP_GMYTHTV_DBG,
   275 	 g_param_spec_boolean("mythtv-debug", "mythtv-debug",
   276 						  "Enable MythTV debug messages", FALSE,
   277 						  G_PARAM_READWRITE));
   278 #endif
   279 
   280   gstbasesrc_class->start = gst_mythtv_src_start;
   281   gstbasesrc_class->stop = gst_mythtv_src_stop;
   282   gstbasesrc_class->get_size = gst_mythtv_src_get_size;
   283   gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable;
   284 
   285   gstbasesrc_class->do_seek = gst_mythtv_src_do_seek;
   286   gstpushsrc_class->create = gst_mythtv_src_create;
   287 
   288   GST_DEBUG_CATEGORY_INIT(mythtvsrc_debug, "mythtvsrc", 0,
   289 						  "MythTV Client Source");
   290 }
   291 
   292 static void
   293 gst_mythtv_src_init(GstMythtvSrc * this, GstMythtvSrcClass * g_class)
   294 {
   295   this->file = NULL;
   296 
   297   this->unique_setup = FALSE;
   298 
   299   this->mythtv_version = GMYTHTV_VERSION_DEFAULT;
   300 
   301   this->state = GST_MYTHTV_SRC_FILE_TRANSFER;
   302 
   303   this->bytes_read = 0;
   304 
   305   this->prev_content_size = 0;
   306 
   307   this->content_size = 0;
   308   this->read_offset = 0;
   309 
   310   this->content_size_last = 0;
   311 
   312   this->live_tv = FALSE;
   313 
   314   this->enable_timing_position = FALSE;
   315   this->update_prog_chain = FALSE;
   316 
   317   this->user_agent = g_strdup("mythtvsrc");
   318   this->update_prog_chain = FALSE;
   319 
   320   this->channel_name = NULL;
   321 
   322   this->eos = FALSE;
   323 
   324   this->bytes_queue = NULL;
   325 
   326   this->wait_to_transfer = 0;
   327 
   328   gst_base_src_set_format(GST_BASE_SRC(this), GST_FORMAT_BYTES);
   329 
   330   gst_pad_set_event_function(GST_BASE_SRC_PAD(GST_BASE_SRC(this)),
   331 							 gst_mythtv_src_handle_event);
   332   gst_pad_set_query_function(GST_BASE_SRC_PAD(GST_BASE_SRC(this)),
   333 							 gst_mythtv_src_handle_query);
   334 
   335 }
   336 
   337 static void
   338 gst_mythtv_src_clear(GstMythtvSrc * mythtv_src)
   339 {
   340   mythtv_src->unique_setup = FALSE;
   341 
   342   if (mythtv_src->spawn_livetv)
   343 	{
   344 	  g_object_unref(mythtv_src->spawn_livetv);
   345 	  mythtv_src->spawn_livetv = NULL;
   346 	}
   347 
   348   if (mythtv_src->file)
   349 	{
   350 	  g_object_unref(mythtv_src->file);
   351 	  mythtv_src->file = NULL;
   352 	}
   353 
   354   if (mythtv_src->backend_info)
   355 	{
   356 	  g_object_unref(mythtv_src->backend_info);
   357 	  mythtv_src->backend_info = NULL;
   358 	}
   359 
   360   if (mythtv_src->bytes_queue)
   361 	{
   362 	  g_byte_array_free(mythtv_src->bytes_queue, TRUE);
   363 	  mythtv_src->bytes_queue = NULL;
   364 	}
   365 }
   366 
   367 static void
   368 gst_mythtv_src_finalize(GObject * gobject)
   369 {
   370   GstMythtvSrc *this = GST_MYTHTV_SRC(gobject);
   371 
   372   gst_mythtv_src_clear(this);
   373 
   374   if (this->uri_name)
   375 	{
   376 	  g_free(this->uri_name);
   377 	  this->uri_name = NULL;
   378 	}
   379 
   380   if (this->user_agent)
   381 	{
   382 	  g_free(this->user_agent);
   383 	  this->user_agent = NULL;
   384 	}
   385 
   386   G_OBJECT_CLASS(parent_class)->finalize(gobject);
   387 }
   388 
   389 static GMythFileReadResult
   390 do_read_request_response(GstMythtvSrc * src, guint size,
   391 						 GByteArray * data_ptr)
   392 {
   393   gint read = 0;
   394   guint sizetoread = size;
   395   gint max_iters = GMYTHTV_TRANSFER_MAX_RESENDS;
   396   GMythFileReadResult result;
   397 
   398   GST_LOG_OBJECT(src, "Starting: Reading %d bytes...", sizetoread);
   399 
   400  /* Loop sending the Myth File Transfer request:
   401   * Retry whilst authentication fails and we supply it. */
   402 
   403   while (sizetoread == size && --max_iters > 0)
   404 	{
   405 	 /* if ( gmyth_backend_info_is_local_file(src->backend_info) ) */
   406 	  if (IS_GMYTH_FILE_LOCAL(src->file))
   407 		result = gmyth_file_local_read(GMYTH_FILE_LOCAL(src->file),
   408 									   data_ptr, sizetoread, src->live_tv);
   409 	  else if (IS_GMYTH_FILE_TRANSFER(src->file))
   410 		result = gmyth_file_transfer_read(GMYTH_FILE_TRANSFER(src->file),
   411 										  data_ptr, sizetoread, src->live_tv);
   412 
   413 	  if (data_ptr->len > 0)
   414 		{
   415 		  read += data_ptr->len;
   416 		  sizetoread -= data_ptr->len;
   417 		}
   418 	  else if (data_ptr->len <= 0)
   419 		{
   420 		  if (src->live_tv == FALSE)
   421 			{
   422 			  result = GMYTH_FILE_READ_EOF;
   423 			  goto eos;
   424 			}
   425 		  else
   426 			{
   427 			  if (result == GMYTH_FILE_READ_ERROR)
   428 				{				/* -314 */
   429 				  GST_INFO_OBJECT(src, "[LiveTV] FileTransfer READ_ERROR!");
   430 				  goto done;
   431 				}
   432 			  else if (result == GMYTH_FILE_READ_NEXT_PROG_CHAIN)
   433 				{				/* -315 */
   434 				  GST_INFO_OBJECT(src,
   435 								  "[LiveTV] FileTransfer - Go to athe next program chain!");
   436 				  src->update_prog_chain = TRUE;
   437 				  continue;
   438 				}
   439 			  goto done;
   440 			}
   441 
   442 		}						/* else if (data_ptr->len == 0)
   443 								   goto done; */
   444 
   445 	  if (read == sizetoread)
   446 		goto done;
   447 	}
   448 
   449   if ((read < 0 && !src->live_tv) || max_iters == 0)
   450 	{
   451 	  result = GMYTH_FILE_READ_EOF;
   452 	  goto eos;
   453 	}
   454 
   455   goto done;
   456 
   457 eos:
   458   src->eos = TRUE;
   459 
   460 done:
   461   return result;
   462 }
   463 
   464 static GstFlowReturn
   465 gst_mythtv_src_create(GstPushSrc * psrc, GstBuffer ** outbuf)
   466 {
   467   GstMythtvSrc *src;
   468   GstFlowReturn ret = GST_FLOW_OK;
   469   guint buffer_size_inter = 0;
   470 
   471   src = GST_MYTHTV_SRC(psrc);
   472 
   473  /* The caller should know the number of bytes and not read beyond EOS. */
   474   if (G_UNLIKELY(src->eos))
   475 	goto eos;
   476   GST_DEBUG_OBJECT(src, "offset = %" G_GUINT64_FORMAT ", size = %d...",
   477 				   src->read_offset, MAX_READ_SIZE);
   478 
   479   GST_DEBUG_OBJECT(src, "Create: buffer_remain: %d, buffer_size = %d.",
   480 				   (gint) src->buffer_remain, src->bytes_queue->len);
   481 
   482 program_chain_changed:
   483  /* just get from the byte array, no network effort... */
   484   if ((src->buffer_remain = src->bytes_queue->len) < MAX_READ_SIZE)
   485 	{
   486 	  GByteArray *buffer;
   487 	  GMythFileReadResult result = GMYTH_FILE_READ_OK;
   488 
   489 	  buffer = NULL;
   490 	  buffer_size_inter = (INTERNAL_BUFFER_SIZE - src->buffer_remain);
   491 
   492 	  if (buffer_size_inter > REQUEST_MAX_SIZE)
   493 		buffer_size_inter = REQUEST_MAX_SIZE;
   494 
   495 	  buffer = g_byte_array_new();
   496 
   497 	  result = do_read_request_response(src, buffer_size_inter, buffer);
   498 
   499 	 /* got the next program info? */
   500 	  if (G_UNLIKELY(src->update_prog_chain)
   501 		  || (result == GMYTH_FILE_READ_NEXT_PROG_CHAIN))
   502 		{
   503 		  GST_DEBUG_OBJECT(src, "Update PROGRAM CHAIN!!! buffer_size = %d.",
   504 						   src->bytes_queue->len);
   505 		  gst_pad_push_event(GST_BASE_SRC_PAD(GST_BASE_SRC(psrc)),
   506 							 gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM,
   507 												  NULL));
   508 /*
   509       gst_pad_push_event (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
   510 		      gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
   511 */
   512 		  src->update_prog_chain = FALSE;
   513 		  src->eos = FALSE;
   514 
   515 		  if (result == GMYTH_FILE_READ_NEXT_PROG_CHAIN)
   516 			{
   517 			 /*
   518 			    if  (buffer != NULL) {
   519 			    g_byte_array_free (buffer, TRUE);
   520 			    buffer = NULL;
   521 			    }
   522 			    goto program_chain_changed; */
   523 			}
   524 		  else if (result == GMYTH_FILE_READ_OK)
   525 			{
   526 			 /* remove wasteful, NUV file header data */
   527 			 /* buffer = g_byte_array_remove_range( buffer, 0, 512 ); */
   528 			 /* TODO: need to send a new segment event to NUVDemux? */
   529 			 //gst_pad_push_event (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
   530 			 //      gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
   531 
   532 			 /* goto change_progchain; */
   533 			}
   534 
   535 		}						/* */
   536 
   537 	  if (G_UNLIKELY(buffer->len < 0))
   538 		{
   539 
   540 		  if (buffer != NULL)
   541 			{
   542 			  g_byte_array_free(buffer, TRUE);
   543 			  buffer = NULL;
   544 			}
   545 
   546 		  if (src->live_tv || (result == GMYTH_FILE_READ_NEXT_PROG_CHAIN))
   547 			goto change_progchain;
   548 		  else
   549 			goto read_error;
   550 		}
   551 	  else if (G_UNLIKELY(buffer->len == 0))
   552 		{
   553 
   554 		  if (buffer != NULL)
   555 			{
   556 			  g_byte_array_free(buffer, TRUE);
   557 			  buffer = NULL;
   558 			}
   559 
   560 		  if (!src->live_tv)
   561 			goto done;
   562 		  else
   563 			goto program_chain_changed;
   564 		}
   565 
   566 	  src->bytes_queue =
   567 		g_byte_array_append(src->bytes_queue, buffer->data, buffer->len);
   568 	  if (buffer->len > buffer_size_inter)
   569 		GST_WARNING_OBJECT(src,
   570 						   "INCREASED buffer size! Backend sent more than we ask him... (%d)",
   571 						   abs(buffer->len - buffer_size_inter));
   572 
   573 	  src->buffer_remain += buffer->len;
   574 
   575 	  if (buffer != NULL)
   576 		{
   577 		  g_byte_array_free(buffer, TRUE);
   578 		  buffer = NULL;
   579 		}
   580 
   581 	 /*
   582 	    GST_DEBUG_OBJECT (src,
   583 	    "BYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "
   584 	    "OFFSET = %llu, CONTENT SIZE = %llu.", read,
   585 	    src->bytes_read, src->read_offset, src->content_size);
   586 	  */
   587 	}
   588 
   589   guint buffer_size =
   590 	(src->buffer_remain < MAX_READ_SIZE) ? src->buffer_remain : MAX_READ_SIZE;
   591 
   592   *outbuf = gst_buffer_new();
   593 
   594  /*
   595     GST_DEBUG_OBJECT (src, "read from network? %s!, buffer_remain = %d",
   596     (buffer_size_inter ==
   597     0) ? "NO, got from buffer" : "YES, go see the backend's log file",
   598     src->buffer_remain);
   599   */
   600 
   601   GST_BUFFER_SIZE(*outbuf) = buffer_size;
   602   GST_BUFFER_MALLOCDATA(*outbuf) = g_malloc0(GST_BUFFER_SIZE(*outbuf));
   603   GST_BUFFER_DATA(*outbuf) = GST_BUFFER_MALLOCDATA(*outbuf);
   604   g_memmove(GST_BUFFER_DATA((*outbuf)), src->bytes_queue->data,
   605 			GST_BUFFER_SIZE(*outbuf));
   606   GST_BUFFER_OFFSET(*outbuf) = src->read_offset;
   607   GST_BUFFER_OFFSET_END(*outbuf) =
   608 	src->read_offset + GST_BUFFER_SIZE(*outbuf);
   609 
   610   src->buffer_remain -= GST_BUFFER_SIZE(*outbuf);
   611 
   612   src->read_offset += GST_BUFFER_SIZE(*outbuf);
   613   src->bytes_read += GST_BUFFER_SIZE(*outbuf);
   614  //GST_DEBUG_OBJECT (src, "Buffer output with size: %d",
   615  //    GST_BUFFER_SIZE (*outbuf));
   616 
   617  /* flushs the newly buffer got from byte array */
   618   src->bytes_queue =
   619 	g_byte_array_remove_range(src->bytes_queue, 0, buffer_size);
   620 
   621   if (G_UNLIKELY(src->eos) || (!src->live_tv
   622 							   && (src->bytes_read >= src->content_size)))
   623 	goto eos;
   624 
   625 done:
   626   {
   627 	const gchar *reason = gst_flow_get_name(ret);
   628 	return ret;
   629   }
   630 eos:
   631   {
   632 	const gchar *reason = gst_flow_get_name(ret);
   633 
   634 	GST_DEBUG_OBJECT(src, "pausing task, reason %s", reason);
   635 	return GST_FLOW_UNEXPECTED;
   636   }
   637  /* ERRORS */
   638 read_error:
   639   {
   640 	GST_ELEMENT_ERROR(src, RESOURCE, READ,
   641 					  (NULL), ("Could not read any bytes (%i, %s)", read,
   642 							   src->uri_name));
   643 	return GST_FLOW_ERROR;
   644   }
   645 change_progchain:
   646   {
   647 	GST_ELEMENT_ERROR(src, RESOURCE, READ,
   648 					  (NULL),
   649 					  ("Seek failed, go to the next program info... (%i, %s)",
   650 					   read, src->uri_name));
   651 
   652 /* TODO: need to send a new segment event to NUVDemux? */
   653 	gst_pad_push_event(GST_BASE_SRC_PAD(GST_BASE_SRC(psrc)),
   654 					   gst_event_new_new_segment(TRUE, 1.0, GST_FORMAT_TIME,
   655 												 0, -1, 0));
   656 
   657 	goto program_chain_changed;
   658   }
   659 
   660 }
   661 
   662 gint64
   663 gst_mythtv_src_get_position(GstMythtvSrc * src)
   664 {
   665 
   666   gint64 size_tmp = 0;
   667   guint max_tries = 2;
   668 
   669   if (src->live_tv == TRUE && (abs(src->content_size - src->bytes_read) <
   670 							   GMYTHTV_TRANSFER_MAX_BUFFER))
   671 	{
   672 
   673 	get_file_pos:
   674 	  g_usleep(10);
   675 	  size_tmp =
   676 		gmyth_recorder_get_file_position(src->spawn_livetv->recorder);
   677 	  if (size_tmp > (src->content_size + GMYTHTV_TRANSFER_MAX_BUFFER))
   678 		src->content_size = size_tmp;
   679 	  else if (size_tmp > 0 && --max_tries > 0)
   680 		goto get_file_pos;
   681 	  GST_LOG_OBJECT(src, "GET_POSITION: file_position = %lld", size_tmp);
   682 	 /* sets the last content size amount before it can be updated */
   683 	  src->prev_content_size = src->content_size;
   684 	}
   685 
   686   return src->content_size;
   687 
   688 }
   689 
   690 static gboolean
   691 gst_mythtv_src_do_seek(GstBaseSrc * base, GstSegment * segment)
   692 {
   693   GstMythtvSrc *src = GST_MYTHTV_SRC(base);
   694   gint64 new_offset = -1;
   695   gint64 actual_seek = segment->start;
   696   gboolean ret = TRUE;
   697 
   698   GST_LOG_OBJECT(src, "seek, segment: %" GST_SEGMENT_FORMAT, segment);
   699 
   700   if (segment->format == GST_FORMAT_TIME)
   701 	{
   702 	  goto done;
   703 	}
   704   GST_LOG_OBJECT(src,
   705 				 "Trying to seek at the value (actual_seek = %lld, read_offset = %lld)",
   706 				 actual_seek, src->read_offset);
   707  /* verify if it needs to seek */
   708   if (src->read_offset != actual_seek)
   709 	{
   710 
   711 	 /* if ( gmyth_backend_info_is_local_file(src->backend_info) ) */
   712 	  if (IS_GMYTH_FILE_LOCAL(src->file))
   713 		new_offset =
   714 		  gmyth_file_local_seek(GMYTH_FILE_LOCAL(src->file), segment->start,
   715 								G_SEEK_SET);
   716 	  else if (IS_GMYTH_FILE_TRANSFER(src->file))
   717 		new_offset =
   718 		  gmyth_file_transfer_seek(GMYTH_FILE_TRANSFER(src->file),
   719 								   segment->start, SEEK_SET);
   720 
   721 	  GST_LOG_OBJECT(src,
   722 					 "Segment offset start = %lld, SRC Offset = %lld, NEW actual backend SEEK Offset = %lld.",
   723 					 segment->start, src->read_offset, new_offset);
   724 	  if (G_UNLIKELY(new_offset < 0))
   725 		{
   726 		  ret = FALSE;
   727 		  if (!src->live_tv)
   728 			goto eos;
   729 		}
   730 
   731 	  src->read_offset = new_offset;
   732 
   733 	  if (ret == FALSE)
   734 		{
   735 		  GST_INFO_OBJECT(src, "Failed to set the SEEK on segment!");
   736 		}
   737 
   738 	}
   739 
   740 done:
   741   return ret;
   742 
   743 eos:
   744   {
   745 	GST_DEBUG_OBJECT(src, "EOS found on seeking!!!");
   746 	return FALSE;
   747   }
   748 
   749 }
   750 
   751 /* create a socket for connecting to remote server */
   752 static gboolean
   753 gst_mythtv_src_start(GstBaseSrc * bsrc)
   754 {
   755   GstMythtvSrc *src = GST_MYTHTV_SRC(bsrc);
   756 
   757   GString *chain_id_local = NULL;
   758   GMythURI *gmyth_uri = NULL;
   759   gboolean ret = TRUE;
   760   GstMessage *msg;
   761 
   762   if (src->unique_setup == FALSE)
   763 	{
   764 	  src->unique_setup = TRUE;
   765 	}
   766   else
   767 	{
   768 	  goto done;
   769 	}
   770 
   771   gmyth_uri = gmyth_uri_new_with_value(src->uri_name);
   772   src->backend_info = gmyth_backend_info_new_with_uri(src->uri_name);
   773   src->live_tv = gmyth_uri_is_livetv(gmyth_uri);
   774  /* testing UPnP... */
   775  /* gmyth_backend_info_set_hostname( src->backend_info, NULL ); */
   776   if (src->live_tv)
   777 	{
   778 	  src->spawn_livetv = gmyth_livetv_new(src->backend_info);
   779 
   780 	  gchar *ch = gmyth_uri_get_channel_name(gmyth_uri);
   781 	  if (ch != NULL)
   782 		src->channel_name = ch;
   783 
   784 	  if (src->channel_name != NULL)
   785 		{
   786 		  gboolean result;
   787 		  result =
   788 			gmyth_livetv_channel_name_setup(src->spawn_livetv,
   789 											src->channel_name);
   790 		  if (result == FALSE)
   791 			{
   792 			  GST_INFO_OBJECT(src, "LiveTV setup felt down on error");
   793 			  ret = FALSE;
   794 			  goto init_failed;
   795 			}
   796 
   797 		}
   798 	  else
   799 		{
   800 		  if (gmyth_livetv_setup(src->spawn_livetv) == FALSE)
   801 			{
   802 			  GST_INFO_OBJECT(src, "LiveTV setup felt down on error");
   803 			  ret = FALSE;
   804 			  goto init_failed;
   805 			}
   806 		}
   807 
   808 	 /* testing change channel... */
   809 	 /* gmyth_recorder_change_channel( src->spawn_livetv->recorder, CHANNEL_DIRECTION_UP ); */
   810 
   811 	  src->file =
   812 		GMYTH_FILE(gmyth_livetv_create_file_transfer(src->spawn_livetv));
   813 
   814 	  if (NULL == src->file)
   815 		{
   816 		  GST_INFO_OBJECT(src, "[LiveTV] FileTransfer equals to NULL");
   817 		  ret = FALSE;
   818 		  goto init_failed;
   819 		}
   820 
   821 	 /* Check if the file is local to this specific client renderer */
   822 	  if (gmyth_uri_is_local_file(gmyth_uri))
   823 		ret = gmyth_file_local_open(GMYTH_FILE_LOCAL(src->file));
   824 	  else
   825 		ret =
   826 		  gmyth_file_transfer_open(GMYTH_FILE_TRANSFER(src->file),
   827 								   src->spawn_livetv->uri !=
   828 								   NULL ? gmyth_uri_get_path(src->
   829 															 spawn_livetv->
   830 															 uri) : src->
   831 								   spawn_livetv->proginfo->pathname->str);
   832 
   833 	 /* sets the mythtvsrc "location" property */
   834 	  g_object_set(src, "location", gmyth_file_get_uri(src->file), NULL);
   835 
   836 	  if (!ret)
   837 		{
   838 		  GST_INFO_OBJECT(src,
   839 						  "Error: couldn't open the FileTransfer from LiveTV source!");
   840 		  g_object_unref(src->file);
   841 		  src->file = NULL;
   842 		  goto init_failed;
   843 		}
   844 	}
   845   else
   846 	{
   847 
   848 	 /* Check if the file is local to this specific client renderer, and tries to open
   849 	  * a local connection
   850 	  */
   851 	  if (gmyth_uri_is_local_file(gmyth_uri))
   852 		{
   853 		  src->file = GMYTH_FILE(gmyth_file_local_new(src->backend_info));
   854 		  ret = gmyth_file_local_open(GMYTH_FILE_LOCAL(src->file));
   855 		}
   856 	  else
   857 		{
   858 		  src->file = GMYTH_FILE(gmyth_file_transfer_new(src->backend_info));
   859 		  ret =
   860 			gmyth_file_transfer_open(GMYTH_FILE_TRANSFER(src->file),
   861 									 src->uri_name);
   862 		}
   863 
   864 	}							/* if (else) - recorded FileTransfer */
   865 
   866   if (NULL == src->file)
   867 	{
   868 	  GST_INFO_OBJECT(src, "FileTransfer is NULL");
   869 	  goto init_failed;
   870 	}
   871  /*GST_INFO_OBJECT( src, "uri = %s", src->spawn_livetv->file); */
   872 
   873   if (ret == FALSE)
   874 	{
   875 #ifndef GST_DISABLE_GST_DEBUG
   876 	  if (src->mythtv_msgs_dbg)
   877 		GST_INFO_OBJECT(src,
   878 						"MythTV FileTransfer request failed when setting up socket connection!");
   879 #endif
   880 	  goto begin_req_failed;
   881 	}
   882 
   883   GST_INFO_OBJECT(src,
   884 				  "MythTV FileTransfer filesize = %lld, content_size = %lld!",
   885 				  gmyth_file_get_filesize(src->file), src->content_size);
   886 
   887   src->content_size = gmyth_file_get_filesize(src->file);
   888 
   889   msg =
   890 	gst_message_new_duration(GST_OBJECT(src), GST_FORMAT_BYTES,
   891 							 src->content_size);
   892   gst_element_post_message(GST_ELEMENT(src), msg);
   893 
   894 
   895   src->do_start = FALSE;
   896 
   897  /* this is used for the buffer cache */
   898   src->bytes_queue = g_byte_array_sized_new(INTERNAL_BUFFER_SIZE);
   899   src->buffer_remain = 0;
   900 
   901   gst_pad_push_event(GST_BASE_SRC_PAD(GST_BASE_SRC(src)),
   902 					 gst_event_new_new_segment(TRUE, 1.0, GST_FORMAT_TIME, 0,
   903 											   src->content_size, 0));
   904 
   905 done:
   906   if (gmyth_uri != NULL)
   907 	{
   908 	  g_object_unref(gmyth_uri);
   909 	  gmyth_uri = NULL;
   910 	}
   911 
   912   if (chain_id_local != NULL)
   913 	{
   914 	  g_string_free(chain_id_local, TRUE);
   915 	  chain_id_local = NULL;
   916 	}
   917 
   918   return TRUE;
   919 
   920  /* ERRORS */
   921 init_failed:
   922   if (gmyth_uri != NULL)
   923 	{
   924 	  g_object_unref(gmyth_uri);
   925 	  gmyth_uri = NULL;
   926 	}
   927 
   928   if (src->spawn_livetv != NULL)
   929 	{
   930 	  g_object_unref(src->spawn_livetv);
   931 	  src->spawn_livetv = NULL;
   932 	}
   933 
   934   GST_ELEMENT_ERROR(src, LIBRARY, INIT,
   935 					(NULL), ("Could not initialize MythTV library (%i, %s)",
   936 							 ret, src->uri_name));
   937 
   938 
   939   gst_mythtv_src_clear(src);
   940 
   941   return FALSE;
   942 begin_req_failed:
   943   if (gmyth_uri != NULL)
   944 	{
   945 	  g_object_unref(gmyth_uri);
   946 	  gmyth_uri = NULL;
   947 	}
   948 
   949   GST_ELEMENT_ERROR(src, LIBRARY, INIT,
   950 					(NULL),
   951 					("Could not begin request sent to MythTV server (%i, %s)",
   952 					 ret, src->uri_name));
   953   return FALSE;
   954 
   955 }
   956 
   957 static gboolean
   958 gst_mythtv_src_get_size(GstBaseSrc * bsrc, guint64 * size)
   959 {
   960   GstMythtvSrc *src = GST_MYTHTV_SRC(bsrc);
   961   gboolean ret = TRUE;
   962 
   963   GST_LOG_OBJECT(src, "Differs from previous content size: %d (max.: %d)",
   964 				 abs(src->content_size - src->prev_content_size),
   965 				 GMYTHTV_TRANSFER_MAX_BUFFER);
   966 
   967   if (src->live_tv)
   968 	{
   969 	  ret = FALSE;
   970 	}
   971   else if (src->live_tv && src->enable_timing_position
   972 		   && (abs(src->content_size - src->bytes_read) <
   973 			   GMYTHTV_TRANSFER_MAX_BUFFER))
   974 	{
   975 
   976 	  gint64 new_offset =
   977 		gmyth_recorder_get_file_position(src->spawn_livetv->recorder);
   978 	  if (new_offset > 0 && new_offset > src->content_size)
   979 		{
   980 		  src->content_size = new_offset;
   981 		}
   982 	  else if (new_offset < src->content_size)
   983 		{
   984 		  src->update_prog_chain = TRUE;
   985 		}
   986 
   987 	}
   988 
   989   *size = src->content_size;
   990   GST_LOG_OBJECT(src, "Content size = %lld", src->content_size);
   991 
   992   return ret;
   993 
   994 }
   995 
   996 /* close the socket and associated resources
   997  * used both to recover from errors and go to NULL state */
   998 static gboolean
   999 gst_mythtv_src_stop(GstBaseSrc * bsrc)
  1000 {
  1001   GstMythtvSrc *src = GST_MYTHTV_SRC(bsrc);
  1002 
  1003   gst_mythtv_src_clear(src);
  1004 
  1005  /* src->eos = FALSE; */
  1006 
  1007   return TRUE;
  1008 }
  1009 
  1010 static gboolean
  1011 gst_mythtv_src_handle_event(GstPad * pad, GstEvent * event)
  1012 {
  1013   GstMythtvSrc *src = GST_MYTHTV_SRC(GST_PAD_PARENT(pad));
  1014   gint64 cont_size = 0;
  1015   gboolean ret = FALSE;
  1016 
  1017   switch (GST_EVENT_TYPE(event))
  1018 	{
  1019 	case GST_EVENT_EOS:
  1020 	  GST_WARNING_OBJECT(src, "Got EOS event");
  1021 
  1022 	  if (src->live_tv)
  1023 		{
  1024 		  cont_size = gst_mythtv_src_get_position(src);
  1025 		  if (cont_size > src->content_size)
  1026 			{
  1027 			  src->content_size = cont_size;
  1028 			  src->eos = FALSE;
  1029 			}
  1030 		  else
  1031 			{
  1032 			  src->eos = TRUE;
  1033 			  gst_element_set_state(GST_ELEMENT(src), GST_STATE_NULL);
  1034 			  gst_element_set_locked_state(GST_ELEMENT(src), FALSE);
  1035 			}
  1036 		}
  1037 	  break;
  1038 	default:
  1039 	  ret = gst_pad_event_default(pad, event);
  1040 	}
  1041 
  1042   return ret;
  1043 }
  1044 
  1045 static gboolean
  1046 gst_mythtv_src_is_seekable(GstBaseSrc * push_src)
  1047 {
  1048   return TRUE;
  1049 }
  1050 
  1051 static gboolean
  1052 gst_mythtv_src_handle_query(GstPad * pad, GstQuery * query)
  1053 {
  1054   gboolean res = FALSE;
  1055   GstMythtvSrc *myth = GST_MYTHTV_SRC(gst_pad_get_parent(pad));
  1056   GstFormat formt;
  1057 
  1058 
  1059   switch (GST_QUERY_TYPE(query))
  1060 	{
  1061 	case GST_QUERY_POSITION:
  1062 	  {
  1063 		gst_query_parse_position(query, &formt, NULL);
  1064 		if (formt == GST_FORMAT_BYTES)
  1065 		  {
  1066 			gst_query_set_position(query, formt, myth->read_offset);
  1067 			GST_DEBUG_OBJECT(myth, "POS %" G_GINT64_FORMAT,
  1068 							 myth->read_offset);
  1069 			res = TRUE;
  1070 		  }
  1071 		else if (formt == GST_FORMAT_TIME)
  1072 		  {
  1073 			res = gst_pad_query_default(pad, query);
  1074 		  }
  1075 		break;
  1076 	  }
  1077 	case GST_QUERY_DURATION:
  1078 	  {
  1079 		gst_query_parse_duration(query, &formt, NULL);
  1080 		if (formt == GST_FORMAT_BYTES)
  1081 		  {
  1082 			gint64 size = myth->content_size;
  1083 			gst_query_set_duration(query, GST_FORMAT_BYTES, 10);
  1084 			GST_DEBUG_OBJECT(myth, "SIZE %" G_GINT64_FORMAT, size);
  1085 			res = TRUE;
  1086 		  }
  1087 		else if (formt == GST_FORMAT_TIME)
  1088 		  {
  1089 			res = gst_pad_query_default(pad, query);
  1090 		  }
  1091 		break;
  1092 	  }
  1093 	default:
  1094 	  {
  1095 		res = gst_pad_query_default(pad, query);
  1096 		break;
  1097 	  }
  1098 	}
  1099 
  1100   gst_object_unref(myth);
  1101 
  1102   return res;
  1103 }
  1104 
  1105 static GstStateChangeReturn
  1106 gst_mythtv_src_change_state(GstElement * element, GstStateChange transition)
  1107 {
  1108   GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
  1109   GstMythtvSrc *src = GST_MYTHTV_SRC(element);
  1110 
  1111   switch (transition)
  1112 	{
  1113 	case GST_STATE_CHANGE_NULL_TO_READY:
  1114 	  break;
  1115 	case GST_STATE_CHANGE_READY_TO_PAUSED:
  1116 	case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
  1117 	  if (src->live_tv)
  1118 		{
  1119 		  if (!gmyth_recorder_send_frontend_ready_command(src->spawn_livetv->
  1120 														  recorder))
  1121 			GST_WARNING_OBJECT(src,
  1122 							   "Couldn't send the FRONTEND_READY message to the backend!");
  1123 		  else
  1124 			GST_DEBUG_OBJECT(src, "FRONTEND_READY was sent to the backend");
  1125 		}
  1126 	  break;
  1127 	default:
  1128 	  break;
  1129 	}
  1130 
  1131 
  1132   ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
  1133   if (ret == GST_STATE_CHANGE_FAILURE)
  1134 	return ret;
  1135 
  1136 
  1137   switch (transition)
  1138 	{
  1139 	case GST_STATE_CHANGE_READY_TO_NULL:
  1140 	  gst_mythtv_src_clear(src);
  1141 	  break;
  1142 	case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
  1143 	case GST_STATE_CHANGE_PAUSED_TO_READY:
  1144 	  break;
  1145 	default:
  1146 	  break;
  1147 	}
  1148 
  1149   return ret;
  1150 }
  1151 
  1152 static void
  1153 gst_mythtv_src_set_property(GObject * object, guint prop_id,
  1154 							const GValue * value, GParamSpec * pspec)
  1155 {
  1156   GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC(object);
  1157 
  1158   GST_OBJECT_LOCK(mythtvsrc);
  1159   switch (prop_id)
  1160 	{
  1161 	case PROP_LOCATION:
  1162 	  {
  1163 		if (!g_value_get_string(value))
  1164 		  {
  1165 			GST_WARNING("location property cannot be NULL");
  1166 			break;
  1167 		  }
  1168 
  1169 		if (mythtvsrc->uri_name != NULL)
  1170 		  {
  1171 			g_free(mythtvsrc->uri_name);
  1172 			mythtvsrc->uri_name = NULL;
  1173 		  }
  1174 		mythtvsrc->uri_name = g_value_dup_string(value);
  1175 
  1176 		break;
  1177 	  }
  1178 #ifndef GST_DISABLE_GST_DEBUG
  1179 	case PROP_GMYTHTV_DBG:
  1180 	  {
  1181 		mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean(value);
  1182 		break;
  1183 	  }
  1184 #endif
  1185 	case PROP_GMYTHTV_VERSION:
  1186 	  {
  1187 		mythtvsrc->mythtv_version = g_value_get_int(value);
  1188 		break;
  1189 	  }
  1190 	case PROP_GMYTHTV_LIVEID:
  1191 	  {
  1192 		mythtvsrc->live_tv_id = g_value_get_int(value);
  1193 		break;
  1194 	  }
  1195 	case PROP_GMYTHTV_LIVE:
  1196 	  {
  1197 		mythtvsrc->live_tv = g_value_get_boolean(value);
  1198 		break;
  1199 	  }
  1200 	case PROP_GMYTHTV_ENABLE_TIMING_POSITION:
  1201 	  {
  1202 		mythtvsrc->enable_timing_position = g_value_get_boolean(value);
  1203 		break;
  1204 	  }
  1205 	case PROP_GMYTHTV_LIVE_CHAINID:
  1206 	  {
  1207 		if (!g_value_get_string(value))
  1208 		  {
  1209 			GST_WARNING("MythTV Live chainid property cannot be NULL");
  1210 			break;
  1211 		  }
  1212 
  1213 		if (mythtvsrc->live_chain_id != NULL)
  1214 		  {
  1215 			g_free(mythtvsrc->live_chain_id);
  1216 			mythtvsrc->live_chain_id = NULL;
  1217 		  }
  1218 		mythtvsrc->live_chain_id = g_value_dup_string(value);
  1219 		break;
  1220 	  }
  1221 	case PROP_GMYTHTV_CHANNEL_NUM:
  1222 	  {
  1223 		mythtvsrc->channel_name = g_value_dup_string(value);
  1224 		break;
  1225 	  }
  1226 	case PROP_GMYTHTV_MAX_TRY:
  1227 	  {
  1228 		mythtvsrc->max_try = g_value_get_int(value);
  1229 		break;
  1230 	  }
  1231 	default:
  1232 	  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  1233 	  break;
  1234 	}
  1235 
  1236   GST_OBJECT_UNLOCK(mythtvsrc);
  1237 }
  1238 
  1239 static void
  1240 gst_mythtv_src_get_property(GObject * object, guint prop_id,
  1241 							GValue * value, GParamSpec * pspec)
  1242 {
  1243   GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC(object);
  1244 
  1245   GST_OBJECT_LOCK(mythtvsrc);
  1246   switch (prop_id)
  1247 	{
  1248 	case PROP_LOCATION:
  1249 	  {
  1250 		g_value_set_string(value, mythtvsrc->uri_name);
  1251 		break;
  1252 	  }
  1253 #ifndef GST_DISABLE_GST_DEBUG
  1254 	case PROP_GMYTHTV_DBG:
  1255 	  g_value_set_boolean(value, mythtvsrc->mythtv_msgs_dbg);
  1256 	  break;
  1257 #endif
  1258 	case PROP_GMYTHTV_VERSION:
  1259 	  {
  1260 		g_value_set_int(value, mythtvsrc->mythtv_version);
  1261 		break;
  1262 	  }
  1263 	case PROP_GMYTHTV_LIVEID:
  1264 	  {
  1265 		g_value_set_int(value, mythtvsrc->live_tv_id);
  1266 		break;
  1267 	  }
  1268 	case PROP_GMYTHTV_LIVE:
  1269 	  g_value_set_boolean(value, mythtvsrc->live_tv);
  1270 	  break;
  1271 	case PROP_GMYTHTV_ENABLE_TIMING_POSITION:
  1272 	  g_value_set_boolean(value, mythtvsrc->enable_timing_position);
  1273 	  break;
  1274 	case PROP_GMYTHTV_LIVE_CHAINID:
  1275 	  {
  1276 		g_value_set_string(value, mythtvsrc->live_chain_id);
  1277 		break;
  1278 	  }
  1279 	case PROP_GMYTHTV_CHANNEL_NUM:
  1280 	  {
  1281 		g_value_set_string(value, mythtvsrc->channel_name);
  1282 		break;
  1283 	  }
  1284 	case PROP_GMYTHTV_MAX_TRY:
  1285 	  {
  1286 		g_value_set_int(value, mythtvsrc->max_try);
  1287 		break;
  1288 	  }
  1289 
  1290 	default:
  1291 	  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  1292 	  break;
  1293 	}
  1294   GST_OBJECT_UNLOCK(mythtvsrc);
  1295 }
  1296 
  1297 static gboolean
  1298 plugin_init(GstPlugin * plugin)
  1299 {
  1300   return gst_element_register(plugin, "mythtvsrc", GST_RANK_NONE,
  1301 							  GST_TYPE_MYTHTV_SRC);
  1302 }
  1303 
  1304 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
  1305 				  GST_VERSION_MINOR,
  1306 				  "mythtv",
  1307 				  "lib MythTV src",
  1308 				  plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
  1309 				  GST_PACKAGE_ORIGIN);
  1310 
  1311 
  1312 /*** GSTURIHANDLER INTERFACE *************************************************/
  1313 static guint
  1314 gst_mythtv_src_uri_get_type(void)
  1315 {
  1316   return GST_URI_SRC;
  1317 }
  1318 
  1319 static gchar **
  1320 gst_mythtv_src_uri_get_protocols(void)
  1321 {
  1322   static gchar *protocols[] = { "myth", "myths", NULL };
  1323 
  1324   return protocols;
  1325 }
  1326 
  1327 static const gchar *
  1328 gst_mythtv_src_uri_get_uri(GstURIHandler * handler)
  1329 {
  1330   GstMythtvSrc *src = GST_MYTHTV_SRC(handler);
  1331 
  1332   return src->uri_name;
  1333 }
  1334 
  1335 static gboolean
  1336 gst_mythtv_src_uri_set_uri(GstURIHandler * handler, const gchar * uri)
  1337 {
  1338   GstMythtvSrc *src = GST_MYTHTV_SRC(handler);
  1339 
  1340   gchar *protocol;
  1341 
  1342   protocol = gst_uri_get_protocol(uri);
  1343   if ((strcmp(protocol, "myth") != 0) && (strcmp(protocol, "myths") != 0))
  1344 	{
  1345 	  g_free(protocol);
  1346 	  return FALSE;
  1347 	}
  1348   g_free(protocol);
  1349   g_object_set(src, "location", uri, NULL);
  1350 
  1351   return TRUE;
  1352 }
  1353 
  1354 static void
  1355 gst_mythtv_src_uri_handler_init(gpointer g_iface, gpointer iface_data)
  1356 {
  1357   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
  1358 
  1359   iface->get_type = gst_mythtv_src_uri_get_type;
  1360   iface->get_protocols = gst_mythtv_src_uri_get_protocols;
  1361   iface->get_uri = gst_mythtv_src_uri_get_uri;
  1362   iface->set_uri = gst_mythtv_src_uri_set_uri;
  1363 }
  1364 
  1365 void
  1366 size_header_handler(void *userdata, const char *value)
  1367 {
  1368   GstMythtvSrc *src = GST_MYTHTV_SRC(userdata);
  1369 
  1370   GST_DEBUG_OBJECT(src, "content size = %lld bytes", src->content_size);
  1371 }