File indexing completed on 2025-02-09 05:41:16
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"