File indexing completed on 2024-05-05 04:48:35

0001 /****************************************************************************************
0002  * Copyright (c) 2010 Sergey Ivanov <123kash@gmail.com>                                 *
0003  *                                                                                      *
0004  * This program is free software; you can redistribute it and/or modify it under        *
0005  * the terms of the GNU General Public License as published by the Free Software        *
0006  * Foundation; either version 2 of the License, or (at your option) any later           *
0007  * version.                                                                             *
0008  *                                                                                      *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0012  *                                                                                      *
0013  * You should have received a copy of the GNU General Public License along with         *
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0015  ****************************************************************************************/
0016 
0017 #define DEBUG_PREFIX "MusicDNSAudioDecoder"
0018 
0019 #include "MusicDNSAudioDecoder.h"
0020 
0021 #include <config.h>
0022 #include "core/support/Debug.h"
0023 #include "core/meta/Meta.h"
0024 
0025 extern "C" {
0026     typedef quint64 UINT64_C;
0027     #include <libavcodec/avcodec.h>
0028     #include <libavformat/avformat.h>
0029     #include <libavutil/mathematics.h>
0030 }
0031 
0032 #include <ofa1/ofa.h>
0033 
0034 DecodedAudioData::DecodedAudioData()
0035                  : m_sRate( 0 )
0036                  , m_channels( 0 )
0037                  , m_duration( 0 )
0038                  , m_data( new QByteArray )
0039 {
0040 }
0041 
0042 DecodedAudioData::~DecodedAudioData()
0043 {
0044     if( m_data )
0045         delete m_data;
0046 }
0047 
0048 int
0049 DecodedAudioData::sRate()
0050 {
0051     return m_sRate;
0052 }
0053 
0054 void
0055 DecodedAudioData::setSampleRate( const int sampleRate )
0056 {
0057     m_sRate = sampleRate;
0058 }
0059 
0060 quint8
0061 DecodedAudioData::channels()
0062 {
0063     return m_channels;
0064 }
0065 
0066 void
0067 DecodedAudioData::setChannels( const quint8 channels )
0068 {
0069     m_channels = channels;
0070 }
0071 
0072 const char *
0073 DecodedAudioData::data()
0074 {
0075     return m_data->data();
0076 }
0077 
0078 qint64
0079 DecodedAudioData::duration()
0080 {
0081     return m_duration;
0082 }
0083 
0084 void
0085 DecodedAudioData::addTime( const qint64 ms )
0086 {
0087     m_duration += ms;
0088 }
0089 
0090 int
0091 DecodedAudioData::length()
0092 {
0093     return m_data->length();
0094 }
0095 
0096 void
0097 DecodedAudioData::appendData( const quint8 *data, int length )
0098 {
0099     m_data->append( (const char *)data, length );
0100 }
0101 
0102 DecodedAudioData &DecodedAudioData::operator<< ( const quint8 &byte )
0103 {
0104     m_data->append( byte );
0105     return *this;
0106 }
0107 
0108 void DecodedAudioData::flush()
0109 {
0110     m_sRate = 0;
0111     m_channels = 0;
0112     m_duration = 0;
0113     m_data->clear();
0114 }
0115 
0116 MusicDNSAudioDecoder::MusicDNSAudioDecoder( const Meta::TrackList &tracks, const int sampleLength )
0117                     : QObject()
0118                     , ThreadWeaver::Job()
0119                     , m_tracks( tracks )
0120                     , m_sampleLength( sampleLength )
0121 {
0122 }
0123 
0124 MusicDNSAudioDecoder::~MusicDNSAudioDecoder()
0125 {
0126 
0127 }
0128 
0129 void
0130 MusicDNSAudioDecoder::run(ThreadWeaver::JobPointer self, ThreadWeaver::Thread *thread)
0131 {
0132     Q_UNUSED(self);
0133     Q_UNUSED(thread);
0134     DecodedAudioData data;
0135 
0136 #if LIBAVCODEC_VERSION_MAJOR < 59
0137     avcodec_register_all();
0138     av_register_all();
0139 #endif
0140 
0141     foreach( Meta::TrackPtr track, m_tracks )
0142     {
0143         decode( track->playableUrl().toLocalFile(), &data, m_sampleLength );
0144         if( data.duration() > MIN_SAMPLE_LENGTH )
0145         {
0146             QString fingerprint( ofa_create_print( ( unsigned char * ) data.data(),
0147                                                    OFA_LITTLE_ENDIAN, ( data.length() >> 1 ),
0148                                                    data.sRate(), data.channels() ) );
0149             emit trackDecoded( track, fingerprint );
0150         }
0151         else
0152             warning() << QLatin1String( "Some error occurred during fingerprint generation, probably track is too short: " ) +
0153                          track->playableUrl().toLocalFile();
0154         data.flush();
0155     }
0156 }
0157 
0158 void
0159 MusicDNSAudioDecoder::defaultBegin(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread)
0160 {
0161     Q_EMIT started(self);
0162     ThreadWeaver::Job::defaultBegin(self, thread);
0163 }
0164 
0165 void
0166 MusicDNSAudioDecoder::defaultEnd(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread)
0167 {
0168     ThreadWeaver::Job::defaultEnd(self, thread);
0169     if (!self->success()) {
0170         Q_EMIT failed(self);
0171     }
0172     Q_EMIT done(self);
0173 }
0174 
0175 // Function below has separate implementation for each ffmpeg API version
0176 int
0177 MusicDNSAudioDecoder::decode( const QString &fileName, DecodedAudioData *data, const int length )
0178 #if LIBAVCODEC_VERSION_MAJOR >= 59 // ffmpeg 5.0
0179 {
0180     AVFormatContext *pFormatCtx = nullptr;
0181     AVCodecContext *pCodecCtx = nullptr;
0182     const AVCodec *pCodec = nullptr;
0183     AVFrame *decodedFrame = nullptr;
0184     AVPacket *packet = nullptr, *avpkt = nullptr;
0185     AVCodecParameters *codecpar = nullptr;
0186     AVRational streamTimeBase = { 1, 1000000 };
0187     AVRational localTimeBase = { 1, 1000 };
0188 
0189     int audioStream = 0;
0190     int decoderRet = 0;
0191     int planeSize = 0;
0192 
0193     bool isOk = true;
0194     av_log_set_level(AV_LOG_VERBOSE);
0195 
0196     if( avformat_open_input( &pFormatCtx, fileName.toLocal8Bit(), nullptr, nullptr ) < 0 )
0197     {
0198         warning() << QLatin1String( "Unable to open input file: " ) + fileName;
0199         return 0;
0200     }
0201 
0202     if( avformat_find_stream_info( pFormatCtx, nullptr ) < 0 )
0203     {
0204         warning() << QLatin1String( "Unable to find stream info: " ) + fileName;
0205         avformat_close_input( &pFormatCtx );
0206         return 0;
0207     }
0208 
0209     audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0);
0210     if( audioStream < 0 )
0211     {
0212         warning() << QLatin1String( "Unable to find stream: " ) + fileName;
0213         avformat_close_input( &pFormatCtx );
0214         return 0;
0215     }
0216 
0217     if( !pCodec )
0218     {
0219         warning() << QLatin1String( "Unable to find decoder: " ) + fileName;
0220         avformat_close_input( &pFormatCtx );
0221         return 0;
0222     }
0223 
0224     pCodecCtx = avcodec_alloc_context3(pCodec);
0225 
0226     if( avcodec_open2( pCodecCtx, pCodec, nullptr ) < 0 )
0227     {
0228         warning() << QLatin1String( "Unable to open codec " ) + fileName;
0229         avformat_close_input( &pFormatCtx );
0230         return 0;
0231     }
0232 
0233     streamTimeBase = pFormatCtx->streams[audioStream]->time_base;
0234     codecpar = pFormatCtx->streams[audioStream]->codecpar;
0235 
0236     data->setSampleRate( codecpar->sample_rate );
0237     data->setChannels( ( codecpar->channels > 1 )? 1 : 0 );
0238 
0239     avpkt = av_packet_alloc();
0240     packet = av_packet_alloc();
0241     while( !av_read_frame( pFormatCtx, packet ) && isOk )
0242     {
0243         if( packet->stream_index == audioStream )
0244         {
0245             avpkt->size = packet->size;
0246             avpkt->data = packet->data;
0247             if( !decodedFrame )
0248             {
0249                 decodedFrame = av_frame_alloc();
0250                 if( !decodedFrame )
0251                 {
0252                     warning() << "Unable to allocate enough memory to decode file.";
0253                     isOk = false;
0254                     break;
0255                 }
0256                 else
0257                 av_frame_unref( decodedFrame );
0258             }
0259 
0260             decoderRet = avcodec_send_packet( pCodecCtx, avpkt );
0261             if( decoderRet < 0 )
0262             {
0263                 warning() << "Error while sending avcodec packet.";
0264                 isOk = false;
0265                 break;
0266             }
0267             do {
0268                 decoderRet = avcodec_receive_frame( pCodecCtx, decodedFrame );
0269                 if( decoderRet == AVERROR(AVERROR_EOF) || decoderRet == AVERROR(EAGAIN) )
0270                 {
0271                     break;
0272                 }
0273                 else if( decoderRet < 0 )
0274                 {
0275                     warning() << "Error while decoding.";
0276                     isOk = false;
0277                     break;
0278                 }
0279                 av_samples_get_buffer_size( &planeSize, pCodecCtx->channels, decodedFrame->nb_samples, pCodecCtx->sample_fmt, 1);
0280                 for( int i = 0; i < qMin( pCodecCtx->channels, 2 ); i++ )
0281                     data->appendData( const_cast<const quint8 *>( decodedFrame->extended_data[i] ), planeSize );
0282             } while( decoderRet == 0 );
0283 
0284             data->addTime( av_rescale_q( packet->duration, streamTimeBase, localTimeBase ) );
0285         }
0286 
0287         av_packet_unref( packet );
0288 
0289         if( data->duration() >= length )
0290             break;
0291     }
0292 
0293     av_packet_unref( avpkt );
0294 
0295     avcodec_close( pCodecCtx );
0296     avformat_close_input( &pFormatCtx );
0297     av_free( decodedFrame );
0298 
0299     return data->duration();
0300 }
0301 #elif LIBAVCODEC_VERSION_MAJOR >= 54  // ffmpeg 0.11
0302 {
0303     AVFormatContext *pFormatCtx = nullptr;
0304     AVCodecContext *pCodecCtx = nullptr;
0305     AVCodec *pCodec = nullptr;
0306     AVFrame *decodedFrame = nullptr;
0307     AVPacket packet, avpkt;
0308     AVRational streamTimeBase = { 1, 1000000 };
0309     AVRational localTimeBase = { 1, 1000 };
0310 
0311     int audioStream = 0;
0312     int gotFrame = 0;
0313     int decoderRet = 0;
0314     int planeSize = 0;
0315 
0316     bool isOk = true;
0317 
0318     if( avformat_open_input( &pFormatCtx, fileName.toLocal8Bit(), nullptr, nullptr ) < 0 )
0319     {
0320         warning() << QLatin1String( "Unable to open input file: " ) + fileName;
0321         return 0;
0322     }
0323 
0324     if( avformat_find_stream_info( pFormatCtx, nullptr ) < 0 )
0325     {
0326         warning() << QLatin1String( "Unable to find stream info: " ) + fileName;
0327         avformat_close_input( &pFormatCtx );
0328         return 0;
0329     }
0330 
0331     audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0);
0332     if( audioStream < 0 )
0333     {
0334         warning() << QLatin1String( "Unable to find stream: " ) + fileName;
0335         avformat_close_input( &pFormatCtx );
0336         return 0;
0337     }
0338 
0339     if( !pCodec )
0340     {
0341         warning() << QLatin1String( "Unable to find decoder: " ) + fileName;
0342         avformat_close_input( &pFormatCtx );
0343         return 0;
0344     }
0345 
0346     pCodecCtx = pFormatCtx->streams[audioStream]->codec;
0347 
0348     if( avcodec_open2( pCodecCtx, pCodec, nullptr ) < 0 )
0349     {
0350         warning() << QLatin1String( "Unable to open codec " ) + fileName;
0351         avformat_close_input( &pFormatCtx );
0352         return 0;
0353     }
0354 
0355     streamTimeBase = pFormatCtx->streams[audioStream]->time_base;
0356 
0357     data->setSampleRate( pCodecCtx->sample_rate );
0358     data->setChannels( ( pCodecCtx->channels > 1 )? 1 : 0 );
0359 
0360     av_init_packet( &avpkt );
0361     while( !av_read_frame( pFormatCtx, &packet ) && isOk )
0362     {
0363         if( packet.stream_index == audioStream )
0364         {
0365             avpkt.size = packet.size;
0366             avpkt.data = packet.data;
0367             while( avpkt.size > 0 )
0368             {
0369                 if( !decodedFrame )
0370                 {
0371                     decodedFrame = av_frame_alloc();
0372                     if( !decodedFrame )
0373                     {
0374                         warning() << "Unable to allocate enough memory to decode file.";
0375                         isOk = false;
0376                         break;
0377                     }
0378                     else
0379                  av_frame_unref( decodedFrame );
0380                 }
0381 
0382                 decoderRet = avcodec_decode_audio4( pCodecCtx, decodedFrame, &gotFrame, &avpkt );
0383                 if( decoderRet < 0 )
0384                 {
0385                     warning() << "Error while decoding.";
0386                     isOk = false;
0387                     break;
0388                 }
0389 
0390                 if( gotFrame )
0391                 {
0392 
0393                     av_samples_get_buffer_size( &planeSize, pCodecCtx->channels, decodedFrame->nb_samples, pCodecCtx->sample_fmt, 1);
0394                     for( int i = 0; i < qMin( pCodecCtx->channels, 2 ); i++ )
0395                         data->appendData( const_cast<const quint8 *>( decodedFrame->extended_data[i] ), planeSize );
0396                 }
0397 
0398                 avpkt.size -= decoderRet;
0399                 avpkt.data += decoderRet;
0400             }
0401 
0402             data->addTime( av_rescale_q( packet.duration, streamTimeBase, localTimeBase ) );
0403         }
0404 
0405         av_free_packet( &packet );
0406 
0407         if( data->duration() >= length )
0408             break;
0409     }
0410 
0411     av_free_packet( &avpkt );
0412 
0413     avcodec_close( pCodecCtx );
0414     avformat_close_input( &pFormatCtx );
0415     av_free( decodedFrame );
0416 
0417     return data->duration();
0418 }
0419 #elif LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 60  // ffmpeg 0.10
0420 {
0421     AVFormatContext *pFormatCtx = NULL;
0422     AVCodecContext *pCodecCtx = NULL;
0423     AVCodec *pCodec = NULL;
0424     AVFrame *decodedFrame = NULL;
0425     AVPacket packet, avpkt;
0426     AVRational streamTimeBase = { 1, 1000000 };
0427     AVRational localTimeBase = { 1, 1000 };
0428 
0429     int audioStream = 0;
0430     int gotFrame = 0;
0431     int decoderRet = 0;
0432     int planeSize = 0;
0433 
0434     bool isOk = true;
0435 
0436     if( avformat_open_input( &pFormatCtx, fileName.toLocal8Bit(), NULL, NULL ) < 0 )
0437     {
0438         warning() << QLatin1String( "Unable to open input file: " ) + fileName;
0439         return 0;
0440     }
0441 
0442     if( avformat_find_stream_info( pFormatCtx, NULL ) < 0 )
0443     {
0444         warning() << QLatin1String( "Unable to find stream info: " ) + fileName;
0445         avformat_close_input( &pFormatCtx );
0446         return 0;
0447     }
0448 
0449     audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0);
0450     if( audioStream < 0 )
0451     {
0452         warning() << QLatin1String( "Unable to find stream: " ) + fileName;
0453         avformat_close_input( &pFormatCtx );
0454         return 0;
0455     }
0456 
0457     if( !pCodec )
0458     {
0459         warning() << QLatin1String( "Unable to find decoder: " ) + fileName;
0460         avformat_close_input( &pFormatCtx );
0461         return 0;
0462     }
0463 
0464     pCodecCtx = pFormatCtx->streams[audioStream]->codec;
0465 
0466     if( avcodec_open2( pCodecCtx, pCodec, NULL ) < 0 )
0467     {
0468         warning() << QLatin1String( "Unable to open codec " ) + fileName;
0469         avformat_close_input( &pFormatCtx );
0470         return 0;
0471     }
0472 
0473     streamTimeBase = pFormatCtx->streams[audioStream]->time_base;
0474 
0475     data->setSampleRate( pCodecCtx->sample_rate );
0476     data->setChannels( ( pCodecCtx->channels > 1 )? 1 : 0 );
0477 
0478     av_init_packet( &avpkt );
0479     while( !av_read_frame( pFormatCtx, &packet ) && isOk )
0480     {
0481         if( packet.stream_index == audioStream )
0482         {
0483             avpkt.size = packet.size;
0484             avpkt.data = packet.data;
0485             while( avpkt.size > 0 )
0486             {
0487                 if( !decodedFrame )
0488                 {
0489                     decodedFrame = av_frame_alloc();
0490                     if( !decodedFrame )
0491                     {
0492                         warning() << "Unable to allocate enough memory to decode file.";
0493                         isOk = false;
0494                         break;
0495                     }
0496                     else
0497                  av_frame_unref( decodedFrame );
0498                 }
0499 
0500                 decoderRet = avcodec_decode_audio4( pCodecCtx, decodedFrame, &gotFrame, &avpkt );
0501                 if( decoderRet < 0 )
0502                 {
0503                     warning() << "Error while decoding.";
0504                     isOk = false;
0505                     break;
0506                 }
0507 
0508                 if( gotFrame )
0509                 {
0510                     
0511                     av_samples_get_buffer_size( &planeSize, pCodecCtx->channels, decodedFrame->nb_samples, pCodecCtx->sample_fmt, 1);
0512                     for( int i = 0; i < qMin( pCodecCtx->channels, 2 ); i++ )
0513                         data->appendData( const_cast<const quint8 *>( decodedFrame->extended_data[i] ), planeSize );
0514                 }
0515 
0516                 avpkt.size -= decoderRet;
0517                 avpkt.data += decoderRet;
0518             }
0519 
0520             data->addTime( av_rescale_q( packet.duration, streamTimeBase, localTimeBase ) );
0521         }
0522 
0523         av_free_packet( &packet );
0524 
0525         if( data->duration() >= length )
0526             break;
0527     }
0528 
0529     av_free_packet( &avpkt );
0530 
0531     avcodec_close( pCodecCtx );
0532     avformat_close_input( &pFormatCtx );
0533     av_free( decodedFrame );
0534 
0535     return data->duration();
0536 }
0537 #elif LIBAVCODEC_VERSION_MAJOR == 53  && LIBAVCODEC_VERSION_MINOR >= 42 // ffmpeg 0.9
0538 {
0539     AVFormatContext *pFormatCtx = NULL;
0540     AVCodecContext *pCodecCtx = NULL;
0541     AVCodec *pCodec = NULL;
0542     AVFrame *decodedFrame = NULL;
0543     AVPacket packet, avpkt;
0544     AVRational streamTimeBase = { 1, 1000000 };
0545     AVRational localTimeBase = { 1, 1000 };
0546 
0547     int audioStream = 0;
0548     int gotFrame = 0;
0549     int decoderRet = 0;
0550     int planeSize = 0;
0551 
0552     bool isOk = true;
0553 
0554     if( avformat_open_input( &pFormatCtx, fileName.toLocal8Bit(), NULL, NULL ) < 0 )
0555     {
0556         warning() << QLatin1String( "Unable to open input file: " ) + fileName;
0557         return 0;
0558     }
0559 
0560     if( avformat_find_stream_info( pFormatCtx, NULL ) < 0 )
0561     {
0562         warning() << QLatin1String( "Unable to find stream info: " ) + fileName;
0563         av_close_input_file( pFormatCtx );
0564         return 0;
0565     }
0566 
0567     audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0);
0568     if( audioStream < 0 )
0569     {
0570         warning() << QLatin1String( "Unable to find stream: " ) + fileName;
0571         av_close_input_file( pFormatCtx );
0572         return 0;
0573     }
0574 
0575     if( !pCodec )
0576     {
0577         warning() << QLatin1String( "Unable to find decoder: " ) + fileName;
0578         av_close_input_file( pFormatCtx );
0579         return 0;
0580     }
0581 
0582     pCodecCtx = pFormatCtx->streams[audioStream]->codec;
0583 
0584     if( avcodec_open2( pCodecCtx, pCodec, NULL ) < 0 )
0585     {
0586         warning() << QLatin1String( "Unable to open codec " ) + fileName;
0587         av_close_input_file( pFormatCtx );
0588         return 0;
0589     }
0590 
0591     streamTimeBase = pFormatCtx->streams[audioStream]->time_base;
0592 
0593     data->setSampleRate( pCodecCtx->sample_rate );
0594     data->setChannels( ( pCodecCtx->channels > 1 )? 1 : 0 );
0595 
0596     av_init_packet( &avpkt );
0597     while( !av_read_frame( pFormatCtx, &packet ) && isOk )
0598     {
0599         if( packet.stream_index == audioStream )
0600         {
0601             avpkt.size = packet.size;
0602             avpkt.data = packet.data;
0603             while( avpkt.size > 0 )
0604             {
0605                 if( !decodedFrame )
0606                 {
0607                     decodedFrame = av_frame_alloc();
0608                     if( !decodedFrame )
0609                     {
0610                         warning() << "Unable to allocate enough memory to decode file.";
0611                         isOk = false;
0612                         break;
0613                     }
0614                     else
0615                  av_frame_unref( decodedFrame );
0616                 }
0617 
0618                 decoderRet = avcodec_decode_audio4( pCodecCtx, decodedFrame, &gotFrame, &avpkt );
0619                 if( decoderRet < 0 )
0620                 {
0621                     warning() << "Error while decoding.";
0622                     isOk = false;
0623                     break;
0624                 }
0625 
0626                 if( gotFrame )
0627                 {
0628 
0629                     av_samples_get_buffer_size( &planeSize, pCodecCtx->channels, decodedFrame->nb_samples, pCodecCtx->sample_fmt, 1);
0630                     for( int i = 0; i < qMin( pCodecCtx->channels, 2 ); i++ )
0631                         data->appendData( const_cast<const quint8 *>( decodedFrame->extended_data[i] ), planeSize );
0632                 }
0633 
0634                 avpkt.size -= decoderRet;
0635                 avpkt.data += decoderRet;
0636             }
0637 
0638             data->addTime( av_rescale_q( packet.duration, streamTimeBase, localTimeBase ) );
0639         }
0640 
0641         av_free_packet( &packet );
0642 
0643         if( data->duration() >= length )
0644             break;
0645     }
0646 
0647     av_free_packet( &avpkt );
0648 
0649     avcodec_close( pCodecCtx );
0650     av_close_input_file( pFormatCtx );
0651     av_free( decodedFrame );
0652 
0653     return data->duration();
0654 }
0655 #elif LIBAVCODEC_VERSION_MAJOR == 53  && LIBAVCODEC_VERSION_MINOR >= 7 // ffmpeg 0.8
0656 {
0657     AVFormatContext *pFormatCtx = NULL;
0658     AVCodecContext *pCodecCtx = NULL;
0659     AVCodec *pCodec = NULL;
0660     AVPacket packet, avpkt;
0661     AVRational streamTimeBase = { 1, 1000000 };
0662     AVRational localTimeBase = { 1, 1000 };
0663 
0664     qint8 *buffer = new qint8[AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
0665     qint32 bufferSize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
0666 
0667     int outSize = 0;
0668 
0669     int audioStream = 0;
0670     int decoderRet = 0;
0671 
0672     bool isOk = true;
0673 
0674     if( avformat_open_input( &pFormatCtx, fileName.toLocal8Bit(), NULL, NULL ) < 0 )
0675     {
0676         warning() << QLatin1String( "Unable to open input file: " ) + fileName;
0677         return 0;
0678     }
0679 
0680     if( av_find_stream_info( pFormatCtx ) < 0 )
0681     {
0682         warning() << QLatin1String( "Unable to find stream info: " ) + fileName;
0683         av_close_input_file( pFormatCtx );
0684         return 0;
0685     }
0686 
0687     audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0);
0688     if( audioStream < 0 )
0689     {
0690         warning() << QLatin1String( "Unable to find stream: " ) + fileName;
0691         av_close_input_file( pFormatCtx );
0692         return 0;
0693     }
0694 
0695     if( !pCodec )
0696     {
0697         warning() << QLatin1String( "Unable to find decoder: " ) + fileName;
0698         av_close_input_file( pFormatCtx );
0699         return 0;
0700     }
0701 
0702     pCodecCtx = pFormatCtx->streams[audioStream]->codec;
0703 
0704     if( avcodec_open( pCodecCtx, pCodec ) < 0 )
0705     {
0706         warning() << QLatin1String( "Unable to open codec " ) + fileName;
0707         av_close_input_file( pFormatCtx );
0708         return 0;
0709     }
0710 
0711     streamTimeBase = pFormatCtx->streams[audioStream]->time_base;
0712 
0713     data->setSampleRate( pCodecCtx->sample_rate );
0714     data->setChannels( ( pCodecCtx->channels > 1 )? 1 : 0 );
0715 
0716     av_init_packet( &avpkt );
0717     while( !av_read_frame( pFormatCtx, &packet ) && isOk )
0718     {
0719         if( packet.stream_index == audioStream )
0720         {
0721             avpkt.size = packet.size;
0722             avpkt.data = packet.data;
0723             while( avpkt.size > 0 )
0724             {
0725                 if( bufferSize < qMax( AVCODEC_MAX_AUDIO_FRAME_SIZE, avpkt.size*2 ) )
0726                 {
0727                     bufferSize = qMax( AVCODEC_MAX_AUDIO_FRAME_SIZE, avpkt.size*2 );
0728                     delete [] buffer;
0729                     buffer = new qint8[bufferSize+FF_INPUT_BUFFER_PADDING_SIZE];
0730                 }
0731 
0732                 outSize = bufferSize;
0733                 decoderRet = avcodec_decode_audio3( pCodecCtx, ( qint16 * )buffer, &outSize, &avpkt );
0734                 if( decoderRet < 0 )
0735                 {
0736                     warning() << "Error while decoding.";
0737                     isOk = false;
0738                     break;
0739                 }
0740 
0741                 if( outSize > 0 )
0742                 {
0743                     data->appendData( ( const quint8 *)buffer, outSize );
0744                 }
0745 
0746                 avpkt.size -= decoderRet;
0747                 avpkt.data += decoderRet;
0748             }
0749 
0750             data->addTime( av_rescale_q( packet.duration, streamTimeBase, localTimeBase ) );
0751         }
0752 
0753         av_free_packet( &packet );
0754 
0755         if( data->duration() >= length )
0756             break;
0757     }
0758 
0759     delete [] buffer;
0760 
0761     av_free_packet( &avpkt );
0762 
0763     avcodec_close( pCodecCtx );
0764     av_close_input_file( pFormatCtx );
0765 
0766     return data->duration();
0767 }
0768 #elif LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 122 // ffmpeg 0.7
0769 {
0770     AVFormatContext *pFormatCtx = NULL;
0771     AVCodecContext *pCodecCtx = NULL;
0772     AVCodec *pCodec = NULL;
0773     AVPacket packet, avpkt;
0774     AVRational streamTimeBase = { 1, 1000000 };
0775     AVRational localTimeBase = { 1, 1000 };
0776 
0777     qint8 *buffer = new qint8[AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
0778     qint32 bufferSize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
0779 
0780     int outSize = 0;
0781 
0782     int audioStream = 0;
0783     int decoderRet = 0;
0784 
0785     bool isOk = true;
0786 
0787     if( avformat_open_input( &pFormatCtx, fileName.toLocal8Bit(), NULL, NULL ) < 0 )
0788     {
0789         warning() << QLatin1String( "Unable to open input file: " ) + fileName;
0790         return 0;
0791     }
0792 
0793     if( av_find_stream_info( pFormatCtx ) < 0 )
0794     {
0795         warning() << QLatin1String( "Unable to find stream info: " ) + fileName;
0796         av_close_input_file( pFormatCtx );
0797         return 0;
0798     }
0799 
0800     audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &pCodec, 0);
0801     if( audioStream < 0 )
0802     {
0803         warning() << QLatin1String( "Unable to find stream: " ) + fileName;
0804         av_close_input_file( pFormatCtx );
0805         return 0;
0806     }
0807 
0808     if( !pCodec )
0809     {
0810         warning() << QLatin1String( "Unable to find decoder: " ) + fileName;
0811         av_close_input_file( pFormatCtx );
0812         return 0;
0813     }
0814 
0815     pCodecCtx = pFormatCtx->streams[audioStream]->codec;
0816 
0817     if( avcodec_open( pCodecCtx, pCodec ) < 0 )
0818     {
0819         warning() << QLatin1String( "Unable to open codec " ) + fileName;
0820         av_close_input_file( pFormatCtx );
0821         return 0;
0822     }
0823 
0824     streamTimeBase = pFormatCtx->streams[audioStream]->time_base;
0825 
0826     data->setSampleRate( pCodecCtx->sample_rate );
0827     data->setChannels( ( pCodecCtx->channels > 1 )? 1 : 0 );
0828 
0829     av_init_packet( &avpkt );
0830     while( !av_read_frame( pFormatCtx, &packet ) && isOk )
0831     {
0832         if( packet.stream_index == audioStream )
0833         {
0834             avpkt.size = packet.size;
0835             avpkt.data = packet.data;
0836             while( avpkt.size > 0 )
0837             {
0838                 if( bufferSize < qMax( AVCODEC_MAX_AUDIO_FRAME_SIZE, avpkt.size*2 ) )
0839                 {
0840                     bufferSize = qMax( AVCODEC_MAX_AUDIO_FRAME_SIZE, avpkt.size*2 );
0841                     delete [] buffer;
0842                     buffer = new qint8[bufferSize+FF_INPUT_BUFFER_PADDING_SIZE];
0843                 }
0844 
0845                 outSize = bufferSize;
0846                 decoderRet = avcodec_decode_audio3( pCodecCtx, ( qint16 * )buffer, &outSize, &avpkt );
0847                 if( decoderRet < 0 )
0848                 {
0849                     warning() << "Error while decoding.";
0850                     isOk = false;
0851                     break;
0852                 }
0853 
0854                 if( outSize > 0 )
0855                 {
0856                     data->appendData( ( const quint8 *)buffer, outSize );
0857                 }
0858 
0859                 avpkt.size -= decoderRet;
0860                 avpkt.data += decoderRet;
0861             }
0862 
0863             data->addTime( av_rescale_q( packet.duration, streamTimeBase, localTimeBase ) );
0864         }
0865 
0866         av_free_packet( &packet );
0867 
0868         if( data->duration() >= length )
0869             break;
0870     }
0871 
0872     delete [] buffer;
0873 
0874     av_free_packet( &avpkt );
0875 
0876     avcodec_close( pCodecCtx );
0877     av_close_input_file( pFormatCtx );
0878 
0879     return data->duration();
0880 }
0881 #else
0882 {
0883     Q_UNUSED( fileName )
0884     Q_UNUSED( data )
0885 
0886     warning() << QLatin1String( "Unsupported ffmpeg version. Decoding is abandoned." );
0887 
0888     return 0;
0889 }
0890 #endif
0891 
0892