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