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