| 1 | /*  This file is part of the KDE project.
 | 
|---|
| 2 | 
 | 
|---|
| 3 | Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 | 
|---|
| 4 | 
 | 
|---|
| 5 | This library is free software: you can redistribute it and/or modify
 | 
|---|
| 6 | it under the terms of the GNU Lesser General Public License as published by
 | 
|---|
| 7 | the Free Software Foundation, either version 2.1 or 3 of the License.
 | 
|---|
| 8 | 
 | 
|---|
| 9 | This library is distributed in the hope that it will be useful,
 | 
|---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 12 | GNU Lesser General Public License for more details.
 | 
|---|
| 13 | 
 | 
|---|
| 14 | You should have received a copy of the GNU Lesser General Public License
 | 
|---|
| 15 | along with this library.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 16 | */
 | 
|---|
| 17 | 
 | 
|---|
| 18 | #include <gst/gst.h>
 | 
|---|
| 19 | #include <gst/base/gstbasesrc.h>
 | 
|---|
| 20 | #include "phononsrc.h"
 | 
|---|
| 21 | #include "streamreader.h"
 | 
|---|
| 22 | 
 | 
|---|
| 23 | QT_BEGIN_NAMESPACE
 | 
|---|
| 24 | 
 | 
|---|
| 25 | namespace Phonon
 | 
|---|
| 26 | {
 | 
|---|
| 27 | namespace Gstreamer
 | 
|---|
| 28 | {
 | 
|---|
| 29 | 
 | 
|---|
| 30 | static GstStaticPadTemplate srctemplate =
 | 
|---|
| 31 |        GST_STATIC_PAD_TEMPLATE ("src",
 | 
|---|
| 32 |                                 GST_PAD_SRC,
 | 
|---|
| 33 |                                 GST_PAD_ALWAYS,
 | 
|---|
| 34 |                                 GST_STATIC_CAPS_ANY);
 | 
|---|
| 35 | 
 | 
|---|
| 36 | GST_DEBUG_CATEGORY_STATIC (phonon_src_debug);
 | 
|---|
| 37 | 
 | 
|---|
| 38 | // PhononSrc args
 | 
|---|
| 39 | enum
 | 
|---|
| 40 | {
 | 
|---|
| 41 |     ARG_0,
 | 
|---|
| 42 |     ARG_PHONONSRC
 | 
|---|
| 43 | };
 | 
|---|
| 44 | 
 | 
|---|
| 45 | static void phonon_src_finalize (GObject * object);
 | 
|---|
| 46 | 
 | 
|---|
| 47 | static void phonon_src_set_property (GObject * object, guint prop_id,
 | 
|---|
| 48 |                                         const GValue * value, GParamSpec * pspec);
 | 
|---|
| 49 | static void phonon_src_get_property (GObject * object, guint prop_id,
 | 
|---|
| 50 |                                         GValue * value, GParamSpec * pspec);
 | 
|---|
| 51 | 
 | 
|---|
| 52 | static gboolean phonon_src_start (GstBaseSrc * basesrc);
 | 
|---|
| 53 | static gboolean phonon_src_stop (GstBaseSrc * basesrc);
 | 
|---|
| 54 | 
 | 
|---|
| 55 | static gboolean phonon_src_is_seekable (GstBaseSrc * src);
 | 
|---|
| 56 | static gboolean phonon_src_get_size (GstBaseSrc * src, guint64 * size);
 | 
|---|
| 57 | static GstFlowReturn phonon_src_create (GstBaseSrc * src, guint64 offset,
 | 
|---|
| 58 |                                            guint length, GstBuffer ** buffer);
 | 
|---|
| 59 | 
 | 
|---|
| 60 | static void _do_init (GType filesrc_type)
 | 
|---|
| 61 | {
 | 
|---|
| 62 |     Q_UNUSED(filesrc_type);
 | 
|---|
| 63 |     GST_DEBUG_CATEGORY_INIT (phonon_src_debug, "phononsrc", 0, "QIODevice element");
 | 
|---|
| 64 | }
 | 
|---|
| 65 | 
 | 
|---|
| 66 | GST_BOILERPLATE_FULL (PhononSrc, phonon_src, GstBaseSrc, GST_TYPE_BASE_SRC, _do_init)
 | 
|---|
| 67 | 
 | 
|---|
| 68 | // Register element details
 | 
|---|
| 69 | static void phonon_src_base_init (gpointer g_class) {
 | 
|---|
| 70 |     GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
 | 
|---|
| 71 |     static gchar longname[] = "Phonon Stream Source",
 | 
|---|
| 72 |                     klass[] = "Source/File",
 | 
|---|
| 73 |               description[] = "Read from a Phonon StreamInterface",
 | 
|---|
| 74 |                    author[] = "Nokia Corporation and/or its subsidiary(-ies) <qt-info@nokia.com>";
 | 
|---|
| 75 |     GstElementDetails details = GST_ELEMENT_DETAILS (longname,
 | 
|---|
| 76 |                                           klass,
 | 
|---|
| 77 |                                           description,
 | 
|---|
| 78 |                                           author);
 | 
|---|
| 79 |     gst_element_class_set_details (gstelement_class, &details);
 | 
|---|
| 80 |     gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate));
 | 
|---|
| 81 | }
 | 
|---|
| 82 | 
 | 
|---|
| 83 | static void phonon_src_class_init (PhononSrcClass * klass)
 | 
|---|
| 84 | {
 | 
|---|
| 85 |     GObjectClass *gobject_class;
 | 
|---|
| 86 |     GstElementClass *gstelement_class;
 | 
|---|
| 87 |     GstBaseSrcClass *gstbasesrc_class;
 | 
|---|
| 88 | 
 | 
|---|
| 89 |     gobject_class = G_OBJECT_CLASS (klass);
 | 
|---|
| 90 |     gstelement_class = GST_ELEMENT_CLASS (klass);
 | 
|---|
| 91 |     gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
 | 
|---|
| 92 | 
 | 
|---|
| 93 |     gobject_class->set_property = phonon_src_set_property;
 | 
|---|
| 94 |     gobject_class->get_property = phonon_src_get_property;
 | 
|---|
| 95 | 
 | 
|---|
| 96 |     g_object_class_install_property (gobject_class, ARG_PHONONSRC,
 | 
|---|
| 97 |                                      g_param_spec_pointer ("iodevice", "A Phonon StreamReader",
 | 
|---|
| 98 |                                      "A Phonon::GStreamer::StreamReader to read from", GParamFlags(G_PARAM_READWRITE)));
 | 
|---|
| 99 | 
 | 
|---|
| 100 |     gobject_class->finalize = GST_DEBUG_FUNCPTR (phonon_src_finalize);
 | 
|---|
| 101 | 
 | 
|---|
| 102 |     gstbasesrc_class->start = GST_DEBUG_FUNCPTR (phonon_src_start);
 | 
|---|
| 103 |     gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (phonon_src_stop);
 | 
|---|
| 104 |     gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (phonon_src_is_seekable);
 | 
|---|
| 105 |     gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (phonon_src_get_size);
 | 
|---|
| 106 |     gstbasesrc_class->create = GST_DEBUG_FUNCPTR (phonon_src_create);
 | 
|---|
| 107 | }
 | 
|---|
| 108 | 
 | 
|---|
| 109 | static void phonon_src_init (PhononSrc * src, PhononSrcClass * g_class)
 | 
|---|
| 110 | {
 | 
|---|
| 111 |     Q_UNUSED(g_class);
 | 
|---|
| 112 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 113 |     src->device = 0;
 | 
|---|
| 114 | #else
 | 
|---|
| 115 |     Q_UNUSED(src);
 | 
|---|
| 116 | #endif
 | 
|---|
| 117 | }
 | 
|---|
| 118 | 
 | 
|---|
| 119 | static void phonon_src_finalize (GObject * object)
 | 
|---|
| 120 | {
 | 
|---|
| 121 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 122 |     PhononSrc *src;
 | 
|---|
| 123 |     src = GST_PHONON_SRC (object);
 | 
|---|
| 124 |     delete src->device;
 | 
|---|
| 125 |     src->device = 0;
 | 
|---|
| 126 | #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 127 |     G_OBJECT_CLASS (parent_class)->finalize (object);
 | 
|---|
| 128 | }
 | 
|---|
| 129 | 
 | 
|---|
| 130 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 131 | static gboolean phonon_src_set_device(PhononSrc * src, StreamReader* device)
 | 
|---|
| 132 | {
 | 
|---|
| 133 |     GstState state;
 | 
|---|
| 134 |     // The element must be stopped in order to do this
 | 
|---|
| 135 |     GST_OBJECT_LOCK (src);
 | 
|---|
| 136 |     state = GST_STATE (src);
 | 
|---|
| 137 | 
 | 
|---|
| 138 |     if (state != GST_STATE_READY && state != GST_STATE_NULL)
 | 
|---|
| 139 |         goto wrong_state;
 | 
|---|
| 140 | 
 | 
|---|
| 141 |     GST_OBJECT_UNLOCK (src);
 | 
|---|
| 142 | 
 | 
|---|
| 143 |     src->device = device;
 | 
|---|
| 144 |     g_object_notify (G_OBJECT (src), "iodevice");
 | 
|---|
| 145 |     return TRUE;
 | 
|---|
| 146 | 
 | 
|---|
| 147 |     // Error
 | 
|---|
| 148 | wrong_state:
 | 
|---|
| 149 |     {
 | 
|---|
| 150 |         //GST_DEBUG_OBJECT (src, "setting location in wrong state");
 | 
|---|
| 151 |         GST_OBJECT_UNLOCK (src);
 | 
|---|
| 152 |         return FALSE;
 | 
|---|
| 153 |     }
 | 
|---|
| 154 | }
 | 
|---|
| 155 | #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 156 | 
 | 
|---|
| 157 | static void phonon_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
 | 
|---|
| 158 | {
 | 
|---|
| 159 |     PhononSrc *src;
 | 
|---|
| 160 |     g_return_if_fail (GST_IS_PHONON_SRC (object));
 | 
|---|
| 161 |     src = GST_PHONON_SRC (object);
 | 
|---|
| 162 | 
 | 
|---|
| 163 |     switch (prop_id) {
 | 
|---|
| 164 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 165 |     case ARG_PHONONSRC:
 | 
|---|
| 166 |     {
 | 
|---|
| 167 |         StreamReader *dev = (StreamReader*)(g_value_get_pointer(value));
 | 
|---|
| 168 |         if (dev)
 | 
|---|
| 169 |             phonon_src_set_device(src, dev);
 | 
|---|
| 170 |         break;
 | 
|---|
| 171 |     }
 | 
|---|
| 172 | #else
 | 
|---|
| 173 |     Q_UNUSED(value);
 | 
|---|
| 174 | #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 175 |    default:
 | 
|---|
| 176 |        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
|---|
| 177 |        break;
 | 
|---|
| 178 |    }
 | 
|---|
| 179 | }
 | 
|---|
| 180 | 
 | 
|---|
| 181 | static void phonon_src_get_property (GObject * object, guint prop_id, GValue * value,
 | 
|---|
| 182 |                                         GParamSpec * pspec)
 | 
|---|
| 183 | {
 | 
|---|
| 184 |     PhononSrc *src;
 | 
|---|
| 185 |     g_return_if_fail (GST_IS_PHONON_SRC (object));
 | 
|---|
| 186 |     src = GST_PHONON_SRC (object);
 | 
|---|
| 187 | 
 | 
|---|
| 188 |     switch (prop_id) {
 | 
|---|
| 189 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 190 |     case ARG_PHONONSRC:
 | 
|---|
| 191 |         g_value_set_pointer(value, src->device);
 | 
|---|
| 192 |         break;
 | 
|---|
| 193 | #else //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 194 |     Q_UNUSED(value);
 | 
|---|
| 195 | #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 196 |     default:
 | 
|---|
| 197 |         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | 
|---|
| 198 |         break;
 | 
|---|
| 199 |     }
 | 
|---|
| 200 | }
 | 
|---|
| 201 | 
 | 
|---|
| 202 | static GstFlowReturn phonon_src_create_read (PhononSrc * src, guint64 offset, guint length, GstBuffer ** buffer)
 | 
|---|
| 203 | {
 | 
|---|
| 204 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 205 |     Q_ASSERT(src->device);
 | 
|---|
| 206 |     if (!src->device)
 | 
|---|
| 207 |         return GST_FLOW_ERROR;
 | 
|---|
| 208 | 
 | 
|---|
| 209 |     GstBuffer *buf = gst_buffer_new_and_alloc (length);
 | 
|---|
| 210 |     GST_BUFFER_SIZE (buf) = length;
 | 
|---|
| 211 |     GST_BUFFER_OFFSET (buf) = offset;
 | 
|---|
| 212 |     GST_BUFFER_OFFSET_END (buf) = offset + length;
 | 
|---|
| 213 | 
 | 
|---|
| 214 |     bool success = src->device->read(offset, length, (char*)GST_BUFFER_DATA (buf));
 | 
|---|
| 215 |     //GST_LOG_OBJECT (src, "Reading %d bytes", length);
 | 
|---|
| 216 | 
 | 
|---|
| 217 |     if (success) {
 | 
|---|
| 218 |         *buffer = buf;
 | 
|---|
| 219 |         return GST_FLOW_OK;
 | 
|---|
| 220 |     }
 | 
|---|
| 221 | 
 | 
|---|
| 222 |     gst_mini_object_unref(GST_MINI_OBJECT(buf));
 | 
|---|
| 223 |     return GST_FLOW_ERROR;
 | 
|---|
| 224 | #else //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 225 |     Q_UNUSED(src);
 | 
|---|
| 226 |     Q_UNUSED(offset);
 | 
|---|
| 227 |     Q_UNUSED(length);
 | 
|---|
| 228 |     Q_UNUSED(buffer);
 | 
|---|
| 229 |     return GST_FLOW_ERROR;
 | 
|---|
| 230 | #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 231 | }
 | 
|---|
| 232 | 
 | 
|---|
| 233 | static GstFlowReturn phonon_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
 | 
|---|
| 234 | {
 | 
|---|
| 235 |     PhononSrc *src;
 | 
|---|
| 236 |     GstFlowReturn ret;
 | 
|---|
| 237 |     src = GST_PHONON_SRC (basesrc);
 | 
|---|
| 238 |     ret = phonon_src_create_read (src, offset, length, buffer);
 | 
|---|
| 239 |     return ret;
 | 
|---|
| 240 | }
 | 
|---|
| 241 | 
 | 
|---|
| 242 | static gboolean phonon_src_is_seekable (GstBaseSrc * basesrc)
 | 
|---|
| 243 | {
 | 
|---|
| 244 |     PhononSrc *src = GST_PHONON_SRC (basesrc);
 | 
|---|
| 245 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 246 |     if (src->device)
 | 
|---|
| 247 |         return src->device->streamSeekable();
 | 
|---|
| 248 | #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 249 |     return false;
 | 
|---|
| 250 | }
 | 
|---|
| 251 | 
 | 
|---|
| 252 | static gboolean phonon_src_get_size (GstBaseSrc * basesrc, guint64 * size)
 | 
|---|
| 253 | {
 | 
|---|
| 254 | #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 255 |     PhononSrc *src;
 | 
|---|
| 256 |     src = GST_PHONON_SRC (basesrc);
 | 
|---|
| 257 |     if (src->device && src->device->streamSeekable()) {
 | 
|---|
| 258 |         *size = src->device->streamSize();
 | 
|---|
| 259 |         return TRUE;
 | 
|---|
| 260 |     }
 | 
|---|
| 261 | #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
 | 
|---|
| 262 |     *size = 0;
 | 
|---|
| 263 |     return FALSE;
 | 
|---|
| 264 | }
 | 
|---|
| 265 | 
 | 
|---|
| 266 | // Necessary to go to READY state
 | 
|---|
| 267 | static gboolean phonon_src_start (GstBaseSrc * basesrc)
 | 
|---|
| 268 | {
 | 
|---|
| 269 |     Q_UNUSED(basesrc);
 | 
|---|
| 270 |     // Opening the device is handled by the frontend
 | 
|---|
| 271 |     // We can only assume it is already open
 | 
|---|
| 272 |     return TRUE;
 | 
|---|
| 273 | }
 | 
|---|
| 274 | 
 | 
|---|
| 275 | static gboolean phonon_src_stop (GstBaseSrc * basesrc)
 | 
|---|
| 276 | {
 | 
|---|
| 277 |     Q_UNUSED(basesrc);
 | 
|---|
| 278 |     // Closing the device is handled by the frontend
 | 
|---|
| 279 |     return TRUE;
 | 
|---|
| 280 | }
 | 
|---|
| 281 | 
 | 
|---|
| 282 | }
 | 
|---|
| 283 | } //namespace Phonon::Gstreamer
 | 
|---|
| 284 | 
 | 
|---|
| 285 | QT_END_NAMESPACE
 | 
|---|