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