From 50b48aec6ddd451a6d1709c0942477b503457663 Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 3 Feb 2010 02:15:56 +0000 Subject: 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 --- plugins/decoder/flac/Makefile.am | 13 + plugins/decoder/flac/configure.in.bot | 13 + plugins/decoder/flac/configure.in.in | 41 +++ plugins/decoder/flac/k3bflacdecoder.cpp | 494 +++++++++++++++++++++++++++++ plugins/decoder/flac/k3bflacdecoder.h | 68 ++++ plugins/decoder/flac/k3bflacdecoder.plugin | 9 + 6 files changed, 638 insertions(+) create mode 100644 plugins/decoder/flac/Makefile.am create mode 100644 plugins/decoder/flac/configure.in.bot create mode 100644 plugins/decoder/flac/configure.in.in create mode 100644 plugins/decoder/flac/k3bflacdecoder.cpp create mode 100644 plugins/decoder/flac/k3bflacdecoder.h create mode 100644 plugins/decoder/flac/k3bflacdecoder.plugin (limited to 'plugins/decoder/flac') 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::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 + * Copyright (C) 2003-2004 John Steele Scott + * + * 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 + +#include "k3bflacdecoder.h" + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_TAGLIB +#include +#include +#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( "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 + * Copyright (C) 2003 John Steele Scott + * + * 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 + +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 -- cgit v1.2.1