id3tag.c

Go to the documentation of this file.
00001 /*
00002  * id3tag.c -- Write ID3 version 1 and 2 tags.
00003  *
00004  * Copyright (C) 2000 Don Melton.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 
00021 /*
00022  * HISTORY: This source file is part of LAME (see http://www.mp3dev.org/mp3/)
00023  * and was originally adapted by Conrad Sanderson <c.sanderson@me.gu.edu.au>
00024  * from mp3info by Ricardo Cerqueira <rmc@rccn.net> to write only ID3 version 1
00025  * tags.  Don Melton <don@blivet.com> COMPLETELY rewrote it to support version
00026  * 2 tags and be more conformant to other standards while remaining flexible.
00027  *
00028  * NOTE: See http://id3.org/ for more information about ID3 tag formats.
00029  */
00030 
00031 /* $Id: id3tag.c,v 1.42 2007/07/24 17:46:10 bouvigne Exp $ */
00032 
00033 #ifdef HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036 
00037 #ifdef STDC_HEADERS
00038 # include <stddef.h>
00039 # include <stdlib.h>
00040 # include <string.h>
00041 #else
00042 # ifndef HAVE_STRCHR
00043 #  define strchr index
00044 #  define strrchr rindex
00045 # endif
00046 char   *strchr(), *strrchr();
00047 # ifndef HAVE_MEMCPY
00048 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
00049 #  define memmove(d, s, n) bcopy ((s), (d), (n))
00050 # endif
00051 #endif
00052 
00053 
00054 #ifdef _MSC_VER
00055 #define snprintf _snprintf
00056 #endif
00057 
00058 
00059 #include "lame.h"
00060 #include "machine.h"
00061 #include "encoder.h"
00062 #include "id3tag.h"
00063 #include "lame_global_flags.h"
00064 #include "util.h"
00065 #include "bitstream.h"
00066 
00067 
00068 static const char *const genre_names[] = {
00069     /*
00070      * NOTE: The spelling of these genre names is identical to those found in
00071      * Winamp and mp3info.
00072      */
00073     "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
00074     "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
00075     "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
00076     "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
00077     "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
00078     "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alternative Rock",
00079     "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
00080     "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
00081     "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
00082     "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
00083     "Native US", "Cabaret", "New Wave", "Psychedelic", "Rave",
00084     "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
00085     "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
00086     "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin",
00087     "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
00088     "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
00089     "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
00090     "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
00091     "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
00092     "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
00093     "Punk Rock", "Drum Solo", "Acappella", "Euro-House", "Dance Hall",
00094     "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
00095     "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta",
00096     "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
00097     "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
00098     "SynthPop"
00099 };
00100 
00101 #define GENRE_NAME_COUNT \
00102     ((int)(sizeof genre_names / sizeof (const char *const)))
00103 
00104 static const int genre_alpha_map[] = {
00105     123, 34, 74, 73, 99, 20, 40, 26, 145, 90, 116, 41, 135, 85, 96, 138, 89, 0,
00106     107, 132, 65, 88, 104, 102, 97, 136, 61, 141, 32, 1, 112, 128, 57, 140, 2,
00107     139, 58, 3, 125, 50, 22, 4, 55, 127, 122, 120, 98, 52, 48, 54, 124, 25, 84,
00108     80, 115, 81, 119, 5, 30, 36, 59, 126, 38, 49, 91, 6, 129, 79, 137, 7, 35,
00109     100, 131, 19, 33, 46, 47, 8, 29, 146, 63, 86, 71, 45, 142, 9, 77, 82, 64,
00110     133, 10, 66, 39, 11, 103, 12, 75, 134, 13, 53, 62, 109, 117, 23, 108, 92,
00111     67, 93, 43, 121, 15, 68, 14, 16, 76, 87, 118, 17, 78, 143, 114, 110, 69, 21,
00112     111, 95, 105, 42, 37, 24, 56, 44, 101, 83, 94, 106, 147, 113, 18, 51, 130,
00113     144, 60, 70, 31, 72, 27, 28
00114 };
00115 
00116 #define GENRE_ALPHA_COUNT ((int)(sizeof genre_alpha_map / sizeof (int)))
00117 
00118 #define GENRE_INDEX_OTHER 12
00119 
00120 void
00121 id3tag_genre_list(void (*handler) (int, const char *, void *), void *cookie)
00122 {
00123     if (handler) {
00124         int     i;
00125         for (i = 0; i < GENRE_NAME_COUNT; ++i) {
00126             if (i < GENRE_ALPHA_COUNT) {
00127                 int     j = genre_alpha_map[i];
00128                 handler(j, genre_names[j], cookie);
00129             }
00130         }
00131     }
00132 }
00133 
00134 #define GENRE_NUM_UNKNOWN 255
00135 
00136 void
00137 id3tag_init(lame_global_flags * gfp)
00138 {
00139     lame_internal_flags *gfc = gfp->internal_flags;
00140     free_id3tag(gfc);
00141     memset(&gfc->tag_spec, 0, sizeof gfc->tag_spec);
00142     gfc->tag_spec.genre_id3v1 = GENRE_NUM_UNKNOWN;
00143 }
00144 
00145 
00146 
00147 void
00148 id3tag_add_v2(lame_global_flags * gfp)
00149 {
00150     lame_internal_flags *gfc = gfp->internal_flags;
00151     gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
00152     gfc->tag_spec.flags |= ADD_V2_FLAG;
00153 }
00154 
00155 void
00156 id3tag_v1_only(lame_global_flags * gfp)
00157 {
00158     lame_internal_flags *gfc = gfp->internal_flags;
00159     gfc->tag_spec.flags &= ~(ADD_V2_FLAG | V2_ONLY_FLAG);
00160     gfc->tag_spec.flags |= V1_ONLY_FLAG;
00161 }
00162 
00163 void
00164 id3tag_v2_only(lame_global_flags * gfp)
00165 {
00166     lame_internal_flags *gfc = gfp->internal_flags;
00167     gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
00168     gfc->tag_spec.flags |= V2_ONLY_FLAG;
00169 }
00170 
00171 void
00172 id3tag_space_v1(lame_global_flags * gfp)
00173 {
00174     lame_internal_flags *gfc = gfp->internal_flags;
00175     gfc->tag_spec.flags &= ~V2_ONLY_FLAG;
00176     gfc->tag_spec.flags |= SPACE_V1_FLAG;
00177 }
00178 
00179 void
00180 id3tag_pad_v2(lame_global_flags * gfp)
00181 {
00182     lame_internal_flags *gfc = gfp->internal_flags;
00183     gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
00184     gfc->tag_spec.flags |= PAD_V2_FLAG;
00185 }
00186 
00187 
00188 static void
00189 local_strdup( char** dst, const char* src )
00190 {
00191     if (dst == 0) {
00192         return;
00193     }
00194     if (src == 0) {
00195         return;
00196     }
00197     if (*dst != 0) {
00198         free(*dst);
00199     }
00200     *dst = strdup(src);
00201 }
00202 
00203 
00204 void
00205 id3tag_set_title(lame_global_flags * gfp, const char *title)
00206 {
00207     lame_internal_flags *gfc = gfp->internal_flags;
00208     if (title && *title) {
00209         local_strdup(&gfc->tag_spec.title, title);
00210         gfc->tag_spec.flags |= CHANGED_FLAG;
00211     }
00212 }
00213 
00214 void
00215 id3tag_set_artist(lame_global_flags * gfp, const char *artist)
00216 {
00217     lame_internal_flags *gfc = gfp->internal_flags;
00218     if (artist && *artist) {
00219         local_strdup(&gfc->tag_spec.artist, artist);
00220         gfc->tag_spec.flags |= CHANGED_FLAG;
00221     }
00222 }
00223 
00224 void
00225 id3tag_set_album(lame_global_flags * gfp, const char *album)
00226 {
00227     lame_internal_flags *gfc = gfp->internal_flags;
00228     if (album && *album) {
00229         local_strdup(&gfc->tag_spec.album, album);
00230         gfc->tag_spec.flags |= CHANGED_FLAG;
00231     }
00232 }
00233 
00234 void
00235 id3tag_set_year(lame_global_flags * gfp, const char *year)
00236 {
00237     lame_internal_flags *gfc = gfp->internal_flags;
00238     if (year && *year) {
00239         int     num = atoi(year);
00240         if (num < 0) {
00241             num = 0;
00242         }
00243         /* limit a year to 4 digits so it fits in a version 1 tag */
00244         if (num > 9999) {
00245             num = 9999;
00246         }
00247         if (num) {
00248             gfc->tag_spec.year = num;
00249             gfc->tag_spec.flags |= CHANGED_FLAG;
00250         }
00251     }
00252 }
00253 
00254 void
00255 id3tag_set_comment(lame_global_flags * gfp, const char *comment)
00256 {
00257     lame_internal_flags *gfc = gfp->internal_flags;
00258     if (comment && *comment) {
00259         local_strdup(&gfc->tag_spec.comment, comment);
00260         gfc->tag_spec.flags |= CHANGED_FLAG;
00261     }
00262 }
00263 
00264 int
00265 id3tag_set_track(lame_global_flags * gfp, const char *track)
00266 {
00267     char   *trackcount;
00268     lame_internal_flags *gfc = gfp->internal_flags;
00269     int     ret = 0;
00270 
00271     if (track && *track) {
00272         int     num = atoi(track);
00273         /* check for valid ID3v1 track number range */
00274         if (num < 1 || num > 255) {
00275             num = 0;
00276             ret = -1; /* track number out of ID3v1 range, ignored for ID3v1 */
00277             gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG);
00278         }
00279         if (num) {
00280             gfc->tag_spec.track_id3v1 = num;
00281             gfc->tag_spec.flags |= CHANGED_FLAG;
00282         }
00283         local_strdup(&gfc->tag_spec.track_id3v2, track);
00284 
00285         /* Look for the total track count after a "/", same restrictions */
00286         trackcount = strchr(track, '/');
00287         if (trackcount && *trackcount) {
00288             gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG);
00289         }
00290     }
00291     return ret;
00292 }
00293 
00294 /* would use real "strcasecmp" but it isn't portable */
00295 static int
00296 local_strcasecmp(const char *s1, const char *s2)
00297 {
00298     unsigned char c1;
00299     unsigned char c2;
00300     do {
00301         c1 = tolower(*s1);
00302         c2 = tolower(*s2);
00303         if (!c1) {
00304             break;
00305         }
00306         ++s1;
00307         ++s2;
00308     } while (c1 == c2);
00309     return c1 - c2;
00310 }
00311 
00312 int
00313 id3tag_set_genre(lame_global_flags * gfp, const char *genre)
00314 {
00315     lame_internal_flags *gfc = gfp->internal_flags;
00316     int ret = 0;
00317     if (genre && *genre) {
00318         char   *str;
00319         int     num = strtol(genre, &str, 10);
00320         /* is the input a string or a valid number? */
00321         if (*str) {
00322             int     i;
00323             for (i = 0; i < GENRE_NAME_COUNT; ++i) {
00324                 if (!local_strcasecmp(genre, genre_names[i])) {
00325                     num = i;
00326                     break;
00327                 }
00328             }
00329             if (i == GENRE_NAME_COUNT) {
00330                 num = GENRE_INDEX_OTHER;
00331                 ret = -2;
00332             }
00333         }
00334         else {
00335             if ((num < 0) || (num >= GENRE_NAME_COUNT)) {
00336                 return -1;
00337             }
00338             genre = genre_names[num];
00339         }
00340         local_strdup(&gfc->tag_spec.genre_id3v2, genre);
00341         gfc->tag_spec.genre_id3v1 = num;
00342         gfc->tag_spec.flags |= CHANGED_FLAG;
00343         if (ret) {
00344             gfc->tag_spec.flags |= ADD_V2_FLAG;
00345         }
00346     }
00347     return ret;
00348 }
00349 
00350 
00351 /*
00352 Some existing options for ID3 tag can be specified by --tv option
00353 as follows.
00354 --tt <value>, --tv TIT2=value
00355 --ta <value>, --tv TPE1=value
00356 --tl <value>, --tv TALB=value
00357 --ty <value>, --tv TYER=value
00358 --tn <value>, --tv TRCK=value
00359 --tg <value>, --tv TCON=value
00360 (although some are not exactly same)*/
00361 
00362 int
00363 id3tag_set_fieldvalue(lame_global_flags * gfp, const char *fieldvalue)
00364 {
00365     lame_internal_flags *gfc = gfp->internal_flags;
00366     if (fieldvalue && *fieldvalue) {
00367         char **p = NULL;
00368         if (strlen(fieldvalue) < 5 || fieldvalue[4] != '=') {
00369             return -1;
00370         }
00371         p = (char **)realloc(gfc->tag_spec.values, sizeof(char*) * (gfc->tag_spec.num_values + 1));
00372         if (!p) {
00373             return -1;
00374         }
00375         gfc->tag_spec.values = (char**)p;
00376         gfc->tag_spec.values[gfc->tag_spec.num_values++] = strdup(fieldvalue);
00377         gfc->tag_spec.flags |= CHANGED_FLAG;
00378     }
00379     id3tag_add_v2(gfp);
00380     return 0;
00381 }
00382 
00383 int
00384 id3tag_set_albumart(lame_global_flags* gfp, const char* image, unsigned long size)
00385 {
00386     int mimetype = 0;
00387     unsigned char *data = (unsigned char *)image;
00388     lame_internal_flags *gfc = gfp->internal_flags;
00389 
00390     /* make sure the image size is no larger than the maximum value */
00391     if (LAME_MAXALBUMART < size) {
00392         return -1;
00393     }
00394     /* determine MIME type from the actual image data */
00395     if (2 < size && data[0] == 0xFF && data[1] == 0xD8) {
00396         mimetype = MIMETYPE_JPEG;
00397     } else if (4 < size && data[0] == 0x89 && strncmp((const char *)&data[1], "PNG", 3) == 0) {
00398         mimetype = MIMETYPE_PNG;
00399     } else if (4 < size && strncmp((const char *)data, "GIF8", 4) == 0) { 
00400         mimetype = MIMETYPE_GIF;
00401     } else {
00402         return -1;
00403     }
00404     if (gfc->tag_spec.albumart != 0) {
00405         free(gfc->tag_spec.albumart);
00406         gfc->tag_spec.albumart = 0;
00407         gfc->tag_spec.albumart_size = 0;
00408         gfc->tag_spec.albumart_mimetype = MIMETYPE_NONE;
00409     }
00410     if (size < 1) {
00411         return 0;
00412     }
00413     gfc->tag_spec.albumart = malloc(size);
00414     if (gfc->tag_spec.albumart != 0) {
00415         memcpy(gfc->tag_spec.albumart, image, size);
00416         gfc->tag_spec.albumart_size = size;
00417         gfc->tag_spec.albumart_mimetype = mimetype;
00418         gfc->tag_spec.flags |= CHANGED_FLAG;
00419         id3tag_add_v2(gfp);
00420     }
00421     return 0;
00422 }
00423 
00424 static unsigned char *
00425 set_4_byte_value(unsigned char *bytes, unsigned long value)
00426 {
00427     int     index;
00428     for (index = 3; index >= 0; --index) {
00429         bytes[index] = value & 0xfful;
00430         value >>= 8;
00431     }
00432     return bytes + 4;
00433 }
00434 
00435 #define FRAME_ID(a, b, c, d) \
00436     ( ((unsigned long)(a) << 24) \
00437     | ((unsigned long)(b) << 16) \
00438     | ((unsigned long)(c) <<  8) \
00439     | ((unsigned long)(d) <<  0) )
00440 #define TITLE_FRAME_ID FRAME_ID('T', 'I', 'T', '2')
00441 #define ARTIST_FRAME_ID FRAME_ID('T', 'P', 'E', '1')
00442 #define ALBUM_FRAME_ID FRAME_ID('T', 'A', 'L', 'B')
00443 #define YEAR_FRAME_ID FRAME_ID('T', 'Y', 'E', 'R')
00444 #define COMMENT_FRAME_ID FRAME_ID('C', 'O', 'M', 'M')
00445 #define TRACK_FRAME_ID FRAME_ID('T', 'R', 'C', 'K')
00446 #define GENRE_FRAME_ID FRAME_ID('T', 'C', 'O', 'N')
00447 #define ENCODER_FRAME_ID FRAME_ID('T', 'S', 'S', 'E')
00448 #define PLAYLENGTH_FRAME_ID FRAME_ID('T', 'L', 'E', 'N')
00449 
00450 static unsigned char *
00451 set_frame(unsigned char *frame, unsigned long id, const char *text, size_t length)
00452 {
00453     if (length) {
00454         unsigned long frame_size = (unsigned long)length;
00455         frame_size += ((id == COMMENT_FRAME_ID) ? 5 : 1);
00456         frame = set_4_byte_value(frame, id);
00457         /* Set frame size = total size - header size.  Frame header and field
00458          * bytes include 2-byte header flags, 1 encoding descriptor byte, and
00459          * for comment frames: 3-byte language descriptor and 1 content
00460          * descriptor byte */
00461         frame = set_4_byte_value(frame, frame_size);
00462         /* clear 2-byte header flags */
00463         *frame++ = 0;
00464         *frame++ = 0;
00465         /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */
00466         *frame++ = 0;
00467         if (id == COMMENT_FRAME_ID) {
00468             /* use id3lib-compatible bogus language descriptor */
00469             *frame++ = 'X';
00470             *frame++ = 'X';
00471             *frame++ = 'X';
00472             /* clear 1 byte to make content descriptor empty string */
00473             *frame++ = 0;
00474         }
00475         while (length--) {
00476             *frame++ = *text++;
00477         }
00478     }
00479     return frame;
00480 }
00481 
00482 static unsigned char *
00483 set_frame_custom(unsigned char *frame, const char *fieldvalue)
00484 {
00485     if (fieldvalue && *fieldvalue) {
00486         const char *value = fieldvalue + 5;
00487         size_t length = strlen(value);
00488         *frame++ = *fieldvalue++;
00489         *frame++ = *fieldvalue++;
00490         *frame++ = *fieldvalue++;
00491         *frame++ = *fieldvalue++;
00492         frame = set_4_byte_value(frame, (unsigned long)(strlen(value) + 1));
00493         /* clear 2-byte header flags */
00494         *frame++ = 0;
00495         *frame++ = 0;
00496         /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */
00497         *frame++ = 0;
00498         while (length--) {
00499             *frame++ = *value++;
00500         }
00501     }
00502     return frame;
00503 }
00504 
00505 static unsigned char *
00506 set_frame_apic(unsigned char *frame, const char *mimetype, const unsigned char *data, size_t size)
00507 {
00508     /* ID3v2.3 standard APIC frame:
00509      *     <Header for 'Attached picture', ID: "APIC">
00510      *     Text encoding    $xx
00511      *     MIME type        <text string> $00
00512      *     Picture type     $xx
00513      *     Description      <text string according to encoding> $00 (00)
00514      *     Picture data     <binary data>
00515      */
00516     if (mimetype && data && size) {
00517         frame = set_4_byte_value(frame, FRAME_ID('A', 'P', 'I', 'C'));
00518         frame = set_4_byte_value(frame, (unsigned long)(4 + strlen(mimetype) + size));
00519         /* clear 2-byte header flags */
00520         *frame++ = 0;
00521         *frame++ = 0;
00522         /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */
00523         *frame++ = 0;
00524         /* copy mime_type */
00525         while (*mimetype) {
00526             *frame++ = *mimetype++;
00527         }
00528         *frame++ = 0;
00529         /* set picture type to 0 */
00530         *frame++ = 0;
00531         /* empty description field */
00532         *frame++ = 0;
00533         /* copy the image data */
00534         while (size--) {
00535             *frame++ = *data++;
00536         }
00537     }
00538     return frame;
00539 }
00540 
00541 int
00542 id3tag_write_v2(lame_global_flags * gfp)
00543 {
00544     lame_internal_flags *gfc = gfp->internal_flags;
00545     if ((gfc->tag_spec.flags & CHANGED_FLAG)
00546         && !(gfc->tag_spec.flags & V1_ONLY_FLAG)) {
00547         /* calculate length of four fields which may not fit in verion 1 tag */
00548         size_t  title_length = gfc->tag_spec.title ? strlen(gfc->tag_spec.title) : 0;
00549         size_t  artist_length = gfc->tag_spec.artist ? strlen(gfc->tag_spec.artist) : 0;
00550         size_t  album_length = gfc->tag_spec.album ? strlen(gfc->tag_spec.album) : 0;
00551         size_t  comment_length = gfc->tag_spec.comment ? strlen(gfc->tag_spec.comment) : 0;
00552         /* write tag if explicitly requested or if fields overflow */
00553         if ((gfc->tag_spec.flags & (ADD_V2_FLAG | V2_ONLY_FLAG))
00554             || (title_length > 30)
00555             || (artist_length > 30) || (album_length > 30)
00556             || (comment_length > 30)
00557             || (gfc->tag_spec.track_id3v1 && (comment_length > 28))) {
00558             size_t  tag_size;
00559             char    encoder[80];
00560             size_t  encoder_length;
00561             unsigned long playlength_ms;
00562             char    playlength[20];
00563             size_t  playlength_length;
00564             char    year[5];
00565             size_t  year_length;
00566             size_t  track_length;
00567             size_t  genre_length = 0;
00568             unsigned char *tag;
00569             unsigned char *p;
00570             size_t  adjusted_tag_size;
00571             unsigned int index;
00572             const char *albumart_mime = NULL;
00573             static const char *mime_jpeg = "image/jpeg";
00574             static const char *mime_png = "image/png";
00575             static const char *mime_gif = "image/gif";
00576             /* calculate playlength in milliseconds */
00577             {
00578                 double const max_ulong = MAX_U_32_NUM;
00579                 double ms = gfp->num_samples;
00580                 ms *= 1000;
00581                 ms /= gfp->in_samplerate;
00582                 if (ms > max_ulong) {
00583                     playlength_ms = max_ulong;
00584                 }
00585                 else if (ms < 0) {
00586                     playlength_ms = 0;
00587                 }
00588                 else {
00589                     playlength_ms = ms;
00590                 }
00591             }
00592             /* calulate size of tag starting with 10-byte tag header */
00593             tag_size = 10;
00594 #if defined(__hpux) || defined(__svr4__) || defined(M_UNIX) || defined(_AIX)
00595             encoder_length = sprintf(encoder, "LAME v%s", get_lame_version());
00596             if (encoder_length + 1 > sizeof(encoder))
00597                 abort();
00598             playlength_length = sprintf(playlength, "%lu", playlength_ms);
00599             if (playlength_length + 1 > sizeof(playlength))
00600                 abort();
00601 #else
00602 #if defined(__sun__)
00603             (void) sprintf(encoder, "LAME v%s", get_lame_version());
00604             encoder_length = strlen(encoder);
00605             (void) sprintf(playlength, "%lu", playlength_ms);
00606             playlength_length = strlen(playlength);
00607 #else
00608             encoder_length = snprintf(encoder, sizeof(encoder),
00609                                       "LAME v%s", get_lame_version());
00610             playlength_length = snprintf(playlength, sizeof(playlength), "%lu", playlength_ms);
00611 #endif
00612 #endif
00613             tag_size += 11 + encoder_length;
00614             tag_size += 11 + playlength_length;
00615             if (title_length) {
00616                 /* add 10-byte frame header, 1 encoding descriptor byte ... */
00617                 tag_size += 11 + title_length;
00618             }
00619             if (artist_length) {
00620                 tag_size += 11 + artist_length;
00621             }
00622             if (album_length) {
00623                 tag_size += 11 + album_length;
00624             }
00625             if (gfc->tag_spec.year) {
00626                 year_length = sprintf(year, "%d", gfc->tag_spec.year);
00627                 if (year_length + 1 > sizeof(year))
00628                     abort();
00629                 tag_size += 11 + year_length;
00630             }
00631             else {
00632                 year_length = 0;
00633             }
00634             if (comment_length) {
00635                 /* add 10-byte frame header, 1 encoding descriptor byte,
00636                  * 3-byte language descriptor, 1 content descriptor byte ... */
00637                 tag_size += 15 + comment_length;
00638             }
00639             if (gfc->tag_spec.track_id3v2 != 0) {
00640                 track_length = strlen(gfc->tag_spec.track_id3v2);
00641                 tag_size += 11 + track_length;
00642             }
00643             else {
00644                 track_length = 0;
00645             }
00646             if (gfc->tag_spec.genre_id3v2 != 0) {
00647                 genre_length = strlen(gfc->tag_spec.genre_id3v2);
00648                 tag_size += 11 + genre_length;
00649             }
00650             else {
00651                 genre_length = 0;
00652             }
00653             for (index = 0;index < gfc->tag_spec.num_values;++index) {
00654                 tag_size += 6 + strlen(gfc->tag_spec.values[index]);
00655             }
00656             if (gfc->tag_spec.albumart && gfc->tag_spec.albumart_size) {
00657                 switch (gfc->tag_spec.albumart_mimetype) {
00658                 case MIMETYPE_JPEG:
00659                     albumart_mime = mime_jpeg;
00660                     break;
00661                 case MIMETYPE_PNG:
00662                     albumart_mime = mime_png;
00663                     break;
00664                 case MIMETYPE_GIF:
00665                     albumart_mime = mime_gif;
00666                     break;
00667                 }
00668                 tag_size += 10 + 4 + strlen(albumart_mime) + gfc->tag_spec.albumart_size;
00669             }
00670             if (gfc->tag_spec.flags & PAD_V2_FLAG) {
00671                 /* add 128 bytes of padding */
00672                 tag_size += 128;
00673             }
00674             tag = (unsigned char *) malloc(tag_size);
00675             if (!tag) {
00676                 return -1;
00677             }
00678             p = tag;
00679             /* set tag header starting with file identifier */
00680             *p++ = 'I';
00681             *p++ = 'D';
00682             *p++ = '3';
00683             /* set version number word */
00684             *p++ = 3;
00685             *p++ = 0;
00686             /* clear flags byte */
00687             *p++ = 0;
00688             /* calculate and set tag size = total size - header size */
00689             adjusted_tag_size = tag_size - 10;
00690             /* encode adjusted size into four bytes where most significant 
00691              * bit is clear in each byte, for 28-bit total */
00692             *p++ = (unsigned char)((adjusted_tag_size >> 21) & 0x7fu);
00693             *p++ = (unsigned char)((adjusted_tag_size >> 14) & 0x7fu);
00694             *p++ = (unsigned char)((adjusted_tag_size >> 7) & 0x7fu);
00695             *p++ = (unsigned char)(adjusted_tag_size & 0x7fu);
00696 
00697             /*
00698              * NOTE: The remainder of the tag (frames and padding, if any)
00699              * are not "unsynchronized" to prevent false MPEG audio headers
00700              * from appearing in the bitstream.  Why?  Well, most players
00701              * and utilities know how to skip the ID3 version 2 tag by now
00702              * even if they don't read its contents, and it's actually
00703              * very unlikely that such a false "sync" pattern would occur
00704              * in just the simple text frames added here.
00705              */
00706 
00707             /* set each frame in tag */
00708             p = set_frame(p, ENCODER_FRAME_ID, encoder, encoder_length);
00709             p = set_frame(p, PLAYLENGTH_FRAME_ID, playlength, playlength_length);
00710             p = set_frame(p, TITLE_FRAME_ID, gfc->tag_spec.title, title_length);
00711             p = set_frame(p, ARTIST_FRAME_ID, gfc->tag_spec.artist, artist_length);
00712             p = set_frame(p, ALBUM_FRAME_ID, gfc->tag_spec.album, album_length);
00713             p = set_frame(p, YEAR_FRAME_ID, year, year_length);
00714             p = set_frame(p, COMMENT_FRAME_ID, gfc->tag_spec.comment, comment_length);
00715             p = set_frame(p, TRACK_FRAME_ID, gfc->tag_spec.track_id3v2, track_length);
00716             p = set_frame(p, GENRE_FRAME_ID, gfc->tag_spec.genre_id3v2, genre_length);
00717             p = set_frame_apic(p, albumart_mime, gfc->tag_spec.albumart, gfc->tag_spec.albumart_size);
00718             for (index = 0;index < gfc->tag_spec.num_values;++index) {
00719                 p = set_frame_custom(p, gfc->tag_spec.values[index]);
00720             }
00721             /* clear any padding bytes */
00722             memset(p, 0, tag_size - (p - tag));
00723             /* write tag directly into bitstream at current position */
00724             for (index = 0; index < tag_size; ++index) {
00725                 add_dummy_byte(gfp, tag[index], 1);
00726             }
00727             free(tag);
00728             return (int)tag_size;
00729         }
00730     }
00731     return 0;
00732 }
00733 
00734 static unsigned char *
00735 set_text_field(unsigned char *field, const char *text, size_t size, int pad)
00736 {
00737     while (size--) {
00738         if (text && *text) {
00739             *field++ = *text++;
00740         }
00741         else {
00742             *field++ = pad;
00743         }
00744     }
00745     return field;
00746 }
00747 
00748 int
00749 id3tag_write_v1(lame_global_flags * gfp)
00750 {
00751     lame_internal_flags *gfc = gfp->internal_flags;
00752     if ((gfc->tag_spec.flags & CHANGED_FLAG)
00753         && !(gfc->tag_spec.flags & V2_ONLY_FLAG)) {
00754         unsigned char tag[128];
00755         unsigned char *p = tag;
00756         int     pad = (gfc->tag_spec.flags & SPACE_V1_FLAG) ? ' ' : 0;
00757         char    year[5];
00758         int     year_length;
00759         unsigned int index;
00760         /* set tag identifier */
00761         *p++ = 'T';
00762         *p++ = 'A';
00763         *p++ = 'G';
00764         /* set each field in tag */
00765         p = set_text_field(p, gfc->tag_spec.title, 30, pad);
00766         p = set_text_field(p, gfc->tag_spec.artist, 30, pad);
00767         p = set_text_field(p, gfc->tag_spec.album, 30, pad);
00768         year_length = sprintf(year, "%d", gfc->tag_spec.year);
00769         if (year_length + 1 > sizeof(year))
00770             abort();
00771         p = set_text_field(p, gfc->tag_spec.year ? year : NULL, 4, pad);
00772         /* limit comment field to 28 bytes if a track is specified */
00773         p = set_text_field(p, gfc->tag_spec.comment, gfc->tag_spec.track_id3v1 ? 28 : 30, pad);
00774         if (gfc->tag_spec.track_id3v1) {
00775             /* clear the next byte to indicate a version 1.1 tag */
00776             *p++ = 0;
00777             *p++ = gfc->tag_spec.track_id3v1;
00778         }
00779         *p++ = gfc->tag_spec.genre_id3v1;
00780         /* write tag directly into bitstream at current position */
00781         for (index = 0; index < 128; ++index) {
00782             add_dummy_byte(gfp, tag[index], 1);
00783         }
00784         return 128;
00785     }
00786     return 0;
00787 }

Generated on Sun Dec 2 11:34:19 2007 for LAME by  doxygen 1.5.2