/* This file is part of the KDE project. Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2.1 or 3 of the License. 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include "phononsrc.h" #include "streamreader.h" QT_BEGIN_NAMESPACE namespace Phonon { namespace Gstreamer { static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); GST_DEBUG_CATEGORY_STATIC (phonon_src_debug); // PhononSrc args enum { ARG_0, ARG_PHONONSRC }; static void phonon_src_finalize (GObject * object); static void phonon_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void phonon_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static gboolean phonon_src_start (GstBaseSrc * basesrc); static gboolean phonon_src_stop (GstBaseSrc * basesrc); static gboolean phonon_src_is_seekable (GstBaseSrc * src); static gboolean phonon_src_get_size (GstBaseSrc * src, guint64 * size); static GstFlowReturn phonon_src_create (GstBaseSrc * src, guint64 offset, guint length, GstBuffer ** buffer); static void _do_init (GType filesrc_type) { Q_UNUSED(filesrc_type); GST_DEBUG_CATEGORY_INIT (phonon_src_debug, "phononsrc", 0, "QIODevice element"); } GST_BOILERPLATE_FULL (PhononSrc, phonon_src, GstBaseSrc, GST_TYPE_BASE_SRC, _do_init) // Register element details static void phonon_src_base_init (gpointer g_class) { GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); static gchar longname[] = "Phonon Stream Source", klass[] = "Source/File", description[] = "Read from a Phonon StreamInterface", author[] = "Nokia Corporation and/or its subsidiary(-ies) "; GstElementDetails details = GST_ELEMENT_DETAILS (longname, klass, description, author); gst_element_class_set_details (gstelement_class, &details); gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate)); } static void phonon_src_class_init (PhononSrcClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; GstBaseSrcClass *gstbasesrc_class; gobject_class = G_OBJECT_CLASS (klass); gstelement_class = GST_ELEMENT_CLASS (klass); gstbasesrc_class = GST_BASE_SRC_CLASS (klass); gobject_class->set_property = phonon_src_set_property; gobject_class->get_property = phonon_src_get_property; g_object_class_install_property (gobject_class, ARG_PHONONSRC, g_param_spec_pointer ("iodevice", "A Phonon StreamReader", "A Phonon::GStreamer::StreamReader to read from", GParamFlags(G_PARAM_READWRITE))); gobject_class->finalize = GST_DEBUG_FUNCPTR (phonon_src_finalize); gstbasesrc_class->start = GST_DEBUG_FUNCPTR (phonon_src_start); gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (phonon_src_stop); gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (phonon_src_is_seekable); gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (phonon_src_get_size); gstbasesrc_class->create = GST_DEBUG_FUNCPTR (phonon_src_create); } static void phonon_src_init (PhononSrc * src, PhononSrcClass * g_class) { Q_UNUSED(g_class); #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM src->device = 0; #else Q_UNUSED(src); #endif } static void phonon_src_finalize (GObject * object) { #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM PhononSrc *src; src = GST_PHONON_SRC (object); delete src->device; src->device = 0; #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM G_OBJECT_CLASS (parent_class)->finalize (object); } #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM static gboolean phonon_src_set_device(PhononSrc * src, StreamReader* device) { GstState state; // The element must be stopped in order to do this GST_OBJECT_LOCK (src); state = GST_STATE (src); if (state != GST_STATE_READY && state != GST_STATE_NULL) goto wrong_state; GST_OBJECT_UNLOCK (src); src->device = device; g_object_notify (G_OBJECT (src), "iodevice"); return TRUE; // Error wrong_state: { //GST_DEBUG_OBJECT (src, "setting location in wrong state"); GST_OBJECT_UNLOCK (src); return FALSE; } } #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM static void phonon_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { PhononSrc *src; g_return_if_fail (GST_IS_PHONON_SRC (object)); src = GST_PHONON_SRC (object); switch (prop_id) { #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM case ARG_PHONONSRC: { StreamReader *dev = (StreamReader*)(g_value_get_pointer(value)); if (dev) phonon_src_set_device(src, dev); break; } #else Q_UNUSED(value); #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void phonon_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { PhononSrc *src; g_return_if_fail (GST_IS_PHONON_SRC (object)); src = GST_PHONON_SRC (object); switch (prop_id) { #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM case ARG_PHONONSRC: g_value_set_pointer(value, src->device); break; #else //QT_NO_PHONON_ABSTRACTMEDIASTREAM Q_UNUSED(value); #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GstFlowReturn phonon_src_create_read (PhononSrc * src, guint64 offset, guint length, GstBuffer ** buffer) { #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM Q_ASSERT(src->device); if (!src->device) return GST_FLOW_ERROR; GstBuffer *buf = gst_buffer_new_and_alloc (length); GST_BUFFER_SIZE (buf) = length; GST_BUFFER_OFFSET (buf) = offset; GST_BUFFER_OFFSET_END (buf) = offset + length; bool success = src->device->read(offset, length, (char*)GST_BUFFER_DATA (buf)); //GST_LOG_OBJECT (src, "Reading %d bytes", length); if (success) { *buffer = buf; return GST_FLOW_OK; } gst_mini_object_unref(GST_MINI_OBJECT(buf)); return GST_FLOW_ERROR; #else //QT_NO_PHONON_ABSTRACTMEDIASTREAM Q_UNUSED(src); Q_UNUSED(offset); Q_UNUSED(length); Q_UNUSED(buffer); return GST_FLOW_ERROR; #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM } static GstFlowReturn phonon_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer) { PhononSrc *src; GstFlowReturn ret; src = GST_PHONON_SRC (basesrc); ret = phonon_src_create_read (src, offset, length, buffer); return ret; } static gboolean phonon_src_is_seekable (GstBaseSrc * basesrc) { PhononSrc *src = GST_PHONON_SRC (basesrc); #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM if (src->device) return src->device->streamSeekable(); #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM return false; } static gboolean phonon_src_get_size (GstBaseSrc * basesrc, guint64 * size) { #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM PhononSrc *src; src = GST_PHONON_SRC (basesrc); if (src->device && src->device->streamSeekable()) { *size = src->device->streamSize(); return TRUE; } #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM *size = 0; return FALSE; } // Necessary to go to READY state static gboolean phonon_src_start (GstBaseSrc * basesrc) { Q_UNUSED(basesrc); // Opening the device is handled by the frontend // We can only assume it is already open return TRUE; } static gboolean phonon_src_stop (GstBaseSrc * basesrc) { Q_UNUSED(basesrc); // Closing the device is handled by the frontend return TRUE; } } } //namespace Phonon::Gstreamer QT_END_NAMESPACE