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