1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/gst-plugins-mythtv/src/gstmythtvsrc.c.new Tue Oct 24 20:05:07 2006 +0100
1.3 @@ -0,0 +1,1033 @@
1.4 +/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2 -*- */
1.5 +/* GStreamer MythTV Plug-in
1.6 + * Copyright (C) <2006> Rosfran Borges <rosfran.borges@indt.org.br>
1.7 + *
1.8 + * This library is free software; you can redistribute it and/or
1.9 + * modify it under the terms of the GNU Library General Public
1.10 + * License as published by the Free Software Foundation; either
1.11 + * version 2 of the License, or (at your option) any later version.
1.12 + *
1.13 + * This library is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.16 + * Library General Public License for more
1.17 + */
1.18 +
1.19 +#ifdef HAVE_CONFIG_H
1.20 +#include "config.h"
1.21 +#endif
1.22 +
1.23 +#include "gstmythtvsrc.h"
1.24 +#include "myth_file_transfer.h"
1.25 +#include "myth_livetv.h"
1.26 +
1.27 +#include <gmyth/gmyth_socket.h>
1.28 +#include <gmyth/gmyth_tvchain.h>
1.29 +
1.30 +#include <string.h>
1.31 +#include <unistd.h>
1.32 +
1.33 +GST_DEBUG_CATEGORY_STATIC (mythtvsrc_debug);
1.34 +#define GST_CAT_DEFAULT mythtvsrc_debug
1.35 +
1.36 +#define GST_MYTHTV_ID_NUM 1
1.37 +
1.38 +#define MYTHTV_VERSION_DEFAULT 30
1.39 +
1.40 +#define MYTHTV_TRANSFER_MAX_WAITS 100
1.41 +
1.42 +#define MYTHTV_TRANSFER_MAX_BUFFER ( 32*1024 )
1.43 +
1.44 +/* 4*1024 ??? */
1.45 +#define MAX_READ_SIZE ( 16*1024 )
1.46 +
1.47 +#define ENABLE_TIMING_POSITION 1
1.48 +
1.49 +/* stablish a maximum iteration value to the IS_RECORDING message */
1.50 +static guint wait_to_transfer = 0;
1.51 +
1.52 +static const GstElementDetails gst_mythtv_src_details =
1.53 +GST_ELEMENT_DETAILS ("MythTV client source",
1.54 + "Source/Network",
1.55 + "Control and receive data as a client over the network via raw socket connections using the MythTV protocol",
1.56 + "Rosfran Borges <rosfran.borges@indt.org.br>");
1.57 +
1.58 +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
1.59 + GST_PAD_SRC,
1.60 + GST_PAD_ALWAYS,
1.61 + GST_STATIC_CAPS_ANY);
1.62 +
1.63 +static GstTask *update_size_task = NULL;
1.64 +
1.65 +static GStaticRecMutex update_size_mutex = G_STATIC_REC_MUTEX_INIT;
1.66 +
1.67 +enum
1.68 +{
1.69 + PROP_0,
1.70 + PROP_LOCATION,
1.71 + PROP_URI,
1.72 +#ifndef GST_DISABLE_GST_DEBUG
1.73 + PROP_MYTHTV_DBG,
1.74 +#endif
1.75 + PROP_MYTHTV_VERSION,
1.76 + PROP_MYTHTV_LIVE,
1.77 + PROP_MYTHTV_LIVEID,
1.78 + PROP_MYTHTV_LIVE_CHAINID
1.79 +};
1.80 +
1.81 +static void gst_mythtv_src_finalize (GObject * gobject);
1.82 +
1.83 +static GstFlowReturn gst_mythtv_src_create (GstBaseSrc * psrc,
1.84 + guint64 offset, guint size, GstBuffer ** outbuf);
1.85 +static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc);
1.86 +static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc);
1.87 +static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size);
1.88 +static gboolean gst_mythtv_src_is_seekable( GstBaseSrc *base_src );
1.89 +
1.90 +static void gst_mythtv_src_set_property (GObject * object, guint prop_id,
1.91 + const GValue * value, GParamSpec * pspec);
1.92 +static void gst_mythtv_src_get_property (GObject * object, guint prop_id,
1.93 + GValue * value, GParamSpec * pspec);
1.94 +
1.95 +static void
1.96 +gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
1.97 +
1.98 +static gboolean
1.99 +gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event);
1.100 +
1.101 + static void
1.102 +_urihandler_init (GType type)
1.103 +{
1.104 + static const GInterfaceInfo urihandler_info = {
1.105 + gst_mythtv_src_uri_handler_init,
1.106 + NULL,
1.107 + NULL
1.108 + };
1.109 +
1.110 + g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
1.111 +
1.112 + GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
1.113 + "MythTV src");
1.114 +}
1.115 +
1.116 +GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstBaseSrc,
1.117 + GST_TYPE_BASE_SRC, _urihandler_init);
1.118 +
1.119 + static void
1.120 +gst_mythtv_src_base_init (gpointer g_class)
1.121 +{
1.122 + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1.123 +
1.124 + gst_element_class_add_pad_template (element_class,
1.125 + gst_static_pad_template_get (&srctemplate));
1.126 +
1.127 + gst_element_class_set_details (element_class, &gst_mythtv_src_details);
1.128 +}
1.129 +
1.130 + static void
1.131 +gst_mythtv_src_class_init (GstMythtvSrcClass * klass)
1.132 +{
1.133 + GObjectClass *gobject_class;
1.134 + GstBaseSrcClass *gstbasesrc_class;
1.135 +
1.136 + gobject_class = (GObjectClass *) klass;
1.137 + gstbasesrc_class = (GstBaseSrcClass *) klass;
1.138 +
1.139 + gobject_class->set_property = gst_mythtv_src_set_property;
1.140 + gobject_class->get_property = gst_mythtv_src_get_property;
1.141 + gobject_class->finalize = gst_mythtv_src_finalize;
1.142 +
1.143 + g_object_class_install_property
1.144 + (gobject_class, PROP_LOCATION,
1.145 + g_param_spec_string ("location", "Location",
1.146 + "The location. In the form:"
1.147 + "\n\t\t\tmyth://a.com/file.nuv"
1.148 + "\n\t\t\tmyth://a.com:23223/file.nuv "
1.149 + "\n\t\t\ta.com/file.nuv - default scheme 'myth'",
1.150 + "", G_PARAM_READWRITE));
1.151 +
1.152 + g_object_class_install_property
1.153 + (gobject_class, PROP_URI,
1.154 + g_param_spec_string ("uri", "Uri",
1.155 + "The location in form of a URI (deprecated; use location)",
1.156 + "", G_PARAM_READWRITE));
1.157 +
1.158 + g_object_class_install_property
1.159 + (gobject_class, PROP_MYTHTV_VERSION,
1.160 + g_param_spec_int ("mythtv-version", "mythtv-version",
1.161 + "Change Myth TV version",
1.162 + 26, 30, 26, G_PARAM_READWRITE));
1.163 +
1.164 + g_object_class_install_property
1.165 + (gobject_class, PROP_MYTHTV_LIVEID,
1.166 + g_param_spec_int ("mythtv-live-id", "mythtv-live-id",
1.167 + "Change Myth TV version",
1.168 + 0, 200, GST_MYTHTV_ID_NUM, G_PARAM_READWRITE));
1.169 +
1.170 + g_object_class_install_property
1.171 + (gobject_class, PROP_MYTHTV_LIVE_CHAINID,
1.172 + g_param_spec_string ("mythtv-live-chainid", "mythtv-live-chainid",
1.173 + "Sets the Myth TV chain ID (from TV Chain)",
1.174 + "", G_PARAM_READWRITE));
1.175 +
1.176 + g_object_class_install_property
1.177 + (gobject_class, PROP_MYTHTV_LIVE,
1.178 + g_param_spec_boolean ("mythtv-live", "mythtv-live",
1.179 + "Enable MythTV Live TV content streaming",
1.180 + FALSE, G_PARAM_READWRITE));
1.181 +
1.182 +#ifndef GST_DISABLE_GST_DEBUG
1.183 + g_object_class_install_property
1.184 + (gobject_class, PROP_MYTHTV_DBG,
1.185 + g_param_spec_boolean ("mythtv-debug", "mythtv-debug",
1.186 + "Enable MythTV debug messages",
1.187 + FALSE, G_PARAM_READWRITE));
1.188 +#endif
1.189 +
1.190 + gstbasesrc_class->start = gst_mythtv_src_start;
1.191 + gstbasesrc_class->stop = gst_mythtv_src_stop;
1.192 + gstbasesrc_class->get_size = gst_mythtv_src_get_size;
1.193 + gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable;
1.194 +
1.195 + gstbasesrc_class->create = gst_mythtv_src_create;
1.196 +
1.197 + GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0,
1.198 + "MythTV Client Source");
1.199 +}
1.200 +
1.201 + static void
1.202 +gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class)
1.203 +{
1.204 + this->file_transfer = NULL;
1.205 +
1.206 + this->unique_setup = FALSE;
1.207 +
1.208 + this->mythtv_version = MYTHTV_VERSION_DEFAULT;
1.209 +
1.210 + this->bytes_read = 0;
1.211 +
1.212 + this->content_size = -1;
1.213 + this->read_offset = 0;
1.214 +
1.215 + this->live_tv = FALSE;
1.216 +
1.217 + this->user_agent = g_strdup ("mythtvsrc");
1.218 + this->mythtv_caps = NULL;
1.219 +
1.220 + gst_base_src_set_live ( GST_BASE_SRC( this ), TRUE );
1.221 +
1.222 + gst_pad_set_event_function (GST_BASE_SRC_PAD(GST_BASE_SRC(this)),
1.223 + GST_DEBUG_FUNCPTR (gst_mythtv_src_handle_event));
1.224 +
1.225 +}
1.226 +
1.227 + static void
1.228 +gst_mythtv_src_finalize (GObject * gobject)
1.229 +{
1.230 + GstMythtvSrc *this = GST_MYTHTV_SRC (gobject);
1.231 +
1.232 + g_free (this->user_agent);
1.233 +
1.234 + if (this->mythtv_caps) {
1.235 + gst_caps_unref (this->mythtv_caps);
1.236 + this->mythtv_caps = NULL;
1.237 + }
1.238 +
1.239 + if (this->file_transfer) {
1.240 + g_object_unref (this->file_transfer);
1.241 + this->file_transfer = NULL;
1.242 + }
1.243 +
1.244 + if (this->uri_name) {
1.245 + g_free (this->uri_name);
1.246 + }
1.247 +
1.248 + if (this->user_agent) {
1.249 + g_free (this->user_agent);
1.250 + }
1.251 +
1.252 + if ( update_size_task != NULL ) {
1.253 +
1.254 + if ( GST_TASK_STATE( update_size_task ) != GST_TASK_STOPPED )
1.255 + gst_task_stop( update_size_task );
1.256 +
1.257 + gst_object_unref( update_size_task );
1.258 +
1.259 + update_size_task = NULL;
1.260 +
1.261 + }
1.262 +
1.263 + G_OBJECT_CLASS (parent_class)->finalize (gobject);
1.264 +}
1.265 +
1.266 +#if 0
1.267 + static guint
1.268 +do_seek( GstMythtvSrc *src, guint64 offset, guint size, GstBuffer *outbuf )
1.269 +{
1.270 + guint64 off_uint64 = myth_file_transfer_seek(src->file_transfer, offset, 1);
1.271 +
1.272 + g_print( "[%s] Call MythTV SEEK with offset %llu, got a new one %llu...\n", __FUNCTION__,
1.273 + offset, off_uint64 );
1.274 +
1.275 + return off_uint64;
1.276 +
1.277 +}
1.278 +#endif
1.279 +
1.280 + static guint
1.281 +do_read_request_response (GstMythtvSrc * src, guint64 offset, guint size, GstBuffer * outbuf)
1.282 +{
1.283 + guint read = 0;
1.284 + guint sizetoread = size; //GST_BUFFER_SIZE (outbuf);
1.285 +
1.286 + g_print( "[%s] Reading %d bytes...\n", __FUNCTION__, sizetoread );
1.287 +
1.288 + /* Loop sending the request:
1.289 + * Retry whilst authentication fails and we supply it. */
1.290 +
1.291 + ssize_t len = 0;
1.292 +
1.293 + //GST_OBJECT_LOCK(src);
1.294 +
1.295 + while ( sizetoread > 0 ) {
1.296 +
1.297 + len = myth_file_transfer_read( src->file_transfer,
1.298 + GST_BUFFER_DATA (outbuf) + read, sizetoread, TRUE );
1.299 +
1.300 + if ( len > 0 ) {
1.301 + read += len;
1.302 + src->read_offset += read;
1.303 + sizetoread -= len;
1.304 + } else if ( len < 0 ) {
1.305 + goto done;
1.306 + }
1.307 + else if ( len == 0 ) {
1.308 + if ( src->live_tv == FALSE )
1.309 + goto done;
1.310 + else
1.311 + goto eos;
1.312 +
1.313 + }
1.314 +
1.315 + if ( len == sizetoread )
1.316 + break;
1.317 +
1.318 + }
1.319 +
1.320 + if ( read > 0 ) {
1.321 + src->bytes_read += read;
1.322 +
1.323 + GST_BUFFER_SIZE (outbuf) = read;
1.324 + } else if ( read <= 0 || len <= 0 ) {
1.325 + if ( src->live_tv == FALSE )
1.326 + goto eos;
1.327 + else
1.328 + goto done;
1.329 + }
1.330 + //GST_BUFFER_OFFSET (outbuf) = src->read_offset;
1.331 +
1.332 + g_print( "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\
1.333 + "OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read,
1.334 + src->read_offset, src->content_size );
1.335 +
1.336 + //GST_OBJECT_UNLOCK(src);
1.337 +
1.338 + if ( len < 0 ) {
1.339 + read = len;
1.340 + if ( src->live_tv == FALSE )
1.341 + goto eos;
1.342 + else
1.343 + goto done;
1.344 + }
1.345 +
1.346 + if ( src->bytes_read < src->content_size )
1.347 + goto done;
1.348 +
1.349 +eos:
1.350 + //GST_OBJECT_UNLOCK(src);
1.351 +
1.352 + src->eos = TRUE;
1.353 +done:
1.354 + //GST_OBJECT_UNLOCK(src);
1.355 +
1.356 + return read;
1.357 +}
1.358 +
1.359 + static GstFlowReturn
1.360 +gst_mythtv_src_create ( GstBaseSrc * psrc, guint64 offset,
1.361 + guint size, GstBuffer **outbuf )
1.362 +{
1.363 + GstMythtvSrc *src;
1.364 + GstFlowReturn ret = GST_FLOW_OK;
1.365 + guint read = 0;
1.366 +
1.367 + src = GST_MYTHTV_SRC (psrc);
1.368 +
1.369 + //src->do_start = FALSE;
1.370 + src->do_start = FALSE;
1.371 + gst_task_join ( update_size_task );
1.372 +
1.373 + g_print( "[%s]\tBUFFER OFFSET = %llu, BUFFER SIZE = %d.\n", __FUNCTION__, offset,
1.374 + size );
1.375 +
1.376 + /* The caller should know the number of bytes and not read beyond EOS. */
1.377 + //if (G_UNLIKELY (src->eos))
1.378 + // goto eos;
1.379 + //g_static_rec_mutex_lock( &update_size_mutex );
1.380 +
1.381 + /* Create the buffer. */
1.382 + ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)),
1.383 + // GST_BUFFER_OFFSET_NONE, GST_BASE_SRC (psrc)->blocksize,
1.384 + offset, size,
1.385 + src->mythtv_caps ? src->mythtv_caps :
1.386 + GST_PAD_CAPS (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc))), outbuf );
1.387 +
1.388 + //if (G_UNLIKELY (ret == GST_FLOW_UNEXPECTED))
1.389 + // goto eos;
1.390 +
1.391 + if (G_UNLIKELY (ret != GST_FLOW_OK))
1.392 + goto eos;
1.393 +
1.394 + if (G_UNLIKELY (ret == GST_FLOW_ERROR))
1.395 + goto read_error;
1.396 +
1.397 + read = do_read_request_response ( src, offset, size, *outbuf );
1.398 +
1.399 + //g_static_rec_mutex_unlock( &update_size_mutex );
1.400 +
1.401 + src->do_start = TRUE;
1.402 + gst_task_start ( update_size_task );
1.403 +
1.404 +#if 0
1.405 + g_static_rec_mutex_lock( &update_size_mutex );
1.406 + src->do_start = FALSE;
1.407 + g_static_rec_mutex_unlock( &update_size_mutex );
1.408 + GST_TASK_SIGNAL( update_size_task );
1.409 +#endif
1.410 +
1.411 + //g_static_rec_mutex_unlock( &update_size_mutex );
1.412 +
1.413 +#if 0
1.414 +#if ENABLE_TIMING_POSITION == 1
1.415 + guint64 size_tmp = 0;
1.416 + if (src->live_tv == TRUE) {
1.417 + //g_usleep( 1000 );
1.418 +get_file_pos:
1.419 + //g_usleep( 100 );
1.420 + size_tmp = myth_file_transfer_get_file_position( src->file_transfer );
1.421 + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) )
1.422 + src->content_size = size_tmp;
1.423 + else
1.424 + goto get_file_pos;
1.425 + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n",
1.426 + __FUNCTION__, size_tmp);
1.427 +
1.428 + }
1.429 +#endif
1.430 +#endif
1.431 +
1.432 + //if (G_UNLIKELY (read < 0))
1.433 + // goto read_error;
1.434 +
1.435 + if (G_UNLIKELY(src->eos))
1.436 + goto eos;
1.437 + else
1.438 + goto done;
1.439 +
1.440 +done:
1.441 + return ret;
1.442 +eos:
1.443 +#if 0
1.444 +#if ENABLE_TIMING_POSITION == 1
1.445 + if ( src->live_tv == TRUE ) {
1.446 + //g_usleep( 1000 );
1.447 + guint64 size_tmp = 0;
1.448 +get_file_pos_eos:
1.449 + //g_usleep( 100 );
1.450 + size_tmp = myth_file_transfer_get_file_position( src->file_transfer );
1.451 + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) )
1.452 + src->content_size = size_tmp;
1.453 + else
1.454 + goto get_file_pos_eos;
1.455 + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n",
1.456 + __FUNCTION__, size_tmp);
1.457 + goto done;
1.458 + } else
1.459 +#endif
1.460 +#endif
1.461 + {
1.462 + GST_DEBUG_OBJECT (src, "EOS reached");
1.463 + return GST_FLOW_UNEXPECTED;
1.464 + }
1.465 + /* ERRORS */
1.466 +read_error:
1.467 + {
1.468 + GST_ELEMENT_ERROR (src, RESOURCE, READ,
1.469 + (NULL), ("Could not read any bytes (%i, %s)", read,
1.470 + src->uri_name));
1.471 + return GST_FLOW_ERROR;
1.472 + }
1.473 + #if 0
1.474 +need_pause:
1.475 + {
1.476 + const gchar *reason = gst_flow_get_name (ret);
1.477 +
1.478 + GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
1.479 + return GST_FLOW_UNEXPECTED;
1.480 + }
1.481 + #endif
1.482 +
1.483 +}
1.484 +
1.485 +#if 0
1.486 +/* The following two charset mangling functions were copied from gnomevfssrc.
1.487 + * Preserve them under the unverified assumption that they do something vaguely
1.488 + * worthwhile.
1.489 + */
1.490 + static char *
1.491 +unicodify (const char *str, int len, ...)
1.492 +{
1.493 + char *ret = NULL, *cset;
1.494 + va_list args;
1.495 + gsize bytes_read, bytes_written;
1.496 +
1.497 + if (g_utf8_validate (str, len, NULL))
1.498 + return g_strndup (str, len >= 0 ? len : strlen (str));
1.499 +
1.500 + va_start (args, len);
1.501 + while ((cset = va_arg (args, char *)) != NULL)
1.502 + {
1.503 + if (!strcmp (cset, "locale"))
1.504 + ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL);
1.505 + else
1.506 + ret = g_convert (str, len, "UTF-8", cset,
1.507 + &bytes_read, &bytes_written, NULL);
1.508 + if (ret)
1.509 + break;
1.510 + }
1.511 + va_end (args);
1.512 +
1.513 + return ret;
1.514 +}
1.515 +
1.516 + static char *
1.517 +gst_mythtv_src_unicodify (const char *str)
1.518 +{
1.519 + return unicodify (str, -1, "locale", "ISO-8859-1", NULL);
1.520 +}
1.521 +#endif
1.522 +
1.523 +void
1.524 +update_size_func( void *mythtv_data )
1.525 +{
1.526 + GstMythtvSrc *src;
1.527 +
1.528 + g_return_if_fail( mythtv_data != NULL );
1.529 +
1.530 + src = GST_MYTHTV_SRC ( mythtv_data );
1.531 + if ( src->do_start ) {
1.532 + #if ENABLE_TIMING_POSITION == 1
1.533 + guint64 size_tmp = 0;
1.534 + if (src->live_tv == TRUE) {
1.535 +get_file_pos:
1.536 + //g_usleep( 50 );
1.537 + size_tmp = myth_file_transfer_get_file_position( src->file_transfer );
1.538 + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) )
1.539 + src->content_size = size_tmp;
1.540 + else
1.541 + goto get_file_pos;
1.542 + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n",
1.543 + __FUNCTION__, size_tmp );
1.544 + }
1.545 +#endif
1.546 +}
1.547 + gst_task_pause( update_size_task );
1.548 + // src->do_start = FALSE;
1.549 + //GST_TASK_SIGNAL( update_size_task );
1.550 +
1.551 +}
1.552 +
1.553 +/* create a socket for connecting to remote server */
1.554 + static gboolean
1.555 +gst_mythtv_src_start ( GstBaseSrc * bsrc )
1.556 +{
1.557 + GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc);
1.558 +
1.559 + GString *chain_id_local = NULL;
1.560 +
1.561 + gboolean ret = TRUE;
1.562 +#if 0
1.563 + if (src->live_tv == TRUE && src->file_transfer != NULL) {
1.564 + guint64 size_tmp = myth_file_transfer_get_file_position( src->file_transfer );
1.565 + if (size_tmp > src->content_size)
1.566 + src->content_size = size_tmp;
1.567 + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n",
1.568 + __FUNCTION__, size_tmp);
1.569 + }
1.570 +#endif
1.571 + if (src->unique_setup == FALSE) {
1.572 + src->unique_setup = TRUE;
1.573 + } else {
1.574 + goto done;
1.575 + }
1.576 +
1.577 + //GST_OBJECT_LOCK(src);
1.578 +
1.579 + if ( src->live_tv ) {
1.580 + src->spawn_livetv = myth_livetv_new( );
1.581 + if ( myth_livetv_setup( src->spawn_livetv ) == FALSE ) {
1.582 + ret = FALSE;
1.583 + goto init_failed;
1.584 + }
1.585 + /* set up the uri variable */
1.586 + src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str );
1.587 + chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain );
1.588 + if ( chain_id_local != NULL ) {
1.589 + src->live_chain_id = g_strdup( chain_id_local->str );
1.590 + g_print( "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id );
1.591 + }
1.592 + src->live_tv_id = src->spawn_livetv->remote_encoder->recorder_num;
1.593 + g_print ( "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name );
1.594 + }
1.595 +
1.596 + src->file_transfer = myth_file_transfer_new( src->live_tv_id,
1.597 + g_string_new( src->uri_name ), -1, src->mythtv_version );
1.598 +
1.599 + if ( src->file_transfer == NULL ) {
1.600 + //GST_OBJECT_UNLOCK(src);
1.601 +
1.602 + goto init_failed;
1.603 + }
1.604 +
1.605 + if ( src->live_tv ) {
1.606 + g_print ( "[%s] GST MYTHTVSRC: live_chain_id = %s\n", __FUNCTION__, src->live_chain_id );
1.607 + /* sets the MythSocket to the FileTransfer */
1.608 + //ret = myth_file_transfer_livetv_setup( &(src->file_transfer), src->spawn_livetv->remote_encoder->myth_socket );
1.609 + }
1.610 + /* sets the Playback monitor connection */
1.611 + ret = myth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv );
1.612 +
1.613 + if ( src->live_tv == TRUE && ret == TRUE ) {
1.614 + /* loop finished, set the max tries variable to zero again... */
1.615 + wait_to_transfer = 0;
1.616 +
1.617 + while ( wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS && ( myth_file_transfer_is_recording( src->file_transfer ) == FALSE
1.618 + /*|| ( myth_file_transfer_get_file_position( src->file_transfer ) < ( src->content_size + 327680 ) )*/ ) )
1.619 + g_usleep( 100 );
1.620 + }
1.621 +
1.622 + /* sets the FileTransfer instance connection (video/audio download) */
1.623 + ret = myth_file_transfer_setup( &(src->file_transfer), src->live_tv );
1.624 +
1.625 + if ( ret == FALSE ) {
1.626 + //GST_OBJECT_UNLOCK(src);
1.627 +#ifndef GST_DISABLE_GST_DEBUG
1.628 + if ( src->mythtv_msgs_dbg )
1.629 + g_printerr( "MythTV FileTransfer request failed when setting up socket connection!\n" );
1.630 +#endif
1.631 + goto begin_req_failed;
1.632 + }
1.633 +
1.634 + src->content_size = src->file_transfer->filesize;
1.635 +
1.636 + //GST_OBJECT_UNLOCK(src);
1.637 +
1.638 + update_size_task = gst_task_create( update_size_func, src );
1.639 +
1.640 + gst_task_set_lock( update_size_task, &update_size_mutex );
1.641 +
1.642 + g_print( "[%s] Update Size task = %s\n", __FUNCTION__, gst_task_start( update_size_task ) &&
1.643 + GST_TASK_STATE( update_size_task ) == GST_TASK_STARTED ? "OK !" : "ERROR!!!" );
1.644 +
1.645 + src->do_start = TRUE;
1.646 +
1.647 +#if 0
1.648 + const char *str_value;
1.649 + gint gint_value;
1.650 +
1.651 + str_value = ne_get_response_header (src->request, "myth-metaint");
1.652 + if (str_value) {
1.653 + if ( sscanf (str_value, "%d", &gint_value) == 1 ) {
1.654 + if (src->myth_caps) {
1.655 + gst_caps_unref (src->myth_caps);
1.656 + src->myth_caps = NULL;
1.657 + }
1.658 + src->myth_metaint = gint_value;
1.659 +#endif
1.660 + //src->mythtv_caps = gst_caps_new_simple ("application/x-gst_ff-nuv", NULL);
1.661 + // }
1.662 + // }
1.663 +done:
1.664 + return TRUE;
1.665 +
1.666 + /* ERRORS */
1.667 +init_failed:
1.668 + {
1.669 + if (src->spawn_livetv != NULL )
1.670 + g_object_unref( src->spawn_livetv );
1.671 +
1.672 + GST_ELEMENT_ERROR (src, LIBRARY, INIT,
1.673 + (NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name));
1.674 + return FALSE;
1.675 + }
1.676 +begin_req_failed:
1.677 + {
1.678 + GST_ELEMENT_ERROR (src, LIBRARY, INIT,
1.679 + (NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name));
1.680 + return FALSE;
1.681 + }
1.682 +}
1.683 +
1.684 +#if 0
1.685 +static gboolean
1.686 +gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size)
1.687 +{
1.688 + GstMythtvSrc *src;
1.689 + gboolean ret = FALSE;
1.690 +
1.691 + src = GST_MYTHTV_SRC (bsrc);
1.692 +
1.693 + g_static_rec_mutex_lock( &update_size_mutex );
1.694 + src->do_start = FALSE;
1.695 + g_static_rec_mutex_unlock( &update_size_mutex );
1.696 + GST_TASK_SIGNAL( update_size_task );
1.697 +
1.698 +
1.699 + while (1) {
1.700 +
1.701 + g_static_rec_mutex_lock( &update_size_mutex );
1.702 + if ( !src->do_start ) {
1.703 +
1.704 + g_print( "[%s] GET SIZE: do_start? == %s\n", __FUNCTION__, src->do_start ? "YES" : "NO" );
1.705 +
1.706 + GST_TASK_WAIT( update_size_task );
1.707 + } else {
1.708 + if (src->content_size <= 0) {
1.709 + g_static_rec_mutex_unlock( &update_size_mutex );
1.710 + goto done;
1.711 + }
1.712 +
1.713 + *size = src->content_size;
1.714 + src->do_start = FALSE;
1.715 +
1.716 + g_static_rec_mutex_unlock( &update_size_mutex );
1.717 +
1.718 + break;
1.719 + }
1.720 + g_static_rec_mutex_unlock( &update_size_mutex );
1.721 +
1.722 + } // while (1)
1.723 +
1.724 +done:
1.725 + return ret;
1.726 +
1.727 +}
1.728 +#endif
1.729 +
1.730 +static gboolean
1.731 +gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size)
1.732 +{
1.733 + GstMythtvSrc *src;
1.734 + gboolean ret = TRUE;
1.735 +
1.736 + src = GST_MYTHTV_SRC (bsrc);
1.737 +
1.738 + if (src->content_size <= 0)
1.739 + ret= FALSE;
1.740 +
1.741 + *size = src->content_size;
1.742 +
1.743 + return ret;
1.744 +
1.745 +}
1.746 +/* close the socket and associated resources
1.747 + * used both to recover from errors and go to NULL state */
1.748 + static gboolean
1.749 +gst_mythtv_src_stop (GstBaseSrc * bsrc)
1.750 +{
1.751 + GstMythtvSrc *src;
1.752 +
1.753 + src = GST_MYTHTV_SRC (bsrc);
1.754 +
1.755 + if (src->uri_name) {
1.756 + g_free (src->uri_name);
1.757 + src->uri_name = NULL;
1.758 + }
1.759 +
1.760 + if (src->mythtv_caps) {
1.761 + gst_caps_unref (src->mythtv_caps);
1.762 + src->mythtv_caps = NULL;
1.763 + }
1.764 +
1.765 + src->eos = FALSE;
1.766 +
1.767 + return TRUE;
1.768 +}
1.769 +
1.770 + static gboolean
1.771 +gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event)
1.772 +{
1.773 + GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad));
1.774 +
1.775 + switch (GST_EVENT_TYPE (event)) {
1.776 + case GST_EVENT_FLUSH_START:
1.777 + src->eos = FALSE;
1.778 + break;
1.779 + //return TRUE;
1.780 +#if 0
1.781 +case GST_EVENT_FLUSH_STOP:
1.782 + src->do_start = TRUE;
1.783 + src->eos = FALSE;
1.784 + gst_element_set_state (GST_ELEMENT(src), GST_STATE_NULL);
1.785 + //gst_element_set_locked_state (GST_ELEMENT(src), TRUE);
1.786 + break;
1.787 +#endif
1.788 + case GST_EVENT_SEEK:
1.789 + {
1.790 + gdouble rate;
1.791 + //gboolean update = TRUE;
1.792 + GstFormat format;
1.793 + GstSeekType cur_type, stop_type;
1.794 + GstSeekFlags flags;
1.795 + gint64 cur = 0, stop = 0;
1.796 + gst_event_parse_seek ( event, &rate, &format,
1.797 + &flags, &cur_type, &cur,
1.798 + &stop_type, &stop );
1.799 +
1.800 + g_print( "[%s] Got EVENT_SEEK.\n", __FUNCTION__ );
1.801 + if ( !( flags & GST_SEEK_FLAG_FLUSH ) ) {
1.802 + g_print( "[%s] Could get the FLAG_FLUSH message.\n", __FUNCTION__ );
1.803 + }
1.804 + //gboolean ret = gst_event_parse_new_segment ( event,
1.805 + // &update, &rate, &format, &start, &stop,
1.806 + // &position );
1.807 + //GstFlowReturn flow_ret = gst_mythtv_src_create (GST_BASE_SRC( GST_PAD_PARENT( psrc ) ),
1.808 + // cur, stop - cur + 1, GstBuffer)
1.809 +
1.810 + }
1.811 + default:
1.812 + return gst_pad_event_default (pad, event);
1.813 + }
1.814 +
1.815 + return gst_pad_event_default (pad, event);
1.816 +}
1.817 +
1.818 + static gboolean
1.819 +gst_mythtv_src_is_seekable( GstBaseSrc *base_src )
1.820 +{
1.821 + return TRUE;
1.822 +}
1.823 +
1.824 + static void
1.825 +gst_mythtv_src_set_property (GObject * object, guint prop_id,
1.826 + const GValue * value, GParamSpec * pspec)
1.827 +{
1.828 + GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
1.829 +
1.830 + GST_OBJECT_LOCK (mythtvsrc);
1.831 + switch (prop_id) {
1.832 + case PROP_URI:
1.833 + case PROP_LOCATION:
1.834 + {
1.835 + if (!g_value_get_string (value)) {
1.836 + GST_WARNING ("location property cannot be NULL");
1.837 + goto done;
1.838 + }
1.839 +
1.840 + if (mythtvsrc->uri_name != NULL) {
1.841 + g_free (mythtvsrc->uri_name);
1.842 + mythtvsrc->uri_name = NULL;
1.843 + }
1.844 + mythtvsrc->uri_name = g_value_dup_string (value);
1.845 +
1.846 + break;
1.847 + }
1.848 +#ifndef GST_DISABLE_GST_DEBUG
1.849 + case PROP_MYTHTV_DBG:
1.850 + {
1.851 + mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value);
1.852 + break;
1.853 + }
1.854 +#endif
1.855 + case PROP_MYTHTV_VERSION:
1.856 + {
1.857 + mythtvsrc->mythtv_version = g_value_get_int (value);
1.858 + break;
1.859 + }
1.860 + case PROP_MYTHTV_LIVEID:
1.861 + {
1.862 + mythtvsrc->live_tv_id = g_value_get_int (value);
1.863 + break;
1.864 + }
1.865 + case PROP_MYTHTV_LIVE:
1.866 + {
1.867 + mythtvsrc->live_tv = g_value_get_boolean (value);
1.868 + break;
1.869 + }
1.870 + case PROP_MYTHTV_LIVE_CHAINID:
1.871 + {
1.872 + if (!g_value_get_string (value)) {
1.873 + GST_WARNING ("MythTV Live chainid property cannot be NULL");
1.874 + goto done;
1.875 + }
1.876 +
1.877 + if (mythtvsrc->live_chain_id != NULL) {
1.878 + g_free (mythtvsrc->live_chain_id);
1.879 + mythtvsrc->live_chain_id = NULL;
1.880 + }
1.881 + mythtvsrc->live_chain_id = g_value_dup_string (value);
1.882 +
1.883 + break;
1.884 + }
1.885 +
1.886 + default:
1.887 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1.888 + break;
1.889 + }
1.890 + GST_OBJECT_UNLOCK (mythtvsrc);
1.891 +done:
1.892 + return;
1.893 +}
1.894 +
1.895 + static void
1.896 +gst_mythtv_src_get_property (GObject * object, guint prop_id,
1.897 + GValue * value, GParamSpec * pspec)
1.898 +{
1.899 + GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object);
1.900 +
1.901 + GST_OBJECT_LOCK (mythtvsrc);
1.902 + switch (prop_id) {
1.903 + case PROP_URI:
1.904 + case PROP_LOCATION:
1.905 + {
1.906 + gchar *str = g_strdup( "" );
1.907 +
1.908 + if ( mythtvsrc->uri_name == NULL ) {
1.909 + g_free (mythtvsrc->uri_name);
1.910 + mythtvsrc->uri_name = NULL;
1.911 + } else {
1.912 + str = g_strdup( mythtvsrc->uri_name );
1.913 + }
1.914 + g_value_set_string ( value, str );
1.915 + break;
1.916 + }
1.917 +#ifndef GST_DISABLE_GST_DEBUG
1.918 + case PROP_MYTHTV_DBG:
1.919 + g_value_set_boolean ( value, mythtvsrc->mythtv_msgs_dbg );
1.920 + break;
1.921 +#endif
1.922 + case PROP_MYTHTV_VERSION:
1.923 + {
1.924 + g_value_set_int ( value, mythtvsrc->mythtv_version );
1.925 + break;
1.926 + }
1.927 + case PROP_MYTHTV_LIVEID:
1.928 + {
1.929 + g_value_set_int ( value, mythtvsrc->live_tv_id );
1.930 + break;
1.931 + }
1.932 + case PROP_MYTHTV_LIVE:
1.933 + g_value_set_boolean ( value, mythtvsrc->live_tv );
1.934 + break;
1.935 + case PROP_MYTHTV_LIVE_CHAINID:
1.936 + {
1.937 + gchar *str = g_strdup( "" );
1.938 +
1.939 + if ( mythtvsrc->live_chain_id == NULL ) {
1.940 + g_free (mythtvsrc->live_chain_id);
1.941 + mythtvsrc->live_chain_id = NULL;
1.942 + } else {
1.943 + str = g_strdup( mythtvsrc->live_chain_id );
1.944 + }
1.945 + g_value_set_string ( value, str );
1.946 + break;
1.947 + }
1.948 + default:
1.949 + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1.950 + break;
1.951 + }
1.952 + GST_OBJECT_UNLOCK (mythtvsrc);
1.953 +}
1.954 +
1.955 +/* entry point to initialize the plug-in
1.956 + * initialize the plug-in itself
1.957 + * register the element factories and pad templates
1.958 + * register the features
1.959 + */
1.960 + static gboolean
1.961 +plugin_init (GstPlugin * plugin)
1.962 +{
1.963 + return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE,
1.964 + GST_TYPE_MYTHTV_SRC);
1.965 +}
1.966 +
1.967 +/* this is the structure that gst-register looks for
1.968 + * so keep the name plugin_desc, or you cannot get your plug-in registered */
1.969 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1.970 + GST_VERSION_MINOR,
1.971 + "mythtv",
1.972 + "lib MythTV src",
1.973 + plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
1.974 +
1.975 +
1.976 +/*** GSTURIHANDLER INTERFACE *************************************************/
1.977 + static guint
1.978 +gst_mythtv_src_uri_get_type (void)
1.979 +{
1.980 + return GST_URI_SRC;
1.981 +}
1.982 +
1.983 + static gchar **
1.984 +gst_mythtv_src_uri_get_protocols (void)
1.985 +{
1.986 + static gchar *protocols[] = { "myth", "myths", NULL };
1.987 +
1.988 + return protocols;
1.989 +}
1.990 +
1.991 + static const gchar *
1.992 +gst_mythtv_src_uri_get_uri (GstURIHandler * handler)
1.993 +{
1.994 + GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
1.995 +
1.996 + return src->uri_name;
1.997 +}
1.998 +
1.999 + static gboolean
1.1000 +gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
1.1001 +{
1.1002 + GstMythtvSrc *src = GST_MYTHTV_SRC (handler);
1.1003 +
1.1004 + gchar *protocol;
1.1005 +
1.1006 + protocol = gst_uri_get_protocol (uri);
1.1007 + if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) {
1.1008 + g_free (protocol);
1.1009 + return FALSE;
1.1010 + }
1.1011 + g_free (protocol);
1.1012 + g_object_set (src, "location", uri, NULL);
1.1013 +
1.1014 + return TRUE;
1.1015 +}
1.1016 +
1.1017 + static void
1.1018 +gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
1.1019 +{
1.1020 + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
1.1021 +
1.1022 + iface->get_type = gst_mythtv_src_uri_get_type;
1.1023 + iface->get_protocols = gst_mythtv_src_uri_get_protocols;
1.1024 + iface->get_uri = gst_mythtv_src_uri_get_uri;
1.1025 + iface->set_uri = gst_mythtv_src_uri_set_uri;
1.1026 +}
1.1027 +
1.1028 + void
1.1029 +size_header_handler (void *userdata, const char *value)
1.1030 +{
1.1031 + GstMythtvSrc *src = GST_MYTHTV_SRC (userdata);
1.1032 +
1.1033 + //src->content_size = g_ascii_strtoull (value, NULL, 10);
1.1034 +
1.1035 + GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size);
1.1036 +}