src/3rdparty/phonon/gstreamer/audiodataoutput.cpp
changeset 30 5dc02b23752f
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /*  This file is part of the KDE project
       
     2     Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
       
     3     Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>
       
     4 
       
     5     This library is free software; you can redistribute it and/or
       
     6     modify it under the terms of the GNU Lesser General Public
       
     7     License as published by the Free Software Foundation; either
       
     8     version 2.1 of the License, or (at your option) version 3, or any
       
     9     later version accepted by the membership of KDE e.V. (or its
       
    10     successor approved by the membership of KDE e.V.), Nokia Corporation
       
    11     (or its successors, if any) and the KDE Free Qt Foundation, which shall
       
    12     act as a proxy defined in Section 6 of version 3 of the license.
       
    13 
       
    14     This library is distributed in the hope that it will be useful,
       
    15     but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    17     Lesser General Public License for more details.
       
    18 
       
    19     You should have received a copy of the GNU Lesser General Public
       
    20     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
       
    21 
       
    22 */
       
    23 
       
    24 #include "audiodataoutput.h"
       
    25 #include "gsthelper.h"
       
    26 #include "medianode.h"
       
    27 #include "mediaobject.h"
       
    28 #include <QtCore/QVector>
       
    29 #include <QtCore/QMap>
       
    30 #include <phonon/audiooutput.h>
       
    31 
       
    32 QT_BEGIN_HEADER
       
    33 QT_BEGIN_NAMESPACE
       
    34 
       
    35 namespace Phonon
       
    36 {
       
    37 namespace Gstreamer
       
    38 {
       
    39 AudioDataOutput::AudioDataOutput(Backend *backend, QObject *parent)
       
    40     : QObject(parent),
       
    41     MediaNode(backend, AudioSink | AudioSource)
       
    42 {
       
    43     static int count = 0;
       
    44     m_name = "AudioDataOutput" + QString::number(count++);
       
    45 
       
    46     m_queue = gst_element_factory_make ("identity", NULL);
       
    47     gst_object_ref(m_queue);
       
    48     m_isValid = true;
       
    49 }
       
    50 
       
    51 AudioDataOutput::~AudioDataOutput()
       
    52 {
       
    53     gst_element_set_state(m_queue, GST_STATE_NULL);
       
    54     gst_object_unref(m_queue);
       
    55 }
       
    56 
       
    57 int AudioDataOutput::dataSize() const
       
    58 {
       
    59     return m_dataSize;
       
    60 }
       
    61 
       
    62 int AudioDataOutput::sampleRate() const
       
    63 {
       
    64     return 44100;
       
    65 }
       
    66 
       
    67 void AudioDataOutput::setDataSize(int size)
       
    68 {
       
    69     m_dataSize = size;
       
    70 }
       
    71 
       
    72 typedef QMap<Phonon::AudioDataOutput::Channel, QVector<float> > FloatMap;
       
    73 typedef QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > IntMap;
       
    74 
       
    75 inline void AudioDataOutput::convertAndEmit(const QVector<qint16> &leftBuffer, const QVector<qint16> &rightBuffer)
       
    76 {
       
    77     //TODO: Floats
       
    78     IntMap map;
       
    79     map.insert(Phonon::AudioDataOutput::LeftChannel, leftBuffer);
       
    80     map.insert(Phonon::AudioDataOutput::RightChannel, rightBuffer);
       
    81     emit dataReady(map);
       
    82 }
       
    83 
       
    84 void AudioDataOutput::processBuffer(GstPad*, GstBuffer* buffer, gpointer gThat)
       
    85 {
       
    86     // TODO emit endOfMedia
       
    87     AudioDataOutput *that = reinterpret_cast<AudioDataOutput*>(gThat);
       
    88 
       
    89     // determine the number of channels
       
    90     GstStructure* structure = gst_caps_get_structure (GST_BUFFER_CAPS(buffer), 0);
       
    91     gst_structure_get_int (structure, "channels", &that->m_channels);
       
    92 
       
    93     if (that->m_channels > 2 || that->m_channels < 0) {
       
    94         qWarning() << Q_FUNC_INFO << ": Number of channels not supported: " << that->m_channels;
       
    95         return;
       
    96     }
       
    97 
       
    98     gint16 *data = reinterpret_cast<gint16*>(GST_BUFFER_DATA(buffer));
       
    99     guint size = GST_BUFFER_SIZE(buffer) / sizeof(gint16);
       
   100 
       
   101     that->m_pendingData.reserve(that->m_pendingData.size() + size);
       
   102 
       
   103     for (uint i=0; i<size; i++) {
       
   104         // 8 bit? interleaved? yay for lacking documentation!
       
   105         that->m_pendingData.append(data[i]);
       
   106     }
       
   107 
       
   108     while (that->m_pendingData.size() > that->m_dataSize * that->m_channels) {
       
   109         if (that->m_channels == 1) {
       
   110             QVector<qint16> intBuffer(that->m_dataSize);
       
   111             memcpy(intBuffer.data(), that->m_pendingData.constData(), that->m_dataSize * sizeof(qint16));
       
   112 
       
   113             that->convertAndEmit(intBuffer, intBuffer);
       
   114             int newSize = that->m_pendingData.size() - that->m_dataSize;
       
   115             memmove(that->m_pendingData.data(), that->m_pendingData.constData() + that->m_dataSize, newSize * sizeof(qint16));
       
   116             that->m_pendingData.resize(newSize);
       
   117         } else {
       
   118             QVector<qint16> left(that->m_dataSize), right(that->m_dataSize);
       
   119             for (int i=0; i<that->m_dataSize; i++) {
       
   120                 left[i] = that->m_pendingData[i*2];
       
   121                 right[i] = that->m_pendingData[i*2+1];
       
   122             }
       
   123             that->m_pendingData.resize(that->m_pendingData.size() - that->m_dataSize*2);
       
   124             that->convertAndEmit(left, right);
       
   125         }
       
   126     }
       
   127 }
       
   128 
       
   129 void AudioDataOutput::mediaNodeEvent(const MediaNodeEvent *event)
       
   130 {
       
   131     if (event->type() == MediaNodeEvent::MediaObjectConnected && root()) {
       
   132         g_object_set(G_OBJECT(audioElement()), "sync", true, (const char*)NULL);
       
   133         GstPad *audiopad = gst_element_get_pad (audioElement(), "src");
       
   134         gst_pad_add_buffer_probe (audiopad, G_CALLBACK(processBuffer), this);
       
   135         gst_object_unref (audiopad);
       
   136         return;
       
   137     }
       
   138 
       
   139     MediaNode::mediaNodeEvent(event);
       
   140 }
       
   141 
       
   142 }} //namespace Phonon::Gstreamer
       
   143 
       
   144 QT_END_NAMESPACE
       
   145 QT_END_HEADER
       
   146 
       
   147 #include "moc_audiodataoutput.cpp"
       
   148 // vim: sw=4 ts=4
       
   149