mirror of
https://github.com/taglib/taglib.git
synced 2026-03-15 11:20:35 -04:00
Add my old WMA and MP4 code. It is disabled by default, must be explicitly enabled to be compiled.
Scott: If you think this is really a bad idea, please revert. git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@883108 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
This commit is contained in:
@ -4,6 +4,10 @@ OPTION(BUILD_TESTS "Build the test suite" OFF)
|
||||
OPTION(BUILD_EXAMPLES "Build the examples" OFF)
|
||||
|
||||
OPTION(NO_ITUNES_HACKS "Disable workarounds for iTunes bugs" OFF)
|
||||
OPTION(WITH_ASF "Enable ASF tag reading/writing code" OFF)
|
||||
OPTION(WITH_MP4 "Enable MP4 tag reading/writing code" OFF)
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
|
||||
#add some KDE specific stuff
|
||||
set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" )
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/toolkit
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/asf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/vorbis
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/flac
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/flac
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mp4
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg/id3v2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/wavpack
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/speex
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir)/taglib \
|
||||
-I$(top_srcdir)/taglib/toolkit \
|
||||
-I$(top_srcdir)/taglib/asf \
|
||||
-I$(top_srcdir)/taglib/mpeg \
|
||||
-I$(top_srcdir)/taglib/ogg \
|
||||
-I$(top_srcdir)/taglib/ogg/vorbis \
|
||||
@ -8,6 +9,7 @@ INCLUDES = \
|
||||
-I$(top_srcdir)/taglib/ogg/flac \
|
||||
-I$(top_srcdir)/taglib/flac \
|
||||
-I$(top_srcdir)/taglib/mpc \
|
||||
-I$(top_srcdir)/taglib/mp4 \
|
||||
-I$(top_srcdir)/taglib/mpeg/id3v2 \
|
||||
-I$(top_srcdir)/taglib/wavpack \
|
||||
-I$(top_srcdir)/taglib/trueaudio \
|
||||
|
||||
@ -19,11 +19,16 @@
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../../config.h"
|
||||
#endif
|
||||
|
||||
#include "tag_c.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fileref.h>
|
||||
#include <tfile.h>
|
||||
#include <asffile.h>
|
||||
#include <vorbisfile.h>
|
||||
#include <mpegfile.h>
|
||||
#include <flacfile.h>
|
||||
@ -32,6 +37,7 @@
|
||||
#include <wavpackfile.h>
|
||||
#include <speexfile.h>
|
||||
#include <trueaudiofile.h>
|
||||
#include <mp4file.h>
|
||||
#include <tag.h>
|
||||
#include <string.h>
|
||||
#include <id3v2framefactory.h>
|
||||
@ -80,6 +86,14 @@ TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
|
||||
return reinterpret_cast<TagLib_File *>(new Ogg::Speex::File(filename));
|
||||
case TagLib_File_TrueAudio:
|
||||
return reinterpret_cast<TagLib_File *>(new TrueAudio::File(filename));
|
||||
#ifdef WITH_MP4
|
||||
case TagLib_File_MP4:
|
||||
return reinterpret_cast<TagLib_File *>(new MP4::File(filename));
|
||||
#endif
|
||||
#ifdef WITH_ASF
|
||||
case TagLib_File_ASF:
|
||||
return reinterpret_cast<TagLib_File *>(new ASF::File(filename));
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -89,7 +89,9 @@ typedef enum {
|
||||
TagLib_File_OggFlac,
|
||||
TagLib_File_WavPack,
|
||||
TagLib_File_Speex,
|
||||
TagLib_File_TrueAudio
|
||||
TagLib_File_TrueAudio,
|
||||
TagLib_File_MP4,
|
||||
TagLib_File_ASF
|
||||
} TagLib_File_Type;
|
||||
|
||||
/*!
|
||||
|
||||
@ -7,3 +7,5 @@
|
||||
#cmakedefine HAVE_ZLIB 1
|
||||
|
||||
#cmakedefine NO_ITUNES_HACKS 1
|
||||
#cmakedefine WITH_ASF 1
|
||||
#cmakedefine WITH_MP4 1
|
||||
|
||||
@ -2,11 +2,13 @@
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
INCLUDE_DIRECTORIES(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/toolkit
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/asf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/flac
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/flac
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mp4
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/vorbis
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/speex
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2
|
||||
@ -25,11 +27,13 @@ if(ZLIB_FOUND)
|
||||
endif(ZLIB_FOUND)
|
||||
|
||||
ADD_SUBDIRECTORY( toolkit )
|
||||
ADD_SUBDIRECTORY( asf )
|
||||
ADD_SUBDIRECTORY( mpeg )
|
||||
ADD_SUBDIRECTORY( ogg )
|
||||
ADD_SUBDIRECTORY( flac )
|
||||
ADD_SUBDIRECTORY( ape )
|
||||
ADD_SUBDIRECTORY( mpc )
|
||||
ADD_SUBDIRECTORY( mp4 )
|
||||
ADD_SUBDIRECTORY( wavpack )
|
||||
ADD_SUBDIRECTORY( trueaudio )
|
||||
ADD_SUBDIRECTORY( riff )
|
||||
@ -101,6 +105,18 @@ mpc/mpcfile.cpp
|
||||
mpc/mpcproperties.cpp
|
||||
)
|
||||
|
||||
IF(WITH_MP4)
|
||||
SET(mp4_SRCS
|
||||
mp4/mp4file.cpp
|
||||
mp4/mp4atom.cpp
|
||||
mp4/mp4tag.cpp
|
||||
mp4/mp4item.cpp
|
||||
mp4/mp4properties.cpp
|
||||
)
|
||||
ELSE(WITH_MP4)
|
||||
SET(mp4_SRCS)
|
||||
ENDIF(WITH_MP4)
|
||||
|
||||
SET(ape_SRCS
|
||||
ape/apetag.cpp
|
||||
ape/apefooter.cpp
|
||||
@ -122,6 +138,17 @@ trueaudio/trueaudiofile.cpp
|
||||
trueaudio/trueaudioproperties.cpp
|
||||
)
|
||||
|
||||
IF(WITH_ASF)
|
||||
SET(asf_SRCS
|
||||
asf/asftag.cpp
|
||||
asf/asffile.cpp
|
||||
asf/asfproperties.cpp
|
||||
asf/asfattribute.cpp
|
||||
)
|
||||
ELSE(WITH_ASF)
|
||||
SET(asf_SRCS)
|
||||
ENDIF(WITH_ASF)
|
||||
|
||||
SET(riff_SRCS
|
||||
riff/rifffile.cpp
|
||||
)
|
||||
@ -149,6 +176,7 @@ toolkit/unicode.cpp
|
||||
SET(tag_LIB_SRCS ${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
|
||||
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
|
||||
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
|
||||
${mp4_SRCS} ${asf_SRCS}
|
||||
tag.cpp
|
||||
tagunion.cpp
|
||||
fileref.cpp
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
SUBDIRS = toolkit mpeg ogg flac ape mpc wavpack trueaudio riff
|
||||
SUBDIRS = toolkit mpeg ogg flac ape mpc wavpack trueaudio riff asf mp4
|
||||
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir)/taglib \
|
||||
@ -8,6 +8,8 @@ INCLUDES = \
|
||||
-I$(top_srcdir)/taglib/ogg/flac \
|
||||
-I$(top_srcdir)/taglib/flac \
|
||||
-I$(top_srcdir)/taglib/mpc \
|
||||
-I$(top_srcdir)/taglib/asf \
|
||||
-I$(top_srcdir)/taglib/mp4 \
|
||||
-I$(top_srcdir)/taglib/ogg/vorbis \
|
||||
-I$(top_srcdir)/taglib/ogg/speex \
|
||||
-I$(top_srcdir)/taglib/wavpack \
|
||||
@ -27,4 +29,5 @@ taglib_includedir = $(includedir)/taglib
|
||||
libtag_la_LDFLAGS = $(all_libraries) -no-undefined -version-info 6:0:5
|
||||
libtag_la_LIBADD = ./mpeg/libmpeg.la ./ogg/libogg.la ./flac/libflac.la ./mpc/libmpc.la \
|
||||
./ape/libape.la ./toolkit/libtoolkit.la ./wavpack/libwavpack.la \
|
||||
./trueaudio/libtrueaudio.la ./riff/libriff.la
|
||||
./trueaudio/libtrueaudio.la ./riff/libriff.la \
|
||||
./mp4/libmp4.la ./asf/libasf.la
|
||||
|
||||
1
taglib/asf/CMakeLists.txt
Normal file
1
taglib/asf/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
INSTALL( FILES asffile.h asfproperties.h asftag.h asfattribute.h DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
|
||||
11
taglib/asf/Makefile.am
Normal file
11
taglib/asf/Makefile.am
Normal file
@ -0,0 +1,11 @@
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir)/taglib \
|
||||
-I$(top_srcdir)/taglib/toolkit \
|
||||
$(all_includes)
|
||||
|
||||
noinst_LTLIBRARIES = libasf.la
|
||||
|
||||
libasf_la_SOURCES = asfattribute.cpp asffile.cpp asfproperties.cpp asftag.cpp
|
||||
|
||||
taglib_include_HEADERS = asfattribute.h asffile.h asfproperties.h asftag.h
|
||||
taglib_includedir = $(includedir)/taglib
|
||||
316
taglib/asf/asfattribute.cpp
Normal file
316
taglib/asf/asfattribute.cpp
Normal file
@ -0,0 +1,316 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ASF
|
||||
|
||||
#include <taglib.h>
|
||||
#include "asfattribute.h"
|
||||
#include "asffile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Attribute::AttributePrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
AttributePrivate()
|
||||
: stream(0),
|
||||
language(0) {}
|
||||
AttributeTypes type;
|
||||
String stringValue;
|
||||
ByteVector byteVectorValue;
|
||||
union {
|
||||
unsigned int intValue;
|
||||
unsigned short shortValue;
|
||||
unsigned long long longLongValue;
|
||||
bool boolValue;
|
||||
};
|
||||
int stream;
|
||||
int language;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Attribute::Attribute()
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = UnicodeType;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const ASF::Attribute &other)
|
||||
: d(other.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
ASF::Attribute &
|
||||
ASF::Attribute::operator=(const ASF::Attribute &other)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = other.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASF::Attribute::~Attribute()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const String &value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = UnicodeType;
|
||||
d->stringValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const ByteVector &value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = BytesType;
|
||||
d->byteVectorValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned int value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = DWordType;
|
||||
d->intValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned long long value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = QWordType;
|
||||
d->longLongValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned short value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = WordType;
|
||||
d->shortValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(bool value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = BoolType;
|
||||
d->boolValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::AttributeTypes
|
||||
ASF::Attribute::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Attribute::toString() const
|
||||
{
|
||||
return d->stringValue;
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::Attribute::toByteVector() const
|
||||
{
|
||||
return d->byteVectorValue;
|
||||
}
|
||||
|
||||
unsigned short
|
||||
ASF::Attribute::toBool() const
|
||||
{
|
||||
return d->shortValue;
|
||||
}
|
||||
|
||||
unsigned short
|
||||
ASF::Attribute::toUShort() const
|
||||
{
|
||||
return d->shortValue;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ASF::Attribute::toUInt() const
|
||||
{
|
||||
return d->intValue;
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
ASF::Attribute::toULongLong() const
|
||||
{
|
||||
return d->longLongValue;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Attribute::parse(ASF::File &f, int kind)
|
||||
{
|
||||
int size, nameLength;
|
||||
String name;
|
||||
|
||||
// extended content descriptor
|
||||
if(kind == 0) {
|
||||
nameLength = f.readWORD();
|
||||
name = f.readString(nameLength);
|
||||
d->type = ASF::Attribute::AttributeTypes(f.readWORD());
|
||||
size = f.readWORD();
|
||||
}
|
||||
// metadata & metadata library
|
||||
else {
|
||||
int temp = f.readWORD();
|
||||
// metadata library
|
||||
if(kind == 2) {
|
||||
d->language = temp;
|
||||
}
|
||||
d->stream = f.readWORD();
|
||||
nameLength = f.readWORD();
|
||||
d->type = ASF::Attribute::AttributeTypes(f.readWORD());
|
||||
size = f.readDWORD();
|
||||
name = f.readString(nameLength);
|
||||
}
|
||||
|
||||
switch(d->type) {
|
||||
case WordType:
|
||||
d->shortValue = f.readWORD();
|
||||
break;
|
||||
|
||||
case BoolType:
|
||||
if(kind == 0) {
|
||||
d->boolValue = f.readDWORD() == 1;
|
||||
}
|
||||
else {
|
||||
d->boolValue = f.readWORD() == 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DWordType:
|
||||
d->intValue = f.readDWORD();
|
||||
break;
|
||||
|
||||
case QWordType:
|
||||
d->longLongValue = f.readQWORD();
|
||||
break;
|
||||
|
||||
case UnicodeType:
|
||||
d->stringValue = f.readString(size);
|
||||
break;
|
||||
|
||||
case BytesType:
|
||||
case GuidType:
|
||||
d->byteVectorValue = f.readBlock(size);
|
||||
break;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::Attribute::render(const String &name, int kind) const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
switch (d->type) {
|
||||
case WordType:
|
||||
data.append(ByteVector::fromShort(d->shortValue, false));
|
||||
break;
|
||||
|
||||
case BoolType:
|
||||
if(kind == 0) {
|
||||
data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false));
|
||||
}
|
||||
else {
|
||||
data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false));
|
||||
}
|
||||
break;
|
||||
|
||||
case DWordType:
|
||||
data.append(ByteVector::fromUInt(d->intValue, false));
|
||||
break;
|
||||
|
||||
case QWordType:
|
||||
data.append(ByteVector::fromLongLong(d->longLongValue, false));
|
||||
break;
|
||||
|
||||
case UnicodeType:
|
||||
data.append(File::renderString(d->stringValue));
|
||||
break;
|
||||
|
||||
case BytesType:
|
||||
case GuidType:
|
||||
data.append(d->byteVectorValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if(kind == 0) {
|
||||
data = File::renderString(name, true) +
|
||||
ByteVector::fromShort((int)d->type, false) +
|
||||
ByteVector::fromShort(data.size(), false) +
|
||||
data;
|
||||
}
|
||||
else {
|
||||
ByteVector nameData = File::renderString(name);
|
||||
data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
|
||||
ByteVector::fromShort(d->stream, false) +
|
||||
ByteVector::fromShort(nameData.size(), false) +
|
||||
ByteVector::fromShort((int)d->type, false) +
|
||||
ByteVector::fromUInt(data.size(), false) +
|
||||
nameData +
|
||||
data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int
|
||||
ASF::Attribute::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Attribute::setLanguage(int value)
|
||||
{
|
||||
d->language = value;
|
||||
}
|
||||
|
||||
int
|
||||
ASF::Attribute::stream() const
|
||||
{
|
||||
return d->stream;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Attribute::setStream(int value)
|
||||
{
|
||||
d->stream = value;
|
||||
}
|
||||
|
||||
#endif
|
||||
181
taglib/asf/asfattribute.h
Normal file
181
taglib/asf/asfattribute.h
Normal file
@ -0,0 +1,181 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFATTRIBUTE_H
|
||||
#define TAGLIB_ASFATTRIBUTE_H
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tbytevector.h>
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
|
||||
namespace ASF
|
||||
{
|
||||
|
||||
class File;
|
||||
|
||||
class TAGLIB_EXPORT Attribute
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Enum of types an Attribute can have.
|
||||
*/
|
||||
enum AttributeTypes {
|
||||
UnicodeType = 0,
|
||||
BytesType = 1,
|
||||
BoolType = 2,
|
||||
DWordType = 3,
|
||||
QWordType = 4,
|
||||
WordType = 5,
|
||||
GuidType = 6
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty attribute.
|
||||
*/
|
||||
Attribute();
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a UnicodeType \a value.
|
||||
*/
|
||||
Attribute(const String &value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a BytesType \a value.
|
||||
*/
|
||||
Attribute(const ByteVector &value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a DWordType \a value.
|
||||
*/
|
||||
Attribute(unsigned int value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a QWordType \a value.
|
||||
*/
|
||||
Attribute(unsigned long long value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a WordType \a value.
|
||||
*/
|
||||
Attribute(unsigned short value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a BoolType \a value.
|
||||
*/
|
||||
Attribute(bool value);
|
||||
|
||||
/*!
|
||||
* Construct an attribute as a copy of \a other.
|
||||
*/
|
||||
Attribute(const Attribute &item);
|
||||
|
||||
/*!
|
||||
* Copies the contents of \a other into this item.
|
||||
*/
|
||||
ASF::Attribute &operator=(const Attribute &other);
|
||||
|
||||
/*!
|
||||
* Destroys the attribute.
|
||||
*/
|
||||
virtual ~Attribute();
|
||||
|
||||
/*!
|
||||
* Returns type of the value.
|
||||
*/
|
||||
AttributeTypes type() const;
|
||||
|
||||
/*!
|
||||
* Returns the BoolType \a value.
|
||||
*/
|
||||
unsigned short toBool() const;
|
||||
|
||||
/*!
|
||||
* Returns the WordType \a value.
|
||||
*/
|
||||
unsigned short toUShort() const;
|
||||
|
||||
/*!
|
||||
* Returns the DWordType \a value.
|
||||
*/
|
||||
unsigned int toUInt() const;
|
||||
|
||||
/*!
|
||||
* Returns the QWordType \a value.
|
||||
*/
|
||||
unsigned long long toULongLong() const;
|
||||
|
||||
/*!
|
||||
* Returns the UnicodeType \a value.
|
||||
*/
|
||||
String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the BytesType \a value.
|
||||
*/
|
||||
ByteVector toByteVector() const;
|
||||
|
||||
/*!
|
||||
* Returns the language number, or 0 is no stream number was set.
|
||||
*/
|
||||
int language() const;
|
||||
|
||||
/*!
|
||||
* Sets the language number.
|
||||
*/
|
||||
void setLanguage(int value);
|
||||
|
||||
/*!
|
||||
* Returns the stream number, or 0 is no stream number was set.
|
||||
*/
|
||||
int stream() const;
|
||||
|
||||
/*!
|
||||
* Sets the stream number.
|
||||
*/
|
||||
void setStream(int value);
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
/* THIS IS PRIVATE, DON'T TOUCH IT! */
|
||||
String parse(ASF::File &file, int kind = 0);
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class File;
|
||||
|
||||
ByteVector render(const String &name, int kind = 0) const;
|
||||
|
||||
class AttributePrivate;
|
||||
AttributePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
562
taglib/asf/asffile.cpp
Normal file
562
taglib/asf/asffile.cpp
Normal file
@ -0,0 +1,562 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ASF
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tstring.h>
|
||||
#include "asffile.h"
|
||||
#include "asftag.h"
|
||||
#include "asfproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate():
|
||||
size(0),
|
||||
tag(0),
|
||||
properties(0),
|
||||
contentDescriptionObject(0),
|
||||
extendedContentDescriptionObject(0),
|
||||
headerExtensionObject(0),
|
||||
metadataObject(0),
|
||||
metadataLibraryObject(0) {}
|
||||
unsigned long long size;
|
||||
ASF::Tag *tag;
|
||||
ASF::Properties *properties;
|
||||
List<ASF::File::BaseObject *> objects;
|
||||
ASF::File::ContentDescriptionObject *contentDescriptionObject;
|
||||
ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject;
|
||||
ASF::File::HeaderExtensionObject *headerExtensionObject;
|
||||
ASF::File::MetadataObject *metadataObject;
|
||||
ASF::File::MetadataLibraryObject *metadataLibraryObject;
|
||||
};
|
||||
|
||||
static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||
static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
|
||||
static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
|
||||
static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||
static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
|
||||
static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
|
||||
static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
|
||||
static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
|
||||
|
||||
class ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector data;
|
||||
virtual ~BaseObject() {}
|
||||
virtual ByteVector guid() = 0;
|
||||
virtual void parse(ASF::File *file, unsigned int size);
|
||||
virtual ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::UnknownObject : public ASF::File::BaseObject
|
||||
{
|
||||
ByteVector myGuid;
|
||||
public:
|
||||
UnknownObject(const ByteVector &guid);
|
||||
ByteVector guid();
|
||||
};
|
||||
|
||||
class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
};
|
||||
|
||||
class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
};
|
||||
|
||||
class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::MetadataObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
List<ASF::File::BaseObject *> objects;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
void
|
||||
ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
|
||||
{
|
||||
data = file->readBlock(size - 24);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::BaseObject::render(ASF::File * /*file*/)
|
||||
{
|
||||
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
|
||||
}
|
||||
|
||||
ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
|
||||
{
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::UnknownObject::guid()
|
||||
{
|
||||
return myGuid;
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::FilePropertiesObject::guid()
|
||||
{
|
||||
return filePropertiesGuid;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
|
||||
{
|
||||
BaseObject::parse(file, size);
|
||||
file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L));
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::StreamPropertiesObject::guid()
|
||||
{
|
||||
return streamPropertiesGuid;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
|
||||
{
|
||||
BaseObject::parse(file, size);
|
||||
file->d->properties->setChannels(data.mid(56, 2).toShort(false));
|
||||
file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false));
|
||||
file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::ContentDescriptionObject::guid()
|
||||
{
|
||||
return contentDescriptionGuid;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->contentDescriptionObject = this;
|
||||
int titleLength = file->readWORD();
|
||||
int artistLength = file->readWORD();
|
||||
int copyrightLength = file->readWORD();
|
||||
int commentLength = file->readWORD();
|
||||
int ratingLength = file->readWORD();
|
||||
file->d->tag->setTitle(file->readString(titleLength));
|
||||
file->d->tag->setArtist(file->readString(artistLength));
|
||||
file->d->tag->setCopyright(file->readString(copyrightLength));
|
||||
file->d->tag->setComment(file->readString(commentLength));
|
||||
file->d->tag->setRating(file->readString(ratingLength));
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::ContentDescriptionObject::render(ASF::File *file)
|
||||
{
|
||||
ByteVector v1 = file->renderString(file->d->tag->title());
|
||||
ByteVector v2 = file->renderString(file->d->tag->artist());
|
||||
ByteVector v3 = file->renderString(file->d->tag->copyright());
|
||||
ByteVector v4 = file->renderString(file->d->tag->comment());
|
||||
ByteVector v5 = file->renderString(file->d->tag->rating());
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(v1.size(), false));
|
||||
data.append(ByteVector::fromShort(v2.size(), false));
|
||||
data.append(ByteVector::fromShort(v3.size(), false));
|
||||
data.append(ByteVector::fromShort(v4.size(), false));
|
||||
data.append(ByteVector::fromShort(v5.size(), false));
|
||||
data.append(v1);
|
||||
data.append(v2);
|
||||
data.append(v3);
|
||||
data.append(v4);
|
||||
data.append(v5);
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::ExtendedContentDescriptionObject::guid()
|
||||
{
|
||||
return extendedContentDescriptionGuid;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->extendedContentDescriptionObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::MetadataObject::guid()
|
||||
{
|
||||
return metadataGuid;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->metadataObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 1);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::MetadataObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::MetadataLibraryObject::guid()
|
||||
{
|
||||
return metadataLibraryGuid;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->metadataLibraryObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 2);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::MetadataLibraryObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::HeaderExtensionObject::guid()
|
||||
{
|
||||
return headerExtensionGuid;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->headerExtensionObject = this;
|
||||
file->seek(18, File::Current);
|
||||
long long dataSize = file->readDWORD();
|
||||
long long dataPos = 0;
|
||||
while(dataPos < dataSize) {
|
||||
ByteVector guid = file->readBlock(16);
|
||||
long long size = file->readQWORD();
|
||||
BaseObject *obj;
|
||||
if(guid == metadataGuid) {
|
||||
obj = new MetadataObject();
|
||||
}
|
||||
else if(guid == metadataLibraryGuid) {
|
||||
obj = new MetadataLibraryObject();
|
||||
}
|
||||
else {
|
||||
obj = new UnknownObject(guid);
|
||||
}
|
||||
obj->parse(file, size);
|
||||
objects.append(obj);
|
||||
dataPos += size;
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::HeaderExtensionObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
for(unsigned int i = 0; i < objects.size(); i++) {
|
||||
data.append(objects[i]->render(file));
|
||||
}
|
||||
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle)
|
||||
: TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
ASF::File::~File()
|
||||
{
|
||||
for(unsigned int i = 0; i < d->objects.size(); i++) {
|
||||
delete d->objects[i];
|
||||
}
|
||||
if(d->tag) {
|
||||
delete d->tag;
|
||||
}
|
||||
if(d->properties) {
|
||||
delete d->properties;
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
ASF::Tag *ASF::File::tag() const
|
||||
{
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
ASF::Properties *ASF::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
|
||||
{
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
ByteVector guid = readBlock(16);
|
||||
if(guid != headerGuid) {
|
||||
debug("ASF: Not an ASF file.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->tag = new ASF::Tag();
|
||||
d->properties = new ASF::Properties();
|
||||
|
||||
d->size = readQWORD();
|
||||
int numObjects = readDWORD();
|
||||
seek(2, Current);
|
||||
|
||||
for(int i = 0; i < numObjects; i++) {
|
||||
ByteVector guid = readBlock(16);
|
||||
long size = (long)readQWORD();
|
||||
BaseObject *obj;
|
||||
if(guid == filePropertiesGuid) {
|
||||
obj = new FilePropertiesObject();
|
||||
}
|
||||
else if(guid == streamPropertiesGuid) {
|
||||
obj = new StreamPropertiesObject();
|
||||
}
|
||||
else if(guid == contentDescriptionGuid) {
|
||||
obj = new ContentDescriptionObject();
|
||||
}
|
||||
else if(guid == extendedContentDescriptionGuid) {
|
||||
obj = new ExtendedContentDescriptionObject();
|
||||
}
|
||||
else if(guid == headerExtensionGuid) {
|
||||
obj = new HeaderExtensionObject();
|
||||
}
|
||||
else {
|
||||
obj = new UnknownObject(guid);
|
||||
}
|
||||
obj->parse(this, size);
|
||||
d->objects.append(obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool ASF::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("ASF: File is read-only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!d->contentDescriptionObject) {
|
||||
d->contentDescriptionObject = new ContentDescriptionObject();
|
||||
d->objects.append(d->contentDescriptionObject);
|
||||
}
|
||||
if(!d->extendedContentDescriptionObject) {
|
||||
d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
|
||||
d->objects.append(d->extendedContentDescriptionObject);
|
||||
}
|
||||
if(!d->headerExtensionObject) {
|
||||
d->headerExtensionObject = new HeaderExtensionObject();
|
||||
d->objects.append(d->headerExtensionObject);
|
||||
}
|
||||
if(!d->metadataObject) {
|
||||
d->metadataObject = new MetadataObject();
|
||||
d->headerExtensionObject->objects.append(d->metadataObject);
|
||||
}
|
||||
if(!d->metadataLibraryObject) {
|
||||
d->metadataLibraryObject = new MetadataLibraryObject();
|
||||
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
|
||||
}
|
||||
|
||||
ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin();
|
||||
for(; it != d->tag->attributeListMap().end(); it++) {
|
||||
const String &name = it->first;
|
||||
const AttributeList &attributes = it->second;
|
||||
bool inExtendedContentDescriptionObject = false;
|
||||
bool inMetadataObject = false;
|
||||
for(unsigned int j = 0; j < attributes.size(); j++) {
|
||||
const Attribute &attribute = attributes[j];
|
||||
if(!inExtendedContentDescriptionObject && attribute.language() == 0 && attribute.stream() == 0) {
|
||||
d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
|
||||
inExtendedContentDescriptionObject = true;
|
||||
}
|
||||
else if(!inMetadataObject && attribute.language() == 0 && attribute.stream() != 0) {
|
||||
d->metadataObject->attributeData.append(attribute.render(name, 1));
|
||||
inMetadataObject = true;
|
||||
}
|
||||
else {
|
||||
d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector data;
|
||||
for(unsigned int i = 0; i < d->objects.size(); i++) {
|
||||
data.append(d->objects[i]->render(this));
|
||||
}
|
||||
data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data;
|
||||
insert(data, 0, d->size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ASF::File::readBYTE()
|
||||
{
|
||||
ByteVector v = readBlock(1);
|
||||
return v[0];
|
||||
}
|
||||
|
||||
int ASF::File::readWORD()
|
||||
{
|
||||
ByteVector v = readBlock(2);
|
||||
return v.toShort(false);
|
||||
}
|
||||
|
||||
unsigned int ASF::File::readDWORD()
|
||||
{
|
||||
ByteVector v = readBlock(4);
|
||||
return v.toUInt(false);
|
||||
}
|
||||
|
||||
long long ASF::File::readQWORD()
|
||||
{
|
||||
ByteVector v = readBlock(8);
|
||||
return v.toLongLong(false);
|
||||
}
|
||||
|
||||
String
|
||||
ASF::File::readString(int length)
|
||||
{
|
||||
ByteVector data = readBlock(length);
|
||||
unsigned int size = data.size();
|
||||
while (size >= 2) {
|
||||
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
|
||||
break;
|
||||
}
|
||||
size -= 2;
|
||||
}
|
||||
if(size != data.size()) {
|
||||
data.resize(size);
|
||||
}
|
||||
return String(data, String::UTF16LE);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
ASF::File::renderString(const String &str, bool includeLength)
|
||||
{
|
||||
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
|
||||
if(includeLength) {
|
||||
data = ByteVector::fromShort(data.size(), false) + data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
#endif
|
||||
119
taglib/asf/asffile.h
Normal file
119
taglib/asf/asffile.h
Normal file
@ -0,0 +1,119 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFFILE_H
|
||||
#define TAGLIB_ASFFILE_H
|
||||
|
||||
#include <tag.h>
|
||||
#include <tfile.h>
|
||||
#include "taglib_export.h"
|
||||
#include "asfproperties.h"
|
||||
#include "asftag.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! An implementation of ASF (WMA) metadata
|
||||
namespace ASF {
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for ASF 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 ASF files.
|
||||
*/
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Contructs an ASF 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.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ASF tag of the file.
|
||||
*
|
||||
* ASF::Tag implements the tag interface, so this serves as the
|
||||
* reimplementation of TagLib::File::tag().
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the ASF::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
virtual Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the ASF audio properties for this file.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
private:
|
||||
|
||||
int readBYTE();
|
||||
int readWORD();
|
||||
unsigned int readDWORD();
|
||||
long long readQWORD();
|
||||
static ByteVector renderString(const String &str, bool includeLength = false);
|
||||
String readString(int len);
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
|
||||
friend class Attribute;
|
||||
|
||||
class BaseObject;
|
||||
class UnknownObject;
|
||||
class FilePropertiesObject;
|
||||
class StreamPropertiesObject;
|
||||
class ContentDescriptionObject;
|
||||
class ExtendedContentDescriptionObject;
|
||||
class HeaderExtensionObject;
|
||||
class MetadataObject;
|
||||
class MetadataLibraryObject;
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
107
taglib/asf/asfproperties.cpp
Normal file
107
taglib/asf/asfproperties.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ASF
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "asfproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate(): length(0), bitrate(0), sampleRate(0), channels(0) {}
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Properties::Properties() : AudioProperties(AudioProperties::Average)
|
||||
{
|
||||
d = new PropertiesPrivate;
|
||||
}
|
||||
|
||||
ASF::Properties::~Properties()
|
||||
{
|
||||
if(d)
|
||||
delete d;
|
||||
}
|
||||
|
||||
int ASF::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int ASF::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int ASF::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int ASF::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ASF::Properties::setLength(int length)
|
||||
{
|
||||
d->length = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setBitrate(int length)
|
||||
{
|
||||
d->bitrate = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setSampleRate(int length)
|
||||
{
|
||||
d->sampleRate = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setChannels(int length)
|
||||
{
|
||||
d->channels = length;
|
||||
}
|
||||
|
||||
#endif
|
||||
74
taglib/asf/asfproperties.h
Normal file
74
taglib/asf/asfproperties.h
Normal file
@ -0,0 +1,74 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFPROPERTIES_H
|
||||
#define TAGLIB_ASFPROPERTIES_H
|
||||
|
||||
#include <audioproperties.h>
|
||||
#include <tstring.h>
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ASF {
|
||||
|
||||
//! An implementation of ASF audio properties
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Create an instance of ASF::Properties.
|
||||
*/
|
||||
Properties();
|
||||
|
||||
/*!
|
||||
* Destroys this ASF::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
// Reimplementations.
|
||||
virtual int length() const;
|
||||
virtual int bitrate() const;
|
||||
virtual int sampleRate() const;
|
||||
virtual int channels() const;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
void setLength(int value);
|
||||
void setBitrate(int value);
|
||||
void setSampleRate(int value);
|
||||
void setChannels(int value);
|
||||
#endif
|
||||
|
||||
private:
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
214
taglib/asf/asftag.cpp
Normal file
214
taglib/asf/asftag.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ASF
|
||||
|
||||
#include "asftag.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
String title;
|
||||
String artist;
|
||||
String copyright;
|
||||
String comment;
|
||||
String rating;
|
||||
AttributeListMap attributeListMap;
|
||||
};
|
||||
|
||||
ASF::Tag::Tag()
|
||||
: TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
ASF::Tag::~Tag()
|
||||
{
|
||||
if(d)
|
||||
delete d;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Tag::artist() const
|
||||
{
|
||||
return d->artist;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Tag::album() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/AlbumTitle"))
|
||||
return d->attributeListMap["WM/AlbumTitle"][0].toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Tag::copyright() const
|
||||
{
|
||||
return d->copyright;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Tag::rating() const
|
||||
{
|
||||
return d->rating;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ASF::Tag::year() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Year"))
|
||||
return d->attributeListMap["WM/Year"][0].toString().toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ASF::Tag::track() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/TrackNumber"))
|
||||
return d->attributeListMap["WM/TrackNumber"][0].toString().toInt();
|
||||
if(d->attributeListMap.contains("WM/Track"))
|
||||
return d->attributeListMap["WM/Track"][0].toUInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
String
|
||||
ASF::Tag::genre() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Genre"))
|
||||
return d->attributeListMap["WM/Genre"][0].toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setTitle(const String &value)
|
||||
{
|
||||
d->title = value;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setArtist(const String &value)
|
||||
{
|
||||
d->artist = value;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setCopyright(const String &value)
|
||||
{
|
||||
d->copyright = value;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setComment(const String &value)
|
||||
{
|
||||
d->comment = value;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setRating(const String &value)
|
||||
{
|
||||
d->rating = value;
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setAlbum(const String &value)
|
||||
{
|
||||
setAttribute("WM/AlbumTitle", value);
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setGenre(const String &value)
|
||||
{
|
||||
setAttribute("WM/Genre", value);
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setYear(uint value)
|
||||
{
|
||||
setAttribute("WM/Year", String::number(value));
|
||||
}
|
||||
|
||||
void
|
||||
ASF::Tag::setTrack(uint value)
|
||||
{
|
||||
setAttribute("WM/TrackNumber", String::number(value));
|
||||
}
|
||||
|
||||
ASF::AttributeListMap&
|
||||
ASF::Tag::attributeListMap()
|
||||
{
|
||||
return d->attributeListMap;
|
||||
}
|
||||
|
||||
void ASF::Tag::removeItem(const String &key)
|
||||
{
|
||||
AttributeListMap::Iterator it = d->attributeListMap.find(key);
|
||||
if(it != d->attributeListMap.end())
|
||||
d->attributeListMap.erase(it);
|
||||
}
|
||||
|
||||
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
|
||||
{
|
||||
AttributeList value;
|
||||
value.append(attribute);
|
||||
d->attributeListMap.insert(name, value);
|
||||
}
|
||||
|
||||
void ASF::Tag::addAttribute(const String &name, const Attribute &attribute)
|
||||
{
|
||||
if(d->attributeListMap.contains(name)) {
|
||||
d->attributeListMap[name].append(attribute);
|
||||
}
|
||||
else {
|
||||
setAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
bool ASF::Tag::isEmpty() const {
|
||||
return TagLib::Tag::isEmpty() &&
|
||||
copyright().isEmpty() &&
|
||||
rating().isEmpty() &&
|
||||
d->attributeListMap.isEmpty();
|
||||
}
|
||||
|
||||
#endif
|
||||
186
taglib/asf/asftag.h
Normal file
186
taglib/asf/asftag.h
Normal file
@ -0,0 +1,186 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFTAG_H
|
||||
#define TAGLIB_ASFTAG_H
|
||||
|
||||
#include <tag.h>
|
||||
#include <tlist.h>
|
||||
#include <tmap.h>
|
||||
#include "taglib_export.h"
|
||||
#include "asfattribute.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ASF {
|
||||
|
||||
typedef List<Attribute> AttributeList;
|
||||
typedef Map<String, AttributeList> AttributeListMap;
|
||||
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag {
|
||||
|
||||
friend class File;
|
||||
|
||||
public:
|
||||
|
||||
Tag();
|
||||
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Returns the track name.
|
||||
*/
|
||||
virtual String title() const;
|
||||
|
||||
/*!
|
||||
* Returns the artist name.
|
||||
*/
|
||||
virtual String artist() const;
|
||||
|
||||
/*!
|
||||
* Returns the album name; if no album name is present in the tag
|
||||
* String::null will be returned.
|
||||
*/
|
||||
virtual String album() const;
|
||||
|
||||
/*!
|
||||
* Returns the track comment.
|
||||
*/
|
||||
virtual String comment() const;
|
||||
|
||||
/*!
|
||||
* Returns the genre name; if no genre is present in the tag String::null
|
||||
* will be returned.
|
||||
*/
|
||||
virtual String genre() const;
|
||||
|
||||
/*!
|
||||
* Returns the rating.
|
||||
*/
|
||||
virtual String rating() const;
|
||||
|
||||
/*!
|
||||
* Returns the genre name; if no genre is present in the tag String::null
|
||||
* will be returned.
|
||||
*/
|
||||
virtual String copyright() const;
|
||||
|
||||
/*!
|
||||
* Returns the year; if there is no year set, this will return 0.
|
||||
*/
|
||||
virtual uint year() const;
|
||||
|
||||
/*!
|
||||
* Returns the track number; if there is no track number set, this will
|
||||
* return 0.
|
||||
*/
|
||||
virtual uint track() const;
|
||||
|
||||
/*!
|
||||
* Sets the title to \a s.
|
||||
*/
|
||||
virtual void setTitle(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the artist to \a s.
|
||||
*/
|
||||
virtual void setArtist(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the album to \a s. If \a s is String::null then this value will be
|
||||
* cleared.
|
||||
*/
|
||||
virtual void setAlbum(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the comment to \a s.
|
||||
*/
|
||||
virtual void setComment(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the rating to \a s.
|
||||
*/
|
||||
virtual void setRating(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the copyright to \a s.
|
||||
*/
|
||||
virtual void setCopyright(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the genre to \a s.
|
||||
*/
|
||||
virtual void setGenre(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the year to \a i. If \a s is 0 then this value will be cleared.
|
||||
*/
|
||||
virtual void setYear(uint i);
|
||||
|
||||
/*!
|
||||
* Sets the track to \a i. If \a s is 0 then this value will be cleared.
|
||||
*/
|
||||
virtual void setTrack(uint i);
|
||||
|
||||
/*!
|
||||
* Returns true if the tag does not contain any data. This should be
|
||||
* reimplemented in subclasses that provide more than the basic tagging
|
||||
* abilities in this class.
|
||||
*/
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the item list map. This is an AttributeListMap of
|
||||
* all of the items in the tag.
|
||||
*
|
||||
* This is the most powerfull structure for accessing the items of the tag.
|
||||
*/
|
||||
AttributeListMap &attributeListMap();
|
||||
|
||||
/*!
|
||||
* Removes the \a key attribute from the tag
|
||||
*/
|
||||
void removeItem(const String &name);
|
||||
|
||||
/*!
|
||||
* Sets the \a key attribute to the value of \a attribute. If an attribute
|
||||
* with the \a key is already present, it will be replaced.
|
||||
*/
|
||||
void setAttribute(const String &name, const Attribute &attribute);
|
||||
|
||||
/*!
|
||||
* Sets the \a key attribute to the value of \a attribute. If an attribute
|
||||
* with the \a key is already present, it will be added to the list.
|
||||
*/
|
||||
void addAttribute(const String &name, const Attribute &attribute);
|
||||
|
||||
private:
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -23,15 +23,21 @@
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tfile.h>
|
||||
#include <tstring.h>
|
||||
|
||||
#include "fileref.h"
|
||||
#include "asffile.h"
|
||||
#include "mpegfile.h"
|
||||
#include "vorbisfile.h"
|
||||
#include "flacfile.h"
|
||||
#include "oggflacfile.h"
|
||||
#include "mpcfile.h"
|
||||
#include "mp4file.h"
|
||||
#include "wavpackfile.h"
|
||||
#include "speexfile.h"
|
||||
#include "trueaudiofile.h"
|
||||
@ -123,6 +129,15 @@ StringList FileRef::defaultFileExtensions()
|
||||
l.append("wv");
|
||||
l.append("spx");
|
||||
l.append("tta");
|
||||
#ifdef WITH_MP4
|
||||
l.append("m4a");
|
||||
l.append("m4b");
|
||||
l.append("m4p");
|
||||
l.append("3g2");
|
||||
#endif
|
||||
#ifdef WITH_ASF
|
||||
l.append("wma");
|
||||
#endif
|
||||
l.append("aif");
|
||||
l.append("aiff");
|
||||
l.append("wav");
|
||||
@ -202,6 +217,17 @@ File *FileRef::create(FileName fileName, bool readAudioProperties,
|
||||
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(s.substr(s.size() - 4, 4).upper() == ".TTA")
|
||||
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
#ifdef WITH_MP4
|
||||
if(s.substr(s.size() - 4, 4).upper() == ".M4A" ||
|
||||
s.substr(s.size() - 4, 4).upper() == ".M4B" ||
|
||||
s.substr(s.size() - 4, 4).upper() == ".M4P" ||
|
||||
s.substr(s.size() - 4, 4).upper() == ".3G2")
|
||||
return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
#endif
|
||||
#ifdef WITH_ASF
|
||||
if(s.substr(s.size() - 4, 4).upper() == ".WMA")
|
||||
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
#endif
|
||||
if(s.substr(s.size() - 4, 4).upper() == ".AIF")
|
||||
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(s.substr(s.size() - 4, 4).upper() == ".WAV")
|
||||
|
||||
1
taglib/mp4/CMakeLists.txt
Normal file
1
taglib/mp4/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
INSTALL( FILES mp4file.h mp4atom.h mp4tag.h mp4item.h mp4properties.h DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
|
||||
11
taglib/mp4/Makefile.am
Normal file
11
taglib/mp4/Makefile.am
Normal file
@ -0,0 +1,11 @@
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir)/taglib \
|
||||
-I$(top_srcdir)/taglib/toolkit \
|
||||
$(all_includes)
|
||||
|
||||
noinst_LTLIBRARIES = libmp4.la
|
||||
|
||||
libmp4_la_SOURCES = mp4atom.cpp mp4file.cpp mp4item.cpp mp4properties.cpp mp4tag.cpp
|
||||
|
||||
taglib_include_HEADERS = mp4atom.h mp4file.h mp4item.h mp4properties.h mp4tag.h
|
||||
taglib_includedir = $(includedir)/taglib
|
||||
175
taglib/mp4/mp4atom.cpp
Normal file
175
taglib/mp4/mp4atom.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_MP4
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "mp4atom.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
const char *MP4::Atom::containers[10] = {
|
||||
"moov", "udta", "mdia", "meta", "ilst",
|
||||
"stbl", "minf", "moof", "traf", "trak",
|
||||
};
|
||||
|
||||
MP4::Atom::Atom(File *file)
|
||||
{
|
||||
offset = file->tell();
|
||||
ByteVector header = file->readBlock(8);
|
||||
length = header.mid(0, 4).toUInt();
|
||||
|
||||
if (length == 1) {
|
||||
debug("MP4: 64-bit atoms are not supported");
|
||||
length = 0;
|
||||
file->seek(0, File::End);
|
||||
return;
|
||||
}
|
||||
if (length < 8) {
|
||||
debug("MP4: Invalid atom size");
|
||||
length = 0;
|
||||
file->seek(0, File::End);
|
||||
return;
|
||||
}
|
||||
|
||||
name = header.mid(4, 4);
|
||||
|
||||
for(int i = 0; i < numContainers; i++) {
|
||||
if(name == containers[i]) {
|
||||
if(name == "meta") {
|
||||
file->seek(4, File::Current);
|
||||
}
|
||||
while(file->tell() < offset + length) {
|
||||
children.append(new MP4::Atom(file));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
file->seek(offset + length);
|
||||
}
|
||||
|
||||
MP4::Atom::~Atom()
|
||||
{
|
||||
for(unsigned int i = 0; i < children.size(); i++) {
|
||||
delete children[i];
|
||||
}
|
||||
children.clear();
|
||||
}
|
||||
|
||||
MP4::Atom *
|
||||
MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
if(name1 == 0) {
|
||||
return this;
|
||||
}
|
||||
for(unsigned int i = 0; i < children.size(); i++) {
|
||||
if(children[i]->name == name1) {
|
||||
return children[i]->find(name2, name3, name4);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MP4::AtomList
|
||||
MP4::Atom::findall(const char *name, bool recursive)
|
||||
{
|
||||
MP4::AtomList result;
|
||||
for(unsigned int i = 0; i < children.size(); i++) {
|
||||
if(children[i]->name == name) {
|
||||
result.append(children[i]);
|
||||
}
|
||||
if(recursive) {
|
||||
result.append(children[i]->findall(name, recursive));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3)
|
||||
{
|
||||
path.append(this);
|
||||
if(name1 == 0) {
|
||||
return true;
|
||||
}
|
||||
for(unsigned int i = 0; i < children.size(); i++) {
|
||||
if(children[i]->name == name1) {
|
||||
return children[i]->path(path, name2, name3);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MP4::Atoms::Atoms(File *file)
|
||||
{
|
||||
file->seek(0, File::End);
|
||||
long end = file->tell();
|
||||
file->seek(0);
|
||||
while(file->tell() + 8 <= end) {
|
||||
atoms.append(new MP4::Atom(file));
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Atoms::~Atoms()
|
||||
{
|
||||
for(unsigned int i = 0; i < atoms.size(); i++) {
|
||||
delete atoms[i];
|
||||
}
|
||||
atoms.clear();
|
||||
}
|
||||
|
||||
MP4::Atom *
|
||||
MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
for(unsigned int i = 0; i < atoms.size(); i++) {
|
||||
if(atoms[i]->name == name1) {
|
||||
return atoms[i]->find(name2, name3, name4);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MP4::AtomList
|
||||
MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
MP4::AtomList path;
|
||||
for(unsigned int i = 0; i < atoms.size(); i++) {
|
||||
if(atoms[i]->name == name1) {
|
||||
if(!atoms[i]->path(path, name2, name3, name4)) {
|
||||
path.clear();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
#endif
|
||||
77
taglib/mp4/mp4atom.h
Normal file
77
taglib/mp4/mp4atom.h
Normal file
@ -0,0 +1,77 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
// This file is not part of the public API!
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
#ifndef TAGLIB_MP4ATOM_H
|
||||
#define TAGLIB_MP4ATOM_H
|
||||
|
||||
#include <tfile.h>
|
||||
#include <tlist.h>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class Atom;
|
||||
typedef TagLib::List<Atom *> AtomList;
|
||||
|
||||
class Atom
|
||||
{
|
||||
public:
|
||||
Atom(File *file);
|
||||
~Atom();
|
||||
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||
bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0);
|
||||
AtomList findall(const char *name, bool recursive = false);
|
||||
long offset;
|
||||
long length;
|
||||
TagLib::ByteVector name;
|
||||
AtomList children;
|
||||
private:
|
||||
static const int numContainers = 10;
|
||||
static const char *containers[10];
|
||||
};
|
||||
|
||||
//! Root-level atoms
|
||||
class Atoms
|
||||
{
|
||||
public:
|
||||
Atoms(File *file);
|
||||
~Atoms();
|
||||
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||
AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||
AtomList atoms;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
111
taglib/mp4/mp4file.cpp
Normal file
111
taglib/mp4/mp4file.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_MP4
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "mp4atom.h"
|
||||
#include "mp4tag.h"
|
||||
#include "mp4file.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() : tag(0), atoms(0)
|
||||
{
|
||||
}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
if(atoms) {
|
||||
delete atoms;
|
||||
atoms = 0;
|
||||
}
|
||||
if(tag) {
|
||||
delete tag;
|
||||
tag = 0;
|
||||
}
|
||||
if(properties) {
|
||||
delete properties;
|
||||
properties = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Tag *tag;
|
||||
MP4::Atoms *atoms;
|
||||
MP4::Properties *properties;
|
||||
};
|
||||
|
||||
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
: TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
MP4::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
MP4::Tag *
|
||||
MP4::File::tag() const
|
||||
{
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
MP4::Properties *
|
||||
MP4::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::File::read(bool readProperties, Properties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
d->atoms = new Atoms(this);
|
||||
d->tag = new Tag(this, d->atoms);
|
||||
if(readProperties) {
|
||||
d->properties = new Properties(this, d->atoms, audioPropertiesStyle);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::File::save()
|
||||
{
|
||||
return d->tag->save();
|
||||
}
|
||||
|
||||
#endif
|
||||
102
taglib/mp4/mp4file.h
Normal file
102
taglib/mp4/mp4file.h
Normal file
@ -0,0 +1,102 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4FILE_H
|
||||
#define TAGLIB_MP4FILE_H
|
||||
|
||||
#include <tag.h>
|
||||
#include <tfile.h>
|
||||
#include "taglib_export.h"
|
||||
#include "mp4properties.h"
|
||||
#include "mp4tag.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! An implementation of MP4 (AAC, ALAC, ...) metadata
|
||||
namespace MP4 {
|
||||
|
||||
class Atoms;
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for MP4 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 MP4 files.
|
||||
*/
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Contructs an ASF 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.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the MP4 tag of the file.
|
||||
*
|
||||
* MP4::Tag implements the tag interface, so this serves as the
|
||||
* reimplementation of TagLib::File::tag().
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the ASF::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the MP4 audio properties for this file.
|
||||
*/
|
||||
Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
private:
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle audioPropertiesStyle);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
136
taglib/mp4/mp4item.cpp
Normal file
136
taglib/mp4/mp4item.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_MP4
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include "mp4item.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::Item::ItemPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
ItemPrivate() : RefCounter(), valid(true) {}
|
||||
|
||||
bool valid;
|
||||
union {
|
||||
bool m_bool;
|
||||
int m_int;
|
||||
IntPair m_intPair;
|
||||
};
|
||||
StringList m_stringList;
|
||||
};
|
||||
|
||||
MP4::Item::Item()
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->valid = false;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const Item &item) : d(item.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
MP4::Item &
|
||||
MP4::Item::operator=(const Item &item)
|
||||
{
|
||||
if(d->deref()) {
|
||||
delete d;
|
||||
}
|
||||
d = item.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MP4::Item::~Item()
|
||||
{
|
||||
if(d->deref()) {
|
||||
delete d;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Item::Item(bool value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_bool = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(int value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_int = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(int value1, int value2)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_intPair.first = value1;
|
||||
d->m_intPair.second = value2;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const StringList &value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_stringList = value;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Item::toBool() const
|
||||
{
|
||||
return d->m_bool;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Item::toInt() const
|
||||
{
|
||||
return d->m_int;
|
||||
}
|
||||
|
||||
MP4::Item::IntPair
|
||||
MP4::Item::toIntPair() const
|
||||
{
|
||||
return d->m_intPair;
|
||||
}
|
||||
|
||||
StringList
|
||||
MP4::Item::toStringList() const
|
||||
{
|
||||
return d->m_stringList;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Item::isValid() const
|
||||
{
|
||||
return d->valid;
|
||||
}
|
||||
|
||||
#endif
|
||||
69
taglib/mp4/mp4item.h
Normal file
69
taglib/mp4/mp4item.h
Normal file
@ -0,0 +1,69 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4ITEM_H
|
||||
#define TAGLIB_MP4ITEM_H
|
||||
|
||||
#include <tstringlist.h>
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class TAGLIB_EXPORT Item
|
||||
{
|
||||
public:
|
||||
struct IntPair {
|
||||
int first, second;
|
||||
};
|
||||
|
||||
Item();
|
||||
Item(const Item &item);
|
||||
Item &operator=(const Item &item);
|
||||
~Item();
|
||||
|
||||
Item(int value);
|
||||
Item(bool value);
|
||||
Item(int first, int second);
|
||||
Item(const StringList &value);
|
||||
|
||||
int toInt() const;
|
||||
bool toBool() const;
|
||||
IntPair toIntPair() const;
|
||||
StringList toStringList() const;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
class ItemPrivate;
|
||||
ItemPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
169
taglib/mp4/mp4properties.cpp
Normal file
169
taglib/mp4/mp4properties.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_MP4
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "mp4file.h"
|
||||
#include "mp4atom.h"
|
||||
#include "mp4properties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), bitsPerSample(0) {}
|
||||
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int bitsPerSample;
|
||||
};
|
||||
|
||||
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
|
||||
: AudioProperties(style)
|
||||
{
|
||||
d = new PropertiesPrivate;
|
||||
|
||||
MP4::Atom *moov = atoms->find("moov");
|
||||
if(!moov) {
|
||||
debug("MP4: Atom 'moov' not found");
|
||||
return;
|
||||
}
|
||||
|
||||
MP4::Atom *trak = 0;
|
||||
ByteVector data;
|
||||
|
||||
MP4::AtomList trakList = moov->findall("trak");
|
||||
for (unsigned int i = 0; i < trakList.size(); i++) {
|
||||
trak = trakList[i];
|
||||
MP4::Atom *hdlr = trak->find("mdia", "hdlr");
|
||||
if(!hdlr) {
|
||||
debug("MP4: Atom 'trak.mdia.hdlr' not found");
|
||||
return;
|
||||
}
|
||||
file->seek(hdlr->offset);
|
||||
data = file->readBlock(hdlr->length);
|
||||
if(data.mid(16, 4) == "soun") {
|
||||
break;
|
||||
}
|
||||
trak = 0;
|
||||
}
|
||||
if (!trak) {
|
||||
debug("MP4: No audio tracks");
|
||||
return;
|
||||
}
|
||||
|
||||
MP4::Atom *mdhd = trak->find("mdia", "mdhd");
|
||||
if(!mdhd) {
|
||||
debug("MP4: Atom 'trak.mdia.mdhd' not found");
|
||||
return;
|
||||
}
|
||||
|
||||
file->seek(mdhd->offset);
|
||||
data = file->readBlock(mdhd->length);
|
||||
if(data[8] == 0) {
|
||||
unsigned int unit = data.mid(20, 4).toUInt();
|
||||
unsigned int length = data.mid(24, 4).toUInt();
|
||||
d->length = length / unit;
|
||||
}
|
||||
else {
|
||||
long long unit = data.mid(28, 8).toLongLong();
|
||||
long long length = data.mid(36, 8).toLongLong();
|
||||
d->length = int(length / unit);
|
||||
}
|
||||
|
||||
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
|
||||
if(!atom) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->seek(atom->offset);
|
||||
data = file->readBlock(atom->length);
|
||||
if(data.mid(20, 4) == "mp4a") {
|
||||
d->channels = data.mid(40, 2).toShort();
|
||||
d->bitsPerSample = data.mid(42, 2).toShort();
|
||||
d->sampleRate = data.mid(46, 4).toUInt();
|
||||
if(data.mid(56, 4) == "esds" && data[64] == 0x03) {
|
||||
long pos = 65;
|
||||
if(data.mid(pos, 3) == "\x80\x80\x80") {
|
||||
pos += 3;
|
||||
}
|
||||
pos += 4;
|
||||
if(data[pos] == 0x04) {
|
||||
pos += 1;
|
||||
if(data.mid(pos, 3) == "\x80\x80\x80") {
|
||||
pos += 3;
|
||||
}
|
||||
pos += 10;
|
||||
d->bitrate = (data.mid(pos, 4).toUInt() + 500) / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::bitsPerSample() const
|
||||
{
|
||||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
#endif
|
||||
61
taglib/mp4/mp4properties.h
Normal file
61
taglib/mp4/mp4properties.h
Normal file
@ -0,0 +1,61 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4PROPERTIES_H
|
||||
#define TAGLIB_MP4PROPERTIES_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class Atoms;
|
||||
class File;
|
||||
|
||||
//! An implementation of MP4 audio properties
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||
{
|
||||
public:
|
||||
Properties(File *file, Atoms *atoms, ReadStyle style = Average);
|
||||
virtual ~Properties();
|
||||
|
||||
virtual int length() const;
|
||||
virtual int bitrate() const;
|
||||
virtual int sampleRate() const;
|
||||
virtual int channels() const;
|
||||
virtual int bitsPerSample() const;
|
||||
|
||||
private:
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
558
taglib/mp4/mp4tag.cpp
Normal file
558
taglib/mp4/mp4tag.cpp
Normal file
@ -0,0 +1,558 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_MP4
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "mp4atom.h"
|
||||
#include "mp4tag.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() : file(0), atoms(0) {}
|
||||
~TagPrivate() {}
|
||||
File *file;
|
||||
Atoms *atoms;
|
||||
ItemListMap items;
|
||||
};
|
||||
|
||||
MP4::Tag::Tag(File *file, MP4::Atoms *atoms)
|
||||
{
|
||||
d = new TagPrivate;
|
||||
d->file = file;
|
||||
d->atoms = atoms;
|
||||
|
||||
MP4::Atom *ilst = atoms->find("moov", "udta", "meta", "ilst");
|
||||
if(!ilst) {
|
||||
//debug("Atom moov.udta.meta.ilst not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < ilst->children.size(); i++) {
|
||||
MP4::Atom *atom = ilst->children[i];
|
||||
file->seek(atom->offset + 8);
|
||||
if(atom->name == "----") {
|
||||
parseFreeForm(atom, file);
|
||||
}
|
||||
else if(atom->name == "trkn" || atom->name == "disk") {
|
||||
parseIntPair(atom, file);
|
||||
}
|
||||
else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst") {
|
||||
parseBool(atom, file);
|
||||
}
|
||||
else if(atom->name == "tmpo") {
|
||||
parseInt(atom, file);
|
||||
}
|
||||
else {
|
||||
parseText(atom, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVectorList
|
||||
MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm)
|
||||
{
|
||||
ByteVectorList result;
|
||||
ByteVector data = file->readBlock(atom->length - 8);
|
||||
int i = 0;
|
||||
unsigned int pos = 0;
|
||||
while(pos < data.size()) {
|
||||
int length = data.mid(pos, 4).toUInt();
|
||||
ByteVector name = data.mid(pos + 4, 4);
|
||||
int flags = data.mid(pos + 8, 4).toUInt();
|
||||
if(freeForm && i < 2) {
|
||||
if(i == 0 && name != "mean") {
|
||||
debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\"");
|
||||
return result;
|
||||
}
|
||||
else if(i == 1 && name != "name") {
|
||||
debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\"");
|
||||
return result;
|
||||
}
|
||||
result.append(data.mid(pos + 12, length - 12));
|
||||
}
|
||||
else {
|
||||
if(name != "data") {
|
||||
debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
|
||||
return result;
|
||||
}
|
||||
if(expectedFlags == -1 || flags == expectedFlags) {
|
||||
result.append(data.mid(pos + 16, length - 16));
|
||||
}
|
||||
}
|
||||
pos += length;
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
d->items.insert(atom->name, (int)data[0].toShort());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
int a = data[0].mid(2, 2).toShort();
|
||||
int b = data[0].mid(4, 2).toShort();
|
||||
d->items.insert(atom->name, MP4::Item(a, b));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
d->items.insert(atom->name, data[0][0] != '\0');
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file, expectedFlags);
|
||||
if(data.size()) {
|
||||
StringList value;
|
||||
for(unsigned int i = 0; i < data.size(); i++) {
|
||||
value.append(String(data[i], String::UTF8));
|
||||
}
|
||||
d->items.insert(atom->name, value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file, 1, true);
|
||||
if(data.size() > 2) {
|
||||
StringList value;
|
||||
for(unsigned int i = 2; i < data.size(); i++) {
|
||||
value.append(String(data[i], String::UTF8));
|
||||
}
|
||||
String name = "----:" + data[0] + ":" + data[1];
|
||||
d->items.insert(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::padIlst(const ByteVector &data, int length)
|
||||
{
|
||||
if (length == -1) {
|
||||
length = ((data.size() + 1023) & ~1023) - data.size();
|
||||
}
|
||||
return renderAtom("free", ByteVector(length, '\1'));
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data)
|
||||
{
|
||||
return ByteVector::fromUInt(data.size() + 8) + name + data;
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data)
|
||||
{
|
||||
ByteVector result;
|
||||
for(unsigned int i = 0; i < data.size(); i++) {
|
||||
result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + data[i]));
|
||||
}
|
||||
return renderAtom(name, result);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderBool(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(1, item.toBool() ? '\1' : '\0'));
|
||||
return renderData(name, 0x15, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderInt(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector::fromShort(item.toInt()));
|
||||
return renderData(name, 0x15, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderIntPair(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(2, '\0') +
|
||||
ByteVector::fromShort(item.toIntPair().first) +
|
||||
ByteVector::fromShort(item.toIntPair().second) +
|
||||
ByteVector(2, '\0'));
|
||||
return renderData(name, 0x15, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(2, '\0') +
|
||||
ByteVector::fromShort(item.toIntPair().first) +
|
||||
ByteVector::fromShort(item.toIntPair().second));
|
||||
return renderData(name, 0x15, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderText(const ByteVector &name, MP4::Item &item, int flags)
|
||||
{
|
||||
ByteVectorList data;
|
||||
StringList value = item.toStringList();
|
||||
for(unsigned int i = 0; i < value.size(); i++) {
|
||||
data.append(value[i].data(String::UTF8));
|
||||
}
|
||||
return renderData(name, flags, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderFreeForm(const String &name, MP4::Item &item)
|
||||
{
|
||||
StringList header = StringList::split(name, ":");
|
||||
if (header.size() != 3) {
|
||||
debug("MP4: Invalid free-form item name \"" + name + "\"");
|
||||
return ByteVector::null;
|
||||
}
|
||||
ByteVector data;
|
||||
data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8)));
|
||||
data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8)));
|
||||
StringList value = item.toStringList();
|
||||
for(unsigned int i = 0; i < value.size(); i++) {
|
||||
data.append(renderAtom("data", ByteVector::fromUInt(1) + ByteVector(4, '\0') + value[i].data(String::UTF8)));
|
||||
}
|
||||
return renderAtom("----", data);
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Tag::save()
|
||||
{
|
||||
ByteVector data;
|
||||
for(MP4::ItemListMap::Iterator i = d->items.begin(); i != d->items.end(); i++) {
|
||||
const String name = i->first;
|
||||
if(name.startsWith("----")) {
|
||||
data.append(renderFreeForm(name, i->second));
|
||||
}
|
||||
else if(name == "trkn") {
|
||||
data.append(renderIntPair(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "disk") {
|
||||
data.append(renderIntPairNoTrailing(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "cpil" || name == "pgap" || name == "pcst") {
|
||||
data.append(renderBool(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "tmpo") {
|
||||
data.append(renderInt(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name.size() == 4){
|
||||
data.append(renderText(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else {
|
||||
debug("MP4: Unknown item name \"" + name + "\"");
|
||||
}
|
||||
}
|
||||
data = renderAtom("ilst", data);
|
||||
|
||||
AtomList path = d->atoms->path("moov", "udta", "meta", "ilst");
|
||||
if(path.size() == 4) {
|
||||
saveExisting(data, path);
|
||||
}
|
||||
else {
|
||||
saveNew(data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::updateParents(AtomList &path, long delta, int ignore)
|
||||
{
|
||||
for(unsigned int i = 0; i < path.size() - ignore; i++) {
|
||||
d->file->seek(path[i]->offset);
|
||||
long size = d->file->readBlock(4).toUInt() + delta;
|
||||
d->file->seek(path[i]->offset);
|
||||
d->file->writeBlock(ByteVector::fromUInt(size));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::updateOffsets(long delta, long offset)
|
||||
{
|
||||
MP4::Atom *moov = d->atoms->find("moov");
|
||||
if(moov) {
|
||||
MP4::AtomList stco = moov->findall("stco", true);
|
||||
for(unsigned int i = 0; i < stco.size(); i++) {
|
||||
MP4::Atom *atom = stco[i];
|
||||
if(atom->offset > offset) {
|
||||
atom->offset += delta;
|
||||
}
|
||||
d->file->seek(atom->offset + 12);
|
||||
ByteVector data = d->file->readBlock(atom->length - 12);
|
||||
unsigned int count = data.mid(0, 4).toUInt();
|
||||
d->file->seek(atom->offset + 16);
|
||||
int pos = 4;
|
||||
while(count--) {
|
||||
long o = data.mid(pos, 4).toUInt();
|
||||
if(o > offset) {
|
||||
o += delta;
|
||||
}
|
||||
d->file->writeBlock(ByteVector::fromUInt(o));
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::AtomList co64 = moov->findall("co64", true);
|
||||
for(unsigned int i = 0; i < co64.size(); i++) {
|
||||
MP4::Atom *atom = co64[i];
|
||||
if(atom->offset > offset) {
|
||||
atom->offset += delta;
|
||||
}
|
||||
d->file->seek(atom->offset + 12);
|
||||
ByteVector data = d->file->readBlock(atom->length - 12);
|
||||
unsigned int count = data.mid(0, 4).toUInt();
|
||||
d->file->seek(atom->offset + 16);
|
||||
int pos = 4;
|
||||
while(count--) {
|
||||
long long o = data.mid(pos, 8).toLongLong();
|
||||
if(o > offset) {
|
||||
o += delta;
|
||||
}
|
||||
d->file->writeBlock(ByteVector::fromLongLong(o));
|
||||
pos += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Atom *moof = d->atoms->find("moof");
|
||||
if(moof) {
|
||||
MP4::AtomList tfhd = moof->findall("tfhd", true);
|
||||
for(unsigned int i = 0; i < tfhd.size(); i++) {
|
||||
MP4::Atom *atom = tfhd[i];
|
||||
if(atom->offset > offset) {
|
||||
atom->offset += delta;
|
||||
}
|
||||
d->file->seek(atom->offset + 9);
|
||||
ByteVector data = d->file->readBlock(atom->offset - 9);
|
||||
unsigned int flags = (ByteVector(1, '\0') + data.mid(0, 3)).toUInt();
|
||||
if(flags & 1) {
|
||||
long long o = data.mid(7, 8).toLongLong();
|
||||
if(o > offset) {
|
||||
o += delta;
|
||||
}
|
||||
d->file->seek(atom->offset + 16);
|
||||
d->file->writeBlock(ByteVector::fromLongLong(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::saveNew(ByteVector &data)
|
||||
{
|
||||
data = renderAtom("meta", TagLib::ByteVector(4, '\0') +
|
||||
renderAtom("hdlr", TagLib::ByteVector(8, '\0') + TagLib::ByteVector("mdirappl") + TagLib::ByteVector(9, '\0')) +
|
||||
data + padIlst(data));
|
||||
|
||||
AtomList path = d->atoms->path("moov", "udta");
|
||||
if(path.size() != 2) {
|
||||
path = d->atoms->path("moov");
|
||||
data = renderAtom("udta", data);
|
||||
}
|
||||
|
||||
long offset = path[path.size() - 1]->offset + 8;
|
||||
d->file->insert(data, offset, 0);
|
||||
|
||||
updateParents(path, data.size());
|
||||
updateOffsets(data.size(), offset);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::saveExisting(ByteVector &data, AtomList &path)
|
||||
{
|
||||
MP4::Atom *ilst = path[path.size() - 1];
|
||||
long offset = ilst->offset;
|
||||
long length = ilst->length;
|
||||
|
||||
MP4::Atom *meta = path[path.size() - 2];
|
||||
AtomList::Iterator index = meta->children.find(ilst);
|
||||
if(index != meta->children.begin()) {
|
||||
AtomList::Iterator prevIndex = index;
|
||||
prevIndex--;
|
||||
MP4::Atom *prev = *prevIndex;
|
||||
if(prev->name == "free") {
|
||||
offset = prev->offset;
|
||||
length += prev->length;
|
||||
}
|
||||
}
|
||||
if(index != meta->children.end()) {
|
||||
AtomList::Iterator nextIndex = index;
|
||||
nextIndex++;
|
||||
MP4::Atom *next = *nextIndex;
|
||||
if(next->name == "free") {
|
||||
length += next->length;
|
||||
}
|
||||
}
|
||||
|
||||
long delta = data.size() - length;
|
||||
if(delta > 0 || (delta < 0 && delta > -8)) {
|
||||
data.append(padIlst(data));
|
||||
delta = data.size() - length;
|
||||
}
|
||||
else if(delta < 0) {
|
||||
data.append(padIlst(data, -delta - 8));
|
||||
delta = 0;
|
||||
}
|
||||
|
||||
d->file->insert(data, offset, length);
|
||||
|
||||
if(delta) {
|
||||
updateParents(path, delta, 1);
|
||||
updateOffsets(delta, offset);
|
||||
}
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::title() const
|
||||
{
|
||||
if(d->items.contains("\251nam"))
|
||||
return d->items["\251nam"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::artist() const
|
||||
{
|
||||
if(d->items.contains("\251ART"))
|
||||
return d->items["\251ART"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::album() const
|
||||
{
|
||||
if(d->items.contains("\251alb"))
|
||||
return d->items["\251alb"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::comment() const
|
||||
{
|
||||
if(d->items.contains("\251cmt"))
|
||||
return d->items["\251cmt"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::genre() const
|
||||
{
|
||||
if(d->items.contains("\251gen"))
|
||||
return d->items["\251gen"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MP4::Tag::year() const
|
||||
{
|
||||
if(d->items.contains("\251day"))
|
||||
return d->items["\251day"].toStringList().toString().toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MP4::Tag::track() const
|
||||
{
|
||||
if(d->items.contains("trkn"))
|
||||
return d->items["trkn"].toIntPair().first;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setTitle(const String &value)
|
||||
{
|
||||
d->items["\251nam"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setArtist(const String &value)
|
||||
{
|
||||
d->items["\251ART"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setAlbum(const String &value)
|
||||
{
|
||||
d->items["\251alb"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setComment(const String &value)
|
||||
{
|
||||
d->items["\251cmt"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setGenre(const String &value)
|
||||
{
|
||||
d->items["\251gen"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setYear(uint value)
|
||||
{
|
||||
d->items["\251day"] = StringList(String::number(value));
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setTrack(uint value)
|
||||
{
|
||||
d->items["trkn"] = MP4::Item(value, 0);
|
||||
}
|
||||
|
||||
MP4::ItemListMap &
|
||||
MP4::Tag::itemListMap()
|
||||
{
|
||||
return d->items;
|
||||
}
|
||||
|
||||
#endif
|
||||
100
taglib/mp4/mp4tag.h
Normal file
100
taglib/mp4/mp4tag.h
Normal file
@ -0,0 +1,100 @@
|
||||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4TAG_H
|
||||
#define TAGLIB_MP4TAG_H
|
||||
|
||||
#include <tag.h>
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tfile.h>
|
||||
#include <tmap.h>
|
||||
#include <tstringlist.h>
|
||||
#include "taglib_export.h"
|
||||
#include "mp4atom.h"
|
||||
#include "mp4item.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
typedef TagLib::Map<String, Item> ItemListMap;
|
||||
|
||||
class TAGLIB_EXPORT Tag: public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
Tag(TagLib::File *file, Atoms *atoms);
|
||||
bool save();
|
||||
|
||||
String title() const;
|
||||
String artist() const;
|
||||
String album() const;
|
||||
String comment() const;
|
||||
String genre() const;
|
||||
uint year() const;
|
||||
uint track() const;
|
||||
|
||||
void setTitle(const String &value);
|
||||
void setArtist(const String &value);
|
||||
void setAlbum(const String &value);
|
||||
void setComment(const String &value);
|
||||
void setGenre(const String &value);
|
||||
void setYear(uint value);
|
||||
void setTrack(uint value);
|
||||
|
||||
ItemListMap &itemListMap();
|
||||
|
||||
private:
|
||||
TagLib::ByteVectorList parseData(Atom *atom, TagLib::File *file, int expectedFlags = -1, bool freeForm = false);
|
||||
void parseText(Atom *atom, TagLib::File *file, int expectedFlags = 1);
|
||||
void parseFreeForm(Atom *atom, TagLib::File *file);
|
||||
void parseInt(Atom *atom, TagLib::File *file);
|
||||
void parseIntPair(Atom *atom, TagLib::File *file);
|
||||
void parseBool(Atom *atom, TagLib::File *file);
|
||||
|
||||
TagLib::ByteVector padIlst(const ByteVector &data, int length = -1);
|
||||
TagLib::ByteVector renderAtom(const ByteVector &name, const TagLib::ByteVector &data);
|
||||
TagLib::ByteVector renderData(const ByteVector &name, int flags, const TagLib::ByteVectorList &data);
|
||||
TagLib::ByteVector renderText(const ByteVector &name, Item &item, int flags = 1);
|
||||
TagLib::ByteVector renderFreeForm(const String &name, Item &item);
|
||||
TagLib::ByteVector renderBool(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderInt(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderIntPair(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderIntPairNoTrailing(const ByteVector &name, Item &item);
|
||||
|
||||
void updateParents(AtomList &path, long delta, int ignore = 0);
|
||||
void updateOffsets(long delta, long offset);
|
||||
|
||||
void saveNew(TagLib::ByteVector &data);
|
||||
void saveExisting(TagLib::ByteVector &data, AtomList &path);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -14,6 +14,7 @@ DEPENDPATH += . \
|
||||
ape \
|
||||
flac \
|
||||
mpc \
|
||||
mp4 \
|
||||
mpeg \
|
||||
ogg \
|
||||
ogg/speex \
|
||||
@ -33,6 +34,7 @@ INCLUDEPATH += . \
|
||||
flac \
|
||||
ogg/flac \
|
||||
mpc \
|
||||
mp4 \
|
||||
wavpack \
|
||||
ogg/speex \
|
||||
trueaudio \
|
||||
@ -54,6 +56,10 @@ HEADERS += audioproperties.h \
|
||||
flac/flacproperties.h \
|
||||
mpc/mpcfile.h \
|
||||
mpc/mpcproperties.h \
|
||||
mp4/mp4atom.h \
|
||||
mp4/mp4item.h \
|
||||
mp4/mp4file.h \
|
||||
mp4/mp4properties.h \
|
||||
mpeg/mpegfile.h \
|
||||
mpeg/mpegheader.h \
|
||||
mpeg/mpegproperties.h \
|
||||
@ -111,6 +117,10 @@ SOURCES += audioproperties.cpp \
|
||||
ape/apetag.cpp \
|
||||
flac/flacfile.cpp \
|
||||
flac/flacproperties.cpp \
|
||||
mp4/mp4atom.cpp \
|
||||
mp4/mp4item.cpp \
|
||||
mp4/mp4file.cpp \
|
||||
mp4/mp4properties.cpp \
|
||||
mpc/mpcfile.cpp \
|
||||
mpc/mpcproperties.cpp \
|
||||
mpeg/mpegfile.cpp \
|
||||
@ -168,6 +178,10 @@ SOURCES += audioproperties.cpp \
|
||||
ape/apetag.h \
|
||||
flac/flacfile.h \
|
||||
flac/flacproperties.h \
|
||||
mp4/mp4atom.h \
|
||||
mp4/mp4item.h \
|
||||
mp4/mp4file.h \
|
||||
mp4/mp4properties.h \
|
||||
mpc/mpcfile.h \
|
||||
mpc/mpcproperties.h \
|
||||
mpeg/mpegfile.h \
|
||||
|
||||
@ -3,10 +3,12 @@ if(BUILD_TESTS)
|
||||
INCLUDE_DIRECTORIES(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/toolkit
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/asf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v1
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2/frames
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mp4
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/trueaudio
|
||||
)
|
||||
|
||||
@ -23,6 +25,12 @@ SET(test_runner_SRCS
|
||||
test_id3v1.cpp
|
||||
test_id3v2.cpp
|
||||
)
|
||||
IF(WITH_MP4)
|
||||
SET(test_runner_SRCS ${test_runner_SRCS} test_mp4.cpp)
|
||||
ENDIF(WITH_MP4)
|
||||
IF(WITH_ASF)
|
||||
SET(test_runner_SRCS ${test_runner_SRCS} test_asf.cpp)
|
||||
ENDIF(WITH_ASF)
|
||||
|
||||
ADD_EXECUTABLE(test_runner ${test_runner_SRCS})
|
||||
TARGET_LINK_LIBRARIES(test_runner tag ${CPPUNIT_LIBRARIES})
|
||||
|
||||
BIN
tests/data/click.wv
Normal file
BIN
tests/data/click.wv
Normal file
Binary file not shown.
BIN
tests/data/has-tags.m4a
Normal file
BIN
tests/data/has-tags.m4a
Normal file
Binary file not shown.
BIN
tests/data/no-tags.3g2
Normal file
BIN
tests/data/no-tags.3g2
Normal file
Binary file not shown.
BIN
tests/data/no-tags.m4a
Normal file
BIN
tests/data/no-tags.m4a
Normal file
Binary file not shown.
BIN
tests/data/silence-1.wma
Normal file
BIN
tests/data/silence-1.wma
Normal file
Binary file not shown.
103
tests/test_asf.cpp
Normal file
103
tests/test_asf.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <tag.h>
|
||||
#include <tstringlist.h>
|
||||
#include <tbytevectorlist.h>
|
||||
#include <asffile.h>
|
||||
#include "utils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace TagLib;
|
||||
|
||||
class TestASF : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(TestASF);
|
||||
CPPUNIT_TEST(testProperties);
|
||||
CPPUNIT_TEST(testRead);
|
||||
CPPUNIT_TEST(testSaveMultipleValues);
|
||||
CPPUNIT_TEST(testSaveStream);
|
||||
CPPUNIT_TEST(testSaveLanguage);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
|
||||
void testProperties()
|
||||
{
|
||||
ASF::File f("data/silence-1.wma");
|
||||
CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->length());
|
||||
CPPUNIT_ASSERT_EQUAL(64, f.audioProperties()->bitrate());
|
||||
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
|
||||
CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate());
|
||||
}
|
||||
|
||||
void testRead()
|
||||
{
|
||||
ASF::File f("data/silence-1.wma");
|
||||
CPPUNIT_ASSERT_EQUAL(String("test"), f.tag()->title());
|
||||
}
|
||||
|
||||
void testSaveMultipleValues()
|
||||
{
|
||||
string newname = copyFile("silence-1", ".wma");
|
||||
|
||||
ASF::File *f = new ASF::File(newname.c_str());
|
||||
ASF::AttributeList values;
|
||||
values.append("Foo");
|
||||
values.append("Bar");
|
||||
f->tag()->attributeListMap()["WM/AlbumTitle"] = values;
|
||||
f->save();
|
||||
delete f;
|
||||
|
||||
f = new ASF::File(newname.c_str());
|
||||
CPPUNIT_ASSERT_EQUAL(2, (int)f->tag()->attributeListMap()["WM/AlbumTitle"].size());
|
||||
delete f;
|
||||
|
||||
deleteFile(newname);
|
||||
}
|
||||
|
||||
void testSaveStream()
|
||||
{
|
||||
string newname = copyFile("silence-1", ".wma");
|
||||
|
||||
ASF::File *f = new ASF::File(newname.c_str());
|
||||
ASF::AttributeList values;
|
||||
ASF::Attribute attr("Foo");
|
||||
attr.setStream(43);
|
||||
values.append(attr);
|
||||
f->tag()->attributeListMap()["WM/AlbumTitle"] = values;
|
||||
f->save();
|
||||
delete f;
|
||||
|
||||
f = new ASF::File(newname.c_str());
|
||||
CPPUNIT_ASSERT_EQUAL(43, f->tag()->attributeListMap()["WM/AlbumTitle"][0].stream());
|
||||
delete f;
|
||||
|
||||
deleteFile(newname);
|
||||
}
|
||||
|
||||
void testSaveLanguage()
|
||||
{
|
||||
string newname = copyFile("silence-1", ".wma");
|
||||
|
||||
ASF::File *f = new ASF::File(newname.c_str());
|
||||
ASF::AttributeList values;
|
||||
ASF::Attribute attr("Foo");
|
||||
attr.setStream(32);
|
||||
attr.setLanguage(56);
|
||||
values.append(attr);
|
||||
f->tag()->attributeListMap()["WM/AlbumTitle"] = values;
|
||||
f->save();
|
||||
delete f;
|
||||
|
||||
f = new ASF::File(newname.c_str());
|
||||
CPPUNIT_ASSERT_EQUAL(32, f->tag()->attributeListMap()["WM/AlbumTitle"][0].stream());
|
||||
CPPUNIT_ASSERT_EQUAL(56, f->tag()->attributeListMap()["WM/AlbumTitle"][0].language());
|
||||
delete f;
|
||||
|
||||
deleteFile(newname);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestASF);
|
||||
@ -11,11 +11,15 @@ using namespace TagLib;
|
||||
class TestFileRef : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(TestFileRef);
|
||||
CPPUNIT_TEST(testASF);
|
||||
CPPUNIT_TEST(testMusepack);
|
||||
CPPUNIT_TEST(testVorbis);
|
||||
CPPUNIT_TEST(testSpeex);
|
||||
CPPUNIT_TEST(testFLAC);
|
||||
CPPUNIT_TEST(testMP3);
|
||||
CPPUNIT_TEST(testMP4_1);
|
||||
CPPUNIT_TEST(testMP4_2);
|
||||
CPPUNIT_TEST(testMP4_3);
|
||||
CPPUNIT_TEST(testTrueAudio);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
@ -71,6 +75,11 @@ public:
|
||||
fileRefSave("click", ".mpc");
|
||||
}
|
||||
|
||||
void testASF()
|
||||
{
|
||||
fileRefSave("silence-1", ".wma");
|
||||
}
|
||||
|
||||
void testVorbis()
|
||||
{
|
||||
fileRefSave("empty", ".ogg");
|
||||
@ -96,6 +105,21 @@ public:
|
||||
fileRefSave("empty", ".tta");
|
||||
}
|
||||
|
||||
void testMP4_1()
|
||||
{
|
||||
fileRefSave("has-tags", ".m4a");
|
||||
}
|
||||
|
||||
void testMP4_2()
|
||||
{
|
||||
fileRefSave("no-tags", ".m4a");
|
||||
}
|
||||
|
||||
void testMP4_3()
|
||||
{
|
||||
fileRefSave("no-tags", ".3g2");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestFileRef);
|
||||
|
||||
103
tests/test_mp4.cpp
Normal file
103
tests/test_mp4.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <tag.h>
|
||||
#include <mp4tag.h>
|
||||
#include <tbytevectorlist.h>
|
||||
#include <mp4atom.h>
|
||||
#include <mp4file.h>
|
||||
#include "utils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace TagLib;
|
||||
|
||||
class TestMP4 : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(TestMP4);
|
||||
CPPUNIT_TEST(testProperties);
|
||||
CPPUNIT_TEST(testFreeForm);
|
||||
CPPUNIT_TEST(testUpdateStco);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
|
||||
void testProperties()
|
||||
{
|
||||
MP4::File f("data/has-tags.m4a");
|
||||
CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length());
|
||||
CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->bitrate());
|
||||
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
|
||||
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
|
||||
CPPUNIT_ASSERT_EQUAL(16, ((MP4::Properties *)f.audioProperties())->bitsPerSample());
|
||||
}
|
||||
|
||||
void testUpdateStco()
|
||||
{
|
||||
string filename = copyFile("no-tags", ".3g2");
|
||||
|
||||
MP4::File *f = new MP4::File(filename.c_str());
|
||||
f->tag()->setArtist(ByteVector(3000, 'x'));
|
||||
|
||||
ByteVectorList data1;
|
||||
{
|
||||
MP4::Atoms a(f);
|
||||
MP4::Atom *stco = a.find("moov")->findall("stco", true)[0];
|
||||
f->seek(stco->offset + 12);
|
||||
ByteVector data = f->readBlock(stco->length - 12);
|
||||
unsigned int count = data.mid(0, 4).toUInt();
|
||||
int pos = 4;
|
||||
while (count--) {
|
||||
unsigned int offset = data.mid(pos, 4).toUInt();
|
||||
f->seek(offset);
|
||||
data1.append(f->readBlock(20));
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
f->save();
|
||||
delete f;
|
||||
f = new MP4::File(filename.c_str());
|
||||
|
||||
{
|
||||
MP4::Atoms a(f);
|
||||
MP4::Atom *stco = a.find("moov")->findall("stco", true)[0];
|
||||
f->seek(stco->offset + 12);
|
||||
ByteVector data = f->readBlock(stco->length - 12);
|
||||
unsigned int count = data.mid(0, 4).toUInt();
|
||||
int pos = 4, i = 0;
|
||||
while (count--) {
|
||||
unsigned int offset = data.mid(pos, 4).toUInt();
|
||||
f->seek(offset);
|
||||
CPPUNIT_ASSERT_EQUAL(data1[i], f->readBlock(20));
|
||||
pos += 4;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
delete f;
|
||||
|
||||
deleteFile(filename);
|
||||
}
|
||||
|
||||
void testFreeForm()
|
||||
{
|
||||
string filename = copyFile("has-tags", ".m4a");
|
||||
|
||||
MP4::File *f = new MP4::File(filename.c_str());
|
||||
CPPUNIT_ASSERT(f->tag()->itemListMap().contains("----:com.apple.iTunes:iTunNORM"));
|
||||
f->tag()->itemListMap()["----:org.kde.TagLib:Foo"] = StringList("Bar");
|
||||
f->save();
|
||||
delete f;
|
||||
|
||||
f = new MP4::File(filename.c_str());
|
||||
CPPUNIT_ASSERT(f->tag()->itemListMap().contains("----:org.kde.TagLib:Foo"));
|
||||
CPPUNIT_ASSERT_EQUAL(String("Bar"), f->tag()->itemListMap()["----:org.kde.TagLib:Foo"].toStringList()[0]);
|
||||
f->save();
|
||||
delete f;
|
||||
|
||||
deleteFile(filename);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4);
|
||||
Reference in New Issue
Block a user