diff -Naur amarok-1.4.10/amarok/src/metadata/mp4/mp4file.cpp amarok-1.4.10.new/amarok/src/metadata/mp4/mp4file.cpp --- amarok-1.4.10/amarok/src/metadata/mp4/mp4file.cpp 2008-08-13 23:21:51.000000000 +0200 +++ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4file.cpp 2010-02-27 14:32:05.687651410 +0100 @@ -28,6 +28,7 @@ #include "mp4tag.h" #include #include +#include #include diff -Naur amarok-1.4.10/amarok/src/metadata/mp4/mp4file.cpp~ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4file.cpp~ --- amarok-1.4.10/amarok/src/metadata/mp4/mp4file.cpp~ 1970-01-01 01:00:00.000000000 +0100 +++ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4file.cpp~ 2010-02-27 14:31:41.439999097 +0100 @@ -0,0 +1,198 @@ +/*************************************************************************** +copyright : (C) 2005 by Andy Leadbetter +email : andrew.leadbetter@gmail.com + +copyright : (C) 2005 by Martin Aumueller +email : aumuell@reserv.at + (write support) + ***************************************************************************/ + +/*************************************************************************** + * 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., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301 USA * + ***************************************************************************/ + +#include "mp4file.h" + +#include "mp4tag.h" +#include +#include +#include + +#include + +#define MP4V2_HAS_WRITE_BUG 1 + +namespace TagLib { +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +MP4::File::File(const char *file, + bool readProperties, + Properties::ReadStyle propertiesStyle, + MP4FileHandle handle) : TagLib::File(file), + mp4tag(NULL), properties(NULL) +{ + + // debug ("MP4::File: create new file object."); + //debug ( file ); + /** + * Create the MP4 file. + */ + + if(handle == MP4_INVALID_FILE_HANDLE) + { + mp4file = MP4Read(file); + } + else + { + mp4file = handle; + } + + if( isOpen() ) + { + read(readProperties, propertiesStyle ); + } +} + +MP4::File::~File() +{ + MP4Close(mp4file); + delete mp4tag; + delete properties; +} + +TagLib::Tag *MP4::File::tag() const +{ + return mp4tag; +} + +TagLib::MP4::Tag *MP4::File::getMP4Tag() const +{ + return mp4tag; +} + +MP4::Properties *MP4::File::audioProperties() const +{ + return properties; +} + +bool MP4::File::save() +{ + MP4Close(mp4file); + + MP4FileHandle handle = MP4Modify(name()); + if(handle == MP4_INVALID_FILE_HANDLE) + { + mp4file = MP4Read(name()); + return false; + } + +#ifdef MP4V2_HAS_WRITE_BUG + /* according to gtkpod we have to delete all meta data before modifying it, + save the stuff we would not touch */ + + // need to fetch/rewrite this only if we aren't going to anyway + uint8_t compilation = 0; + bool has_compilation = mp4tag->compilation() == MP4::Tag::Undefined ? MP4GetMetadataCompilation(handle, &compilation) : false; + + char *tool = NULL; + MP4GetMetadataTool(handle, &tool); + + MP4MetadataDelete(handle); +#endif + + + +#define setmeta(val, tag) \ + if(mp4tag->val().isNull()) { \ + /*MP4DeleteMetadata##tag(handle);*/ \ + MP4SetMetadata##tag(handle, ""); \ + } else { \ + MP4SetMetadata##tag(handle, mp4tag->val().toCString(true)); \ + } + + setmeta(title, Name); + setmeta(artist, Artist); + setmeta(album, Album); + setmeta(comment, Comment); + setmeta(genre, Genre); + + char buf[100] = ""; + if(mp4tag->year()) + snprintf(buf, sizeof(buf), "%u", mp4tag->year()); + MP4SetMetadataYear(handle, buf); + u_int16_t t1, t2; + MP4GetMetadataTrack(handle, &t1, &t2); + MP4SetMetadataTrack(handle, mp4tag->track(), t2); + if(mp4tag->bpm() != 0) + MP4SetMetadataTempo(handle, mp4tag->bpm()); + if(mp4tag->compilation() != MP4::Tag::Undefined) { + MP4SetMetadataCompilation(handle, mp4tag->compilation()); + } + + MP4SetMetadataCoverArt(handle, mp4tag->cover().size() ? const_cast( reinterpret_cast( mp4tag->cover().data() ) ) : 0, mp4tag->cover().size()); + +#ifdef MP4V2_HAS_WRITE_BUG + // set the saved data again + + if(has_compilation) + MP4SetMetadataCompilation(handle, compilation); + if(tool) + { + MP4SetMetadataTool(handle, tool); + free(tool); + } +#endif + + MP4Close(handle); + + mp4file = MP4Read(name()); + if(mp4file == MP4_INVALID_FILE_HANDLE) + { + fprintf(stderr, "reopen failed\n"); + return false; + } + + return true; +} + +bool MP4::File::isOpen() +{ + return mp4file != MP4_INVALID_FILE_HANDLE; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void MP4::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) +{ + properties = new MP4::Properties(propertiesStyle); + mp4tag = new MP4::Tag(); + + if (mp4file != MP4_INVALID_FILE_HANDLE) { + + if(readProperties) + { + // Parse bitrate etc. + properties->readMP4Properties( mp4file ); + } + + mp4tag->readTags( mp4file ); + } +} + +} diff -Naur amarok-1.4.10/amarok/src/metadata/mp4/mp4properties.cpp amarok-1.4.10.new/amarok/src/metadata/mp4/mp4properties.cpp --- amarok-1.4.10/amarok/src/metadata/mp4/mp4properties.cpp 2008-08-13 23:21:51.000000000 +0200 +++ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4properties.cpp 2010-02-27 14:32:02.308624679 +0100 @@ -21,8 +21,11 @@ #include "mp4properties.h" +#include +#include +#include + -#include #include #ifdef HAVE_SYSTEMS_H diff -Naur amarok-1.4.10/amarok/src/metadata/mp4/mp4properties.cpp~ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4properties.cpp~ --- amarok-1.4.10/amarok/src/metadata/mp4/mp4properties.cpp~ 1970-01-01 01:00:00.000000000 +0100 +++ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4properties.cpp~ 2010-02-27 14:31:31.780800707 +0100 @@ -0,0 +1,123 @@ +/*************************************************************************** +copyright : (C) 2005 by Andy Leadbetter +email : andrew.leadbetter@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., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301 USA * + ***************************************************************************/ + +#include "mp4properties.h" + +#include +#include +#include + + + +#include +#ifdef HAVE_SYSTEMS_H +#include +#endif + +#include + +#ifndef UINT64_TO_DOUBLE +#define UINT64_TO_DOUBLE(a) ((double)((int64_t)(a))) +#endif + +using namespace TagLib; + + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +MP4::Properties::Properties(Properties::ReadStyle style) : AudioProperties(style) +{ + m_length = 0; + m_bitrate = 0; + m_sampleRate = 0; + m_channels = 0; +} + +MP4::Properties::~Properties() +{ +} + +int MP4::Properties::length() const +{ + return m_length; +} + +int MP4::Properties::bitrate() const +{ + return m_bitrate; +} + +int MP4::Properties::sampleRate() const +{ + return m_sampleRate; +} + +int MP4::Properties::channels() const +{ + return m_channels; +} + +void MP4::Properties::readMP4Properties( MP4FileHandle mp4File ) +{ + u_int32_t numTracks = MP4GetNumberOfTracks(mp4File); + + for (u_int32_t i = 0; i < numTracks; i++) + { + MP4TrackId trackId = MP4FindTrackId(mp4File, i); + + const char* trackType = + MP4GetTrackType(mp4File, trackId); + + if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)) + { + // OK we found an audio track so + // decode it. + readAudioTrackProperties(mp4File, trackId ); + } + } +} + +void MP4::Properties::readAudioTrackProperties(MP4FileHandle mp4File, MP4TrackId trackId ) +{ + + u_int32_t timeScale = + MP4GetTrackTimeScale(mp4File, trackId); + + MP4Duration trackDuration = + MP4GetTrackDuration(mp4File, trackId); + + double msDuration = + UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, + trackDuration, MP4_MSECS_TIME_SCALE)); + + u_int32_t avgBitRate = + MP4GetTrackBitRate(mp4File, trackId); + + m_bitrate = (avgBitRate + 500) / 1000; + m_sampleRate = timeScale; + m_length = (int)(msDuration / 1000.0); + m_channels = 2; + + + +} diff -Naur amarok-1.4.10/amarok/src/metadata/mp4/mp4tag.cpp amarok-1.4.10.new/amarok/src/metadata/mp4/mp4tag.cpp --- amarok-1.4.10/amarok/src/metadata/mp4/mp4tag.cpp 2008-08-13 23:21:51.000000000 +0200 +++ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4tag.cpp 2010-02-27 14:32:04.019143693 +0100 @@ -24,6 +24,7 @@ #include #include +#include using namespace TagLib; diff -Naur amarok-1.4.10/amarok/src/metadata/mp4/mp4tag.cpp~ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4tag.cpp~ --- amarok-1.4.10/amarok/src/metadata/mp4/mp4tag.cpp~ 1970-01-01 01:00:00.000000000 +0100 +++ amarok-1.4.10.new/amarok/src/metadata/mp4/mp4tag.cpp~ 2010-02-27 14:31:34.717976251 +0100 @@ -0,0 +1,128 @@ + +/*************************************************************************** +copyright : (C) 2005 by Andy Leadbetter +email : andrew.leadbetter@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., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301 USA * + ***************************************************************************/ + +#include "mp4tag.h" + +#include +#include +#include + +using namespace TagLib; + +MP4::Tag::Tag() : TagLib::Tag::Tag() { + m_title = String::null; + m_artist = String::null; + m_album = String::null; + m_comment = String::null; + m_genre = String::null; + m_composer = String::null; + m_year = 0; + m_track = 0; + m_disk = 0; + m_bpm = 0; + m_compilation = Undefined; +} + +MP4::Tag::~Tag() { +} + +bool MP4::Tag::isEmpty() const { + return m_title == String::null && + m_artist == String::null && + m_album == String::null && + m_comment == String::null && + m_genre == String::null && + m_composer == String::null && + m_year == 0 && + m_track == 0 && + m_disk == 0 && + m_bpm == 0 && + m_compilation == Undefined && + m_image.size() == 0; +} + +void MP4::Tag::duplicate(const Tag *source, Tag *target, bool overwrite) { + // Duplicate standard information + Tag::duplicate(source, target, overwrite); + + if (overwrite || target->compilation() == Undefined && source->compilation() != Undefined) + target->setCompilation(source->compilation()); + + if (overwrite || target->cover().size() == 0) + target->setCover(source->cover()); +} + +void MP4::Tag::readTags( MP4FileHandle mp4file ) +{ + // Now parse tag. + char *value; + uint8_t boolvalue; + uint16_t numvalue, numvalue2; + uint8_t *image; + uint32_t imageSize; + if (MP4GetMetadataName(mp4file, &value) && value != NULL) { + m_title = String(value, String::UTF8); + free(value); + } + if (MP4GetMetadataArtist(mp4file, &value) && value != NULL) { + m_artist = String(value, String::UTF8); + free(value); + } + + if (MP4GetMetadataComment(mp4file, &value) && value != NULL) { + m_comment = String(value, String::UTF8); + free(value); + } + + if (MP4GetMetadataYear(mp4file, &value) && value != NULL) { + m_year = strtol(value, NULL,0); + free(value); + } + if (MP4GetMetadataAlbum(mp4file, &value) && value != NULL) { + m_album = String(value, String::UTF8); + free(value); + } + if (MP4GetMetadataTrack(mp4file, &numvalue, &numvalue2)) { + m_track = numvalue; + } + if (MP4GetMetadataDisk(mp4file, &numvalue, &numvalue2)) { + m_disk = numvalue; + } + if (MP4GetMetadataTempo(mp4file, &numvalue)) { + m_bpm = numvalue; + } + if (MP4GetMetadataCompilation(mp4file, &boolvalue)) { + m_compilation = boolvalue; + } + if (MP4GetMetadataGenre(mp4file, &value) && value != NULL) { + m_genre = String(value, String::UTF8); + free(value); + } + if (MP4GetMetadataWriter(mp4file, &value) && value != NULL) { + m_composer = String(value, String::UTF8); + free(value); + } + if (MP4GetMetadataCoverArt(mp4file, &image, &imageSize) && image && imageSize) { + m_image.setData(reinterpret_cast( image ), imageSize); + free(image); + } +} diff -Naur amarok-1.4.10/amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp amarok-1.4.10.new/amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp --- amarok-1.4.10/amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp 2008-08-13 23:21:51.000000000 +0200 +++ amarok-1.4.10.new/amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp 2010-02-27 14:32:09.183657400 +0100 @@ -24,6 +24,7 @@ #include "taglib_mp4filetyperesolver.h" #include "mp4file.h" +#include TagLib::File *MP4FileTypeResolver::createFile(const char *fileName, bool readProperties, diff -Naur amarok-1.4.10/amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp~ amarok-1.4.10.new/amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp~ --- amarok-1.4.10/amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp~ 1970-01-01 01:00:00.000000000 +0100 +++ amarok-1.4.10.new/amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp~ 2010-02-27 14:31:45.415795962 +0100 @@ -0,0 +1,49 @@ +/*************************************************************************** + copyright : (C) 2005 by Martin Aumueller + email : aumuell@reserv.at + ***************************************************************************/ + +/*************************************************************************** + * 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., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301 USA * + ***************************************************************************/ + +// (c) 2005 Martin Aumueller +// See COPYING file for licensing information + +#include "taglib_mp4filetyperesolver.h" +#include "mp4file.h" +#include + +TagLib::File *MP4FileTypeResolver::createFile(const char *fileName, + bool readProperties, + TagLib::AudioProperties::ReadStyle propertiesStyle) const +{ + const char *ext = strrchr(fileName, '.'); + if(ext && (!strcasecmp(ext, ".m4a") + || !strcasecmp(ext, ".m4b") || !strcasecmp(ext, ".m4p") + || !strcasecmp(ext, ".mp4") + || !strcasecmp(ext, ".m4v") || !strcasecmp(ext, ".mp4v"))) + { + MP4FileHandle h = MP4Read(fileName, 0); + if(MP4_INVALID_FILE_HANDLE == h) + { + return 0; + } + + return new TagLib::MP4::File(fileName, readProperties, propertiesStyle, h); + } + + return 0; +}