X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmeta_engine%2Ftaglib.cpp;h=e1e03fbef29a6112bb7ac9b4c14e9491011c4a48;hb=b0eb44053c3fffdf04b00f5e0cd1986c7fdf848f;hp=d2b3c988970c1de3dee193d66cb16825d49acc33;hpb=8505bf177a1679b9bb472ce3e0f99a93eab11453;p=vlc diff --git a/modules/meta_engine/taglib.cpp b/modules/meta_engine/taglib.cpp index d2b3c98897..e1e03fbef2 100644 --- a/modules/meta_engine/taglib.cpp +++ b/modules/meta_engine/taglib.cpp @@ -1,11 +1,12 @@ /***************************************************************************** * taglib.cpp: Taglib tag parser/writer ***************************************************************************** - * Copyright (C) 2003-2008 the VideoLAN team + * Copyright (C) 2003-2009 the VideoLAN team * $Id$ * * Authors: Clément Stenac * Rafaël Carré + * Rémi Duraffort * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,11 +29,13 @@ #include #include -#include #include #include #include #include +#include +#include +#include /* for attachment_new */ #ifdef WIN32 # include @@ -40,45 +43,48 @@ # include #endif -#include +// Taglib headers +#include #include +#include + +#include #include #include -#include #include #include #include #include #include + +#ifdef TAGLIB_WITH_ASF +# include +# include +#endif + +#ifdef TAGLIB_WITH_MP4 +# include +#endif + #include -#include #include +#include #include -#include -#include -#include #include -//#include /* ogg flac files aren't auto-casted by TagLib */ -#include -#include -#include -#include #include -//#include /* parse the tags without TagLib helpers? */ +#include -static int ReadMeta ( vlc_object_t * ); -static int DownloadArt ( vlc_object_t * ); -static int WriteMeta ( vlc_object_t * ); + +// Local functions +static int ReadMeta ( vlc_object_t * ); +static int WriteMeta ( vlc_object_t * ); vlc_module_begin () set_capability( "meta reader", 1000 ) set_callbacks( ReadMeta, NULL ) - add_submodule () - set_capability( "art downloader", 50 ) - set_callbacks( DownloadArt, NULL ) add_submodule () set_capability( "meta writer", 50 ) set_callbacks( WriteMeta, NULL ) @@ -87,181 +93,25 @@ vlc_module_end () using namespace TagLib; -/* Try detecting embedded art */ -static void DetectImage( FileRef f, demux_t *p_demux ) -{ - demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private; - vlc_meta_t *p_meta = p_demux_meta->p_meta; - int i_score = -1; - - /* Preferred type of image - * The 21 types are defined in id3v2 standard: - * http://www.id3.org/id3v2.4.0-frames */ - static const int pi_cover_score[] = { - 0, /* Other */ - 5, /* 32x32 PNG image that should be used as the file icon */ - 4, /* File icon of a different size or format. */ - 20, /* Front cover image of the album. */ - 19, /* Back cover image of the album. */ - 13, /* Inside leaflet page of the album. */ - 18, /* Image from the album itself. */ - 17, /* Picture of the lead artist or soloist. */ - 16, /* Picture of the artist or performer. */ - 14, /* Picture of the conductor. */ - 15, /* Picture of the band or orchestra. */ - 9, /* Picture of the composer. */ - 8, /* Picture of the lyricist or text writer. */ - 7, /* Picture of the recording location or studio. */ - 10, /* Picture of the artists during recording. */ - 11, /* Picture of the artists during performance. */ - 6, /* Picture from a movie or video related to the track. */ - 1, /* Picture of a large, coloured fish. */ - 12, /* Illustration related to the track. */ - 3, /* Logo of the band or performer. */ - 2 /* Logo of the publisher (record company). */ - }; - - if( MPEG::File *mpeg = dynamic_cast(f.file() ) ) - { - ID3v2::Tag *p_tag = mpeg->ID3v2Tag(); - if( !p_tag ) - return; - ID3v2::FrameList list = p_tag->frameListMap()[ "APIC" ]; - if( list.isEmpty() ) - return; - ID3v2::AttachedPictureFrame *p_apic; - - TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments ); - for( ID3v2::FrameList::Iterator iter = list.begin(); - iter != list.end(); iter++ ) - { - p_apic = dynamic_cast(*iter); - input_attachment_t *p_attachment; - - const char *psz_name, *psz_mime, *psz_description; - ByteVector p_data_taglib; const char *p_data; int i_data; - - psz_mime = p_apic->mimeType().toCString(true); - psz_description = psz_name = p_apic->description().toCString(true); - - /* some old iTunes version not only sets incorrectly the mime type - * or the description of the image, - * but also embeds incorrectly the image. - * Recent versions seem to behave correctly */ - if( !strncmp( psz_mime, "PNG", 3 ) || - !strncmp( psz_name, "\xC2\x89PNG", 5 ) ) - { - msg_Warn( p_demux, - "%s: Invalid picture embedded by broken iTunes version, " - "you really shouldn't use this crappy software.", - (const char *)f.file()->name() ); - break; - } - - p_data_taglib = p_apic->picture(); - p_data = p_data_taglib.data(); - i_data = p_data_taglib.size(); - - msg_Dbg( p_demux, "Found embedded art: %s (%s) is %i bytes", - psz_name, psz_mime, i_data ); - - p_attachment = vlc_input_attachment_New( psz_name, psz_mime, - psz_description, p_data, i_data ); - TAB_APPEND_CAST( (input_attachment_t**), - p_demux_meta->i_attachments, p_demux_meta->attachments, - p_attachment ); - - if( pi_cover_score[p_apic->type()] > i_score ) - { - i_score = pi_cover_score[p_apic->type()]; - char *psz_url; - if( asprintf( &psz_url, "attachment://%s", - p_attachment->psz_name ) == -1 ) - return; - vlc_meta_SetArtURL( p_meta, psz_url ); - free( psz_url ); - } - } - } - else - if( Ogg::Vorbis::File *oggv = dynamic_cast(f.file() ) ) - { - Ogg::XiphComment *p_tag = oggv->tag(); - if( !p_tag ) - return; - - StringList mime_list = p_tag->fieldListMap()[ "COVERARTMIME" ]; - StringList art_list = p_tag->fieldListMap()[ "COVERART" ]; - - /* we support only one cover in ogg/vorbis */ - if( mime_list.size() != 1 || art_list.size() != 1 ) - return; - - input_attachment_t *p_attachment; - - const char *psz_name, *psz_mime, *psz_description; - uint8_t *p_data; - int i_data; - - psz_name = "cover"; - psz_mime = mime_list[0].toCString(true); - psz_description = "cover"; - - i_data = vlc_b64_decode_binary( &p_data, art_list[0].toCString(true) ); - - msg_Dbg( p_demux, "Found embedded art: %s (%s) is %i bytes", - psz_name, psz_mime, i_data ); - - TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments ); - p_attachment = vlc_input_attachment_New( psz_name, psz_mime, - psz_description, p_data, i_data ); - free( p_data ); - - TAB_APPEND_CAST( (input_attachment_t**), - p_demux_meta->i_attachments, p_demux_meta->attachments, - p_attachment ); - - vlc_meta_SetArtURL( p_meta, "attachment://cover" ); - } - -#if 0 - //flac embedded images are extracted in the flac demuxer - else if( FLAC::File *flac = - dynamic_cast(f.file() ) ) - { - p_tag = flac->ID3v2Tag(); - if( p_tag ) - return; - ID3v2::FrameList l = p_tag->frameListMap()[ "APIC" ]; - if( l.isEmpty() ) - return; - vlc_meta_SetArtURL( p_meta, "APIC" ); - } -#endif -#if 0 -/* TagLib doesn't support MP4 file yet */ - else if( MP4::File *mp4 = - dynamic_cast( f.file() ) ) - { - MP4::Tag *mp4tag = - dynamic_cast( mp4->tag() ); - if( mp4tag && mp4tag->cover().size() ) - vlc_meta_SetArtURL( p_meta, "MP4C" ); - } -#endif -} - - - /** - * Read meta informations from APE tags + * Read meta information from APE tags * @param tag: the APE tag + * @param p_demux; the demux object + * @param p_demux_meta: the demuxer meta * @param p_meta: the meta - * @return VLC_SUCCESS if everything goes ok */ -static int ReadMetaFromAPE( APE::Tag* tag, vlc_meta_t* p_meta ) +static void ReadMetaFromAPE( APE::Tag* tag, demux_t* p_demux, demux_meta_t* p_demux_meta, vlc_meta_t* p_meta ) { - return VLC_SUCCESS; + APE::Item item; +#define SET( keyName, metaName ) \ + item = tag->itemListMap()[keyName]; \ + vlc_meta_Set##metaName( p_meta, item.toString().toCString( true ) );\ + + SET( "COPYRIGHT", Copyright ); + SET( "LANGUAGE", Language ); + SET( "PUBLISHER", Publisher ); + +#undef SET } @@ -269,10 +119,11 @@ static int ReadMetaFromAPE( APE::Tag* tag, vlc_meta_t* p_meta ) /** * Read meta information from id3v2 tags * @param tag: the id3v2 tag + * @param p_demux; the demux object + * @param p_demux_meta: the demuxer meta * @param p_meta: the meta - * @return VLC_SUCCESS if everything goes ok */ -static int ReadMetaFromId2v2( ID3v2::Tag* tag, vlc_meta_t* p_meta ) +static void ReadMetaFromId3v2( ID3v2::Tag* tag, demux_t* p_demux, demux_meta_t* p_demux_meta, vlc_meta_t* p_meta ) { // Get the unique file identifier ID3v2::FrameList list = tag->frameListMap()["UFID"]; @@ -281,6 +132,8 @@ static int ReadMetaFromId2v2( ID3v2::Tag* tag, vlc_meta_t* p_meta ) { ID3v2::UniqueFileIdentifierFrame* p_ufid = dynamic_cast(*iter); + if( !p_ufid ) + continue; const char *owner = p_ufid->owner().toCString(); if (!strcmp( owner, "http://musicbrainz.org" )) { @@ -288,12 +141,9 @@ static int ReadMetaFromId2v2( ID3v2::Tag* tag, vlc_meta_t* p_meta ) * but in our case it will be a '\0' * terminated string */ char psz_ufid[64]; - int j = 0; - int max_size = p_ufid->identifier().size() < 63 ? - p_ufid->identifier().size() : 63; - while( j < max_size ) - psz_ufid[j] = p_ufid->identifier()[j++]; - psz_ufid[j] = '\0'; + int max_size = __MIN( p_ufid->identifier().size(), 63); + strncpy( psz_ufid, p_ufid->identifier().data(), max_size ); + psz_ufid[max_size] = '\0'; vlc_meta_SetTrackID( p_meta, psz_ufid ); } } @@ -304,11 +154,13 @@ static int ReadMetaFromId2v2( ID3v2::Tag* tag, vlc_meta_t* p_meta ) { ID3v2::UserTextIdentificationFrame* p_txxx = dynamic_cast(*iter); + if( !p_txxx ) + continue; vlc_meta_AddExtra( p_meta, p_txxx->description().toCString( true ), p_txxx->fieldList().toString().toCString( true ) ); } - // Get some more informations + // Get some more information #define SET( tagName, metaName ) \ list = tag->frameListMap()[tagName]; \ if( !list.isEmpty() ) \ @@ -321,23 +173,183 @@ static int ReadMetaFromId2v2( ID3v2::Tag* tag, vlc_meta_t* p_meta ) SET( "TPUB", Publisher ); #undef SET - return VLC_SUCCESS; + + /* Preferred type of image + * The 21 types are defined in id3v2 standard: + * http://www.id3.org/id3v2.4.0-frames */ + static const int pi_cover_score[] = { + 0, /* Other */ + 5, /* 32x32 PNG image that should be used as the file icon */ + 4, /* File icon of a different size or format. */ + 20, /* Front cover image of the album. */ + 19, /* Back cover image of the album. */ + 13, /* Inside leaflet page of the album. */ + 18, /* Image from the album itself. */ + 17, /* Picture of the lead artist or soloist. */ + 16, /* Picture of the artist or performer. */ + 14, /* Picture of the conductor. */ + 15, /* Picture of the band or orchestra. */ + 9, /* Picture of the composer. */ + 8, /* Picture of the lyricist or text writer. */ + 7, /* Picture of the recording location or studio. */ + 10, /* Picture of the artists during recording. */ + 11, /* Picture of the artists during performance. */ + 6, /* Picture from a movie or video related to the track. */ + 1, /* Picture of a large, coloured fish. */ + 12, /* Illustration related to the track. */ + 3, /* Logo of the band or performer. */ + 2 /* Logo of the publisher (record company). */ + }; + int i_score = -1; + + // Try now to get embedded art + list = tag->frameListMap()[ "APIC" ]; + if( list.isEmpty() ) + return; + + TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments ); + for( iter = list.begin(); iter != list.end(); iter++ ) + { + ID3v2::AttachedPictureFrame* p_apic = + dynamic_cast(*iter); + if( !p_apic ) + continue; + input_attachment_t *p_attachment; + + const char *psz_mime; + char *psz_name, *psz_description; + + // Get the mime and description of the image. + // If the description is empty, take the type as a description + psz_mime = p_apic->mimeType().toCString( true ); + if( p_apic->description().size() > 0 ) + psz_description = strdup( p_apic->description().toCString( true ) ); + else + { + if( asprintf( &psz_description, "%i", p_apic->type() ) == -1 ) + psz_description = NULL; + } + + if( !psz_description ) + continue; + psz_name = psz_description; + + /* some old iTunes version not only sets incorrectly the mime type + * or the description of the image, + * but also embeds incorrectly the image. + * Recent versions seem to behave correctly */ + if( !strncmp( psz_mime, "PNG", 3 ) || + !strncmp( psz_name, "\xC2\x89PNG", 5 ) ) + { + msg_Warn( p_demux_meta, "Invalid picture embedded by broken iTunes version" ); + free( psz_description ); + continue; + } + + const ByteVector picture = p_apic->picture(); + const char *p_data = picture.data(); + const unsigned i_data = picture.size(); + + msg_Dbg( p_demux_meta, "Found embedded art: %s (%s) is %u bytes", + psz_name, psz_mime, i_data ); + + p_attachment = vlc_input_attachment_New( psz_name, psz_mime, + psz_description, p_data, i_data ); + if( p_attachment ) + TAB_APPEND_CAST( (input_attachment_t**), + p_demux_meta->i_attachments, p_demux_meta->attachments, + p_attachment ); + free( psz_description ); + + if( pi_cover_score[p_apic->type()] > i_score ) + { + i_score = pi_cover_score[p_apic->type()]; + char *psz_url; + if( asprintf( &psz_url, "attachment://%s", + p_attachment->psz_name ) == -1 ) + continue; + vlc_meta_SetArtURL( p_meta, psz_url ); + free( psz_url ); + } + } } /** - * Read the meta informations from XiphComments + * Read the meta information from XiphComments * @param tag: the Xiph Comment + * @param p_demux; the demux object + * @param p_demux_meta: the demuxer meta * @param p_meta: the meta - * @return VLC_SUCCESS if everything goes ok */ -static int ReadMetaFromXiph( Ogg::XiphComment* tag, vlc_meta_t* p_meta ) +static void ReadMetaFromXiph( Ogg::XiphComment* tag, demux_t* p_demux, demux_meta_t* p_demux_meta, vlc_meta_t* p_meta ) { - return VLC_SUCCESS; +#define SET( keyName, metaName ) \ + StringList list = tag->fieldListMap()[keyName]; \ + if( !list.isEmpty() ) \ + vlc_meta_Set##metaName( p_meta, (*list.begin()).toCString( true ) ); + + SET( "COPYRIGHT", Copyright ); +#undef SET + + // Try now to get embedded art + StringList mime_list = tag->fieldListMap()[ "COVERARTMIME" ]; + StringList art_list = tag->fieldListMap()[ "COVERART" ]; + + // We get only the first covert art + if( mime_list.size() > 1 || art_list.size() > 1 ) + msg_Warn( p_demux_meta, "Found %i embedded arts, so using only the first one", + art_list.size() ); + else if( mime_list.size() == 0 || art_list.size() == 0 ) + return; + + input_attachment_t *p_attachment; + + const char* psz_name = "cover"; + const char* psz_mime = mime_list[0].toCString(true); + const char* psz_description = "cover"; + + uint8_t *p_data; + int i_data = vlc_b64_decode_binary( &p_data, art_list[0].toCString(true) ); + + msg_Dbg( p_demux_meta, "Found embedded art: %s (%s) is %i bytes", + psz_name, psz_mime, i_data ); + + TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments ); + p_attachment = vlc_input_attachment_New( psz_name, psz_mime, + psz_description, p_data, i_data ); + free( p_data ); + + TAB_APPEND_CAST( (input_attachment_t**), + p_demux_meta->i_attachments, p_demux_meta->attachments, + p_attachment ); + + vlc_meta_SetArtURL( p_meta, "attachment://cover" ); } +#if defined(TAGLIB_WITH_MP4) && defined(HAVE_TAGLIB_MP4COVERART_H) +static void ReadMetaFromMP4( MP4::Tag* tag, demux_t *p_demux, demux_meta_t *p_demux_meta, vlc_meta_t* p_meta ) +{ + if( tag->itemListMap().contains("covr") ) + { + MP4::CoverArtList list = tag->itemListMap()["covr"].toCoverArtList(); + const char *psz_format = list[0].format() == MP4::CoverArt::PNG ? "image/png" : "image/jpeg"; + + msg_Dbg( p_demux_meta, "Found embedded art (%s) is %i bytes", + psz_format, list[0].data().size() ); + TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments ); + input_attachment_t *p_attachment = + vlc_input_attachment_New( "cover", psz_format, "cover", + list[0].data().data(), list[0].data().size() ); + TAB_APPEND_CAST( (input_attachment_t**), + p_demux_meta->i_attachments, p_demux_meta->attachments, + p_attachment ); + vlc_meta_SetArtURL( p_meta, "attachment://cover" ); + } +} +#endif /** * Get the tags from the file using TagLib @@ -346,17 +358,39 @@ static int ReadMetaFromXiph( Ogg::XiphComment* tag, vlc_meta_t* p_meta ) */ static int ReadMeta( vlc_object_t* p_this) { - demux_t* p_demux = (demux_t*)p_this; - demux_meta_t* p_demux_meta = (demux_meta_t*)p_demux->p_private; + demux_meta_t* p_demux_meta = (demux_meta_t *)p_this; + demux_t* p_demux = p_demux_meta->p_demux; vlc_meta_t* p_meta; - TagLib::FileRef f; + FileRef f; p_demux_meta->p_meta = NULL; - const char* local_name = ToLocale( p_demux->psz_path ); + if( strcmp( p_demux->psz_access, "file" ) ) + return VLC_EGENERIC; + + char *psz_path = strdup( p_demux->psz_file ); + if( !psz_path ) + return VLC_ENOMEM; + +#if defined(WIN32) || defined (UNDER_CE) + wchar_t wpath[MAX_PATH + 1]; + if( !MultiByteToWideChar( CP_UTF8, 0, psz_path, -1, wpath, MAX_PATH) ) + { + free( psz_path ); + return VLC_EGENERIC; + } + wpath[MAX_PATH] = L'\0'; + f = FileRef( wpath ); +#else + const char* local_name = ToLocale( psz_path ); if( !local_name ) + { + free( psz_path ); return VLC_EGENERIC; + } f = FileRef( local_name ); LocaleFree( local_name ); +#endif + free( psz_path ); if( f.isNull() ) return VLC_EGENERIC; @@ -371,10 +405,10 @@ static int ReadMeta( vlc_object_t* p_this) // Read the tags from the file Tag* p_tag = f.tag(); -#define SET( meta, tag ) \ +#define SET( tag, meta ) \ if( !p_tag->tag().isNull() && !p_tag->tag().isEmpty() ) \ vlc_meta_Set##meta( p_meta, p_tag->tag().toCString(true) ) -#define SETINT( meta, tag ) \ +#define SETINT( tag, meta ) \ if( p_tag->tag() ) \ { \ char psz_tmp[10]; \ @@ -382,13 +416,13 @@ static int ReadMeta( vlc_object_t* p_this) vlc_meta_Set##meta( p_meta, psz_tmp ); \ } - SET( Title, title ); - SET( Artist, artist ); - SET( Album, album ); - SET( Description, comment ); - SET( Genre, genre ); - SETINT( Date, year ); - SETINT( Tracknum, track ); + SET( title, Title ); + SET( artist, Artist ); + SET( album, Album ); + SET( comment, Description ); + SET( genre, Genre ); + SETINT( year, Date ); + SETINT( track, TrackNum ); #undef SETINT #undef SET @@ -398,59 +432,86 @@ static int ReadMeta( vlc_object_t* p_this) if( FLAC::File* flac = dynamic_cast(f.file()) ) { if( flac->ID3v2Tag() ) - ReadMetaFromId2v2( flac->ID3v2Tag(), p_meta ); + ReadMetaFromId3v2( flac->ID3v2Tag(), p_demux, p_demux_meta, p_meta ); else if( flac->xiphComment() ) - ReadMetaFromXiph( flac->xiphComment(), p_meta ); + ReadMetaFromXiph( flac->xiphComment(), p_demux, p_demux_meta, p_meta ); } +#if defined(TAGLIB_WITH_MP4) && defined(HAVE_TAGLIB_MP4COVERART_H) + else if( MP4::File *mp4 = dynamic_cast(f.file()) ) + { + if( mp4->tag() ) + ReadMetaFromMP4( mp4->tag(), p_demux, p_demux_meta, p_meta ); + } +#endif else if( MPC::File* mpc = dynamic_cast(f.file()) ) { if( mpc->APETag() ) - ReadMetaFromAPE( mpc->APETag(), p_meta ); + ReadMetaFromAPE( mpc->APETag(), p_demux, p_demux_meta, p_meta ); } else if( MPEG::File* mpeg = dynamic_cast(f.file()) ) { if( mpeg->ID3v2Tag() ) - ReadMetaFromId2v2( mpeg->ID3v2Tag(), p_meta ); + ReadMetaFromId3v2( mpeg->ID3v2Tag(), p_demux, p_demux_meta, p_meta ); else if( mpeg->APETag() ) - ReadMetaFromAPE( mpeg->APETag(), p_meta ); + ReadMetaFromAPE( mpeg->APETag(), p_demux, p_demux_meta, p_meta ); } else if( Ogg::File* ogg = dynamic_cast(f.file()) ) { if( Ogg::FLAC::File* ogg_flac = dynamic_cast(f.file())) - ReadMetaFromXiph( ogg_flac->tag(), p_meta ); + ReadMetaFromXiph( ogg_flac->tag(), p_demux, p_demux_meta, p_meta ); else if( Ogg::Speex::File* ogg_speex = dynamic_cast(f.file()) ) - ReadMetaFromXiph( ogg_speex->tag(), p_meta ); + ReadMetaFromXiph( ogg_speex->tag(), p_demux, p_demux_meta, p_meta ); else if( Ogg::Vorbis::File* ogg_vorbis = dynamic_cast(f.file()) ) - ReadMetaFromXiph( ogg_vorbis->tag(), p_meta ); + ReadMetaFromXiph( ogg_vorbis->tag(), p_demux, p_demux_meta, p_meta ); } +#ifdef TAGLIB_WITH_ASF + else if( RIFF::File* riff = dynamic_cast(f.file()) ) + { + if( RIFF::AIFF::File* riff_aiff = dynamic_cast(f.file()) ) + ReadMetaFromId3v2( riff_aiff->tag(), p_demux, p_demux_meta, p_meta ); + else if( RIFF::WAV::File* riff_wav = dynamic_cast(f.file()) ) + ReadMetaFromId3v2( riff_wav->tag(), p_demux, p_demux_meta, p_meta ); + } +#endif else if( TrueAudio::File* trueaudio = dynamic_cast(f.file()) ) { if( trueaudio->ID3v2Tag() ) - ReadMetaFromId2v2( trueaudio->ID3v2Tag(), p_meta ); + ReadMetaFromId3v2( trueaudio->ID3v2Tag(), p_demux, p_demux_meta, p_meta ); } else if( WavPack::File* wavpack = dynamic_cast(f.file()) ) { if( wavpack->APETag() ) - ReadMetaFromAPE( wavpack->APETag(), p_meta ); + ReadMetaFromAPE( wavpack->APETag(), p_demux, p_demux_meta, p_meta ); } - // Try now to find a image - DetectImage( f, p_demux ); - return VLC_SUCCESS; } /** - * Write meta informations to APE tags + * Write meta information to APE tags * @param tag: the APE tag - * @param p_input: the input item - * @return VLC_SUCCESS if everything goes ok + * @param p_item: the input item */ -static int WriteMetaToAPE( APE::Tag* tag, input_item_t* p_input ) +static void WriteMetaToAPE( APE::Tag* tag, input_item_t* p_item ) { - return VLC_SUCCESS; + char* psz_meta; +#define WRITE( metaName, keyName ) \ + psz_meta = input_item_Get##metaName( p_item ); \ + if( psz_meta ) \ + { \ + String key( keyName, String::UTF8 ); \ + String value( psz_meta, String::UTF8 ); \ + tag->addValue( key, value, true ); \ + } \ + free( psz_meta ); + + WRITE( Copyright, "COPYRIGHT" ); + WRITE( Language, "LANGUAGE" ); + WRITE( Publisher, "PUBLISHER" ); + +#undef WRITE } @@ -459,9 +520,8 @@ static int WriteMetaToAPE( APE::Tag* tag, input_item_t* p_input ) * Write meta information to id3v2 tags * @param tag: the id3v2 tag * @param p_input: the input item - * @return VLC_SUCCESS if everything goes ok */ -static int WriteMetaToId2v2( ID3v2::Tag* tag, input_item_t* p_item ) +static void WriteMetaToId3v2( ID3v2::Tag* tag, input_item_t* p_item ) { char* psz_meta; #define WRITE( metaName, tagName ) \ @@ -483,18 +543,16 @@ static int WriteMetaToId2v2( ID3v2::Tag* tag, input_item_t* p_item ) WRITE( Publisher, "TPUB" ); #undef WRITE - return VLC_SUCCESS; } /** - * Write the meta informations to XiphComments + * Write the meta information to XiphComments * @param tag: the Xiph Comment * @param p_input: the input item - * @return VLC_SUCCESS if everything goes ok */ -static int WriteMetaToXiph( Ogg::XiphComment* tag, input_item_t* p_item ) +static void WriteMetaToXiph( Ogg::XiphComment* tag, input_item_t* p_item ) { char* psz_meta; #define WRITE( metaName, keyName ) \ @@ -510,7 +568,6 @@ static int WriteMetaToXiph( Ogg::XiphComment* tag, input_item_t* p_item ) WRITE( Copyright, "COPYRIGHT" ); #undef WRITE - return VLC_SUCCESS; } @@ -523,9 +580,9 @@ static int WriteMetaToXiph( Ogg::XiphComment* tag, input_item_t* p_item ) static int WriteMeta( vlc_object_t *p_this ) { - playlist_t *p_playlist = (playlist_t *)p_this; - meta_export_t *p_export = (meta_export_t *)p_playlist->p_private; + meta_export_t *p_export = (meta_export_t *)p_this; input_item_t *p_item = p_export->p_item; + FileRef f; if( !p_item ) { @@ -533,11 +590,24 @@ static int WriteMeta( vlc_object_t *p_this ) return VLC_EGENERIC; } - FileRef f( p_export->psz_file ); +#if defined(WIN32) || defined (UNDER_CE) + wchar_t wpath[MAX_PATH + 1]; + if( !MultiByteToWideChar( CP_UTF8, 0, p_export->psz_file, -1, wpath, MAX_PATH) ) + return VLC_EGENERIC; + wpath[MAX_PATH] = L'\0'; + f = FileRef( wpath ); +#else + const char* local_name = ToLocale( p_export->psz_file ); + if( !local_name ) + return VLC_EGENERIC; + f = FileRef( local_name ); + LocaleFree( local_name ); +#endif + if( f.isNull() || !f.tag() || f.file()->readOnly() ) { - msg_Err( p_this, "File %s can't be opened for tag writing\n", - p_export->psz_file ); + msg_Err( p_this, "File %s can't be opened for tag writing", + p_export->psz_file ); return VLC_EGENERIC; } @@ -547,36 +617,22 @@ static int WriteMeta( vlc_object_t *p_this ) char *psz_meta; -#define SET( a, b ) \ - if( b ) \ - { \ - String* psz_tmp = new String( b, String::UTF8 ); \ - p_tag->set##a( *psz_tmp ); \ - delete psz_tmp; \ - } +#define SET( a, b ) \ + psz_meta = input_item_Get ## a( p_item ); \ + if( psz_meta ) \ + { \ + String tmp( psz_meta, String::UTF8 ); \ + p_tag->set##b( tmp ); \ + } \ + free( psz_meta ); // Saving all common fields // If the title is empty, use the name - psz_meta = input_item_GetTitle( p_item ); - if( !psz_meta ) psz_meta = input_item_GetName( p_item ); - SET( Title, psz_meta ); - free( psz_meta ); - - psz_meta = input_item_GetArtist( p_item ); - SET( Artist, psz_meta ); - free( psz_meta ); - - psz_meta = input_item_GetAlbum( p_item ); - SET( Album, psz_meta ); - free( psz_meta ); - - psz_meta = input_item_GetDescription( p_item ); - SET( Comment, psz_meta ); - free( psz_meta ); - - psz_meta = input_item_GetGenre( p_item ); - SET( Genre, psz_meta ); - free( psz_meta ); + SET( TitleFbName, Title ); + SET( Artist, Artist ); + SET( Album, Album ); + SET( Description, Comment ); + SET( Genre, Genre ); #undef SET @@ -593,7 +649,7 @@ static int WriteMeta( vlc_object_t *p_this ) if( FLAC::File* flac = dynamic_cast(f.file()) ) { if( flac->ID3v2Tag() ) - WriteMetaToId2v2( flac->ID3v2Tag(), p_item ); + WriteMetaToId3v2( flac->ID3v2Tag(), p_item ); else if( flac->xiphComment() ) WriteMetaToXiph( flac->xiphComment(), p_item ); } @@ -605,7 +661,7 @@ static int WriteMeta( vlc_object_t *p_this ) else if( MPEG::File* mpeg = dynamic_cast(f.file()) ) { if( mpeg->ID3v2Tag() ) - WriteMetaToId2v2( mpeg->ID3v2Tag(), p_item ); + WriteMetaToId3v2( mpeg->ID3v2Tag(), p_item ); else if( mpeg->APETag() ) WriteMetaToAPE( mpeg->APETag(), p_item ); } @@ -618,10 +674,19 @@ static int WriteMeta( vlc_object_t *p_this ) else if( Ogg::Vorbis::File* ogg_vorbis = dynamic_cast(f.file()) ) WriteMetaToXiph( ogg_vorbis->tag(), p_item ); } +#ifdef TAGLIB_WITH_ASF + else if( RIFF::File* riff = dynamic_cast(f.file()) ) + { + if( RIFF::AIFF::File* riff_aiff = dynamic_cast(f.file()) ) + WriteMetaToId3v2( riff_aiff->tag(), p_item ); + else if( RIFF::WAV::File* riff_wav = dynamic_cast(f.file()) ) + WriteMetaToId3v2( riff_wav->tag(), p_item ); + } +#endif else if( TrueAudio::File* trueaudio = dynamic_cast(f.file()) ) { if( trueaudio->ID3v2Tag() ) - WriteMetaToId2v2( trueaudio->ID3v2Tag(), p_item ); + WriteMetaToId3v2( trueaudio->ID3v2Tag(), p_item ); } else if( WavPack::File* wavpack = dynamic_cast(f.file()) ) { @@ -635,13 +700,3 @@ static int WriteMeta( vlc_object_t *p_this ) return VLC_SUCCESS; } - - -static int DownloadArt( vlc_object_t *p_this ) -{ - /* We need to be passed the file name - * Fetch the thing from the file, save it to the cache folder - */ - return VLC_EGENERIC; -} -