Adding Ogg/FLAC support to TagLib

git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@301825 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
This commit is contained in:
Allan Sandfeld Jensen 2004-04-06 20:35:29 +00:00
parent 4f1f6adf59
commit 1bc8909bba
4 changed files with 374 additions and 2 deletions

View File

@ -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)

15
ogg/flac/Makefile.am Normal file
View File

@ -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)

247
ogg/flac/oggflacfile.cpp Normal file
View File

@ -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 <tbytevector.h>
#include <tstring.h>
#include <tdebug.h>
#include <xiphcomment.h>
#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;
}

110
ogg/flac/oggflacfile.h Normal file
View File

@ -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 <oggfile.h>
#include <flacproperties.h>
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