summaryrefslogtreecommitdiff
path: root/apps/metadata.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/metadata.c')
-rw-r--r--apps/metadata.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/apps/metadata.c b/apps/metadata.c
index 2883b01407..b8fbd65738 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -75,6 +75,7 @@ static const struct format_list formats[] =
75 { AFMT_A52, "a52" }, 75 { AFMT_A52, "a52" },
76 { AFMT_A52, "ac3" }, 76 { AFMT_A52, "ac3" },
77 { AFMT_WAVPACK, "wv" }, 77 { AFMT_WAVPACK, "wv" },
78 { AFMT_ALAC, "m4a" },
78}; 79};
79 80
80static const unsigned short a52_bitrates[] = 81static const unsigned short a52_bitrates[] =
@@ -180,6 +181,30 @@ static void convert_endian(void *data, const char *format)
180 } 181 }
181} 182}
182 183
184/* read_uint32be() - read an unsigned integer from a big-endian
185 (e.g. Quicktime) file. This is used by the .m4a parser
186*/
187#ifdef ROCKBOX_BIG_ENDIAN
188#define read_uint32be(fd,buf) read((fd),(buf),4)
189#else
190int read_uint32be(int fd, unsigned int* buf) {
191 char tmp;
192 char* p=(char*)buf;
193 size_t n;
194
195 n=read(fd,tmp,4);
196 if (n==4) {
197 tmp=p[0];
198 p[0]=p[3];
199 p[1]=p[2];
200 p[2]=p[1];
201 p[3]=tmp;
202 }
203
204 return(n);
205}
206#endif
207
183/* Read an unaligned 32-bit little endian long from buffer. */ 208/* Read an unaligned 32-bit little endian long from buffer. */
184static unsigned long get_long(void* buf) 209static unsigned long get_long(void* buf)
185{ 210{
@@ -264,6 +289,37 @@ static void convert_utf8(char* utf8)
264 *dest = 0; 289 *dest = 0;
265} 290}
266 291
292
293/* Read a string tag from an M4A file */
294void read_m4a_tag_string(int fd, int len,char** bufptr,size_t* bytes_remaining, char** dest)
295{
296 int data_length;
297
298 if (bytes_remaining==0) {
299 lseek(fd,len,SEEK_CUR); /* Skip everything */
300 } else {
301 /* Skip the data tag header - maybe we should parse it properly? */
302 lseek(fd,16,SEEK_CUR);
303 len-=16;
304
305 *dest=*bufptr;
306 if ((size_t)len+1 > *bytes_remaining) {
307 read(fd,*bufptr,*bytes_remaining-1);
308 lseek(fd,len-(*bytes_remaining-1),SEEK_CUR);
309 *bufptr+=(*bytes_remaining-1);
310 } else {
311 read(fd,*bufptr,len);
312 *bufptr+=len;
313 }
314 **bufptr=(char)0;
315
316 convert_utf8(*dest);
317 data_length = strlen(*dest)+1;
318 *bufptr=(*dest)+data_length;
319 *bytes_remaining-=data_length;
320 }
321}
322
267/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly. 323/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
268 * String values to keep are written to buf. Returns number of bytes written 324 * String values to keep are written to buf. Returns number of bytes written
269 * to buf (including end nil). 325 * to buf (including end nil).
@@ -887,6 +943,280 @@ static bool get_wave_metadata(int fd, struct mp3entry* id3)
887} 943}
888 944
889 945
946
947static bool get_alac_metadata(int fd, struct mp3entry* id3)
948{
949 unsigned char* buf;
950 unsigned long totalsamples;
951 int i,j,k;
952 size_t n;
953 size_t bytes_remaining;
954 char* id3buf;
955 unsigned int compressedsize;
956 unsigned int sample_count;
957 unsigned int sample_duration;
958 int numentries;
959 int entry_size;
960 int size_remaining;
961 int chunk_len;
962 unsigned char chunk_id[4];
963 int sub_chunk_len;
964 unsigned char sub_chunk_id[4];
965
966 /* A simple parser to read vital metadata from an ALAC file.
967 This parser also works for AAC files - they are both stored in
968 a Quicktime M4A container. */
969
970 /* Use the trackname part of the id3 structure as a temporary buffer */
971 buf=id3->path;
972
973 lseek(fd, 0, SEEK_SET);
974
975 totalsamples=0;
976 compressedsize=0;
977 /* read the chunks - we stop when we find the mdat chunk and set compressedsize */
978 while (compressedsize==0) {
979 n=read_uint32be(fd,&chunk_len);
980
981 // This means it was a 64-bit file, so we have problems.
982 if (chunk_len == 1) {
983 logf("need 64bit support\n");
984 return false;
985 }
986
987 n=read(fd,&chunk_id,4);
988 if (memcmp(&chunk_id,"ftyp",4)==0) {
989 /* Check for M4A type */
990 n=read(fd,&chunk_id,4);
991 if (memcmp(&chunk_id,"M4A ",4)!=0) {
992 logf("Not an M4A file, aborting\n");
993 return false;
994 }
995 /* Skip rest of chunk */
996 lseek(fd, chunk_len - 8 - 4, SEEK_CUR); /* FIXME not 8 */
997 } else if (memcmp(&chunk_id,"moov",4)==0) {
998 size_remaining=chunk_len - 8; /* FIXME not 8 */
999
1000 while (size_remaining > 0) {
1001 n=read_uint32be(fd,&sub_chunk_len);
1002 if ((sub_chunk_len < 1) || (sub_chunk_len > size_remaining)) {
1003 logf("Strange sub_chunk_len value inside moov: %d (remaining: %d)\n",sub_chunk_len,size_remaining);
1004 return false;
1005 }
1006 n=read(fd,&sub_chunk_id,4);
1007 size_remaining-=8;
1008
1009 if (memcmp(&sub_chunk_id,"mvhd",4)==0) {
1010 /* We don't need anything from here - skip */
1011 lseek(fd, sub_chunk_len - 8, SEEK_CUR); /* FIXME not 8 */
1012 size_remaining-=(sub_chunk_len-8);
1013 } else if (memcmp(&sub_chunk_id,"udta",4)==0) {
1014 /* The udta chunk contains the metadata - track, artist, album etc.
1015 The format appears to be:
1016 udta
1017 meta
1018 hdlr
1019 ilst
1020 .nam
1021 [rest of tags]
1022 free
1023
1024 NOTE: This code was written by examination of some .m4a files
1025 produced by iTunes v4.9 - it may not therefore be 100%
1026 compliant with all streams. But it should fail gracefully.
1027 */
1028 j=(sub_chunk_len-8);
1029 size_remaining-=j;
1030 n=read_uint32be(fd,&sub_chunk_len);
1031 n=read(fd,&sub_chunk_id,4);
1032 j-=8;
1033 if (memcmp(&sub_chunk_id,"meta",4)==0) {
1034 lseek(fd, 4, SEEK_CUR);
1035 j-=4;
1036 n=read_uint32be(fd,&sub_chunk_len);
1037 n=read(fd,&sub_chunk_id,4);
1038 j-=8;
1039 if (memcmp(&sub_chunk_id,"hdlr",4)==0) {
1040 lseek(fd, sub_chunk_len - 8, SEEK_CUR);
1041 j-=(sub_chunk_len - 8);
1042 n=read_uint32be(fd,&sub_chunk_len);
1043 n=read(fd,&sub_chunk_id,4);
1044 j-=8;
1045 if (memcmp(&sub_chunk_id,"ilst",4)==0) {
1046 /* Here are the actual tags. We use the id3v2 300-byte buffer
1047 to store the string data */
1048 bytes_remaining=sizeof(id3->id3v2buf);
1049 id3->genre=255; /* Not every track is the Blues */
1050 id3buf=id3->id3v2buf;
1051 k=sub_chunk_len-8;
1052 j-=k;
1053 while (k > 0) {
1054 n=read_uint32be(fd,&sub_chunk_len);
1055 n=read(fd,&sub_chunk_id,4);
1056 k-=8;
1057 if (memcmp(sub_chunk_id,"\251nam",4)==0) {
1058 read_m4a_tag_string(fd,sub_chunk_len-8,&id3buf,&bytes_remaining,&id3->title);
1059 } else if (memcmp(sub_chunk_id,"\251ART",4)==0) {
1060 read_m4a_tag_string(fd,sub_chunk_len-8,&id3buf,&bytes_remaining,&id3->artist);
1061 } else if (memcmp(sub_chunk_id,"\251alb",4)==0) {
1062 read_m4a_tag_string(fd,sub_chunk_len-8,&id3buf,&bytes_remaining,&id3->album);
1063 } else if (memcmp(sub_chunk_id,"\251gen",4)==0) {
1064 read_m4a_tag_string(fd,sub_chunk_len-8,&id3buf,&bytes_remaining,&id3->genre_string);
1065 } else if (memcmp(sub_chunk_id,"\251day",4)==0) {
1066 read_m4a_tag_string(fd,sub_chunk_len-8,&id3buf,&bytes_remaining,&id3->year_string);
1067 } else if (memcmp(sub_chunk_id,"trkn",4)==0) {
1068 if (sub_chunk_len==0x20) {
1069 read(fd,buf,sub_chunk_len-8);
1070 id3->tracknum=buf[19];
1071 } else {
1072 lseek(fd, sub_chunk_len-8,SEEK_CUR);
1073 }
1074 } else {
1075 lseek(fd, sub_chunk_len-8,SEEK_CUR);
1076 }
1077 k-=(sub_chunk_len-8);
1078 }
1079 }
1080 }
1081 }
1082 /* Skip any remaining data in udta chunk */
1083 lseek(fd, j, SEEK_CUR);
1084 } else if (memcmp(&sub_chunk_id,"trak",4)==0) {
1085 /* Format of trak chunk:
1086 tkhd
1087 mdia
1088 mdhd
1089 hdlr
1090 minf
1091 smhd
1092 dinf
1093 stbl
1094 stsd - Samplerate, Samplesize, Numchannels
1095 stts - time_to_sample array - RLE'd table containing duration of each block
1096 stsz - sample_byte_size array - ?Size in bytes of each compressed block
1097 stsc - Seek table related?
1098 stco - Seek table related?
1099 */
1100
1101 /* Skip tkhd - not needed */
1102 n=read_uint32be(fd,&sub_chunk_len);
1103 n=read(fd,&sub_chunk_id,4);
1104 if (memcmp(&sub_chunk_id,"tkhd",4)!=0) {
1105 logf("Expecting tkhd\n");
1106 return false;
1107 }
1108 lseek(fd, sub_chunk_len - 8, SEEK_CUR); /* FIXME not 8 */
1109 size_remaining-=sub_chunk_len;
1110
1111 /* Process mdia */
1112 n=read_uint32be(fd,&sub_chunk_len);
1113 n=read(fd,&sub_chunk_id,4);
1114 if (memcmp(&sub_chunk_id,"mdia",4)!=0) {
1115 logf("Expecting mdia\n");
1116 return false;
1117 }
1118 size_remaining-=sub_chunk_len;
1119 j=sub_chunk_len-8;
1120
1121 while (j > 0) {
1122 n=read_uint32be(fd,&sub_chunk_len);
1123 n=read(fd,&sub_chunk_id,4);
1124 j-=4;
1125 if (memcmp(&sub_chunk_id,"minf",4)==0) {
1126 j=sub_chunk_len-8;
1127 } else if (memcmp(&sub_chunk_id,"stbl",4)==0) {
1128 j=sub_chunk_len-8;
1129 } else if (memcmp(&sub_chunk_id,"stsd",4)==0) {
1130 n=read(fd,buf,sub_chunk_len-8);
1131 j-=sub_chunk_len;
1132 i=0;
1133 /* Skip version and flags */
1134 i+=4;
1135
1136 numentries=(buf[i]<<24)|(buf[i+1]<<16)|(buf[i+2]<<8)|buf[i+3];
1137 i+=4;
1138 if (numentries!=1) {
1139 logf("ERROR: Expecting only one entry in stsd\n");
1140 }
1141
1142 entry_size=(buf[i]<<24)|(buf[i+1]<<16)|(buf[i+2]<<8)|buf[i+3];
1143 i+=4;
1144
1145 /* Check the codec type - 'alac' for ALAC, 'mp4a' for AAC */
1146 if (memcmp(&buf[i],"alac",4)!=0) {
1147 logf("Not an ALAC file\n");
1148 return false;
1149 }
1150
1151 //numchannels=(buf[i+20]<<8)|buf[i+21]; /* Not used - assume Stereo */
1152 //samplesize=(buf[i+22]<<8)|buf[i+23]; /* Not used - assume 16-bit */
1153
1154 /* Samplerate is 32-bit fixed point, but this works for < 65536 Hz */
1155 id3->frequency=(buf[i+28]<<8)|buf[i+29];
1156 } else if (memcmp(&sub_chunk_id,"stts",4)==0) {
1157 j-=sub_chunk_len;
1158 i=8;
1159 n=read(fd,buf,8);
1160 i+=8;
1161 numentries=(buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7];
1162 for (k=0;k<numentries;k++) {
1163 n=read_uint32be(fd,&sample_count);
1164 n=read_uint32be(fd,&sample_duration);
1165 totalsamples+=sample_count*sample_duration;
1166 i+=8;
1167 }
1168 if (i > 0) lseek(fd, sub_chunk_len - i, SEEK_CUR);
1169 } else if (memcmp(&sub_chunk_id,"stsz",4)==0) {
1170 j-=sub_chunk_len;
1171 i=8;
1172 n=read(fd,buf,8);
1173 i+=8;
1174 numentries=(buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7];
1175 for (k=0;k<numentries;k++) {
1176 n=read_uint32be(fd,&sample_count);
1177 n=read_uint32be(fd,&sample_duration);
1178 totalsamples+=sample_count*sample_duration;
1179 i+=8;
1180 }
1181 if (i > 0) lseek(fd, sub_chunk_len - i, SEEK_CUR);
1182 } else {
1183 lseek(fd, sub_chunk_len - 8, SEEK_CUR); /* FIXME not 8 */
1184 j-=sub_chunk_len;
1185 }
1186 }
1187 } else {
1188 logf("Unexpected sub_chunk_id inside moov: %c%c%c%c\n",
1189 sub_chunk_id[0],sub_chunk_id[1],sub_chunk_id[2],sub_chunk_id[3]);
1190 return false;
1191 }
1192 }
1193 } else if (memcmp(&chunk_id,"mdat",4)==0) {
1194 /* once we hit mdat we stop reading and return.
1195 * this is on the assumption that there is no furhter interesting
1196 * stuff in the stream. if there is stuff will fail (:()).
1197 * But we need the read pointer to be at the mdat stuff
1198 * for the decoder. And we don't want to rely on fseek/ftell,
1199 * as they may not always be avilable */
1200 lseek(fd, chunk_len - 8, SEEK_CUR); /* FIXME not 8 */
1201 compressedsize=chunk_len-8;
1202 } else if (memcmp(&chunk_id,"free",4)==0) {
1203 /* these following atoms can be skipped !!!! */
1204 lseek(fd, chunk_len - 8, SEEK_CUR); /* FIXME not 8 */
1205 } else {
1206 logf("(top) unknown chunk id: %c%c%c%c\n", chunk_id[0],chunk_id[1],chunk_id[2],chunk_id[3]);
1207 return false;
1208 }
1209 }
1210
1211 id3->vbr=true; /* All ALAC files are VBR */
1212 id3->filesize=filesize(fd);
1213 id3->samples=totalsamples;
1214 id3->length=(10*totalsamples)/(id3->frequency/100);
1215 id3->bitrate=(compressedsize*8)/id3->length;;
1216
1217 return true;
1218}
1219
890/* Simple file type probing by looking at the filename extension. */ 1220/* Simple file type probing by looking at the filename extension. */
891unsigned int probe_file_format(const char *filename) 1221unsigned int probe_file_format(const char *filename)
892{ 1222{
@@ -1064,6 +1394,14 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
1064 track->id3.length = (totalsamples / track->id3.frequency) * 1000; 1394 track->id3.length = (totalsamples / track->id3.frequency) * 1000;
1065 break; 1395 break;
1066 1396
1397 case AFMT_ALAC:
1398 if (!get_alac_metadata(fd, &(track->id3)))
1399 {
1400// return false;
1401 }
1402
1403 break;
1404
1067 /* If we don't know how to read the metadata, just store the filename */ 1405 /* If we don't know how to read the metadata, just store the filename */
1068 default: 1406 default:
1069 break; 1407 break;