1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/gst-gmyth/mythsrc/gstmythtvsrc.c Thu May 03 16:07:54 2007 +0100
1.3 @@ -0,0 +1,1259 @@
1.4 +/* GStreamer MythTV Plug-in
1.5 + * Copyright (C) <2006> Rosfran Borges <rosfran.borges@indt.org.br>
1.6 + *
1.7 + * This library is free software; you can redistribute it and/or
1.8 + * modify it under the terms of the GNU Library General Public
1.9 + * License as published by the Free Software Foundation; either
1.10 + * version 2 of the License, or (at your option) any later version.
1.11 + *
1.12 + * This library is distributed in the hope that it will be useful,
1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.15 + * Library General Public License for more details.
1.16 + *
1.17 + * You should have received a copy of the GNU Library General Public
1.18 + * License along with this library; if not, write to the
1.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1.20 + * Boston, MA 02111-1307, USA.
1.21 + */
1.22 +/**
1.23 + * SECTION:element-mythtvsrc
1.24 + *
1.25 + * <refsect2>
1.26 + * <para>
1.27 + * MythTVSrc allows to access a remote MythTV backend streaming Video/Audio server,
1.28 + * and to render audio and video content through a TCP/IP connection to a specific
1.29 + * port on this server, and based on a known MythTV protocol that is based on
1.30 + * some message passing, such as REQUEST_BLOCK on a specified number of bytes, to get
1.31 + * some chunk of remote file data.
1.32 + * You should pass the information aboute the remote MythTV backend server
1.33 + * through the <link linkend="GstMythTVSrc--location">location</link> property.
1.34 + * </para>
1.35 + * <title>Examples</title>
1.36 + * <para>
1.37 + * If you want to get the LiveTV content (set channel, TV tuner, RemoteEncoder,
1.38 + * Recorder),
1.39 + * put the following URI:
1.40 + *
1.41 + * <programlisting>
1.42 + * myth://xxx.xxx.xxx.xxx:6543/livetv?channel=BBC
1.43 + * </programlisting>
1.44 + *
1.45 + * This URI will say to the gmyth library to configure the Recorder instance (used to
1.46 + * change the channel, start the TV multimedia content transmition, etc.), using
1.47 + * the IP address (xxx.xxx.xxx.xxx) and port number (6543) of the MythTV backend
1.48 + * server, and setting the channel name to "BBC".
1.49 + *
1.50 + * To get a already recorded the MythTV NUV file, put the following URI:
1.51 + *
1.52 + * <programlisting>
1.53 + * myth://xxx.xxx.xxx.xxx:6543/filename.nuv
1.54 + * </programlisting>
1.55 + *
1.56 + * This URI will say to the gmyth library to configure the Recorder instance (used to
1.57 + * change the channel, start the TV multimedia content transmition, etc.), using
1.58 + * the IP address (xxx.xxx.xxx.xxx) and port number (6543) of the MythTV backend
1.59 + * server, and setting the channel name to "BBC".
1.60 + *
1.61 + * Another possible way to use the LiveTV content, and just in the case you want to
1.62 + * use the mysql database, put the location URI in the following format:
1.63 + *
1.64 + * <programlisting>
1.65 + * myth://mythtv:mythtv@xxx.xxx.xxx.xxx:6543/?mythconverg&channel=9
1.66 + * </programlisting>
1.67 + *
1.68 + * Where the first field is the protocol (myth), the second and third are user
1.69 + * name (mythtv) and password (mythtv), then backend host name and port number,
1.70 + * and the last field is the database name (mythconverg).
1.71 + * </para>
1.72 + * </refsect2>
1.73 + */
1.74 +#ifdef HAVE_CONFIG_H
1.75 +#include "config.h"
1.76 +#endif
1.77 +
1.78 +#include "gstmythtvsrc.h"
1.79 +#include <gmyth/gmyth_file.h>
1.80 +#include <gmyth/gmyth_file_transfer.h>
1.81 +#include <gmyth/gmyth_file_local.h>
1.82 +#include <gmyth/gmyth_livetv.h>
1.83 +
1.84 +#include <gmyth/gmyth_socket.h>
1.85 +#include <gmyth/gmyth_tvchain.h>
1.86 +
1.87 +#include <string.h>
1.88 +#include <unistd.h>
1.89 +
1.90 +GST_DEBUG_CATEGORY_STATIC (mythtvsrc_debug);
1.91 +#define GST_CAT_DEFAULT mythtvsrc_debug
1.92 +
1.93 +#define GST_GMYTHTV_ID_NUM 1
1.94 +
1.95 +#define GST_GMYTHTV_CHANNEL_DEFAULT_NUM (-1)
1.96 +
1.97 +#define GMYTHTV_VERSION_DEFAULT 30
1.98 +
1.99 +#define GMYTHTV_TRANSFER_MAX_WAITS 100
1.100 +
1.101 +#define GMYTHTV_TRANSFER_MAX_RESENDS 2
1.102 +
1.103 +#define GMYTHTV_TRANSFER_MAX_BUFFER (128*1024)
1.104 +
1.105 +#define MAX_READ_SIZE (4*1024)
1.106 +
1.107 +#define GST_FLOW_ERROR_NO_DATA (-101)
1.108 +
1.109 +#define REQUEST_MAX_SIZE (64*1024)
1.110 +
1.111 +#define INTERNAL_BUFFER_SIZE (90*1024)
1.112 +
1.113 +static const GstElementDetails gst_mythtv_src_details =
1.114 +GST_ELEMENT_DETAILS ("MythTV client source",
1.115 + "Source/Network",
1.116 + "Control and receive data as a client over the network "
1.117 + "via raw socket connections using the MythTV protocol",
1.118 + "Rosfran Borges <rosfran.borges@indt.org.br>");
1.119 +
1.120 +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
1.121 + GST_PAD_SRC,
1.122 + GST_PAD_ALWAYS,
1.123 + GST_STATIC_CAPS ("video/x-nuv"));
1.124 +
1.125 +enum
1.126 +{
1.127 + PROP_0,
1.128 + PROP_LOCATION,
1.129 +#ifndef GST_DISABLE_GST_DEBUG
1.130 + PROP_GMYTHTV_DBG,
1.131 +#endif
1.132 + PROP_GMYTHTV_VERSION,
1.133 + PROP_GMYTHTV_LIVE,
1.134 + PROP_GMYTHTV_LIVEID,
1.135 + PROP_GMYTHTV_LIVE_CHAINID,
1.136 + PROP_GMYTHTV_ENABLE_TIMING_POSITION,
1.137 + PROP_GMYTHTV_CHANNEL_NUM,
1.138 + PROP_GMYTHTV_MAX_TRY
1.139 +};
1.140 +
1.141 +static void gst_mythtv_src_clear (GstMythtvSrc *mythtv_src);
1.142 +
1.143 +static void gst_mythtv_src_finalize (GObject * gobject);
1.144 +
1.145 +static GstFlowReturn gst_mythtv_src_create (GstPushSrc * psrc,
1.146 + GstBuffer ** outbuf);
1.147 +
1.148 +static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc);
1.149 +static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc);
1.150 +static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size);
1.151 +static gboolean gst_mythtv_src_is_seekable (GstBaseSrc * push_src);
1.152 +
1.153 +static gboolean gst_mythtv_src_do_seek (GstBaseSrc * base,
1.154 + GstSegment * segment);
1.155 +
1.156 +static GstStateChangeReturn
1.157 +gst_mythtv_src_change_state (GstElement * element, GstStateChange transition);
1.158 +
1.159 +static void gst_mythtv_src_set_property (GObject * object, guint prop_id,
1.160 + const GValue * value, GParamSpec * pspec);
1.161 +static void gst_mythtv_src_get_property (GObject * object, guint prop_id,
1.162 + GValue * value, GParamSpec * pspec);
1.163 +
1.164 +static void gst_mythtv_src_uri_handler_init (gpointer g_iface,
1.165 + gpointer iface_data);
1.166 +
1.167 +static gboolean gst_mythtv_src_handle_query (GstPad * pad, GstQuery * query);
1.168 +
1.169 +static gboolean gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event);
1.170 +
1.171 +static GMythFileReadResult do_read_request_response (GstMythtvSrc * src, guint size,
1.172 + GByteArray * data_ptr);
1.173 +
1.174 +static void
1.175 +_urihandler_init (GType type)
1.176 +{
1.177 + static const GInterfaceInfo urihandler_info = {
1.178 + gst_mythtv_src_uri_handler_init,
1.179 + NULL,
1.180 + NULL
1.181 + };
1.182 +
1.183 + g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
1.184 +
1.185 + GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, "MythTV src");
1.186 +}
1.187 +
1.188 +GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstPushSrc,
1.189 + GST_TYPE_PUSH_SRC, _urihandler_init)
1.190 +
1.191 + static void gst_mythtv_src_base_init (gpointer g_class)
1.192 +{
1.193 + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1.194 +
1.195 + gst_element_class_add_pad_template (element_class,
1.196 + gst_static_pad_template_get (&srctemplate));
1.197 +
1.198 + gst_element_class_set_details (element_class, &gst_mythtv_src_details);
1.199 +
1.200 + element_class->change_state = gst_mythtv_src_change_state;
1.201 +
1.202 +}
1.203 +
1.204 +static void
1.205 +gst_mythtv_src_class_init (GstMythtvSrcClass * klass)
1.206 +{
1.207 + GObjectClass *gobject_class;
1.208 + GstPushSrcClass *gstpushsrc_class;
1.209 + GstBaseSrcClass *gstbasesrc_class;
1.210 +
1.211 + gobject_class = (GObjectClass *) klass;
1.212 + gstbasesrc_class = (GstBaseSrcClass *) klass;
1.213 + gstpushsrc_class = (GstPushSrcClass *) klass;
1.214 +
1.215 + gobject_class->set_property = gst_mythtv_src_set_property;
1.216 + gobject_class->get_property = gst_mythtv_src_get_property;
1.217 + gobject_class->finalize = gst_mythtv_src_finalize;
1.218 +
1.219 + g_object_class_install_property
1.220 + (gobject_class, PROP_LOCATION,
1.221 + g_param_spec_string ("location", "Location",
1.222 + "The location. In the form:"
1.223 + "\n\t\t\tmyth://a.com/file.nuv"
1.224 + "\n\t\t\tmyth://a.com:23223/file.nuv "
1.225 + "\n\t\t\ta.com/file.nuv - default scheme 'myth'",
1.226 + "", G_PARAM_READWRITE));
1.227 +
1.228 + g_object_class_install_property
1.229 + (gobject_class, PROP_GMYTHTV_VERSION,
1.230 + g_param_spec_int ("mythtv-version", "mythtv-version",
1.231 + "Change MythTV version", 26, 30, 26, G_PARAM_READWRITE));
1.232 +
1.233 + g_object_class_install_property
1.234 + (gobject_class, PROP_GMYTHTV_LIVEID,
1.235 + g_param_spec_int ("mythtv-live-id", "mythtv-live-id",
1.236 + "Change MythTV version",
1.237 + 0, 200, GST_GMYTHTV_ID_NUM, G_PARAM_READWRITE));
1.238 +
1.239 + g_object_class_install_property
1.240 + (gobject_class, PROP_GMYTHTV_LIVE_CHAINID,
1.241 + g_param_spec_string ("mythtv-live-chainid", "mythtv-live-chainid",
1.242 + "Sets the MythTV chain ID (from TV Chain)", "", G_PARAM_READWRITE));
1.243 +
1.244 + g_object_class_install_property
1.245 + (gobject_class, PROP_GMYTHTV_LIVE,
1.246 + g_param_spec_boolean ("mythtv-live", "mythtv-live",
1.247 + "Enable MythTV Live TV content streaming", FALSE, G_PARAM_READWRITE));
1.248 +
1.249 + g_object_class_install_property
1.250 + (gobject_class, PROP_GMYTHTV_ENABLE_TIMING_POSITION,
1.251 + g_param_spec_boolean ("mythtv-enable-timing-position",
1.252 + "mythtv-enable-timing-position",
1.253 + "Enable MythTV Live TV content size continuous updating", FALSE,
1.254 + G_PARAM_READWRITE));
1.255 +
1.256 + g_object_class_install_property
1.257 + (gobject_class, PROP_GMYTHTV_CHANNEL_NUM,
1.258 + g_param_spec_string ("mythtv-channel", "mythtv-channel",
1.259 + "Change MythTV channel number",
1.260 + "", G_PARAM_READWRITE));
1.261 +
1.262 + g_object_class_install_property
1.263 + (gobject_class, PROP_GMYTHTV_MAX_TRY,
1.264 + g_param_spec_int ("max-try", "max-try",
1.265 + "Set the max try for get MythTV free recorder",
1.266 + 0, G_MAXINT, 10, G_PARAM_READWRITE));
1.267 +
1.268 +
1.269 +#ifndef GST_DISABLE_GST_DEBUG
1.270 + g_object_class_install_property
1.271 + (gobject_class, PROP_GMYTHTV_DBG,
1.272 + g_param_spec_boolean ("mythtv-debug", "mythtv-debug",
1.273 + "Enable MythTV debug messages", FALSE, G_PARAM_READWRITE));
1.274 +#endif
1.275 +
1.276 + gstbasesrc_class->start = gst_mythtv_src_start;
1.277 + gstbasesrc_class->stop = gst_mythtv_src_stop;
1.278 + gstbasesrc_class->get_size = gst_mythtv_src_get_size;
1.279 + gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable;
1.280 +
1.281 + gstbasesrc_class->do_seek = gst_mythtv_src_do_seek;
1.282 + gstpushsrc_class->create = gst_mythtv_src_create;
1.283 +
1.284 + GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
1.285 + "MythTV Client Source");
1.286 +}
1.287 +
1.288 +static void
1.289 +gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class)
1.290 +{
1.291 + this->file = NULL;
1.292 +
1.293 + this->unique_setup = FALSE;
1.294 +
1.295 + this->mythtv_version = GMYTHTV_VERSION_DEFAULT;
1.296 +
1.297 + this->state = GST_MYTHTV_SRC_FILE_TRANSFER;
1.298 +
1.299 + this->bytes_read = 0;
1.300 +
1.301 + this->prev_content_size = 0;
1.302 +
1.303 + this->content_size = 0;
1.304 + this->read_offset = 0;
1.305 +
1.306 + this->content_size_last = 0;
1.307 +
1.308 + this->live_tv = FALSE;
1.309 +
1.310 + this->enable_timing_position = FALSE;
1.311 + this->update_prog_chain = FALSE;
1.312 +
1.313 + this->user_agent = g_strdup ("mythtvsrc");
1.314 + this->update_prog_chain = FALSE;
1.315 +
1.316 + this->channel_name = NULL;
1.317 +
1.318 + this->eos = FALSE;
1.319 +
1.320 + this->bytes_queue = NULL;
1.321 +
1.322 + this->wait_to_transfer = 0;
1.323 + this->try_number = 0;
1.324 + this->max_try = 10;
1.325 +
1.326 + gst_base_src_set_format (GST_BASE_SRC (this), GST_FORMAT_BYTES);
1.327 +
1.328 + gst_pad_set_event_function (GST_BASE_SRC_PAD (GST_BASE_SRC (this)),
1.329 + gst_mythtv_src_handle_event);
1.330 + gst_pad_set_query_function (GST_BASE_SRC_PAD (GST_BASE_SRC (this)),
1.331 + gst_mythtv_src_handle_query);
1.332 +
1.333 +}
1.334 +
1.335 +static void
1.336 +gst_mythtv_src_clear (GstMythtvSrc *mythtv_src)
1.337 +{
1.338 + mythtv_src->unique_setup = FALSE;
1.339 + mythtv_src->try_number = 0;
1.340 +
1.341 + if (mythtv_src->spawn_livetv) {
1.342 + g_object_unref (mythtv_src->spawn_livetv);
1.343 + mythtv_src->spawn_livetv = NULL;
1.344 + }
1.345 +
1.346 + if (mythtv_src->file) {
1.347 + g_object_unref (mythtv_src->file);
1.348 + mythtv_src->file = NULL;
1.349 + }
1.350 +
1.351 + if (mythtv_src->backend_info) {
1.352 + g_object_unref (mythtv_src->backend_info);
1.353 + mythtv_src->backend_info = NULL;
1.354 + }
1.355 +
1.356 + if (mythtv_src->bytes_queue) {
1.357 + g_byte_array_free (mythtv_src->bytes_queue, TRUE);
1.358 + mythtv_src->bytes_queue = NULL;
1.359 + }
1.360 +
1.361 +}
1.362 +
1.363 +static void
1.364 +gst_mythtv_src_finalize (GObject * gobject)
1.365 +{
1.366 + GstMythtvSrc *this = GST_MYTHTV_SRC (gobject);
1.367 +
1.368 + gst_mythtv_src_clear (this);
1.369 +
1.370 + if (this->uri_name) {
1.371 + g_free (this->uri_name);
1.372 + this->uri_name = NULL;
1.373 + }
1.374 +
1.375 + if (this->user_agent) {
1.376 + g_free (this->user_agent);
1.377 + this->user_agent = NULL;
1.378 + }
1.379 +
1.380 + G_OBJECT_CLASS (parent_class)->finalize (gobject);
1.381 +}
1.382 +
1.383 +static GMythFileReadResult
1.384 +do_read_request_response (GstMythtvSrc * src, guint size, GByteArray *data_ptr)
1.385 +{
1.386 + gint read = 0;
1.387 + guint sizetoread = size;
1.388 + gint max_iters = GMYTHTV_TRANSFER_MAX_RESENDS;
1.389 + GMythFileReadResult result;
1.390 +
1.391 + GST_LOG_OBJECT (src, "Starting: Reading %d bytes...", sizetoread);
1.392 +
1.393 + /* Loop sending the Myth File Transfer request:
1.394 + * Retry whilst authentication fails and we supply it. */
1.395 +
1.396 + while (sizetoread == size && --max_iters > 0) {
1.397 + /* if ( gmyth_backend_info_is_local_file(src->backend_info) ) */
1.398 + if ( IS_GMYTH_FILE_LOCAL(src->file) )
1.399 + result = gmyth_file_local_read ( GMYTH_FILE_LOCAL(src->file),
1.400 + data_ptr, sizetoread, src->live_tv);
1.401 + else if ( IS_GMYTH_FILE_TRANSFER(src->file) )
1.402 + result = gmyth_file_transfer_read ( GMYTH_FILE_TRANSFER(src->file),
1.403 + data_ptr, sizetoread, src->live_tv);
1.404 +
1.405 + if (data_ptr->len > 0) {
1.406 + read += data_ptr->len;
1.407 + sizetoread -= data_ptr->len;
1.408 + } else if (data_ptr->len < 0) {
1.409 + if (src->live_tv == FALSE) {
1.410 + result = GMYTH_FILE_READ_EOF;
1.411 + goto eos;
1.412 + } else {
1.413 + if (result == GMYTH_FILE_READ_ERROR) { /* -314 */
1.414 + GST_INFO_OBJECT (src, "[LiveTV] FileTransfer READ_ERROR!");
1.415 + goto done;
1.416 + } else if (result == GMYTH_FILE_READ_NEXT_PROG_CHAIN) { /* -315 */
1.417 + GST_INFO_OBJECT (src,
1.418 + "[LiveTV] FileTransfer - Go to the next program chain!");
1.419 + continue;
1.420 + }
1.421 + goto done;
1.422 + }
1.423 +
1.424 + } else if (data_ptr->len == 0)
1.425 + goto done;
1.426 +
1.427 + if (read == sizetoread)
1.428 + goto done;
1.429 + }
1.430 +
1.431 + if ((read < 0 && !src->live_tv) || max_iters == 0){
1.432 + result = GMYTH_FILE_READ_EOF;
1.433 + goto eos;
1.434 + }
1.435 +
1.436 + goto done;
1.437 +
1.438 +eos:
1.439 + src->eos = TRUE;
1.440 +
1.441 +done:
1.442 + return result;
1.443 +}
1.444 +
1.445 +static GstFlowReturn
1.446 +gst_mythtv_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
1.447 +{
1.448 + GstMythtvSrc *src;
1.449 + GstFlowReturn ret = GST_FLOW_OK;
1.450 + guint buffer_size_inter = 0;
1.451 +
1.452 + src = GST_MYTHTV_SRC (psrc);
1.453 +
1.454 + /* The caller should know the number of bytes and not read beyond EOS. */
1.455 + if (G_UNLIKELY (src->eos))
1.456 + goto eos;
1.457 + if (G_UNLIKELY (src->update_prog_chain))
1.458 + goto change_progchain;
1.459 +
1.460 + GST_DEBUG_OBJECT (src, "offset = %" G_GUINT64_FORMAT ", size = %d...",
1.461 + src->read_offset, MAX_READ_SIZE);
1.462 +
1.463 + GST_DEBUG_OBJECT (src, "Create: buffer_remain: %d, buffer_size = %d.",
1.464 + (gint) src->buffer_remain, src->bytes_queue->len);
1.465 +
1.466 +program_chain_changed:
1.467 + /* just get from the byte array, no network effort... */
1.468 + if ((src->buffer_remain = src->bytes_queue->len) < MAX_READ_SIZE) {
1.469 + GByteArray *buffer;
1.470 + GMythFileReadResult result = GMYTH_FILE_READ_OK;
1.471 +
1.472 + buffer = NULL;
1.473 + buffer_size_inter = (INTERNAL_BUFFER_SIZE - src->buffer_remain);
1.474 +
1.475 + if (buffer_size_inter > REQUEST_MAX_SIZE)
1.476 + buffer_size_inter = REQUEST_MAX_SIZE;
1.477 +
1.478 + buffer = g_byte_array_new ();
1.479 +
1.480 + result = do_read_request_response (src, buffer_size_inter, buffer);
1.481 +
1.482 + if (G_UNLIKELY (buffer->len < 0)) {
1.483 +
1.484 + if (buffer != NULL) {
1.485 + g_byte_array_free (buffer, TRUE);
1.486 + buffer = NULL;
1.487 + }
1.488 +
1.489 + if (src->live_tv || ( result == GMYTH_FILE_READ_NEXT_PROG_CHAIN ))
1.490 + goto change_progchain;
1.491 + else
1.492 + goto read_error;
1.493 + } else if (G_UNLIKELY (read == 0)) {
1.494 +
1.495 + if (buffer != NULL) {
1.496 + g_byte_array_free (buffer, TRUE);
1.497 + buffer = NULL;
1.498 + }
1.499 +
1.500 + if (!src->live_tv)
1.501 + goto done;
1.502 + else
1.503 + goto program_chain_changed;
1.504 + }
1.505 +
1.506 + if (G_UNLIKELY (src->update_prog_chain))
1.507 + {
1.508 + if (buffer != NULL) {
1.509 + g_byte_array_free (buffer, TRUE);
1.510 + buffer = NULL;
1.511 + }
1.512 + goto change_progchain;
1.513 + }
1.514 +
1.515 + src->bytes_queue =
1.516 + g_byte_array_append (src->bytes_queue, buffer->data, buffer->len);
1.517 + if (buffer->len > buffer_size_inter)
1.518 + GST_WARNING_OBJECT (src,
1.519 + "INCREASED buffer size! Backend sent more than we ask him... (%d)",
1.520 + abs (buffer->len - buffer_size_inter));
1.521 +
1.522 + src->buffer_remain += buffer->len;
1.523 +
1.524 + if (buffer != NULL) {
1.525 + g_byte_array_free (buffer, TRUE);
1.526 + buffer = NULL;
1.527 + }
1.528 +
1.529 + GST_DEBUG_OBJECT (src,
1.530 + "BYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "
1.531 + "OFFSET = %llu, CONTENT SIZE = %llu.", read,
1.532 + src->bytes_read, src->read_offset, src->content_size);
1.533 +
1.534 + }
1.535 +
1.536 + guint buffer_size =
1.537 + (src->buffer_remain < MAX_READ_SIZE) ? src->buffer_remain : MAX_READ_SIZE;
1.538 +
1.539 + *outbuf = gst_buffer_new ();
1.540 +
1.541 + /* gets the first buffer_size bytes from the byte array buffer variable */
1.542 + /* guint8 *buf = g_memdup( src->bytes_queue->data, buffer_size ); */
1.543 +
1.544 + GST_DEBUG_OBJECT (src, "read from network? %s!, buffer_remain = %d",
1.545 + (buffer_size_inter ==
1.546 + 0) ? "NO, got from buffer" : "YES, go see the backend's log file",
1.547 + src->buffer_remain);
1.548 +
1.549 + GST_BUFFER_SIZE (*outbuf) = buffer_size;
1.550 + GST_BUFFER_MALLOCDATA (*outbuf) = g_malloc0 (GST_BUFFER_SIZE (*outbuf));
1.551 + GST_BUFFER_DATA (*outbuf) = GST_BUFFER_MALLOCDATA (*outbuf);
1.552 + g_memmove (GST_BUFFER_DATA ((*outbuf)), src->bytes_queue->data,
1.553 + GST_BUFFER_SIZE (*outbuf));
1.554 + GST_BUFFER_OFFSET (*outbuf) = src->read_offset;
1.555 + GST_BUFFER_OFFSET_END (*outbuf) =
1.556 + src->read_offset + GST_BUFFER_SIZE (*outbuf);
1.557 +
1.558 + src->buffer_remain -= GST_BUFFER_SIZE (*outbuf);
1.559 +
1.560 + src->read_offset += GST_BUFFER_SIZE (*outbuf);
1.561 + src->bytes_read += GST_BUFFER_SIZE (*outbuf);
1.562 + GST_DEBUG_OBJECT (src, "Buffer output with size: %d",
1.563 + GST_BUFFER_SIZE (*outbuf));
1.564 +
1.565 + /* flushs the newly buffer got from byte array */
1.566 + src->bytes_queue =
1.567 + g_byte_array_remove_range (src->bytes_queue, 0, buffer_size);
1.568 +
1.569 + GST_DEBUG_OBJECT ( src, "Got buffer: BUFFER --->SIZE = %d, OFFSET = %llu, "
1.570 + "OFFSET_END = %llu.", GST_BUFFER_SIZE (*outbuf),
1.571 + GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf) );
1.572 +
1.573 + GST_DEBUG_OBJECT (src, "CONTENT_SIZE = %llu, BYTES_READ = %llu.",
1.574 + src->content_size, src->bytes_read);
1.575 +
1.576 + if ( G_UNLIKELY (src->eos) || ( !src->live_tv
1.577 + && ( src->bytes_read >= src->content_size ) ) )
1.578 + goto eos;
1.579 +
1.580 +done:
1.581 + {
1.582 + const gchar *reason = gst_flow_get_name (ret);
1.583 +
1.584 + GST_DEBUG_OBJECT (src, "DONE task, reason %s", reason);
1.585 + return ret;
1.586 + }
1.587 +eos:
1.588 + {
1.589 + const gchar *reason = gst_flow_get_name (ret);
1.590 +
1.591 + GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
1.592 + return GST_FLOW_UNEXPECTED;
1.593 + }
1.594 + /* ERRORS */
1.595 +read_error:
1.596 + {
1.597 + GST_ELEMENT_ERROR (src, RESOURCE, READ,
1.598 + (NULL), ("Could not read any bytes (%i, %s)", read, src->uri_name));
1.599 + return GST_FLOW_ERROR;
1.600 + }
1.601 +change_progchain:
1.602 + {
1.603 + GST_ELEMENT_ERROR (src, RESOURCE, READ,
1.604 + (NULL), ("Seek failed, go to the next program info... (%i, %s)", read,
1.605 + src->uri_name));
1.606 +
1.607 +/*
1.608 + TODO: need to send a new segment event to NUVDemux?
1.609 + gst_pad_push_event (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
1.610 + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
1.611 +*/
1.612 +
1.613 + goto program_chain_changed;
1.614 + }
1.615 +
1.616 +}
1.617 +
1.618 +gint64
1.619 +gst_mythtv_src_get_position (GstMythtvSrc * src)
1.620 +{
1.621 +
1.622 + gint64 size_tmp = 0;
1.623 + guint max_tries = 2;
1.624 +
1.625 + if (src->live_tv == TRUE && (abs (src->content_size - src->bytes_read) <
1.626 + GMYTHTV_TRANSFER_MAX_BUFFER)) {
1.627 +
1.628 + get_file_pos:
1.629 + g_usleep (10);
1.630 + size_tmp = gmyth_recorder_get_file_position (src->spawn_livetv->recorder);
1.631 + if (size_tmp > (src->content_size + GMYTHTV_TRANSFER_MAX_BUFFER))
1.632 + src->content_size = size_tmp;
1.633 + else if (size_tmp > 0 && --max_tries > 0)
1.634 + goto get_file_pos;
1.635 + GST_LOG_OBJECT (src, "GET_POSITION: file_position = %lld", size_tmp);
1.636 + /* sets the last content size amount before it can be updated */
1.637 + src->prev_content_size = src->content_size;
1.638 + }
1.639 +
1.640 + return src->content_size;
1.641 +
1.642 +}
1.643 +
1.644 +static gboolean
1.645 +gst_mythtv_src_do_seek (GstBaseSrc * base, GstSegment * segment)
1.646 +{
1.647 + GstMythtvSrc *src = GST_MYTHTV_SRC (base);
1.648 + gint64 new_offset = -1;
1.649 + gint64 actual_seek = segment->start;
1.650 + gboolean ret = TRUE;
1.651 +
1.652 + GST_LOG_OBJECT (src, "seek, segment: %" GST_SEGMENT_FORMAT, segment);
1.653 +
1.654 + if (segment->format == GST_FORMAT_TIME) {
1.655 + goto done;
1.656 + }
1.657 + GST_LOG_OBJECT (src,
1.658 + "Trying to seek at the value (actual_seek = %lld, read_offset = %lld)",
1.659 + actual_seek, src->read_offset);
1.660 + /* verify if it needs to seek */
1.661 + if (src->read_offset != actual_seek) {
1.662 +
1.663 + /* if ( gmyth_backend_info_is_local_file(src->backend_info) ) */
1.664 + if ( IS_GMYTH_FILE_LOCAL(src->file) )
1.665 + new_offset =
1.666 + gmyth_file_local_seek ( GMYTH_FILE_LOCAL(src->file), segment->start, G_SEEK_SET);
1.667 + else if ( IS_GMYTH_FILE_TRANSFER(src->file) )
1.668 + new_offset =
1.669 + gmyth_file_transfer_seek ( GMYTH_FILE_TRANSFER(src->file), segment->start, SEEK_SET);
1.670 +
1.671 + GST_LOG_OBJECT (src,
1.672 + "Segment offset start = %lld, SRC Offset = %lld, NEW actual backend SEEK Offset = %lld.",
1.673 + segment->start, src->read_offset, new_offset);
1.674 + if (G_UNLIKELY (new_offset < 0)) {
1.675 + ret = FALSE;
1.676 + if (!src->live_tv)
1.677 + goto eos;
1.678 + }
1.679 +
1.680 + src->read_offset = new_offset;
1.681 +
1.682 + if (ret == FALSE) {
1.683 + GST_INFO_OBJECT (src, "Failed to set the SEEK on segment!");
1.684 + }
1.685 +
1.686 + }
1.687 +
1.688 +done:
1.689 + return ret;
1.690 +
1.691 +eos:
1.692 + {
1.693 + GST_DEBUG_OBJECT (src, "EOS found on seeking!!!");
1.694 + return FALSE;
1.695 + }
1.696 +
1.697 +}
1.698 +
1.699 +/* create a socket for connecting to remote server */
1.700 +static gboolean
1.701 +gst_mythtv_src_start (GstBaseSrc * bsrc)
1.702 +{
1.703 + GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
1.704 +
1.705 + GString *chain_id_local = NULL;
1.706 + GMythURI *gmyth_uri = NULL;
1.707 + gboolean ret = TRUE;
1.708 +
1.709 + if (src->unique_setup == FALSE) {
1.710 + src->unique_setup = TRUE;
1.711 + } else {
1.712 + goto done;
1.713 + }
1.714 +
1.715 + gmyth_uri = gmyth_uri_new_with_value (src->uri_name);
1.716 + src->backend_info = gmyth_backend_info_new_with_uri (src->uri_name);
1.717 + src->live_tv = gmyth_uri_is_livetv( gmyth_uri );
1.718 + /* testing UPnP... */
1.719 + /* gmyth_backend_info_set_hostname( src->backend_info, NULL ); */
1.720 + if ( src->live_tv ) {
1.721 + src->spawn_livetv = gmyth_livetv_new (src->backend_info);
1.722 +
1.723 + gchar* ch = gmyth_uri_get_channel_name( gmyth_uri );
1.724 + if ( ch != NULL )
1.725 + src->channel_name = ch;
1.726 +
1.727 + if (src->channel_name != NULL) {
1.728 + if (gmyth_livetv_channel_name_setup (src->spawn_livetv, src->channel_name) == FALSE) {
1.729 + GST_INFO_OBJECT (src, "LiveTV setup felt down on error");
1.730 + ret = FALSE;
1.731 + goto init_failed;
1.732 + }
1.733 + } else {
1.734 + if (gmyth_livetv_setup (src->spawn_livetv) == FALSE) {
1.735 + GST_INFO_OBJECT (src, "LiveTV setup felt down on error");
1.736 + ret = FALSE;
1.737 + goto init_failed;
1.738 + }
1.739 + }
1.740 +
1.741 + /* testing change channel... */
1.742 + /* gmyth_recorder_change_channel( src->spawn_livetv->recorder, CHANNEL_DIRECTION_UP ); */
1.743 +
1.744 + src->file = GMYTH_FILE( gmyth_livetv_create_file_transfer (src->spawn_livetv) );
1.745 +
1.746 + if (NULL == src->file) {
1.747 + GST_INFO_OBJECT (src, "[LiveTV] FileTransfer equals to NULL");
1.748 + ret = FALSE;
1.749 + goto init_failed;
1.750 + }
1.751 +
1.752 + /* Check if the file is local to this specific client renderer */
1.753 + if ( gmyth_uri_is_local_file(gmyth_uri) )
1.754 + ret = gmyth_file_local_open( GMYTH_FILE_LOCAL(src->file) );
1.755 + else
1.756 + ret = gmyth_file_transfer_open( GMYTH_FILE_TRANSFER(src->file), src->spawn_livetv->uri != NULL ?
1.757 + gmyth_uri_get_path(src->spawn_livetv->uri) :
1.758 + src->spawn_livetv->proginfo->pathname->str );
1.759 +
1.760 + /* sets the mythtvsrc "location" property */
1.761 + g_object_set (src, "location", gmyth_file_get_uri (src->file), NULL);
1.762 +
1.763 + if ( !ret )
1.764 + {
1.765 + GST_INFO_OBJECT (src, "Error: couldn't open the FileTransfer from LiveTV source!" );
1.766 + g_object_unref( src->file );
1.767 + src->file = NULL;
1.768 + goto init_failed;
1.769 + }
1.770 + } else {
1.771 +
1.772 + /* Check if the file is local to this specific client renderer, and tries to open
1.773 + * a local connection
1.774 + */
1.775 + if ( gmyth_uri_is_local_file(gmyth_uri) )
1.776 + {
1.777 + src->file = GMYTH_FILE(gmyth_file_local_new(src->backend_info));
1.778 + ret = gmyth_file_local_open ( GMYTH_FILE_LOCAL( src->file ) );
1.779 + } else {
1.780 + src->file = GMYTH_FILE(gmyth_file_transfer_new(src->backend_info));
1.781 + ret = gmyth_file_transfer_open ( GMYTH_FILE_TRANSFER(src->file), src->uri_name );
1.782 + }
1.783 +
1.784 + } /* if (else) - recorded FileTransfer */
1.785 +
1.786 + if (NULL == src->file) {
1.787 + GST_INFO_OBJECT (src, "FileTransfer is NULL");
1.788 + goto init_failed;
1.789 + }
1.790 + /*GST_INFO_OBJECT( src, "uri = %s", src->spawn_livetv->file); */
1.791 +
1.792 + if (ret == FALSE) {
1.793 +#ifndef GST_DISABLE_GST_DEBUG
1.794 + if (src->mythtv_msgs_dbg)
1.795 + GST_INFO_OBJECT (src,
1.796 + "MythTV FileTransfer request failed when setting up socket connection!");
1.797 +#endif
1.798 + goto begin_req_failed;
1.799 + }
1.800 +
1.801 + GST_INFO_OBJECT (src,
1.802 + "MythTV FileTransfer filesize = %lld, content_size = %lld!",
1.803 + gmyth_file_get_filesize( src->file ), src->content_size);
1.804 +
1.805 + src->content_size = gmyth_file_get_filesize (src->file);
1.806 +
1.807 + src->do_start = FALSE;
1.808 +
1.809 + /* this is used for the buffer cache */
1.810 + src->bytes_queue = g_byte_array_sized_new (INTERNAL_BUFFER_SIZE);
1.811 + src->buffer_remain = 0;
1.812 +
1.813 + gst_pad_push_event (GST_BASE_SRC_PAD (GST_BASE_SRC (src)),
1.814 + gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, 0,
1.815 + src->content_size, 0));
1.816 +
1.817 +done:
1.818 + if (gmyth_uri != NULL)
1.819 + {
1.820 + g_object_unref (gmyth_uri);
1.821 + gmyth_uri = NULL;
1.822 + }
1.823 +
1.824 + if (chain_id_local != NULL) {
1.825 + g_string_free (chain_id_local, TRUE);
1.826 + chain_id_local = NULL;
1.827 + }
1.828 +
1.829 + return TRUE;
1.830 +
1.831 + /* ERRORS */
1.832 +init_failed:
1.833 + if (gmyth_uri != NULL)
1.834 + {
1.835 + g_object_unref (gmyth_uri);
1.836 + gmyth_uri = NULL;
1.837 + }
1.838 +
1.839 + if (src->spawn_livetv != NULL) {
1.840 + g_object_unref (src->spawn_livetv);
1.841 + src->spawn_livetv = NULL;
1.842 + }
1.843 +
1.844 + /*
1.845 + GST_ELEMENT_ERROR (src, LIBRARY, INIT,
1.846 + (NULL), ("Could not initialize MythTV library (%i, %s)", ret,
1.847 + src->uri_name));
1.848 + */
1.849 +
1.850 + if (++src->try_number <= src->max_try) {
1.851 + gst_mythtv_src_clear (src);
1.852 + GST_DEBUG_OBJECT (src, "Starting new try for get free recorder on MythTV");
1.853 + g_usleep (0.5 * G_USEC_PER_SEC);
1.854 + return gst_mythtv_src_start (bsrc);
1.855 + }
1.856 +
1.857 + return FALSE;
1.858 +begin_req_failed:
1.859 + if (gmyth_uri != NULL)
1.860 + {
1.861 + g_object_unref (gmyth_uri);
1.862 + gmyth_uri = NULL;
1.863 + }
1.864 +
1.865 + GST_ELEMENT_ERROR (src, LIBRARY, INIT,
1.866 + (NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret,
1.867 + src->uri_name));
1.868 + return FALSE;
1.869 +
1.870 +}
1.871 +
1.872 +static gboolean
1.873 +gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size)
1.874 +{
1.875 + GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
1.876 + gboolean ret = TRUE;
1.877 +
1.878 + GST_LOG_OBJECT (src, "Differs from previous content size: %d (max.: %d)",
1.879 + abs (src->content_size - src->prev_content_size),
1.880 + GMYTHTV_TRANSFER_MAX_BUFFER);
1.881 +
1.882 + if (src->live_tv) {
1.883 + ret = FALSE;
1.884 + } else if (src->live_tv && src->enable_timing_position
1.885 + && (abs (src->content_size - src->bytes_read) <
1.886 + GMYTHTV_TRANSFER_MAX_BUFFER)) {
1.887 +
1.888 + gint64 new_offset =
1.889 + gmyth_recorder_get_file_position (src->spawn_livetv->recorder);
1.890 + if (new_offset > 0 && new_offset > src->content_size) {
1.891 + src->content_size = new_offset;
1.892 + } else if (new_offset < src->content_size) {
1.893 + src->update_prog_chain = TRUE;
1.894 + }
1.895 +
1.896 + }
1.897 +
1.898 + *size = src->content_size;
1.899 + GST_LOG_OBJECT (src, "Content size = %lld", src->content_size);
1.900 +
1.901 + return ret;
1.902 +
1.903 +}
1.904 +
1.905 +/* close the socket and associated resources
1.906 + * used both to recover from errors and go to NULL state */
1.907 +static gboolean
1.908 +gst_mythtv_src_stop (GstBaseSrc * bsrc)
1.909 +{
1.910 + GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
1.911 +
1.912 + gst_mythtv_src_clear (src);
1.913 +
1.914 + /* src->eos = FALSE; */
1.915 +
1.916 + return TRUE;
1.917 +}
1.918 +
1.919 +static gboolean
1.920 +gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event)
1.921 +{
1.922 + GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad));
1.923 + gint64 cont_size = 0;
1.924 + gboolean ret = FALSE;
1.925 +
1.926 + switch (GST_EVENT_TYPE (event)) {
1.927 + case GST_EVENT_EOS:
1.928 + GST_WARNING_OBJECT (src, "Got EOS event");
1.929 +
1.930 + if (src->live_tv) {
1.931 + cont_size = gst_mythtv_src_get_position (src);
1.932 + if (cont_size > src->content_size) {
1.933 + src->content_size = cont_size;
1.934 + src->eos = FALSE;
1.935 + } else {
1.936 + src->eos = TRUE;
1.937 + gst_element_set_state (GST_ELEMENT (src), GST_STATE_NULL);
1.938 + gst_element_set_locked_state (GST_ELEMENT (src), FALSE);
1.939 + }
1.940 + }
1.941 + break;
1.942 + default:
1.943 + ret = gst_pad_event_default (pad, event);
1.944 + }
1.945 +
1.946 + return ret;
1.947 +}
1.948 +
1.949 +static gboolean
1.950 +gst_mythtv_src_is_seekable (GstBaseSrc * push_src)
1.951 +{
1.952 + return TRUE;
1.953 +}
1.954 +
1.955 +static gboolean
1.956 +gst_mythtv_src_handle_query (GstPad * pad, GstQuery * query)
1.957 +{
1.958 + gboolean res = FALSE;
1.959 + GstMythtvSrc *myth = GST_MYTHTV_SRC (gst_pad_get_parent (pad));
1.960 + GstFormat formt;
1.961 +
1.962 + switch (GST_QUERY_TYPE (query)) {
1.963 + case GST_QUERY_POSITION:
1.964 + {
1.965 + gst_query_parse_position (query, &formt, NULL);
1.966 + if (formt == GST_FORMAT_BYTES) {
1.967 + gst_query_set_position (query, formt, myth->read_offset);
1.968 + GST_DEBUG_OBJECT (myth, "POS %" G_GINT64_FORMAT, myth->read_offset);
1.969 + res = TRUE;
1.970 + } else if (formt == GST_FORMAT_TIME) {
1.971 + res = gst_pad_query_default (pad, query);
1.972 + }
1.973 + break;
1.974 + }
1.975 + case GST_QUERY_DURATION:
1.976 + {
1.977 +#if 0
1.978 + if (myth->duration != 0) {
1.979 + gint64 total;
1.980 + gint64 fps;
1.981 +
1.982 + fps = nuv->h->i_fpsn / nuv->h->i_fpsd;
1.983 + total =
1.984 + gst_util_uint64_scale_int (GST_SECOND, nuv->h->i_video_blocks, fps);
1.985 + }
1.986 +#endif
1.987 +
1.988 + gst_query_parse_duration (query, &formt, NULL);
1.989 + if (formt == GST_FORMAT_BYTES) {
1.990 + gst_query_set_duration (query, formt, myth->content_size);
1.991 + GST_DEBUG_OBJECT (myth, "SIZE %" G_GINT64_FORMAT, myth->content_size);
1.992 + res = TRUE;
1.993 + } else if (formt == GST_FORMAT_TIME) {
1.994 + res = gst_pad_query_default (pad, query);
1.995 + }
1.996 + break;
1.997 + }
1.998 + default:
1.999 + {
1.1000 + res = gst_pad_query_default (pad, query);
1.1001 + break;
1.1002 + }
1.1003 + }
1.1004 +
1.1005 + gst_object_unref (myth);
1.1006 +
1.1007 + return res;
1.1008 +}
1.1009 +
1.1010 +static GstStateChangeReturn
1.1011 +gst_mythtv_src_change_state (GstElement * element, GstStateChange transition)
1.1012 +{
1.1013 + GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
1.1014 + GstMythtvSrc *src = GST_MYTHTV_SRC (element);
1.1015 +
1.1016 + switch (transition) {
1.1017 + case GST_STATE_CHANGE_NULL_TO_READY:
1.1018 + break;
1.1019 + case GST_STATE_CHANGE_READY_TO_PAUSED:
1.1020 + case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1.1021 + if (src->live_tv) {
1.1022 + if (!gmyth_recorder_send_frontend_ready_command (src->spawn_livetv->
1.1023 + recorder))
1.1024 + GST_WARNING_OBJECT (src,
1.1025 + "Couldn't send the FRONTEND_READY message to the backend!");
1.1026 + else
1.1027 + GST_DEBUG_OBJECT (src, "FRONTEND_READY was sent to the backend");
1.1028 + }
1.1029 + break;
1.1030 + default:
1.1031 + break;
1.1032 + }
1.1033 +
1.1034 + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1.1035 + if (ret == GST_STATE_CHANGE_FAILURE)
1.1036 + return ret;
1.1037 +
1.1038 + switch (transition) {
1.1039 + case GST_STATE_CHANGE_READY_TO_NULL:
1.1040 + break;
1.1041 + case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1.1042 + case GST_STATE_CHANGE_PAUSED_TO_READY:
1.1043 + break;
1.1044 + default:
1.1045 + break;
1.1046 + }
1.1047 +
1.1048 + return ret;
1.1049 +}
1.1050 +
1.1051 +static void
1.1052 +gst_mythtv_src_set_property (GObject * object, guint prop_id,
1.1053 + const GValue * value, GParamSpec * pspec)
1.1054 +{
1.1055 + GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
1.1056 +
1.1057 + GST_OBJECT_LOCK (mythtvsrc);
1.1058 + switch (prop_id) {
1.1059 + case PROP_LOCATION:
1.1060 + {
1.1061 + if (!g_value_get_string (value)) {
1.1062 + GST_WARNING ("location property cannot be NULL");
1.1063 + break;
1.1064 + }
1.1065 +
1.1066 + if (mythtvsrc->uri_name != NULL) {
1.1067 + g_free (mythtvsrc->uri_name);
1.1068 + mythtvsrc->uri_name = NULL;
1.1069 + }
1.1070 + mythtvsrc->uri_name = g_value_dup_string (value);
1.1071 +
1.1072 + break;
1.1073 + }
1.1074 +#ifndef GST_DISABLE_GST_DEBUG
1.1075 + case PROP_GMYTHTV_DBG:
1.1076 + {
1.1077 + mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value);
1.1078 + break;
1.1079 + }
1.1080 +#endif
1.1081 + case PROP_GMYTHTV_VERSION:
1.1082 + {
1.1083 + mythtvsrc->mythtv_version = g_value_get_int (value);
1.1084 + break;
1.1085 + }
1.1086 + case PROP_GMYTHTV_LIVEID:
1.1087 + {
1.1088 + mythtvsrc->live_tv_id = g_value_get_int (value);
1.1089 + break;
1.1090 + }
1.1091 + case PROP_GMYTHTV_LIVE:
1.1092 + {
1.1093 + mythtvsrc->live_tv = g_value_get_boolean (value);
1.1094 + break;
1.1095 + }
1.1096 + case PROP_GMYTHTV_ENABLE_TIMING_POSITION:
1.1097 + {
1.1098 + mythtvsrc->enable_timing_position = g_value_get_boolean (value);
1.1099 + break;
1.1100 + }
1.1101 + case PROP_GMYTHTV_LIVE_CHAINID:
1.1102 + {
1.1103 + if (!g_value_get_string (value)) {
1.1104 + GST_WARNING ("MythTV Live chainid property cannot be NULL");
1.1105 + break;
1.1106 + }
1.1107 +
1.1108 + if (mythtvsrc->live_chain_id != NULL) {
1.1109 + g_free (mythtvsrc->live_chain_id);
1.1110 + mythtvsrc->live_chain_id = NULL;
1.1111 + }
1.1112 + mythtvsrc->live_chain_id = g_value_dup_string (value);
1.1113 + break;
1.1114 + }
1.1115 + case PROP_GMYTHTV_CHANNEL_NUM:
1.1116 + {
1.1117 + mythtvsrc->channel_name = g_value_dup_string (value);
1.1118 + break;
1.1119 + }
1.1120 + case PROP_GMYTHTV_MAX_TRY:
1.1121 + {
1.1122 + mythtvsrc->max_try = g_value_get_int (value);
1.1123 + break;
1.1124 + }
1.1125 + default:
1.1126 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1.1127 + break;
1.1128 + }
1.1129 +
1.1130 + GST_OBJECT_UNLOCK (mythtvsrc);
1.1131 +}
1.1132 +
1.1133 +static void
1.1134 +gst_mythtv_src_get_property (GObject * object, guint prop_id,
1.1135 + GValue * value, GParamSpec * pspec)
1.1136 +{
1.1137 + GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
1.1138 +
1.1139 + GST_OBJECT_LOCK (mythtvsrc);
1.1140 + switch (prop_id) {
1.1141 + case PROP_LOCATION:
1.1142 + {
1.1143 + g_value_set_string (value, mythtvsrc->uri_name);
1.1144 + break;
1.1145 + }
1.1146 +#ifndef GST_DISABLE_GST_DEBUG
1.1147 + case PROP_GMYTHTV_DBG:
1.1148 + g_value_set_boolean (value, mythtvsrc->mythtv_msgs_dbg);
1.1149 + break;
1.1150 +#endif
1.1151 + case PROP_GMYTHTV_VERSION:
1.1152 + {
1.1153 + g_value_set_int (value, mythtvsrc->mythtv_version);
1.1154 + break;
1.1155 + }
1.1156 + case PROP_GMYTHTV_LIVEID:
1.1157 + {
1.1158 + g_value_set_int (value, mythtvsrc->live_tv_id);
1.1159 + break;
1.1160 + }
1.1161 + case PROP_GMYTHTV_LIVE:
1.1162 + g_value_set_boolean (value, mythtvsrc->live_tv);
1.1163 + break;
1.1164 + case PROP_GMYTHTV_ENABLE_TIMING_POSITION:
1.1165 + g_value_set_boolean (value, mythtvsrc->enable_timing_position);
1.1166 + break;
1.1167 + case PROP_GMYTHTV_LIVE_CHAINID:
1.1168 + {
1.1169 + g_value_set_string (value, mythtvsrc->live_chain_id);
1.1170 + break;
1.1171 + }
1.1172 + case PROP_GMYTHTV_CHANNEL_NUM:
1.1173 + {
1.1174 + g_value_set_string (value, mythtvsrc->channel_name);
1.1175 + break;
1.1176 + }
1.1177 + case PROP_GMYTHTV_MAX_TRY:
1.1178 + {
1.1179 + g_value_set_int (value, mythtvsrc->max_try);
1.1180 + break;
1.1181 + }
1.1182 +
1.1183 + default:
1.1184 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1.1185 + break;
1.1186 + }
1.1187 + GST_OBJECT_UNLOCK (mythtvsrc);
1.1188 +}
1.1189 +
1.1190 +static gboolean
1.1191 +plugin_init (GstPlugin * plugin)
1.1192 +{
1.1193 + return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE,
1.1194 + GST_TYPE_MYTHTV_SRC);
1.1195 +}
1.1196 +
1.1197 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1.1198 + GST_VERSION_MINOR,
1.1199 + "mythtv",
1.1200 + "lib MythTV src",
1.1201 + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
1.1202 +
1.1203 +
1.1204 +/*** GSTURIHANDLER INTERFACE *************************************************/
1.1205 +static guint
1.1206 +gst_mythtv_src_uri_get_type (void)
1.1207 +{
1.1208 + return GST_URI_SRC;
1.1209 +}
1.1210 +
1.1211 +static gchar **
1.1212 +gst_mythtv_src_uri_get_protocols (void)
1.1213 +{
1.1214 + static gchar *protocols[] = { "myth", "myths", NULL };
1.1215 +
1.1216 + return protocols;
1.1217 +}
1.1218 +
1.1219 +static const gchar *
1.1220 +gst_mythtv_src_uri_get_uri (GstURIHandler * handler)
1.1221 +{
1.1222 + GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
1.1223 +
1.1224 + return src->uri_name;
1.1225 +}
1.1226 +
1.1227 +static gboolean
1.1228 +gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
1.1229 +{
1.1230 + GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
1.1231 +
1.1232 + gchar *protocol;
1.1233 +
1.1234 + protocol = gst_uri_get_protocol (uri);
1.1235 + if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) {
1.1236 + g_free (protocol);
1.1237 + return FALSE;
1.1238 + }
1.1239 + g_free (protocol);
1.1240 + g_object_set (src, "location", uri, NULL);
1.1241 +
1.1242 + return TRUE;
1.1243 +}
1.1244 +
1.1245 +static void
1.1246 +gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
1.1247 +{
1.1248 + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
1.1249 +
1.1250 + iface->get_type = gst_mythtv_src_uri_get_type;
1.1251 + iface->get_protocols = gst_mythtv_src_uri_get_protocols;
1.1252 + iface->get_uri = gst_mythtv_src_uri_get_uri;
1.1253 + iface->set_uri = gst_mythtv_src_uri_set_uri;
1.1254 +}
1.1255 +
1.1256 +void
1.1257 +size_header_handler (void *userdata, const char *value)
1.1258 +{
1.1259 + GstMythtvSrc *src = GST_MYTHTV_SRC (userdata);
1.1260 +
1.1261 + GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size);
1.1262 +}