diff options
| author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-03 02:15:56 +0000 | 
|---|---|---|
| committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-03 02:15:56 +0000 | 
| commit | 50b48aec6ddd451a6d1709c0942477b503457663 (patch) | |
| tree | a9ece53ec06fd0a2819de7a2a6de997193566626 /plugins/decoder | |
| download | k3b-50b48aec6ddd451a6d1709c0942477b503457663.tar.gz k3b-50b48aec6ddd451a6d1709c0942477b503457663.zip  | |
Added abandoned KDE3 version of K3B
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/k3b@1084400 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'plugins/decoder')
50 files changed, 4558 insertions, 0 deletions
diff --git a/plugins/decoder/Makefile.am b/plugins/decoder/Makefile.am new file mode 100644 index 0000000..1b4eafa --- /dev/null +++ b/plugins/decoder/Makefile.am @@ -0,0 +1,26 @@ + +if include_OGG +DECOGGDIR = ogg +endif + +if include_MP3 +DECMP3DIR = mp3 +endif + +if include_FLAC +DECFLACDIR = flac +endif + +if include_AIFF +DECAIFFDIR = libsndfile +endif + +if include_FFMPEG +FFMPEGDIR = ffmpeg +endif + +if include_MPC +MPCDIR = musepack +endif + +SUBDIRS = wave $(DECOGGDIR) $(DECMP3DIR) $(DECFLACDIR) $(DECAIFFDIR) $(FFMPEGDIR) $(MPCDIR) diff --git a/plugins/decoder/ffmpeg/Makefile.am b/plugins/decoder/ffmpeg/Makefile.am new file mode 100644 index 0000000..b4c46e2 --- /dev/null +++ b/plugins/decoder/ffmpeg/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice $(all_includes) +KDE_CXXFLAGS = -D__STDC_CONSTANT_MACROS + +kde_module_LTLIBRARIES = libk3bffmpegdecoder.la + +libk3bffmpegdecoder_la_SOURCES = k3bffmpegdecoder.cpp k3bffmpegwrapper.cpp + +libk3bffmpegdecoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDEUI) -lavcodec -lavformat +libk3bffmpegdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bffmpegdecoder.plugin + +METASOURCES = AUTO + diff --git a/plugins/decoder/ffmpeg/configure.in.bot b/plugins/decoder/ffmpeg/configure.in.bot new file mode 100644 index 0000000..3d24645 --- /dev/null +++ b/plugins/decoder/ffmpeg/configure.in.bot @@ -0,0 +1,25 @@ +echo "" + +echo "K3b - FFMpeg decoder plugin (decodes wma and others):" +if test  x$have_ffmpeg = xyes; then +        echo "K3b -                                        yes" +	if test x$enable_ffmpeg_all_codecs = xyes; then +		echo "K3b -     WARNING: You enabled all codecs in the ffmpeg decoder plugin." +		echo "K3b -              Be aware that most are not tested and track lengths" +		echo "K3b -              will be wrong in many cases." +	fi +else +        echo "K3b -                                         no" +if test "$ac_cv_use_ffmpeg" = "yes"; then +	if test "$ffmpeg_compiles" = "yes"; then +		echo "K3b -     You are missing the ffmpeg libraries." +		echo "K3b -     Make sure ffmpeg has been configured as a" +		echo "K3b -     shared library (which is not the default)." +	else +		echo "K3b -     You are missing the ffmpeg headers and libraries" +		echo "K3b -     version 0.4.9 or higher." +	fi +	echo "K3b -     The ffmpeg audio decoding plugin (decodes wma and" +	echo "K3b -     others) won't be compiled." +fi +fi diff --git a/plugins/decoder/ffmpeg/configure.in.in b/plugins/decoder/ffmpeg/configure.in.in new file mode 100644 index 0000000..84b345a --- /dev/null +++ b/plugins/decoder/ffmpeg/configure.in.in @@ -0,0 +1,68 @@ +dnl --------------- FFMPEG CHECK --------------------------------- + +AC_ARG_WITH( +	ffmpeg,  +	AS_HELP_STRING( +		[--without-ffmpeg],  +		[build K3b without ffmpeg audio decoder support (default=no)]), +	[ac_cv_use_ffmpeg=$withval],  +	[ac_cv_use_ffmpeg=yes] +) + +# +# The ffmpeg decoder plugin needs ffmpeg 0.4.9 or higher +# +have_ffmpeg=no +if test "$ac_cv_use_ffmpeg" = "yes"; then +	k3b_cxxflags_save="$CXXFLAGS" +	CXXFLAGS="$CXXFLAGS -D__STDC_CONSTANT_MACROS" +	AC_MSG_CHECKING(for ffmpeg >= 0.4.9) +	AC_LANG_SAVE +	AC_LANG_CPLUSPLUS +	AC_COMPILE_IFELSE(  +		extern "C" { +		#include <libavformat/avformat.h> +		#include <libavcodec/avcodec.h> +		} + +		int main() { +		  AVFormatContext* fc = 0; +		  AVPacket* p = 0; +		  av_register_all(); +		  return av_read_frame( fc, p ); +		}, +	[ffmpeg_compiles=yes], [ffmpeg_compiles=no] ) +	OLD_LIBS=$LIBS +	LIBS="-lavformat -lavcodec $LIBS" +	AC_LINK_IFELSE(  +		extern "C" { +		#include <libavformat/avformat.h> +		#include <libavcodec/avcodec.h> +		} + +		int main() { +		  AVFormatContext* fc = 0; +		  AVPacket* p = 0; +		  av_register_all(); +		  return av_read_frame( fc, p ); +		}, +	[ffmpeg_links=yes], [ffmpeg_links=no] ) +	AC_LANG_RESTORE +	LIBS=$OLD_LIBS +	have_ffmpeg=$ffmpeg_links +	AC_MSG_RESULT($have_ffmpeg) +	CXXFLAGS=$k3b_cxxflags_save +fi +AM_CONDITIONAL(include_FFMPEG, [test x$have_ffmpeg = xyes]) + +dnl --------------- FFMPEG CHECK END ------------------------------ + +AC_ARG_ENABLE( +	ffmpeg-all-codecs,  +	AS_HELP_STRING( +		[--enable-ffmpeg-all-codecs],  +		[Build K3b's ffmeg decoder plugin with all audio codecs enabled (default=disabled)]), +	[AC_DEFINE(K3B_FFMPEG_ALL_CODECS, 1, [Defined if all ffmpeg codecs should be allowed]) +	 enable_ffmpeg_all_codecs=yes],  +	[enable_ffmpeg_all_codecs=no] +) diff --git a/plugins/decoder/ffmpeg/k3bffmpegdecoder.cpp b/plugins/decoder/ffmpeg/k3bffmpegdecoder.cpp new file mode 100644 index 0000000..fd47c52 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegdecoder.cpp @@ -0,0 +1,155 @@ +/*  + * + * $Id: k3bffmpegdecoder.cpp 641798 2007-03-12 16:07:10Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bffmpegdecoder.h" +#include "k3bffmpegwrapper.h" + +#include <kdebug.h> +#include <k3bpluginfactory.h> + +extern "C" { +#include <libavcodec/avcodec.h> +} + +#include <math.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3bffmpegdecoder, K3bPluginFactory<K3bFFMpegDecoderFactory>( "k3bffmpegdecoder" ) ) + + +K3bFFMpegDecoderFactory::K3bFFMpegDecoderFactory( QObject* parent, const char* name ) +  : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bFFMpegDecoderFactory::~K3bFFMpegDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bFFMpegDecoderFactory::createDecoder( QObject* parent,  +							 const char* name ) const +{ +  return new K3bFFMpegDecoder( parent, name ); +} + + +bool K3bFFMpegDecoderFactory::canDecode( const KURL& url ) +{ +  K3bFFMpegFile* file = K3bFFMpegWrapper::instance()->open( url.path() ); +  if( file ) { +    delete file; +    return true; +  } +  else { +    return false; +  } +} + + + + + + +K3bFFMpegDecoder::K3bFFMpegDecoder( QObject* parent, const char* name ) +  : K3bAudioDecoder( parent, name ), +    m_file(0) +{ +} + + +K3bFFMpegDecoder::~K3bFFMpegDecoder() +{ +} + + +QString K3bFFMpegDecoder::fileType() const +{ +  return m_type; +} + + +bool K3bFFMpegDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ +  m_file = K3bFFMpegWrapper::instance()->open( filename() ); +  if( m_file ) { + +    // TODO: call addTechnicalInfo + +    addMetaInfo( META_TITLE, m_file->title() ); +    addMetaInfo( META_ARTIST, m_file->author() ); +    addMetaInfo( META_COMMENT, m_file->comment() ); + +    samplerate = m_file->sampleRate(); +    ch = m_file->channels(); +    m_type = m_file->typeComment(); +    frames = m_file->length(); + +    // ffmpeg's length information is not reliable at all +    // so we have to decode the whole file in order to get the correct length +//     char buffer[10*2048]; +//     int len = 0; +//     unsigned long long bytes = 0; +//     while( ( len = m_file->read( buffer, 10*2048 ) ) > 0 ) +//       bytes += len; +     +//     frames = (unsigned long)ceil((double)bytes/2048.0); + +    // cleanup; +    delete m_file; +    m_file = 0; + +    return true; +  } +  else +    return false; +} + + +bool K3bFFMpegDecoder::initDecoderInternal() +{ +  if( !m_file ) +    m_file = K3bFFMpegWrapper::instance()->open( filename() ); + +  return (m_file != 0); +} + + +void K3bFFMpegDecoder::cleanup() +{ +  delete m_file; +  m_file = 0; +} + + +bool K3bFFMpegDecoder::seekInternal( const K3b::Msf& msf ) +{ +  if( msf == 0 ) +    return initDecoderInternal(); +  else +    return m_file->seek( msf ); +} + + +int K3bFFMpegDecoder::decodeInternal( char* _data, int maxLen ) +{ +  return m_file->read( _data, maxLen ); +} + + +#include "k3bffmpegdecoder.moc" diff --git a/plugins/decoder/ffmpeg/k3bffmpegdecoder.h b/plugins/decoder/ffmpeg/k3bffmpegdecoder.h new file mode 100644 index 0000000..1c21827 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegdecoder.h @@ -0,0 +1,67 @@ +/*  + * + * $Id: k3bffmpegdecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FFMPEG_DECODER_H_ +#define _K3B_FFMPEG_DECODER_H_ + +#include <k3baudiodecoder.h> + +class K3bFFMpegFile; + + +class K3bFFMpegDecoderFactory : public K3bAudioDecoderFactory +{ +  Q_OBJECT + + public: +  K3bFFMpegDecoderFactory( QObject* parent = 0, const char* name = 0 ); +  ~K3bFFMpegDecoderFactory(); + +  bool canDecode( const KURL& filename ); + +  int pluginSystemVersion() const { return 3; } + +  bool multiFormatDecoder() const { return true; } + +  K3bAudioDecoder* createDecoder( QObject* parent = 0,  +				  const char* name = 0 ) const; +}; + + +class K3bFFMpegDecoder : public K3bAudioDecoder +{ +  Q_OBJECT + + public: +  K3bFFMpegDecoder( QObject* parent = 0, const char* name = 0 ); +  ~K3bFFMpegDecoder(); + +  QString fileType() const; + +  void cleanup(); + + protected: +  bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); +  bool initDecoderInternal(); +  bool seekInternal( const K3b::Msf& ); + +  int decodeInternal( char* _data, int maxLen ); + + private: +  K3bFFMpegFile* m_file; +  QString m_type; +}; + +#endif diff --git a/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin b/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin new file mode 100644 index 0000000..3592388 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegdecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bffmpegdecoder +Group=AudioDecoder +Name=K3b FFMpeg Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=0.9.1 +Comment=Decoding module to decode wma files +License=GPL diff --git a/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp b/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp new file mode 100644 index 0000000..514fd67 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp @@ -0,0 +1,375 @@ +/*  + * + * $Id: k3bffmpegwrapper.cpp 641819 2007-03-12 17:29:23Z trueg $ + * Copyright (C) 2004-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bffmpegwrapper.h" + +extern "C" { +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.h> +} + +#include <string.h> + +#include <klocale.h> + + +#if LIBAVFORMAT_BUILD < 4629 +#define FFMPEG_BUILD_PRE_4629 +#endif + + +K3bFFMpegWrapper* K3bFFMpegWrapper::s_instance = 0; + + +class K3bFFMpegFile::Private +{ +public: +  AVFormatContext* formatContext; +  AVCodec* codec; + +  K3b::Msf length; + +  // for decoding +  char outputBuffer[AVCODEC_MAX_AUDIO_FRAME_SIZE]; +  char* outputBufferPos; +  int outputBufferSize; +  AVPacket packet; +  Q_UINT8* packetData; +  int packetSize; +}; + + +K3bFFMpegFile::K3bFFMpegFile( const QString& filename ) +  : m_filename(filename) +{ +  d = new Private; +  d->formatContext = 0; +  d->codec = 0; +} + + +K3bFFMpegFile::~K3bFFMpegFile() +{ +  close(); +  delete d; +} + + +bool K3bFFMpegFile::open() +{ +  close(); + +  // open the file +  int err = av_open_input_file( &d->formatContext, m_filename.local8Bit(), 0, 0, 0 ); +  if( err < 0 ) { +    kdDebug() << "(K3bFFMpegFile) unable to open " << m_filename << " with error " << err << endl; +    return false; +  } + +  // analyze the streams +  av_find_stream_info( d->formatContext ); + +  // we only handle files containing one audio stream +  if( d->formatContext->nb_streams != 1 ) { +    kdDebug() << "(K3bFFMpegFile) more than one stream in " << m_filename << endl; +    return false; +  } + +  // urgh... ugly +#ifdef FFMPEG_BUILD_PRE_4629 +  AVCodecContext* codecContext =  &d->formatContext->streams[0]->codec; +#else +  AVCodecContext* codecContext =  d->formatContext->streams[0]->codec; +#endif +  if( codecContext->codec_type != CODEC_TYPE_AUDIO ) { +    kdDebug() << "(K3bFFMpegFile) not a simple audio stream: " << m_filename << endl; +    return false; +  } + +  // get the codec +  d->codec = avcodec_find_decoder(codecContext->codec_id); +  if( !d->codec ) { +    kdDebug() << "(K3bFFMpegFile) no codec found for " << m_filename << endl; +    return false; +  } + +  // open the codec on our context +  kdDebug() << "(K3bFFMpegFile) found codec for " << m_filename << endl; +  if( avcodec_open( codecContext, d->codec ) < 0 ) { +    kdDebug() << "(K3bFFMpegDecoderFactory) could not open codec." << endl; +    return false; +  } + +  // determine the length of the stream +  d->length = K3b::Msf::fromSeconds( (double)d->formatContext->duration / (double)AV_TIME_BASE ); + +  if( d->length == 0 ) { +    kdDebug() << "(K3bFFMpegDecoderFactory) invalid length." << endl; +    return false; +  } + +  // dump some debugging info +  dump_format( d->formatContext, 0, m_filename.local8Bit(), 0 ); + +  return true; +} + + +void K3bFFMpegFile::close() +{ +  d->outputBufferSize = 0; +  d->packetSize = 0; +  d->packetData = 0; + +  if( d->codec ) { +#ifdef FFMPEG_BUILD_PRE_4629 +    avcodec_close( &d->formatContext->streams[0]->codec ); +#else +    avcodec_close( d->formatContext->streams[0]->codec ); +#endif +    d->codec = 0; +  } + +  if( d->formatContext ) { +    av_close_input_file( d->formatContext ); +    d->formatContext = 0; +  } +} + + +K3b::Msf K3bFFMpegFile::length() const +{ +  return d->length; +} + + +int K3bFFMpegFile::sampleRate() const +{ +#ifdef FFMPEG_BUILD_PRE_4629 +  return d->formatContext->streams[0]->codec.sample_rate; +#else +  return d->formatContext->streams[0]->codec->sample_rate; +#endif +} + + +int K3bFFMpegFile::channels() const +{ +#ifdef FFMPEG_BUILD_PRE_4629 +  return d->formatContext->streams[0]->codec.channels; +#else +  return d->formatContext->streams[0]->codec->channels; +#endif +} + + +int K3bFFMpegFile::type() const +{ +#ifdef FFMPEG_BUILD_PRE_4629 +  return d->formatContext->streams[0]->codec.codec_id; +#else +  return d->formatContext->streams[0]->codec->codec_id; +#endif +} + + +QString K3bFFMpegFile::typeComment() const +{ +  switch( type() ) { +  case CODEC_ID_WMAV1: +    return i18n("Windows Media v1"); +  case CODEC_ID_WMAV2: +    return i18n("Windows Media v2"); +  case CODEC_ID_MP3: +    return i18n("MPEG 1 Layer III"); +  case CODEC_ID_AAC: +    return i18n("Advanced Audio Coding (AAC)"); +  default: +    return QString::fromLocal8Bit( d->codec->name ); +  } +} + + +QString K3bFFMpegFile::title() const +{ +  // FIXME: is this UTF8 or something?? +  if( d->formatContext->title[0] != '\0' ) +    return QString::fromLocal8Bit( d->formatContext->title ); +  else +    return QString::null; +} + + +QString K3bFFMpegFile::author() const +{ +  // FIXME: is this UTF8 or something?? +  if( d->formatContext->author[0] != '\0' ) +    return QString::fromLocal8Bit( d->formatContext->author ); +  else +    return QString::null; +} + + +QString K3bFFMpegFile::comment() const +{ +  // FIXME: is this UTF8 or something?? +  if( d->formatContext->comment[0] != '\0' ) +    return QString::fromLocal8Bit( d->formatContext->comment ); +  else +    return QString::null; +} + + +int K3bFFMpegFile::read( char* buf, int bufLen ) +{ +  if( fillOutputBuffer() > 0 ) { +    int len = QMIN(bufLen, d->outputBufferSize); +    ::memcpy( buf, d->outputBufferPos, len ); + +    // TODO: only swap if needed +    for( int i = 0; i < len-1; i+=2 ) { +      char a = buf[i]; +      buf[i] = buf[i+1]; +      buf[i+1] = a; +    } + +    d->outputBufferPos += len; +    d->outputBufferSize -= len; +    return len; +  } +  else +    return 0; +} + + +// fill d->packetData with data to decode +int K3bFFMpegFile::readPacket() +{ +  if( d->packetSize <= 0 ) { +    av_init_packet( &d->packet ); + +    if( av_read_frame( d->formatContext, &d->packet ) < 0 ) { +      return 0; +    } + +    d->packetSize = d->packet.size; +    d->packetData = d->packet.data; +  } + +  return d->packetSize; +} + + +// decode data in d->packetData and fill d->outputBuffer +int K3bFFMpegFile::fillOutputBuffer() +{ +  // decode if the output buffer is empty +  if( d->outputBufferSize <= 0 ) { + +    // make sure we have data to decode +    if( readPacket() == 0 ) { +      return 0; +    } + +    d->outputBufferPos = d->outputBuffer; + +#ifdef FFMPEG_BUILD_PRE_4629 +    int len = avcodec_decode_audio2( &d->formatContext->streams[0]->codec, +#else +    int len = avcodec_decode_audio2( d->formatContext->streams[0]->codec, +#endif +				    (short*)d->outputBuffer, &d->outputBufferSize, +				    d->packetData, d->packetSize ); + +    d->packetSize -= len; +    d->packetData += len; + +    if( d->packetSize <= 0 ) +      av_free_packet( &d->packet ); +  } + +  // if it is still empty try again +  if( d->outputBufferSize <= 0 ) +    return fillOutputBuffer(); +  else +    return d->outputBufferSize; +} + + +bool K3bFFMpegFile::seek( const K3b::Msf& msf ) +{ +  d->outputBufferSize = 0; +  d->packetSize = 0; + +  double seconds = (double)msf.totalFrames()/75.0; +  Q_UINT64 timestamp = (Q_UINT64)(seconds * (double)AV_TIME_BASE); + +  // FIXME: do we really need the start_time and why? +#if LIBAVFORMAT_BUILD >= 4619 +  return ( av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time, 0 ) >= 0 ); +#else +  return ( av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time ) >= 0 ); +#endif +} + + + + + + +K3bFFMpegWrapper::K3bFFMpegWrapper() +{ +  av_register_all(); +} + + +K3bFFMpegWrapper::~K3bFFMpegWrapper() +{ +  s_instance = 0; +} + + +K3bFFMpegWrapper* K3bFFMpegWrapper::instance() +{ +  if( !s_instance ) { +    s_instance = new K3bFFMpegWrapper(); +  } + +  return s_instance; +} + + +K3bFFMpegFile* K3bFFMpegWrapper::open( const QString& filename ) const +{ +  K3bFFMpegFile* file = new K3bFFMpegFile( filename ); +  if( file->open() ) { +#ifndef K3B_FFMPEG_ALL_CODECS +    // +    // only allow tested formats. ffmpeg seems not to be too reliable with every format. +    // mp3 being one of them sadly. Most importantly: allow the libsndfile decoder to do +    // its thing. +    // +    if( file->type() == CODEC_ID_WMAV1 || +	file->type() == CODEC_ID_WMAV2 || +	file->type() == CODEC_ID_AAC ) +#endif +      return file; +  } + +  delete file; +  return 0; +} diff --git a/plugins/decoder/ffmpeg/k3bffmpegwrapper.h b/plugins/decoder/ffmpeg/k3bffmpegwrapper.h new file mode 100644 index 0000000..63b5f58 --- /dev/null +++ b/plugins/decoder/ffmpeg/k3bffmpegwrapper.h @@ -0,0 +1,85 @@ +/*  + * + * $Id: k3bffmpegwrapper.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_FFMPEG_WRAPPER_H_ +#define _K3B_FFMPEG_WRAPPER_H_ + +#include <k3bmsf.h> + + + +/** + * Create with K3bFFMpegWrapper::open + */ +class K3bFFMpegFile +{ +  friend class K3bFFMpegWrapper; + + public: +  ~K3bFFMpegFile(); + +  const QString& filename() const { return m_filename; } + +  bool open(); +  void close(); + +  K3b::Msf length() const; +  int sampleRate() const; +  int channels() const; + +  /** +   * ffmpeg internal enumeration +   */ +  int type() const; +  QString typeComment() const; + +  QString title() const; +  QString author() const; +  QString comment() const; + +  int read( char* buf, int bufLen ); +  bool seek( const K3b::Msf& ); + + private: +  K3bFFMpegFile( const QString& filename ); +  int readPacket(); +  int fillOutputBuffer(); + +  QString m_filename; + +  class Private; +  Private* d; +}; + + +class K3bFFMpegWrapper +{ + public: +  ~K3bFFMpegWrapper(); + +  /** +   * returns 0 on failure. +   */ +  K3bFFMpegFile* open( const QString& filename ) const; + +  static K3bFFMpegWrapper* instance(); + + private: +  K3bFFMpegWrapper(); + +  static K3bFFMpegWrapper* s_instance; +}; + +#endif diff --git a/plugins/decoder/flac/Makefile.am b/plugins/decoder/flac/Makefile.am new file mode 100644 index 0000000..bdcc4a3 --- /dev/null +++ b/plugins/decoder/flac/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice -I$(srcdir)/../../../libk3b/core $(taglib_includes) $(all_includes) + +kde_module_LTLIBRARIES = libk3bflacdecoder.la + +libk3bflacdecoder_la_SOURCES = k3bflacdecoder.cpp + +libk3bflacdecoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDEUI) -lFLAC++ -lFLAC $(taglib_libs)  +libk3bflacdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bflacdecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/flac/configure.in.bot b/plugins/decoder/flac/configure.in.bot new file mode 100644 index 0000000..f2d95a4 --- /dev/null +++ b/plugins/decoder/flac/configure.in.bot @@ -0,0 +1,13 @@ +echo "" + +if test x$have_flac = xyes; then +	echo "K3b - FLAC support:                          yes" +else +	echo "K3b - FLAC support:                           no" +if test "$ac_cv_use_flac" = "yes"; then +	if test "$have_flac" = "no"; then +		echo "K3b -     You are missing the FLAC++ headers and libraries." +		echo "K3b -     The FLAC decoding plugin won't be compiled." +	fi +fi +fi diff --git a/plugins/decoder/flac/configure.in.in b/plugins/decoder/flac/configure.in.in new file mode 100644 index 0000000..e6a3700 --- /dev/null +++ b/plugins/decoder/flac/configure.in.in @@ -0,0 +1,41 @@ +dnl === test for FLAC++ and FLAC - begin ==== +AC_ARG_WITH( +	flac,  +	AS_HELP_STRING([--without-flac], [build K3b without FLAC support (default=no)]),  +	[ac_cv_use_flac=$withval],  +	[ac_cv_use_flac=yes] +) + +have_flac=no +if test "$ac_cv_use_flac" = "yes"; then +  KDE_CHECK_HEADERS(FLAC++/decoder.h, [ +     AC_CHECK_LIB(FLAC,FLAC__stream_decoder_process_single, +	        have_flac=yes,[],$all_libraries)]) + +    AC_MSG_CHECKING(for libFLAC newer than 1.1.1) +    AC_CACHE_VAL(k3b_flac_new, +    [ +	AC_LANG_SAVE +	AC_LANG_CPLUSPLUS +	AC_TRY_COMPILE( +	[ +		#include <FLAC++/metadata.h> +	], [ +		FLAC::Metadata::VorbisComment* vc; +		vc->get_vendor_string().get_field(); +	], k3b_flac_new=no, k3b_flac_new=yes ) +	AC_LANG_RESTORE +    ]) +    AC_MSG_RESULT($k3b_flac_new) +    if test $k3b_flac_new = yes; then +	AC_DEFINE(FLAC_NEWER_THAN_1_1_1,  +		1, +		[Define to 1 if your flac library's version is newer than or equal to 1.1.2] +	) +    fi +else +    have_flac=no +fi + +AM_CONDITIONAL(include_FLAC, [test x$have_flac = xyes]) +dnl === test for FLAC++ and FLAC - end ==== diff --git a/plugins/decoder/flac/k3bflacdecoder.cpp b/plugins/decoder/flac/k3bflacdecoder.cpp new file mode 100644 index 0000000..762403f --- /dev/null +++ b/plugins/decoder/flac/k3bflacdecoder.cpp @@ -0,0 +1,494 @@ +/*  + * FLAC decoder module for K3b. + * Based on the Ogg Vorbis module for same. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * Copyright (C) 2003-2004 John Steele Scott <toojays@toojays.net> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bflacdecoder.h" + +#include <k3bpluginfactory.h> + +#include <qbuffer.h> +#include <qfile.h> +#include <qstringlist.h> + +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> + +#include <string.h> +#include <math.h> +#include <FLAC++/metadata.h> +#include <FLAC++/decoder.h> + +#ifdef HAVE_TAGLIB +#include <taglib/tag.h> +#include <taglib/flacfile.h> +#endif + +#if !defined FLACPP_API_VERSION_CURRENT || FLACPP_API_VERSION_CURRENT < 6 +#define LEGACY_FLAC +#else +#undef LEGACY_FLAC +#endif + +K_EXPORT_COMPONENT_FACTORY( libk3bflacdecoder, K3bPluginFactory<K3bFLACDecoderFactory>( "libk3bflacdecoder" ) ) + + +class K3bFLACDecoder::Private +#ifdef LEGACY_FLAC +  : public FLAC::Decoder::SeekableStream +#else +  : public FLAC::Decoder::Stream +#endif +{ +public: +  void open(QFile* f) { +    file = f; +    file->open(IO_ReadOnly); +     +    internalBuffer->flush(); +     +    set_metadata_respond(FLAC__METADATA_TYPE_STREAMINFO); +    set_metadata_respond(FLAC__METADATA_TYPE_VORBIS_COMMENT); + +    init(); +    process_until_end_of_metadata(); +  } + +  void cleanup() { +    file->close(); +    finish(); +    delete comments; +    comments = 0; +  } + +  Private(QFile* f) +#ifdef LEGACY_FLAC +    : FLAC::Decoder::SeekableStream(), +#else +    : FLAC::Decoder::Stream(), +#endif +      comments(0) { +    internalBuffer = new QBuffer(); +    internalBuffer->open(IO_ReadWrite); + +    open(f); +  } +   + +  ~Private() { +    cleanup(); +    delete internalBuffer; +  } +   +  bool seekToFrame(int frame); + +  QFile* file; +  QBuffer* internalBuffer; +  FLAC::Metadata::VorbisComment* comments; +  unsigned rate; +  unsigned channels; +  unsigned bitsPerSample; +  unsigned maxFramesize; +  unsigned maxBlocksize; +  unsigned minFramesize; +  unsigned minBlocksize; +  FLAC__uint64 samples; +   +protected: +#ifdef LEGACY_FLAC +  virtual FLAC__SeekableStreamDecoderReadStatus read_callback(FLAC__byte buffer[], unsigned *bytes); +  virtual FLAC__SeekableStreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); +  virtual FLAC__SeekableStreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); +  virtual FLAC__SeekableStreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length); +#else +  virtual FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes); +  virtual FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); +  virtual FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); +  virtual FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length); +#endif +  virtual bool eof_callback(); +  virtual void error_callback(FLAC__StreamDecoderErrorStatus){}; +  virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata); +  virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); +}; + +bool K3bFLACDecoder::Private::seekToFrame(int frame) { +  FLAC__uint64 sample = frame * rate / 75; +  return seek_absolute(sample); +} + +bool K3bFLACDecoder::Private::eof_callback() { +  return file->atEnd(); +} + +#ifdef LEGACY_FLAC +FLAC__SeekableStreamDecoderReadStatus K3bFLACDecoder::Private::read_callback(FLAC__byte buffer[],                                                                             unsigned *bytes) { +  long retval =  file->readBlock((char *)buffer, (*bytes)); +  if(-1 == retval) { +    return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; +  } else { +    (*bytes) = retval; +    return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; +  } +} +#else +FLAC__StreamDecoderReadStatus K3bFLACDecoder::Private::read_callback(FLAC__byte buffer[],                                                                             size_t *bytes) { +  long retval =  file->readBlock((char *)buffer, (*bytes)); +  if(-1 == retval) { +    return FLAC__STREAM_DECODER_READ_STATUS_ABORT; +  } else { +    (*bytes) = retval; +    return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +  } +} +#endif + +#ifdef LEGACY_FLAC +FLAC__SeekableStreamDecoderSeekStatus  +K3bFLACDecoder::Private::seek_callback(FLAC__uint64 absolute_byte_offset) { +  if(!file->at(absolute_byte_offset)) +    return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; +  else +    return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; +} +#else +FLAC__StreamDecoderSeekStatus  +K3bFLACDecoder::Private::seek_callback(FLAC__uint64 absolute_byte_offset) { +  if(file->at(absolute_byte_offset) == FALSE) +    return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; +  else +    return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} +#endif + +#ifdef LEGACY_FLAC +FLAC__SeekableStreamDecoderTellStatus  +K3bFLACDecoder::Private::tell_callback(FLAC__uint64 *absolute_byte_offset) { +  (*absolute_byte_offset) = file->at(); +  return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; +} +#else +FLAC__StreamDecoderTellStatus  +K3bFLACDecoder::Private::tell_callback(FLAC__uint64 *absolute_byte_offset) { +  (*absolute_byte_offset) = file->at(); +  return FLAC__STREAM_DECODER_TELL_STATUS_OK; +} +#endif + +#ifdef LEGACY_FLAC +FLAC__SeekableStreamDecoderLengthStatus  +K3bFLACDecoder::Private::length_callback(FLAC__uint64 *stream_length) { +  (*stream_length) = file->size(); +  return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; +} +#else +FLAC__StreamDecoderLengthStatus  +K3bFLACDecoder::Private::length_callback(FLAC__uint64 *stream_length) { +  (*stream_length) = file->size(); +  return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; +} +#endif + + +void K3bFLACDecoder::Private::metadata_callback(const FLAC__StreamMetadata *metadata) { +  switch (metadata->type) { +  case FLAC__METADATA_TYPE_STREAMINFO: +    channels = metadata->data.stream_info.channels; +    rate = metadata->data.stream_info.sample_rate; +    bitsPerSample = metadata->data.stream_info.bits_per_sample; +    samples = metadata->data.stream_info.total_samples; +    maxFramesize = metadata->data.stream_info.max_framesize; +    minFramesize = metadata->data.stream_info.min_framesize; +    maxBlocksize = metadata->data.stream_info.max_blocksize; +    minBlocksize = metadata->data.stream_info.min_blocksize; +    break; +  case FLAC__METADATA_TYPE_VORBIS_COMMENT: +    comments = new FLAC::Metadata::VorbisComment((FLAC__StreamMetadata *)metadata, true); +    break; +  default: +    break; +  } +} + +FLAC__StreamDecoderWriteStatus K3bFLACDecoder::Private::write_callback(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) { +  unsigned i, j; +  // Note that in canDecode we made sure that the input is 1-16 bit stereo or mono. +  unsigned samples = frame->header.blocksize; + +  for(i=0; i < samples; i++) { +   // in FLAC channel 0 is left, 1 is right +   for(j=0; j < this->channels; j++) { +    FLAC__int32 value = (buffer[j][i])<<(16 - frame->header.bits_per_sample); +    internalBuffer->putch(value >> 8); // msb +    internalBuffer->putch(value & 0xFF); // lsb +   } +  } + +  // Rewind the buffer so the decode method will take data from the beginning. +  internalBuffer->at(0); +  return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +K3bFLACDecoder::K3bFLACDecoder( QObject* parent, const char* name ) +  : K3bAudioDecoder( parent, name ) +{ +  d = 0; +} + + +K3bFLACDecoder::~K3bFLACDecoder() +{ +  delete d; +} + +void K3bFLACDecoder::cleanup() +{ +  if (d) { +    d->cleanup(); +    d->open(new QFile(filename())); +  } +  else +    d = new Private(new QFile(filename())); +} + +bool K3bFLACDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ +  cleanup(); + +  frames = (unsigned long)ceil((d->samples * 75.0)/d->rate); +  samplerate = d->rate; +  ch = d->channels; + +  // add meta info +  if( d->comments != 0 ) { +    kdDebug() << "(K3bFLACDecoder) unpacking Vorbis tags" << endl; +    for( unsigned int i = 0; i < d->comments->get_num_comments(); ++i ) { +      QString key = QString::fromUtf8( d->comments->get_comment(i).get_field_name(), +                                       d->comments->get_comment(i).get_field_name_length() ); +      QString value = QString::fromUtf8( d->comments->get_comment(i).get_field_value(), +                                         d->comments->get_comment(i).get_field_value_length() ); + +      if( key.upper() == "TITLE" ) +        addMetaInfo( META_TITLE, value ); +      else if( key.upper() == "ARTIST" ) +        addMetaInfo( META_ARTIST, value ); +      else if( key.upper() == "DESCRIPTION" ) +        addMetaInfo( META_COMMENT, value ); +    } +  } +#ifdef HAVE_TAGLIB +  if ((d->comments == 0) || (d->comments->get_num_comments() == 0)) { +    // no Vorbis comments, check for ID3 tags +    kdDebug() << "(K3bFLACDecoder) using taglib to read tag" << endl; +    TagLib::FLAC::File f( QFile::encodeName(filename()) ); +    if( f.isOpen() ) { +      addMetaInfo( META_TITLE, TStringToQString( f.tag()->title() ) ); +      addMetaInfo( META_ARTIST, TStringToQString( f.tag()->artist() ) ); +      addMetaInfo( META_COMMENT, TStringToQString( f.tag()->comment() ) ); +    } +  } +#endif + +  return true; +} + + +bool K3bFLACDecoder::initDecoderInternal() +{ +  cleanup(); + +  return true; +} + + +int K3bFLACDecoder::decodeInternal( char* _data, int maxLen ) +{ +  int bytesToCopy; +  int bytesCopied; +  int bytesAvailable; + +#ifdef LEGACY_FLAC +  if(d->internalBuffer->size() == 0) { +    // want more data +    switch(d->get_state()) { +    case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM: +      d->finish(); +      break; +    case FLAC__SEEKABLE_STREAM_DECODER_OK: +      if(! d->process_single()) +        return -1; +      break; +    default: +      return -1; +    } +  } +#else +  if(d->internalBuffer->size() == 0) { +    // want more data +    if(d->get_state() == FLAC__STREAM_DECODER_END_OF_STREAM) +      d->finish(); +    else if(d->get_state() < FLAC__STREAM_DECODER_END_OF_STREAM) { +      if(! d->process_single()) +        return -1; +    } +    else +      return -1; +  } +#endif +   +  bytesAvailable = d->internalBuffer->size() - d->internalBuffer->at(); +  bytesToCopy = QMIN(maxLen, bytesAvailable); +  bytesCopied = (int)d->internalBuffer->readBlock(_data, bytesToCopy); + +  if(bytesCopied == bytesAvailable) { +    // reset the buffer +    d->internalBuffer->close(); +    d->internalBuffer->open(IO_ReadWrite|IO_Truncate); +  } + +  return bytesCopied; +} + + +bool K3bFLACDecoder::seekInternal( const K3b::Msf& pos ) +{ +  return d->seekToFrame(pos.totalFrames()); +} + + +QString K3bFLACDecoder::fileType() const +{ +  return i18n("FLAC"); +} + + +QStringList K3bFLACDecoder::supportedTechnicalInfos() const +{ +  return QStringList::split( ";",  +                             i18n("Channels") + ";" + +                             i18n("Sampling Rate") + ";" + +                             i18n("Sample Size") ); +} + + +QString K3bFLACDecoder::technicalInfo( const QString& info ) const +{ +  if( d->comments != 0 ) { +    if( info == i18n("Vendor") ) +#ifdef FLAC_NEWER_THAN_1_1_1 +      return QString::fromUtf8((char*)d->comments->get_vendor_string()); +#else +      return QString::fromUtf8(d->comments->get_vendor_string().get_field()); +#endif +    else if( info == i18n("Channels") ) +      return QString::number(d->channels); +    else if( info == i18n("Sampling Rate") ) +      return i18n("%1 Hz").arg(d->rate); +    else if( info == i18n("Sample Size") ) +      return i18n("%1 bits").arg(d->bitsPerSample); +  } + +  return QString::null; +} + + + +K3bFLACDecoderFactory::K3bFLACDecoderFactory( QObject* parent, const char* name ) +  : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bFLACDecoderFactory::~K3bFLACDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bFLACDecoderFactory::createDecoder( QObject* parent,  +						 const char* name ) const +{ +  return new K3bFLACDecoder( parent, name ); +} + + +bool K3bFLACDecoderFactory::canDecode( const KURL& url ) +{ +  // buffer large enough to read an ID3 tag header +  char buf[10]; + +  // Note: since file is created on the stack it will be closed automatically +  // by its destructor when this method (i.e. canDecode) returns. +  QFile file(url.path()); + +  if(!file.open(IO_ReadOnly)) { +    kdDebug() << "(K3bFLACDecoder) Could not open file " << url.path() << endl; +    return false; +  } + +  // look for a fLaC magic number or ID3 tag header +  if(10 != file.readBlock(buf, 10)) { +    kdDebug() << "(K3bFLACDecorder) File " << url.path() +              << " is too small to be a FLAC file" << endl; +    return false; +  } + +  if(0 == memcmp(buf, "ID3", 3)) { +    // Found ID3 tag, try and seek past it. +    kdDebug() << "(K3bFLACDecorder) File " << url.path() << ": found ID3 tag" << endl; + +    // See www.id3.org for details of the header, note that the size field +    // unpacks to 7-bit bytes, then the +10 is for the header itself. +    int pos; +    pos = ((buf[6]<<21)|(buf[7]<<14)|(buf[8]<<7)|buf[9]) + 10; + +    kdDebug() << "(K3bFLACDecoder) " << url.path() << ": seeking to "  +              << pos << endl; +    if(!file.at(pos)) { +      kdDebug() << "(K3bFLACDecoder) " << url.path() << ": couldn't seek to "  +                << pos << endl; +      return false; +    }else{ +      // seek was okay, try and read magic number into buf +      if(4 != file.readBlock(buf, 4)) { +        kdDebug() << "(K3bFLACDecorder) File " << url.path() +                  << " has ID3 tag but naught else!" << endl; +        return false; +      } +    } +  } + +  if(memcmp(buf, "fLaC", 4) != 0) { +    kdDebug() << "(K3bFLACDecoder) " << url.path() << ": not a FLAC file" << endl; +    return false; +  } + +  FLAC::Metadata::StreamInfo info = FLAC::Metadata::StreamInfo(); +  FLAC::Metadata::get_streaminfo(url.path().ascii(), info); + +  if((info.get_channels() <= 2) && +     (info.get_bits_per_sample() <= 16)) { +    return true; +  } else { +    kdDebug() << "(K3bFLACDecoder) " << url.path() << ": wrong format:" << endl +              << "                channels:    "  +              << QString::number(info.get_channels()) << endl +              << "                samplerate:  " +              << QString::number(info.get_sample_rate()) << endl +              << "                bits/sample: " +              << QString::number(info.get_bits_per_sample()) << endl; +    return false; +  } +} + +#include "k3bflacdecoder.moc" diff --git a/plugins/decoder/flac/k3bflacdecoder.h b/plugins/decoder/flac/k3bflacdecoder.h new file mode 100644 index 0000000..aace651 --- /dev/null +++ b/plugins/decoder/flac/k3bflacdecoder.h @@ -0,0 +1,68 @@ +/*  + * FLAC decoder module for K3b. + * Based on the Ogg Vorbis module for same. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * Copyright (C) 2003 John Steele Scott <toojays@toojays.net> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_FLAC_DECODER_H_ +#define _K3B_FLAC_DECODER_H_ + + +#include <k3baudiodecoder.h> + +class KURL; + + +class K3bFLACDecoderFactory : public K3bAudioDecoderFactory +{ +  Q_OBJECT + + public: +  K3bFLACDecoderFactory( QObject* parent = 0, const char* name = 0 ); +  ~K3bFLACDecoderFactory(); + +  bool canDecode( const KURL& filename ); + +  int pluginSystemVersion() const { return 3; } + +  K3bAudioDecoder* createDecoder( QObject* parent = 0,  +				  const char* name = 0 ) const; +}; + + +class K3bFLACDecoder : public K3bAudioDecoder +{ +  Q_OBJECT + + public:  +  K3bFLACDecoder( QObject* parent = 0, const char* name = 0 ); +  ~K3bFLACDecoder(); + +  void cleanup(); + +  bool seekInternal( const K3b::Msf& ); + +  QString fileType() const; +  QStringList supportedTechnicalInfos() const; +  QString technicalInfo( const QString& ) const; + + protected: +  bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); +  bool initDecoderInternal(); + +  int decodeInternal( char* _data, int maxLen ); + + private: +  class Private; +  Private* d; +}; + +#endif diff --git a/plugins/decoder/flac/k3bflacdecoder.plugin b/plugins/decoder/flac/k3bflacdecoder.plugin new file mode 100644 index 0000000..1e1bcbb --- /dev/null +++ b/plugins/decoder/flac/k3bflacdecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bflacdecoder +Group=AudioDecoder +Name=K3b FLAC Decoder +Author=John Steele Scott +Email=toojays@toojays.net +Version=2.1 +Comment=Decoding module to decode FLAC files +License=GPL diff --git a/plugins/decoder/libsndfile/Makefile.am b/plugins/decoder/libsndfile/Makefile.am new file mode 100644 index 0000000..2af9911 --- /dev/null +++ b/plugins/decoder/libsndfile/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3blibsndfiledecoder.la + +libk3blibsndfiledecoder_la_SOURCES = k3blibsndfiledecoder.cpp + +libk3blibsndfiledecoder_la_LIBADD = ../../../libk3b/libk3b.la $(LIB_KDEUI) -lsndfile +libk3blibsndfiledecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3blibsndfiledecoder.plugin + +METASOURCES = AUTO + diff --git a/plugins/decoder/libsndfile/configure.in.bot b/plugins/decoder/libsndfile/configure.in.bot new file mode 100644 index 0000000..cf1e4e9 --- /dev/null +++ b/plugins/decoder/libsndfile/configure.in.bot @@ -0,0 +1,11 @@ +echo "" + +if $av_cv_sndfile; then +	echo "K3b - libsndfile audio decoding support:     yes" +else +	echo "K3b - libsndfile audio decoding support:      no" +if test "$ac_cv_use_sndfile" = "yes"; then +	echo "K3b -     You are missing the libsndfile headers and libraries." +	echo "K3b -     The libsndfile audio decoding plugin won't be compiled." +fi +fi diff --git a/plugins/decoder/libsndfile/configure.in.in b/plugins/decoder/libsndfile/configure.in.in new file mode 100644 index 0000000..e0efcc5 --- /dev/null +++ b/plugins/decoder/libsndfile/configure.in.in @@ -0,0 +1,52 @@ +dnl === test for libsndfile - begin === +dnl +dnl Don't use PKG_CHECK, since if there is no pkg-config installed, +dnl then there is no auto* magic for it either. +dnl +dnl Tests copied from kdebase/kioslave/thumbnail/ +dnl +if test -z "$PKG_CONFIG"; then +    AC_PATH_PROG(PKG_CONFIG, pkg-config, no) +fi + +AC_ARG_WITH( +	sndfile,  +	AS_HELP_STRING([--without-sndfile],  +	[build K3b without libsndfile support (default=no)]),  +	[ac_cv_use_sndfile=$withval],  +	[ac_cv_use_sndfile=yes] +) + +if test "$ac_cv_use_sndfile" = "yes"; then +  SNDFILE_CFLAGS="" +  SNDFILE_LIBS="" +  if test "$PKG_CONFIG" = "no" ; then +      ac_cv_sndfile=0 +      echo "*** The pkg-config script could not be found. Make sure it is" +      echo "*** in your path, or set the PKG_CONFIG environment variable" +      echo "*** to the full path to pkg-config." +      echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." +  else +      if !(`$PKG_CONFIG --exists sndfile`) ; then +          echo "*** sndfile is not installed." +          ac_cv_sndfile=0 +      else +          if !(`$PKG_CONFIG --atleast-version="1.0.2" sndfile`) ; then +              echo "*** You need at least version 1.0.2 of sndfile." +              ac_cv_sndfile=0 +          else +              ac_cv_sndfile=1 +              SNDFILE_CFLAGS=`$PKG_CONFIG --cflags sndfile` +              SNDFILE_LIBS=`$PKG_CONFIG --libs sndfile` +          fi +      fi +  fi + +  AC_DEFINE_UNQUOTED([HAVE_SNDFILE],${ac_cv_sndfile}, +  			[Set to 1 if you have libsndfile.]) +  AC_SUBST(SNDFILE_CFLAGS) +  AC_SUBST(SNDFILE_LIBS) +fi + +AM_CONDITIONAL(include_AIFF, [test x$ac_cv_sndfile = x1]) +dnl === test for libsndfile - end === diff --git a/plugins/decoder/libsndfile/k3blibsndfiledecoder.cpp b/plugins/decoder/libsndfile/k3blibsndfiledecoder.cpp new file mode 100644 index 0000000..ea3d014 --- /dev/null +++ b/plugins/decoder/libsndfile/k3blibsndfiledecoder.cpp @@ -0,0 +1,254 @@ +/*  + * + * $Id: k3blibsndfiledecoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Matthieu Bedouet <mbedouet@no-log.org> + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3blibsndfiledecoder.h" + +#include <k3bpluginfactory.h> + +#include <qfile.h> +#include <qstringlist.h> + +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> +#include <kinstance.h> + + +#include <math.h> +#include <stdio.h> +#include <sndfile.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3blibsndfiledecoder, K3bPluginFactory<K3bLibsndfileDecoderFactory>( "libk3blibsndfiledecoder" ) ) + + +class K3bLibsndfileDecoder::Private +{ +public: +  Private():  +    isOpen(false), +    buffer(0), +    bufferSize(0) { +    format_info.name = 0; +  } +   +  SNDFILE *sndfile; +  SF_INFO sndinfo; +  SF_FORMAT_INFO format_info; +  bool isOpen; +  float* buffer; +  int bufferSize; +}; + + + +K3bLibsndfileDecoder::K3bLibsndfileDecoder( QObject* parent, const char* name ) +  : K3bAudioDecoder( parent, name ) +{ +  d = new Private(); +} + + +K3bLibsndfileDecoder::~K3bLibsndfileDecoder() +{ +  delete d; +} + + +QString K3bLibsndfileDecoder::fileType() const +{ +  if( d->format_info.name ) +    return QString::fromLocal8Bit(d->format_info.name); +  else +    return "-"; +} +	 + + +bool K3bLibsndfileDecoder::openFile() +{ +  if( !d->isOpen ) { +     +    cleanup(); +     +    d->sndinfo.format = 0; +    d->sndfile = sf_open (QFile::encodeName(filename()), SFM_READ, &d->sndinfo); +    if ( !d->sndfile ) { +      kdDebug() << "(K3bLibsndfileDecoder::openLibsndfileFile) : " << sf_strerror(d->sndfile) << endl; +      return false; +    } +    else { +      //retrieve infos (name, extension) about the format: +      d->format_info.format = d->sndinfo.format & SF_FORMAT_TYPEMASK ; +      sf_command (d->sndfile, SFC_GET_FORMAT_INFO, &d->format_info, sizeof (SF_FORMAT_INFO)) ; +       +      d->isOpen = true; +      kdDebug() << "(K3bLibsndfileDecoder::openLibsndfileFile) " << d->format_info.name << " file opened " << endl; +      return true; +    } +  } + +  return d->isOpen; +} + + +bool K3bLibsndfileDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ +  cleanup(); +   +  if( openFile() ) { +    // check length of track +    if ( d->sndinfo.frames <= 0 ) { +      kdDebug() << "(K3bLibsndfileDecoder::analyseFileInternal) Could not determine length of file " +		<< filename() << endl; +      cleanup(); +      return false; +    } +    else { +      addMetaInfo( META_TITLE, sf_get_string(d->sndfile, SF_STR_TITLE) ); +      addMetaInfo( META_ARTIST, sf_get_string(d->sndfile, SF_STR_ARTIST) ); +      addMetaInfo( META_COMMENT, sf_get_string(d->sndfile, SF_STR_COMMENT) ); +       +      addTechnicalInfo( i18n("Channels"), QString::number(d->sndinfo.channels) ); +      addTechnicalInfo( i18n("Sampling Rate"), i18n("%1 Hz").arg(d->sndinfo.samplerate) ); +       +      frames = (unsigned long)ceil(d->sndinfo.frames / d->sndinfo.samplerate * 75.0);  +      samplerate = d->sndinfo.samplerate; +      ch = d->sndinfo.channels; + +      kdDebug() << "(K3bLibsndfileDecoder) successfully analysed file: " << frames << " frames." << endl; + +      cleanup(); +      return true; +    } +  } +  else +    return false; +} + + + +bool K3bLibsndfileDecoder::initDecoderInternal() +{	 +  cleanup(); +  return openFile(); +} + + + +int K3bLibsndfileDecoder::decodeInternal( char* data, int maxLen ) +{ +  if( !d->buffer ) { +    d->buffer = new float[maxLen]; +    d->bufferSize = maxLen/2; +  } +   +  int read = (int) sf_read_float(d->sndfile, d->buffer,d->bufferSize) ; +  fromFloatTo16BitBeSigned( d->buffer, data, read ); +  read = read * 2; +   +  if( read < 0 ) { +    kdDebug() << "(K3bLibsndfileDecoder::decodeInternal) Error: " << read << endl; +    return -1; +  } +  else if( read == 0 ) { +    kdDebug() << "(K3bLibsndfileDecoder::decodeInternal) successfully finished decoding." << endl; +    return 0; +  } +  else if( read != maxLen ) { +    kdDebug() << "(K3bLibsndfileDecoder::decodeInternal) read:" << read << " expected:" << maxLen << endl; +    return -1; +  } +  else  +    return read; + } + + + +bool K3bLibsndfileDecoder::seekInternal( const K3b::Msf& pos) +{ +  return ( sf_seek( d->sndfile, pos.pcmSamples(), SEEK_SET ) == 0 ); +} + + + + +void K3bLibsndfileDecoder::cleanup() +{ +  if( d->isOpen ) { +    kdDebug() << "(K3bLibsndfileDecoder) cleaning up." << endl; +    sf_close( d->sndfile ); +    d->isOpen = false; +  } +} + + + +/********************************************************/ + + +K3bLibsndfileDecoderFactory::K3bLibsndfileDecoderFactory( QObject* parent, const char* name ) +  : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bLibsndfileDecoderFactory::~K3bLibsndfileDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bLibsndfileDecoderFactory::createDecoder( QObject* parent,  +							     const char* name ) const +{ +  return new K3bLibsndfileDecoder( parent, name ); +} + + +bool K3bLibsndfileDecoderFactory::canDecode( const KURL& url ) +{ +  SF_INFO infos; +  infos.format = 0; +  SNDFILE* sndfile = sf_open (QFile::encodeName(url.path()), SFM_READ, &infos); +   +  //is it supported by libsndfile? +  if ( !sndfile ) { +    kdDebug() << "(K3bLibsndfileDecoder) " << sf_strerror(sndfile) << endl; +    return false; +  } +  //we exclude only WAVE as there is another plugin for this +  else if ( infos.format && ((infos.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WAV) )  { +     +    //retrieve infos (name) about the format: +    SF_FORMAT_INFO format_info; +    format_info.format = infos.format & SF_FORMAT_TYPEMASK ; +    sf_command (sndfile, SFC_GET_FORMAT_INFO, &format_info, sizeof (format_info)) ; +     +    kdDebug() << "(K3bLibsndfileDecoder) " << format_info.name << " file === OK === "  << endl; +    sf_close( sndfile ); +    return true; +  } +  else { +    kdDebug() << "(K3bLibsndfileDecoder) " << url.path() << "not supported" << endl; +    sf_close( sndfile ); +    return false; +  } +  return false; +} + +#include "k3blibsndfiledecoder.moc" diff --git a/plugins/decoder/libsndfile/k3blibsndfiledecoder.h b/plugins/decoder/libsndfile/k3blibsndfiledecoder.h new file mode 100644 index 0000000..7ffbe2d --- /dev/null +++ b/plugins/decoder/libsndfile/k3blibsndfiledecoder.h @@ -0,0 +1,69 @@ +/*  + * + * $Id: k3blibsndfiledecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Matthieu Bedouet <mbedouet@no-log.org> + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_AIFF_DECODER_H_ +#define _K3B_AIFF_DECODER_H_ + +#include <k3baudiodecoder.h> + +class KURL; + + +class K3bLibsndfileDecoderFactory : public K3bAudioDecoderFactory +{ +  Q_OBJECT + + public: +  K3bLibsndfileDecoderFactory( QObject* parent = 0, const char* name = 0 ); +  ~K3bLibsndfileDecoderFactory(); + +  bool canDecode( const KURL& filename ); + +  int pluginSystemVersion() const { return 3; } + +  bool multiFormatDecoder() const { return true; } + +  K3bAudioDecoder* createDecoder( QObject* parent = 0,  +				  const char* name = 0 ) const; +}; + + +class K3bLibsndfileDecoder : public K3bAudioDecoder +{ +  Q_OBJECT + + public: +  K3bLibsndfileDecoder( QObject* parent = 0, const char* name = 0 ); +  ~K3bLibsndfileDecoder(); +  void cleanup(); +  QString fileType() const; + + protected: +  bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); +  bool initDecoderInternal(); +  bool seekInternal( const K3b::Msf& ); + +  int decodeInternal( char* _data, int maxLen ); +  + private: +  bool openFile(); + +  class Private; +  Private* d; +   +}; + +#endif diff --git a/plugins/decoder/libsndfile/k3blibsndfiledecoder.plugin b/plugins/decoder/libsndfile/k3blibsndfiledecoder.plugin new file mode 100644 index 0000000..7ae05f1 --- /dev/null +++ b/plugins/decoder/libsndfile/k3blibsndfiledecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3blibsndfiledecoder +Group=AudioDecoder +Name=K3b Libsndfile Decoder +Author=Matthieu Bedouet +Email=mbedouet@no-log.org +Version=1.0 +Comment=Decoding module to decode audio files supported by libsndfile +License=GPL diff --git a/plugins/decoder/mp3/Makefile.am b/plugins/decoder/mp3/Makefile.am new file mode 100644 index 0000000..7f74d21 --- /dev/null +++ b/plugins/decoder/mp3/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3bdevice $(taglib_includes) $(all_includes) + +kde_module_LTLIBRARIES = libk3bmaddecoder.la + +libk3bmaddecoder_la_SOURCES = k3bmad.cpp k3bmaddecoder.cpp + +libk3bmaddecoder_la_LIBADD = $(LIB_KDECORE) $(MAD_LIB) $(taglib_libs) ../../../libk3b/libk3b.la +libk3bmaddecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bmaddecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/mp3/configure.in.bot b/plugins/decoder/mp3/configure.in.bot new file mode 100644 index 0000000..0ee4872 --- /dev/null +++ b/plugins/decoder/mp3/configure.in.bot @@ -0,0 +1,11 @@ +echo "" + +if test -n "$MAD_LIB"; then +	echo "K3b - Mp3 decoding support (libmad):         yes" +else +	echo "K3b - Mp3 decoding support (libmad):          no" +if test "$ac_cv_use_libmad" = "yes"; then +	echo "K3b -     You are missing the libmad headers and libraries." +	echo "K3b -     The Mp3 decoding plugin won't be compiled." +fi +fi diff --git a/plugins/decoder/mp3/configure.in.in b/plugins/decoder/mp3/configure.in.in new file mode 100644 index 0000000..fb92936 --- /dev/null +++ b/plugins/decoder/mp3/configure.in.in @@ -0,0 +1,24 @@ +dnl === libmad MPEG decoder check - begin === +AC_ARG_WITH( +	libmad,  +	AS_HELP_STRING([--without-libmad], [build K3b without libmad support (default=no)]),  +	[ac_cv_use_libmad=$withval],  +	[ac_cv_use_libmad=yes] +) + +if test "$ac_cv_use_libmad" = "yes"; then +  MAD_LIB="" +  KDE_CHECK_HEADER(mad.h, [ +	AC_CHECK_LIB(mad, mad_synth_frame, [ +		MAD_LIB="-lmad" +		AC_DEFINE(HAVE_LIBMAD,1,[defined if you have libmad headers and libraries])], +		[], +		$all_libraries +	) +  ]) +  AC_SUBST(MAD_LIB) + +fi + +AM_CONDITIONAL(include_MP3, [test -n "$MAD_LIB"]) +dnl === libmad MPeg decoder check - end === diff --git a/plugins/decoder/mp3/k3bmad.cpp b/plugins/decoder/mp3/k3bmad.cpp new file mode 100644 index 0000000..cb4cf6c --- /dev/null +++ b/plugins/decoder/mp3/k3bmad.cpp @@ -0,0 +1,359 @@ +/*  + * + * $Id: k3bmad.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmad.h" + +#include <qfile.h> +#include <kdebug.h> + + +static const int INPUT_BUFFER_SIZE = 5*8192; + + +K3bMad::K3bMad() +  : m_madStructuresInitialized(false), +    m_bInputError(false) +{ +  madStream = new mad_stream; +  madFrame  = new mad_frame; +  madSynth  = new mad_synth; +  madTimer  = new mad_timer_t; + +  // +  // we allocate additional MAD_BUFFER_GUARD bytes to always be able to append the +  // zero bytes needed for decoding the last frame. +  // +  m_inputBuffer = new unsigned char[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD]; +} + + +K3bMad::~K3bMad() +{ +  cleanup(); + +  delete madStream; +  delete madFrame; +  delete madSynth; +  delete madTimer; + +  delete [] m_inputBuffer; +} + + +bool K3bMad::open( const QString& filename ) +{ +  cleanup(); + +  m_bInputError = false; +  m_channels = m_sampleRate = 0; + +  m_inputFile.setName( filename ); +    +  if( !m_inputFile.open( IO_ReadOnly ) ) { +    kdError() << "(K3bMad) could not open file " << m_inputFile.name() << endl; +    return false; +  } + +  initMad(); + +  memset( m_inputBuffer, 0, INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD ); + +  return true; +} + + +bool K3bMad::inputError() const +{ +  return m_bInputError; +} + + +bool K3bMad::fillStreamBuffer() +{ +  /* The input bucket must be filled if it becomes empty or if +   * it's the first execution of the loop. +   */ +  if( madStream->buffer == 0 || madStream->error == MAD_ERROR_BUFLEN ) { +    if( eof() ) +      return false; + +    long readSize, remaining; +    unsigned char* readStart; + +    if( madStream->next_frame != 0 ) { +      remaining = madStream->bufend - madStream->next_frame; +      memmove( m_inputBuffer, madStream->next_frame, remaining ); +      readStart = m_inputBuffer + remaining; +      readSize = INPUT_BUFFER_SIZE - remaining; +    } +    else { +      readSize  = INPUT_BUFFER_SIZE; +      readStart = m_inputBuffer; +      remaining = 0; +    } +			 +    // Fill-in the buffer.  +    Q_LONG result = m_inputFile.readBlock( (char*)readStart, readSize ); +    if( result < 0 ) { +      kdDebug() << "(K3bMad) read error on bitstream)" << endl; +      m_bInputError = true; +      return false; +    } +    else if( result == 0 ) { +      kdDebug() << "(K3bMad) end of input stream" << endl; +      return false; +    } +    else { +      readStart += result; + +      if( eof() ) { +	kdDebug() << "(K3bMad::fillStreamBuffer) MAD_BUFFER_GUARD" << endl; +	memset( readStart, 0, MAD_BUFFER_GUARD ); +	result += MAD_BUFFER_GUARD; +      } + +      // Pipe the new buffer content to libmad's stream decoder facility. +      mad_stream_buffer( madStream, m_inputBuffer, result + remaining ); +      madStream->error = MAD_ERROR_NONE; +    } +  } + +  return true; +} + + +bool K3bMad::skipTag() +{ +  // skip the tag at the beginning of the file +  m_inputFile.at( 0 ); + +  // +  // now check if the file starts with an id3 tag and skip it if so +  // +  char buf[4096]; +  int bufLen = 4096; +  if( m_inputFile.readBlock( buf, bufLen ) < bufLen ) { +    kdDebug() << "(K3bMad) unable to read " << bufLen << " bytes from "  +	      << m_inputFile.name() << endl; +    return false; +  } + +  if( ( buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3' ) && +      ( (unsigned short)buf[3] < 0xff && (unsigned short)buf[4] < 0xff ) ) { +    // do we have a footer? +    bool footer = (buf[5] & 0x10); + +    // the size is saved as a synched int meaning bit 7 is always cleared to 0 +    unsigned int size =  +      ( (buf[6] & 0x7f) << 21 ) |  +      ( (buf[7] & 0x7f) << 14 ) |  +      ( (buf[8] & 0x7f) << 7) |  +      (buf[9] & 0x7f); +    unsigned int offset = size + 10; +    if( footer ) +      offset += 10; + +    kdDebug() << "(K3bMad) skipping past ID3 tag to " << offset << endl; + +    // skip the id3 tag +    if( !m_inputFile.at(offset) ) { +      kdDebug() << "(K3bMad) " << m_inputFile.name() +		<< ": couldn't seek to " << offset << endl; +      return false; +    } +  } +  else { +    // reset file +    return m_inputFile.at( 0 ); +  } + +  return true; +} + + +bool K3bMad::seekFirstHeader() +{ +  // +  // A lot of mp3 files start with a lot of junk which confuses mad. +  // We "allow" an mp3 file to start with at most 1 KB of junk. This is just +  // some random value since we do not want to search the hole file. That would +  // take way to long for non-mp3 files. +  // +  bool headerFound = findNextHeader(); +  QIODevice::Offset inputPos = streamPos(); +  while( !headerFound &&  +	 !m_inputFile.atEnd() &&  +	 streamPos() <= inputPos+1024 ) { +    headerFound = findNextHeader(); +  } + +  // seek back to the begin of the frame +  if( headerFound ) { +    int streamSize = madStream->bufend - madStream->buffer; +    int bytesToFrame = madStream->this_frame - madStream->buffer; +    m_inputFile.at( m_inputFile.at() - streamSize + bytesToFrame ); + +    kdDebug() << "(K3bMad) found first header at " << m_inputFile.at() << endl; +  } + +  // reset the stream to make sure mad really starts decoding at out seek position +  mad_stream_finish( madStream ); +  mad_stream_init( madStream ); + +  return headerFound; +} + + +bool K3bMad::eof() const +{  +  return m_inputFile.atEnd(); +} + + +QIODevice::Offset K3bMad::inputPos() const +{ +  return m_inputFile.at(); +} + + +QIODevice::Offset K3bMad::streamPos() const +{ +  return inputPos() - (madStream->bufend - madStream->this_frame + 1); +} + + +bool K3bMad::inputSeek( QIODevice::Offset pos ) +{ +  return m_inputFile.at( pos ); +} + + +void K3bMad::initMad() +{ +  if( !m_madStructuresInitialized ) { +    mad_stream_init( madStream ); +    mad_timer_reset( madTimer ); +    mad_frame_init( madFrame ); +    mad_synth_init( madSynth ); + +    m_madStructuresInitialized = true; +  } +} + + +void K3bMad::cleanup() +{ +  if( m_inputFile.isOpen() ) { +    kdDebug() << "(K3bMad) cleanup at offset: "  +	      << "Input file at: " << m_inputFile.at() << " " +	      << "Input file size: " << m_inputFile.size() << " " +	      << "stream pos: "  +	      << ( m_inputFile.at() - (madStream->bufend - madStream->this_frame + 1) ) +	      << endl; +    m_inputFile.close(); +  } +     +  if( m_madStructuresInitialized ) { +    mad_frame_finish( madFrame ); +    mad_synth_finish( madSynth ); +    mad_stream_finish( madStream ); +  } +     +  m_madStructuresInitialized = false; +} + + +// +// LOSTSYNC could happen when mad encounters the id3 tag... +// +bool K3bMad::findNextHeader() +{ +  if( !fillStreamBuffer() ) +    return false; + +  // +  // MAD_RECOVERABLE == true:  frame was read, decoding failed (about to skip frame) +  // MAD_RECOVERABLE == false: frame was not read, need data +  // + +  if( mad_header_decode( &madFrame->header, madStream ) < 0 ) { +    if( MAD_RECOVERABLE( madStream->error ) || +	madStream->error == MAD_ERROR_BUFLEN ) { +      return findNextHeader(); +    } +    else +      kdDebug() << "(K3bMad::findNextHeader) error: " << mad_stream_errorstr( madStream ) << endl; + +    // FIXME probably we should not do this here since we don't do it +    // in the frame decoding +//     if( !checkFrameHeader( &madFrame->header ) ) +//       return findNextHeader(); + +    return false; +  } + +  if( !m_channels ) { +    m_channels = MAD_NCHANNELS(&madFrame->header); +    m_sampleRate = madFrame->header.samplerate; +  } + +  mad_timer_add( madTimer, madFrame->header.duration ); + +  return true; +} + + +bool K3bMad::decodeNextFrame() +{ +  if( !fillStreamBuffer() ) +    return false; + +  if( mad_frame_decode( madFrame, madStream ) < 0 ) { +    if( MAD_RECOVERABLE( madStream->error ) || + 	madStream->error == MAD_ERROR_BUFLEN ) { +      return decodeNextFrame(); +    } + +    return false; +  } + +  if( !m_channels ) { +    m_channels = MAD_NCHANNELS(&madFrame->header); +    m_sampleRate = madFrame->header.samplerate; +  } + +  mad_timer_add( madTimer, madFrame->header.duration ); + +  return true; +} + + +// +// This is from the arts mad decoder +// +bool K3bMad::checkFrameHeader( mad_header* header ) const +{ +  int frameSize = MAD_NSBSAMPLES( header ) * 32; + +  if( frameSize <= 0 ) +    return false; + +  if( m_channels && m_channels != MAD_NCHANNELS(header) ) +    return false; +     +  return true; +} + + diff --git a/plugins/decoder/mp3/k3bmad.h b/plugins/decoder/mp3/k3bmad.h new file mode 100644 index 0000000..a4d9aae --- /dev/null +++ b/plugins/decoder/mp3/k3bmad.h @@ -0,0 +1,92 @@ +/*  + * + * $Id: k3bmad.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2004 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MAD_H_ +#define _K3B_MAD_H_ + +extern "C" { +#include <mad.h> +} + +#include <qfile.h> + + +class K3bMad +{ +public: +  K3bMad(); +  ~K3bMad(); + +  bool open( const QString& filename ); + +  /** +   * @return true if the mad stream contains data +   *         false if there is no data left or an error occurred. +   *         In the latter case inputError() returns true. +   */ +  bool fillStreamBuffer(); + +  /** +   * Skip id3 tags. +   * +   * This will reset the input file. +   */ +  bool skipTag(); + +  /** +   * Find first frame and seek to the beginning of that frame. +   * This is used to skip the junk that many mp3 files start with. +   */ +  bool seekFirstHeader(); + +  bool eof() const; +  bool inputError() const; + +  /** +   * Current position in theinput file. This does NOT +   * care about the status of the mad stream. Use streamPos() +   * in that case. +   */ +  QIODevice::Offset inputPos() const; + +  /** +   * Current absolut position of the decoder stream. +   */ +  QIODevice::Offset streamPos() const; +  bool inputSeek( QIODevice::Offset pos ); + +  void initMad(); +  void cleanup(); + +  bool decodeNextFrame(); +  bool findNextHeader(); +  bool checkFrameHeader( mad_header* header ) const; + +  mad_stream*   madStream; +  mad_frame*    madFrame; +  mad_synth*    madSynth; +  mad_timer_t*  madTimer; + +private: +  QFile m_inputFile; +  bool m_madStructuresInitialized; +  unsigned char* m_inputBuffer; +  bool m_bInputError; + +  int m_channels; +  int m_sampleRate; +}; + +#endif diff --git a/plugins/decoder/mp3/k3bmaddecoder.cpp b/plugins/decoder/mp3/k3bmaddecoder.cpp new file mode 100644 index 0000000..e3aef56 --- /dev/null +++ b/plugins/decoder/mp3/k3bmaddecoder.cpp @@ -0,0 +1,542 @@ +/* + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + + +// +// Some notes on mp3: +// A mp3 Frame is always samples/samplerate seconds in length +// +// +// +// What we need are raw 16 bit stereo samples at 44100 Hz which results in 588 samples +// per block (2352 bytes: 32*588 bit). 1 second are 75 blocks. +// + +#include <config.h> + +#include "k3bmaddecoder.h" +#include "k3bmad.h" + +#include <k3bpluginfactory.h> + +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> + +#include <qstring.h> +#include <qfile.h> +#include <qvaluevector.h> + +#include <stdlib.h> +#include <cmath> +#include <cstdlib> + +#include <config.h> + +#ifdef HAVE_TAGLIB +#include <taglib/tag.h> +#include <taglib/mpegfile.h> +#endif + + +K_EXPORT_COMPONENT_FACTORY( libk3bmaddecoder, K3bPluginFactory<K3bMadDecoderFactory>( "k3bmaddecoder" ) ) + + +int K3bMadDecoder::MaxAllowedRecoverableErrors = 10; + + + +class K3bMadDecoder::MadDecoderPrivate +{ +public: +  MadDecoderPrivate() +    : outputBuffer(0), +      outputPointer(0), +      outputBufferEnd(0) { +    mad_header_init( &firstHeader ); +  } + +  K3bMad* handle; + +  QValueVector<unsigned long long> seekPositions; + +  bool bOutputFinished; + +  char* outputBuffer; +  char* outputPointer; +  char* outputBufferEnd; + +  // the first frame header for technical info +  mad_header firstHeader; +  bool vbr; +}; + + + + +K3bMadDecoder::K3bMadDecoder( QObject* parent, const char* name ) +  : K3bAudioDecoder( parent, name ) +{ +  d = new MadDecoderPrivate(); +  d->handle = new K3bMad(); +} + + +K3bMadDecoder::~K3bMadDecoder() +{ +  cleanup(); +  delete d->handle; +  delete d; +} + + +QString K3bMadDecoder::metaInfo( MetaDataField f ) +{ +#ifdef HAVE_TAGLIB +  TagLib::MPEG::File file( QFile::encodeName( filename() ).data() ); + +  if ( file.tag() ) { +      switch( f ) { +      case META_TITLE: +          return TStringToQString( file.tag()->title() ); +      case META_ARTIST: +          return TStringToQString( file.tag()->artist() ); +      case META_COMMENT: +          return TStringToQString( file.tag()->comment() ); +      default: +          return QString::null; +      } +  } +  else { +      return QString::null; +  } + +#else +  return K3bAudioDecoder::metaInfo( f ); +#endif +} + + +bool K3bMadDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ +  initDecoderInternal(); +  frames = countFrames(); +  if( frames > 0 ) { +    // we convert mono to stereo all by ourselves. :) +    ch = 2; +    samplerate = d->firstHeader.samplerate; +    return true; +  } +  else +    return false; +} + + +bool K3bMadDecoder::initDecoderInternal() +{ +  cleanup(); + +  d->bOutputFinished = false; + +  if( !d->handle->open( filename() ) ) +    return false; + +  if( !d->handle->skipTag() ) +    return false; + +  if( !d->handle->seekFirstHeader() ) +    return false; + +  return true; +} + + +unsigned long K3bMadDecoder::countFrames() +{ +  kdDebug() << "(K3bMadDecoder::countFrames)" << endl; + +  unsigned long frames = 0; +  bool error = false; +  d->vbr = false; +  bool bFirstHeaderSaved = false; + +  d->seekPositions.clear(); + +  while( !error && d->handle->findNextHeader() ) { + +    if( !bFirstHeaderSaved ) { +      bFirstHeaderSaved = true; +      d->firstHeader = d->handle->madFrame->header; +    } +    else if( d->handle->madFrame->header.bitrate != d->firstHeader.bitrate ) +      d->vbr = true; + +    // +    // position in stream: postion in file minus the not yet used buffer +    // +    unsigned long long seekPos = d->handle->inputPos() - +      (d->handle->madStream->bufend - d->handle->madStream->this_frame + 1); + +    // save the number of bytes to be read to decode i-1 frames at position i +    // in other words: when seeking to seekPos the next decoded frame will be i +    d->seekPositions.append( seekPos ); +  } + +  if( !d->handle->inputError() && !error ) { +    // we need the length of the track to be multiple of frames (1/75 second) +    float seconds = (float)d->handle->madTimer->seconds + +      (float)d->handle->madTimer->fraction/(float)MAD_TIMER_RESOLUTION; +    frames = (unsigned long)ceil(seconds * 75.0); +    kdDebug() << "(K3bMadDecoder) length of track " << seconds << endl; +  } + +  cleanup(); + +  kdDebug() << "(K3bMadDecoder::countFrames) end" << endl; + +  return frames; +} + + +int K3bMadDecoder::decodeInternal( char* _data, int maxLen ) +{ +  d->outputBuffer = _data; +  d->outputBufferEnd = d->outputBuffer + maxLen; +  d->outputPointer = d->outputBuffer; + +  bool bOutputBufferFull = false; + +  while( !bOutputBufferFull && d->handle->fillStreamBuffer() ) { + +    // a mad_synth contains of the data of one mad_frame +    // one mad_frame represents a mp3-frame which is always 1152 samples +    // for us that means we need 4*1152 bytes of output buffer for every frame +    // since one sample has 16 bit +    if( d->outputBufferEnd - d->outputPointer < 4*1152 ) { +      bOutputBufferFull = true; +    } +    else if( d->handle->decodeNextFrame() ) { +      // +      // Once decoded the frame is synthesized to PCM samples. No errors +      // are reported by mad_synth_frame(); +      // +      mad_synth_frame( d->handle->madSynth, d->handle->madFrame ); + +      // this fills the output buffer +      if( !createPcmSamples( d->handle->madSynth ) ) { +	return -1; +      } +    } +    else if( d->handle->inputError() ) { +      return -1; +    } +  } + +  // flush the output buffer +  size_t buffersize = d->outputPointer - d->outputBuffer; + +  return buffersize; +} + + +unsigned short K3bMadDecoder::linearRound( mad_fixed_t fixed ) +{ +  // round +  fixed += (1L << ( MAD_F_FRACBITS - 16 )); + +  // clip +  if( fixed >= MAD_F_ONE - 1 ) +    fixed = MAD_F_ONE - 1; +  else if( fixed < -MAD_F_ONE ) +    fixed = -MAD_F_ONE; + +  // quatisize +  return fixed >> (MAD_F_FRACBITS + 1 - 16 ); +} + + +bool K3bMadDecoder::createPcmSamples( mad_synth* synth ) +{ +  unsigned short nsamples = synth->pcm.length; + +  // this should not happen since we only decode if the +  // output buffer has enough free space +  if( d->outputBufferEnd - d->outputPointer < nsamples*4 ) { +    kdDebug() <<  "(K3bMadDecoder) buffer overflow!" << endl; +    return false; +  } + +  // now create the output +  for( int i = 0; i < nsamples; i++ ) { + +    /* Left channel */ +    unsigned short sample = linearRound( synth->pcm.samples[0][i] ); +    *(d->outputPointer++) = (sample >> 8) & 0xff; +    *(d->outputPointer++) = sample & 0xff; + +    /* Right channel. If the decoded stream is monophonic then +     * the right output channel is the same as the left one. +     */ +    if( synth->pcm.channels == 2 ) +      sample = linearRound( synth->pcm.samples[1][i] ); + +    *(d->outputPointer++) = (sample >> 8) & 0xff; +    *(d->outputPointer++) = sample & 0xff; +  } // pcm conversion + +  return true; +} + + +void K3bMadDecoder::cleanup() +{ +  d->handle->cleanup(); +} + + +bool K3bMadDecoder::seekInternal( const K3b::Msf& pos ) +{ +  // +  // we need to reset the complete mad stuff +  // +  if( !initDecoderInternal() ) +    return false; + +  // +  // search a position +  // This is all hacking, I don't really know what I am doing here... ;) +  // +  double mp3FrameSecs = static_cast<double>(d->firstHeader.duration.seconds) +    + static_cast<double>(d->firstHeader.duration.fraction) / static_cast<double>(MAD_TIMER_RESOLUTION); + +  double posSecs = static_cast<double>(pos.totalFrames()) / 75.0; + +  // seekPosition to seek after frame i +  unsigned int frame = static_cast<unsigned int>( posSecs / mp3FrameSecs ); + +  // Rob said: 29 frames is the theoretically max frame reservoir limit (whatever that means...) +  // it seems that mad needs at most 29 frames to get ready +  unsigned int frameReservoirProtect = ( frame > 29 ? 29 : frame ); + +  frame -= frameReservoirProtect; + +  // seek in the input file behind the already decoded data +  d->handle->inputSeek( d->seekPositions[frame] ); + +  kdDebug() << "(K3bMadDecoder) Seeking to frame " << frame << " with " +	    << frameReservoirProtect << " reservoir frames." << endl; + +  // decode some frames ignoring MAD_ERROR_BADDATAPTR errors +  unsigned int i = 1; +  while( i <= frameReservoirProtect ) { +    d->handle->fillStreamBuffer(); +    if( mad_frame_decode( d->handle->madFrame, d->handle->madStream ) ) { +      if( MAD_RECOVERABLE( d->handle->madStream->error ) ) { +	if( d->handle->madStream->error == MAD_ERROR_BUFLEN ) +	  continue; +	else if( d->handle->madStream->error != MAD_ERROR_BADDATAPTR ) { +	  kdDebug() << "(K3bMadDecoder) Seeking: recoverable mad error (" +		    << mad_stream_errorstr(d->handle->madStream) << ")" << endl; +	  continue; +	} +	else { +	  kdDebug() << "(K3bMadDecoder) Seeking: ignoring (" +		    << mad_stream_errorstr(d->handle->madStream) << ")" << endl; +	} +      } +      else +	return false; +    } + +    if( i == frameReservoirProtect )  // synth only the last frame (Rob said so ;) +      mad_synth_frame( d->handle->madSynth, d->handle->madFrame ); + +    ++i; +  } + +  return true; +} + + +QString K3bMadDecoder::fileType() const +{ +  switch( d->firstHeader.layer ) { +  case MAD_LAYER_I: +    return "MPEG1 Layer I"; +  case MAD_LAYER_II: +    return "MPEG1 Layer II"; +  case MAD_LAYER_III: +    return "MPEG1 Layer III"; +  default: +    return "Mp3"; +  } +} + +QStringList K3bMadDecoder::supportedTechnicalInfos() const +{ +  return QStringList::split( ";", +			     i18n("Channels") + ";" + +			     i18n("Sampling Rate") + ";" + +			     i18n("Bitrate") + ";" + +			     i18n("Layer") + ";" + +			     i18n("Emphasis") + ";" + +			     i18n("Copyright") + ";" + +			     i18n("Original") + ";" + +			     i18n("CRC") ); +} + + +QString K3bMadDecoder::technicalInfo( const QString& name ) const +{ +  if( name == i18n("Channels") ) { +    switch( d->firstHeader.mode ) { +    case MAD_MODE_SINGLE_CHANNEL: +      return i18n("Mono"); +    case MAD_MODE_DUAL_CHANNEL: +      return i18n("Dual"); +    case MAD_MODE_JOINT_STEREO: +      return i18n("Joint Stereo"); +    case MAD_MODE_STEREO: +      return i18n("Stereo"); +    default: +      return "?"; +    } +  } +  else if( name == i18n("Sampling Rate") ) +    return i18n("%1 Hz").arg(d->firstHeader.samplerate); +  else if( name == i18n("Bitrate") ) { +    if( d->vbr ) +      return i18n("VBR"); +    else +      return i18n("%1 bps").arg(d->firstHeader.bitrate); +  } +  else if(  name == i18n("Layer") ){ +    switch( d->firstHeader.layer ) { +    case MAD_LAYER_I: +      return "I"; +    case MAD_LAYER_II: +      return "II"; +    case MAD_LAYER_III: +      return "III"; +    default: +      return "?"; +    } +  } +  else if( name == i18n("Emphasis") ) { +    switch( d->firstHeader.emphasis ) { +    case MAD_EMPHASIS_NONE: +      return i18n("None"); +    case MAD_EMPHASIS_50_15_US: +      return i18n("50/15 ms"); +    case MAD_EMPHASIS_CCITT_J_17: +      return i18n("CCITT J.17"); +    default: +      return i18n("Unknown"); +    } +  } +  else if( name == i18n("Copyright") ) +    return ( d->firstHeader.flags & MAD_FLAG_COPYRIGHT ? i18n("Yes") : i18n("No") ); +  else if( name == i18n("Original") ) +    return ( d->firstHeader.flags & MAD_FLAG_ORIGINAL ? i18n("Yes") : i18n("No") ); +  else if( name == i18n("CRC") ) +    return ( d->firstHeader.flags & MAD_FLAG_PROTECTION ? i18n("Yes") : i18n("No") ); +  else +    return QString::null; +} + + +K3bMadDecoderFactory::K3bMadDecoderFactory( QObject* parent, const char* name ) +  : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bMadDecoderFactory::~K3bMadDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bMadDecoderFactory::createDecoder( QObject* parent, +						      const char* name ) const +{ +  return new K3bMadDecoder( parent, name ); +} + + +bool K3bMadDecoderFactory::canDecode( const KURL& url ) +{ +  // +  // HACK: +  // +  // I am simply no good at this and this detection code is no good as well +  // It always takes waves for mp3 files so we introduce this hack to +  // filter out wave files. :( +  // +  QFile f( url.path() ); +  if( !f.open( IO_ReadOnly ) ) +    return false; +  char buffer[12]; +  if( f.readBlock( buffer, 12 ) != 12 ) +    return false; +  if( !qstrncmp( buffer, "RIFF", 4 ) && +      !qstrncmp( buffer + 8, "WAVE", 4 ) ) +    return false; +  f.close(); + + +  K3bMad handle; +  if( !handle.open( url.path() ) ) +    return false; + +  handle.skipTag(); +  if( !handle.seekFirstHeader() ) +    return false; + +  if( handle.findNextHeader() ) { +    int c = MAD_NCHANNELS( &handle.madFrame->header ); +    int layer = handle.madFrame->header.layer; +    unsigned int s = handle.madFrame->header.samplerate; + +    // +    // find 4 more mp3 headers (random value since 2 was not enough) +    // This way we get most of the mp3 files while sorting out +    // for example wave files. +    // +    int cnt = 1; +    while( handle.findNextHeader() ) { +      // compare the found headers +      if( MAD_NCHANNELS( &handle.madFrame->header ) == c && +	  handle.madFrame->header.layer == layer && +	  handle.madFrame->header.samplerate == s ) { +	// only support layer III for now since otherwise some wave files +	// are taken for layer I +	if( ++cnt >= 5 ) { +	  kdDebug() << "(K3bMadDecoder) valid mpeg 1 layer " << layer +		    << " file with " << c << " channels and a samplerate of " +		    << s << endl; +	  return ( layer == MAD_LAYER_III ); +	} +      } +      else +	break; +    } +  } + +  kdDebug() << "(K3bMadDecoder) unsupported format: " << url.path() << endl; + +  return false; +} + +#include "k3bmaddecoder.moc" diff --git a/plugins/decoder/mp3/k3bmaddecoder.h b/plugins/decoder/mp3/k3bmaddecoder.h new file mode 100644 index 0000000..91e0f6c --- /dev/null +++ b/plugins/decoder/mp3/k3bmaddecoder.h @@ -0,0 +1,79 @@ +/*  + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef K3BMP3MODULE_H +#define K3BMP3MODULE_H + + +#include <k3baudiodecoder.h> + +extern "C" { +#include <mad.h> +} + + +class K3bMadDecoderFactory : public K3bAudioDecoderFactory +{ +  Q_OBJECT + + public: +  K3bMadDecoderFactory( QObject* parent = 0, const char* name = 0 ); +  ~K3bMadDecoderFactory(); + +  bool canDecode( const KURL& filename ); + +  int pluginSystemVersion() const { return 3; } + +  K3bAudioDecoder* createDecoder( QObject* parent = 0,  +				  const char* name = 0 ) const; +}; + + +class K3bMadDecoder : public K3bAudioDecoder +{ +  Q_OBJECT + + public: +  K3bMadDecoder( QObject* parent = 0, const char* name = 0 ); +  ~K3bMadDecoder(); + +  QString metaInfo( MetaDataField ); + +  void cleanup(); + +  bool seekInternal( const K3b::Msf& ); + +  QString fileType() const; +  QStringList supportedTechnicalInfos() const; +  QString technicalInfo( const QString& ) const; + + protected: +  bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); +  bool initDecoderInternal(); + +  int decodeInternal( char* _data, int maxLen ); +  + private: +  unsigned long countFrames(); +  inline unsigned short linearRound( mad_fixed_t fixed ); +  bool createPcmSamples( mad_synth* ); + +  static int MaxAllowedRecoverableErrors; + +  class MadDecoderPrivate; +  MadDecoderPrivate* d; +}; + +#endif diff --git a/plugins/decoder/mp3/k3bmaddecoder.plugin b/plugins/decoder/mp3/k3bmaddecoder.plugin new file mode 100644 index 0000000..69fbbb8 --- /dev/null +++ b/plugins/decoder/mp3/k3bmaddecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bmaddecoder +Group=AudioDecoder +Name=K3b MAD Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=3.1 +Comment=Decoding module to decode MPEG 1 Layer III files +License=GPL diff --git a/plugins/decoder/musepack/Makefile.am b/plugins/decoder/musepack/Makefile.am new file mode 100644 index 0000000..beb7d63 --- /dev/null +++ b/plugins/decoder/musepack/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/plugin \ +	-I$(srcdir)/../../../libk3b/core \ +	-I$(srcdir)/../../../libk3bdevice \ +	$(all_includes) + +kde_module_LTLIBRARIES = libk3bmpcdecoder.la + +libk3bmpcdecoder_la_SOURCES = k3bmpcdecoder.cpp k3bmpcwrapper.cpp + +libk3bmpcdecoder_la_LIBADD = ../../../libk3b/libk3b.la $(MPC_LIBS) +libk3bmpcdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bmpcdecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/musepack/configure.in.bot b/plugins/decoder/musepack/configure.in.bot new file mode 100644 index 0000000..8fb871b --- /dev/null +++ b/plugins/decoder/musepack/configure.in.bot @@ -0,0 +1,12 @@ +echo "" + +if test x$have_mpc = xyes; then +	echo "K3b - Musepack support:                      yes" +else +	echo "K3b - Musepack support:                       no" +if test "$ac_cv_use_mpc" = "yes"; then +	echo "K3b -     You are missing the Musepack headers and libraries >= 1.1." +	echo "K3b -     The Musepack audio decoding plugin won't be compiled." +fi +fi + diff --git a/plugins/decoder/musepack/configure.in.in b/plugins/decoder/musepack/configure.in.in new file mode 100644 index 0000000..42d24c0 --- /dev/null +++ b/plugins/decoder/musepack/configure.in.in @@ -0,0 +1,52 @@ +dnl --------- MUSEPACK CHECK --------------- + +AC_ARG_WITH( +	musepack,  +	AS_HELP_STRING( +		[--without-musepack],  +		[build K3b without Musepack audio support (default=no)]), +	[ac_cv_use_mpc=$withval],  +	[ac_cv_use_mpc=yes] +) + +have_mpc=no +if test "$ac_cv_use_mpc" = "yes"; then + +  dnl - search for both the new and the old naming - + +  KDE_CHECK_HEADERS(mpcdec/mpcdec.h, [ +  	AC_CHECK_LIB(mpcdec, mpc_decoder_setup, [ +  		have_mpc=yes +		MPC_LIBS="-lmpcdec" +		AC_DEFINE( +			MPC_HEADER_FILE,  +			<mpcdec/mpcdec.h>,  +			[The header to include for MPC decoding.]) +		], +		[], [], []) +  ]) +	 +  if test "$have_mpc" = "no"; then +    KDE_CHECK_HEADERS(musepack/musepack.h, [ +    	  AC_CHECK_LIB(musepack, mpc_decoder_setup, [ +  		  have_mpc=yes +		  MPC_LIBS="-lmusepack" +		  AC_DEFINE( +			  MPC_HEADER_FILE,  +			  <musepack/musepack.h>,  +			  [The header to include for MPC decoding.] +		  ) +		  AC_DEFINE( +			  mpc_bool_t, +			  BOOL, +			  [backwards compatibility stuff] +		  ) +  		  ], [], []) +    ]) +  fi +fi +AC_SUBST(MPC_LIBS) + +AM_CONDITIONAL(include_MPC, [test x$have_mpc = xyes]) + +dnl --------- MUSEPACK CHECK END ----------- diff --git a/plugins/decoder/musepack/k3bmpcdecoder.cpp b/plugins/decoder/musepack/k3bmpcdecoder.cpp new file mode 100644 index 0000000..0cdf644 --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcdecoder.cpp @@ -0,0 +1,111 @@ +/*  + * + * $Id: k3bmpcdecoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bmpcdecoder.h" +#include "k3bmpcwrapper.h" + +#include <k3bpluginfactory.h> + +#include <klocale.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3bmpcdecoder, K3bPluginFactory<K3bMpcDecoderFactory>( "libk3bmpcdecoder" ) ) + + +K3bMpcDecoderFactory::K3bMpcDecoderFactory( QObject* parent, const char* name ) +  : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bMpcDecoderFactory::~K3bMpcDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bMpcDecoderFactory::createDecoder( QObject* parent,  +							 const char* name ) const +{ +  return new K3bMpcDecoder( parent, name ); +} + + +bool K3bMpcDecoderFactory::canDecode( const KURL& url ) +{ +  K3bMpcWrapper w; +  return w.open( url.path() ); +} + + + + + + +K3bMpcDecoder::K3bMpcDecoder( QObject* parent, const char* name ) +  : K3bAudioDecoder( parent, name ) +{ +  m_mpc = new K3bMpcWrapper(); +} + + +K3bMpcDecoder::~K3bMpcDecoder() +{ +  delete m_mpc; +} + + +QString K3bMpcDecoder::fileType() const +{ +  return i18n("Musepack"); +} + + +bool K3bMpcDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ +  if( m_mpc->open( filename() ) ) { +    frames = m_mpc->length(); +    samplerate = m_mpc->samplerate(); +    ch = m_mpc->channels(); + +    // call addTechnicalInfo and addMetaInfo here + +    return true; +  } +  else +    return false; +} + + +bool K3bMpcDecoder::initDecoderInternal() +{ +  return m_mpc->open( filename() ); +} + + +bool K3bMpcDecoder::seekInternal( const K3b::Msf& msf ) +{ +  return m_mpc->seek( msf ); +} + + +int K3bMpcDecoder::decodeInternal( char* _data, int maxLen ) +{ +  return m_mpc->decode( _data, maxLen ); +} + + +#include "k3bmpcdecoder.moc" diff --git a/plugins/decoder/musepack/k3bmpcdecoder.h b/plugins/decoder/musepack/k3bmpcdecoder.h new file mode 100644 index 0000000..74dc509 --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcdecoder.h @@ -0,0 +1,62 @@ +/*  + * + * $Id: k3bmpcdecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MPC_DECODER_H_ +#define _K3B_MPC_DECODER_H_ + +#include <k3baudiodecoder.h> + +class K3bMpcWrapper; + + +class K3bMpcDecoderFactory : public K3bAudioDecoderFactory +{ +  Q_OBJECT + + public: +  K3bMpcDecoderFactory( QObject* parent = 0, const char* name = 0 ); +  ~K3bMpcDecoderFactory(); + +  bool canDecode( const KURL& filename ); + +  int pluginSystemVersion() const { return 3; } + +  K3bAudioDecoder* createDecoder( QObject* parent = 0,  +				  const char* name = 0 ) const; +}; + + +class K3bMpcDecoder : public K3bAudioDecoder +{ +  Q_OBJECT + + public: +  K3bMpcDecoder( QObject* parent = 0, const char* name = 0 ); +  ~K3bMpcDecoder(); + +  QString fileType() const; + + protected: +  bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); +  bool initDecoderInternal(); +  bool seekInternal( const K3b::Msf& ); + +  int decodeInternal( char* _data, int maxLen ); + + private: +  K3bMpcWrapper* m_mpc; +}; + +#endif diff --git a/plugins/decoder/musepack/k3bmpcdecoder.plugin b/plugins/decoder/musepack/k3bmpcdecoder.plugin new file mode 100644 index 0000000..6e350dc --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcdecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bmpcdecoder +Group=AudioDecoder +Name=K3b Musepack Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=1.0 +Comment=Decoding module to decode Musepack audio files +License=GPL diff --git a/plugins/decoder/musepack/k3bmpcwrapper.cpp b/plugins/decoder/musepack/k3bmpcwrapper.cpp new file mode 100644 index 0000000..9f54b28 --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcwrapper.cpp @@ -0,0 +1,193 @@ +/*  + * + * $Id: k3bmpcwrapper.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include "k3bmpcwrapper.h" + +#include <kdebug.h> +#include <qfile.h> + + +mpc_int32_t read_impl( void* data, void* ptr, mpc_int32_t size ) +{ +  QFile* input = static_cast<QFile*>( data ); +  return input->readBlock( (char*)ptr, size ); +} + + +mpc_bool_t seek_impl( void* data, mpc_int32_t offset ) +{ +  QFile* input = static_cast<QFile*>( data ); +  return input->at( offset ); +} + +mpc_int32_t tell_impl( void* data ) +{ +  QFile* input = static_cast<QFile*>( data ); +  return input->at(); +} + +mpc_int32_t get_size_impl( void* data ) +{ +  QFile* input = static_cast<QFile*>( data ); +  return input->size(); +} + +mpc_bool_t canseek_impl( void* ) +{ +  return true; +} + + +#ifdef MPC_FIXED_POINT +static int shift_signed( MPC_SAMPLE_FORMAT val, int shift ) +{ +  if(shift > 0) +    val <<= shift; +  else if(shift < 0) +    val >>= -shift; +  return (int) val; +} +#endif + + +K3bMpcWrapper::K3bMpcWrapper() +{ +  m_input = new QFile(); + +  m_reader           = new mpc_reader; +  m_reader->read     = read_impl; +  m_reader->seek     = seek_impl; +  m_reader->tell     = tell_impl; +  m_reader->get_size = get_size_impl; +  m_reader->canseek  = canseek_impl; +  m_reader->data     = m_input; + +  m_decoder          = new mpc_decoder; + +  m_info             = new mpc_streaminfo; +} + + +K3bMpcWrapper::~K3bMpcWrapper() +{ +  close(); + +  delete m_reader; +  delete m_decoder; +  delete m_info; +  delete m_input; +} + + +bool K3bMpcWrapper::open( const QString& filename ) +{ +  close(); + +  m_input->setName( filename ); + +  if( m_input->open( IO_ReadOnly ) ) { +    mpc_streaminfo_init( m_info ); +    if( mpc_streaminfo_read( m_info, m_reader ) != ERROR_CODE_OK ) { +      kdDebug() << "(K3bMpcWrapper) Not a valid musepack file: \"" << filename << "\"" << endl; +      return false; +    } +    else { +      mpc_decoder_setup( m_decoder, m_reader ); +      if( !mpc_decoder_initialize( m_decoder, m_info ) ) { +	kdDebug() << "(K3bMpcWrapper) failed to initialize the Musepack decoder." << endl; +	close(); +	return false; +      } +      else { +	kdDebug() << "(K3bMpcWrapper) valid musepack file. "  +		  << channels() << " Channels and Samplerate: " << samplerate() << endl; +	return true; +      } +    } +  } +  else +    return false; +} + + +void K3bMpcWrapper::close() +{ +  m_input->close(); +} + + +int K3bMpcWrapper::decode( char* data, int max ) +{ +  // FIXME: make this a member variable +  MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH]; + +  unsigned int samples = mpc_decoder_decode( m_decoder, sample_buffer, 0, 0 ); + +  if( samples*channels()*2 > (unsigned int)max ) { +    kdDebug() << "(K3bMpcWrapper) buffer not big enough." << endl; +    return -1; +  } + +  static const unsigned int bps = 16; +  static const int clip_min = -1 << (bps - 1); +  static const int clip_max = (1 << (bps - 1)) - 1; +  static const int float_scale = 1 << (bps - 1); + +  for( unsigned int n = 0; n < samples*channels(); ++n ) { +    int val = 0; + +#ifdef MPC_FIXED_POINT +    val = shift_signed( sample_buffer[n], +			bps - MPC_FIXED_POINT_SCALE_SHIFT); +#else +    val = (int)(sample_buffer[n] * float_scale); +#endif + +    if( val < clip_min ) +      val = clip_min; +    else if( val > clip_max ) +      val = clip_max; + +    data[2*n]   = (val>>8) & 0xff; +    data[2*n+1] = val & 0xff; +  } + +  return samples*channels()*2; +} + + +bool K3bMpcWrapper::seek( const K3b::Msf& msf ) +{ +  return mpc_decoder_seek_seconds( m_decoder, (double)msf.totalFrames()/75.0 ); +} + + +K3b::Msf K3bMpcWrapper::length() const +{ +  return K3b::Msf::fromSeconds( mpc_streaminfo_get_length( m_info ) ); +} + + +int K3bMpcWrapper::samplerate() const +{ +  return m_info->sample_freq; +} + + +unsigned int K3bMpcWrapper::channels() const +{ +  return m_info->channels; +} + diff --git a/plugins/decoder/musepack/k3bmpcwrapper.h b/plugins/decoder/musepack/k3bmpcwrapper.h new file mode 100644 index 0000000..743e25f --- /dev/null +++ b/plugins/decoder/musepack/k3bmpcwrapper.h @@ -0,0 +1,58 @@ +/*  + * + * $Id: k3bmpcwrapper.h 630384 2007-02-05 09:33:17Z mlaurent $ + * Copyright (C) 2005 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_MPC_WRAPPER_H_ +#define _K3B_MPC_WRAPPER_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qstring.h> + +#include <k3bmsf.h> + +#include MPC_HEADER_FILE + +class QFile; + + +class K3bMpcWrapper +{ + public: +  K3bMpcWrapper(); +  ~K3bMpcWrapper(); + +  bool open( const QString& filename ); +  void close(); + +  int decode( char*, int max ); + +  bool seek( const K3b::Msf& ); + +  K3b::Msf length() const; +  int samplerate() const; +  unsigned int channels() const; + +  QFile* input() const { return m_input; } + + private: +  QFile* m_input; +  mpc_reader* m_reader; +  mpc_decoder* m_decoder; +  mpc_streaminfo* m_info; +}; + +#endif diff --git a/plugins/decoder/ogg/Makefile.am b/plugins/decoder/ogg/Makefile.am new file mode 100644 index 0000000..6705be2 --- /dev/null +++ b/plugins/decoder/ogg/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3boggvorbisdecoder.la + +libk3boggvorbisdecoder_la_SOURCES = k3boggvorbisdecoder.cpp + +libk3boggvorbisdecoder_la_LIBADD = ../../../libk3b/libk3b.la -logg -lvorbis -lvorbisfile  +libk3boggvorbisdecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3boggvorbisdecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/ogg/configure.in.bot b/plugins/decoder/ogg/configure.in.bot new file mode 100644 index 0000000..b27ab18 --- /dev/null +++ b/plugins/decoder/ogg/configure.in.bot @@ -0,0 +1,11 @@ +echo "" + +if test x$ogg_vorbis = xyes; then +	echo "K3b - Ogg Vorbis support:                    yes" +else +	echo "K3b - Ogg Vorbis support:                     no" +if test "$ac_cv_use_oggvorbis" = "yes"; then +	echo "K3b -     You are missing the Ogg-Vorbis headers and libraries." +	echo "K3b -     The Ogg Vorbis decoding and encoding plugins won't be compiled." +fi +fi diff --git a/plugins/decoder/ogg/configure.in.in b/plugins/decoder/ogg/configure.in.in new file mode 100644 index 0000000..69b1b9c --- /dev/null +++ b/plugins/decoder/ogg/configure.in.in @@ -0,0 +1,32 @@ +dnl === Ogg Vorbis Test - Begin === +AC_ARG_WITH( +	oggvorbis,  +	AS_HELP_STRING([--without-oggvorbis], [build K3b without OggVorbis support (default=no)]),  +	[ac_cv_use_oggvorbis=$withval],  +	[ac_cv_use_oggvorbis=yes] +) + +if test "$ac_cv_use_oggvorbis" = "yes"; then + +  AC_MSG_CHECKING(for ogg/vorbis headers) +  ogg_vorbis=no +  AC_TRY_COMPILE([ +  		#include <vorbis/codec.h> +  		#include <vorbis/vorbisfile.h> +                ],[ +                ],[ +                ogg_vorbis=yes +                ]) +  AC_MSG_RESULT($ogg_vorbis) +  if test x$ogg_vorbis = xyes; then +     dnl we need the ogg_vorbis_lib because otherwise we override LIBS ! +     AC_CHECK_LIB(vorbisfile,ov_open,ogg_vorbis_lib=yes, +                  ogg_vorbis=no,[$all_libraries -lvorbisfile -lvorbis -logg]) +  fi +  if test x$ogg_vorbis = xyes; then +	AC_DEFINE(OGG_VORBIS,1,[Define if you have ogg/vorbis installed]) +  fi +fi + +AM_CONDITIONAL(include_OGG, [test x$ogg_vorbis = xyes]) +dnl === Ogg Vorbis Test - End === diff --git a/plugins/decoder/ogg/k3boggvorbisdecoder.cpp b/plugins/decoder/ogg/k3boggvorbisdecoder.cpp new file mode 100644 index 0000000..15ca665 --- /dev/null +++ b/plugins/decoder/ogg/k3boggvorbisdecoder.cpp @@ -0,0 +1,252 @@ +/*  + * + * $Id$ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3boggvorbisdecoder.h" + +#include <k3bpluginfactory.h> + +#include <qfile.h> +#include <qstringlist.h> + +#include <kurl.h> +#include <kdebug.h> +#include <klocale.h> + +#include <stdio.h> +#include <stdlib.h> +#include <vorbis/codec.h> +#include <vorbis/vorbisfile.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3boggvorbisdecoder, K3bPluginFactory<K3bOggVorbisDecoderFactory>( "libk3boggvorbisdecoder" ) ) + + +class K3bOggVorbisDecoder::Private +{ +public: +  Private() +    : vInfo(0), +      vComment(0), +      isOpen(false) { +  } + +  OggVorbis_File oggVorbisFile; +  vorbis_info* vInfo; +  vorbis_comment* vComment; +  bool isOpen; +}; + + +K3bOggVorbisDecoder::K3bOggVorbisDecoder( QObject* parent, const char* name ) +  : K3bAudioDecoder( parent, name ) +{ +  d = new Private(); +} + + +K3bOggVorbisDecoder::~K3bOggVorbisDecoder() +{ +  delete d; +} + + +bool K3bOggVorbisDecoder::openOggVorbisFile() +{ +  if( !d->isOpen ) { +    FILE* file = fopen( QFile::encodeName(filename()), "r" ); +    if( !file ) { +      kdDebug() << "(K3bOggVorbisDecoder) Could not open file " << filename() << endl; +      return false; +    } +    else if( ov_open( file, &d->oggVorbisFile, 0, 0 ) ) { +      kdDebug() << "(K3bOggVorbisDecoder) " << filename()  +		<< " seems not to to be an ogg vorbis file." << endl; +      fclose( file ); +      return false; +    } +  } + +  d->isOpen = true; +  return true; +} + + +bool K3bOggVorbisDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ +  cleanup(); + +  if( openOggVorbisFile() ) { +    // check length of track +    double seconds = ov_time_total( &d->oggVorbisFile, -1 ); +    if( seconds == OV_EINVAL ) { +      kdDebug() << "(K3bOggVorbisDecoder) Could not determine length of file " << filename() << endl; +      cleanup(); +      return false; +    } +    else { + +      d->vInfo = ov_info( &d->oggVorbisFile, -1 /* current bitstream */ ); +      d->vComment = ov_comment( &d->oggVorbisFile, -1 ); + +      // add meta tags +      for( int i = 0; i < d->vComment->comments; ++i ) { +	QString comment = QString::fromUtf8( d->vComment->user_comments[i] ); +	QStringList values = QStringList::split( "=", comment ); +	if( values.count() > 1 ) { +	  if( values[0].lower() == "title" ) +	    addMetaInfo( META_TITLE, values[1] ); +	  else if( values[0].lower() == "artist" ) +	    addMetaInfo( META_ARTIST, values[1] ); +	  else if( values[0].lower() == "description" ) +	    addMetaInfo( META_COMMENT, values[1] ); +	} +      } + + +      // add technical infos +      addTechnicalInfo( i18n("Version"), QString::number(d->vInfo->version) ); +      addTechnicalInfo( i18n("Channels"), QString::number(d->vInfo->channels) ); +      addTechnicalInfo( i18n("Sampling Rate"), i18n("%1 Hz").arg(d->vInfo->rate) ); +      if( d->vInfo->bitrate_upper > 0 ) +	addTechnicalInfo( i18n("Bitrate Upper"), i18n( "%1 bps" ).arg(d->vInfo->bitrate_upper) ); +      if( d->vInfo->bitrate_nominal > 0 ) +	addTechnicalInfo( i18n("Bitrate Nominal"), i18n( "%1 bps" ).arg(d->vInfo->bitrate_nominal) ); +      if( d->vInfo->bitrate_lower > 0 ) +	addTechnicalInfo( i18n("Bitrate Lower"), i18n( "%1 bps" ).arg(d->vInfo->bitrate_lower) ); + +      frames = K3b::Msf::fromSeconds(seconds); +      samplerate = d->vInfo->rate; +      ch = d->vInfo->channels; + +      cleanup(); + +      return true; +    } +  } +  else +    return false; +} + + +bool K3bOggVorbisDecoder::initDecoderInternal() +{ +  cleanup(); +  return openOggVorbisFile(); +} + + +int K3bOggVorbisDecoder::decodeInternal( char* data, int maxLen ) +{ +  int bitStream = 0; +  long bytesRead = ov_read( &d->oggVorbisFile,  +			    data, +			    maxLen,  // max length to be read +			    1,                   // big endian +			    2,                   // word size: 16-bit samples +			    1,                   // signed +			    &bitStream );        // current bitstream + +  if( bitStream != 0 ) { +    kdDebug() << "(K3bOggVorbisDecoder) bitstream != 0. Multible bitstreams not supported." << endl; +    return -1; +  } +   +  else if( bytesRead == OV_HOLE ) { +    kdDebug() << "(K3bOggVorbisDecoder) OV_HOLE" << endl; +    // recursive new try +    return decodeInternal( data, maxLen ); +  } + +  else if( bytesRead < 0 ) { +    kdDebug() << "(K3bOggVorbisDecoder) Error: " << bytesRead << endl; +    return -1; +  } + +  else if( bytesRead == 0 ) { +    kdDebug() << "(K3bOggVorbisDecoder) successfully finished decoding." << endl; +    return 0; +  } + +  else { +    return bytesRead; +  } +} + + +void K3bOggVorbisDecoder::cleanup() +{ +  if( d->isOpen ) +    ov_clear( &d->oggVorbisFile ); +  d->isOpen = false; +  d->vComment = 0; +  d->vInfo = 0; +} + + +bool K3bOggVorbisDecoder::seekInternal( const K3b::Msf& pos ) +{ +  return ( ov_pcm_seek( &d->oggVorbisFile, pos.pcmSamples() ) == 0 ); +} + + +QString K3bOggVorbisDecoder::fileType() const +{ +  return i18n("Ogg-Vorbis"); +} + + +K3bOggVorbisDecoderFactory::K3bOggVorbisDecoderFactory( QObject* parent, const char* name ) +  : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bOggVorbisDecoderFactory::~K3bOggVorbisDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bOggVorbisDecoderFactory::createDecoder( QObject* parent,  +							    const char* name ) const +{ +  return new K3bOggVorbisDecoder( parent, name ); +} + + +bool K3bOggVorbisDecoderFactory::canDecode( const KURL& url ) +{ +  FILE* file = fopen( QFile::encodeName(url.path()), "r" ); +  if( !file ) { +    kdDebug() << "(K3bOggVorbisDecoder) Could not open file " << url.path() << endl; +    return false; +  } + +  OggVorbis_File of; + +  if( ov_open( file, &of, 0, 0 ) ) { +    fclose( file ); +    kdDebug() << "(K3bOggVorbisDecoder) not an Ogg-Vorbis file: " << url.path() << endl; +    return false; +  } + +  ov_clear( &of ); + +  return true; +} + + +#include "k3boggvorbisdecoder.moc" diff --git a/plugins/decoder/ogg/k3boggvorbisdecoder.h b/plugins/decoder/ogg/k3boggvorbisdecoder.h new file mode 100644 index 0000000..20ae094 --- /dev/null +++ b/plugins/decoder/ogg/k3boggvorbisdecoder.h @@ -0,0 +1,72 @@ +/*  + * + * $Id: k3boggvorbisdecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + + +#ifndef _K3B_OGGVORBIS_DECODER_H_ +#define _K3B_OGGVORBIS_DECODER_H_ + + +#include <k3baudiodecoder.h> + +class KURL; + + +class K3bOggVorbisDecoderFactory : public K3bAudioDecoderFactory +{ +  Q_OBJECT + + public: +  K3bOggVorbisDecoderFactory( QObject* parent = 0, const char* name = 0 ); +  ~K3bOggVorbisDecoderFactory(); + +  bool canDecode( const KURL& filename ); + +  int pluginSystemVersion() const { return 3; } + +  K3bAudioDecoder* createDecoder( QObject* parent = 0,  +				  const char* name = 0 ) const; +}; + + +/** +  *@author Sebastian Trueg +  */ +class K3bOggVorbisDecoder : public K3bAudioDecoder +{ +  Q_OBJECT + + public:  +  K3bOggVorbisDecoder( QObject* parent = 0, const char* name = 0 ); +  ~K3bOggVorbisDecoder(); + +  void cleanup(); + +  QString fileType() const; + + protected: +  bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); +  bool initDecoderInternal(); +  bool seekInternal( const K3b::Msf& ); + +  int decodeInternal( char* _data, int maxLen ); + + private: +  bool openOggVorbisFile(); + +  class Private; +  Private* d; +}; + +#endif diff --git a/plugins/decoder/ogg/k3boggvorbisdecoder.plugin b/plugins/decoder/ogg/k3boggvorbisdecoder.plugin new file mode 100644 index 0000000..0f1c48e --- /dev/null +++ b/plugins/decoder/ogg/k3boggvorbisdecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3boggvorbisdecoder +Group=AudioDecoder +Name=K3b Ogg Vorbis Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=3.0 +Comment=Decoding module to decode Ogg Vorbis files +License=GPL diff --git a/plugins/decoder/skeleton.cpp b/plugins/decoder/skeleton.cpp new file mode 100644 index 0000000..940814b --- /dev/null +++ b/plugins/decoder/skeleton.cpp @@ -0,0 +1,101 @@ +/*  + * + * $Id: skeleton.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3b<name>decoder.h" + +#include <k3bpluginfactory.h> + + +K_EXPORT_COMPONENT_FACTORY( libk3b<name>decoder, K3bPluginFactory<K3b<name>DecoderFactory>( "libk3b<name>decoder" ) ) + + +K3b<name>DecoderFactory::K3b<name>DecoderFactory( QObject* parent, const char* name ) +  : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3b<name>DecoderFactory::~K3b<name>DecoderFactory() +{ +} + + +K3bAudioDecoder* K3b<name>DecoderFactory::createDecoder( QObject* parent,  +							 const char* name ) const +{ +  return new K3b<name>Decoder( parent, name ); +} + + +bool K3b<name>DecoderFactory::canDecode( const KURL& url ) +{ +  // PUT YOUR CODE HERE +  return false; +} + + + + + + +K3b<name>Decoder::K3b<name>Decoder( QObject* parent, const char* name ) +  : K3bAudioDecoder( parent, name ) +{ +} + + +K3b<name>Decoder::~K3b<name>Decoder() +{ +} + + +QString K3b<name>Decoder::fileType() const +{ +  // PUT YOUR CODE HERE +} + + +bool K3b<name>Decoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ) +{ +  // PUT YOUR CODE HERE +  // call addTechnicalInfo and addMetaInfo here +  return false; +} + + +bool K3b<name>Decoder::initDecoderInternal() +{ +  // PUT YOUR CODE HERE +  return false; +} + + +bool K3b<name>Decoder::seekInternal( const K3b::Msf& ) +{ +  // PUT YOUR CODE HERE +  return false; +} + + +int K3b<name>Decoder::decodeInternal( char* _data, int maxLen ) +{ +  // PUT YOUR CODE HERE +  return -1; +} + + +#include "k3b<name>decoder.moc" diff --git a/plugins/decoder/skeleton.h b/plugins/decoder/skeleton.h new file mode 100644 index 0000000..00f5d15 --- /dev/null +++ b/plugins/decoder/skeleton.h @@ -0,0 +1,57 @@ +/*  + * + * $Id: skeleton.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_<name>_DECODER_H_ +#define _K3B_<name>_DECODER_H_ + +#include <k3baudiodecoder.h> + + +class K3b<name>DecoderFactory : public K3bAudioDecoderFactory +{ +  Q_OBJECT + + public: +  K3b<name>DecoderFactory( QObject* parent = 0, const char* name = 0 ); +  ~K3b<name>DecoderFactory(); + +  bool canDecode( const KURL& filename ); + +  int pluginSystemVersion() const { return 3; } + +  K3bAudioDecoder* createDecoder( QObject* parent = 0,  +				  const char* name = 0 ) const; +}; + + +class K3b<name>Decoder : public K3bAudioDecoder +{ +  Q_OBJECT + + public: +  K3b<name>Decoder( QObject* parent = 0, const char* name = 0 ); +  ~K3b<name>Decoder(); + +  QString fileType() const; + + protected: +  bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& ch ); +  bool initDecoderInternal(); +  bool seekInternal( const K3b::Msf& ); + +  int decodeInternal( char* _data, int maxLen ); +}; + +#endif diff --git a/plugins/decoder/skeleton.plugin b/plugins/decoder/skeleton.plugin new file mode 100644 index 0000000..c9bc0f4 --- /dev/null +++ b/plugins/decoder/skeleton.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=lib<name>decoder +Group=AudioDecoder +Name=K3b ??? Decoder +Author=??? +Email=??? +Version=0.1 +Comment=Decoding module to decode ??? files +License=??? diff --git a/plugins/decoder/wave/Makefile.am b/plugins/decoder/wave/Makefile.am new file mode 100644 index 0000000..5debea1 --- /dev/null +++ b/plugins/decoder/wave/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../libk3b/plugin -I$(srcdir)/../../../libk3b/core -I$(srcdir)/../../../libk3bdevice $(all_includes) + +kde_module_LTLIBRARIES = libk3bwavedecoder.la + +libk3bwavedecoder_la_SOURCES = k3bwavedecoder.cpp + +libk3bwavedecoder_la_LIBADD = $(LIB_KDECORE) ../../../libk3b/libk3b.la +libk3bwavedecoder_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/k3b/plugins +plugins_DATA = k3bwavedecoder.plugin + +METASOURCES = AUTO diff --git a/plugins/decoder/wave/k3bwavedecoder.cpp b/plugins/decoder/wave/k3bwavedecoder.cpp new file mode 100644 index 0000000..6494e5c --- /dev/null +++ b/plugins/decoder/wave/k3bwavedecoder.cpp @@ -0,0 +1,392 @@ +/*  + * + * $Id: k3bwavedecoder.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bwavedecoder.h" + +#include <k3bpluginfactory.h> + +#include <qfile.h> +#include <qcstring.h> + +#include <kdebug.h> +#include <klocale.h> + + + +K_EXPORT_COMPONENT_FACTORY( libk3bwavedecoder, K3bPluginFactory<K3bWaveDecoderFactory>( "libk3bwavedecoder" ) ) + + +static unsigned short le_a_to_u_short( unsigned char* a ) { +  return ((unsigned short)  +	  ((a[0]       & 0xFF) |  +	   (a[1] << 8  & 0xFF00)) ); +} + +static unsigned long le_a_to_u_long( unsigned char* a ) { +  return ((unsigned long)  +	  ((a[0]       & 0xFF) |  +	   (a[1] << 8  & 0xFF00) |  +	   (a[2] << 16 & 0xFF0000) |  +	   (a[3] << 24 & 0xFF000000)) ); +} + + +/** + * Returns the length of the wave file in bytes + * Otherwise 0 is returned. + * leave file seek pointer past WAV header. + */ +static unsigned long identifyWaveFile( QFile* f, int* samplerate = 0, int* channels = 0, int* samplesize = 0 ) +{ +  typedef struct { +    unsigned char	ckid[4]; +    unsigned char	cksize[4]; +  } chunk_t; + +  typedef struct { +    unsigned char	wave[4]; +  } riff_chunk; + +  typedef struct { +    unsigned char	fmt_tag[2]; +    unsigned char	channels[2]; +    unsigned char	sample_rate[4]; +    unsigned char	av_byte_rate[4]; +    unsigned char	block_size[2]; +    unsigned char	bits_per_sample[2]; +  } fmt_chunk; +  +  static const char* WAV_RIFF_MAGIC = "RIFF";		// Magic for file format +  static const char* WAV_WAVE_MAGIC = "WAVE";		// Magic for Waveform Audio +  static const char* WAV_FMT_MAGIC  = "fmt ";		// Start of Waveform format +  static const char* WAV_DATA_MAGIC = "data";		// Start of data chunk + +  chunk_t chunk; +  riff_chunk riff; +  fmt_chunk fmt; + + +  // read riff chunk +  if( f->readBlock( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) { +    kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; +    return 0; +  } +  if( qstrncmp( (char*)chunk.ckid, WAV_RIFF_MAGIC, 4 ) ) { +    kdDebug() << "(K3bWaveDecoder) " << f->name() << ": not a RIFF file." << endl; +    return 0; +  } + +  // read wave chunk +  if( f->readBlock( (char*)&riff, sizeof(riff) ) != sizeof(riff) ) { +    kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; +    return 0; +  } +  if( qstrncmp( (char*)riff.wave, WAV_WAVE_MAGIC, 4 ) ) { +    kdDebug() << "(K3bWaveDecoder) " << f->name() << ": not a WAVE file." << endl; +    return 0; +  } + + +  // read fmt chunk +  if( f->readBlock( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) { +    kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; +    return 0; +  } +  if( qstrncmp( (char*)chunk.ckid, WAV_FMT_MAGIC, 4 ) ) { +    kdDebug() << "(K3bWaveDecoder) " << f->name() << ": could not find format chunk." << endl; +    return 0; +  } +  if( f->readBlock( (char*)&fmt, sizeof(fmt) ) != sizeof(fmt) ) { +    kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; +    return 0; +  } +  if( le_a_to_u_short(fmt.fmt_tag) != 1 || +      le_a_to_u_short(fmt.channels) > 2 || +      ( le_a_to_u_short(fmt.bits_per_sample) != 16 && +	le_a_to_u_short(fmt.bits_per_sample) != 8 ) ) { +    kdDebug() << "(K3bWaveDecoder) " << f->name() << ": wrong format:" << endl +	      << "                format:      " << le_a_to_u_short(fmt.fmt_tag) << endl +	      << "                channels:    " << le_a_to_u_short(fmt.channels) << endl +	      << "                samplerate:  " << le_a_to_u_long(fmt.sample_rate) << endl +	      << "                bits/sample: " << le_a_to_u_short(fmt.bits_per_sample) << endl; +    return 0; +  } + +  int sampleRate = le_a_to_u_long(fmt.sample_rate); +  int ch = le_a_to_u_short(fmt.channels); +  int sampleSize = le_a_to_u_short(fmt.bits_per_sample);; +  if( samplerate ) +    *samplerate = sampleRate; +  if( channels ) +    *channels = ch; +  if( samplesize ) +    *samplesize = sampleSize; + +  // skip all other (unknown) format chunk fields +  if( !f->at( f->at() + le_a_to_u_long(chunk.cksize) - sizeof(fmt) ) ) { +    kdDebug() << "(K3bWaveDecoder) " << f->name() << ": could not seek in file." << endl; +    return 0; +  } + + +  // find data chunk +  bool foundData = false; +  while( !foundData ) { +    if( f->readBlock( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) { +      kdDebug() << "(K3bWaveDecoder) unable to read from " << f->name() << endl; +      return 0; +    } + +    // skip chunk data of unknown chunk +    if( qstrncmp( (char*)chunk.ckid, WAV_DATA_MAGIC, 4 ) ) { +      kdDebug() << "(K3bWaveDecoder) skipping chunk: " << (char*)chunk.ckid << endl; +      if( !f->at( f->at() + le_a_to_u_long(chunk.cksize) ) ) { +        kdDebug() << "(K3bWaveDecoder) " << f->name() << ": could not seek in file." << endl; +        return 0; +      } +    } +    else +      foundData = true; +  } + +  // found data chunk +  unsigned long size = le_a_to_u_long(chunk.cksize); +  if( f->at() + size > (unsigned long)f->size() ) { +    kdDebug() << "(K3bWaveDecoder) " << f->name() << ": file length " << f->size()  +    << " does not match length from WAVE header " << f->at() << " + " << size +    << " - using actual length." << endl; +    size = (f->size() - f->at()); +  } + +  return size; +} + + +class K3bWaveDecoder::Private { +public: +  Private() +    : buffer(0), +      bufferSize(0) { +  } + +  QFile* file; + +  long headerLength; +  int sampleRate; +  int channels; +  int sampleSize; +  unsigned long size; +  unsigned long alreadyRead; + +  char* buffer; +  int bufferSize; +}; + + +K3bWaveDecoder::K3bWaveDecoder( QObject* parent, const char* name ) +  : K3bAudioDecoder( parent, name ) +{ +  d = new Private(); +  d->file = new QFile(); +} + + +K3bWaveDecoder::~K3bWaveDecoder() +{ +  delete d->file; +  delete d; +} + + +int K3bWaveDecoder::decodeInternal( char* _data, int maxLen ) +{ +  int read = 0; + +  maxLen = QMIN( maxLen, (int)(d->size - d->alreadyRead) ); + +  if( d->sampleSize == 16 ) { +    read = d->file->readBlock( _data, maxLen ); +    if( read > 0 ) { +      d->alreadyRead += read; + +      if( read % 2 > 0 ) { +	kdDebug() << "(K3bWaveDecoder) data length is not a multiple of 2! Cutting data." << endl; +	read -= 1; +      } + +      // swap bytes +      char buf; +      for( int i = 0; i < read; i+=2 ) { +	buf = _data[i]; +	_data[i] = _data[i+1]; +	_data[i+1] = buf; +      } +    } +  } +  else { +    if( !d->buffer ) { +      d->buffer = new char[maxLen/2]; +      d->bufferSize = maxLen/2; +    } + +    read = d->file->readBlock( d->buffer, QMIN(maxLen/2, d->bufferSize) ); +    d->alreadyRead += read; + +    // stretch samples to 16 bit +    from8BitTo16BitBeSigned( d->buffer, _data, read ); + +    read *= 2; +  } + +  return read; +} + + +bool K3bWaveDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& channels ) +{ +  // handling wave files is very easy... +  if( initDecoderInternal() ) { + +    // +    // d->size is the number of bytes in the wave file +    // +    unsigned long size = d->size; +    if( d->sampleRate != 44100 ) +      size = (int)((double)size * 44100.0 / (double)d->sampleRate); + +    if( d->sampleSize == 8 ) +      size *= 2; +    if( d->channels == 1 ) +      size *= 2; + +    // +    // we pad to a multiple of 2352 bytes  +    // (the actual padding of zero data will be done by the K3bAudioDecoder class) +    // +    if( (size%2352) > 0 ) +      size = (size/2352) + 1; +    else +      size = size/2352; + +    frames = size; +    samplerate = d->sampleRate; +    channels = d->channels; +    return true; +  } +  else +    return false; +} + + +bool K3bWaveDecoder::initDecoderInternal() +{ +  cleanup(); + +  d->file->setName( filename() ); +  if( !d->file->open( IO_ReadOnly ) ) { +    kdDebug() << "(K3bWaveDecoder) could not open file." << endl; +    return false; +  } + +  // skip the header +  d->size = identifyWaveFile( d->file, &d->sampleRate, &d->channels, &d->sampleSize ); +  if( d->size <= 0 ) { +    kdDebug() << "(K3bWaveDecoder) no supported wave file." << endl; +    cleanup(); +    return false; +  } + +  d->headerLength = d->file->at(); +  d->alreadyRead = 0; + +  return true; +} + + +bool K3bWaveDecoder::seekInternal( const K3b::Msf& pos ) +{ +  return( d->file->at( d->headerLength + (pos.totalFrames()*2352) ) ); +} + + +void K3bWaveDecoder::cleanup() +{ +  if( d->file->isOpen() ) +    d->file->close(); +} + + +QString K3bWaveDecoder::fileType() const +{ +  return i18n("WAVE"); +} + + +QStringList K3bWaveDecoder::supportedTechnicalInfos() const +{ +  return QStringList::split( ";",  +			     i18n("Channels") + ";" + +			     i18n("Sampling Rate") + ";" + +			     i18n("Sample Size") ); +} + + +QString K3bWaveDecoder::technicalInfo( const QString& name ) const +{ +  if( name == i18n("Channels") ) +    return QString::number(d->channels); +  else if( name == i18n("Sampling Rate") ) +    return i18n("%1 Hz").arg(d->sampleRate); +  else if( name == i18n("Sample Size") ) +    return i18n("%1 bits").arg(d->sampleSize); +  else +    return QString::null; +} + + +K3bWaveDecoderFactory::K3bWaveDecoderFactory( QObject* parent, const char* name ) +  : K3bAudioDecoderFactory( parent, name ) +{ +} + + +K3bWaveDecoderFactory::~K3bWaveDecoderFactory() +{ +} + + +K3bAudioDecoder* K3bWaveDecoderFactory::createDecoder( QObject* parent,  +						       const char* name ) const +{ +  return new K3bWaveDecoder( parent, name ); +} + + +bool K3bWaveDecoderFactory::canDecode( const KURL& url )  +{ +  QFile f( url.path() ); +  if( !f.open(	IO_ReadOnly ) ) { +    kdDebug() << "(K3bWaveDecoder) could not open file " << url.path() << endl; +    return false; +  } + +  return (identifyWaveFile( &f ) > 0); +} + + + +#include "k3bwavedecoder.moc" diff --git a/plugins/decoder/wave/k3bwavedecoder.h b/plugins/decoder/wave/k3bwavedecoder.h new file mode 100644 index 0000000..3f92e9a --- /dev/null +++ b/plugins/decoder/wave/k3bwavedecoder.h @@ -0,0 +1,74 @@ +/*  + * + * $Id: k3bwavedecoder.h 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + +#ifndef _K3B_WAVE_DECODER_H_ +#define _K3B_WAVE_DECODER_H_ + +#include <k3baudiodecoder.h> +#include <k3b_export.h> + +#include <kurl.h> +#include <qcstring.h> + + +class QFile; + + +class LIBK3B_EXPORT K3bWaveDecoderFactory : public K3bAudioDecoderFactory +{ +  Q_OBJECT + + public: +  K3bWaveDecoderFactory( QObject* parent = 0, const char* name = 0 ); +  ~K3bWaveDecoderFactory(); + +  bool canDecode( const KURL& filename ); + +  int pluginSystemVersion() const { return 3; } + +  K3bAudioDecoder* createDecoder( QObject* parent = 0,  +				  const char* name = 0 ) const; +}; + + +class LIBK3B_EXPORT K3bWaveDecoder : public K3bAudioDecoder +{ +  Q_OBJECT + + public: +  K3bWaveDecoder( QObject* parent = 0, const char* name = 0 ); +  ~K3bWaveDecoder(); + +  void cleanup(); + +  bool seekInternal( const K3b::Msf& ); + +  QString fileType() const; + +  QStringList supportedTechnicalInfos() const; + +  QString technicalInfo( const QString& ) const; + + protected: +  bool analyseFileInternal( K3b::Msf& frames, int& samplerate, int& channels ); +  bool initDecoderInternal(); +  int decodeInternal( char* data, int maxLen ); + + private: +  class Private; +  Private* d; +}; + +#endif diff --git a/plugins/decoder/wave/k3bwavedecoder.plugin b/plugins/decoder/wave/k3bwavedecoder.plugin new file mode 100644 index 0000000..7b0a4f4 --- /dev/null +++ b/plugins/decoder/wave/k3bwavedecoder.plugin @@ -0,0 +1,9 @@ +[K3b Plugin] +Lib=libk3bwavedecoder +Group=AudioDecoder +Name=K3b Wave Decoder +Author=Sebastian Trueg +Email=trueg@k3b.org +Version=3.0 +Comment=Decoding module to decode wave files +License=GPL  | 
