From 1bc8909bbaa4c3a8367d94f9ffdd5722c735fbc1 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 6 Apr 2004 20:35:29 +0000 Subject: [PATCH] Adding Ogg/FLAC support to TagLib git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@301825 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- ogg/Makefile.am | 4 +- ogg/flac/Makefile.am | 15 +++ ogg/flac/oggflacfile.cpp | 247 +++++++++++++++++++++++++++++++++++++++ ogg/flac/oggflacfile.h | 110 +++++++++++++++++ 4 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 ogg/flac/Makefile.am create mode 100644 ogg/flac/oggflacfile.cpp create mode 100644 ogg/flac/oggflacfile.h diff --git a/ogg/Makefile.am b/ogg/Makefile.am index 915146bf..d80e5e4f 100644 --- a/ogg/Makefile.am +++ b/ogg/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = vorbis +SUBDIRS = vorbis flac INCLUDES = -I$(top_srcdir)/taglib -I$(top_srcdir)/taglib/toolkit $(all_includes) @@ -18,6 +18,6 @@ taglib_include_HEADERS = \ taglib_includedir = $(includedir)/taglib -libogg_la_LIBADD = ./vorbis/libvorbis.la +libogg_la_LIBADD = ./vorbis/libvorbis.la ./flac/liboggflac.la EXTRA_DIST = $(libogg_la_SOURCES) $(taglib_include_HEADERS) diff --git a/ogg/flac/Makefile.am b/ogg/flac/Makefile.am new file mode 100644 index 00000000..83c08539 --- /dev/null +++ b/ogg/flac/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = \ + -I$(top_srcdir)/taglib \ + -I$(top_srcdir)/taglib/toolkit \ + -I$(top_srcdir)/taglib/ogg \ + -I$(top_srcdir)/taglib/flac \ + $(all_includes) + +noinst_LTLIBRARIES = liboggflac.la + +liboggflac_la_SOURCES = oggflacfile.cpp + +taglib_include_HEADERS = oggflacfile.h +taglib_includedir = $(includedir)/taglib + +EXTRA_DIST = $(liboggflac_la_SOURCES) $(taglib_include_HEADERS) diff --git a/ogg/flac/oggflacfile.cpp b/ogg/flac/oggflacfile.cpp new file mode 100644 index 00000000..210b3b31 --- /dev/null +++ b/ogg/flac/oggflacfile.cpp @@ -0,0 +1,247 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#include +#include +#include + +#include +#include "oggflacfile.h" + +using namespace TagLib; +using TagLib::FLAC::Properties; + +class Ogg::FLAC::File::FilePrivate +{ +public: + FilePrivate() : + comment(0), + properties(0), + streamStart(0), + streamLength(0), + scanned(false), + hasXiphComment(false), + commentPacket(0) {} + + ~FilePrivate() + { + delete comment; + delete properties; + } + + Ogg::XiphComment *comment; + + Properties *properties; + ByteVector streamInfoData; + ByteVector xiphCommentData; + long streamStart; + long streamLength; + bool scanned; + + bool hasXiphComment; + int commentPacket; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +Ogg::FLAC::File::File(const char *file, bool readProperties, + Properties::ReadStyle propertiesStyle) : Ogg::File(file) +{ + d = new FilePrivate; + read(readProperties, propertiesStyle); +} + +Ogg::FLAC::File::~File() +{ + delete d; +} + +TagLib::Tag* Ogg::FLAC::File::tag() const +{ + return d->comment; +} + +Properties* Ogg::FLAC::File::audioProperties() const +{ + return d->properties; +} + + +void Ogg::FLAC::File::save() +{ + d->xiphCommentData = d->comment->render(); + + // Create FLAC metadata-block: + + // Put the size in the first 32 bit ( I assume no more than 24 bit are used ) + + ByteVector v = ByteVector::fromUInt(d->xiphCommentData.size()); + + // Set the type of the metadata-block to be a Xiph / Vorbis comment + + v[0] = 4; + + // Append the comment-data after the 32 bit header + + v.append(d->xiphCommentData); + + // Save the packet at the old spot + // FIXME: Use padding if size is increasing + + setPacket(d->commentPacket, v); + + Ogg::File::save(); +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void Ogg::FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) +{ + // Sanity: Check if we really have an Ogg/FLAC file + +/* + ByteVector oggHeader = packet(0); + + if (oggHeader.mid(28,4) != "fLaC") { + debug("Ogg::FLAC::File::read() -- Not an Ogg/FLAC file"); + setValid(false); + return; + }*/ + + // Look for FLAC metadata, including vorbis comments + + scan(); + + if (!d->scanned) { + setValid(false); + return; + } + + + if(d->hasXiphComment) + d->comment = new Ogg::XiphComment(xiphCommentData()); + else { + d->comment = new Ogg::XiphComment(); + } + + + if(readProperties) + d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle); +} + +ByteVector Ogg::FLAC::File::streamInfoData() +{ + scan(); + return d->streamInfoData; +} + +ByteVector Ogg::FLAC::File::xiphCommentData() +{ + scan(); + return d->xiphCommentData; +} + +long Ogg::FLAC::File::streamLength() +{ + scan(); + return d->streamLength; +} + +void Ogg::FLAC::File::scan() +{ + // Scan the metadata pages + + if(d->scanned) + return; + + if(!isValid()) + return; + + int ipacket = 1; + long overhead = 0; + + ByteVector metadataHeader = packet(ipacket); + + if (metadataHeader == ByteVector::null) + return; + + ByteVector header = metadataHeader.mid(0,4); + + // Header format (from spec): + // <1> Last-metadata-block flag + // <7> BLOCK_TYPE + // 0 : STREAMINFO + // 1 : PADDING + // .. + // 4 : VORBIS_COMMENT + // .. + // <24> Length of metadata to follow + + char blockType = header[0] & 0x7f; + bool lastBlock = header[0] & 0x80; + uint length = header.mid(1, 3).toUInt(); + overhead += length; + + // Sanity: First block should be the stream_info metadata + + if(blockType != 0) { + debug("Ogg::FLAC::File::scan() -- Invalid Ogg/FLAC stream"); + return; + } + + d->streamInfoData = metadataHeader.mid(4,length); + + // Search through the remaining metadata + + while(!lastBlock) { + metadataHeader = packet(++ipacket); + + header = metadataHeader.mid(0, 4); + blockType = header[0] & 0x7f; + lastBlock = header[0] & 0x80; + length = header.mid(1, 3).toUInt(); + overhead += length; + + if(blockType == 1) { +// debug("Ogg::FLAC::File::scan() -- Padding found"); + } else + if(blockType == 4) { +// debug("Ogg::FLAC::File::scan() -- Vorbis-comments found"); + d->xiphCommentData = metadataHeader.mid(4, length); + d->hasXiphComment = true; + d->commentPacket = ipacket; + } else + if(blockType > 5) { + debug("Ogg::FLAC::File::scan() -- Unknown metadata block"); + } + + } + + // End of metadata, now comes the datastream + d->streamStart = overhead; + d->streamLength = File::length() - d->streamStart; + + d->scanned = true; +} diff --git a/ogg/flac/oggflacfile.h b/ogg/flac/oggflacfile.h new file mode 100644 index 00000000..3c3900af --- /dev/null +++ b/ogg/flac/oggflacfile.h @@ -0,0 +1,110 @@ +/*************************************************************************** + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + ***************************************************************************/ + +#ifndef TAGLIB_OGGFLACFILE_H +#define TAGLIB_OGGFLACFILE_H + +#include + +#include + +namespace TagLib { + + class Tag; + + //! An implementation of Ogg/FLAC metadata + + /*! + * This is implementation of FLAC metadata for Ogg/FLAC files. For native + * FLAC files look under the FLAC hiearchy. + * + * Unlike native FLAC-files, Ogg/FLAC only supports Xiph-comments, + * while the audio-properties are the same. + */ + + namespace Ogg { + namespace FLAC { + + using TagLib::FLAC::Properties; + + //! An implementation of TagLib::File with Ogg/FLAC specific methods + + /*! + * This implements and provides an interface for Ogg/FLAC files to the + * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing + * the abstract TagLib::File API as well as providing some additional + * information specific to Ogg/FLAC files. + */ + + class File : public TagLib::Ogg::File + { + public: + /*! + * Contructs an Ogg/FLAC file from \a file. If \a readProperties is true + * the file's audio properties will also be read using \a propertiesStyle. * If false, \a propertiesStyle is ignored. + */ + File(const char *file, bool readProperties = true, + Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Destroys this instance of the File. + */ + virtual ~File(); + + /*! + * Returns the Tag for this file. This will always be a XiphComment. + */ + virtual TagLib::Tag *tag() const; + + /*! + * Returns the FLAC::Properties for this file. If no audio properties + * were read then this will return a null pointer. + */ + virtual Properties *audioProperties() const; + + /*! + * Save the file. This will primarily save and update the XiphComment. + */ + virtual void save(); + + /*! + * Returns the length of the audio-stream, used by FLAC::Properties for + * calculating the bitrate. + */ + long streamLength(); + + private: + File(const File &); + File &operator=(const File &); + + void read(bool readProperties, Properties::ReadStyle propertiesStyle); + void scan(); + ByteVector streamInfoData(); + ByteVector xiphCommentData(); + + class FilePrivate; + FilePrivate *d; + }; + } // namespace FLAC + } // namespace Ogg +} // namespace TagLib + +#endif -- 2.40.0