summaryrefslogtreecommitdiff
path: root/lib/rbcodec/metadata/mp3.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/metadata/mp3.c')
-rw-r--r--lib/rbcodec/metadata/mp3.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/lib/rbcodec/metadata/mp3.c b/lib/rbcodec/metadata/mp3.c
new file mode 100644
index 0000000000..feb1a52f77
--- /dev/null
+++ b/lib/rbcodec/metadata/mp3.c
@@ -0,0 +1,193 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21/*
22 * Parts of this code has been stolen from the Ample project and was written
23 * by David H�deman. It has since been extended and enhanced pretty much by
24 * all sorts of friendly Rockbox people.
25 *
26 */
27
28 /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <stdbool.h>
35#include "string-extra.h"
36#include "config.h"
37#include "file.h"
38#include "logf.h"
39
40#include "system.h"
41#include "metadata.h"
42#include "mp3data.h"
43#include "metadata_common.h"
44#include "metadata_parsers.h"
45
46/*
47 * Calculates the length (in milliseconds) of an MP3 file.
48 *
49 * Modified to only use integers.
50 *
51 * Arguments: file - the file to calculate the length upon
52 * entry - the entry to update with the length
53 *
54 * Returns: the song length in milliseconds,
55 * 0 means that it couldn't be calculated
56 */
57static int getsonglength(int fd, struct mp3entry *entry)
58{
59 unsigned long filetime = 0;
60 struct mp3info info;
61 long bytecount;
62
63 /* Start searching after ID3v2 header */
64 if(-1 == lseek(fd, entry->id3v2len, SEEK_SET))
65 return 0;
66
67 bytecount = get_mp3file_info(fd, &info);
68
69 logf("Space between ID3V2 tag and first audio frame: 0x%lx bytes",
70 bytecount);
71
72 if(bytecount < 0)
73 return -1;
74
75 bytecount += entry->id3v2len;
76
77 /* Validate byte count, in case the file has been edited without
78 * updating the header.
79 */
80 if (info.byte_count)
81 {
82 const unsigned long expected = entry->filesize - entry->id3v1len
83 - entry->id3v2len;
84 const unsigned long diff = MAX(10240, info.byte_count / 20);
85
86 if ((info.byte_count > expected + diff)
87 || (info.byte_count < expected - diff))
88 {
89 logf("Note: info.byte_count differs from expected value by "
90 "%ld bytes", labs((long) (expected - info.byte_count)));
91 info.byte_count = 0;
92 info.frame_count = 0;
93 info.file_time = 0;
94 info.enc_padding = 0;
95
96 /* Even if the bitrate was based on "known bad" values, it
97 * should still be better for VBR files than using the bitrate
98 * of the first audio frame.
99 */
100 }
101 }
102
103 entry->bitrate = info.bitrate;
104 entry->frequency = info.frequency;
105 entry->layer = info.layer;
106 switch(entry->layer) {
107#if CONFIG_CODEC==SWCODEC
108 case 0:
109 entry->codectype=AFMT_MPA_L1;
110 break;
111#endif
112 case 1:
113 entry->codectype=AFMT_MPA_L2;
114 break;
115 case 2:
116 entry->codectype=AFMT_MPA_L3;
117 break;
118 }
119
120 /* If the file time hasn't been established, this may be a fixed
121 rate MP3, so just use the default formula */
122
123 filetime = info.file_time;
124
125 if(filetime == 0)
126 {
127 /* Prevent a division by zero */
128 if (info.bitrate < 8)
129 filetime = 0;
130 else
131 filetime = (entry->filesize - bytecount) / (info.bitrate / 8);
132 /* bitrate is in kbps so this delivers milliseconds. Doing bitrate / 8
133 * instead of filesize * 8 is exact, because mpeg audio bitrates are
134 * always multiples of 8, and it avoids overflows. */
135 }
136
137 entry->frame_count = info.frame_count;
138
139 entry->vbr = info.is_vbr;
140 entry->has_toc = info.has_toc;
141
142#if CONFIG_CODEC==SWCODEC
143 if (!entry->lead_trim)
144 entry->lead_trim = info.enc_delay;
145 if (!entry->tail_trim)
146 entry->tail_trim = info.enc_padding;
147#endif
148
149 memcpy(entry->toc, info.toc, sizeof(info.toc));
150
151 /* Update the seek point for the first playable frame */
152 entry->first_frame_offset = bytecount;
153 logf("First frame is at %lx", entry->first_frame_offset);
154
155 return filetime;
156}
157
158/*
159 * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc)
160 * about an MP3 file and updates it's entry accordingly.
161 *
162 Note, that this returns true for successful, false for error! */
163bool get_mp3_metadata(int fd, struct mp3entry *entry)
164{
165 entry->title = NULL;
166 entry->filesize = filesize(fd);
167 entry->id3v2len = getid3v2len(fd);
168 entry->tracknum = 0;
169 entry->discnum = 0;
170
171 if (entry->id3v2len)
172 setid3v2title(fd, entry);
173 int len = getsonglength(fd, entry);
174 if (len < 0)
175 return false;
176 entry->length = len;
177
178 /* Subtract the meta information from the file size to get
179 the true size of the MP3 stream */
180 entry->filesize -= entry->first_frame_offset;
181
182 /* only seek to end of file if no id3v2 tags were found */
183 if (!entry->id3v2len) {
184 setid3v1title(fd, entry);
185 }
186
187 if(!entry->length || (entry->filesize < 8 ))
188 /* no song length or less than 8 bytes is hereby considered to be an
189 invalid mp3 and won't be played by us! */
190 return false;
191
192 return true;
193}