File indexing completed on 2024-07-14 08:19:23

0001 /*
0002     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #include "k3boggvorbisdecoder.h"
0007 #include "k3bplugin_i18n.h"
0008 
0009 #include <config-k3b.h>
0010 
0011 #include <QDebug>
0012 #include <QFile>
0013 #include <QStringList>
0014 
0015 #include <stdio.h>
0016 #include <stdlib.h>
0017 #include <vorbis/codec.h>
0018 #include <vorbis/vorbisfile.h>
0019 
0020 K_PLUGIN_CLASS_WITH_JSON(K3bOggVorbisDecoderFactory, "k3boggvorbisdecoder.json")
0021 
0022 class K3bOggVorbisDecoder::Private
0023 {
0024 public:
0025     Private()
0026         : vInfo(0),
0027           vComment(0),
0028           isOpen(false) {
0029     }
0030 
0031     OggVorbis_File oggVorbisFile;
0032     vorbis_info* vInfo;
0033     vorbis_comment* vComment;
0034     bool isOpen;
0035 };
0036 
0037 
0038 K3bOggVorbisDecoder::K3bOggVorbisDecoder( QObject* parent )
0039     : K3b::AudioDecoder( parent )
0040 {
0041     d = new Private();
0042 }
0043 
0044 
0045 K3bOggVorbisDecoder::~K3bOggVorbisDecoder()
0046 {
0047     delete d;
0048 }
0049 
0050 
0051 bool K3bOggVorbisDecoder::openOggVorbisFile()
0052 {
0053     if( !d->isOpen ) {
0054         FILE* file = fopen( QFile::encodeName(filename()), "r" );
0055         if( !file ) {
0056             qDebug() << "(K3bOggVorbisDecoder) Could not open file " << filename();
0057             return false;
0058         }
0059         else if( ov_open( file, &d->oggVorbisFile, 0, 0 ) ) {
0060             qDebug() << "(K3bOggVorbisDecoder) " << filename()
0061                      << " seems not to to be an ogg vorbis file." << Qt::endl;
0062             fclose( file );
0063             return false;
0064         }
0065     }
0066 
0067     d->isOpen = true;
0068     return true;
0069 }
0070 
0071 
0072 bool K3bOggVorbisDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch )
0073 {
0074     cleanup();
0075 
0076     if( openOggVorbisFile() ) {
0077         // check length of track
0078         double seconds = ov_time_total( &d->oggVorbisFile, -1 );
0079         if( seconds == OV_EINVAL ) {
0080             qDebug() << "(K3bOggVorbisDecoder) Could not determine length of file " << filename();
0081             cleanup();
0082             return false;
0083         }
0084         else {
0085 
0086             d->vInfo = ov_info( &d->oggVorbisFile, -1 /* current bitstream */ );
0087             d->vComment = ov_comment( &d->oggVorbisFile, -1 );
0088 
0089             // add meta tags
0090             for( int i = 0; i < d->vComment->comments; ++i ) {
0091                 QString comment = QString::fromUtf8( d->vComment->user_comments[i] );
0092                 QStringList values = comment.split( '=' );
0093                 if( values.count() > 1 ) {
0094                     if( values[0].toLower() == "title" )
0095                         addMetaInfo( META_TITLE, values[1] );
0096                     else if( values[0].toLower() == "artist" )
0097                         addMetaInfo( META_ARTIST, values[1] );
0098                     else if( values[0].toLower() == "description" )
0099                         addMetaInfo( META_COMMENT, values[1] );
0100                 }
0101             }
0102 
0103 
0104             // add technical infos
0105             addTechnicalInfo( i18n("Version"), QString::number(d->vInfo->version) );
0106             addTechnicalInfo( i18n("Channels"), QString::number(d->vInfo->channels) );
0107             addTechnicalInfo( i18n("Sampling Rate"), i18n("%1 Hz",d->vInfo->rate) );
0108             if( d->vInfo->bitrate_upper > 0 )
0109                 addTechnicalInfo( i18n("Bitrate Upper"), i18n( "%1 bps" ,d->vInfo->bitrate_upper) );
0110             if( d->vInfo->bitrate_nominal > 0 )
0111                 addTechnicalInfo( i18n("Bitrate Nominal"), i18n( "%1 bps" ,d->vInfo->bitrate_nominal) );
0112             if( d->vInfo->bitrate_lower > 0 )
0113                 addTechnicalInfo( i18n("Bitrate Lower"), i18n( "%1 bps",d->vInfo->bitrate_lower) );
0114 
0115             frames = K3b::Msf::fromSeconds(seconds);
0116             samplerate = d->vInfo->rate;
0117             ch = d->vInfo->channels;
0118 
0119             cleanup();
0120 
0121             return true;
0122         }
0123     }
0124     else
0125         return false;
0126 }
0127 
0128 
0129 bool K3bOggVorbisDecoder::initDecoderInternal()
0130 {
0131     cleanup();
0132     return openOggVorbisFile();
0133 }
0134 
0135 
0136 int K3bOggVorbisDecoder::decodeInternal( char* data, int maxLen )
0137 {
0138     int bitStream = 0;
0139     long bytesRead = ov_read( &d->oggVorbisFile,
0140                               data,
0141                               maxLen,  // max length to be read
0142                               1,                   // big endian
0143                               2,                   // word size: 16-bit samples
0144                               1,                   // signed
0145                               &bitStream );        // current bitstream
0146 
0147     if( bitStream != 0 ) {
0148         qDebug() << "(K3bOggVorbisDecoder) bitstream != 0. Multiple bitstreams not supported.";
0149         return -1;
0150     }
0151 
0152     else if( bytesRead == OV_HOLE ) {
0153         qDebug() << "(K3bOggVorbisDecoder) OV_HOLE";
0154         // recursive new try
0155         return decodeInternal( data, maxLen );
0156     }
0157 
0158     else if( bytesRead < 0 ) {
0159         qDebug() << "(K3bOggVorbisDecoder) Error: " << bytesRead;
0160         return -1;
0161     }
0162 
0163     else if( bytesRead == 0 ) {
0164         qDebug() << "(K3bOggVorbisDecoder) successfully finished decoding.";
0165         return 0;
0166     }
0167 
0168     else {
0169         return bytesRead;
0170     }
0171 }
0172 
0173 
0174 void K3bOggVorbisDecoder::cleanup()
0175 {
0176     if( d->isOpen )
0177         ov_clear( &d->oggVorbisFile );
0178     d->isOpen = false;
0179     d->vComment = 0;
0180     d->vInfo = 0;
0181 }
0182 
0183 
0184 bool K3bOggVorbisDecoder::seekInternal( const K3b::Msf& pos )
0185 {
0186     return ( ov_pcm_seek( &d->oggVorbisFile, pos.pcmSamples() ) == 0 );
0187 }
0188 
0189 
0190 QString K3bOggVorbisDecoder::fileType() const
0191 {
0192     return i18n("Ogg-Vorbis");
0193 }
0194 
0195 
0196 K3bOggVorbisDecoderFactory::K3bOggVorbisDecoderFactory( QObject* parent, const QVariantList& )
0197     : K3b::AudioDecoderFactory( parent )
0198 {
0199 }
0200 
0201 
0202 K3bOggVorbisDecoderFactory::~K3bOggVorbisDecoderFactory()
0203 {
0204 }
0205 
0206 
0207 K3b::AudioDecoder* K3bOggVorbisDecoderFactory::createDecoder( QObject* parent ) const
0208 {
0209     return new K3bOggVorbisDecoder( parent );
0210 }
0211 
0212 
0213 bool K3bOggVorbisDecoderFactory::canDecode( const QUrl& url )
0214 {
0215     FILE* file = fopen( QFile::encodeName(url.toLocalFile()), "r" );
0216     if( !file ) {
0217         qDebug() << "(K3bOggVorbisDecoder) Could not open file " << url.toLocalFile();
0218         return false;
0219     }
0220 
0221     OggVorbis_File of;
0222 
0223     if( ov_open( file, &of, 0, 0 ) ) {
0224         fclose( file );
0225         qDebug() << "(K3bOggVorbisDecoder) not an Ogg-Vorbis file: " << url.toLocalFile();
0226         return false;
0227     }
0228 
0229     ov_clear( &of );
0230 
0231     return true;
0232 }
0233 
0234 
0235 #include "k3boggvorbisdecoder.moc"
0236 
0237 #include "moc_k3boggvorbisdecoder.cpp"