00001
00002 #include <unistd.h>
00003 #include <sys/stat.h>
00004
00005
00006 #include <cmath>
00007
00008
00009 #include <cstdlib>
00010 #include <iostream>
00011 using namespace std;
00012
00013
00014 #include <mythtv/compat.h>
00015 #include <mythtv/util.h>
00016
00017
00018 #include "metaiooggvorbiscomment.h"
00019 #include "metaiovorbiscomment.h"
00020 #include "metadata.h"
00021 #include "vcedit.h"
00022 #include <vorbis/vorbisfile.h>
00023 #include <qfileinfo.h>
00024
00025
00026 MetaIOOggVorbisComment::MetaIOOggVorbisComment(void)
00027 : MetaIO(".ogg")
00028 {
00029 }
00030
00031
00032
00033 MetaIOOggVorbisComment::~MetaIOOggVorbisComment(void)
00034 {
00035 }
00036
00037
00038
00047 vorbis_comment*
00048 MetaIOOggVorbisComment::getRawVorbisComment(Metadata* mdata,
00049 vorbis_comment* pComment)
00050 {
00051
00052 if (!mdata)
00053 return NULL;
00054
00055 vorbis_comment* p_comment = new vorbis_comment;
00056
00057 if (!p_comment)
00058 return NULL;
00059
00060 vorbis_comment_init(p_comment);
00061
00062 if (pComment)
00063 {
00064
00065
00066
00067
00068 QString tmp;
00069 for (int i=0; i<pComment->comments; ++i)
00070 {
00071
00072 tmp = pComment->user_comments[i];
00073 int tag = tmp.find('=');
00074 if (tag)
00075 {
00076 tmp = tmp.left(tag).upper();
00077 if (MYTH_VORBISCOMMENT_ARTIST != tmp
00078 && MYTH_VORBISCOMMENT_COMPILATIONARTIST != tmp
00079 && MYTH_VORBISCOMMENT_TITLE != tmp
00080 && MYTH_VORBISCOMMENT_ALBUM != tmp
00081 && MYTH_VORBISCOMMENT_GENRE != tmp
00082 && MYTH_VORBISCOMMENT_TRACK != tmp
00083 && MYTH_VORBISCOMMENT_MUSICBRAINZ_ALBUMARTISTID != tmp)
00084 {
00085 vorbis_comment_add(p_comment, pComment->user_comments[i]);
00086 }
00087 }
00088 }
00089
00090
00091 vorbis_comment_clear(pComment);
00092 vorbis_comment_init(pComment);
00093 if (p_comment->comments > 0)
00094 {
00095 for (int i=0; i<p_comment->comments; ++i)
00096 {
00097 vorbis_comment_add(pComment, p_comment->user_comments[i]);
00098 }
00099 }
00100
00101
00102 vorbis_comment_clear(p_comment);
00103 delete p_comment;
00104 p_comment = pComment;
00105 }
00106
00107 QCString utf8str;
00108 if (!mdata->Artist().isEmpty())
00109 {
00110 utf8str = mdata->Artist().utf8();
00111 char *artist = utf8str.data();
00112 vorbis_comment_add_tag(p_comment, (char *)MYTH_VORBISCOMMENT_ARTIST,
00113 artist);
00114 }
00115
00116 if (mdata->Compilation())
00117 {
00118
00119 vorbis_comment_add_tag(p_comment, (char *)MYTH_VORBISCOMMENT_MUSICBRAINZ_ALBUMARTISTID,
00120 MYTH_MUSICBRAINZ_ALBUMARTIST_UUID);
00121
00122 if (!mdata->CompilationArtist().isEmpty())
00123 {
00124 utf8str = mdata->CompilationArtist().utf8();
00125 char *compilation_artist = utf8str.data();
00126 vorbis_comment_add_tag(p_comment, (char *)MYTH_VORBISCOMMENT_COMPILATIONARTIST,
00127 compilation_artist);
00128
00129 }
00130 }
00131
00132 if (!mdata->Title().isEmpty())
00133 {
00134 utf8str = mdata->Title().utf8();
00135 char *title = utf8str.data();
00136 vorbis_comment_add_tag(p_comment, (char *)MYTH_VORBISCOMMENT_TITLE,
00137 title);
00138 }
00139
00140 if (!mdata->Album().isEmpty())
00141 {
00142 utf8str = mdata->Album().utf8();
00143 char *album = utf8str.data();
00144 vorbis_comment_add_tag(p_comment, (char *)MYTH_VORBISCOMMENT_ALBUM,
00145 album);
00146 }
00147
00148 if (!mdata->Genre().isEmpty())
00149 {
00150 utf8str = mdata->Genre().utf8();
00151 char *genre = utf8str.data();
00152 vorbis_comment_add_tag(p_comment, (char *)MYTH_VORBISCOMMENT_GENRE,
00153 genre);
00154 }
00155
00156 if (0 != mdata->Track())
00157 {
00158 char tracknum[10];
00159 snprintf(tracknum, 9, "%d", mdata->Track());
00160 vorbis_comment_add_tag(p_comment, (char *)MYTH_VORBISCOMMENT_TRACK,
00161 tracknum);
00162 }
00163
00164 if (0 != mdata->Year())
00165 {
00166 char year[10];
00167 snprintf(year, 9, "%d", mdata->Year());
00168 vorbis_comment_add_tag(p_comment, (char *)MYTH_VORBISCOMMENT_DATE,
00169 year);
00170 }
00171
00172
00173 return p_comment;
00174 }
00175
00176
00177
00187 bool MetaIOOggVorbisComment::write(Metadata* mdata, bool exclusive)
00188 {
00189
00190 if (!mdata)
00191 return false;
00192
00193 FILE* p_input = NULL;
00194 p_input = fopen(mdata->Filename().local8Bit(), "rb");
00195 if (!p_input)
00196 p_input = fopen(mdata->Filename().ascii(), "rb");
00197
00198 if (!p_input)
00199 return false;
00200
00201 QString newfilename = createTempFile(
00202 mdata->Filename().local8Bit() + ".XXXXXX");
00203
00204 FILE *p_output = fopen(newfilename, "wb");
00205
00206 if (!p_output)
00207 {
00208 fclose(p_input);
00209 return false;
00210 }
00211
00212 vcedit_state* p_state = vcedit_new_state();
00213
00214 if (vcedit_open(p_state, p_input) < 0)
00215 {
00216 vcedit_clear(p_state);
00217 fclose(p_input);
00218 fclose(p_output);
00219 return false;
00220 }
00221
00222
00223 vorbis_comment* p_comment = vcedit_comments(p_state);
00224
00225 if (exclusive)
00226 {
00227 vorbis_comment_clear(p_comment);
00228 vorbis_comment_init(p_comment);
00229 }
00230
00231 if (!getRawVorbisComment(mdata, p_comment))
00232 {
00233 vcedit_clear(p_state);
00234 fclose(p_input);
00235 fclose(p_output);
00236 return false;
00237 }
00238
00239
00240
00241 if (vcedit_write(p_state, p_output) < 0)
00242 {
00243 vcedit_clear(p_state);
00244 fclose(p_input);
00245 fclose(p_output);
00246 return false;
00247 }
00248
00249
00250 vcedit_clear(p_state);
00251 fclose(p_input);
00252 fclose(p_output);
00253
00254
00255 if (0 != rename(newfilename.local8Bit(), mdata->Filename().local8Bit())
00256 || 0 != rename(newfilename.ascii(), mdata->Filename().ascii()))
00257 {
00258
00259 remove(newfilename.local8Bit()) && remove(newfilename.ascii());
00260 return false;
00261 }
00262
00263 return true;
00264 }
00265
00266
00267
00274 Metadata* MetaIOOggVorbisComment::read(QString filename)
00275 {
00276 QString artist = "", compilation_artist = "", album = "", title = "", genre = "";
00277 int year = 0, tracknum = 0, length = 0;
00278 bool compilation = false;
00279
00280 FILE* p_input = NULL;
00281 p_input = fopen(filename.local8Bit(), "rb");
00282 if (!p_input)
00283 p_input = fopen(filename.ascii(), "rb");
00284
00285 if (p_input)
00286 {
00287 OggVorbis_File vf;
00288 vorbis_comment *comment = NULL;
00289
00290 if (0 != ov_open(p_input, &vf, NULL, 0))
00291 {
00292 fclose(p_input);
00293 }
00294 else
00295 {
00296 comment = ov_comment(&vf, -1);
00297
00298
00299
00300
00301
00302 artist = getComment(comment, MYTH_VORBISCOMMENT_ARTIST);
00303 compilation_artist = getComment(comment, MYTH_VORBISCOMMENT_COMPILATIONARTIST);
00304 album = getComment(comment, MYTH_VORBISCOMMENT_ALBUM);
00305 title = getComment(comment, MYTH_VORBISCOMMENT_TITLE);
00306 genre = getComment(comment, MYTH_VORBISCOMMENT_GENRE);
00307 tracknum = atoi(getComment(comment, MYTH_VORBISCOMMENT_TRACK).ascii());
00308 year = atoi(getComment(comment, MYTH_VORBISCOMMENT_DATE).ascii());
00309
00310 QString tmp = getComment(comment, MYTH_VORBISCOMMENT_MUSICBRAINZ_ALBUMARTISTID);
00311 compilation = (MYTH_MUSICBRAINZ_ALBUMARTIST_UUID == tmp);
00312
00313 length = getTrackLength(&vf);
00314
00315
00316 ov_clear(&vf);
00317 }
00318 }
00319
00320
00321
00322
00323
00324
00325 if (title.isEmpty())
00326 {
00327 year = 0;
00328 readFromFilename(filename, artist, album, title, genre, tracknum);
00329 }
00330
00331 Metadata *retdata = new Metadata(filename, artist, compilation_artist, album,
00332 title, genre, year, tracknum, length);
00333
00334 retdata->setCompilation(compilation);
00335
00336 return retdata;
00337 }
00338
00339
00340
00347 int MetaIOOggVorbisComment::getTrackLength(OggVorbis_File* pVf)
00348 {
00349 if (!pVf)
00350 return 0;
00351
00352 return (int)(ov_time_total(pVf, -1) * 1000);
00353 }
00354
00355
00356
00363 int MetaIOOggVorbisComment::getTrackLength(QString filename)
00364 {
00365 FILE* p_input = NULL;
00366 p_input = fopen(filename.local8Bit(), "rb");
00367 if (!p_input)
00368 p_input = fopen(filename.ascii(), "rb");
00369
00370 if (!p_input)
00371 return 0;
00372
00373 OggVorbis_File vf;
00374
00375 if (ov_open(p_input, &vf, NULL, 0))
00376 {
00377 fclose(p_input);
00378 return 0;
00379 }
00380
00381 int rv = getTrackLength(&vf);
00382
00383
00384 ov_clear(&vf);
00385
00386 return rv;
00387 }
00388
00389
00390
00398 QString MetaIOOggVorbisComment::getComment(vorbis_comment* pComment,
00399 const char* pLabel)
00400 {
00401 char *tag;
00402 QString retstr;
00403
00404 if (pComment
00405 && NULL != (tag = vorbis_comment_query(pComment, (char *)pLabel, 0)))
00406 retstr = QString::fromUtf8(tag);
00407 else
00408 retstr = "";
00409
00410 return retstr;
00411 }
00412