# HG changeset patch # User abnerf # Date 1159282717 -3600 # Node ID f3cdc78441781ac3470dba67437cfa9b74534dee # Parent 343d4e3c03ab9d7132bf110f3957532b00068563 [svn r14] new source tree. diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/Makefile.am --- a/gst-plugins-mythtv/Makefile.am Tue Sep 26 15:30:52 2006 +0100 +++ b/gst-plugins-mythtv/Makefile.am Tue Sep 26 15:58:37 2006 +0100 @@ -1,27 +1,3 @@ -plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ +SUBDIRS = src -plugin_LTLIBRARIES = libgstmythtvsrc.la - -libgstmythtvsrc_la_SOURCES = \ - gstmythtvsrc.c \ - myth_uri.c \ - myth_file_transfer.c \ - myth_livetv.c - -libgstmythtvsrc_la_CFLAGS = \ - $(GST_CFLAGS) \ - $(GMYTH_CFLAGS) - -libgstmythtvsrc_la_LDFLAGS = \ - $(GST_PLUGIN_LDFLAGS) - -libgstmythtvsrc_la_LIBADD = \ - $(GST_BASE_LIBS) \ - $(GMYTH_LIBS) - -noinst_HEADERS = \ - gstmythtvsrc.h \ - myth_uri.h \ - myth_file_transfer.h \ - myth_livetv.h - +DIST_SUBDIRS = src diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/configure.ac --- a/gst-plugins-mythtv/configure.ac Tue Sep 26 15:30:52 2006 +0100 +++ b/gst-plugins-mythtv/configure.ac Tue Sep 26 15:58:37 2006 +0100 @@ -5,7 +5,7 @@ AC_INIT([mythtvsrc],[0.1]) -dnl AC_CONFIG_SRCDIR([src/mmyth_main.c]) +dnl AC_CONFIG_SRCDIR([src]) AC_CONFIG_HEADER(config.h) dnl when going to/from release please set the nano (fourth number) right ! @@ -176,6 +176,9 @@ # make GST_MAJORMINOR available in Makefile.am AC_SUBST(GST_MAJORMINOR) -AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([ +Makefile +src/Makefile +]) AC_OUTPUT diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/gstmythtvsrc.c --- a/gst-plugins-mythtv/gstmythtvsrc.c Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,901 +0,0 @@ -/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2 -*- */ -/* GStreamer MythTV Plug-in - * Copyright (C) <2006> Rosfran Borges - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstmythtvsrc.h" -#include "myth_file_transfer.h" -#include "myth_livetv.h" - -#include -#include - -#include -#include - -GST_DEBUG_CATEGORY_STATIC (mythtvsrc_debug); -#define GST_CAT_DEFAULT mythtvsrc_debug - -#define GST_MYTHTV_ID_NUM 1 - -#define MYTHTV_VERSION_DEFAULT 30 - -#define MYTHTV_TRANSFER_MAX_WAITS 100 - -#define MYTHTV_TRANSFER_MAX_BUFFER ( 32*1024 ) - -/* 4*1024 ??? */ -#define MAX_READ_SIZE ( 16*1024 ) - -#define ENABLE_TIMING_POSITION 1 - -/* stablish a maximum iteration value to the IS_RECORDING message */ -static guint wait_to_transfer = 0; - -static const GstElementDetails gst_mythtv_src_details = -GST_ELEMENT_DETAILS ("MythTV client source", - "Source/Network", - "Control and receive data as a client over the network via raw socket connections using the MythTV protocol", - "Rosfran Borges "); - -static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -enum -{ - PROP_0, - PROP_LOCATION, - PROP_URI, -#ifndef GST_DISABLE_GST_DEBUG - PROP_MYTHTV_DBG, -#endif - PROP_MYTHTV_VERSION, - PROP_MYTHTV_LIVE, - PROP_MYTHTV_LIVEID, - PROP_MYTHTV_LIVE_CHAINID -}; - -static void gst_mythtv_src_finalize (GObject * gobject); - -static GstFlowReturn gst_mythtv_src_create (GstBaseSrc * psrc, - guint64 offset, guint size, GstBuffer ** outbuf); -static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc); -static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc); -static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size); -static gboolean gst_mythtv_src_is_seekable( GstBaseSrc *base_src ); - -static void gst_mythtv_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_mythtv_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static void -gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data); - -static gboolean -gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event); - - static void -_urihandler_init (GType type) -{ - static const GInterfaceInfo urihandler_info = { - gst_mythtv_src_uri_handler_init, - NULL, - NULL - }; - - g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); - - GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, - "MythTV src"); -} - -GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstBaseSrc, - GST_TYPE_BASE_SRC, _urihandler_init); - - static void -gst_mythtv_src_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&srctemplate)); - - gst_element_class_set_details (element_class, &gst_mythtv_src_details); -} - - static void -gst_mythtv_src_class_init (GstMythtvSrcClass * klass) -{ - GObjectClass *gobject_class; - GstBaseSrcClass *gstbasesrc_class; - - gobject_class = (GObjectClass *) klass; - gstbasesrc_class = (GstBaseSrcClass *) klass; - - gobject_class->set_property = gst_mythtv_src_set_property; - gobject_class->get_property = gst_mythtv_src_get_property; - gobject_class->finalize = gst_mythtv_src_finalize; - - g_object_class_install_property - (gobject_class, PROP_LOCATION, - g_param_spec_string ("location", "Location", - "The location. In the form:" - "\n\t\t\tmyth://a.com/file.nuv" - "\n\t\t\tmyth://a.com:23223/file.nuv " - "\n\t\t\ta.com/file.nuv - default scheme 'myth'", - "", G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_URI, - g_param_spec_string ("uri", "Uri", - "The location in form of a URI (deprecated; use location)", - "", G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_MYTHTV_VERSION, - g_param_spec_int ("mythtv-version", "mythtv-version", - "Change Myth TV version", - 26, 30, 26, G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_MYTHTV_LIVEID, - g_param_spec_int ("mythtv-live-id", "mythtv-live-id", - "Change Myth TV version", - 0, 200, GST_MYTHTV_ID_NUM, G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_MYTHTV_LIVE_CHAINID, - g_param_spec_string ("mythtv-live-chainid", "mythtv-live-chainid", - "Sets the Myth TV chain ID (from TV Chain)", - "", G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_MYTHTV_LIVE, - g_param_spec_boolean ("mythtv-live", "mythtv-live", - "Enable MythTV Live TV content streaming", - FALSE, G_PARAM_READWRITE)); - -#ifndef GST_DISABLE_GST_DEBUG - g_object_class_install_property - (gobject_class, PROP_MYTHTV_DBG, - g_param_spec_boolean ("mythtv-debug", "mythtv-debug", - "Enable MythTV debug messages", - FALSE, G_PARAM_READWRITE)); -#endif - - gstbasesrc_class->start = gst_mythtv_src_start; - gstbasesrc_class->stop = gst_mythtv_src_stop; - gstbasesrc_class->get_size = gst_mythtv_src_get_size; - gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable; - - gstbasesrc_class->create = gst_mythtv_src_create; - - - GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, - "MythTV Client Source"); -} - - static void -gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class) -{ - this->file_transfer = NULL; - - this->unique_setup = FALSE; - - this->mythtv_version = MYTHTV_VERSION_DEFAULT; - - this->bytes_read = 0; - - this->content_size = -1; - this->read_offset = 0; - - this->live_tv = FALSE; - - this->user_agent = g_strdup ("mythtvsrc"); - this->mythtv_caps = NULL; - - gst_pad_set_event_function (GST_BASE_SRC_PAD(GST_BASE_SRC(this)), - GST_DEBUG_FUNCPTR (gst_mythtv_src_handle_event)); - -} - - static void -gst_mythtv_src_finalize (GObject * gobject) -{ - GstMythtvSrc *this = GST_MYTHTV_SRC (gobject); - - g_free (this->user_agent); - - if (this->mythtv_caps) { - gst_caps_unref (this->mythtv_caps); - this->mythtv_caps = NULL; - } - - if (this->file_transfer) { - g_object_unref (this->file_transfer); - this->file_transfer = NULL; - } - - if (this->uri_name) { - g_free (this->uri_name); - } - - if (this->user_agent) { - g_free (this->user_agent); - } - - G_OBJECT_CLASS (parent_class)->finalize (gobject); -} - -#if 0 - static guint -do_seek( GstMythtvSrc *src, guint64 offset, guint size, GstBuffer *outbuf ) -{ - guint64 off_uint64 = myth_file_transfer_seek(src->file_transfer, offset, 1); - - g_print( "[%s] Call MythTV SEEK with offset %llu, got a new one %llu...\n", __FUNCTION__, - offset, off_uint64 ); - - return off_uint64; - -} -#endif - - static guint -do_read_request_response (GstMythtvSrc * src, guint64 offset, guint size, GstBuffer * outbuf) -{ - guint read = 0; - guint sizetoread = size; //GST_BUFFER_SIZE (outbuf); - - g_print( "[%s] Reading %d bytes...\n", __FUNCTION__, sizetoread ); - - /* Loop sending the request: - * Retry whilst authentication fails and we supply it. */ - - ssize_t len = 0; - - GST_OBJECT_LOCK(src); - - while ( sizetoread > 0 ) { - - len = myth_file_transfer_read( src->file_transfer, - GST_BUFFER_DATA (outbuf) + read, sizetoread, TRUE ); - - if ( len > 0 ) { - read += len; - src->read_offset += read; - sizetoread -= len; - } else if ( len < 0 ) { - goto done; - } - /*else if ( len == 0 ) { - goto eos; - }*/ - - if ( len == sizetoread ) - break; - - } - - if ( read > 0 ) { - src->bytes_read += read; - - GST_BUFFER_SIZE (outbuf) = read; - } else if ( read <= 0 || len <= 0 ) { - if ( src->live_tv == FALSE ) - goto eos; - else - goto done; - } - //GST_BUFFER_OFFSET (outbuf) = src->read_offset; - - g_print( "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\ - "OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read, - src->read_offset, src->content_size ); - - GST_OBJECT_UNLOCK(src); - - if ( len < 0 ) { - read = len; - if ( src->live_tv == FALSE ) - goto eos; - else - goto done; - } - - if ( src->bytes_read < src->content_size ) - goto done; - -eos: - GST_OBJECT_UNLOCK(src); - - src->eos = TRUE; -done: - GST_OBJECT_UNLOCK(src); - - return read; -} - - static GstFlowReturn -gst_mythtv_src_create ( GstBaseSrc * psrc, guint64 offset, - guint size, GstBuffer **outbuf ) -{ - GstMythtvSrc *src; - GstFlowReturn ret = GST_FLOW_OK; - guint read; - guint64 size_tmp = 0; - - src = GST_MYTHTV_SRC (psrc); - - g_print( "[%s]\tBUFFER OFFSET = %llu, BUFFER SIZE = %d.\n", __FUNCTION__, offset, - size ); - - - /* The caller should know the number of bytes and not read beyond EOS. */ - if (G_UNLIKELY (src->eos)) - goto eos; - - /* Create the buffer. */ - ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)), - // GST_BUFFER_OFFSET_NONE, GST_BASE_SRC (psrc)->blocksize, - offset, size, - src->mythtv_caps ? src->mythtv_caps : - GST_PAD_CAPS (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc))), outbuf ); - - if (G_UNLIKELY (ret == GST_FLOW_UNEXPECTED)) - goto eos; - - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto done; - - read = do_read_request_response ( src, offset, size, *outbuf ); - -#if ENABLE_TIMING_POSITION == 1 - if (src->live_tv == TRUE) { - //g_usleep( 1000 ); -get_file_pos: - //g_usleep( 100 ); - size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); - if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) - src->content_size = size_tmp; - else - goto get_file_pos; - g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", - __FUNCTION__, size_tmp); - - } -#endif - - if (G_UNLIKELY (read < 0)) - goto read_error; - - if (G_UNLIKELY(src->eos)) - goto eos; - -done: - return ret; -eos: -#if ENABLE_TIMING_POSITION == 1 - if ( src->live_tv == TRUE ) { - //g_usleep( 1000 ); - guint64 size_tmp = 0; -get_file_pos_eos: - //g_usleep( 100 ); - size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); - if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) - src->content_size = size_tmp; - else - goto get_file_pos_eos; - g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", - __FUNCTION__, size_tmp); - goto done; - } else -#endif - { - GST_DEBUG_OBJECT (src, "EOS reached"); - return GST_FLOW_UNEXPECTED; - } - /* ERRORS */ -read_error: - { - GST_ELEMENT_ERROR (src, RESOURCE, READ, - (NULL), ("Could not read any bytes (%i, %s)", read, - src->uri_name)); - return GST_FLOW_ERROR; - } -} - -#if 0 -/* The following two charset mangling functions were copied from gnomevfssrc. - * Preserve them under the unverified assumption that they do something vaguely - * worthwhile. - */ - static char * -unicodify (const char *str, int len, ...) -{ - char *ret = NULL, *cset; - va_list args; - gsize bytes_read, bytes_written; - - if (g_utf8_validate (str, len, NULL)) - return g_strndup (str, len >= 0 ? len : strlen (str)); - - va_start (args, len); - while ((cset = va_arg (args, char *)) != NULL) - { - if (!strcmp (cset, "locale")) - ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL); - else - ret = g_convert (str, len, "UTF-8", cset, - &bytes_read, &bytes_written, NULL); - if (ret) - break; - } - va_end (args); - - return ret; -} - - static char * -gst_mythtv_src_unicodify (const char *str) -{ - return unicodify (str, -1, "locale", "ISO-8859-1", NULL); -} -#endif - -/* create a socket for connecting to remote server */ - static gboolean -gst_mythtv_src_start ( GstBaseSrc * bsrc ) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc); - - GString *chain_id_local = NULL; - - gboolean ret = TRUE; -#if 0 - if (src->live_tv == TRUE && src->file_transfer != NULL) { - guint64 size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); - if (size_tmp > src->content_size) - src->content_size = size_tmp; - g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", - __FUNCTION__, size_tmp); - } -#endif - if (src->unique_setup == FALSE) { - src->unique_setup = TRUE; - } else { - goto done; - } - - GST_OBJECT_LOCK(src); - - if ( src->live_tv ) { - src->spawn_livetv = myth_livetv_new( ); - if ( myth_livetv_setup( src->spawn_livetv ) == FALSE ) { - ret = FALSE; - goto init_failed; - } - /* set up the uri variable */ - src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str ); - chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain ); - if ( chain_id_local != NULL ) { - src->live_chain_id = g_strdup( chain_id_local->str ); - g_print( "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id ); - } - src->live_tv_id = src->spawn_livetv->remote_encoder->recorder_num; - g_print ( "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name ); - } - - src->file_transfer = myth_file_transfer_new( src->live_tv_id, - g_string_new( src->uri_name ), -1, src->mythtv_version ); - - if ( src->file_transfer == NULL ) { - GST_OBJECT_UNLOCK(src); - - goto init_failed; - } - - if ( src->live_tv ) { - g_print ( "[%s] GST MYTHTVSRC: live_chain_id = %s\n", __FUNCTION__, src->live_chain_id ); - /* sets the MythSocket to the FileTransfer */ - //ret = myth_file_transfer_livetv_setup( &(src->file_transfer), src->spawn_livetv->remote_encoder->myth_socket ); - } - /* sets the Playback monitor connection */ - ret = myth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv ); - - if ( src->live_tv == TRUE && ret == TRUE ) { - /* loop finished, set the max tries variable to zero again... */ - wait_to_transfer = 0; - - while ( wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS && ( myth_file_transfer_is_recording( src->file_transfer ) == FALSE - /*|| ( myth_file_transfer_get_file_position( src->file_transfer ) < ( src->content_size + 327680 ) )*/ ) ) - g_usleep( 100 ); - } - - /* sets the FileTransfer instance connection (video/audio download) */ - ret = myth_file_transfer_setup( &(src->file_transfer), src->live_tv ); - - if ( ret == FALSE ) { - GST_OBJECT_UNLOCK(src); -#ifndef GST_DISABLE_GST_DEBUG - if ( src->mythtv_msgs_dbg ) - g_printerr( "MythTV FileTransfer request failed when setting up socket connection!\n" ); -#endif - goto begin_req_failed; - } - - src->content_size = src->file_transfer->filesize; - - GST_OBJECT_UNLOCK(src); - -#if 0 - const char *str_value; - gint gint_value; - - str_value = ne_get_response_header (src->request, "myth-metaint"); - if (str_value) { - if ( sscanf (str_value, "%d", &gint_value) == 1 ) { - if (src->myth_caps) { - gst_caps_unref (src->myth_caps); - src->myth_caps = NULL; - } - src->myth_metaint = gint_value; -#endif - //src->mythtv_caps = gst_caps_new_simple ("application/x-gst_ff-nuv", NULL); - // } - // } -done: - return TRUE; - - /* ERRORS */ -init_failed: - { - if (src->spawn_livetv != NULL ) - g_object_unref( src->spawn_livetv ); - - GST_ELEMENT_ERROR (src, LIBRARY, INIT, - (NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name)); - return FALSE; - } -begin_req_failed: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, - (NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name)); - return FALSE; - } -} - - static gboolean -gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size) -{ - GstMythtvSrc *src; - - src = GST_MYTHTV_SRC (bsrc); -#if ENABLE_TIMING_POSITION == 1 - guint64 size_tmp = 0; - if (src->live_tv == TRUE) { -get_file_pos: - //g_usleep( 100 ); - size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); - if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) - src->content_size = size_tmp; - else - goto get_file_pos; - g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", - __FUNCTION__, size_tmp); - } -#endif - if (src->content_size <= 0) - return FALSE; - - *size = src->content_size; - - return TRUE; -} - -/* close the socket and associated resources - * used both to recover from errors and go to NULL state */ - static gboolean -gst_mythtv_src_stop (GstBaseSrc * bsrc) -{ - GstMythtvSrc *src; - - src = GST_MYTHTV_SRC (bsrc); - - if (src->uri_name) { - g_free (src->uri_name); - src->uri_name = NULL; - } - - if (src->mythtv_caps) { - gst_caps_unref (src->mythtv_caps); - src->mythtv_caps = NULL; - } - - src->eos = FALSE; - - return TRUE; -} - - static gboolean -gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - src->eos = FALSE; - break; - //return TRUE; - case GST_EVENT_FLUSH_STOP: - src->do_start = TRUE; - src->eos = FALSE; - gst_element_set_state (GST_ELEMENT(src), GST_STATE_NULL); - gst_element_set_locked_state (GST_ELEMENT(src), TRUE); - break; - case GST_EVENT_SEEK: - { - gdouble rate; - //gboolean update = TRUE; - GstFormat format; - GstSeekType cur_type, stop_type; - GstSeekFlags flags; - gint64 cur = 0, stop = 0; - gst_event_parse_seek ( event, &rate, &format, - &flags, &cur_type, &cur, - &stop_type, &stop ); - - g_print( "[%s] Got EVENT_SEEK.\n", __FUNCTION__ ); - if ( !( flags & GST_SEEK_FLAG_FLUSH ) ) { - g_print( "[%s] Could get the FLAG_FLUSH message.\n", __FUNCTION__ ); - } - //gboolean ret = gst_event_parse_new_segment ( event, - // &update, &rate, &format, &start, &stop, - // &position ); - //GstFlowReturn flow_ret = gst_mythtv_src_create (GST_BASE_SRC( GST_PAD_PARENT( psrc ) ), - // cur, stop - cur + 1, GstBuffer) - - } - default: - return gst_pad_event_default (pad, event); - } - - return gst_pad_event_default (pad, event); -} - - static gboolean -gst_mythtv_src_is_seekable( GstBaseSrc *base_src ) -{ - return TRUE; -} - - static void -gst_mythtv_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object); - - GST_OBJECT_LOCK (mythtvsrc); - switch (prop_id) { - case PROP_URI: - case PROP_LOCATION: - { - if (!g_value_get_string (value)) { - GST_WARNING ("location property cannot be NULL"); - goto done; - } - - if (mythtvsrc->uri_name != NULL) { - g_free (mythtvsrc->uri_name); - mythtvsrc->uri_name = NULL; - } - mythtvsrc->uri_name = g_value_dup_string (value); - - break; - } -#ifndef GST_DISABLE_GST_DEBUG - case PROP_MYTHTV_DBG: - { - mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value); - break; - } -#endif - case PROP_MYTHTV_VERSION: - { - mythtvsrc->mythtv_version = g_value_get_int (value); - break; - } - case PROP_MYTHTV_LIVEID: - { - mythtvsrc->live_tv_id = g_value_get_int (value); - break; - } - case PROP_MYTHTV_LIVE: - { - mythtvsrc->live_tv = g_value_get_boolean (value); - break; - } - case PROP_MYTHTV_LIVE_CHAINID: - { - if (!g_value_get_string (value)) { - GST_WARNING ("MythTV Live chainid property cannot be NULL"); - goto done; - } - - if (mythtvsrc->live_chain_id != NULL) { - g_free (mythtvsrc->live_chain_id); - mythtvsrc->live_chain_id = NULL; - } - mythtvsrc->live_chain_id = g_value_dup_string (value); - - break; - } - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - GST_OBJECT_UNLOCK (mythtvsrc); -done: - return; -} - - static void -gst_mythtv_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object); - - GST_OBJECT_LOCK (mythtvsrc); - switch (prop_id) { - case PROP_URI: - case PROP_LOCATION: - { - gchar *str = g_strdup( "" ); - - if ( mythtvsrc->uri_name == NULL ) { - g_free (mythtvsrc->uri_name); - mythtvsrc->uri_name = NULL; - } else { - str = g_strdup( mythtvsrc->uri_name ); - } - g_value_set_string ( value, str ); - break; - } -#ifndef GST_DISABLE_GST_DEBUG - case PROP_MYTHTV_DBG: - g_value_set_boolean ( value, mythtvsrc->mythtv_msgs_dbg ); - break; -#endif - case PROP_MYTHTV_VERSION: - { - g_value_set_int ( value, mythtvsrc->mythtv_version ); - break; - } - case PROP_MYTHTV_LIVEID: - { - g_value_set_int ( value, mythtvsrc->live_tv_id ); - break; - } - case PROP_MYTHTV_LIVE: - g_value_set_boolean ( value, mythtvsrc->live_tv ); - break; - case PROP_MYTHTV_LIVE_CHAINID: - { - gchar *str = g_strdup( "" ); - - if ( mythtvsrc->live_chain_id == NULL ) { - g_free (mythtvsrc->live_chain_id); - mythtvsrc->live_chain_id = NULL; - } else { - str = g_strdup( mythtvsrc->live_chain_id ); - } - g_value_set_string ( value, str ); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - GST_OBJECT_UNLOCK (mythtvsrc); -} - -/* entry point to initialize the plug-in - * initialize the plug-in itself - * register the element factories and pad templates - * register the features - */ - static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE, - GST_TYPE_MYTHTV_SRC); -} - -/* this is the structure that gst-register looks for - * so keep the name plugin_desc, or you cannot get your plug-in registered */ -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "mythtv", - "lib MythTV src", - plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") - - -/*** GSTURIHANDLER INTERFACE *************************************************/ - static guint -gst_mythtv_src_uri_get_type (void) -{ - return GST_URI_SRC; -} - - static gchar ** -gst_mythtv_src_uri_get_protocols (void) -{ - static gchar *protocols[] = { "myth", "myths", NULL }; - - return protocols; -} - - static const gchar * -gst_mythtv_src_uri_get_uri (GstURIHandler * handler) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (handler); - - return src->uri_name; -} - - static gboolean -gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (handler); - - gchar *protocol; - - protocol = gst_uri_get_protocol (uri); - if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) { - g_free (protocol); - return FALSE; - } - g_free (protocol); - g_object_set (src, "location", uri, NULL); - - return TRUE; -} - - static void -gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; - - iface->get_type = gst_mythtv_src_uri_get_type; - iface->get_protocols = gst_mythtv_src_uri_get_protocols; - iface->get_uri = gst_mythtv_src_uri_get_uri; - iface->set_uri = gst_mythtv_src_uri_set_uri; -} - - void -size_header_handler (void *userdata, const char *value) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (userdata); - - //src->content_size = g_ascii_strtoull (value, NULL, 10); - - GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size); -} diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/gstmythtvsrc.c.new --- a/gst-plugins-mythtv/gstmythtvsrc.c.new Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1033 +0,0 @@ -/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2 -*- */ -/* GStreamer MythTV Plug-in - * Copyright (C) <2006> Rosfran Borges - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstmythtvsrc.h" -#include "myth_file_transfer.h" -#include "myth_livetv.h" - -#include -#include - -#include -#include - -GST_DEBUG_CATEGORY_STATIC (mythtvsrc_debug); -#define GST_CAT_DEFAULT mythtvsrc_debug - -#define GST_MYTHTV_ID_NUM 1 - -#define MYTHTV_VERSION_DEFAULT 30 - -#define MYTHTV_TRANSFER_MAX_WAITS 100 - -#define MYTHTV_TRANSFER_MAX_BUFFER ( 32*1024 ) - -/* 4*1024 ??? */ -#define MAX_READ_SIZE ( 16*1024 ) - -#define ENABLE_TIMING_POSITION 1 - -/* stablish a maximum iteration value to the IS_RECORDING message */ -static guint wait_to_transfer = 0; - -static const GstElementDetails gst_mythtv_src_details = -GST_ELEMENT_DETAILS ("MythTV client source", - "Source/Network", - "Control and receive data as a client over the network via raw socket connections using the MythTV protocol", - "Rosfran Borges "); - -static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static GstTask *update_size_task = NULL; - -static GStaticRecMutex update_size_mutex = G_STATIC_REC_MUTEX_INIT; - -enum -{ - PROP_0, - PROP_LOCATION, - PROP_URI, -#ifndef GST_DISABLE_GST_DEBUG - PROP_MYTHTV_DBG, -#endif - PROP_MYTHTV_VERSION, - PROP_MYTHTV_LIVE, - PROP_MYTHTV_LIVEID, - PROP_MYTHTV_LIVE_CHAINID -}; - -static void gst_mythtv_src_finalize (GObject * gobject); - -static GstFlowReturn gst_mythtv_src_create (GstBaseSrc * psrc, - guint64 offset, guint size, GstBuffer ** outbuf); -static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc); -static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc); -static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size); -static gboolean gst_mythtv_src_is_seekable( GstBaseSrc *base_src ); - -static void gst_mythtv_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_mythtv_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static void -gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data); - -static gboolean -gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event); - - static void -_urihandler_init (GType type) -{ - static const GInterfaceInfo urihandler_info = { - gst_mythtv_src_uri_handler_init, - NULL, - NULL - }; - - g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); - - GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, - "MythTV src"); -} - -GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstBaseSrc, - GST_TYPE_BASE_SRC, _urihandler_init); - - static void -gst_mythtv_src_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&srctemplate)); - - gst_element_class_set_details (element_class, &gst_mythtv_src_details); -} - - static void -gst_mythtv_src_class_init (GstMythtvSrcClass * klass) -{ - GObjectClass *gobject_class; - GstBaseSrcClass *gstbasesrc_class; - - gobject_class = (GObjectClass *) klass; - gstbasesrc_class = (GstBaseSrcClass *) klass; - - gobject_class->set_property = gst_mythtv_src_set_property; - gobject_class->get_property = gst_mythtv_src_get_property; - gobject_class->finalize = gst_mythtv_src_finalize; - - g_object_class_install_property - (gobject_class, PROP_LOCATION, - g_param_spec_string ("location", "Location", - "The location. In the form:" - "\n\t\t\tmyth://a.com/file.nuv" - "\n\t\t\tmyth://a.com:23223/file.nuv " - "\n\t\t\ta.com/file.nuv - default scheme 'myth'", - "", G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_URI, - g_param_spec_string ("uri", "Uri", - "The location in form of a URI (deprecated; use location)", - "", G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_MYTHTV_VERSION, - g_param_spec_int ("mythtv-version", "mythtv-version", - "Change Myth TV version", - 26, 30, 26, G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_MYTHTV_LIVEID, - g_param_spec_int ("mythtv-live-id", "mythtv-live-id", - "Change Myth TV version", - 0, 200, GST_MYTHTV_ID_NUM, G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_MYTHTV_LIVE_CHAINID, - g_param_spec_string ("mythtv-live-chainid", "mythtv-live-chainid", - "Sets the Myth TV chain ID (from TV Chain)", - "", G_PARAM_READWRITE)); - - g_object_class_install_property - (gobject_class, PROP_MYTHTV_LIVE, - g_param_spec_boolean ("mythtv-live", "mythtv-live", - "Enable MythTV Live TV content streaming", - FALSE, G_PARAM_READWRITE)); - -#ifndef GST_DISABLE_GST_DEBUG - g_object_class_install_property - (gobject_class, PROP_MYTHTV_DBG, - g_param_spec_boolean ("mythtv-debug", "mythtv-debug", - "Enable MythTV debug messages", - FALSE, G_PARAM_READWRITE)); -#endif - - gstbasesrc_class->start = gst_mythtv_src_start; - gstbasesrc_class->stop = gst_mythtv_src_stop; - gstbasesrc_class->get_size = gst_mythtv_src_get_size; - gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable; - - gstbasesrc_class->create = gst_mythtv_src_create; - - GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, - "MythTV Client Source"); -} - - static void -gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class) -{ - this->file_transfer = NULL; - - this->unique_setup = FALSE; - - this->mythtv_version = MYTHTV_VERSION_DEFAULT; - - this->bytes_read = 0; - - this->content_size = -1; - this->read_offset = 0; - - this->live_tv = FALSE; - - this->user_agent = g_strdup ("mythtvsrc"); - this->mythtv_caps = NULL; - - gst_base_src_set_live ( GST_BASE_SRC( this ), TRUE ); - - gst_pad_set_event_function (GST_BASE_SRC_PAD(GST_BASE_SRC(this)), - GST_DEBUG_FUNCPTR (gst_mythtv_src_handle_event)); - -} - - static void -gst_mythtv_src_finalize (GObject * gobject) -{ - GstMythtvSrc *this = GST_MYTHTV_SRC (gobject); - - g_free (this->user_agent); - - if (this->mythtv_caps) { - gst_caps_unref (this->mythtv_caps); - this->mythtv_caps = NULL; - } - - if (this->file_transfer) { - g_object_unref (this->file_transfer); - this->file_transfer = NULL; - } - - if (this->uri_name) { - g_free (this->uri_name); - } - - if (this->user_agent) { - g_free (this->user_agent); - } - - if ( update_size_task != NULL ) { - - if ( GST_TASK_STATE( update_size_task ) != GST_TASK_STOPPED ) - gst_task_stop( update_size_task ); - - gst_object_unref( update_size_task ); - - update_size_task = NULL; - - } - - G_OBJECT_CLASS (parent_class)->finalize (gobject); -} - -#if 0 - static guint -do_seek( GstMythtvSrc *src, guint64 offset, guint size, GstBuffer *outbuf ) -{ - guint64 off_uint64 = myth_file_transfer_seek(src->file_transfer, offset, 1); - - g_print( "[%s] Call MythTV SEEK with offset %llu, got a new one %llu...\n", __FUNCTION__, - offset, off_uint64 ); - - return off_uint64; - -} -#endif - - static guint -do_read_request_response (GstMythtvSrc * src, guint64 offset, guint size, GstBuffer * outbuf) -{ - guint read = 0; - guint sizetoread = size; //GST_BUFFER_SIZE (outbuf); - - g_print( "[%s] Reading %d bytes...\n", __FUNCTION__, sizetoread ); - - /* Loop sending the request: - * Retry whilst authentication fails and we supply it. */ - - ssize_t len = 0; - - //GST_OBJECT_LOCK(src); - - while ( sizetoread > 0 ) { - - len = myth_file_transfer_read( src->file_transfer, - GST_BUFFER_DATA (outbuf) + read, sizetoread, TRUE ); - - if ( len > 0 ) { - read += len; - src->read_offset += read; - sizetoread -= len; - } else if ( len < 0 ) { - goto done; - } - else if ( len == 0 ) { - if ( src->live_tv == FALSE ) - goto done; - else - goto eos; - - } - - if ( len == sizetoread ) - break; - - } - - if ( read > 0 ) { - src->bytes_read += read; - - GST_BUFFER_SIZE (outbuf) = read; - } else if ( read <= 0 || len <= 0 ) { - if ( src->live_tv == FALSE ) - goto eos; - else - goto done; - } - //GST_BUFFER_OFFSET (outbuf) = src->read_offset; - - g_print( "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\ - "OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read, - src->read_offset, src->content_size ); - - //GST_OBJECT_UNLOCK(src); - - if ( len < 0 ) { - read = len; - if ( src->live_tv == FALSE ) - goto eos; - else - goto done; - } - - if ( src->bytes_read < src->content_size ) - goto done; - -eos: - //GST_OBJECT_UNLOCK(src); - - src->eos = TRUE; -done: - //GST_OBJECT_UNLOCK(src); - - return read; -} - - static GstFlowReturn -gst_mythtv_src_create ( GstBaseSrc * psrc, guint64 offset, - guint size, GstBuffer **outbuf ) -{ - GstMythtvSrc *src; - GstFlowReturn ret = GST_FLOW_OK; - guint read = 0; - - src = GST_MYTHTV_SRC (psrc); - - //src->do_start = FALSE; - src->do_start = FALSE; - gst_task_join ( update_size_task ); - - g_print( "[%s]\tBUFFER OFFSET = %llu, BUFFER SIZE = %d.\n", __FUNCTION__, offset, - size ); - - /* The caller should know the number of bytes and not read beyond EOS. */ - //if (G_UNLIKELY (src->eos)) - // goto eos; - //g_static_rec_mutex_lock( &update_size_mutex ); - - /* Create the buffer. */ - ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)), - // GST_BUFFER_OFFSET_NONE, GST_BASE_SRC (psrc)->blocksize, - offset, size, - src->mythtv_caps ? src->mythtv_caps : - GST_PAD_CAPS (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc))), outbuf ); - - //if (G_UNLIKELY (ret == GST_FLOW_UNEXPECTED)) - // goto eos; - - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto eos; - - if (G_UNLIKELY (ret == GST_FLOW_ERROR)) - goto read_error; - - read = do_read_request_response ( src, offset, size, *outbuf ); - - //g_static_rec_mutex_unlock( &update_size_mutex ); - - src->do_start = TRUE; - gst_task_start ( update_size_task ); - -#if 0 - g_static_rec_mutex_lock( &update_size_mutex ); - src->do_start = FALSE; - g_static_rec_mutex_unlock( &update_size_mutex ); - GST_TASK_SIGNAL( update_size_task ); -#endif - - //g_static_rec_mutex_unlock( &update_size_mutex ); - -#if 0 -#if ENABLE_TIMING_POSITION == 1 - guint64 size_tmp = 0; - if (src->live_tv == TRUE) { - //g_usleep( 1000 ); -get_file_pos: - //g_usleep( 100 ); - size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); - if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) - src->content_size = size_tmp; - else - goto get_file_pos; - g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", - __FUNCTION__, size_tmp); - - } -#endif -#endif - - //if (G_UNLIKELY (read < 0)) - // goto read_error; - - if (G_UNLIKELY(src->eos)) - goto eos; - else - goto done; - -done: - return ret; -eos: -#if 0 -#if ENABLE_TIMING_POSITION == 1 - if ( src->live_tv == TRUE ) { - //g_usleep( 1000 ); - guint64 size_tmp = 0; -get_file_pos_eos: - //g_usleep( 100 ); - size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); - if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) - src->content_size = size_tmp; - else - goto get_file_pos_eos; - g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", - __FUNCTION__, size_tmp); - goto done; - } else -#endif -#endif - { - GST_DEBUG_OBJECT (src, "EOS reached"); - return GST_FLOW_UNEXPECTED; - } - /* ERRORS */ -read_error: - { - GST_ELEMENT_ERROR (src, RESOURCE, READ, - (NULL), ("Could not read any bytes (%i, %s)", read, - src->uri_name)); - return GST_FLOW_ERROR; - } - #if 0 -need_pause: - { - const gchar *reason = gst_flow_get_name (ret); - - GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason); - return GST_FLOW_UNEXPECTED; - } - #endif - -} - -#if 0 -/* The following two charset mangling functions were copied from gnomevfssrc. - * Preserve them under the unverified assumption that they do something vaguely - * worthwhile. - */ - static char * -unicodify (const char *str, int len, ...) -{ - char *ret = NULL, *cset; - va_list args; - gsize bytes_read, bytes_written; - - if (g_utf8_validate (str, len, NULL)) - return g_strndup (str, len >= 0 ? len : strlen (str)); - - va_start (args, len); - while ((cset = va_arg (args, char *)) != NULL) - { - if (!strcmp (cset, "locale")) - ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL); - else - ret = g_convert (str, len, "UTF-8", cset, - &bytes_read, &bytes_written, NULL); - if (ret) - break; - } - va_end (args); - - return ret; -} - - static char * -gst_mythtv_src_unicodify (const char *str) -{ - return unicodify (str, -1, "locale", "ISO-8859-1", NULL); -} -#endif - -void -update_size_func( void *mythtv_data ) -{ - GstMythtvSrc *src; - - g_return_if_fail( mythtv_data != NULL ); - - src = GST_MYTHTV_SRC ( mythtv_data ); - if ( src->do_start ) { - #if ENABLE_TIMING_POSITION == 1 - guint64 size_tmp = 0; - if (src->live_tv == TRUE) { -get_file_pos: - //g_usleep( 50 ); - size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); - if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) - src->content_size = size_tmp; - else - goto get_file_pos; - g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", - __FUNCTION__, size_tmp ); - } -#endif -} - gst_task_pause( update_size_task ); - // src->do_start = FALSE; - //GST_TASK_SIGNAL( update_size_task ); - -} - -/* create a socket for connecting to remote server */ - static gboolean -gst_mythtv_src_start ( GstBaseSrc * bsrc ) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc); - - GString *chain_id_local = NULL; - - gboolean ret = TRUE; -#if 0 - if (src->live_tv == TRUE && src->file_transfer != NULL) { - guint64 size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); - if (size_tmp > src->content_size) - src->content_size = size_tmp; - g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", - __FUNCTION__, size_tmp); - } -#endif - if (src->unique_setup == FALSE) { - src->unique_setup = TRUE; - } else { - goto done; - } - - //GST_OBJECT_LOCK(src); - - if ( src->live_tv ) { - src->spawn_livetv = myth_livetv_new( ); - if ( myth_livetv_setup( src->spawn_livetv ) == FALSE ) { - ret = FALSE; - goto init_failed; - } - /* set up the uri variable */ - src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str ); - chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain ); - if ( chain_id_local != NULL ) { - src->live_chain_id = g_strdup( chain_id_local->str ); - g_print( "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id ); - } - src->live_tv_id = src->spawn_livetv->remote_encoder->recorder_num; - g_print ( "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name ); - } - - src->file_transfer = myth_file_transfer_new( src->live_tv_id, - g_string_new( src->uri_name ), -1, src->mythtv_version ); - - if ( src->file_transfer == NULL ) { - //GST_OBJECT_UNLOCK(src); - - goto init_failed; - } - - if ( src->live_tv ) { - g_print ( "[%s] GST MYTHTVSRC: live_chain_id = %s\n", __FUNCTION__, src->live_chain_id ); - /* sets the MythSocket to the FileTransfer */ - //ret = myth_file_transfer_livetv_setup( &(src->file_transfer), src->spawn_livetv->remote_encoder->myth_socket ); - } - /* sets the Playback monitor connection */ - ret = myth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv ); - - if ( src->live_tv == TRUE && ret == TRUE ) { - /* loop finished, set the max tries variable to zero again... */ - wait_to_transfer = 0; - - while ( wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS && ( myth_file_transfer_is_recording( src->file_transfer ) == FALSE - /*|| ( myth_file_transfer_get_file_position( src->file_transfer ) < ( src->content_size + 327680 ) )*/ ) ) - g_usleep( 100 ); - } - - /* sets the FileTransfer instance connection (video/audio download) */ - ret = myth_file_transfer_setup( &(src->file_transfer), src->live_tv ); - - if ( ret == FALSE ) { - //GST_OBJECT_UNLOCK(src); -#ifndef GST_DISABLE_GST_DEBUG - if ( src->mythtv_msgs_dbg ) - g_printerr( "MythTV FileTransfer request failed when setting up socket connection!\n" ); -#endif - goto begin_req_failed; - } - - src->content_size = src->file_transfer->filesize; - - //GST_OBJECT_UNLOCK(src); - - update_size_task = gst_task_create( update_size_func, src ); - - gst_task_set_lock( update_size_task, &update_size_mutex ); - - g_print( "[%s] Update Size task = %s\n", __FUNCTION__, gst_task_start( update_size_task ) && - GST_TASK_STATE( update_size_task ) == GST_TASK_STARTED ? "OK !" : "ERROR!!!" ); - - src->do_start = TRUE; - -#if 0 - const char *str_value; - gint gint_value; - - str_value = ne_get_response_header (src->request, "myth-metaint"); - if (str_value) { - if ( sscanf (str_value, "%d", &gint_value) == 1 ) { - if (src->myth_caps) { - gst_caps_unref (src->myth_caps); - src->myth_caps = NULL; - } - src->myth_metaint = gint_value; -#endif - //src->mythtv_caps = gst_caps_new_simple ("application/x-gst_ff-nuv", NULL); - // } - // } -done: - return TRUE; - - /* ERRORS */ -init_failed: - { - if (src->spawn_livetv != NULL ) - g_object_unref( src->spawn_livetv ); - - GST_ELEMENT_ERROR (src, LIBRARY, INIT, - (NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name)); - return FALSE; - } -begin_req_failed: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, - (NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name)); - return FALSE; - } -} - -#if 0 -static gboolean -gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size) -{ - GstMythtvSrc *src; - gboolean ret = FALSE; - - src = GST_MYTHTV_SRC (bsrc); - - g_static_rec_mutex_lock( &update_size_mutex ); - src->do_start = FALSE; - g_static_rec_mutex_unlock( &update_size_mutex ); - GST_TASK_SIGNAL( update_size_task ); - - - while (1) { - - g_static_rec_mutex_lock( &update_size_mutex ); - if ( !src->do_start ) { - - g_print( "[%s] GET SIZE: do_start? == %s\n", __FUNCTION__, src->do_start ? "YES" : "NO" ); - - GST_TASK_WAIT( update_size_task ); - } else { - if (src->content_size <= 0) { - g_static_rec_mutex_unlock( &update_size_mutex ); - goto done; - } - - *size = src->content_size; - src->do_start = FALSE; - - g_static_rec_mutex_unlock( &update_size_mutex ); - - break; - } - g_static_rec_mutex_unlock( &update_size_mutex ); - - } // while (1) - -done: - return ret; - -} -#endif - -static gboolean -gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size) -{ - GstMythtvSrc *src; - gboolean ret = TRUE; - - src = GST_MYTHTV_SRC (bsrc); - - if (src->content_size <= 0) - ret= FALSE; - - *size = src->content_size; - - return ret; - -} -/* close the socket and associated resources - * used both to recover from errors and go to NULL state */ - static gboolean -gst_mythtv_src_stop (GstBaseSrc * bsrc) -{ - GstMythtvSrc *src; - - src = GST_MYTHTV_SRC (bsrc); - - if (src->uri_name) { - g_free (src->uri_name); - src->uri_name = NULL; - } - - if (src->mythtv_caps) { - gst_caps_unref (src->mythtv_caps); - src->mythtv_caps = NULL; - } - - src->eos = FALSE; - - return TRUE; -} - - static gboolean -gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - src->eos = FALSE; - break; - //return TRUE; -#if 0 -case GST_EVENT_FLUSH_STOP: - src->do_start = TRUE; - src->eos = FALSE; - gst_element_set_state (GST_ELEMENT(src), GST_STATE_NULL); - //gst_element_set_locked_state (GST_ELEMENT(src), TRUE); - break; -#endif - case GST_EVENT_SEEK: - { - gdouble rate; - //gboolean update = TRUE; - GstFormat format; - GstSeekType cur_type, stop_type; - GstSeekFlags flags; - gint64 cur = 0, stop = 0; - gst_event_parse_seek ( event, &rate, &format, - &flags, &cur_type, &cur, - &stop_type, &stop ); - - g_print( "[%s] Got EVENT_SEEK.\n", __FUNCTION__ ); - if ( !( flags & GST_SEEK_FLAG_FLUSH ) ) { - g_print( "[%s] Could get the FLAG_FLUSH message.\n", __FUNCTION__ ); - } - //gboolean ret = gst_event_parse_new_segment ( event, - // &update, &rate, &format, &start, &stop, - // &position ); - //GstFlowReturn flow_ret = gst_mythtv_src_create (GST_BASE_SRC( GST_PAD_PARENT( psrc ) ), - // cur, stop - cur + 1, GstBuffer) - - } - default: - return gst_pad_event_default (pad, event); - } - - return gst_pad_event_default (pad, event); -} - - static gboolean -gst_mythtv_src_is_seekable( GstBaseSrc *base_src ) -{ - return TRUE; -} - - static void -gst_mythtv_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object); - - GST_OBJECT_LOCK (mythtvsrc); - switch (prop_id) { - case PROP_URI: - case PROP_LOCATION: - { - if (!g_value_get_string (value)) { - GST_WARNING ("location property cannot be NULL"); - goto done; - } - - if (mythtvsrc->uri_name != NULL) { - g_free (mythtvsrc->uri_name); - mythtvsrc->uri_name = NULL; - } - mythtvsrc->uri_name = g_value_dup_string (value); - - break; - } -#ifndef GST_DISABLE_GST_DEBUG - case PROP_MYTHTV_DBG: - { - mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value); - break; - } -#endif - case PROP_MYTHTV_VERSION: - { - mythtvsrc->mythtv_version = g_value_get_int (value); - break; - } - case PROP_MYTHTV_LIVEID: - { - mythtvsrc->live_tv_id = g_value_get_int (value); - break; - } - case PROP_MYTHTV_LIVE: - { - mythtvsrc->live_tv = g_value_get_boolean (value); - break; - } - case PROP_MYTHTV_LIVE_CHAINID: - { - if (!g_value_get_string (value)) { - GST_WARNING ("MythTV Live chainid property cannot be NULL"); - goto done; - } - - if (mythtvsrc->live_chain_id != NULL) { - g_free (mythtvsrc->live_chain_id); - mythtvsrc->live_chain_id = NULL; - } - mythtvsrc->live_chain_id = g_value_dup_string (value); - - break; - } - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - GST_OBJECT_UNLOCK (mythtvsrc); -done: - return; -} - - static void -gst_mythtv_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object); - - GST_OBJECT_LOCK (mythtvsrc); - switch (prop_id) { - case PROP_URI: - case PROP_LOCATION: - { - gchar *str = g_strdup( "" ); - - if ( mythtvsrc->uri_name == NULL ) { - g_free (mythtvsrc->uri_name); - mythtvsrc->uri_name = NULL; - } else { - str = g_strdup( mythtvsrc->uri_name ); - } - g_value_set_string ( value, str ); - break; - } -#ifndef GST_DISABLE_GST_DEBUG - case PROP_MYTHTV_DBG: - g_value_set_boolean ( value, mythtvsrc->mythtv_msgs_dbg ); - break; -#endif - case PROP_MYTHTV_VERSION: - { - g_value_set_int ( value, mythtvsrc->mythtv_version ); - break; - } - case PROP_MYTHTV_LIVEID: - { - g_value_set_int ( value, mythtvsrc->live_tv_id ); - break; - } - case PROP_MYTHTV_LIVE: - g_value_set_boolean ( value, mythtvsrc->live_tv ); - break; - case PROP_MYTHTV_LIVE_CHAINID: - { - gchar *str = g_strdup( "" ); - - if ( mythtvsrc->live_chain_id == NULL ) { - g_free (mythtvsrc->live_chain_id); - mythtvsrc->live_chain_id = NULL; - } else { - str = g_strdup( mythtvsrc->live_chain_id ); - } - g_value_set_string ( value, str ); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - GST_OBJECT_UNLOCK (mythtvsrc); -} - -/* entry point to initialize the plug-in - * initialize the plug-in itself - * register the element factories and pad templates - * register the features - */ - static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE, - GST_TYPE_MYTHTV_SRC); -} - -/* this is the structure that gst-register looks for - * so keep the name plugin_desc, or you cannot get your plug-in registered */ -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "mythtv", - "lib MythTV src", - plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") - - -/*** GSTURIHANDLER INTERFACE *************************************************/ - static guint -gst_mythtv_src_uri_get_type (void) -{ - return GST_URI_SRC; -} - - static gchar ** -gst_mythtv_src_uri_get_protocols (void) -{ - static gchar *protocols[] = { "myth", "myths", NULL }; - - return protocols; -} - - static const gchar * -gst_mythtv_src_uri_get_uri (GstURIHandler * handler) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (handler); - - return src->uri_name; -} - - static gboolean -gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (handler); - - gchar *protocol; - - protocol = gst_uri_get_protocol (uri); - if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) { - g_free (protocol); - return FALSE; - } - g_free (protocol); - g_object_set (src, "location", uri, NULL); - - return TRUE; -} - - static void -gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; - - iface->get_type = gst_mythtv_src_uri_get_type; - iface->get_protocols = gst_mythtv_src_uri_get_protocols; - iface->get_uri = gst_mythtv_src_uri_get_uri; - iface->set_uri = gst_mythtv_src_uri_set_uri; -} - - void -size_header_handler (void *userdata, const char *value) -{ - GstMythtvSrc *src = GST_MYTHTV_SRC (userdata); - - //src->content_size = g_ascii_strtoull (value, NULL, 10); - - GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size); -} diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/gstmythtvsrc.h --- a/gst-plugins-mythtv/gstmythtvsrc.h Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2 -*- */ -/* GStreamer - * Copyright (C) <2006> Rosfran Borges - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more - */ - -#ifndef __GST_MYTHTV_SRC_H__ -#define __GST_MYTHTV_SRC_H__ - -#include -#include -#include - -#include -#include "myth_file_transfer.h" -#include "myth_livetv.h" - -G_BEGIN_DECLS - -#define GST_TYPE_MYTHTV_SRC \ - (gst_mythtv_src_get_type()) -#define GST_MYTHTV_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MYTHTV_SRC,GstMythtvSrc)) -#define GST_MYTHTV_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MYTHTV_SRC,GstMythtvSrcClass)) -#define GST_IS_MYTHTV_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MYTHTV_SRC)) -#define GST_IS_MYTHTV_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MYTHTV_SRC)) - -typedef struct _GstMythtvSrc GstMythtvSrc; -typedef struct _GstMythtvSrcClass GstMythtvSrcClass; - -struct _GstMythtvSrc { - GstBaseSrc element; - - /* MythFileTransfer */ - MythFileTransfer *file_transfer; - - MythLiveTV *spawn_livetv; - - gchar *uri_name; - gchar *user_agent; - - gchar *live_chain_id; - - gint mythtv_version; - - guint64 content_size; - - guint64 bytes_read; - - guint64 read_offset; - - gboolean eos; - - gboolean do_start; - - gboolean unique_setup; - - gboolean live_tv; - - gint live_tv_id; - - /* MythTV capabilities */ - GstCaps *mythtv_caps; - - /* enable Myth TV debug messages */ - gboolean mythtv_msgs_dbg; -}; - -struct _GstMythtvSrcClass { - GstBaseSrcClass parent_class; -}; - -GType gst_mythtv_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_MYTHTV_SRC_H__ */ diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/myth_file_transfer.c --- a/gst-plugins-mythtv/myth_file_transfer.c Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,960 +0,0 @@ -/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */ -/** - * GStreamer plug-in properties: - * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv] - * - path (qurl - remote file to be opened) - * - port number - * @author Rosfran Lins Borges - */ - -#include "myth_file_transfer.h" -#include "myth_uri.h" -#include "myth_livetv.h" -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#define MYTHTV_QUERY_HEADER "QUERY_FILETRANSFER" -#define MYTHTV_RECORDER_HEADER "QUERY_RECORDER" - -/* default values to the file transfer parameters */ -#define MYTHTV_USER_READ_AHEAD FALSE -#define MYTHTV_RETRIES 1 -#define MYTHTV_FILE_SIZE -1 - -#define MYTHTV_BUFFER_SIZE 2048 - -#define MYTHTV_VERSION 30 - -#define MYTHTV_TRANSFER_MAX_WAITS 700 - -#ifdef MYTHTV_ENABLE_DEBUG -#define MYTHTV_ENABLE_DEBUG 1 -#else -#undef MYTHTV_ENABLE_DEBUG -#endif - -/* this NDEBUG is to maintain compatibility with GMyth library */ -#ifndef NDEBUG -#define MYTHTV_ENABLE_DEBUG 1 -#endif - -static guint wait_to_transfer = 0; - -enum myth_sock_types { - MYTH_PLAYBACK_TYPE = 0, - MYTH_MONITOR_TYPE, - MYTH_FILETRANSFER_TYPE, - MYTH_RINGBUFFER_TYPE -}; - -static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - -static void myth_file_transfer_class_init (MythFileTransferClass *klass); -static void myth_file_transfer_init (MythFileTransfer *object); - -static void myth_file_transfer_dispose (GObject *object); -static void myth_file_transfer_finalize (GObject *object); - -static GMythSocket *myth_connect_to_transfer_backend( MythFileTransfer **transfer, guint sock_type ); -static void* myth_init_io_watchers( void *data ); - -void myth_file_transfer_close( MythFileTransfer *transfer ); - -G_DEFINE_TYPE(MythFileTransfer, myth_file_transfer, G_TYPE_OBJECT) - -static guint64 -mmyth_util_decode_long_long( GMythStringList *strlist, guint offset ) -{ - - guint64 ret_value = 0LL; - - g_return_val_if_fail( strlist != NULL, ret_value ); - - if ( offset < gmyth_string_list_length( strlist )) - g_printerr( "[%s] Offset is lower than the GMythStringList (offset = %d)!\n", __FUNCTION__, offset ); - g_return_val_if_fail( offset < gmyth_string_list_length( strlist ), ret_value ); - - gint l1 = gmyth_string_list_get_int( strlist, offset ); - gint l2 = gmyth_string_list_get_int( strlist, offset + 1 ); - - ret_value = ((guint64)(l2) & 0xffffffffLL) | ((guint64)(l1) << 32); - - return ret_value; - -} - -static void -myth_file_transfer_class_init (MythFileTransferClass *klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - - gobject_class->dispose = myth_file_transfer_dispose; - gobject_class->finalize = myth_file_transfer_finalize; -} - - static void -myth_file_transfer_init (MythFileTransfer *myth_file_transfer) -{ - g_return_if_fail( myth_file_transfer != NULL ); - myth_file_transfer->mythtv_version = MYTHTV_VERSION; -} - -static void -myth_file_transfer_dispose (GObject *object) -{ - MythFileTransfer *myth_file_transfer = MYTH_FILE_TRANSFER(object); - - myth_file_transfer_close( myth_file_transfer ); - - G_OBJECT_CLASS (myth_file_transfer_parent_class)->dispose (object); -} - - static void -myth_file_transfer_finalize (GObject *object) -{ - g_signal_handlers_destroy (object); - - G_OBJECT_CLASS (myth_file_transfer_parent_class)->finalize (object); -} - - MythFileTransfer* -myth_file_transfer_new (gint num, GString *uri_str, gshort port, gint mythtv_version) -{ - MythFileTransfer *transfer = MYTH_FILE_TRANSFER ( g_object_new ( - MYTH_FILE_TRANSFER_TYPE, FALSE )); - - if ( mythtv_version > 0 ) - transfer->mythtv_version = mythtv_version; - - transfer->card_id = num; - - transfer->rec_id = -1; - - transfer->recordernum = 0; - transfer->uri = myth_uri_new ( uri_str->str ); - - transfer->hostname = g_string_new( myth_uri_gethost(transfer->uri) ); - g_print( "\t--> transfer->hostname = %s\n", transfer->hostname->str ); - - if ( port >= 0 ) - transfer->port = port; - else - transfer->port = myth_uri_getport( transfer->uri ); - - g_print( "\t--> transfer->port = %d\n", transfer->port ); - - transfer->readposition = 0; - transfer->filesize = MYTHTV_FILE_SIZE; - transfer->timeoutisfast = FALSE; - - transfer->userreadahead = MYTHTV_USER_READ_AHEAD; - transfer->retries = MYTHTV_RETRIES; - - transfer->live_tv = FALSE; - - transfer->query = g_string_new( MYTHTV_QUERY_HEADER ); - g_string_append_printf ( transfer->query, " %d", transfer->recordernum ); - g_print( "\t--> transfer->query = %s\n", transfer->query->str ); - - transfer->control_sock = NULL; - transfer->event_sock = NULL; - transfer->sock = NULL; - - return transfer; -} - -gboolean -myth_file_transfer_livetv_setup( MythFileTransfer **transfer, GMythSocket *live_socket ) -{ - (*transfer)->sock = live_socket; - g_object_ref( live_socket ); - - return TRUE; -} - -gboolean -myth_file_transfer_playback_setup( MythFileTransfer **transfer, gboolean live_tv ) -{ - - gboolean ret = TRUE; - - (*transfer)->live_tv = live_tv; - - printf("[%s] Running config to the %s...\n", __FUNCTION__, live_tv ? "LiveTV" : "FileTransfer" ); - - /* configure the control socket */ - if ((*transfer)->control_sock == NULL) { - - if ( myth_connect_to_transfer_backend ( transfer, MYTH_PLAYBACK_TYPE ) == NULL ) { - g_printerr( "Connection to backend failed (Control Socket).\n" ); - ret = FALSE; - } - - } else { - g_warning("Remote transfer control socket already created.\n"); - } - - return ret; - -} - -gboolean -myth_file_transfer_setup( MythFileTransfer **transfer, gboolean live_tv ) -{ - GMythStringList *strlist = NULL; - - gboolean ret = TRUE; - - (*transfer)->live_tv = live_tv; - - printf("[%s] Running config to the %s...\n", __FUNCTION__, live_tv ? "LiveTV" : "FileTransfer" ); - -#if 0 - /* configure the event socket */ - if ((*transfer)->event_sock == NULL) { - - if ( myth_connect_to_transfer_backend ( transfer, MYTH_MONITOR_TYPE ) == NULL ) { - g_printerr( "Connection to backend failed (Event Socket).\n" ); - ret = FALSE; - } - - } else { - g_warning("Remote transfer control socket already created.\n"); - } -#endif - - /* configure the socket */ - if ( (*transfer)->sock == NULL ) { - - //if ( live_tv == FALSE ) { - - if ( myth_connect_to_transfer_backend ( transfer, MYTH_FILETRANSFER_TYPE ) == NULL ) { - g_printerr ("Connection to backend failed (Raw Transfer Socket).\n"); - ret = FALSE; - } - - if ( !(*transfer)->live_tv && (*transfer)->control_sock != NULL) { - strlist = gmyth_string_list_new(); - g_string_printf ( (*transfer)->query, "%s %d", MYTHTV_QUERY_HEADER, (*transfer)->recordernum ); - - gmyth_string_list_append_string( strlist, (*transfer)->query ); - gmyth_string_list_append_char_array( strlist, "IS_OPEN" ); - - gmyth_socket_write_stringlist( (*transfer)->control_sock, strlist ); - gmyth_socket_read_stringlist( (*transfer)->control_sock, strlist ); - - if ( strlist!=NULL && gmyth_string_list_get_int( strlist, 0 ) == 1 ) { - g_print( "[%s] Remote Myth FileTransfer socket is open!\n", __FUNCTION__ ); - } else { - g_print( "[%s] Remote Myth FileTransfer socket is CLOSED! See the MythTV Server Backend for configuration details...\n", __FUNCTION__ ); - ret = FALSE; - } - } - - } else { - g_warning("Remote transfer (raw) socket already created.\n"); - } - - return ret; -} - -static GMythSocket * -myth_connect_to_transfer_backend( MythFileTransfer **transfer, guint sock_type ) -{ - GMythSocket *sock = NULL; - - g_return_val_if_fail( transfer != NULL && *transfer != NULL, NULL ); - g_return_val_if_fail( (*transfer)->uri != NULL, NULL ); - - g_static_mutex_lock (&mutex); - - gchar *path_dir = myth_uri_getpath( (*transfer)->uri ); - //g_print( "\t--> %s: path_dir = %s\n", __FUNCTION__, path_dir ); - - gchar *stype = g_strdup( "" ); - - // if ( (*transfer)->live_tv == FALSE ) { - - sock = gmyth_socket_new(); - - gmyth_socket_connect( &sock, (*transfer)->hostname->str, (*transfer)->port ); - - /* - } else { - sock = (*transfer)->sock; - } - */ -#ifdef MYTHTV_ENABLE_DEBUG - - g_print( "[%s] --> Creating socket... (%s, %d)\n", __FUNCTION__, (*transfer)->hostname->str, (*transfer)->port ); -#endif - - GMythStringList *strlist = NULL; - - GString *hostname = g_string_new( myth_uri_gethost( (*transfer)->uri ) ); - GString *base_str = g_string_new( "" ); - - if ( gmyth_socket_check_protocol_version_number (sock, (*transfer)->mythtv_version) ) { - - if (sock == NULL) { - stype = (sock_type==MYTH_PLAYBACK_TYPE) ? "control socket" : "file data socket"; - g_printerr( "FileTransfer, open_socket(%s): \n" - "\t\t\tCould not connect to server \"%s\" @ port %d\n", stype, - (*transfer)->hostname->str, (*transfer)->port ); - g_object_unref(sock); - g_static_mutex_unlock (&mutex); - return NULL; - } - - hostname = gmyth_socket_get_local_hostname(); - - g_print( "[%s] local hostname = %s\n", __FUNCTION__, hostname->str ); - - if ( sock_type == MYTH_PLAYBACK_TYPE ) - { - (*transfer)->control_sock = sock; - g_string_printf( base_str, "ANN Playback %s %d", hostname->str, FALSE ); - - gmyth_socket_send_command( (*transfer)->control_sock, base_str ); - GString *resp = gmyth_socket_receive_response( (*transfer)->control_sock ); - g_print( "[%s] Got Playback response from %s: %s\n", __FUNCTION__, base_str->str, resp->str ); - } - else if ( sock_type == MYTH_MONITOR_TYPE ) - { - (*transfer)->event_sock = sock; - g_string_printf( base_str, "ANN Monitor %s %d", hostname->str, TRUE ); - - gmyth_socket_send_command( (*transfer)->event_sock, base_str ); - GString *resp = gmyth_socket_receive_response( (*transfer)->event_sock ); - g_print( "[%s] Got Monitor response from %s: %s\n", __FUNCTION__, base_str->str, resp->str ); - g_thread_create( myth_init_io_watchers, (void*)(*transfer), FALSE, NULL ); - - g_printerr( "[%s] Watch listener function to the IO control channel on thread %p.\n", __FUNCTION__, g_thread_self() ); - - } - else if ( sock_type == MYTH_FILETRANSFER_TYPE ) - { - (*transfer)->sock = sock; - strlist = gmyth_string_list_new(); - //g_string_printf( base_str, "ANN FileTransfer %s %d %d", hostname->str, - // transfer->userreadahead, transfer->retries ); - g_string_printf( base_str, "ANN FileTransfer %s", hostname->str ); - - gmyth_string_list_append_string( strlist, base_str ); - gmyth_string_list_append_char_array( strlist, path_dir ); - - gmyth_socket_write_stringlist( (*transfer)->sock, strlist ); - gmyth_socket_read_stringlist( (*transfer)->sock, strlist ); - - /* socket number, where all the stream data comes from - got from the MythTV remote backend */ - (*transfer)->recordernum = gmyth_string_list_get_int( strlist, 1 ); - - /* Myth URI stream file size - decoded using two 8-bytes sequences (64 bits/long long types) */ - (*transfer)->filesize = mmyth_util_decode_long_long( strlist, 2 ); - - printf( "[%s] ***** Received: recordernum = %d, filesize = %" G_GUINT64_FORMAT "\n", __FUNCTION__, - (*transfer)->recordernum, (*transfer)->filesize ); - - if ( (*transfer)->filesize <= 0 ) { - g_print( "[%s] Got filesize equals to %llu is lesser than 0 [invalid stream file]\n", __FUNCTION__, (*transfer)->filesize ); - g_object_unref(sock); - sock = NULL; - } - } - else if ( sock_type == MYTH_RINGBUFFER_TYPE ) - { - (*transfer)->sock = sock; - //myth_file_transfer_spawntv( (*transfer), NULL ); - - strlist = gmyth_string_list_new(); - g_string_printf( base_str, "ANN RingBuffer %s %d", hostname->str, (*transfer)->card_id ); - - gmyth_socket_send_command( (*transfer)->sock, base_str ); - GString *resp = gmyth_socket_receive_response( (*transfer)->sock ); - g_print( "[%s] Got RingBuffer response from %s: %s\n", __FUNCTION__, base_str->str, resp->str ); - - } - - } - - printf("[%s] ANN %s sent: %s\n", (sock_type==MYTH_PLAYBACK_TYPE) ? "Playback" : (sock_type==MYTH_FILETRANSFER_TYPE) ? "FileTransfer" : "Monitor", __FUNCTION__, base_str->str); - - if ( strlist != NULL ) - g_object_unref( strlist ); - - g_static_mutex_unlock (&mutex); - - return sock; -} - -void -myth_file_transfer_spawntv ( MythFileTransfer *file_transfer, - GString *tvchain_id ) -{ - GMythStringList *str_list; - - g_debug ("myth_file_transfer_spawntv.\n"); - - str_list = gmyth_string_list_new (); - - g_string_printf( file_transfer->query, "%s %d", MYTHTV_RECORDER_HEADER, - file_transfer->card_id ); - gmyth_string_list_append_string (str_list, file_transfer->query); - gmyth_string_list_append_string (str_list, g_string_new ("SPAWN_LIVETV")); - if (tvchain_id!=NULL) { - gmyth_string_list_append_string (str_list, tvchain_id); - gmyth_string_list_append_int (str_list, FALSE); // PIP = FALSE (0) - } - - gmyth_socket_sendreceive_stringlist ( file_transfer->sock, str_list ); - - //GString *str = NULL; - - //if (str_list!=NULL && (str = gmyth_string_list_get_string( str_list, 0 )) != NULL && strcasecmp( str->str, "ok" ) != 0 ) { - // g_print( "[%s]\t\tSpawnLiveTV is OK!\n", __FUNCTION__ ); - //} - if (str_list!=NULL) - g_object_unref (str_list); - -} - -gboolean -myth_file_transfer_is_recording ( MythFileTransfer *file_transfer ) -{ - gboolean ret = TRUE; - - GMythStringList *str_list = gmyth_string_list_new (); - - g_debug ( "[%s]\n", __FUNCTION__ ); - g_static_mutex_lock (&mutex); - - g_string_printf( file_transfer->query, "%s %d", MYTHTV_RECORDER_HEADER, - file_transfer->rec_id >= 0 ? file_transfer->rec_id : file_transfer->card_id ); - gmyth_string_list_append_string (str_list, file_transfer->query); - gmyth_string_list_append_string (str_list, g_string_new ("IS_RECORDING")); - - gmyth_socket_sendreceive_stringlist ( file_transfer->control_sock, str_list ); - - if ( str_list != NULL && gmyth_string_list_length(str_list) > 0 ) - { - GString *str = NULL; - if ( ( str = gmyth_string_list_get_string( str_list, 0 ) ) != NULL && strcmp( str->str, "bad" )!= 0 ) { - gint is_rec = gmyth_string_list_get_int( str_list, 0 ); - if ( is_rec != 0 ) - ret = TRUE; - else - ret = FALSE; - } - } - g_print( "[%s] %s, stream is %s being recorded!\n", __FUNCTION__, ret ? "YES" : "NO", ret ? "" : "NOT" ); - g_static_mutex_unlock (&mutex); - - if ( str_list != NULL ) - g_object_unref (str_list); - - return ret; - -} - -guint64 -myth_file_transfer_get_file_position ( MythFileTransfer *file_transfer ) -{ - guint64 pos = 0; - - GMythStringList *str_list = gmyth_string_list_new (); - - g_debug ( "[%s]\n", __FUNCTION__ ); - g_static_mutex_lock (&mutex); - - g_string_printf( file_transfer->query, "%s %d", MYTHTV_RECORDER_HEADER, - file_transfer->rec_id >= 0 ? file_transfer->rec_id : file_transfer->card_id ); - - gmyth_string_list_append_string (str_list, file_transfer->query); - gmyth_string_list_append_string (str_list, g_string_new ("GET_FILE_POSITION")); - - gmyth_socket_sendreceive_stringlist ( file_transfer->control_sock, str_list ); - - if ( str_list != NULL && gmyth_string_list_length(str_list) > 0 ) - { - GString *str = NULL; - if ( ( str = gmyth_string_list_get_string( str_list, 0 ) ) != NULL && strcmp ( str->str, "bad" ) != 0 ) - pos = gmyth_util_decode_long_long( str_list, 0 ); - } - g_static_mutex_unlock (&mutex); - -#ifndef MYTHTV_ENABLE_DEBUG - - g_print( "[%s] Got file position = %llu\n", __FUNCTION__, pos ); -#endif - if (str_list!=NULL) - g_object_unref (str_list); - - return pos; - -} - - glong -myth_file_transfer_get_recordernum( MythFileTransfer *transfer ) -{ - return transfer->recordernum; -} - - glong -myth_file_transfer_get_filesize( MythFileTransfer *transfer ) -{ - return transfer->filesize; -} - - gboolean -myth_file_transfer_isopen( MythFileTransfer *transfer ) -{ - return (transfer->sock != NULL && transfer->control_sock != NULL); -} - - void -myth_file_transfer_close( MythFileTransfer *transfer ) -{ - GMythStringList *strlist; - - if (transfer->control_sock == NULL) - return; - - strlist = gmyth_string_list_new( ); - - g_string_printf( transfer->query, "%s %d", MYTHTV_QUERY_HEADER, - transfer->recordernum ); - gmyth_string_list_append_string( strlist, transfer->query ); - gmyth_string_list_append_char_array( strlist, "DONE" ); - - - if ( gmyth_socket_sendreceive_stringlist(transfer->control_sock, strlist) <= 0 ) - { - g_printerr( "Remote file timeout.\n" ); - } - - if (transfer->sock) - { - g_object_unref( transfer->sock ); - transfer->sock = NULL; - } - - if (transfer->control_sock) - { - g_object_unref( transfer->control_sock ); - transfer->control_sock = NULL; - } - -} - - void -myth_file_transfer_reset_controlsock( MythFileTransfer *transfer ) -{ - if (transfer->control_sock == NULL) - { - g_printerr( "myth_file_transfer_reset_controlsock(): Called with no control socket" ); - return; - } - - GString *str = gmyth_socket_receive_response( transfer->control_sock ); - - g_string_free( str, TRUE ); -} - -void -myth_file_transfer_reset_sock( MythFileTransfer *transfer ) -{ - if ( transfer->sock == NULL ) - { - g_printerr( "myth_file_transfer_reset_sock(): Called with no raw socket" ); - return; - } - - GString *str = gmyth_socket_receive_response( transfer->sock ); - - g_string_free( str, TRUE ); -} - -void -myth_file_transfer_reset( MythFileTransfer *transfer ) -{ - myth_file_transfer_reset_controlsock( transfer ); - myth_file_transfer_reset_sock( transfer ); -} - -guint64 -myth_file_transfer_seek(MythFileTransfer *transfer, guint64 pos, gint whence) -{ - if (transfer->sock == NULL) - { - g_printerr( "[%s] myth_file_transfer_seek(): Called with no socket", __FUNCTION__ ); - return 0; - } - - if (transfer->control_sock == NULL) - return 0; - - // if (!controlSock->isOpen() || controlSock->error()) - // return 0; - - GMythStringList *strlist = gmyth_string_list_new(); - g_string_printf (transfer->query, "%s %d", MYTHTV_QUERY_HEADER, transfer->recordernum); - gmyth_string_list_append_string( strlist, transfer->query ); - gmyth_string_list_append_char_array( strlist, "SEEK" ); - gmyth_string_list_append_uint64( strlist, pos ); - // gmyth_string_list_append_int( strlist, whence ); - - if (pos > 0 ) - gmyth_string_list_append_uint64( strlist, pos ); - else - gmyth_string_list_append_uint64( strlist, transfer->readposition ); - - gmyth_socket_sendreceive_stringlist( transfer->control_sock, strlist ); - - guint64 retval = gmyth_string_list_get_uint64(strlist, 0); - transfer->readposition = retval; - g_print( "[%s] got reading position pointer from the streaming = %llu\n", - __FUNCTION__, retval ); - - //myth_file_transfer_reset( transfer ); - - return retval; -} - -static gboolean -myth_control_sock_listener( GIOChannel *source, GIOCondition condition, gpointer data ) -{ - - GIOStatus ret; - GError *err = NULL; - gchar *msg = g_strdup(""); - - gsize len; - if (condition & G_IO_HUP) - g_error ("Read end of pipe died!\n"); - ret = g_io_channel_read_line ( source, &msg, &len, NULL, &err); - if ( ret == G_IO_STATUS_ERROR ) - g_error ("[%s] Error reading: %s\n", __FUNCTION__, err != NULL ? err->message : "" ); - g_print ("\n\n\n\n\n\n[%s]\t\tEVENT: Read %u bytes: %s\n\n\n\n\n", __FUNCTION__, len, msg != NULL ? msg : "" ); - if ( msg != NULL ) - g_free (msg); - - return TRUE; - -} - -static void* -myth_init_io_watchers( void *data ) -{ - MythFileTransfer *transfer = (MythFileTransfer*)data; - GMainContext *context = g_main_context_new(); - GMainLoop *loop = g_main_loop_new( NULL, FALSE ); - - GSource *source = NULL; - - if ( transfer->event_sock->sd_io_ch != NULL ) - source = g_io_create_watch( transfer->event_sock->sd_io_ch, G_IO_IN | G_IO_HUP ); - - g_source_set_callback ( source, (GSourceFunc)myth_control_sock_listener, NULL, NULL ); - - g_source_attach( source, context ); - - if (source==NULL) - g_printerr( "[%s] Error adding watch listener function to the IO control channel!\n", __FUNCTION__ ); - - g_main_loop_run( loop ); - - g_source_unref( source ); - - g_main_loop_unref( loop ); - - g_main_context_unref( context ); - - return NULL; -} - - gint -myth_file_transfer_read(MythFileTransfer *transfer, void *data, gint size, gboolean read_unlimited) -{ - gint recv = 0; - gsize bytes_read = 0; - - gint sent = 0; - //guint zerocnt = 0; - gboolean response = FALSE; - - GIOChannel *io_channel; - GIOChannel *io_channel_control; - - GIOCondition io_cond; - GIOCondition io_cond_control; - GIOStatus io_status = G_IO_STATUS_NORMAL, io_status_control = G_IO_STATUS_NORMAL; - - gint buf_len = MYTHTV_BUFFER_SIZE; - - GMythStringList *strlist = NULL; - GError *error = NULL; - - gchar *trash = g_strdup(""); - - g_return_val_if_fail ( data != NULL, -2 ); - - /* gets the size of the entire file, if the size requested is lesser than 0 */ - if ( size <= 0 ) - size = transfer->filesize; - - io_channel = transfer->sock->sd_io_ch; - io_channel_control = transfer->control_sock->sd_io_ch; - - //g_io_channel_set_flags( io_channel, G_IO_FLAG_APPEND | - // G_IO_STATUS_AGAIN | G_IO_FLAG_IS_READABLE | G_IO_FLAG_IS_WRITEABLE | - // G_IO_FLAG_IS_SEEKABLE, NULL ); - - io_status = g_io_channel_set_encoding( io_channel, NULL, &error ); - if ( io_status == G_IO_STATUS_NORMAL ) - g_print( "[%s] Setting encoding to binary data socket).\n", __FUNCTION__ ); - - io_cond = g_io_channel_get_buffer_condition( io_channel ); - - io_cond_control = g_io_channel_get_buffer_condition( io_channel ); - - if ( transfer->sock == NULL || ( io_status == G_IO_STATUS_ERROR ) ) - { - g_printerr( "myth_file_transfer_read(): Called with no raw socket.\n" ); - recv = -1; - goto cleanup; - } - - if ( transfer->control_sock == NULL || ( io_status_control == G_IO_STATUS_ERROR ) ) - { - g_printerr( "myth_file_transfer_read(): Called with no control socket.\n" ); - recv = -1; - goto cleanup; - } - - /* - if (!controlSock->isOpen() || controlSock->error()) - return -1; - */ - - if ( ( io_cond & G_IO_IN ) != 0 ) { - do - { - - io_status = g_io_channel_read_line( io_channel, &trash, &bytes_read, NULL, &error); - - g_print( "[%s] cleaning buffer on IO binary channel... (%s)\n", __FUNCTION__, trash ); - io_cond = g_io_channel_get_buffer_condition( io_channel ); - - } while ( ( io_cond & G_IO_IN ) != 0 && ( io_status != G_IO_STATUS_ERROR ) ); - - if ( trash!= NULL ) - g_free( trash ); - } - - if ( ( io_cond_control & G_IO_IN ) != 0 ) { - GMythStringList *strlist_tmp = gmyth_string_list_new(); - gmyth_socket_read_stringlist( transfer->control_sock, strlist_tmp ); - g_object_unref( strlist_tmp ); - } - - wait_to_transfer = 0; - - while ( transfer->live_tv && ( myth_file_transfer_get_file_position( transfer ) < 4096 ) && - wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS ) - g_usleep( 1000*50 ); /* waits just for 2/10 second */ - - //g_thread_create( myth_init_io_watchers, (void*)transfer, FALSE, NULL ); - //g_printerr( "[%s] Watch listener function to the IO control channel on thread %p.\n", __FUNCTION__, g_thread_self() ); - - g_static_mutex_lock (&mutex); - strlist = gmyth_string_list_new(); - - g_string_printf ( transfer->query, "%s %d", /*transfer->live_tv ? MYTHTV_RECORDER_HEADER :*/ MYTHTV_QUERY_HEADER, - /* transfer->live_tv ? transfer->card_id :*/ transfer->recordernum ); // transfer->recordernum - g_print( "\t[%s] Transfer_query = %s\n", __FUNCTION__, transfer->query->str ); - strlist = gmyth_string_list_new(); - - gmyth_string_list_append_string( strlist, transfer->query ); - gmyth_string_list_append_char_array( strlist, /*transfer->live_tv ? "REQUEST_BLOCK_RINGBUF" :*/ "REQUEST_BLOCK" ); - gmyth_string_list_append_int( strlist, size ); - - gmyth_socket_write_stringlist( transfer->control_sock, strlist ); - sent = size; - - //data = (void*)g_new0( gchar, size ); - - g_io_channel_flush( io_channel_control, NULL ); -// g_io_channel_flush( io_channel, NULL ); - - io_cond = g_io_channel_get_buffer_condition( io_channel ); - - while ( ( recv < sent ) )//&& ( io_cond & G_IO_IN ) != 0 ) - { - do - { - //while ( ( io_cond & G_IO_IN ) == 0 ) { - //usleep(200); - // - //io_cond = g_io_channel_get_buffer_condition( io_channel ); - // - - buf_len = ( sent - recv ) > MYTHTV_BUFFER_SIZE ? MYTHTV_BUFFER_SIZE : ( sent - recv ); - - io_status = g_io_channel_read_chars( io_channel, data + recv, - buf_len, &bytes_read, &error ); - /* - GString *sss = g_string_new(""); - sss = g_string_append_len( sss, (gchar*)data+recv, bytes_read ); - - g_print( "[%s] Reading buffer (length = %d)\n", __FUNCTION__, bytes_read); - */ - if ( bytes_read > 0 ) - { - if ( bytes_read <= buf_len ) - recv += bytes_read; - } - - if ( io_status == G_IO_STATUS_EOF ) { - g_printerr( "[%s] got EOS!", __FUNCTION__ ); - break; - } else if ( io_status == G_IO_STATUS_ERROR ) { - g_printerr( "[%s] myth_file_transfer_read(): socket error.\n", __FUNCTION__ ); - break; - } - - /* increase buffer size, to allow get more data (do not obey to the buffer size) */ - if ( read_unlimited == TRUE ) { - //if ( recv > buf_len ) - // sent += (bytes_read - buf_len) + 1; - } - if ( bytes_read == buf_len ) - break; - - /* verify if the input (read) buffer is ready to receive data */ - io_cond = g_io_channel_get_buffer_condition( io_channel ); - - g_print( "[%s]\t io_cond %s prepared for reading! (G_IO_IN) !!!\n\n", __FUNCTION__, - ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" ); - - } while ( recv < sent && ( ( io_cond & G_IO_IN ) != 0 ) && ( io_status == G_IO_STATUS_NORMAL ) ); - - io_cond_control = g_io_channel_get_buffer_condition( io_channel_control ); - if ( ( io_status == G_IO_STATUS_EOF ) || ( ( io_cond_control & G_IO_IN ) != 0 ) ) - { - gmyth_socket_read_stringlist( transfer->control_sock, strlist ); - sent = gmyth_string_list_get_int( strlist, 0 ); // -1 on backend error - g_print( "[%s]\t sent = %d, io_cond %s prepared for reading! (G_IO_IN) !!!\n\n", __FUNCTION__, - sent, ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" ); - response = TRUE; - } - } - - if ( ( ( error == NULL ) && ( response == FALSE ) ) || - ( io_status == G_IO_STATUS_EOF ) || ( ( io_cond & G_IO_IN ) == 0 ) ) - { - if ( gmyth_socket_read_stringlist( transfer->control_sock, strlist ) > 0 ) - { - if ( strlist != NULL && gmyth_string_list_length(strlist) > 0 ) { - sent = gmyth_string_list_get_int( strlist, 0 ); // -1 on backend error - g_print( "[%s]\t sent = %d, io_cond %s prepared for reading! (G_IO_IN) !!!\n\n", __FUNCTION__, - sent, ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" ); - } - } - else - { - g_printerr ( "myth_file_transfer_read(): No response from control socket."); - sent = -1; - } - - if ( error!=NULL ) { - g_printerr( "[%s] Error occurred: (%d, %s)\n", __FUNCTION__, error->code, error->message ); - g_error_free( error ); - } - } - -cleanup: - - if ( trash != NULL ) - g_free( trash ); - - if ( strlist != NULL ) - g_object_unref( strlist ); - - g_static_mutex_unlock (&mutex); - g_print( "myth_file_transfer_read(): reqd=%d, rcvd=%d, rept=%d, "\ - "(rcvd and rept MUST be the same!)\n", size, - recv, sent ); - - //if ( sent != recv ) { - // recv = -1; - //} - - if ( error != NULL ) - g_printerr( "ERROR: %s [msg = %s, code = %d]\n", __FUNCTION__, error->message, - error->code ); - - return recv; -} - - void -myth_file_transfer_settimeout( MythFileTransfer *transfer, gboolean fast ) -{ - - GMythStringList *strlist = NULL; - - if ( transfer->timeoutisfast == fast ) - return; - - if ( transfer->sock == NULL ) - { - g_printerr( "myth_file_transfer_settimeout(): Called with no socket" ); - return; - } - - if ( transfer->control_sock == NULL ) - return; - - strlist = gmyth_string_list_new(); - gmyth_string_list_append_string( strlist, transfer->query ); - gmyth_string_list_append_char_array( strlist, "SET_TIMEOUT" ); - gmyth_string_list_append_int( strlist, fast ); - - gmyth_socket_write_stringlist( transfer->control_sock, strlist ); - gmyth_socket_read_stringlist( transfer->control_sock, strlist ); - - transfer->timeoutisfast = fast; - -} - -#ifdef DO_TESTING - - int -main( int argc, char *argv[] ) -{ - g_type_init(); - - MythFileTransfer *file_transfer = myth_file_transfer_new( 1, - g_string_new("myth://192.168.1.109:6543/jshks.nuv"), -1, MYTHTV_VERSION ); - myth_file_transfer_setup( &file_transfer ); - gchar *data = g_strdup(""); - - gint num = myth_file_transfer_read( file_transfer, data, -1 ); - - return 0; - -} - -#endif diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/myth_file_transfer.h --- a/gst-plugins-mythtv/myth_file_transfer.h Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */ - -#ifndef __MYTH_FILE_TRANSFER_H__ -#define __MYTH_FILE_TRANSFER_H__ - -#include - -#include -#include "myth_uri.h" -#include "myth_livetv.h" - -#include -#include -#include -#include -#include -#include - -#define G_BEGIN_DECLS - -#define MYTH_FILE_TRANSFER_TYPE (myth_file_transfer_get_type ()) -#define MYTH_FILE_TRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MYTH_FILE_TRANSFER_TYPE, MythFileTransfer)) -#define MYTH_FILE_TRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYTH_FILE_TRANSFER_TYPE, MythFileTransferClass)) -#define IS_MYTH_FILE_TRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MYTH_FILE_TRANSFER_TYPE)) -#define IS_MYTH_FILE_TRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYTH_FILE_TRANSFER_TYPE)) -#define MYTH_FILE_TRANSFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MYTH_FILE_TRANSFER_TYPE, MythFileTransferClass)) - - -typedef struct _MythFileTransfer MythFileTransfer; -typedef struct _MythFileTransferClass MythFileTransferClass; - -struct _MythFileTransferClass -{ - GObjectClass parent_class; - - /* callbacks */ - /* no one for now */ -}; - -struct _MythFileTransfer -{ - GObject parent; - - /* Myth URI structure */ - const MythURI *uri; - - /* MythTV version number */ - gint mythtv_version; - - /* socket descriptors */ - GMythSocket *control_sock; - GMythSocket *event_sock; - GMythSocket *sock; - - guint64 readposition; - guint64 filesize; - gboolean timeoutisfast; - gboolean userreadahead; - gboolean live_tv; - gint retries; - - GString *query; - - gint rec_id; - gint recordernum; - gint card_id; - GString *hostname; - gint port; -}; - -GType myth_file_transfer_get_type (void); - -MythFileTransfer* myth_file_transfer_new (gint num, GString *hostname, gshort port, gint mythtv_version ); - -gint myth_file_transfer_read(MythFileTransfer *transfer, void *data, gint size, gboolean read_unlimited); - -guint64 myth_file_transfer_seek(MythFileTransfer *transfer, guint64 pos, gint whence); - -gboolean myth_file_transfer_playback_setup( MythFileTransfer **transfer, gboolean live_tv ); - -gboolean myth_file_transfer_setup( MythFileTransfer **transfer, gboolean live_tv ); - -gboolean myth_file_transfer_livetv_setup( MythFileTransfer **transfer, GMythSocket *live_sock ); - -void myth_file_transfer_spawntv ( MythFileTransfer *file_transfer, GString *tvchain_id ); - -gboolean myth_file_transfer_is_recording( MythFileTransfer *file_transfer ); - -guint64 myth_file_transfer_get_file_position( MythFileTransfer *file_transfer ); - -#define G_END_DECLS - -#endif /* __MYTH_FILE_TRANSFER_H__ */ diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/myth_livetv.c --- a/gst-plugins-mythtv/myth_livetv.c Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ - -#include -#include -#include - -#include "myth_livetv.h" -#include "myth_file_transfer.h" - -static void myth_livetv_class_init (MythLiveTVClass *klass); -static void myth_livetv_init (MythLiveTV *object); - -static void myth_livetv_dispose (GObject *object); -static void myth_livetv_finalize (GObject *object); - -G_DEFINE_TYPE(MythLiveTV, myth_livetv, G_TYPE_OBJECT) - -static void -myth_livetv_class_init (MythLiveTVClass *klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - - gobject_class->dispose = myth_livetv_dispose; - gobject_class->finalize = myth_livetv_finalize; -} - -static void -myth_livetv_init (MythLiveTV *livetv) -{ - livetv->backend_hostname = NULL; - livetv->backend_port = 0; - livetv->local_hostname = NULL; - - livetv->remote_encoder = NULL; - livetv->tvchain = NULL; - livetv->proginfo = NULL; -} - -static void -myth_livetv_dispose (GObject *object) -{ - - G_OBJECT_CLASS (myth_livetv_parent_class)->dispose (object); -} - -static void -myth_livetv_finalize (GObject *object) -{ - g_signal_handlers_destroy (object); - - MythLiveTV *livetv = MYTH_LIVETV (object); - - g_debug ("[%s] Finalizing livetv", __FUNCTION__); - - if ( livetv->remote_encoder != NULL ) { - g_object_unref (livetv->remote_encoder); - livetv->remote_encoder = NULL; - } - - if ( livetv->tvchain != NULL ) { - g_object_unref (livetv->tvchain); - livetv->tvchain = NULL; - } - - if ( livetv->proginfo != NULL ) { - g_object_unref (livetv->proginfo); - livetv->proginfo = NULL; - } - - G_OBJECT_CLASS ( myth_livetv_parent_class )->finalize ( object ); -} - -MythLiveTV* -myth_livetv_new () -{ - MythLiveTV *livetv = MYTH_LIVETV ( g_object_new( MYTH_LIVETV_TYPE, NULL ) ); - - return livetv; -} - -gboolean -myth_livetv_setup ( MythLiveTV *livetv ) -{ - - // FIXME: Get from the settings - GMythSettings *msettings = gmyth_context_get_settings (); - gboolean res = TRUE; - - livetv->is_livetv = TRUE; - - res = gmyth_context_check_connection(); - if (!res) { - g_warning ("[%s] LiveTV can not connect to backend", __FUNCTION__); - res = FALSE; - goto error; - } - - livetv->backend_hostname = gmyth_settings_get_backend_hostname(msettings); - livetv->backend_port = gmyth_settings_get_backend_port (msettings); - - livetv->local_hostname = g_string_new(""); - gmyth_context_get_local_hostname (livetv->local_hostname); - - if ( livetv->local_hostname == NULL ) { - res = FALSE; - goto error; - } - - // Gets the remote encoder num - livetv->remote_encoder = remote_request_next_free_recorder (-1); - - if ( livetv->remote_encoder == NULL ) { - g_warning ("[%s] None remote encoder available", __FUNCTION__); - res = FALSE; - goto error; - } - - // Creates livetv chain handler - livetv->tvchain = GMYTH_TVCHAIN ( g_object_new(GMYTH_TVCHAIN_TYPE, NULL) ); - gmyth_tvchain_initialize ( livetv->tvchain, livetv->local_hostname ); - - if ( livetv->tvchain == NULL || livetv->tvchain->tvchain_id == NULL ) { - res = FALSE; - goto error; - } - - // Init remote encoder. Opens its control socket. - res = gmyth_remote_encoder_setup(livetv->remote_encoder); - if ( !res ) { - g_warning ("[%s] Fail while setting remote encoder\n", __FUNCTION__); - res = FALSE; - goto error; - } - // Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly) - res = gmyth_remote_encoder_spawntv ( livetv->remote_encoder, - gmyth_tvchain_get_id(livetv->tvchain) ); - if (!res) { - g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__); - res = FALSE; - goto error; - } - - // Reload all TV chain from Mysql database. - gmyth_tvchain_reload_all (livetv->tvchain); - - if ( livetv->tvchain == NULL ) { - res = FALSE; - goto error; - } - - // Get program info from database using chanid and starttime - livetv->proginfo = gmyth_tvchain_get_program_at (livetv->tvchain, -1); - if ( livetv->proginfo == NULL ) { - g_warning ("[%s] LiveTV not successfully started.\n", __FUNCTION__ ); - res = FALSE; - goto error; - } else { - g_debug ("[%s] MythLiveTV: All requests to backend to start TV were OK.\n", __FUNCTION__ ); - } - - return res; - -error: - if ( livetv->backend_hostname != NULL ) { - g_string_free( livetv->backend_hostname, TRUE ); - res = FALSE; - } - - if ( livetv->local_hostname != NULL ) { - g_string_free( livetv->local_hostname, TRUE ); - res = FALSE; - } - - if ( livetv->remote_encoder != NULL ) { - g_object_unref (livetv->remote_encoder); - livetv->remote_encoder = NULL; - } - - if ( livetv->tvchain != NULL ) { - g_object_unref (livetv->tvchain); - livetv->tvchain = NULL; - } - - if ( livetv->proginfo != NULL ) { - g_object_unref (livetv->proginfo); - livetv->proginfo = NULL; - } - - return res; - -} - -// FIXME: How to proceed differently between livetv and recorded content -void -myth_livetv_stop_playing (MythLiveTV *livetv) -{ - g_debug ("[%s] Stopping the LiveTV...\n", __FUNCTION__); - - if (livetv->is_livetv) { - if (!gmyth_remote_encoder_stop_livetv (livetv->remote_encoder)) { - g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__); - } - } -} - -gboolean -myth_livetv_is_playing (MythLiveTV *livetv) -{ - return TRUE; -} - -void -myth_livetv_start_playing (MythLiveTV *livetv) -{ - - // TODO - -} - diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/myth_livetv.h --- a/gst-plugins-mythtv/myth_livetv.h Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -#ifndef MYTH_LIVETV_H_ -#define MYTH_LIVETV_H_ - -#include - -#include -#include -#include - -#include "myth_file_transfer.h" - -#define G_BEGIN_DECLS - -#define MYTH_LIVETV_TYPE (myth_livetv_get_type ()) -#define MYTH_LIVETV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MYTH_LIVETV_TYPE, MythLiveTV)) -#define MYTH_LIVETV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYTH_LIVETV_TYPE, MythLiveTVClass)) -#define IS_MYTH_LIVETV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MYTH_LIVETV_TYPE)) -#define IS_MYTH_LIVETV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYTH_LIVETV_TYPE)) -#define MYTH_LIVETV_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MYTH_LIVETV_TYPE, MythLiveTVClass)) - -typedef struct _MythLiveTV MythLiveTV; -typedef struct _MythLiveTVClass MythLiveTVClass; - -struct _MythLiveTVClass -{ - GObjectClass parent_class; - - /* callbacks */ -}; - -struct _MythLiveTV -{ - GObject parent; - - // Backend connection related variables - GString *backend_hostname; - gint backend_port; - GString *local_hostname; - - GMythRemoteEncoder *remote_encoder; - GMythTVChain *tvchain; - GMythProgramInfo *proginfo; - - gboolean is_livetv; - -}; - -GType myth_livetv_get_type (void); - -MythLiveTV* myth_livetv_new (); - -void myth_livetv_start_playing (MythLiveTV *livetv); -void myth_livetv_stop_playing (MythLiveTV *livetv); - -gboolean myth_livetv_setup (MythLiveTV *livetv); - -#define G_END_DECLS - -#endif /*MYTH_LIVETV_H_*/ diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/myth_uri.c --- a/gst-plugins-mythtv/myth_uri.c Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,208 +0,0 @@ -/** - * - * MythURI utils - * - Extracts and parses a URI char string, in according with the RFC 2396 - * [http://www.ietf.org/rfc/rfc2396.txt] - * - * @author Rosfran Borges (rosfran.borges@indt.org.br) - * - */ - -#include "myth_uri.h" -#include -#include -#include - -static gint -myth_strstr( const gchar *haystack, const gchar *needle ) -{ - - gchar *strPos; - - if (haystack == NULL || needle == NULL) - return -1; - strPos = strstr(haystack, needle); - if (strPos == NULL) - return -1; - - return (strPos - haystack); - -} - -static gboolean -myth_uri_isabsolute( const MythURI *uri ) -{ - gboolean ret = FALSE; - - g_return_val_if_fail( uri != NULL && uri->uri != NULL && uri->protocol != NULL, FALSE ); - - if ( myth_strstr( uri->uri->str, MYTH_URI_PROTOCOL_DELIM ) == 0 || strlen(uri->protocol->str) > 0 ) - ret = TRUE; - - return ret; -} - -static gint -myth_strrchr( const gchar *str, const gchar *chars, const gint nchars ) -{ - - gint strLen; - gint i, j; - - if ( str == NULL || chars == NULL ) - return -1; - - strLen = strlen( str ); - for ( i= (strLen-1); 0 <= i; i-- ) { - for ( j=0; jhost = g_string_new(""); - uri->fragment = g_string_new(""); - uri->password = g_string_new(""); - uri->path = g_string_new(""); - uri->protocol = g_string_new(""); - uri->query = g_string_new(""); - uri->uri = g_string_new(""); - uri->user = g_string_new(""); - return uri; -} - -const MythURI * -myth_uri_new( gchar *value ) -{ - - MythURI *uri = myth_uri_init(); - - gchar *protocol; - gint uriLen; - gint currIdx; - gint protoIdx; - gint atIdx; - gint colonIdx; - gint shashIdx; - gchar *host; - gint eblacketIdx; - GString *hostStr; - GString *portStr; - gint hostLen; - gint sharpIdx; - gint questionIdx; - gint queryLen; - - uriLen = strlen(value); - uri->uri = g_string_new( value ); - - currIdx = 0; - - /*** Protocol ****/ - protoIdx = myth_strstr( value, MYTH_URI_PROTOCOL_DELIM ); - if (0 < protoIdx) { - uri->protocol = g_string_append_len( uri->protocol, value, protoIdx ); - currIdx += protoIdx + strlen( MYTH_URI_PROTOCOL_DELIM ); - } - - /*** User (Password) ****/ - atIdx = myth_strstr( value+currIdx, MYTH_URI_USER_DELIM ); - if ( 0 < atIdx ) { - colonIdx = myth_strstr( value+currIdx, MYTH_URI_COLON_DELIM ); - - if (0 < colonIdx && colonIdx < atIdx) { - uri->user = g_string_append_len( uri->user, value+currIdx, colonIdx ); - uri->password = g_string_append_len( uri->password, value+currIdx+colonIdx+1, atIdx-(colonIdx+1) ); - } - else - uri->user = g_string_append_len( uri->user, value+currIdx, atIdx - currIdx ); - currIdx += atIdx + 1; - } - - /*** Host (Port) ****/ - shashIdx = myth_strstr( value+currIdx, MYTH_URI_SLASH_DELIM ); - if ( 0 < shashIdx ) - uri->host = g_string_append_len( uri->host, value+currIdx, shashIdx ); - else if ( myth_uri_isabsolute(uri) == TRUE ) - uri->host = g_string_append_len( uri->host, value+currIdx, strlen(value) - currIdx ); - host = g_strdup( myth_uri_gethost(uri) ); - colonIdx = myth_strrchr( host, MYTH_URI_COLON_DELIM, 1 ); - eblacketIdx = myth_strrchr( host, MYTH_URI_EBLACET_DELIM, 1 ); - if ( ( 0 < colonIdx ) && ( eblacketIdx < colonIdx ) ) { - hostStr = g_string_new( host ); - - hostLen = hostStr->len; - /**** host ****/ - uri->host = g_string_erase( uri->host, 0, hostLen ); - uri->host = g_string_insert_len( uri->host, 0, hostStr->str, colonIdx ); - //host = myth_uri_gethost( uri ); - if (0 < hostLen) { - if (host[0] == '[' && host[hostLen-1] == ']') - uri->host = g_string_append_len( uri->host, hostStr->str+1, colonIdx-2 ); - } - /**** port ****/ - portStr = g_string_new(""); - portStr = g_string_append_len( portStr, hostStr->str+colonIdx+1, hostLen-colonIdx-1 ); - uri->port = atoi( portStr->str ); - g_string_free( portStr, TRUE ); - g_string_free( hostStr, FALSE ); - } - else { - uri->port = MYTH_URI_KNKOWN_PORT; - protocol = myth_uri_getprotocol(uri); - if ( strcmp(protocol, MYTH_URI_PROTOCOL_HTTP) == 0 ) - uri->port = MYTH_URI_DEFAULT_HTTP_PORT; - if ( strcmp(protocol, MYTH_URI_PROTOCOL_FTP) == 0 ) - uri->port = MYTH_URI_DEFAULT_FTP_PORT; - } - - if (shashIdx > 0) currIdx += shashIdx; - - /* - Handle relative URL - */ - if (myth_uri_isabsolute(uri) == FALSE) - { - - if (shashIdx != 0) - { - /* Add slash delimiter at the beginning of the URL, - if it doesn't exist - */ - uri->path = g_string_new( MYTH_URI_SLASH_DELIM ); - } - uri->path = g_string_append( uri->path, value ); - - } else { - /* First set path simply to the rest of URI */ - g_string_append_len( uri->path, value+currIdx, uriLen-currIdx ); - } - - /**** Path (Query/Fragment) ****/ - sharpIdx = myth_strstr(value+currIdx, MYTH_URI_SHARP_DELIM); - if (0 < sharpIdx) { - uri->path = g_string_append_len( uri->path, value+currIdx, sharpIdx); - uri->fragment = g_string_append_len( uri->fragment, - value+currIdx+sharpIdx+1, uriLen-(currIdx+sharpIdx+1)); - } - - questionIdx = myth_strstr( value+currIdx, MYTH_URI_QUESTION_DELIM ); - if ( 0 < questionIdx ) { - uri->path = g_string_append_len( uri->path, value+currIdx, questionIdx ); - queryLen = uriLen-(currIdx+questionIdx+1); - if ( 0 < sharpIdx ) - queryLen -= uriLen - (currIdx+sharpIdx+1); - uri->query = g_string_append_len( uri->query, value+currIdx+questionIdx+1, queryLen ); - } - - return uri; - -} diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/myth_uri.h --- a/gst-plugins-mythtv/myth_uri.h Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/** - * - * MythURI utils - * - Extracts and parses a URI char string, in according with the RFC 2396 - * [http://www.ietf.org/rfc/rfc2396.txt] - * - * @author Rosfran Borges (rosfran.borges@indt.org.br) - * - */ - -#ifndef _MYTH_URI_H_ -#define _MYTH_URI_H_ - -#include - -/**************************************** -* Define -****************************************/ - -#define MYTH_URI_KNKOWN_PORT (-1) -#define MYTH_URI_DEFAULT_HTTP_PORT 80 -#define MYTH_URI_DEFAULT_FTP_PORT 21 -#define MYTH_URI_DEFAULT_PATH "/" -#define MYTH_URI_MAXLEN 256 - -#define MYTH_URI_PROTOCOL_DELIM "://" -#define MYTH_URI_USER_DELIM "@" -#define MYTH_URI_COLON_DELIM ":" -#define MYTH_URI_SLASH_DELIM "/" -#define MYTH_URI_SBLACET_DELIM "[" -#define MYTH_URI_EBLACET_DELIM "]" -#define MYTH_URI_SHARP_DELIM "#" -#define MYTH_URI_QUESTION_DELIM "?" -#define MYTH_URI_ESCAPING_CHAR "%" - -#define MYTH_URI_PROTOCOL_MYTH "myth" -#define MYTH_URI_PROTOCOL_HTTP "http" -#define MYTH_URI_PROTOCOL_FTP "ftp" - -/**************************************** -* Data Type -****************************************/ - -typedef struct _MythURI { - GString *uri; - GString *host; - gint port; - GString *protocol; - GString *path; - GString *fragment; - GString *user; - GString *password; - GString *query; -} MythURI; - -const MythURI *myth_uri_new( gchar *value ); - -#define myth_uri_gethost(urip) (urip->host->str) -#define myth_uri_getport(urip) (urip->port) -#define myth_uri_getprotocol(urip) (urip->protocol->str) -#define myth_uri_getpath(urip) (urip->path->str) - -#endif diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/mythtvsrc-test.c --- a/gst-plugins-mythtv/mythtvsrc-test.c Tue Sep 26 15:30:52 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -#include - -static gboolean -bus_call (GstBus *bus, - GstMessage *msg, - gpointer data) -{ - GMainLoop *loop = data; - - switch (GST_MESSAGE_TYPE (msg)) { - case GST_MESSAGE_EOS: - g_print ("End-of-stream\n"); - g_main_loop_quit (loop); - break; - case GST_MESSAGE_ERROR: { - gchar *debug; - GError *err; - - gst_message_parse_error (msg, &err, &debug); - g_free (debug); - - g_print ("Error: %s\n", err->message); - g_error_free (err); - - g_main_loop_quit (loop); - break; - } - default: - break; - } - - return TRUE; -} - -gint -main (gint argc, - gchar *argv[]) -{ - GstElement *pipeline, *filesrc, *decoder, *filter, *sink; - GMainLoop *loop; - - /* initialization */ - gst_init (&argc, &argv); - loop = g_main_loop_new (NULL, FALSE); - if (argc != 2) { - g_print ("Usage: %s \n", argv[0]); - return 01; - } - - /* create elements */ - pipeline = gst_pipeline_new ("mythtvsrc_pipeline"); - gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)), - bus_call, loop); - - filesrc = gst_element_factory_make ("mythtvsrc", "mythtvsrc"); - decoder = gst_element_factory_make ("mad", "my_decoder"); - filter = gst_element_factory_make ("my_filter", "my_filter"); - sink = gst_element_factory_make ("osssink", "audiosink"); - if (!sink || !decoder) { - g_print ("Decoder or output could not be found - check your install\n"); - return -1; - } else if (!filter) { - g_print ("Your self-written filter could not be found. Make sure it " - "is installed correctly in $(libdir)/gstreamer-0.9/ and that " - "you've ran gst-register-0.9 to register it. Check availability " - "of the plugin afterwards using \"gst-inspect-0.9 my_filter\""); - return -1; - } - - g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); - - /* link everything together */ - gst_element_link_many (filesrc, decoder, filter, sink, NULL); - gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, filter, sink, NULL); - - /* run */ - gst_element_set_state (pipeline, GST_STATE_PLAYING); - g_main_loop_run (loop); - - /* clean up */ - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (pipeline)); - - return 0; -} diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/Makefile.am Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,27 @@ +plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ + +plugin_LTLIBRARIES = libgstmythtvsrc.la + +libgstmythtvsrc_la_SOURCES = \ + gstmythtvsrc.c \ + myth_uri.c \ + myth_file_transfer.c \ + myth_livetv.c + +libgstmythtvsrc_la_CFLAGS = \ + $(GST_CFLAGS) \ + $(GMYTH_CFLAGS) + +libgstmythtvsrc_la_LDFLAGS = \ + $(GST_PLUGIN_LDFLAGS) + +libgstmythtvsrc_la_LIBADD = \ + $(GST_BASE_LIBS) \ + $(GMYTH_LIBS) + +noinst_HEADERS = \ + gstmythtvsrc.h \ + myth_uri.h \ + myth_file_transfer.h \ + myth_livetv.h + diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/Makefile.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/Makefile.in Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,543 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/as-version.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(plugindir)" +pluginLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(plugin_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgstmythtvsrc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libgstmythtvsrc_la_OBJECTS = libgstmythtvsrc_la-gstmythtvsrc.lo \ + libgstmythtvsrc_la-myth_uri.lo \ + libgstmythtvsrc_la-myth_file_transfer.lo \ + libgstmythtvsrc_la-myth_livetv.lo +libgstmythtvsrc_la_OBJECTS = $(am_libgstmythtvsrc_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libgstmythtvsrc_la_SOURCES) +DIST_SOURCES = $(libgstmythtvsrc_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GMYTH_CFLAGS = @GMYTH_CFLAGS@ +GMYTH_LIBS = @GMYTH_LIBS@ +GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ +GOBJECT_LIBS = @GOBJECT_LIBS@ +GSTBASE_CFLAGS = @GSTBASE_CFLAGS@ +GSTBASE_LIBS = @GSTBASE_LIBS@ +GST_CFLAGS = @GST_CFLAGS@ +GST_LIBS = @GST_LIBS@ +GST_MAJORMINOR = @GST_MAJORMINOR@ +GST_PLUGINS_DIR = @GST_PLUGINS_DIR@ +GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@ +HAVE_PKGCONFIG = @HAVE_PKGCONFIG@ +HILDON_CFLAGS = @HILDON_CFLAGS@ +HILDON_LIBS = @HILDON_LIBS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAEMO_PLATFORM_FALSE = @MAEMO_PLATFORM_FALSE@ +MAEMO_PLATFORM_TRUE = @MAEMO_PLATFORM_TRUE@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MYTHTVSRC_MAJORMINOR = @MYTHTVSRC_MAJORMINOR@ +MYTHTVSRC_MAJOR_VERSION = @MYTHTVSRC_MAJOR_VERSION@ +MYTHTVSRC_MICRO_VERSION = @MYTHTVSRC_MICRO_VERSION@ +MYTHTVSRC_MINOR_VERSION = @MYTHTVSRC_MINOR_VERSION@ +MYTHTVSRC_NANO_VERSION = @MYTHTVSRC_NANO_VERSION@ +MYTHTVSRC_RELEASE = @MYTHTVSRC_RELEASE@ +MYTHTVSRC_VERSION = @MYTHTVSRC_VERSION@ +NDEBUG_FALSE = @NDEBUG_FALSE@ +NDEBUG_TRUE = @NDEBUG_TRUE@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_pt_PKG_CONFIG = @ac_pt_PKG_CONFIG@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ +plugin_LTLIBRARIES = libgstmythtvsrc.la +libgstmythtvsrc_la_SOURCES = \ + gstmythtvsrc.c \ + myth_uri.c \ + myth_file_transfer.c \ + myth_livetv.c + +libgstmythtvsrc_la_CFLAGS = \ + $(GST_CFLAGS) \ + $(GMYTH_CFLAGS) + +libgstmythtvsrc_la_LDFLAGS = \ + $(GST_PLUGIN_LDFLAGS) + +libgstmythtvsrc_la_LIBADD = \ + $(GST_BASE_LIBS) \ + $(GMYTH_LIBS) + +noinst_HEADERS = \ + gstmythtvsrc.h \ + myth_uri.h \ + myth_file_transfer.h \ + myth_livetv.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(mkdir_p) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + else :; fi; \ + done + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgstmythtvsrc.la: $(libgstmythtvsrc_la_OBJECTS) $(libgstmythtvsrc_la_DEPENDENCIES) + $(LINK) -rpath $(plugindir) $(libgstmythtvsrc_la_LDFLAGS) $(libgstmythtvsrc_la_OBJECTS) $(libgstmythtvsrc_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstmythtvsrc_la-gstmythtvsrc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstmythtvsrc_la-myth_file_transfer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstmythtvsrc_la-myth_livetv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstmythtvsrc_la-myth_uri.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libgstmythtvsrc_la-gstmythtvsrc.lo: gstmythtvsrc.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstmythtvsrc_la_CFLAGS) $(CFLAGS) -MT libgstmythtvsrc_la-gstmythtvsrc.lo -MD -MP -MF "$(DEPDIR)/libgstmythtvsrc_la-gstmythtvsrc.Tpo" -c -o libgstmythtvsrc_la-gstmythtvsrc.lo `test -f 'gstmythtvsrc.c' || echo '$(srcdir)/'`gstmythtvsrc.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libgstmythtvsrc_la-gstmythtvsrc.Tpo" "$(DEPDIR)/libgstmythtvsrc_la-gstmythtvsrc.Plo"; else rm -f "$(DEPDIR)/libgstmythtvsrc_la-gstmythtvsrc.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gstmythtvsrc.c' object='libgstmythtvsrc_la-gstmythtvsrc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstmythtvsrc_la_CFLAGS) $(CFLAGS) -c -o libgstmythtvsrc_la-gstmythtvsrc.lo `test -f 'gstmythtvsrc.c' || echo '$(srcdir)/'`gstmythtvsrc.c + +libgstmythtvsrc_la-myth_uri.lo: myth_uri.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstmythtvsrc_la_CFLAGS) $(CFLAGS) -MT libgstmythtvsrc_la-myth_uri.lo -MD -MP -MF "$(DEPDIR)/libgstmythtvsrc_la-myth_uri.Tpo" -c -o libgstmythtvsrc_la-myth_uri.lo `test -f 'myth_uri.c' || echo '$(srcdir)/'`myth_uri.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libgstmythtvsrc_la-myth_uri.Tpo" "$(DEPDIR)/libgstmythtvsrc_la-myth_uri.Plo"; else rm -f "$(DEPDIR)/libgstmythtvsrc_la-myth_uri.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='myth_uri.c' object='libgstmythtvsrc_la-myth_uri.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstmythtvsrc_la_CFLAGS) $(CFLAGS) -c -o libgstmythtvsrc_la-myth_uri.lo `test -f 'myth_uri.c' || echo '$(srcdir)/'`myth_uri.c + +libgstmythtvsrc_la-myth_file_transfer.lo: myth_file_transfer.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstmythtvsrc_la_CFLAGS) $(CFLAGS) -MT libgstmythtvsrc_la-myth_file_transfer.lo -MD -MP -MF "$(DEPDIR)/libgstmythtvsrc_la-myth_file_transfer.Tpo" -c -o libgstmythtvsrc_la-myth_file_transfer.lo `test -f 'myth_file_transfer.c' || echo '$(srcdir)/'`myth_file_transfer.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libgstmythtvsrc_la-myth_file_transfer.Tpo" "$(DEPDIR)/libgstmythtvsrc_la-myth_file_transfer.Plo"; else rm -f "$(DEPDIR)/libgstmythtvsrc_la-myth_file_transfer.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='myth_file_transfer.c' object='libgstmythtvsrc_la-myth_file_transfer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstmythtvsrc_la_CFLAGS) $(CFLAGS) -c -o libgstmythtvsrc_la-myth_file_transfer.lo `test -f 'myth_file_transfer.c' || echo '$(srcdir)/'`myth_file_transfer.c + +libgstmythtvsrc_la-myth_livetv.lo: myth_livetv.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstmythtvsrc_la_CFLAGS) $(CFLAGS) -MT libgstmythtvsrc_la-myth_livetv.lo -MD -MP -MF "$(DEPDIR)/libgstmythtvsrc_la-myth_livetv.Tpo" -c -o libgstmythtvsrc_la-myth_livetv.lo `test -f 'myth_livetv.c' || echo '$(srcdir)/'`myth_livetv.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libgstmythtvsrc_la-myth_livetv.Tpo" "$(DEPDIR)/libgstmythtvsrc_la-myth_livetv.Plo"; else rm -f "$(DEPDIR)/libgstmythtvsrc_la-myth_livetv.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='myth_livetv.c' object='libgstmythtvsrc_la-myth_livetv.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstmythtvsrc_la_CFLAGS) $(CFLAGS) -c -o libgstmythtvsrc_la-myth_livetv.lo `test -f 'myth_livetv.c' || echo '$(srcdir)/'`myth_livetv.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-pluginLTLIBRARIES + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-pluginLTLIBRARIES install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-pluginLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/gstmythtvsrc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/gstmythtvsrc.c Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,901 @@ +/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2 -*- */ +/* GStreamer MythTV Plug-in + * Copyright (C) <2006> Rosfran Borges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstmythtvsrc.h" +#include "myth_file_transfer.h" +#include "myth_livetv.h" + +#include +#include + +#include +#include + +GST_DEBUG_CATEGORY_STATIC (mythtvsrc_debug); +#define GST_CAT_DEFAULT mythtvsrc_debug + +#define GST_MYTHTV_ID_NUM 1 + +#define MYTHTV_VERSION_DEFAULT 30 + +#define MYTHTV_TRANSFER_MAX_WAITS 100 + +#define MYTHTV_TRANSFER_MAX_BUFFER ( 32*1024 ) + +/* 4*1024 ??? */ +#define MAX_READ_SIZE ( 16*1024 ) + +#define ENABLE_TIMING_POSITION 1 + +/* stablish a maximum iteration value to the IS_RECORDING message */ +static guint wait_to_transfer = 0; + +static const GstElementDetails gst_mythtv_src_details = +GST_ELEMENT_DETAILS ("MythTV client source", + "Source/Network", + "Control and receive data as a client over the network via raw socket connections using the MythTV protocol", + "Rosfran Borges "); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_URI, +#ifndef GST_DISABLE_GST_DEBUG + PROP_MYTHTV_DBG, +#endif + PROP_MYTHTV_VERSION, + PROP_MYTHTV_LIVE, + PROP_MYTHTV_LIVEID, + PROP_MYTHTV_LIVE_CHAINID +}; + +static void gst_mythtv_src_finalize (GObject * gobject); + +static GstFlowReturn gst_mythtv_src_create (GstBaseSrc * psrc, + guint64 offset, guint size, GstBuffer ** outbuf); +static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc); +static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc); +static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size); +static gboolean gst_mythtv_src_is_seekable( GstBaseSrc *base_src ); + +static void gst_mythtv_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_mythtv_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void +gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data); + +static gboolean +gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event); + + static void +_urihandler_init (GType type) +{ + static const GInterfaceInfo urihandler_info = { + gst_mythtv_src_uri_handler_init, + NULL, + NULL + }; + + g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); + + GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, + "MythTV src"); +} + +GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstBaseSrc, + GST_TYPE_BASE_SRC, _urihandler_init); + + static void +gst_mythtv_src_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&srctemplate)); + + gst_element_class_set_details (element_class, &gst_mythtv_src_details); +} + + static void +gst_mythtv_src_class_init (GstMythtvSrcClass * klass) +{ + GObjectClass *gobject_class; + GstBaseSrcClass *gstbasesrc_class; + + gobject_class = (GObjectClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + + gobject_class->set_property = gst_mythtv_src_set_property; + gobject_class->get_property = gst_mythtv_src_get_property; + gobject_class->finalize = gst_mythtv_src_finalize; + + g_object_class_install_property + (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "Location", + "The location. In the form:" + "\n\t\t\tmyth://a.com/file.nuv" + "\n\t\t\tmyth://a.com:23223/file.nuv " + "\n\t\t\ta.com/file.nuv - default scheme 'myth'", + "", G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_URI, + g_param_spec_string ("uri", "Uri", + "The location in form of a URI (deprecated; use location)", + "", G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_MYTHTV_VERSION, + g_param_spec_int ("mythtv-version", "mythtv-version", + "Change Myth TV version", + 26, 30, 26, G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_MYTHTV_LIVEID, + g_param_spec_int ("mythtv-live-id", "mythtv-live-id", + "Change Myth TV version", + 0, 200, GST_MYTHTV_ID_NUM, G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_MYTHTV_LIVE_CHAINID, + g_param_spec_string ("mythtv-live-chainid", "mythtv-live-chainid", + "Sets the Myth TV chain ID (from TV Chain)", + "", G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_MYTHTV_LIVE, + g_param_spec_boolean ("mythtv-live", "mythtv-live", + "Enable MythTV Live TV content streaming", + FALSE, G_PARAM_READWRITE)); + +#ifndef GST_DISABLE_GST_DEBUG + g_object_class_install_property + (gobject_class, PROP_MYTHTV_DBG, + g_param_spec_boolean ("mythtv-debug", "mythtv-debug", + "Enable MythTV debug messages", + FALSE, G_PARAM_READWRITE)); +#endif + + gstbasesrc_class->start = gst_mythtv_src_start; + gstbasesrc_class->stop = gst_mythtv_src_stop; + gstbasesrc_class->get_size = gst_mythtv_src_get_size; + gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable; + + gstbasesrc_class->create = gst_mythtv_src_create; + + + GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, + "MythTV Client Source"); +} + + static void +gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class) +{ + this->file_transfer = NULL; + + this->unique_setup = FALSE; + + this->mythtv_version = MYTHTV_VERSION_DEFAULT; + + this->bytes_read = 0; + + this->content_size = -1; + this->read_offset = 0; + + this->live_tv = FALSE; + + this->user_agent = g_strdup ("mythtvsrc"); + this->mythtv_caps = NULL; + + gst_pad_set_event_function (GST_BASE_SRC_PAD(GST_BASE_SRC(this)), + GST_DEBUG_FUNCPTR (gst_mythtv_src_handle_event)); + +} + + static void +gst_mythtv_src_finalize (GObject * gobject) +{ + GstMythtvSrc *this = GST_MYTHTV_SRC (gobject); + + g_free (this->user_agent); + + if (this->mythtv_caps) { + gst_caps_unref (this->mythtv_caps); + this->mythtv_caps = NULL; + } + + if (this->file_transfer) { + g_object_unref (this->file_transfer); + this->file_transfer = NULL; + } + + if (this->uri_name) { + g_free (this->uri_name); + } + + if (this->user_agent) { + g_free (this->user_agent); + } + + G_OBJECT_CLASS (parent_class)->finalize (gobject); +} + +#if 0 + static guint +do_seek( GstMythtvSrc *src, guint64 offset, guint size, GstBuffer *outbuf ) +{ + guint64 off_uint64 = myth_file_transfer_seek(src->file_transfer, offset, 1); + + g_print( "[%s] Call MythTV SEEK with offset %llu, got a new one %llu...\n", __FUNCTION__, + offset, off_uint64 ); + + return off_uint64; + +} +#endif + + static guint +do_read_request_response (GstMythtvSrc * src, guint64 offset, guint size, GstBuffer * outbuf) +{ + guint read = 0; + guint sizetoread = size; //GST_BUFFER_SIZE (outbuf); + + g_print( "[%s] Reading %d bytes...\n", __FUNCTION__, sizetoread ); + + /* Loop sending the request: + * Retry whilst authentication fails and we supply it. */ + + ssize_t len = 0; + + GST_OBJECT_LOCK(src); + + while ( sizetoread > 0 ) { + + len = myth_file_transfer_read( src->file_transfer, + GST_BUFFER_DATA (outbuf) + read, sizetoread, TRUE ); + + if ( len > 0 ) { + read += len; + src->read_offset += read; + sizetoread -= len; + } else if ( len < 0 ) { + goto done; + } + /*else if ( len == 0 ) { + goto eos; + }*/ + + if ( len == sizetoread ) + break; + + } + + if ( read > 0 ) { + src->bytes_read += read; + + GST_BUFFER_SIZE (outbuf) = read; + } else if ( read <= 0 || len <= 0 ) { + if ( src->live_tv == FALSE ) + goto eos; + else + goto done; + } + //GST_BUFFER_OFFSET (outbuf) = src->read_offset; + + g_print( "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\ + "OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read, + src->read_offset, src->content_size ); + + GST_OBJECT_UNLOCK(src); + + if ( len < 0 ) { + read = len; + if ( src->live_tv == FALSE ) + goto eos; + else + goto done; + } + + if ( src->bytes_read < src->content_size ) + goto done; + +eos: + GST_OBJECT_UNLOCK(src); + + src->eos = TRUE; +done: + GST_OBJECT_UNLOCK(src); + + return read; +} + + static GstFlowReturn +gst_mythtv_src_create ( GstBaseSrc * psrc, guint64 offset, + guint size, GstBuffer **outbuf ) +{ + GstMythtvSrc *src; + GstFlowReturn ret = GST_FLOW_OK; + guint read; + guint64 size_tmp = 0; + + src = GST_MYTHTV_SRC (psrc); + + g_print( "[%s]\tBUFFER OFFSET = %llu, BUFFER SIZE = %d.\n", __FUNCTION__, offset, + size ); + + + /* The caller should know the number of bytes and not read beyond EOS. */ + if (G_UNLIKELY (src->eos)) + goto eos; + + /* Create the buffer. */ + ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)), + // GST_BUFFER_OFFSET_NONE, GST_BASE_SRC (psrc)->blocksize, + offset, size, + src->mythtv_caps ? src->mythtv_caps : + GST_PAD_CAPS (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc))), outbuf ); + + if (G_UNLIKELY (ret == GST_FLOW_UNEXPECTED)) + goto eos; + + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto done; + + read = do_read_request_response ( src, offset, size, *outbuf ); + +#if ENABLE_TIMING_POSITION == 1 + if (src->live_tv == TRUE) { + //g_usleep( 1000 ); +get_file_pos: + //g_usleep( 100 ); + size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) + src->content_size = size_tmp; + else + goto get_file_pos; + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", + __FUNCTION__, size_tmp); + + } +#endif + + if (G_UNLIKELY (read < 0)) + goto read_error; + + if (G_UNLIKELY(src->eos)) + goto eos; + +done: + return ret; +eos: +#if ENABLE_TIMING_POSITION == 1 + if ( src->live_tv == TRUE ) { + //g_usleep( 1000 ); + guint64 size_tmp = 0; +get_file_pos_eos: + //g_usleep( 100 ); + size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) + src->content_size = size_tmp; + else + goto get_file_pos_eos; + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", + __FUNCTION__, size_tmp); + goto done; + } else +#endif + { + GST_DEBUG_OBJECT (src, "EOS reached"); + return GST_FLOW_UNEXPECTED; + } + /* ERRORS */ +read_error: + { + GST_ELEMENT_ERROR (src, RESOURCE, READ, + (NULL), ("Could not read any bytes (%i, %s)", read, + src->uri_name)); + return GST_FLOW_ERROR; + } +} + +#if 0 +/* The following two charset mangling functions were copied from gnomevfssrc. + * Preserve them under the unverified assumption that they do something vaguely + * worthwhile. + */ + static char * +unicodify (const char *str, int len, ...) +{ + char *ret = NULL, *cset; + va_list args; + gsize bytes_read, bytes_written; + + if (g_utf8_validate (str, len, NULL)) + return g_strndup (str, len >= 0 ? len : strlen (str)); + + va_start (args, len); + while ((cset = va_arg (args, char *)) != NULL) + { + if (!strcmp (cset, "locale")) + ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL); + else + ret = g_convert (str, len, "UTF-8", cset, + &bytes_read, &bytes_written, NULL); + if (ret) + break; + } + va_end (args); + + return ret; +} + + static char * +gst_mythtv_src_unicodify (const char *str) +{ + return unicodify (str, -1, "locale", "ISO-8859-1", NULL); +} +#endif + +/* create a socket for connecting to remote server */ + static gboolean +gst_mythtv_src_start ( GstBaseSrc * bsrc ) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc); + + GString *chain_id_local = NULL; + + gboolean ret = TRUE; +#if 0 + if (src->live_tv == TRUE && src->file_transfer != NULL) { + guint64 size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); + if (size_tmp > src->content_size) + src->content_size = size_tmp; + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", + __FUNCTION__, size_tmp); + } +#endif + if (src->unique_setup == FALSE) { + src->unique_setup = TRUE; + } else { + goto done; + } + + GST_OBJECT_LOCK(src); + + if ( src->live_tv ) { + src->spawn_livetv = myth_livetv_new( ); + if ( myth_livetv_setup( src->spawn_livetv ) == FALSE ) { + ret = FALSE; + goto init_failed; + } + /* set up the uri variable */ + src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str ); + chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain ); + if ( chain_id_local != NULL ) { + src->live_chain_id = g_strdup( chain_id_local->str ); + g_print( "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id ); + } + src->live_tv_id = src->spawn_livetv->remote_encoder->recorder_num; + g_print ( "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name ); + } + + src->file_transfer = myth_file_transfer_new( src->live_tv_id, + g_string_new( src->uri_name ), -1, src->mythtv_version ); + + if ( src->file_transfer == NULL ) { + GST_OBJECT_UNLOCK(src); + + goto init_failed; + } + + if ( src->live_tv ) { + g_print ( "[%s] GST MYTHTVSRC: live_chain_id = %s\n", __FUNCTION__, src->live_chain_id ); + /* sets the MythSocket to the FileTransfer */ + //ret = myth_file_transfer_livetv_setup( &(src->file_transfer), src->spawn_livetv->remote_encoder->myth_socket ); + } + /* sets the Playback monitor connection */ + ret = myth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv ); + + if ( src->live_tv == TRUE && ret == TRUE ) { + /* loop finished, set the max tries variable to zero again... */ + wait_to_transfer = 0; + + while ( wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS && ( myth_file_transfer_is_recording( src->file_transfer ) == FALSE + /*|| ( myth_file_transfer_get_file_position( src->file_transfer ) < ( src->content_size + 327680 ) )*/ ) ) + g_usleep( 100 ); + } + + /* sets the FileTransfer instance connection (video/audio download) */ + ret = myth_file_transfer_setup( &(src->file_transfer), src->live_tv ); + + if ( ret == FALSE ) { + GST_OBJECT_UNLOCK(src); +#ifndef GST_DISABLE_GST_DEBUG + if ( src->mythtv_msgs_dbg ) + g_printerr( "MythTV FileTransfer request failed when setting up socket connection!\n" ); +#endif + goto begin_req_failed; + } + + src->content_size = src->file_transfer->filesize; + + GST_OBJECT_UNLOCK(src); + +#if 0 + const char *str_value; + gint gint_value; + + str_value = ne_get_response_header (src->request, "myth-metaint"); + if (str_value) { + if ( sscanf (str_value, "%d", &gint_value) == 1 ) { + if (src->myth_caps) { + gst_caps_unref (src->myth_caps); + src->myth_caps = NULL; + } + src->myth_metaint = gint_value; +#endif + //src->mythtv_caps = gst_caps_new_simple ("application/x-gst_ff-nuv", NULL); + // } + // } +done: + return TRUE; + + /* ERRORS */ +init_failed: + { + if (src->spawn_livetv != NULL ) + g_object_unref( src->spawn_livetv ); + + GST_ELEMENT_ERROR (src, LIBRARY, INIT, + (NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name)); + return FALSE; + } +begin_req_failed: + { + GST_ELEMENT_ERROR (src, LIBRARY, INIT, + (NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name)); + return FALSE; + } +} + + static gboolean +gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size) +{ + GstMythtvSrc *src; + + src = GST_MYTHTV_SRC (bsrc); +#if ENABLE_TIMING_POSITION == 1 + guint64 size_tmp = 0; + if (src->live_tv == TRUE) { +get_file_pos: + //g_usleep( 100 ); + size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) + src->content_size = size_tmp; + else + goto get_file_pos; + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", + __FUNCTION__, size_tmp); + } +#endif + if (src->content_size <= 0) + return FALSE; + + *size = src->content_size; + + return TRUE; +} + +/* close the socket and associated resources + * used both to recover from errors and go to NULL state */ + static gboolean +gst_mythtv_src_stop (GstBaseSrc * bsrc) +{ + GstMythtvSrc *src; + + src = GST_MYTHTV_SRC (bsrc); + + if (src->uri_name) { + g_free (src->uri_name); + src->uri_name = NULL; + } + + if (src->mythtv_caps) { + gst_caps_unref (src->mythtv_caps); + src->mythtv_caps = NULL; + } + + src->eos = FALSE; + + return TRUE; +} + + static gboolean +gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + src->eos = FALSE; + break; + //return TRUE; + case GST_EVENT_FLUSH_STOP: + src->do_start = TRUE; + src->eos = FALSE; + gst_element_set_state (GST_ELEMENT(src), GST_STATE_NULL); + gst_element_set_locked_state (GST_ELEMENT(src), TRUE); + break; + case GST_EVENT_SEEK: + { + gdouble rate; + //gboolean update = TRUE; + GstFormat format; + GstSeekType cur_type, stop_type; + GstSeekFlags flags; + gint64 cur = 0, stop = 0; + gst_event_parse_seek ( event, &rate, &format, + &flags, &cur_type, &cur, + &stop_type, &stop ); + + g_print( "[%s] Got EVENT_SEEK.\n", __FUNCTION__ ); + if ( !( flags & GST_SEEK_FLAG_FLUSH ) ) { + g_print( "[%s] Could get the FLAG_FLUSH message.\n", __FUNCTION__ ); + } + //gboolean ret = gst_event_parse_new_segment ( event, + // &update, &rate, &format, &start, &stop, + // &position ); + //GstFlowReturn flow_ret = gst_mythtv_src_create (GST_BASE_SRC( GST_PAD_PARENT( psrc ) ), + // cur, stop - cur + 1, GstBuffer) + + } + default: + return gst_pad_event_default (pad, event); + } + + return gst_pad_event_default (pad, event); +} + + static gboolean +gst_mythtv_src_is_seekable( GstBaseSrc *base_src ) +{ + return TRUE; +} + + static void +gst_mythtv_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object); + + GST_OBJECT_LOCK (mythtvsrc); + switch (prop_id) { + case PROP_URI: + case PROP_LOCATION: + { + if (!g_value_get_string (value)) { + GST_WARNING ("location property cannot be NULL"); + goto done; + } + + if (mythtvsrc->uri_name != NULL) { + g_free (mythtvsrc->uri_name); + mythtvsrc->uri_name = NULL; + } + mythtvsrc->uri_name = g_value_dup_string (value); + + break; + } +#ifndef GST_DISABLE_GST_DEBUG + case PROP_MYTHTV_DBG: + { + mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value); + break; + } +#endif + case PROP_MYTHTV_VERSION: + { + mythtvsrc->mythtv_version = g_value_get_int (value); + break; + } + case PROP_MYTHTV_LIVEID: + { + mythtvsrc->live_tv_id = g_value_get_int (value); + break; + } + case PROP_MYTHTV_LIVE: + { + mythtvsrc->live_tv = g_value_get_boolean (value); + break; + } + case PROP_MYTHTV_LIVE_CHAINID: + { + if (!g_value_get_string (value)) { + GST_WARNING ("MythTV Live chainid property cannot be NULL"); + goto done; + } + + if (mythtvsrc->live_chain_id != NULL) { + g_free (mythtvsrc->live_chain_id); + mythtvsrc->live_chain_id = NULL; + } + mythtvsrc->live_chain_id = g_value_dup_string (value); + + break; + } + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + GST_OBJECT_UNLOCK (mythtvsrc); +done: + return; +} + + static void +gst_mythtv_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object); + + GST_OBJECT_LOCK (mythtvsrc); + switch (prop_id) { + case PROP_URI: + case PROP_LOCATION: + { + gchar *str = g_strdup( "" ); + + if ( mythtvsrc->uri_name == NULL ) { + g_free (mythtvsrc->uri_name); + mythtvsrc->uri_name = NULL; + } else { + str = g_strdup( mythtvsrc->uri_name ); + } + g_value_set_string ( value, str ); + break; + } +#ifndef GST_DISABLE_GST_DEBUG + case PROP_MYTHTV_DBG: + g_value_set_boolean ( value, mythtvsrc->mythtv_msgs_dbg ); + break; +#endif + case PROP_MYTHTV_VERSION: + { + g_value_set_int ( value, mythtvsrc->mythtv_version ); + break; + } + case PROP_MYTHTV_LIVEID: + { + g_value_set_int ( value, mythtvsrc->live_tv_id ); + break; + } + case PROP_MYTHTV_LIVE: + g_value_set_boolean ( value, mythtvsrc->live_tv ); + break; + case PROP_MYTHTV_LIVE_CHAINID: + { + gchar *str = g_strdup( "" ); + + if ( mythtvsrc->live_chain_id == NULL ) { + g_free (mythtvsrc->live_chain_id); + mythtvsrc->live_chain_id = NULL; + } else { + str = g_strdup( mythtvsrc->live_chain_id ); + } + g_value_set_string ( value, str ); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + GST_OBJECT_UNLOCK (mythtvsrc); +} + +/* entry point to initialize the plug-in + * initialize the plug-in itself + * register the element factories and pad templates + * register the features + */ + static gboolean +plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE, + GST_TYPE_MYTHTV_SRC); +} + +/* this is the structure that gst-register looks for + * so keep the name plugin_desc, or you cannot get your plug-in registered */ +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "mythtv", + "lib MythTV src", + plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") + + +/*** GSTURIHANDLER INTERFACE *************************************************/ + static guint +gst_mythtv_src_uri_get_type (void) +{ + return GST_URI_SRC; +} + + static gchar ** +gst_mythtv_src_uri_get_protocols (void) +{ + static gchar *protocols[] = { "myth", "myths", NULL }; + + return protocols; +} + + static const gchar * +gst_mythtv_src_uri_get_uri (GstURIHandler * handler) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (handler); + + return src->uri_name; +} + + static gboolean +gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (handler); + + gchar *protocol; + + protocol = gst_uri_get_protocol (uri); + if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) { + g_free (protocol); + return FALSE; + } + g_free (protocol); + g_object_set (src, "location", uri, NULL); + + return TRUE; +} + + static void +gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_mythtv_src_uri_get_type; + iface->get_protocols = gst_mythtv_src_uri_get_protocols; + iface->get_uri = gst_mythtv_src_uri_get_uri; + iface->set_uri = gst_mythtv_src_uri_set_uri; +} + + void +size_header_handler (void *userdata, const char *value) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (userdata); + + //src->content_size = g_ascii_strtoull (value, NULL, 10); + + GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size); +} diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/gstmythtvsrc.c.new --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/gstmythtvsrc.c.new Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,1033 @@ +/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2 -*- */ +/* GStreamer MythTV Plug-in + * Copyright (C) <2006> Rosfran Borges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstmythtvsrc.h" +#include "myth_file_transfer.h" +#include "myth_livetv.h" + +#include +#include + +#include +#include + +GST_DEBUG_CATEGORY_STATIC (mythtvsrc_debug); +#define GST_CAT_DEFAULT mythtvsrc_debug + +#define GST_MYTHTV_ID_NUM 1 + +#define MYTHTV_VERSION_DEFAULT 30 + +#define MYTHTV_TRANSFER_MAX_WAITS 100 + +#define MYTHTV_TRANSFER_MAX_BUFFER ( 32*1024 ) + +/* 4*1024 ??? */ +#define MAX_READ_SIZE ( 16*1024 ) + +#define ENABLE_TIMING_POSITION 1 + +/* stablish a maximum iteration value to the IS_RECORDING message */ +static guint wait_to_transfer = 0; + +static const GstElementDetails gst_mythtv_src_details = +GST_ELEMENT_DETAILS ("MythTV client source", + "Source/Network", + "Control and receive data as a client over the network via raw socket connections using the MythTV protocol", + "Rosfran Borges "); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstTask *update_size_task = NULL; + +static GStaticRecMutex update_size_mutex = G_STATIC_REC_MUTEX_INIT; + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_URI, +#ifndef GST_DISABLE_GST_DEBUG + PROP_MYTHTV_DBG, +#endif + PROP_MYTHTV_VERSION, + PROP_MYTHTV_LIVE, + PROP_MYTHTV_LIVEID, + PROP_MYTHTV_LIVE_CHAINID +}; + +static void gst_mythtv_src_finalize (GObject * gobject); + +static GstFlowReturn gst_mythtv_src_create (GstBaseSrc * psrc, + guint64 offset, guint size, GstBuffer ** outbuf); +static gboolean gst_mythtv_src_start (GstBaseSrc * bsrc); +static gboolean gst_mythtv_src_stop (GstBaseSrc * bsrc); +static gboolean gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size); +static gboolean gst_mythtv_src_is_seekable( GstBaseSrc *base_src ); + +static void gst_mythtv_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_mythtv_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void +gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data); + +static gboolean +gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event); + + static void +_urihandler_init (GType type) +{ + static const GInterfaceInfo urihandler_info = { + gst_mythtv_src_uri_handler_init, + NULL, + NULL + }; + + g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); + + GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, + "MythTV src"); +} + +GST_BOILERPLATE_FULL (GstMythtvSrc, gst_mythtv_src, GstBaseSrc, + GST_TYPE_BASE_SRC, _urihandler_init); + + static void +gst_mythtv_src_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&srctemplate)); + + gst_element_class_set_details (element_class, &gst_mythtv_src_details); +} + + static void +gst_mythtv_src_class_init (GstMythtvSrcClass * klass) +{ + GObjectClass *gobject_class; + GstBaseSrcClass *gstbasesrc_class; + + gobject_class = (GObjectClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + + gobject_class->set_property = gst_mythtv_src_set_property; + gobject_class->get_property = gst_mythtv_src_get_property; + gobject_class->finalize = gst_mythtv_src_finalize; + + g_object_class_install_property + (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "Location", + "The location. In the form:" + "\n\t\t\tmyth://a.com/file.nuv" + "\n\t\t\tmyth://a.com:23223/file.nuv " + "\n\t\t\ta.com/file.nuv - default scheme 'myth'", + "", G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_URI, + g_param_spec_string ("uri", "Uri", + "The location in form of a URI (deprecated; use location)", + "", G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_MYTHTV_VERSION, + g_param_spec_int ("mythtv-version", "mythtv-version", + "Change Myth TV version", + 26, 30, 26, G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_MYTHTV_LIVEID, + g_param_spec_int ("mythtv-live-id", "mythtv-live-id", + "Change Myth TV version", + 0, 200, GST_MYTHTV_ID_NUM, G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_MYTHTV_LIVE_CHAINID, + g_param_spec_string ("mythtv-live-chainid", "mythtv-live-chainid", + "Sets the Myth TV chain ID (from TV Chain)", + "", G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_MYTHTV_LIVE, + g_param_spec_boolean ("mythtv-live", "mythtv-live", + "Enable MythTV Live TV content streaming", + FALSE, G_PARAM_READWRITE)); + +#ifndef GST_DISABLE_GST_DEBUG + g_object_class_install_property + (gobject_class, PROP_MYTHTV_DBG, + g_param_spec_boolean ("mythtv-debug", "mythtv-debug", + "Enable MythTV debug messages", + FALSE, G_PARAM_READWRITE)); +#endif + + gstbasesrc_class->start = gst_mythtv_src_start; + gstbasesrc_class->stop = gst_mythtv_src_stop; + gstbasesrc_class->get_size = gst_mythtv_src_get_size; + gstbasesrc_class->is_seekable = gst_mythtv_src_is_seekable; + + gstbasesrc_class->create = gst_mythtv_src_create; + + GST_DEBUG_CATEGORY_INIT (mythtvsrc_debug, "mythtvsrc", 0, + "MythTV Client Source"); +} + + static void +gst_mythtv_src_init (GstMythtvSrc * this, GstMythtvSrcClass * g_class) +{ + this->file_transfer = NULL; + + this->unique_setup = FALSE; + + this->mythtv_version = MYTHTV_VERSION_DEFAULT; + + this->bytes_read = 0; + + this->content_size = -1; + this->read_offset = 0; + + this->live_tv = FALSE; + + this->user_agent = g_strdup ("mythtvsrc"); + this->mythtv_caps = NULL; + + gst_base_src_set_live ( GST_BASE_SRC( this ), TRUE ); + + gst_pad_set_event_function (GST_BASE_SRC_PAD(GST_BASE_SRC(this)), + GST_DEBUG_FUNCPTR (gst_mythtv_src_handle_event)); + +} + + static void +gst_mythtv_src_finalize (GObject * gobject) +{ + GstMythtvSrc *this = GST_MYTHTV_SRC (gobject); + + g_free (this->user_agent); + + if (this->mythtv_caps) { + gst_caps_unref (this->mythtv_caps); + this->mythtv_caps = NULL; + } + + if (this->file_transfer) { + g_object_unref (this->file_transfer); + this->file_transfer = NULL; + } + + if (this->uri_name) { + g_free (this->uri_name); + } + + if (this->user_agent) { + g_free (this->user_agent); + } + + if ( update_size_task != NULL ) { + + if ( GST_TASK_STATE( update_size_task ) != GST_TASK_STOPPED ) + gst_task_stop( update_size_task ); + + gst_object_unref( update_size_task ); + + update_size_task = NULL; + + } + + G_OBJECT_CLASS (parent_class)->finalize (gobject); +} + +#if 0 + static guint +do_seek( GstMythtvSrc *src, guint64 offset, guint size, GstBuffer *outbuf ) +{ + guint64 off_uint64 = myth_file_transfer_seek(src->file_transfer, offset, 1); + + g_print( "[%s] Call MythTV SEEK with offset %llu, got a new one %llu...\n", __FUNCTION__, + offset, off_uint64 ); + + return off_uint64; + +} +#endif + + static guint +do_read_request_response (GstMythtvSrc * src, guint64 offset, guint size, GstBuffer * outbuf) +{ + guint read = 0; + guint sizetoread = size; //GST_BUFFER_SIZE (outbuf); + + g_print( "[%s] Reading %d bytes...\n", __FUNCTION__, sizetoread ); + + /* Loop sending the request: + * Retry whilst authentication fails and we supply it. */ + + ssize_t len = 0; + + //GST_OBJECT_LOCK(src); + + while ( sizetoread > 0 ) { + + len = myth_file_transfer_read( src->file_transfer, + GST_BUFFER_DATA (outbuf) + read, sizetoread, TRUE ); + + if ( len > 0 ) { + read += len; + src->read_offset += read; + sizetoread -= len; + } else if ( len < 0 ) { + goto done; + } + else if ( len == 0 ) { + if ( src->live_tv == FALSE ) + goto done; + else + goto eos; + + } + + if ( len == sizetoread ) + break; + + } + + if ( read > 0 ) { + src->bytes_read += read; + + GST_BUFFER_SIZE (outbuf) = read; + } else if ( read <= 0 || len <= 0 ) { + if ( src->live_tv == FALSE ) + goto eos; + else + goto done; + } + //GST_BUFFER_OFFSET (outbuf) = src->read_offset; + + g_print( "[%s]\tBYTES READ (actual) = %d, BYTES READ (cumulative) = %llu, "\ + "OFFSET = %llu, CONTENT SIZE = %llu.\n", __FUNCTION__, read, src->bytes_read, + src->read_offset, src->content_size ); + + //GST_OBJECT_UNLOCK(src); + + if ( len < 0 ) { + read = len; + if ( src->live_tv == FALSE ) + goto eos; + else + goto done; + } + + if ( src->bytes_read < src->content_size ) + goto done; + +eos: + //GST_OBJECT_UNLOCK(src); + + src->eos = TRUE; +done: + //GST_OBJECT_UNLOCK(src); + + return read; +} + + static GstFlowReturn +gst_mythtv_src_create ( GstBaseSrc * psrc, guint64 offset, + guint size, GstBuffer **outbuf ) +{ + GstMythtvSrc *src; + GstFlowReturn ret = GST_FLOW_OK; + guint read = 0; + + src = GST_MYTHTV_SRC (psrc); + + //src->do_start = FALSE; + src->do_start = FALSE; + gst_task_join ( update_size_task ); + + g_print( "[%s]\tBUFFER OFFSET = %llu, BUFFER SIZE = %d.\n", __FUNCTION__, offset, + size ); + + /* The caller should know the number of bytes and not read beyond EOS. */ + //if (G_UNLIKELY (src->eos)) + // goto eos; + //g_static_rec_mutex_lock( &update_size_mutex ); + + /* Create the buffer. */ + ret = gst_pad_alloc_buffer ( GST_BASE_SRC_PAD (GST_BASE_SRC (psrc)), + // GST_BUFFER_OFFSET_NONE, GST_BASE_SRC (psrc)->blocksize, + offset, size, + src->mythtv_caps ? src->mythtv_caps : + GST_PAD_CAPS (GST_BASE_SRC_PAD (GST_BASE_SRC (psrc))), outbuf ); + + //if (G_UNLIKELY (ret == GST_FLOW_UNEXPECTED)) + // goto eos; + + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto eos; + + if (G_UNLIKELY (ret == GST_FLOW_ERROR)) + goto read_error; + + read = do_read_request_response ( src, offset, size, *outbuf ); + + //g_static_rec_mutex_unlock( &update_size_mutex ); + + src->do_start = TRUE; + gst_task_start ( update_size_task ); + +#if 0 + g_static_rec_mutex_lock( &update_size_mutex ); + src->do_start = FALSE; + g_static_rec_mutex_unlock( &update_size_mutex ); + GST_TASK_SIGNAL( update_size_task ); +#endif + + //g_static_rec_mutex_unlock( &update_size_mutex ); + +#if 0 +#if ENABLE_TIMING_POSITION == 1 + guint64 size_tmp = 0; + if (src->live_tv == TRUE) { + //g_usleep( 1000 ); +get_file_pos: + //g_usleep( 100 ); + size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) + src->content_size = size_tmp; + else + goto get_file_pos; + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", + __FUNCTION__, size_tmp); + + } +#endif +#endif + + //if (G_UNLIKELY (read < 0)) + // goto read_error; + + if (G_UNLIKELY(src->eos)) + goto eos; + else + goto done; + +done: + return ret; +eos: +#if 0 +#if ENABLE_TIMING_POSITION == 1 + if ( src->live_tv == TRUE ) { + //g_usleep( 1000 ); + guint64 size_tmp = 0; +get_file_pos_eos: + //g_usleep( 100 ); + size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) + src->content_size = size_tmp; + else + goto get_file_pos_eos; + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", + __FUNCTION__, size_tmp); + goto done; + } else +#endif +#endif + { + GST_DEBUG_OBJECT (src, "EOS reached"); + return GST_FLOW_UNEXPECTED; + } + /* ERRORS */ +read_error: + { + GST_ELEMENT_ERROR (src, RESOURCE, READ, + (NULL), ("Could not read any bytes (%i, %s)", read, + src->uri_name)); + return GST_FLOW_ERROR; + } + #if 0 +need_pause: + { + const gchar *reason = gst_flow_get_name (ret); + + GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason); + return GST_FLOW_UNEXPECTED; + } + #endif + +} + +#if 0 +/* The following two charset mangling functions were copied from gnomevfssrc. + * Preserve them under the unverified assumption that they do something vaguely + * worthwhile. + */ + static char * +unicodify (const char *str, int len, ...) +{ + char *ret = NULL, *cset; + va_list args; + gsize bytes_read, bytes_written; + + if (g_utf8_validate (str, len, NULL)) + return g_strndup (str, len >= 0 ? len : strlen (str)); + + va_start (args, len); + while ((cset = va_arg (args, char *)) != NULL) + { + if (!strcmp (cset, "locale")) + ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL); + else + ret = g_convert (str, len, "UTF-8", cset, + &bytes_read, &bytes_written, NULL); + if (ret) + break; + } + va_end (args); + + return ret; +} + + static char * +gst_mythtv_src_unicodify (const char *str) +{ + return unicodify (str, -1, "locale", "ISO-8859-1", NULL); +} +#endif + +void +update_size_func( void *mythtv_data ) +{ + GstMythtvSrc *src; + + g_return_if_fail( mythtv_data != NULL ); + + src = GST_MYTHTV_SRC ( mythtv_data ); + if ( src->do_start ) { + #if ENABLE_TIMING_POSITION == 1 + guint64 size_tmp = 0; + if (src->live_tv == TRUE) { +get_file_pos: + //g_usleep( 50 ); + size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); + if ( size_tmp > ( src->content_size + MYTHTV_TRANSFER_MAX_BUFFER ) ) + src->content_size = size_tmp; + else + goto get_file_pos; + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", + __FUNCTION__, size_tmp ); + } +#endif +} + gst_task_pause( update_size_task ); + // src->do_start = FALSE; + //GST_TASK_SIGNAL( update_size_task ); + +} + +/* create a socket for connecting to remote server */ + static gboolean +gst_mythtv_src_start ( GstBaseSrc * bsrc ) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (bsrc); + + GString *chain_id_local = NULL; + + gboolean ret = TRUE; +#if 0 + if (src->live_tv == TRUE && src->file_transfer != NULL) { + guint64 size_tmp = myth_file_transfer_get_file_position( src->file_transfer ); + if (size_tmp > src->content_size) + src->content_size = size_tmp; + g_print( "\t[%s]\tGET_POSITION: file_position = %llu\n", + __FUNCTION__, size_tmp); + } +#endif + if (src->unique_setup == FALSE) { + src->unique_setup = TRUE; + } else { + goto done; + } + + //GST_OBJECT_LOCK(src); + + if ( src->live_tv ) { + src->spawn_livetv = myth_livetv_new( ); + if ( myth_livetv_setup( src->spawn_livetv ) == FALSE ) { + ret = FALSE; + goto init_failed; + } + /* set up the uri variable */ + src->uri_name = g_strdup( src->spawn_livetv->proginfo->pathname->str ); + chain_id_local = gmyth_tvchain_get_id( src->spawn_livetv->tvchain ); + if ( chain_id_local != NULL ) { + src->live_chain_id = g_strdup( chain_id_local->str ); + g_print( "\t[%s]\tLocal chain ID = %s.\n", __FUNCTION__, src->live_chain_id ); + } + src->live_tv_id = src->spawn_livetv->remote_encoder->recorder_num; + g_print ( "[%s] LiveTV id = %d, URI path = %s.\n", __FUNCTION__, src->live_tv_id, src->uri_name ); + } + + src->file_transfer = myth_file_transfer_new( src->live_tv_id, + g_string_new( src->uri_name ), -1, src->mythtv_version ); + + if ( src->file_transfer == NULL ) { + //GST_OBJECT_UNLOCK(src); + + goto init_failed; + } + + if ( src->live_tv ) { + g_print ( "[%s] GST MYTHTVSRC: live_chain_id = %s\n", __FUNCTION__, src->live_chain_id ); + /* sets the MythSocket to the FileTransfer */ + //ret = myth_file_transfer_livetv_setup( &(src->file_transfer), src->spawn_livetv->remote_encoder->myth_socket ); + } + /* sets the Playback monitor connection */ + ret = myth_file_transfer_playback_setup( &(src->file_transfer), src->live_tv ); + + if ( src->live_tv == TRUE && ret == TRUE ) { + /* loop finished, set the max tries variable to zero again... */ + wait_to_transfer = 0; + + while ( wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS && ( myth_file_transfer_is_recording( src->file_transfer ) == FALSE + /*|| ( myth_file_transfer_get_file_position( src->file_transfer ) < ( src->content_size + 327680 ) )*/ ) ) + g_usleep( 100 ); + } + + /* sets the FileTransfer instance connection (video/audio download) */ + ret = myth_file_transfer_setup( &(src->file_transfer), src->live_tv ); + + if ( ret == FALSE ) { + //GST_OBJECT_UNLOCK(src); +#ifndef GST_DISABLE_GST_DEBUG + if ( src->mythtv_msgs_dbg ) + g_printerr( "MythTV FileTransfer request failed when setting up socket connection!\n" ); +#endif + goto begin_req_failed; + } + + src->content_size = src->file_transfer->filesize; + + //GST_OBJECT_UNLOCK(src); + + update_size_task = gst_task_create( update_size_func, src ); + + gst_task_set_lock( update_size_task, &update_size_mutex ); + + g_print( "[%s] Update Size task = %s\n", __FUNCTION__, gst_task_start( update_size_task ) && + GST_TASK_STATE( update_size_task ) == GST_TASK_STARTED ? "OK !" : "ERROR!!!" ); + + src->do_start = TRUE; + +#if 0 + const char *str_value; + gint gint_value; + + str_value = ne_get_response_header (src->request, "myth-metaint"); + if (str_value) { + if ( sscanf (str_value, "%d", &gint_value) == 1 ) { + if (src->myth_caps) { + gst_caps_unref (src->myth_caps); + src->myth_caps = NULL; + } + src->myth_metaint = gint_value; +#endif + //src->mythtv_caps = gst_caps_new_simple ("application/x-gst_ff-nuv", NULL); + // } + // } +done: + return TRUE; + + /* ERRORS */ +init_failed: + { + if (src->spawn_livetv != NULL ) + g_object_unref( src->spawn_livetv ); + + GST_ELEMENT_ERROR (src, LIBRARY, INIT, + (NULL), ("Could not initialize MythTV library (%i, %s)", ret, src->uri_name)); + return FALSE; + } +begin_req_failed: + { + GST_ELEMENT_ERROR (src, LIBRARY, INIT, + (NULL), ("Could not begin request sent to MythTV server (%i, %s)", ret, src->uri_name)); + return FALSE; + } +} + +#if 0 +static gboolean +gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size) +{ + GstMythtvSrc *src; + gboolean ret = FALSE; + + src = GST_MYTHTV_SRC (bsrc); + + g_static_rec_mutex_lock( &update_size_mutex ); + src->do_start = FALSE; + g_static_rec_mutex_unlock( &update_size_mutex ); + GST_TASK_SIGNAL( update_size_task ); + + + while (1) { + + g_static_rec_mutex_lock( &update_size_mutex ); + if ( !src->do_start ) { + + g_print( "[%s] GET SIZE: do_start? == %s\n", __FUNCTION__, src->do_start ? "YES" : "NO" ); + + GST_TASK_WAIT( update_size_task ); + } else { + if (src->content_size <= 0) { + g_static_rec_mutex_unlock( &update_size_mutex ); + goto done; + } + + *size = src->content_size; + src->do_start = FALSE; + + g_static_rec_mutex_unlock( &update_size_mutex ); + + break; + } + g_static_rec_mutex_unlock( &update_size_mutex ); + + } // while (1) + +done: + return ret; + +} +#endif + +static gboolean +gst_mythtv_src_get_size (GstBaseSrc * bsrc, guint64 * size) +{ + GstMythtvSrc *src; + gboolean ret = TRUE; + + src = GST_MYTHTV_SRC (bsrc); + + if (src->content_size <= 0) + ret= FALSE; + + *size = src->content_size; + + return ret; + +} +/* close the socket and associated resources + * used both to recover from errors and go to NULL state */ + static gboolean +gst_mythtv_src_stop (GstBaseSrc * bsrc) +{ + GstMythtvSrc *src; + + src = GST_MYTHTV_SRC (bsrc); + + if (src->uri_name) { + g_free (src->uri_name); + src->uri_name = NULL; + } + + if (src->mythtv_caps) { + gst_caps_unref (src->mythtv_caps); + src->mythtv_caps = NULL; + } + + src->eos = FALSE; + + return TRUE; +} + + static gboolean +gst_mythtv_src_handle_event (GstPad * pad, GstEvent * event) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (GST_PAD_PARENT (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + src->eos = FALSE; + break; + //return TRUE; +#if 0 +case GST_EVENT_FLUSH_STOP: + src->do_start = TRUE; + src->eos = FALSE; + gst_element_set_state (GST_ELEMENT(src), GST_STATE_NULL); + //gst_element_set_locked_state (GST_ELEMENT(src), TRUE); + break; +#endif + case GST_EVENT_SEEK: + { + gdouble rate; + //gboolean update = TRUE; + GstFormat format; + GstSeekType cur_type, stop_type; + GstSeekFlags flags; + gint64 cur = 0, stop = 0; + gst_event_parse_seek ( event, &rate, &format, + &flags, &cur_type, &cur, + &stop_type, &stop ); + + g_print( "[%s] Got EVENT_SEEK.\n", __FUNCTION__ ); + if ( !( flags & GST_SEEK_FLAG_FLUSH ) ) { + g_print( "[%s] Could get the FLAG_FLUSH message.\n", __FUNCTION__ ); + } + //gboolean ret = gst_event_parse_new_segment ( event, + // &update, &rate, &format, &start, &stop, + // &position ); + //GstFlowReturn flow_ret = gst_mythtv_src_create (GST_BASE_SRC( GST_PAD_PARENT( psrc ) ), + // cur, stop - cur + 1, GstBuffer) + + } + default: + return gst_pad_event_default (pad, event); + } + + return gst_pad_event_default (pad, event); +} + + static gboolean +gst_mythtv_src_is_seekable( GstBaseSrc *base_src ) +{ + return TRUE; +} + + static void +gst_mythtv_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object); + + GST_OBJECT_LOCK (mythtvsrc); + switch (prop_id) { + case PROP_URI: + case PROP_LOCATION: + { + if (!g_value_get_string (value)) { + GST_WARNING ("location property cannot be NULL"); + goto done; + } + + if (mythtvsrc->uri_name != NULL) { + g_free (mythtvsrc->uri_name); + mythtvsrc->uri_name = NULL; + } + mythtvsrc->uri_name = g_value_dup_string (value); + + break; + } +#ifndef GST_DISABLE_GST_DEBUG + case PROP_MYTHTV_DBG: + { + mythtvsrc->mythtv_msgs_dbg = g_value_get_boolean (value); + break; + } +#endif + case PROP_MYTHTV_VERSION: + { + mythtvsrc->mythtv_version = g_value_get_int (value); + break; + } + case PROP_MYTHTV_LIVEID: + { + mythtvsrc->live_tv_id = g_value_get_int (value); + break; + } + case PROP_MYTHTV_LIVE: + { + mythtvsrc->live_tv = g_value_get_boolean (value); + break; + } + case PROP_MYTHTV_LIVE_CHAINID: + { + if (!g_value_get_string (value)) { + GST_WARNING ("MythTV Live chainid property cannot be NULL"); + goto done; + } + + if (mythtvsrc->live_chain_id != NULL) { + g_free (mythtvsrc->live_chain_id); + mythtvsrc->live_chain_id = NULL; + } + mythtvsrc->live_chain_id = g_value_dup_string (value); + + break; + } + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + GST_OBJECT_UNLOCK (mythtvsrc); +done: + return; +} + + static void +gst_mythtv_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstMythtvSrc *mythtvsrc = GST_MYTHTV_SRC (object); + + GST_OBJECT_LOCK (mythtvsrc); + switch (prop_id) { + case PROP_URI: + case PROP_LOCATION: + { + gchar *str = g_strdup( "" ); + + if ( mythtvsrc->uri_name == NULL ) { + g_free (mythtvsrc->uri_name); + mythtvsrc->uri_name = NULL; + } else { + str = g_strdup( mythtvsrc->uri_name ); + } + g_value_set_string ( value, str ); + break; + } +#ifndef GST_DISABLE_GST_DEBUG + case PROP_MYTHTV_DBG: + g_value_set_boolean ( value, mythtvsrc->mythtv_msgs_dbg ); + break; +#endif + case PROP_MYTHTV_VERSION: + { + g_value_set_int ( value, mythtvsrc->mythtv_version ); + break; + } + case PROP_MYTHTV_LIVEID: + { + g_value_set_int ( value, mythtvsrc->live_tv_id ); + break; + } + case PROP_MYTHTV_LIVE: + g_value_set_boolean ( value, mythtvsrc->live_tv ); + break; + case PROP_MYTHTV_LIVE_CHAINID: + { + gchar *str = g_strdup( "" ); + + if ( mythtvsrc->live_chain_id == NULL ) { + g_free (mythtvsrc->live_chain_id); + mythtvsrc->live_chain_id = NULL; + } else { + str = g_strdup( mythtvsrc->live_chain_id ); + } + g_value_set_string ( value, str ); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + GST_OBJECT_UNLOCK (mythtvsrc); +} + +/* entry point to initialize the plug-in + * initialize the plug-in itself + * register the element factories and pad templates + * register the features + */ + static gboolean +plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "mythtvsrc", GST_RANK_NONE, + GST_TYPE_MYTHTV_SRC); +} + +/* this is the structure that gst-register looks for + * so keep the name plugin_desc, or you cannot get your plug-in registered */ +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "mythtv", + "lib MythTV src", + plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") + + +/*** GSTURIHANDLER INTERFACE *************************************************/ + static guint +gst_mythtv_src_uri_get_type (void) +{ + return GST_URI_SRC; +} + + static gchar ** +gst_mythtv_src_uri_get_protocols (void) +{ + static gchar *protocols[] = { "myth", "myths", NULL }; + + return protocols; +} + + static const gchar * +gst_mythtv_src_uri_get_uri (GstURIHandler * handler) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (handler); + + return src->uri_name; +} + + static gboolean +gst_mythtv_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (handler); + + gchar *protocol; + + protocol = gst_uri_get_protocol (uri); + if ((strcmp (protocol, "myth") != 0) && (strcmp (protocol, "myths") != 0)) { + g_free (protocol); + return FALSE; + } + g_free (protocol); + g_object_set (src, "location", uri, NULL); + + return TRUE; +} + + static void +gst_mythtv_src_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_mythtv_src_uri_get_type; + iface->get_protocols = gst_mythtv_src_uri_get_protocols; + iface->get_uri = gst_mythtv_src_uri_get_uri; + iface->set_uri = gst_mythtv_src_uri_set_uri; +} + + void +size_header_handler (void *userdata, const char *value) +{ + GstMythtvSrc *src = GST_MYTHTV_SRC (userdata); + + //src->content_size = g_ascii_strtoull (value, NULL, 10); + + GST_DEBUG_OBJECT (src, "content size = %lld bytes", src->content_size); +} diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/gstmythtvsrc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/gstmythtvsrc.h Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,89 @@ +/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2 -*- */ +/* GStreamer + * Copyright (C) <2006> Rosfran Borges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more + */ + +#ifndef __GST_MYTHTV_SRC_H__ +#define __GST_MYTHTV_SRC_H__ + +#include +#include +#include + +#include +#include "myth_file_transfer.h" +#include "myth_livetv.h" + +G_BEGIN_DECLS + +#define GST_TYPE_MYTHTV_SRC \ + (gst_mythtv_src_get_type()) +#define GST_MYTHTV_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MYTHTV_SRC,GstMythtvSrc)) +#define GST_MYTHTV_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MYTHTV_SRC,GstMythtvSrcClass)) +#define GST_IS_MYTHTV_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MYTHTV_SRC)) +#define GST_IS_MYTHTV_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MYTHTV_SRC)) + +typedef struct _GstMythtvSrc GstMythtvSrc; +typedef struct _GstMythtvSrcClass GstMythtvSrcClass; + +struct _GstMythtvSrc { + GstBaseSrc element; + + /* MythFileTransfer */ + MythFileTransfer *file_transfer; + + MythLiveTV *spawn_livetv; + + gchar *uri_name; + gchar *user_agent; + + gchar *live_chain_id; + + gint mythtv_version; + + guint64 content_size; + + guint64 bytes_read; + + guint64 read_offset; + + gboolean eos; + + gboolean do_start; + + gboolean unique_setup; + + gboolean live_tv; + + gint live_tv_id; + + /* MythTV capabilities */ + GstCaps *mythtv_caps; + + /* enable Myth TV debug messages */ + gboolean mythtv_msgs_dbg; +}; + +struct _GstMythtvSrcClass { + GstBaseSrcClass parent_class; +}; + +GType gst_mythtv_src_get_type (void); + +G_END_DECLS + +#endif /* __GST_MYTHTV_SRC_H__ */ diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/myth_file_transfer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/myth_file_transfer.c Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,960 @@ +/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */ +/** + * GStreamer plug-in properties: + * - location (backend server hostname/URL) [ex.: myth://192.168.1.73:28722/1000_1092091.nuv] + * - path (qurl - remote file to be opened) + * - port number + * @author Rosfran Lins Borges + */ + +#include "myth_file_transfer.h" +#include "myth_uri.h" +#include "myth_livetv.h" +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MYTHTV_QUERY_HEADER "QUERY_FILETRANSFER" +#define MYTHTV_RECORDER_HEADER "QUERY_RECORDER" + +/* default values to the file transfer parameters */ +#define MYTHTV_USER_READ_AHEAD FALSE +#define MYTHTV_RETRIES 1 +#define MYTHTV_FILE_SIZE -1 + +#define MYTHTV_BUFFER_SIZE 2048 + +#define MYTHTV_VERSION 30 + +#define MYTHTV_TRANSFER_MAX_WAITS 700 + +#ifdef MYTHTV_ENABLE_DEBUG +#define MYTHTV_ENABLE_DEBUG 1 +#else +#undef MYTHTV_ENABLE_DEBUG +#endif + +/* this NDEBUG is to maintain compatibility with GMyth library */ +#ifndef NDEBUG +#define MYTHTV_ENABLE_DEBUG 1 +#endif + +static guint wait_to_transfer = 0; + +enum myth_sock_types { + MYTH_PLAYBACK_TYPE = 0, + MYTH_MONITOR_TYPE, + MYTH_FILETRANSFER_TYPE, + MYTH_RINGBUFFER_TYPE +}; + +static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + +static void myth_file_transfer_class_init (MythFileTransferClass *klass); +static void myth_file_transfer_init (MythFileTransfer *object); + +static void myth_file_transfer_dispose (GObject *object); +static void myth_file_transfer_finalize (GObject *object); + +static GMythSocket *myth_connect_to_transfer_backend( MythFileTransfer **transfer, guint sock_type ); +static void* myth_init_io_watchers( void *data ); + +void myth_file_transfer_close( MythFileTransfer *transfer ); + +G_DEFINE_TYPE(MythFileTransfer, myth_file_transfer, G_TYPE_OBJECT) + +static guint64 +mmyth_util_decode_long_long( GMythStringList *strlist, guint offset ) +{ + + guint64 ret_value = 0LL; + + g_return_val_if_fail( strlist != NULL, ret_value ); + + if ( offset < gmyth_string_list_length( strlist )) + g_printerr( "[%s] Offset is lower than the GMythStringList (offset = %d)!\n", __FUNCTION__, offset ); + g_return_val_if_fail( offset < gmyth_string_list_length( strlist ), ret_value ); + + gint l1 = gmyth_string_list_get_int( strlist, offset ); + gint l2 = gmyth_string_list_get_int( strlist, offset + 1 ); + + ret_value = ((guint64)(l2) & 0xffffffffLL) | ((guint64)(l1) << 32); + + return ret_value; + +} + +static void +myth_file_transfer_class_init (MythFileTransferClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = myth_file_transfer_dispose; + gobject_class->finalize = myth_file_transfer_finalize; +} + + static void +myth_file_transfer_init (MythFileTransfer *myth_file_transfer) +{ + g_return_if_fail( myth_file_transfer != NULL ); + myth_file_transfer->mythtv_version = MYTHTV_VERSION; +} + +static void +myth_file_transfer_dispose (GObject *object) +{ + MythFileTransfer *myth_file_transfer = MYTH_FILE_TRANSFER(object); + + myth_file_transfer_close( myth_file_transfer ); + + G_OBJECT_CLASS (myth_file_transfer_parent_class)->dispose (object); +} + + static void +myth_file_transfer_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + G_OBJECT_CLASS (myth_file_transfer_parent_class)->finalize (object); +} + + MythFileTransfer* +myth_file_transfer_new (gint num, GString *uri_str, gshort port, gint mythtv_version) +{ + MythFileTransfer *transfer = MYTH_FILE_TRANSFER ( g_object_new ( + MYTH_FILE_TRANSFER_TYPE, FALSE )); + + if ( mythtv_version > 0 ) + transfer->mythtv_version = mythtv_version; + + transfer->card_id = num; + + transfer->rec_id = -1; + + transfer->recordernum = 0; + transfer->uri = myth_uri_new ( uri_str->str ); + + transfer->hostname = g_string_new( myth_uri_gethost(transfer->uri) ); + g_print( "\t--> transfer->hostname = %s\n", transfer->hostname->str ); + + if ( port >= 0 ) + transfer->port = port; + else + transfer->port = myth_uri_getport( transfer->uri ); + + g_print( "\t--> transfer->port = %d\n", transfer->port ); + + transfer->readposition = 0; + transfer->filesize = MYTHTV_FILE_SIZE; + transfer->timeoutisfast = FALSE; + + transfer->userreadahead = MYTHTV_USER_READ_AHEAD; + transfer->retries = MYTHTV_RETRIES; + + transfer->live_tv = FALSE; + + transfer->query = g_string_new( MYTHTV_QUERY_HEADER ); + g_string_append_printf ( transfer->query, " %d", transfer->recordernum ); + g_print( "\t--> transfer->query = %s\n", transfer->query->str ); + + transfer->control_sock = NULL; + transfer->event_sock = NULL; + transfer->sock = NULL; + + return transfer; +} + +gboolean +myth_file_transfer_livetv_setup( MythFileTransfer **transfer, GMythSocket *live_socket ) +{ + (*transfer)->sock = live_socket; + g_object_ref( live_socket ); + + return TRUE; +} + +gboolean +myth_file_transfer_playback_setup( MythFileTransfer **transfer, gboolean live_tv ) +{ + + gboolean ret = TRUE; + + (*transfer)->live_tv = live_tv; + + printf("[%s] Running config to the %s...\n", __FUNCTION__, live_tv ? "LiveTV" : "FileTransfer" ); + + /* configure the control socket */ + if ((*transfer)->control_sock == NULL) { + + if ( myth_connect_to_transfer_backend ( transfer, MYTH_PLAYBACK_TYPE ) == NULL ) { + g_printerr( "Connection to backend failed (Control Socket).\n" ); + ret = FALSE; + } + + } else { + g_warning("Remote transfer control socket already created.\n"); + } + + return ret; + +} + +gboolean +myth_file_transfer_setup( MythFileTransfer **transfer, gboolean live_tv ) +{ + GMythStringList *strlist = NULL; + + gboolean ret = TRUE; + + (*transfer)->live_tv = live_tv; + + printf("[%s] Running config to the %s...\n", __FUNCTION__, live_tv ? "LiveTV" : "FileTransfer" ); + +#if 0 + /* configure the event socket */ + if ((*transfer)->event_sock == NULL) { + + if ( myth_connect_to_transfer_backend ( transfer, MYTH_MONITOR_TYPE ) == NULL ) { + g_printerr( "Connection to backend failed (Event Socket).\n" ); + ret = FALSE; + } + + } else { + g_warning("Remote transfer control socket already created.\n"); + } +#endif + + /* configure the socket */ + if ( (*transfer)->sock == NULL ) { + + //if ( live_tv == FALSE ) { + + if ( myth_connect_to_transfer_backend ( transfer, MYTH_FILETRANSFER_TYPE ) == NULL ) { + g_printerr ("Connection to backend failed (Raw Transfer Socket).\n"); + ret = FALSE; + } + + if ( !(*transfer)->live_tv && (*transfer)->control_sock != NULL) { + strlist = gmyth_string_list_new(); + g_string_printf ( (*transfer)->query, "%s %d", MYTHTV_QUERY_HEADER, (*transfer)->recordernum ); + + gmyth_string_list_append_string( strlist, (*transfer)->query ); + gmyth_string_list_append_char_array( strlist, "IS_OPEN" ); + + gmyth_socket_write_stringlist( (*transfer)->control_sock, strlist ); + gmyth_socket_read_stringlist( (*transfer)->control_sock, strlist ); + + if ( strlist!=NULL && gmyth_string_list_get_int( strlist, 0 ) == 1 ) { + g_print( "[%s] Remote Myth FileTransfer socket is open!\n", __FUNCTION__ ); + } else { + g_print( "[%s] Remote Myth FileTransfer socket is CLOSED! See the MythTV Server Backend for configuration details...\n", __FUNCTION__ ); + ret = FALSE; + } + } + + } else { + g_warning("Remote transfer (raw) socket already created.\n"); + } + + return ret; +} + +static GMythSocket * +myth_connect_to_transfer_backend( MythFileTransfer **transfer, guint sock_type ) +{ + GMythSocket *sock = NULL; + + g_return_val_if_fail( transfer != NULL && *transfer != NULL, NULL ); + g_return_val_if_fail( (*transfer)->uri != NULL, NULL ); + + g_static_mutex_lock (&mutex); + + gchar *path_dir = myth_uri_getpath( (*transfer)->uri ); + //g_print( "\t--> %s: path_dir = %s\n", __FUNCTION__, path_dir ); + + gchar *stype = g_strdup( "" ); + + // if ( (*transfer)->live_tv == FALSE ) { + + sock = gmyth_socket_new(); + + gmyth_socket_connect( &sock, (*transfer)->hostname->str, (*transfer)->port ); + + /* + } else { + sock = (*transfer)->sock; + } + */ +#ifdef MYTHTV_ENABLE_DEBUG + + g_print( "[%s] --> Creating socket... (%s, %d)\n", __FUNCTION__, (*transfer)->hostname->str, (*transfer)->port ); +#endif + + GMythStringList *strlist = NULL; + + GString *hostname = g_string_new( myth_uri_gethost( (*transfer)->uri ) ); + GString *base_str = g_string_new( "" ); + + if ( gmyth_socket_check_protocol_version_number (sock, (*transfer)->mythtv_version) ) { + + if (sock == NULL) { + stype = (sock_type==MYTH_PLAYBACK_TYPE) ? "control socket" : "file data socket"; + g_printerr( "FileTransfer, open_socket(%s): \n" + "\t\t\tCould not connect to server \"%s\" @ port %d\n", stype, + (*transfer)->hostname->str, (*transfer)->port ); + g_object_unref(sock); + g_static_mutex_unlock (&mutex); + return NULL; + } + + hostname = gmyth_socket_get_local_hostname(); + + g_print( "[%s] local hostname = %s\n", __FUNCTION__, hostname->str ); + + if ( sock_type == MYTH_PLAYBACK_TYPE ) + { + (*transfer)->control_sock = sock; + g_string_printf( base_str, "ANN Playback %s %d", hostname->str, FALSE ); + + gmyth_socket_send_command( (*transfer)->control_sock, base_str ); + GString *resp = gmyth_socket_receive_response( (*transfer)->control_sock ); + g_print( "[%s] Got Playback response from %s: %s\n", __FUNCTION__, base_str->str, resp->str ); + } + else if ( sock_type == MYTH_MONITOR_TYPE ) + { + (*transfer)->event_sock = sock; + g_string_printf( base_str, "ANN Monitor %s %d", hostname->str, TRUE ); + + gmyth_socket_send_command( (*transfer)->event_sock, base_str ); + GString *resp = gmyth_socket_receive_response( (*transfer)->event_sock ); + g_print( "[%s] Got Monitor response from %s: %s\n", __FUNCTION__, base_str->str, resp->str ); + g_thread_create( myth_init_io_watchers, (void*)(*transfer), FALSE, NULL ); + + g_printerr( "[%s] Watch listener function to the IO control channel on thread %p.\n", __FUNCTION__, g_thread_self() ); + + } + else if ( sock_type == MYTH_FILETRANSFER_TYPE ) + { + (*transfer)->sock = sock; + strlist = gmyth_string_list_new(); + //g_string_printf( base_str, "ANN FileTransfer %s %d %d", hostname->str, + // transfer->userreadahead, transfer->retries ); + g_string_printf( base_str, "ANN FileTransfer %s", hostname->str ); + + gmyth_string_list_append_string( strlist, base_str ); + gmyth_string_list_append_char_array( strlist, path_dir ); + + gmyth_socket_write_stringlist( (*transfer)->sock, strlist ); + gmyth_socket_read_stringlist( (*transfer)->sock, strlist ); + + /* socket number, where all the stream data comes from - got from the MythTV remote backend */ + (*transfer)->recordernum = gmyth_string_list_get_int( strlist, 1 ); + + /* Myth URI stream file size - decoded using two 8-bytes sequences (64 bits/long long types) */ + (*transfer)->filesize = mmyth_util_decode_long_long( strlist, 2 ); + + printf( "[%s] ***** Received: recordernum = %d, filesize = %" G_GUINT64_FORMAT "\n", __FUNCTION__, + (*transfer)->recordernum, (*transfer)->filesize ); + + if ( (*transfer)->filesize <= 0 ) { + g_print( "[%s] Got filesize equals to %llu is lesser than 0 [invalid stream file]\n", __FUNCTION__, (*transfer)->filesize ); + g_object_unref(sock); + sock = NULL; + } + } + else if ( sock_type == MYTH_RINGBUFFER_TYPE ) + { + (*transfer)->sock = sock; + //myth_file_transfer_spawntv( (*transfer), NULL ); + + strlist = gmyth_string_list_new(); + g_string_printf( base_str, "ANN RingBuffer %s %d", hostname->str, (*transfer)->card_id ); + + gmyth_socket_send_command( (*transfer)->sock, base_str ); + GString *resp = gmyth_socket_receive_response( (*transfer)->sock ); + g_print( "[%s] Got RingBuffer response from %s: %s\n", __FUNCTION__, base_str->str, resp->str ); + + } + + } + + printf("[%s] ANN %s sent: %s\n", (sock_type==MYTH_PLAYBACK_TYPE) ? "Playback" : (sock_type==MYTH_FILETRANSFER_TYPE) ? "FileTransfer" : "Monitor", __FUNCTION__, base_str->str); + + if ( strlist != NULL ) + g_object_unref( strlist ); + + g_static_mutex_unlock (&mutex); + + return sock; +} + +void +myth_file_transfer_spawntv ( MythFileTransfer *file_transfer, + GString *tvchain_id ) +{ + GMythStringList *str_list; + + g_debug ("myth_file_transfer_spawntv.\n"); + + str_list = gmyth_string_list_new (); + + g_string_printf( file_transfer->query, "%s %d", MYTHTV_RECORDER_HEADER, + file_transfer->card_id ); + gmyth_string_list_append_string (str_list, file_transfer->query); + gmyth_string_list_append_string (str_list, g_string_new ("SPAWN_LIVETV")); + if (tvchain_id!=NULL) { + gmyth_string_list_append_string (str_list, tvchain_id); + gmyth_string_list_append_int (str_list, FALSE); // PIP = FALSE (0) + } + + gmyth_socket_sendreceive_stringlist ( file_transfer->sock, str_list ); + + //GString *str = NULL; + + //if (str_list!=NULL && (str = gmyth_string_list_get_string( str_list, 0 )) != NULL && strcasecmp( str->str, "ok" ) != 0 ) { + // g_print( "[%s]\t\tSpawnLiveTV is OK!\n", __FUNCTION__ ); + //} + if (str_list!=NULL) + g_object_unref (str_list); + +} + +gboolean +myth_file_transfer_is_recording ( MythFileTransfer *file_transfer ) +{ + gboolean ret = TRUE; + + GMythStringList *str_list = gmyth_string_list_new (); + + g_debug ( "[%s]\n", __FUNCTION__ ); + g_static_mutex_lock (&mutex); + + g_string_printf( file_transfer->query, "%s %d", MYTHTV_RECORDER_HEADER, + file_transfer->rec_id >= 0 ? file_transfer->rec_id : file_transfer->card_id ); + gmyth_string_list_append_string (str_list, file_transfer->query); + gmyth_string_list_append_string (str_list, g_string_new ("IS_RECORDING")); + + gmyth_socket_sendreceive_stringlist ( file_transfer->control_sock, str_list ); + + if ( str_list != NULL && gmyth_string_list_length(str_list) > 0 ) + { + GString *str = NULL; + if ( ( str = gmyth_string_list_get_string( str_list, 0 ) ) != NULL && strcmp( str->str, "bad" )!= 0 ) { + gint is_rec = gmyth_string_list_get_int( str_list, 0 ); + if ( is_rec != 0 ) + ret = TRUE; + else + ret = FALSE; + } + } + g_print( "[%s] %s, stream is %s being recorded!\n", __FUNCTION__, ret ? "YES" : "NO", ret ? "" : "NOT" ); + g_static_mutex_unlock (&mutex); + + if ( str_list != NULL ) + g_object_unref (str_list); + + return ret; + +} + +guint64 +myth_file_transfer_get_file_position ( MythFileTransfer *file_transfer ) +{ + guint64 pos = 0; + + GMythStringList *str_list = gmyth_string_list_new (); + + g_debug ( "[%s]\n", __FUNCTION__ ); + g_static_mutex_lock (&mutex); + + g_string_printf( file_transfer->query, "%s %d", MYTHTV_RECORDER_HEADER, + file_transfer->rec_id >= 0 ? file_transfer->rec_id : file_transfer->card_id ); + + gmyth_string_list_append_string (str_list, file_transfer->query); + gmyth_string_list_append_string (str_list, g_string_new ("GET_FILE_POSITION")); + + gmyth_socket_sendreceive_stringlist ( file_transfer->control_sock, str_list ); + + if ( str_list != NULL && gmyth_string_list_length(str_list) > 0 ) + { + GString *str = NULL; + if ( ( str = gmyth_string_list_get_string( str_list, 0 ) ) != NULL && strcmp ( str->str, "bad" ) != 0 ) + pos = gmyth_util_decode_long_long( str_list, 0 ); + } + g_static_mutex_unlock (&mutex); + +#ifndef MYTHTV_ENABLE_DEBUG + + g_print( "[%s] Got file position = %llu\n", __FUNCTION__, pos ); +#endif + if (str_list!=NULL) + g_object_unref (str_list); + + return pos; + +} + + glong +myth_file_transfer_get_recordernum( MythFileTransfer *transfer ) +{ + return transfer->recordernum; +} + + glong +myth_file_transfer_get_filesize( MythFileTransfer *transfer ) +{ + return transfer->filesize; +} + + gboolean +myth_file_transfer_isopen( MythFileTransfer *transfer ) +{ + return (transfer->sock != NULL && transfer->control_sock != NULL); +} + + void +myth_file_transfer_close( MythFileTransfer *transfer ) +{ + GMythStringList *strlist; + + if (transfer->control_sock == NULL) + return; + + strlist = gmyth_string_list_new( ); + + g_string_printf( transfer->query, "%s %d", MYTHTV_QUERY_HEADER, + transfer->recordernum ); + gmyth_string_list_append_string( strlist, transfer->query ); + gmyth_string_list_append_char_array( strlist, "DONE" ); + + + if ( gmyth_socket_sendreceive_stringlist(transfer->control_sock, strlist) <= 0 ) + { + g_printerr( "Remote file timeout.\n" ); + } + + if (transfer->sock) + { + g_object_unref( transfer->sock ); + transfer->sock = NULL; + } + + if (transfer->control_sock) + { + g_object_unref( transfer->control_sock ); + transfer->control_sock = NULL; + } + +} + + void +myth_file_transfer_reset_controlsock( MythFileTransfer *transfer ) +{ + if (transfer->control_sock == NULL) + { + g_printerr( "myth_file_transfer_reset_controlsock(): Called with no control socket" ); + return; + } + + GString *str = gmyth_socket_receive_response( transfer->control_sock ); + + g_string_free( str, TRUE ); +} + +void +myth_file_transfer_reset_sock( MythFileTransfer *transfer ) +{ + if ( transfer->sock == NULL ) + { + g_printerr( "myth_file_transfer_reset_sock(): Called with no raw socket" ); + return; + } + + GString *str = gmyth_socket_receive_response( transfer->sock ); + + g_string_free( str, TRUE ); +} + +void +myth_file_transfer_reset( MythFileTransfer *transfer ) +{ + myth_file_transfer_reset_controlsock( transfer ); + myth_file_transfer_reset_sock( transfer ); +} + +guint64 +myth_file_transfer_seek(MythFileTransfer *transfer, guint64 pos, gint whence) +{ + if (transfer->sock == NULL) + { + g_printerr( "[%s] myth_file_transfer_seek(): Called with no socket", __FUNCTION__ ); + return 0; + } + + if (transfer->control_sock == NULL) + return 0; + + // if (!controlSock->isOpen() || controlSock->error()) + // return 0; + + GMythStringList *strlist = gmyth_string_list_new(); + g_string_printf (transfer->query, "%s %d", MYTHTV_QUERY_HEADER, transfer->recordernum); + gmyth_string_list_append_string( strlist, transfer->query ); + gmyth_string_list_append_char_array( strlist, "SEEK" ); + gmyth_string_list_append_uint64( strlist, pos ); + // gmyth_string_list_append_int( strlist, whence ); + + if (pos > 0 ) + gmyth_string_list_append_uint64( strlist, pos ); + else + gmyth_string_list_append_uint64( strlist, transfer->readposition ); + + gmyth_socket_sendreceive_stringlist( transfer->control_sock, strlist ); + + guint64 retval = gmyth_string_list_get_uint64(strlist, 0); + transfer->readposition = retval; + g_print( "[%s] got reading position pointer from the streaming = %llu\n", + __FUNCTION__, retval ); + + //myth_file_transfer_reset( transfer ); + + return retval; +} + +static gboolean +myth_control_sock_listener( GIOChannel *source, GIOCondition condition, gpointer data ) +{ + + GIOStatus ret; + GError *err = NULL; + gchar *msg = g_strdup(""); + + gsize len; + if (condition & G_IO_HUP) + g_error ("Read end of pipe died!\n"); + ret = g_io_channel_read_line ( source, &msg, &len, NULL, &err); + if ( ret == G_IO_STATUS_ERROR ) + g_error ("[%s] Error reading: %s\n", __FUNCTION__, err != NULL ? err->message : "" ); + g_print ("\n\n\n\n\n\n[%s]\t\tEVENT: Read %u bytes: %s\n\n\n\n\n", __FUNCTION__, len, msg != NULL ? msg : "" ); + if ( msg != NULL ) + g_free (msg); + + return TRUE; + +} + +static void* +myth_init_io_watchers( void *data ) +{ + MythFileTransfer *transfer = (MythFileTransfer*)data; + GMainContext *context = g_main_context_new(); + GMainLoop *loop = g_main_loop_new( NULL, FALSE ); + + GSource *source = NULL; + + if ( transfer->event_sock->sd_io_ch != NULL ) + source = g_io_create_watch( transfer->event_sock->sd_io_ch, G_IO_IN | G_IO_HUP ); + + g_source_set_callback ( source, (GSourceFunc)myth_control_sock_listener, NULL, NULL ); + + g_source_attach( source, context ); + + if (source==NULL) + g_printerr( "[%s] Error adding watch listener function to the IO control channel!\n", __FUNCTION__ ); + + g_main_loop_run( loop ); + + g_source_unref( source ); + + g_main_loop_unref( loop ); + + g_main_context_unref( context ); + + return NULL; +} + + gint +myth_file_transfer_read(MythFileTransfer *transfer, void *data, gint size, gboolean read_unlimited) +{ + gint recv = 0; + gsize bytes_read = 0; + + gint sent = 0; + //guint zerocnt = 0; + gboolean response = FALSE; + + GIOChannel *io_channel; + GIOChannel *io_channel_control; + + GIOCondition io_cond; + GIOCondition io_cond_control; + GIOStatus io_status = G_IO_STATUS_NORMAL, io_status_control = G_IO_STATUS_NORMAL; + + gint buf_len = MYTHTV_BUFFER_SIZE; + + GMythStringList *strlist = NULL; + GError *error = NULL; + + gchar *trash = g_strdup(""); + + g_return_val_if_fail ( data != NULL, -2 ); + + /* gets the size of the entire file, if the size requested is lesser than 0 */ + if ( size <= 0 ) + size = transfer->filesize; + + io_channel = transfer->sock->sd_io_ch; + io_channel_control = transfer->control_sock->sd_io_ch; + + //g_io_channel_set_flags( io_channel, G_IO_FLAG_APPEND | + // G_IO_STATUS_AGAIN | G_IO_FLAG_IS_READABLE | G_IO_FLAG_IS_WRITEABLE | + // G_IO_FLAG_IS_SEEKABLE, NULL ); + + io_status = g_io_channel_set_encoding( io_channel, NULL, &error ); + if ( io_status == G_IO_STATUS_NORMAL ) + g_print( "[%s] Setting encoding to binary data socket).\n", __FUNCTION__ ); + + io_cond = g_io_channel_get_buffer_condition( io_channel ); + + io_cond_control = g_io_channel_get_buffer_condition( io_channel ); + + if ( transfer->sock == NULL || ( io_status == G_IO_STATUS_ERROR ) ) + { + g_printerr( "myth_file_transfer_read(): Called with no raw socket.\n" ); + recv = -1; + goto cleanup; + } + + if ( transfer->control_sock == NULL || ( io_status_control == G_IO_STATUS_ERROR ) ) + { + g_printerr( "myth_file_transfer_read(): Called with no control socket.\n" ); + recv = -1; + goto cleanup; + } + + /* + if (!controlSock->isOpen() || controlSock->error()) + return -1; + */ + + if ( ( io_cond & G_IO_IN ) != 0 ) { + do + { + + io_status = g_io_channel_read_line( io_channel, &trash, &bytes_read, NULL, &error); + + g_print( "[%s] cleaning buffer on IO binary channel... (%s)\n", __FUNCTION__, trash ); + io_cond = g_io_channel_get_buffer_condition( io_channel ); + + } while ( ( io_cond & G_IO_IN ) != 0 && ( io_status != G_IO_STATUS_ERROR ) ); + + if ( trash!= NULL ) + g_free( trash ); + } + + if ( ( io_cond_control & G_IO_IN ) != 0 ) { + GMythStringList *strlist_tmp = gmyth_string_list_new(); + gmyth_socket_read_stringlist( transfer->control_sock, strlist_tmp ); + g_object_unref( strlist_tmp ); + } + + wait_to_transfer = 0; + + while ( transfer->live_tv && ( myth_file_transfer_get_file_position( transfer ) < 4096 ) && + wait_to_transfer++ < MYTHTV_TRANSFER_MAX_WAITS ) + g_usleep( 1000*50 ); /* waits just for 2/10 second */ + + //g_thread_create( myth_init_io_watchers, (void*)transfer, FALSE, NULL ); + //g_printerr( "[%s] Watch listener function to the IO control channel on thread %p.\n", __FUNCTION__, g_thread_self() ); + + g_static_mutex_lock (&mutex); + strlist = gmyth_string_list_new(); + + g_string_printf ( transfer->query, "%s %d", /*transfer->live_tv ? MYTHTV_RECORDER_HEADER :*/ MYTHTV_QUERY_HEADER, + /* transfer->live_tv ? transfer->card_id :*/ transfer->recordernum ); // transfer->recordernum + g_print( "\t[%s] Transfer_query = %s\n", __FUNCTION__, transfer->query->str ); + strlist = gmyth_string_list_new(); + + gmyth_string_list_append_string( strlist, transfer->query ); + gmyth_string_list_append_char_array( strlist, /*transfer->live_tv ? "REQUEST_BLOCK_RINGBUF" :*/ "REQUEST_BLOCK" ); + gmyth_string_list_append_int( strlist, size ); + + gmyth_socket_write_stringlist( transfer->control_sock, strlist ); + sent = size; + + //data = (void*)g_new0( gchar, size ); + + g_io_channel_flush( io_channel_control, NULL ); +// g_io_channel_flush( io_channel, NULL ); + + io_cond = g_io_channel_get_buffer_condition( io_channel ); + + while ( ( recv < sent ) )//&& ( io_cond & G_IO_IN ) != 0 ) + { + do + { + //while ( ( io_cond & G_IO_IN ) == 0 ) { + //usleep(200); + // + //io_cond = g_io_channel_get_buffer_condition( io_channel ); + // + + buf_len = ( sent - recv ) > MYTHTV_BUFFER_SIZE ? MYTHTV_BUFFER_SIZE : ( sent - recv ); + + io_status = g_io_channel_read_chars( io_channel, data + recv, + buf_len, &bytes_read, &error ); + /* + GString *sss = g_string_new(""); + sss = g_string_append_len( sss, (gchar*)data+recv, bytes_read ); + + g_print( "[%s] Reading buffer (length = %d)\n", __FUNCTION__, bytes_read); + */ + if ( bytes_read > 0 ) + { + if ( bytes_read <= buf_len ) + recv += bytes_read; + } + + if ( io_status == G_IO_STATUS_EOF ) { + g_printerr( "[%s] got EOS!", __FUNCTION__ ); + break; + } else if ( io_status == G_IO_STATUS_ERROR ) { + g_printerr( "[%s] myth_file_transfer_read(): socket error.\n", __FUNCTION__ ); + break; + } + + /* increase buffer size, to allow get more data (do not obey to the buffer size) */ + if ( read_unlimited == TRUE ) { + //if ( recv > buf_len ) + // sent += (bytes_read - buf_len) + 1; + } + if ( bytes_read == buf_len ) + break; + + /* verify if the input (read) buffer is ready to receive data */ + io_cond = g_io_channel_get_buffer_condition( io_channel ); + + g_print( "[%s]\t io_cond %s prepared for reading! (G_IO_IN) !!!\n\n", __FUNCTION__, + ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" ); + + } while ( recv < sent && ( ( io_cond & G_IO_IN ) != 0 ) && ( io_status == G_IO_STATUS_NORMAL ) ); + + io_cond_control = g_io_channel_get_buffer_condition( io_channel_control ); + if ( ( io_status == G_IO_STATUS_EOF ) || ( ( io_cond_control & G_IO_IN ) != 0 ) ) + { + gmyth_socket_read_stringlist( transfer->control_sock, strlist ); + sent = gmyth_string_list_get_int( strlist, 0 ); // -1 on backend error + g_print( "[%s]\t sent = %d, io_cond %s prepared for reading! (G_IO_IN) !!!\n\n", __FUNCTION__, + sent, ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" ); + response = TRUE; + } + } + + if ( ( ( error == NULL ) && ( response == FALSE ) ) || + ( io_status == G_IO_STATUS_EOF ) || ( ( io_cond & G_IO_IN ) == 0 ) ) + { + if ( gmyth_socket_read_stringlist( transfer->control_sock, strlist ) > 0 ) + { + if ( strlist != NULL && gmyth_string_list_length(strlist) > 0 ) { + sent = gmyth_string_list_get_int( strlist, 0 ); // -1 on backend error + g_print( "[%s]\t sent = %d, io_cond %s prepared for reading! (G_IO_IN) !!!\n\n", __FUNCTION__, + sent, ( ( io_cond & G_IO_IN ) != 0 ) ? "IS" : "IS NOT" ); + } + } + else + { + g_printerr ( "myth_file_transfer_read(): No response from control socket."); + sent = -1; + } + + if ( error!=NULL ) { + g_printerr( "[%s] Error occurred: (%d, %s)\n", __FUNCTION__, error->code, error->message ); + g_error_free( error ); + } + } + +cleanup: + + if ( trash != NULL ) + g_free( trash ); + + if ( strlist != NULL ) + g_object_unref( strlist ); + + g_static_mutex_unlock (&mutex); + g_print( "myth_file_transfer_read(): reqd=%d, rcvd=%d, rept=%d, "\ + "(rcvd and rept MUST be the same!)\n", size, + recv, sent ); + + //if ( sent != recv ) { + // recv = -1; + //} + + if ( error != NULL ) + g_printerr( "ERROR: %s [msg = %s, code = %d]\n", __FUNCTION__, error->message, + error->code ); + + return recv; +} + + void +myth_file_transfer_settimeout( MythFileTransfer *transfer, gboolean fast ) +{ + + GMythStringList *strlist = NULL; + + if ( transfer->timeoutisfast == fast ) + return; + + if ( transfer->sock == NULL ) + { + g_printerr( "myth_file_transfer_settimeout(): Called with no socket" ); + return; + } + + if ( transfer->control_sock == NULL ) + return; + + strlist = gmyth_string_list_new(); + gmyth_string_list_append_string( strlist, transfer->query ); + gmyth_string_list_append_char_array( strlist, "SET_TIMEOUT" ); + gmyth_string_list_append_int( strlist, fast ); + + gmyth_socket_write_stringlist( transfer->control_sock, strlist ); + gmyth_socket_read_stringlist( transfer->control_sock, strlist ); + + transfer->timeoutisfast = fast; + +} + +#ifdef DO_TESTING + + int +main( int argc, char *argv[] ) +{ + g_type_init(); + + MythFileTransfer *file_transfer = myth_file_transfer_new( 1, + g_string_new("myth://192.168.1.109:6543/jshks.nuv"), -1, MYTHTV_VERSION ); + myth_file_transfer_setup( &file_transfer ); + gchar *data = g_strdup(""); + + gint num = myth_file_transfer_read( file_transfer, data, -1 ); + + return 0; + +} + +#endif diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/myth_file_transfer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/myth_file_transfer.h Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,93 @@ +/* vim: set sw=2: -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2; c-indent-level: 2-*- */ + +#ifndef __MYTH_FILE_TRANSFER_H__ +#define __MYTH_FILE_TRANSFER_H__ + +#include + +#include +#include "myth_uri.h" +#include "myth_livetv.h" + +#include +#include +#include +#include +#include +#include + +#define G_BEGIN_DECLS + +#define MYTH_FILE_TRANSFER_TYPE (myth_file_transfer_get_type ()) +#define MYTH_FILE_TRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MYTH_FILE_TRANSFER_TYPE, MythFileTransfer)) +#define MYTH_FILE_TRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYTH_FILE_TRANSFER_TYPE, MythFileTransferClass)) +#define IS_MYTH_FILE_TRANSFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MYTH_FILE_TRANSFER_TYPE)) +#define IS_MYTH_FILE_TRANSFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYTH_FILE_TRANSFER_TYPE)) +#define MYTH_FILE_TRANSFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MYTH_FILE_TRANSFER_TYPE, MythFileTransferClass)) + + +typedef struct _MythFileTransfer MythFileTransfer; +typedef struct _MythFileTransferClass MythFileTransferClass; + +struct _MythFileTransferClass +{ + GObjectClass parent_class; + + /* callbacks */ + /* no one for now */ +}; + +struct _MythFileTransfer +{ + GObject parent; + + /* Myth URI structure */ + const MythURI *uri; + + /* MythTV version number */ + gint mythtv_version; + + /* socket descriptors */ + GMythSocket *control_sock; + GMythSocket *event_sock; + GMythSocket *sock; + + guint64 readposition; + guint64 filesize; + gboolean timeoutisfast; + gboolean userreadahead; + gboolean live_tv; + gint retries; + + GString *query; + + gint rec_id; + gint recordernum; + gint card_id; + GString *hostname; + gint port; +}; + +GType myth_file_transfer_get_type (void); + +MythFileTransfer* myth_file_transfer_new (gint num, GString *hostname, gshort port, gint mythtv_version ); + +gint myth_file_transfer_read(MythFileTransfer *transfer, void *data, gint size, gboolean read_unlimited); + +guint64 myth_file_transfer_seek(MythFileTransfer *transfer, guint64 pos, gint whence); + +gboolean myth_file_transfer_playback_setup( MythFileTransfer **transfer, gboolean live_tv ); + +gboolean myth_file_transfer_setup( MythFileTransfer **transfer, gboolean live_tv ); + +gboolean myth_file_transfer_livetv_setup( MythFileTransfer **transfer, GMythSocket *live_sock ); + +void myth_file_transfer_spawntv ( MythFileTransfer *file_transfer, GString *tvchain_id ); + +gboolean myth_file_transfer_is_recording( MythFileTransfer *file_transfer ); + +guint64 myth_file_transfer_get_file_position( MythFileTransfer *file_transfer ); + +#define G_END_DECLS + +#endif /* __MYTH_FILE_TRANSFER_H__ */ diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/myth_livetv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/myth_livetv.c Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,220 @@ + +#include +#include +#include + +#include "myth_livetv.h" +#include "myth_file_transfer.h" + +static void myth_livetv_class_init (MythLiveTVClass *klass); +static void myth_livetv_init (MythLiveTV *object); + +static void myth_livetv_dispose (GObject *object); +static void myth_livetv_finalize (GObject *object); + +G_DEFINE_TYPE(MythLiveTV, myth_livetv, G_TYPE_OBJECT) + +static void +myth_livetv_class_init (MythLiveTVClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->dispose = myth_livetv_dispose; + gobject_class->finalize = myth_livetv_finalize; +} + +static void +myth_livetv_init (MythLiveTV *livetv) +{ + livetv->backend_hostname = NULL; + livetv->backend_port = 0; + livetv->local_hostname = NULL; + + livetv->remote_encoder = NULL; + livetv->tvchain = NULL; + livetv->proginfo = NULL; +} + +static void +myth_livetv_dispose (GObject *object) +{ + + G_OBJECT_CLASS (myth_livetv_parent_class)->dispose (object); +} + +static void +myth_livetv_finalize (GObject *object) +{ + g_signal_handlers_destroy (object); + + MythLiveTV *livetv = MYTH_LIVETV (object); + + g_debug ("[%s] Finalizing livetv", __FUNCTION__); + + if ( livetv->remote_encoder != NULL ) { + g_object_unref (livetv->remote_encoder); + livetv->remote_encoder = NULL; + } + + if ( livetv->tvchain != NULL ) { + g_object_unref (livetv->tvchain); + livetv->tvchain = NULL; + } + + if ( livetv->proginfo != NULL ) { + g_object_unref (livetv->proginfo); + livetv->proginfo = NULL; + } + + G_OBJECT_CLASS ( myth_livetv_parent_class )->finalize ( object ); +} + +MythLiveTV* +myth_livetv_new () +{ + MythLiveTV *livetv = MYTH_LIVETV ( g_object_new( MYTH_LIVETV_TYPE, NULL ) ); + + return livetv; +} + +gboolean +myth_livetv_setup ( MythLiveTV *livetv ) +{ + + // FIXME: Get from the settings + GMythSettings *msettings = gmyth_context_get_settings (); + gboolean res = TRUE; + + livetv->is_livetv = TRUE; + + res = gmyth_context_check_connection(); + if (!res) { + g_warning ("[%s] LiveTV can not connect to backend", __FUNCTION__); + res = FALSE; + goto error; + } + + livetv->backend_hostname = gmyth_settings_get_backend_hostname(msettings); + livetv->backend_port = gmyth_settings_get_backend_port (msettings); + + livetv->local_hostname = g_string_new(""); + gmyth_context_get_local_hostname (livetv->local_hostname); + + if ( livetv->local_hostname == NULL ) { + res = FALSE; + goto error; + } + + // Gets the remote encoder num + livetv->remote_encoder = remote_request_next_free_recorder (-1); + + if ( livetv->remote_encoder == NULL ) { + g_warning ("[%s] None remote encoder available", __FUNCTION__); + res = FALSE; + goto error; + } + + // Creates livetv chain handler + livetv->tvchain = GMYTH_TVCHAIN ( g_object_new(GMYTH_TVCHAIN_TYPE, NULL) ); + gmyth_tvchain_initialize ( livetv->tvchain, livetv->local_hostname ); + + if ( livetv->tvchain == NULL || livetv->tvchain->tvchain_id == NULL ) { + res = FALSE; + goto error; + } + + // Init remote encoder. Opens its control socket. + res = gmyth_remote_encoder_setup(livetv->remote_encoder); + if ( !res ) { + g_warning ("[%s] Fail while setting remote encoder\n", __FUNCTION__); + res = FALSE; + goto error; + } + // Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly) + res = gmyth_remote_encoder_spawntv ( livetv->remote_encoder, + gmyth_tvchain_get_id(livetv->tvchain) ); + if (!res) { + g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__); + res = FALSE; + goto error; + } + + // Reload all TV chain from Mysql database. + gmyth_tvchain_reload_all (livetv->tvchain); + + if ( livetv->tvchain == NULL ) { + res = FALSE; + goto error; + } + + // Get program info from database using chanid and starttime + livetv->proginfo = gmyth_tvchain_get_program_at (livetv->tvchain, -1); + if ( livetv->proginfo == NULL ) { + g_warning ("[%s] LiveTV not successfully started.\n", __FUNCTION__ ); + res = FALSE; + goto error; + } else { + g_debug ("[%s] MythLiveTV: All requests to backend to start TV were OK.\n", __FUNCTION__ ); + } + + return res; + +error: + if ( livetv->backend_hostname != NULL ) { + g_string_free( livetv->backend_hostname, TRUE ); + res = FALSE; + } + + if ( livetv->local_hostname != NULL ) { + g_string_free( livetv->local_hostname, TRUE ); + res = FALSE; + } + + if ( livetv->remote_encoder != NULL ) { + g_object_unref (livetv->remote_encoder); + livetv->remote_encoder = NULL; + } + + if ( livetv->tvchain != NULL ) { + g_object_unref (livetv->tvchain); + livetv->tvchain = NULL; + } + + if ( livetv->proginfo != NULL ) { + g_object_unref (livetv->proginfo); + livetv->proginfo = NULL; + } + + return res; + +} + +// FIXME: How to proceed differently between livetv and recorded content +void +myth_livetv_stop_playing (MythLiveTV *livetv) +{ + g_debug ("[%s] Stopping the LiveTV...\n", __FUNCTION__); + + if (livetv->is_livetv) { + if (!gmyth_remote_encoder_stop_livetv (livetv->remote_encoder)) { + g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__); + } + } +} + +gboolean +myth_livetv_is_playing (MythLiveTV *livetv) +{ + return TRUE; +} + +void +myth_livetv_start_playing (MythLiveTV *livetv) +{ + + // TODO + +} + diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/myth_livetv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/myth_livetv.h Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,59 @@ +#ifndef MYTH_LIVETV_H_ +#define MYTH_LIVETV_H_ + +#include + +#include +#include +#include + +#include "myth_file_transfer.h" + +#define G_BEGIN_DECLS + +#define MYTH_LIVETV_TYPE (myth_livetv_get_type ()) +#define MYTH_LIVETV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MYTH_LIVETV_TYPE, MythLiveTV)) +#define MYTH_LIVETV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYTH_LIVETV_TYPE, MythLiveTVClass)) +#define IS_MYTH_LIVETV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MYTH_LIVETV_TYPE)) +#define IS_MYTH_LIVETV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYTH_LIVETV_TYPE)) +#define MYTH_LIVETV_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MYTH_LIVETV_TYPE, MythLiveTVClass)) + +typedef struct _MythLiveTV MythLiveTV; +typedef struct _MythLiveTVClass MythLiveTVClass; + +struct _MythLiveTVClass +{ + GObjectClass parent_class; + + /* callbacks */ +}; + +struct _MythLiveTV +{ + GObject parent; + + // Backend connection related variables + GString *backend_hostname; + gint backend_port; + GString *local_hostname; + + GMythRemoteEncoder *remote_encoder; + GMythTVChain *tvchain; + GMythProgramInfo *proginfo; + + gboolean is_livetv; + +}; + +GType myth_livetv_get_type (void); + +MythLiveTV* myth_livetv_new (); + +void myth_livetv_start_playing (MythLiveTV *livetv); +void myth_livetv_stop_playing (MythLiveTV *livetv); + +gboolean myth_livetv_setup (MythLiveTV *livetv); + +#define G_END_DECLS + +#endif /*MYTH_LIVETV_H_*/ diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/myth_uri.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/myth_uri.c Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,208 @@ +/** + * + * MythURI utils + * - Extracts and parses a URI char string, in according with the RFC 2396 + * [http://www.ietf.org/rfc/rfc2396.txt] + * + * @author Rosfran Borges (rosfran.borges@indt.org.br) + * + */ + +#include "myth_uri.h" +#include +#include +#include + +static gint +myth_strstr( const gchar *haystack, const gchar *needle ) +{ + + gchar *strPos; + + if (haystack == NULL || needle == NULL) + return -1; + strPos = strstr(haystack, needle); + if (strPos == NULL) + return -1; + + return (strPos - haystack); + +} + +static gboolean +myth_uri_isabsolute( const MythURI *uri ) +{ + gboolean ret = FALSE; + + g_return_val_if_fail( uri != NULL && uri->uri != NULL && uri->protocol != NULL, FALSE ); + + if ( myth_strstr( uri->uri->str, MYTH_URI_PROTOCOL_DELIM ) == 0 || strlen(uri->protocol->str) > 0 ) + ret = TRUE; + + return ret; +} + +static gint +myth_strrchr( const gchar *str, const gchar *chars, const gint nchars ) +{ + + gint strLen; + gint i, j; + + if ( str == NULL || chars == NULL ) + return -1; + + strLen = strlen( str ); + for ( i= (strLen-1); 0 <= i; i-- ) { + for ( j=0; jhost = g_string_new(""); + uri->fragment = g_string_new(""); + uri->password = g_string_new(""); + uri->path = g_string_new(""); + uri->protocol = g_string_new(""); + uri->query = g_string_new(""); + uri->uri = g_string_new(""); + uri->user = g_string_new(""); + return uri; +} + +const MythURI * +myth_uri_new( gchar *value ) +{ + + MythURI *uri = myth_uri_init(); + + gchar *protocol; + gint uriLen; + gint currIdx; + gint protoIdx; + gint atIdx; + gint colonIdx; + gint shashIdx; + gchar *host; + gint eblacketIdx; + GString *hostStr; + GString *portStr; + gint hostLen; + gint sharpIdx; + gint questionIdx; + gint queryLen; + + uriLen = strlen(value); + uri->uri = g_string_new( value ); + + currIdx = 0; + + /*** Protocol ****/ + protoIdx = myth_strstr( value, MYTH_URI_PROTOCOL_DELIM ); + if (0 < protoIdx) { + uri->protocol = g_string_append_len( uri->protocol, value, protoIdx ); + currIdx += protoIdx + strlen( MYTH_URI_PROTOCOL_DELIM ); + } + + /*** User (Password) ****/ + atIdx = myth_strstr( value+currIdx, MYTH_URI_USER_DELIM ); + if ( 0 < atIdx ) { + colonIdx = myth_strstr( value+currIdx, MYTH_URI_COLON_DELIM ); + + if (0 < colonIdx && colonIdx < atIdx) { + uri->user = g_string_append_len( uri->user, value+currIdx, colonIdx ); + uri->password = g_string_append_len( uri->password, value+currIdx+colonIdx+1, atIdx-(colonIdx+1) ); + } + else + uri->user = g_string_append_len( uri->user, value+currIdx, atIdx - currIdx ); + currIdx += atIdx + 1; + } + + /*** Host (Port) ****/ + shashIdx = myth_strstr( value+currIdx, MYTH_URI_SLASH_DELIM ); + if ( 0 < shashIdx ) + uri->host = g_string_append_len( uri->host, value+currIdx, shashIdx ); + else if ( myth_uri_isabsolute(uri) == TRUE ) + uri->host = g_string_append_len( uri->host, value+currIdx, strlen(value) - currIdx ); + host = g_strdup( myth_uri_gethost(uri) ); + colonIdx = myth_strrchr( host, MYTH_URI_COLON_DELIM, 1 ); + eblacketIdx = myth_strrchr( host, MYTH_URI_EBLACET_DELIM, 1 ); + if ( ( 0 < colonIdx ) && ( eblacketIdx < colonIdx ) ) { + hostStr = g_string_new( host ); + + hostLen = hostStr->len; + /**** host ****/ + uri->host = g_string_erase( uri->host, 0, hostLen ); + uri->host = g_string_insert_len( uri->host, 0, hostStr->str, colonIdx ); + //host = myth_uri_gethost( uri ); + if (0 < hostLen) { + if (host[0] == '[' && host[hostLen-1] == ']') + uri->host = g_string_append_len( uri->host, hostStr->str+1, colonIdx-2 ); + } + /**** port ****/ + portStr = g_string_new(""); + portStr = g_string_append_len( portStr, hostStr->str+colonIdx+1, hostLen-colonIdx-1 ); + uri->port = atoi( portStr->str ); + g_string_free( portStr, TRUE ); + g_string_free( hostStr, FALSE ); + } + else { + uri->port = MYTH_URI_KNKOWN_PORT; + protocol = myth_uri_getprotocol(uri); + if ( strcmp(protocol, MYTH_URI_PROTOCOL_HTTP) == 0 ) + uri->port = MYTH_URI_DEFAULT_HTTP_PORT; + if ( strcmp(protocol, MYTH_URI_PROTOCOL_FTP) == 0 ) + uri->port = MYTH_URI_DEFAULT_FTP_PORT; + } + + if (shashIdx > 0) currIdx += shashIdx; + + /* + Handle relative URL + */ + if (myth_uri_isabsolute(uri) == FALSE) + { + + if (shashIdx != 0) + { + /* Add slash delimiter at the beginning of the URL, + if it doesn't exist + */ + uri->path = g_string_new( MYTH_URI_SLASH_DELIM ); + } + uri->path = g_string_append( uri->path, value ); + + } else { + /* First set path simply to the rest of URI */ + g_string_append_len( uri->path, value+currIdx, uriLen-currIdx ); + } + + /**** Path (Query/Fragment) ****/ + sharpIdx = myth_strstr(value+currIdx, MYTH_URI_SHARP_DELIM); + if (0 < sharpIdx) { + uri->path = g_string_append_len( uri->path, value+currIdx, sharpIdx); + uri->fragment = g_string_append_len( uri->fragment, + value+currIdx+sharpIdx+1, uriLen-(currIdx+sharpIdx+1)); + } + + questionIdx = myth_strstr( value+currIdx, MYTH_URI_QUESTION_DELIM ); + if ( 0 < questionIdx ) { + uri->path = g_string_append_len( uri->path, value+currIdx, questionIdx ); + queryLen = uriLen-(currIdx+questionIdx+1); + if ( 0 < sharpIdx ) + queryLen -= uriLen - (currIdx+sharpIdx+1); + uri->query = g_string_append_len( uri->query, value+currIdx+questionIdx+1, queryLen ); + } + + return uri; + +} diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/myth_uri.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/myth_uri.h Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,63 @@ +/** + * + * MythURI utils + * - Extracts and parses a URI char string, in according with the RFC 2396 + * [http://www.ietf.org/rfc/rfc2396.txt] + * + * @author Rosfran Borges (rosfran.borges@indt.org.br) + * + */ + +#ifndef _MYTH_URI_H_ +#define _MYTH_URI_H_ + +#include + +/**************************************** +* Define +****************************************/ + +#define MYTH_URI_KNKOWN_PORT (-1) +#define MYTH_URI_DEFAULT_HTTP_PORT 80 +#define MYTH_URI_DEFAULT_FTP_PORT 21 +#define MYTH_URI_DEFAULT_PATH "/" +#define MYTH_URI_MAXLEN 256 + +#define MYTH_URI_PROTOCOL_DELIM "://" +#define MYTH_URI_USER_DELIM "@" +#define MYTH_URI_COLON_DELIM ":" +#define MYTH_URI_SLASH_DELIM "/" +#define MYTH_URI_SBLACET_DELIM "[" +#define MYTH_URI_EBLACET_DELIM "]" +#define MYTH_URI_SHARP_DELIM "#" +#define MYTH_URI_QUESTION_DELIM "?" +#define MYTH_URI_ESCAPING_CHAR "%" + +#define MYTH_URI_PROTOCOL_MYTH "myth" +#define MYTH_URI_PROTOCOL_HTTP "http" +#define MYTH_URI_PROTOCOL_FTP "ftp" + +/**************************************** +* Data Type +****************************************/ + +typedef struct _MythURI { + GString *uri; + GString *host; + gint port; + GString *protocol; + GString *path; + GString *fragment; + GString *user; + GString *password; + GString *query; +} MythURI; + +const MythURI *myth_uri_new( gchar *value ); + +#define myth_uri_gethost(urip) (urip->host->str) +#define myth_uri_getport(urip) (urip->port) +#define myth_uri_getprotocol(urip) (urip->protocol->str) +#define myth_uri_getpath(urip) (urip->path->str) + +#endif diff -r 343d4e3c03ab -r f3cdc7844178 gst-plugins-mythtv/src/mythtvsrc-test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-plugins-mythtv/src/mythtvsrc-test.c Tue Sep 26 15:58:37 2006 +0100 @@ -0,0 +1,85 @@ +#include + +static gboolean +bus_call (GstBus *bus, + GstMessage *msg, + gpointer data) +{ + GMainLoop *loop = data; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_EOS: + g_print ("End-of-stream\n"); + g_main_loop_quit (loop); + break; + case GST_MESSAGE_ERROR: { + gchar *debug; + GError *err; + + gst_message_parse_error (msg, &err, &debug); + g_free (debug); + + g_print ("Error: %s\n", err->message); + g_error_free (err); + + g_main_loop_quit (loop); + break; + } + default: + break; + } + + return TRUE; +} + +gint +main (gint argc, + gchar *argv[]) +{ + GstElement *pipeline, *filesrc, *decoder, *filter, *sink; + GMainLoop *loop; + + /* initialization */ + gst_init (&argc, &argv); + loop = g_main_loop_new (NULL, FALSE); + if (argc != 2) { + g_print ("Usage: %s \n", argv[0]); + return 01; + } + + /* create elements */ + pipeline = gst_pipeline_new ("mythtvsrc_pipeline"); + gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)), + bus_call, loop); + + filesrc = gst_element_factory_make ("mythtvsrc", "mythtvsrc"); + decoder = gst_element_factory_make ("mad", "my_decoder"); + filter = gst_element_factory_make ("my_filter", "my_filter"); + sink = gst_element_factory_make ("osssink", "audiosink"); + if (!sink || !decoder) { + g_print ("Decoder or output could not be found - check your install\n"); + return -1; + } else if (!filter) { + g_print ("Your self-written filter could not be found. Make sure it " + "is installed correctly in $(libdir)/gstreamer-0.9/ and that " + "you've ran gst-register-0.9 to register it. Check availability " + "of the plugin afterwards using \"gst-inspect-0.9 my_filter\""); + return -1; + } + + g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); + + /* link everything together */ + gst_element_link_many (filesrc, decoder, filter, sink, NULL); + gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, filter, sink, NULL); + + /* run */ + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + + /* clean up */ + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + + return 0; +}