aboutsummaryrefslogblamecommitdiff
path: root/src/plugins/Input/cue/decoder_cue.cpp
blob: b9da9a6dfacc92eb46745eff03535c38af50f1ef (plain) (tree)
1
2
                                                                            
                                                                            

















                                                                             




                                
                           














                                                                              



                                






                             
                 




                                                          

                            
                                                 

                     
                                              
                                  





                                                   
 

                             
                                                                            

                     
                                                   





                                                        





                                                    


                         
                                  
     














                                                           
     
 


                                                            

                                          
                                                                   


                                                               
                                                                             
                                       
                            
                                               
                                               

                                                                            
                                       


                
                              








                                            
                             



                                                
                                 


                                         










































                                                             






























                                                 
                                                       
























                                              






                           

                                 
                                 
     
                                                  



                                                              
                                 




                                                   
                                                
                                     







                                                       
                      

                       

                                                                                
     
 
 
                                                                         
 
                                     

                                              
                                           
                                                 


                                             
                                                        
                                                                       
 




                                                                             
                      





                                                        
/***************************************************************************
 *   Copyright (C) 2008-2009 by Ilya Kotov                                 *
 *   forkotov02@hotmail.ru                                                 *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <qmmp/buffer.h>
#include <qmmp/output.h>
#include <qmmp/recycler.h>
#include <qmmp/fileinfo.h>
#include <qmmp/decoderfactory.h>
#include <qmmp/soundcore.h>

#include <QObject>
#include <QFile>

#include "cueparser.h"
#include "decoder_cue.h"


DecoderCUE::DecoderCUE(QObject *parent, DecoderFactory *d, const QString &url)
        : Decoder(parent, d)
{
    path = url;
    m_decoder = 0;
    m_output2 = 0;
    m_input2 = 0;
    for (int i = 1; i < 10; ++i)
        m_bands2[i] = 0;
    m_preamp2 = 0;
    m_useEQ2 = FALSE;
}

DecoderCUE::~DecoderCUE()
{}

bool DecoderCUE::initialize()
{
    m_input2 = 0;

    QString p = QUrl(path).path();
    p.replace(QString(QUrl::toPercentEncoding("#")), "#");
    p.replace(QString(QUrl::toPercentEncoding("%")), "%");
    CUEParser parser(p);
    if (parser.count() == 0)
    {
        qWarning("DecoderCUE: invalid cue file");
        return FALSE;
    }
    int track = path.section("#", -1).toInt();
    path = parser.filePath(track);
    // find next track
    if(track <= parser.count() - 1)
        m_nextUrl = parser.info(track + 1)->path();
    //is it track of another file?
    if(QUrl(m_nextUrl).path() != p)
        m_nextUrl.clear();

    if (!QFile::exists(path))
    {
        qWarning("DecoderCUE: file \"%s\" doesn't exist", qPrintable(path));
        return FALSE;
    }
    DecoderFactory *df = Decoder::findByPath(path);
    if (!df)
    {
        qWarning("DecoderCUE: unsupported file format");
        return FALSE;
    }
    if (!df->properties().noInput)
    {
        m_input2 = new QFile(path);
        if (!m_input2->open(QIODevice::ReadOnly))
        {
            qDebug("DecoderCUE: cannot open input");
            stop();
            return FALSE;
        }
    }
    if (df->properties().noOutput)
    {
        qWarning("DecoderCUE: unsupported file format");
        return FALSE;
    }
    m_output2 = Output::create(this);
    if (!m_output2)
    {
        qWarning("DecoderCUE: unable to create output");
        return FALSE;
    }
    if (!m_output2->initialize())
    {
        qWarning("SoundCore: unable to initialize output");
        delete m_output2;
        m_output2 = 0;
        return FALSE;
    }

    m_length = parser.length(track);
    m_offset = parser.offset(track);
    m_decoder = df->create(this, m_input2, m_output2, path);
    m_decoder->setEQ(m_bands2, m_preamp2);
    m_decoder->setEQEnabled(m_useEQ2);
    connect(m_decoder, SIGNAL(playbackFinished()), SLOT(finish()));
    //replace default state handler to ignore metadata
    m_decoder->setStateHandler(new CUEStateHandler(m_decoder));
    m_output2->setStateHandler(m_decoder->stateHandler());
    connect(stateHandler(), SIGNAL(aboutToFinish()), SLOT(proccessFinish()));
    //prepare decoder and ouput objects
    m_decoder->initialize();
    qDebug("%lld == %lld", m_offset, m_length);
    m_decoder->setFragment(m_offset, m_length);
    //send metadata
    QMap<Qmmp::MetaData, QString> metaData = parser.info(track)->metaData();
    stateHandler()->dispatch(metaData);
    return TRUE;
}

qint64 DecoderCUE::totalTime()
{
    return m_decoder ? m_length : 0;
}

void DecoderCUE::seek(qint64 pos)
{
    if (m_output2 && m_output2->isRunning())
    {
        m_output2->mutex()->lock ();
        m_output2->seek(pos);
        m_output2->mutex()->unlock();
        if (m_decoder && m_decoder->isRunning())
        {
            m_decoder->mutex()->lock ();
            m_decoder->seek(pos);
            m_decoder->mutex()->unlock();
        }
    }
}

void DecoderCUE::stop()
{
    if (m_decoder /*&& m_decoder->isRunning()*/)
    {
        m_decoder->mutex()->lock ();
        m_decoder->stop();
        m_decoder->mutex()->unlock();
        //m_decoder->stateHandler()->dispatch(Qmmp::Stopped);
    }
    if (m_output2)
    {
        m_output2->mutex()->lock ();
        m_output2->stop();
        m_output2->mutex()->unlock();
    }

    // wake up threads
    if (m_decoder)
    {
        m_decoder->mutex()->lock ();
        m_decoder->cond()->wakeAll();
        m_decoder->mutex()->unlock();
    }
    if (m_output2)
    {
        m_output2->recycler()->mutex()->lock ();
        m_output2->recycler()->cond()->wakeAll();
        m_output2->recycler()->mutex()->unlock();
    }
    if (m_decoder)
        m_decoder->wait();
    if (m_output2)
        m_output2->wait();

    if (m_input2)
    {
        m_input2->deleteLater();
        m_input2 = 0;
    }
}

void DecoderCUE::pause()
{
    if (m_output2)
    {
        m_output2->mutex()->lock ();
        m_output2->pause();
        m_output2->mutex()->unlock();
    }
    else if (m_decoder)
    {
        m_decoder->mutex()->lock ();
        m_decoder->pause();
        m_decoder->mutex()->unlock();
    }

    // wake up threads
    if (m_decoder)
    {
        m_decoder->mutex()->lock ();
        m_decoder->cond()->wakeAll();
        m_decoder->mutex()->unlock();
    }

    if (m_output2)
    {
        m_output2->recycler()->mutex()->lock ();
        m_output2->recycler()->cond()->wakeAll();
        m_output2->recycler()->mutex()->unlock();
    }
}

void DecoderCUE::setEQ(double bands[10], double preamp)
{
    for (int i = 0; i < 10; ++i)
        m_bands2[i] = bands[i];
    m_preamp2 = preamp;
    if (m_decoder)
    {
        m_decoder->mutex()->lock ();
        m_decoder->setEQ(m_bands2, m_preamp2);
        m_decoder->setEQEnabled(m_useEQ2);
        m_decoder->mutex()->unlock();
    }
}

void DecoderCUE::setEQEnabled(bool on)
{
    m_useEQ2 = on;
    if (m_decoder)
    {
        m_decoder->mutex()->lock ();
        m_decoder->setEQ(m_bands2, m_preamp2);
        m_decoder->setEQEnabled(on);
        m_decoder->mutex()->unlock();
    }
}

void DecoderCUE::run()
{
    m_decoder->start();
    if (m_output2)
        m_output2->start();
}

void DecoderCUE::proccessFinish()
{
    if(nextUrlRequest(m_nextUrl))
    {
        qDebug("DecoderCUE: going to next track");
        int track = m_nextUrl.section("#", -1).toInt();
        QString p = QUrl(m_nextUrl).path();
        p.replace(QString(QUrl::toPercentEncoding("#")), "#");
        p.replace(QString(QUrl::toPercentEncoding("%")), "%");
        //update current fragment
        CUEParser parser(p);
        m_length = parser.length(track);
        m_offset = parser.offset(track);
        m_decoder->mutex()->lock();
        m_decoder->setFragment(m_offset, m_length);
        m_output2->seek(0); //reset time counter
        m_decoder->mutex()->unlock();
         // find next track
        if(track <= parser.count() - 1)
            m_nextUrl = parser.info(track + 1)->path();
        else
            m_nextUrl.clear();
        //is it track of another file?
        if(QUrl(m_nextUrl).path() != p)
            m_nextUrl.clear();
        //change track
        finish();
        //send metadata
        QMap<Qmmp::MetaData, QString> metaData = parser.info(track)->metaData();
        stateHandler()->dispatch(metaData);
    }
}

CUEStateHandler::CUEStateHandler(QObject *parent): StateHandler(parent){}

CUEStateHandler::~CUEStateHandler(){}

void CUEStateHandler::dispatch(qint64 elapsed,
                               int bitrate,
                               quint32 frequency,
                               int precision,
                               int channels)
{
    StateHandler::instance()->dispatch(elapsed, bitrate,
                                       frequency, precision, channels);

}

void CUEStateHandler::dispatch(const QMap<Qmmp::MetaData, QString> &metaData)
{
    //ignore media file metadata
    Q_UNUSED(metaData)
}

void CUEStateHandler::dispatch(const Qmmp::State &state)
{
    StateHandler::instance()->dispatch(state);
}