File indexing completed on 2025-06-29 07:27:58

0001 /*
0002     FLAC decoder module for K3b.
0003     Based on the Ogg Vorbis module for same.
0004     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0005     SPDX-FileCopyrightText: 2003-2004 John Steele Scott <toojays@toojays.net>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "k3bflacdecoder.h"
0011 #include "k3bplugin_i18n.h"
0012 #include <config-k3b.h>
0013 #include <config-flac.h>
0014 
0015 #include <QBuffer>
0016 #include <QDebug>
0017 #include <QFile>
0018 #include <QStringList>
0019 
0020 #include <kpluginfactory.h>
0021 #include <string.h>
0022 #include <math.h>
0023 #include <FLAC++/metadata.h>
0024 #include <FLAC++/decoder.h>
0025 
0026 K_PLUGIN_CLASS_WITH_JSON(K3bFLACDecoderFactory, "k3bflacdecoder.json")
0027 
0028 #ifdef ENABLE_TAGLIB
0029 #include <tag.h>
0030 #include <flacfile.h>
0031 #endif
0032 
0033 #if !defined FLACPP_API_VERSION_CURRENT || FLACPP_API_VERSION_CURRENT < 6
0034 #define LEGACY_FLAC
0035 #else
0036 #undef LEGACY_FLAC
0037 #endif
0038 
0039 
0040 class K3bFLACDecoder::Private
0041 #ifdef LEGACY_FLAC
0042     : public FLAC::Decoder::SeekableStream
0043 #else
0044         : public FLAC::Decoder::Stream
0045 #endif
0046 {
0047 public:
0048     void open(QFile* f) {
0049         file = f;
0050         file->open(QIODevice::ReadOnly);
0051 
0052         //TODO port me to kde4
0053         //internalBuffer->flush();
0054 
0055         set_metadata_respond(FLAC__METADATA_TYPE_STREAMINFO);
0056         set_metadata_respond(FLAC__METADATA_TYPE_VORBIS_COMMENT);
0057 
0058         init();
0059         process_until_end_of_metadata();
0060     }
0061 
0062     void cleanup() {
0063         file->close();
0064         finish();
0065         delete comments;
0066         comments = 0;
0067     }
0068 
0069     Private(QFile* f)
0070 #ifdef LEGACY_FLAC
0071         : FLAC::Decoder::SeekableStream(),
0072 #else
0073           : FLAC::Decoder::Stream(),
0074 #endif
0075             comments(0) {
0076             internalBuffer = new QBuffer();
0077             internalBuffer->open(QIODevice::ReadWrite);
0078 
0079             open(f);
0080         }
0081 
0082 
0083     ~Private() override {
0084         cleanup();
0085         delete internalBuffer;
0086     }
0087 
0088     bool seekToFrame(int frame);
0089 
0090     QFile* file;
0091     QBuffer* internalBuffer;
0092     FLAC::Metadata::VorbisComment* comments;
0093     unsigned rate;
0094     unsigned channels;
0095     unsigned bitsPerSample;
0096     unsigned maxFramesize;
0097     unsigned maxBlocksize;
0098     unsigned minFramesize;
0099     unsigned minBlocksize;
0100     FLAC__uint64 samples;
0101 
0102 protected:
0103 #ifdef LEGACY_FLAC
0104     virtual FLAC__SeekableStreamDecoderReadStatus read_callback(FLAC__byte buffer[], unsigned *bytes);
0105     virtual FLAC__SeekableStreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
0106     virtual FLAC__SeekableStreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
0107     virtual FLAC__SeekableStreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length);
0108 #else
0109     FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override;
0110     FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override;
0111     FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) override;
0112     FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) override;
0113 #endif
0114     bool eof_callback() override;
0115     void error_callback(FLAC__StreamDecoderErrorStatus) override{};
0116     void metadata_callback(const ::FLAC__StreamMetadata *metadata) override;
0117     ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override;
0118 };
0119 
0120 bool K3bFLACDecoder::Private::seekToFrame(int frame) {
0121     FLAC__uint64 sample = static_cast<FLAC__uint64>(frame) * rate / 75;
0122     return seek_absolute(sample);
0123 }
0124 
0125 bool K3bFLACDecoder::Private::eof_callback() {
0126     return file->atEnd();
0127 }
0128 
0129 #ifdef LEGACY_FLAC
0130 FLAC__SeekableStreamDecoderReadStatus K3bFLACDecoder::Private::read_callback(FLAC__byte buffer[],                                                                             unsigned *bytes) {
0131     long retval =  file->read((char *)buffer, (*bytes));
0132     if(-1 == retval) {
0133         return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
0134     } else {
0135         (*bytes) = retval;
0136         return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
0137     }
0138 }
0139 #else
0140 FLAC__StreamDecoderReadStatus K3bFLACDecoder::Private::read_callback(FLAC__byte buffer[],                                                                             size_t *bytes) {
0141     long retval =  file->read((char *)buffer, (*bytes));
0142     if(-1 == retval) {
0143         return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
0144     } else {
0145         (*bytes) = retval;
0146         return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
0147     }
0148 }
0149 #endif
0150 
0151 #ifdef LEGACY_FLAC
0152 FLAC__SeekableStreamDecoderSeekStatus
0153 K3bFLACDecoder::Private::seek_callback(FLAC__uint64 absolute_byte_offset) {
0154     if(!file->seek(absolute_byte_offset))
0155         return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
0156     else
0157         return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
0158 }
0159 #else
0160 FLAC__StreamDecoderSeekStatus
0161 K3bFLACDecoder::Private::seek_callback(FLAC__uint64 absolute_byte_offset) {
0162     if(file->seek(absolute_byte_offset) == false)
0163         return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
0164     else
0165         return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
0166 }
0167 #endif
0168 
0169 #ifdef LEGACY_FLAC
0170 FLAC__SeekableStreamDecoderTellStatus
0171 K3bFLACDecoder::Private::tell_callback(FLAC__uint64 *absolute_byte_offset) {
0172     (*absolute_byte_offset) = file->pos();
0173     return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
0174 }
0175 #else
0176 FLAC__StreamDecoderTellStatus
0177 K3bFLACDecoder::Private::tell_callback(FLAC__uint64 *absolute_byte_offset) {
0178     (*absolute_byte_offset) = file->pos();
0179     return FLAC__STREAM_DECODER_TELL_STATUS_OK;
0180 }
0181 #endif
0182 
0183 #ifdef LEGACY_FLAC
0184 FLAC__SeekableStreamDecoderLengthStatus
0185 K3bFLACDecoder::Private::length_callback(FLAC__uint64 *stream_length) {
0186     (*stream_length) = file->size();
0187     return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
0188 }
0189 #else
0190 FLAC__StreamDecoderLengthStatus
0191 K3bFLACDecoder::Private::length_callback(FLAC__uint64 *stream_length) {
0192     (*stream_length) = file->size();
0193     return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
0194 }
0195 #endif
0196 
0197 
0198 void K3bFLACDecoder::Private::metadata_callback(const FLAC__StreamMetadata *metadata) {
0199     switch (metadata->type) {
0200     case FLAC__METADATA_TYPE_STREAMINFO:
0201         channels = metadata->data.stream_info.channels;
0202         rate = metadata->data.stream_info.sample_rate;
0203         bitsPerSample = metadata->data.stream_info.bits_per_sample;
0204         samples = metadata->data.stream_info.total_samples;
0205         maxFramesize = metadata->data.stream_info.max_framesize;
0206         minFramesize = metadata->data.stream_info.min_framesize;
0207         maxBlocksize = metadata->data.stream_info.max_blocksize;
0208         minBlocksize = metadata->data.stream_info.min_blocksize;
0209         break;
0210     case FLAC__METADATA_TYPE_VORBIS_COMMENT:
0211         comments = new FLAC::Metadata::VorbisComment((FLAC__StreamMetadata *)metadata, true);
0212         break;
0213     default:
0214         break;
0215     }
0216 }
0217 
0218 FLAC__StreamDecoderWriteStatus K3bFLACDecoder::Private::write_callback(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) {
0219     unsigned i, j;
0220     // Note that in canDecode we made sure that the input is 1-16 bit stereo or mono.
0221     unsigned samples = frame->header.blocksize;
0222 
0223     for(i=0; i < samples; ++i) {
0224         // in FLAC channel 0 is left, 1 is right
0225         for(j=0; j < this->channels; ++j) {
0226             FLAC__int32 value = (buffer[j][i])<<(16 - frame->header.bits_per_sample);
0227             internalBuffer->putChar(value >> 8); // msb
0228             internalBuffer->putChar(value & 0xFF); // lsb
0229         }
0230     }
0231 
0232     // Rewind the buffer so the decode method will take data from the beginning.
0233     internalBuffer->seek(0);
0234     return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
0235 }
0236 
0237 K3bFLACDecoder::K3bFLACDecoder( QObject* parent  )
0238     : K3b::AudioDecoder( parent)
0239 {
0240     d = 0;
0241 }
0242 
0243 
0244 K3bFLACDecoder::~K3bFLACDecoder()
0245 {
0246     delete d;
0247 }
0248 
0249 void K3bFLACDecoder::cleanup()
0250 {
0251     if (d) {
0252         d->cleanup();
0253         d->open(new QFile(filename()));
0254     }
0255     else
0256         d = new Private(new QFile(filename()));
0257 }
0258 
0259 bool K3bFLACDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch )
0260 {
0261     cleanup();
0262 
0263     frames = (unsigned long)ceil((d->samples * 75.0)/d->rate);
0264     samplerate = d->rate;
0265     ch = d->channels;
0266 
0267     // add meta info
0268     if( d->comments != 0 ) {
0269         qDebug() << "(K3bFLACDecoder) unpacking Vorbis tags";
0270         for( unsigned int i = 0; i < d->comments->get_num_comments(); ++i ) {
0271             QString key = QString::fromUtf8( d->comments->get_comment(i).get_field_name(),
0272                                              d->comments->get_comment(i).get_field_name_length() );
0273             QString value = QString::fromUtf8( d->comments->get_comment(i).get_field_value(),
0274                                                d->comments->get_comment(i).get_field_value_length() );
0275 
0276             if( key.toUpper() == "TITLE" )
0277                 addMetaInfo( META_TITLE, value );
0278             else if( key.toUpper() == "ARTIST" )
0279                 addMetaInfo( META_ARTIST, value );
0280             else if( key.toUpper() == "DESCRIPTION" )
0281                 addMetaInfo( META_COMMENT, value );
0282         }
0283     }
0284 #ifdef ENABLE_TAGLIB
0285     if ((d->comments == 0) || (d->comments->get_num_comments() == 0)) {
0286         // no Vorbis comments, check for ID3 tags
0287         qDebug() << "(K3bFLACDecoder) using taglib to read tag";
0288         TagLib::FLAC::File f( QFile::encodeName(filename()) );
0289         if( f.isOpen() ) {
0290             addMetaInfo( META_TITLE, TStringToQString( f.tag()->title() ) );
0291             addMetaInfo( META_ARTIST, TStringToQString( f.tag()->artist() ) );
0292             addMetaInfo( META_COMMENT, TStringToQString( f.tag()->comment() ) );
0293         }
0294     }
0295 #endif
0296 
0297     return true;
0298 }
0299 
0300 
0301 bool K3bFLACDecoder::initDecoderInternal()
0302 {
0303     cleanup();
0304 
0305     return true;
0306 }
0307 
0308 
0309 int K3bFLACDecoder::decodeInternal( char* _data, int maxLen )
0310 {
0311     int bytesToCopy;
0312     int bytesCopied;
0313     int bytesAvailable;
0314 
0315 #ifdef LEGACY_FLAC
0316     if(d->internalBuffer->size() == 0) {
0317         // want more data
0318         switch(d->get_state()) {
0319         case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM:
0320             d->finish();
0321             break;
0322         case FLAC__SEEKABLE_STREAM_DECODER_OK:
0323             if(! d->process_single())
0324                 return -1;
0325             break;
0326         default:
0327             return -1;
0328         }
0329     }
0330 #else
0331     if(d->internalBuffer->size() == 0) {
0332         // want more data
0333         if(d->get_state() == FLAC__STREAM_DECODER_END_OF_STREAM)
0334             d->finish();
0335         else if(d->get_state() < FLAC__STREAM_DECODER_END_OF_STREAM) {
0336             if(! d->process_single())
0337                 return -1;
0338         }
0339         else
0340             return -1;
0341     }
0342 #endif
0343 
0344     bytesAvailable = d->internalBuffer->size() - d->internalBuffer->pos();
0345     bytesToCopy = qMin(maxLen, bytesAvailable);
0346     bytesCopied = (int)d->internalBuffer->read(_data, bytesToCopy);
0347 
0348     if(bytesCopied == bytesAvailable) {
0349         // reset the buffer
0350         d->internalBuffer->close();
0351         d->internalBuffer->open(QIODevice::ReadWrite|QIODevice::Truncate);
0352     }
0353 
0354     return bytesCopied;
0355 }
0356 
0357 
0358 bool K3bFLACDecoder::seekInternal( const K3b::Msf& pos )
0359 {
0360     return d->seekToFrame(pos.totalFrames());
0361 }
0362 
0363 
0364 QString K3bFLACDecoder::fileType() const
0365 {
0366     return i18n("FLAC");
0367 }
0368 
0369 
0370 QStringList K3bFLACDecoder::supportedTechnicalInfos() const
0371 {
0372     return QString( i18n("Channels") + ';' +
0373                     i18n("Sampling Rate") + ';' +
0374                     i18n("Sample Size") ).split( ';' );
0375 }
0376 
0377 
0378 QString K3bFLACDecoder::technicalInfo( const QString& info ) const
0379 {
0380     if( d->comments != 0 ) {
0381         if( info == i18n("Vendor") )
0382 #ifdef FLAC_NEWER_THAN_1_1_1
0383             return QString::fromUtf8((char*)d->comments->get_vendor_string());
0384 #else
0385         return QString::fromUtf8(d->comments->get_vendor_string().get_field());
0386 #endif
0387         else if( info == i18n("Channels") )
0388             return QString::number(d->channels);
0389         else if( info == i18n("Sampling Rate") )
0390             return i18n("%1 Hz",d->rate);
0391         else if( info == i18n("Sample Size") )
0392             return i18np("1 bit","%1 bits",d->bitsPerSample);
0393     }
0394 
0395     return QString();
0396 }
0397 
0398 
0399 
0400 K3bFLACDecoderFactory::K3bFLACDecoderFactory( QObject* parent, const QVariantList& )
0401     : K3b::AudioDecoderFactory( parent )
0402 {
0403 }
0404 
0405 
0406 K3bFLACDecoderFactory::~K3bFLACDecoderFactory()
0407 {
0408 }
0409 
0410 
0411 K3b::AudioDecoder* K3bFLACDecoderFactory::createDecoder( QObject* parent) const
0412 {
0413     return new K3bFLACDecoder( parent );
0414 }
0415 
0416 
0417 bool K3bFLACDecoderFactory::canDecode( const QUrl& url )
0418 {
0419     // buffer large enough to read an ID3 tag header
0420     char buf[10];
0421 
0422     // Note: since file is created on the stack it will be closed automatically
0423     // by its destructor when this method (i.e. canDecode) returns.
0424     QFile file(url.toLocalFile());
0425 
0426     if(!file.open(QIODevice::ReadOnly)) {
0427         qDebug() << "(K3bFLACDecoder) Could not open file " << url.toLocalFile();
0428         return false;
0429     }
0430 
0431     // look for a fLaC magic number or ID3 tag header
0432     if(10 != file.read(buf, 10)) {
0433         qDebug() << "(K3bFLACDecorder) File " << url.toLocalFile()
0434                  << " is too small to be a FLAC file" << Qt::endl;
0435         return false;
0436     }
0437 
0438     if(0 == memcmp(buf, "ID3", 3)) {
0439         // Found ID3 tag, try and seek past it.
0440         qDebug() << "(K3bFLACDecorder) File " << url.toLocalFile() << ": found ID3 tag";
0441 
0442         // See www.id3.org for details of the header, note that the size field
0443         // unpacks to 7-bit bytes, then the +10 is for the header itself.
0444         int pos;
0445         pos = ((buf[6]<<21)|(buf[7]<<14)|(buf[8]<<7)|buf[9]) + 10;
0446 
0447         qDebug() << "(K3bFLACDecoder) " << url.toLocalFile() << ": seeking to "
0448                  << pos << Qt::endl;
0449         if(!file.seek(pos)) {
0450             qDebug() << "(K3bFLACDecoder) " << url.toLocalFile() << ": couldn't seek to "
0451                      << pos << Qt::endl;
0452             return false;
0453         }else{
0454             // seek was okay, try and read magic number into buf
0455             if(4 != file.read(buf, 4)) {
0456                 qDebug() << "(K3bFLACDecorder) File " << url.toLocalFile()
0457                          << " has ID3 tag but naught else!" << Qt::endl;
0458                 return false;
0459             }
0460         }
0461     }
0462 
0463     if(memcmp(buf, "fLaC", 4) != 0) {
0464         qDebug() << "(K3bFLACDecoder) " << url.toLocalFile() << ": not a FLAC file";
0465         return false;
0466     }
0467 
0468     FLAC::Metadata::StreamInfo info = FLAC::Metadata::StreamInfo();
0469     if (!FLAC::Metadata::get_streaminfo(url.toLocalFile().toLocal8Bit(), info)) {
0470         qDebug() << "(K3bFLACDecoder) " << url.toLocalFile() << ": get_streaminfo failed";
0471         return false;
0472     }
0473 
0474     if((info.get_channels() <= 2) &&
0475        (info.get_bits_per_sample() <= 16)) {
0476         return true;
0477     } else {
0478         qDebug() << "(K3bFLACDecoder) " << url.toLocalFile() << ": wrong format:" << Qt::endl
0479                  << "                channels:    "
0480                  << QString::number(info.get_channels()) << Qt::endl
0481                  << "                samplerate:  "
0482                  << QString::number(info.get_sample_rate()) << Qt::endl
0483                  << "                bits/sample: "
0484                  << QString::number(info.get_bits_per_sample()) << Qt::endl;
0485         return false;
0486     }
0487 }
0488 
0489 #include "k3bflacdecoder.moc"
0490 
0491 #include "moc_k3bflacdecoder.cpp"