Wrap up version 1.3.3.
[minidlna.git] / tagutils / tagutils-dsf.c
blob1441356c553ca700c2fb8226f315e03f81b14505
1 //=========================================================================
2 // FILENAME : tagutils-dsf.c
3 // DESCRIPTION : DSF metadata reader
4 //=========================================================================
5 // Copyright (c) 2014 Takeshich NAKAMURA
6 // based on tagutils-mp3.c
7 //=========================================================================
9 /*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #define GET_DSF_INT64(p) ((((uint64_t)((p)[7])) << 56) | \
25 (((uint64_t)((p)[6])) << 48) | \
26 (((uint64_t)((p)[5])) << 40) | \
27 (((uint64_t)((p)[4])) << 32) | \
28 (((uint64_t)((p)[3])) << 24) | \
29 (((uint64_t)((p)[2])) << 16) | \
30 (((uint64_t)((p)[1])) << 8) | \
31 (((uint64_t)((p)[0]))))
33 #define GET_DSF_INT32(p) ((((uint8_t)((p)[3])) << 24) | \
34 (((uint8_t)((p)[2])) << 16) | \
35 (((uint8_t)((p)[1])) << 8) | \
36 (((uint8_t)((p)[0]))))
38 static int
39 _get_dsftags(char *file, struct song_metadata *psong)
41 struct id3_tag *pid3tag;
42 struct id3_frame *pid3frame;
43 int err;
44 int index;
45 int used;
46 unsigned char *utf8_text;
47 int genre = WINAMP_GENRE_UNKNOWN;
48 int have_utf8;
49 int have_text;
50 id3_ucs4_t const *native_text;
51 char *tmp;
52 int got_numeric_genre;
53 id3_byte_t const *image;
54 id3_length_t image_size = 0;
56 FILE *fp;
57 struct id3header *pid3;
58 uint32_t len;
59 unsigned char hdr[28] = { 0 };
60 uint64_t total_size = 0;
61 uint64_t pointer_to_metadata_chunk = 0;
62 uint64_t metadata_chunk_size = 0;
63 unsigned char *id3tagbuf = NULL;
65 //DEBUG DPRINTF(E_DEBUG,L_SCANNER,"Getting DSF file info\n");
67 if ((fp = fopen(file, "rb")) == NULL)
69 DPRINTF(E_WARN, L_SCANNER, "Could not create file handle\n");
70 return -1;
73 len = 28;
74 if (!(len = fread(hdr, len, 1, fp)))
76 DPRINTF(E_WARN, L_SCANNER, "Could not read DSD Chunk from %s\n", file);
77 fclose(fp);
78 return -1;
81 if (strncmp((char*)hdr, "DSD ", 4))
83 DPRINTF(E_WARN, L_SCANNER, "Invalid DSD Chunk header in %s\n", file);
84 fclose(fp);
85 return -1;
88 total_size = GET_DSF_INT64(hdr + 12);
89 pointer_to_metadata_chunk = GET_DSF_INT64(hdr + 20);
91 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", total_size);
92 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", pointer_to_metadata_chunk);
93 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", metadata_chunk_size);
95 //check invalid metadata
96 if (total_size == 0)
98 fclose(fp);
99 DPRINTF(E_INFO, L_SCANNER, "Invalid TotalDataSize in %s\n", file);
100 return 0;
103 if (pointer_to_metadata_chunk == 0)
105 fclose(fp);
106 DPRINTF(E_INFO, L_SCANNER, "Metadata doesn't exist %s\n", file);
107 return 0;
110 if (total_size > pointer_to_metadata_chunk)
112 metadata_chunk_size = total_size - pointer_to_metadata_chunk;
114 else
116 fclose(fp);
117 DPRINTF(E_INFO, L_SCANNER, "Invalid PointerToMetadata in %s\n", file);
118 return 0;
121 fseeko(fp, pointer_to_metadata_chunk, SEEK_SET);
123 id3tagbuf = (unsigned char*)malloc(sizeof(unsigned char) * metadata_chunk_size);
124 if (id3tagbuf == NULL)
126 fclose(fp);
127 DPRINTF(E_WARN, L_SCANNER, "Out of memory.Big MetadataSize in %s\n", file);
128 return -1;
130 memset(id3tagbuf, 0, sizeof(unsigned char) * metadata_chunk_size);
132 if (!(len = fread(id3tagbuf, metadata_chunk_size, 1, fp)))
134 fclose(fp);
135 free(id3tagbuf);
136 DPRINTF(E_WARN, L_SCANNER, "Could not read Metadata Chunk from %s\n", file);
137 return -1;
140 pid3tag = id3_tag_parse(id3tagbuf, metadata_chunk_size);
142 if (!pid3tag)
144 fclose(fp);
145 free(id3tagbuf);
146 err = errno;
147 errno = err;
148 DPRINTF(E_WARN, L_SCANNER, "Cannot get ID3 tag for %s\n", file);
149 return -1;
152 pid3 = (struct id3header*)id3tagbuf;
154 if (strncmp((char*)pid3->id, "ID3", 3) == 0)
156 char tagversion[16];
158 /* found an ID3 header... */
159 snprintf(tagversion, sizeof(tagversion), "ID3v2.%d.%d",
160 pid3->version[0], pid3->version[1]);
161 psong->tagversion = strdup(tagversion);
163 pid3 = NULL;
165 index = 0;
166 while ((pid3frame = id3_tag_findframe(pid3tag, "", index)))
168 used = 0;
169 utf8_text = NULL;
170 native_text = NULL;
171 have_utf8 = 0;
172 have_text = 0;
174 if (!strcmp(pid3frame->id, "YTCP")) /* for id3v2.2 */
176 psong->compilation = 1;
177 DPRINTF(E_DEBUG, L_SCANNER, "Compilation: %d [%s]\n", psong->compilation, basename(file));
179 else if (!strcmp(pid3frame->id, "APIC") && !image_size)
181 if ((strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpeg") == 0) ||
182 (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpg") == 0) ||
183 (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "jpeg") == 0))
185 image = id3_field_getbinarydata(&pid3frame->fields[4], &image_size);
186 if (image_size)
188 psong->image = malloc(image_size);
189 memcpy(psong->image, image, image_size);
190 psong->image_size = image_size;
191 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Found thumbnail: %d\n", psong->image_size);
196 if (((pid3frame->id[0] == 'T') || (strcmp(pid3frame->id, "COMM") == 0)) &&
197 (id3_field_getnstrings(&pid3frame->fields[1])))
198 have_text = 1;
200 if (have_text)
202 native_text = id3_field_getstrings(&pid3frame->fields[1], 0);
204 if (native_text)
206 have_utf8 = 1;
207 if (lang_index >= 0)
208 utf8_text = _get_utf8_text(native_text); // through iconv
209 else
210 utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
212 if (!strcmp(pid3frame->id, "TIT2"))
214 used = 1;
215 psong->title = (char*)utf8_text;
217 else if (!strcmp(pid3frame->id, "TPE1"))
219 used = 1;
220 psong->contributor[ROLE_ARTIST] = (char*)utf8_text;
222 else if (!strcmp(pid3frame->id, "TALB"))
224 used = 1;
225 psong->album = (char*)utf8_text;
227 else if (!strcmp(pid3frame->id, "TCOM"))
229 used = 1;
230 psong->contributor[ROLE_COMPOSER] = (char*)utf8_text;
232 else if (!strcmp(pid3frame->id, "TIT1"))
234 used = 1;
235 psong->grouping = (char*)utf8_text;
237 else if (!strcmp(pid3frame->id, "TPE2"))
239 used = 1;
240 psong->contributor[ROLE_BAND] = (char*)utf8_text;
242 else if (!strcmp(pid3frame->id, "TPE3"))
244 used = 1;
245 psong->contributor[ROLE_CONDUCTOR] = (char*)utf8_text;
247 else if (!strcmp(pid3frame->id, "TCON"))
249 used = 1;
250 psong->genre = (char*)utf8_text;
251 got_numeric_genre = 0;
252 if (psong->genre)
254 if (!strlen(psong->genre))
256 genre = WINAMP_GENRE_UNKNOWN;
257 got_numeric_genre = 1;
259 else if (isdigit(psong->genre[0]))
261 genre = atoi(psong->genre);
262 got_numeric_genre = 1;
264 else if ((psong->genre[0] == '(') && (isdigit(psong->genre[1])))
266 genre = atoi((char*)&psong->genre[1]);
267 got_numeric_genre = 1;
270 if (got_numeric_genre)
272 if ((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
273 genre = WINAMP_GENRE_UNKNOWN;
274 free(psong->genre);
275 psong->genre = strdup(winamp_genre[genre]);
279 else if (!strcmp(pid3frame->id, "COMM"))
281 used = 1;
282 psong->comment = (char*)utf8_text;
284 else if (!strcmp(pid3frame->id, "TPOS"))
286 tmp = (char*)utf8_text;
287 strsep(&tmp, "/");
288 if (tmp)
290 psong->total_discs = atoi(tmp);
292 psong->disc = atoi((char*)utf8_text);
294 else if (!strcmp(pid3frame->id, "TRCK"))
296 tmp = (char*)utf8_text;
297 strsep(&tmp, "/");
298 if (tmp)
300 psong->total_tracks = atoi(tmp);
302 psong->track = atoi((char*)utf8_text);
304 else if (!strcmp(pid3frame->id, "TDRC"))
306 psong->year = atoi((char*)utf8_text);
308 else if (!strcmp(pid3frame->id, "TLEN"))
310 psong->song_length = atoi((char*)utf8_text);
312 else if (!strcmp(pid3frame->id, "TBPM"))
314 psong->bpm = atoi((char*)utf8_text);
316 else if (!strcmp(pid3frame->id, "TCMP"))
318 psong->compilation = (char)atoi((char*)utf8_text);
323 // check if text tag
324 if ((!used) && (have_utf8) && (utf8_text))
325 free(utf8_text);
327 // v2 COMM
328 if ((!strcmp(pid3frame->id, "COMM")) && (pid3frame->nfields == 4))
330 native_text = id3_field_getstring(&pid3frame->fields[2]);
331 if (native_text)
333 utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
334 if ((utf8_text) && (strncasecmp((char*)utf8_text, "iTun", 4) != 0))
336 // read comment
337 free(utf8_text);
339 native_text = id3_field_getfullstring(&pid3frame->fields[3]);
340 if (native_text)
342 utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
343 if (utf8_text)
345 free(psong->comment);
346 psong->comment = (char*)utf8_text;
350 else
352 free(utf8_text);
357 index++;
360 id3_tag_delete(pid3tag);
361 free(id3tagbuf);
362 fclose(fp);
363 //DPRINTF(E_DEBUG, L_SCANNER, "Got id3tag successfully for file=%s\n", file);
364 return 0;
367 static int
368 _get_dsffileinfo(char *file, struct song_metadata *psong)
370 FILE *fp;
371 int len = 80;
372 unsigned char hdr[len];
373 uint32_t channelnum;
374 uint32_t samplingfrequency;
375 uint32_t bitpersample;
376 uint64_t samplecount;
378 if ((fp = fopen(file, "rb")) == NULL)
380 DPRINTF(E_WARN, L_SCANNER, "Could not create file handle\n");
381 return -1;
384 if (!(len = fread(hdr, len, 1, fp)))
386 DPRINTF(E_WARN, L_SCANNER, "Could not read chunks from %s\n", file);
387 fclose(fp);
388 return -1;
391 if (strncmp((char*)hdr, "DSD ", 4))
393 DPRINTF(E_WARN, L_SCANNER, "Invalid DSD Chunk headerin %s\n", file);
394 fclose(fp);
395 return -1;
398 if (strncmp((char*)hdr + 28, "fmt ", 4))
400 DPRINTF(E_WARN, L_SCANNER, "Invalid fmt Chunk header in %s\n", file);
401 fclose(fp);
402 return -1;
405 channelnum = GET_DSF_INT32(hdr + 52);
406 samplingfrequency = GET_DSF_INT32(hdr + 56);
407 bitpersample = GET_DSF_INT32(hdr + 60);
408 samplecount = GET_DSF_INT64(hdr + 64);
410 psong->bitrate = channelnum * samplingfrequency * bitpersample;
411 psong->samplesize = bitpersample;
412 psong->samplerate = samplingfrequency;
413 psong->song_length = (samplecount / samplingfrequency) * 1000;
414 psong->channels = channelnum;
416 DPRINTF(E_MAXDEBUG, L_SCANNER, "Got file info successfully for %s\n", file);
417 //DEBUG DPRINTF(E_MAXDEBUG, L_SCANNER, "bitrate is %d\n", psong->bitrate);
418 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplesize is %d\n", psong->samplesize);
419 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplerate is %d\n", psong->samplerate);
420 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "song_length is %d\n", psong->song_length);
421 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "channels are %d\n", psong->channels);
422 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplecount are %lld\n", samplecount);
423 fclose(fp);
425 xasprintf(&(psong->dlna_pn), "DSF");
426 return 0;