39 {
40 $info = &$this->getid3->info;
41
42 $offset = 0;
43 fseek($this->getid3->fp,
$info[
'avdataoffset'], SEEK_SET);
44 $rawdata =
fread($this->getid3->fp, $this->getid3->fread_buffer_size());
45
46 switch (substr($rawdata, $offset, 4)) {
47 case 'LA02':
48 case 'LA03':
49 case 'LA04':
50 $info[
'fileformat'] =
'la';
51 $info[
'audio'][
'dataformat'] =
'la';
52 $info[
'audio'][
'lossless'] =
true;
53
54 $info[
'la'][
'version_major'] = (int) substr($rawdata, $offset + 2, 1);
55 $info[
'la'][
'version_minor'] = (int) substr($rawdata, $offset + 3, 1);
56 $info[
'la'][
'version'] = (float)
$info[
'la'][
'version_major'] + (
$info[
'la'][
'version_minor'] / 10);
57 $offset += 4;
58
60 $offset += 4;
61 if (
$info[
'la'][
'uncompressed_size'] == 0) {
62 $info[
'error'][] =
'Corrupt LA file: uncompressed_size == zero';
63
64 return false;
65 }
66
67 $WAVEchunk = substr($rawdata, $offset, 4);
68 if ($WAVEchunk !== 'WAVE') {
69 $info[
'error'][] =
'Expected "WAVE" ('.Helper::PrintHexBytes(
'WAVE').
') at offset '.$offset.
', found "'.$WAVEchunk.
'" ('.
Helper::PrintHexBytes($WAVEchunk).
') instead.';
70
71 return false;
72 }
73 $offset += 4;
74
75 $info[
'la'][
'fmt_size'] = 24;
76 if (
$info[
'la'][
'version'] >= 0.3) {
77
79 $info[
'la'][
'header_size'] = 49 +
$info[
'la'][
'fmt_size'] - 24;
80 $offset += 4;
81
82 } else {
83
84
85 $info[
'la'][
'header_size'] = 41;
86
87 }
88
89 $fmt_chunk = substr($rawdata, $offset, 4);
90 if ($fmt_chunk !== 'fmt ') {
91 $info[
'error'][] =
'Expected "fmt " ('.Helper::PrintHexBytes(
'fmt ').
') at offset '.$offset.
', found "'.$fmt_chunk.
'" ('.
Helper::PrintHexBytes($fmt_chunk).
') instead.';
92
93 return false;
94 }
95 $offset += 4;
97 $offset += 4;
98
100 $offset += 2;
101
103 $offset += 2;
104 if (
$info[
'la'][
'channels'] == 0) {
105 $info[
'error'][] =
'Corrupt LA file: channels == zero';
106
107 return false;
108 }
109
111 $offset += 4;
112 if (
$info[
'la'][
'sample_rate'] == 0) {
113 $info[
'error'][] =
'Corrupt LA file: sample_rate == zero';
114
115 return false;
116 }
117
119 $offset += 4;
121 $offset += 2;
123 $offset += 2;
124
126 $offset += 4;
127
129 $offset += 1;
130 $info[
'la'][
'flags'][
'seekable'] = (bool) (
$info[
'la'][
'raw'][
'flags'] & 0x01);
131 if (
$info[
'la'][
'version'] >= 0.4) {
132 $info[
'la'][
'flags'][
'high_compression'] = (bool) (
$info[
'la'][
'raw'][
'flags'] & 0x02);
133 }
134
136 $offset += 4;
137
138
139
140
141
142
143
144 if (
$info[
'la'][
'version'] >= 0.4) {
145 $info[
'la'][
'blocksize'] = 61440;
146 $info[
'la'][
'seekevery'] = 19;
147 } else {
148 $info[
'la'][
'blocksize'] = 73728;
149 $info[
'la'][
'seekevery'] = 16;
150 }
151
152 $info[
'la'][
'seekpoint_count'] = 0;
153 if (
$info[
'la'][
'flags'][
'seekable']) {
154 $info[
'la'][
'seekpoint_count'] = floor(
$info[
'la'][
'samples'] / (
$info[
'la'][
'blocksize'] *
$info[
'la'][
'seekevery']));
155
156 for ($i = 0; $i <
$info[
'la'][
'seekpoint_count']; $i++) {
158 $offset += 4;
159 }
160 }
161
162 if (
$info[
'la'][
'version'] >= 0.3) {
163
164
165
166
168 $offset += 4;
169
170 if (
$info[
'la'][
'footerstart'] >
$info[
'filesize']) {
171 $info[
'warning'][] =
'FooterStart value points to offset '.$info[
'la'][
'footerstart'].
' which is beyond end-of-file ('.
$info[
'filesize'].
')';
172 $info[
'la'][
'footerstart'] =
$info[
'filesize'];
173 }
174
175 } else {
176
177
178 $info[
'la'][
'footerstart'] =
$info[
'avdataend'];
179
180 }
181
182 if (
$info[
'la'][
'footerstart'] <
$info[
'avdataend']) {
184 if ($RIFF_fp = fopen($RIFFtempfilename, 'w+b')) {
185 $RIFFdata = 'WAVE';
186 if (
$info[
'la'][
'version'] == 0.2) {
187 $RIFFdata .= substr($rawdata, 12, 24);
188 } else {
189 $RIFFdata .= substr($rawdata, 16, 24);
190 }
191 if (
$info[
'la'][
'footerstart'] <
$info[
'avdataend']) {
192 fseek($this->getid3->fp,
$info[
'la'][
'footerstart'], SEEK_SET);
193 $RIFFdata .=
fread($this->getid3->fp,
$info[
'avdataend'] -
$info[
'la'][
'footerstart']);
194 }
195 $RIFFdata = 'RIFF'.Helper::LittleEndian2String(strlen($RIFFdata), 4, false).$RIFFdata;
196 fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata));
197 fclose($RIFF_fp);
198
199 $getid3_temp = new GetId3Core();
200 $getid3_temp->openfile($RIFFtempfilename);
201 $getid3_riff = new Riff($getid3_temp);
202 $getid3_riff->analyze();
203
204 if (empty($getid3_temp->info['error'])) {
205 $info[
'riff'] = $getid3_temp->info[
'riff'];
206 } else {
207 $info[
'warning'][] =
'Error parsing RIFF portion of La file: '.implode($getid3_temp->info[
'error']);
208 }
209 unset($getid3_temp, $getid3_riff);
210 }
211 unlink($RIFFtempfilename);
212 }
213 }
214
215
216 $info[
'avdataend'] =
$info[
'avdataoffset'] +
$info[
'la'][
'footerstart'];
217 $info[
'avdataoffset'] =
$info[
'avdataoffset'] + $offset;
218
219
220 $info[
'la'][
'compression_ratio'] = (float) ((
$info[
'avdataend'] -
$info[
'avdataoffset']) /
$info[
'la'][
'uncompressed_size']);
221 $info[
'playtime_seconds'] = (float) (
$info[
'la'][
'samples'] /
$info[
'la'][
'sample_rate']) /
$info[
'la'][
'channels'];
222 if (
$info[
'playtime_seconds'] == 0) {
223 $info[
'error'][] =
'Corrupt LA file: playtime_seconds == zero';
224
225 return false;
226 }
227
228 $info[
'audio'][
'bitrate'] = (
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8 /
$info[
'playtime_seconds'];
229
230 $info[
'audio'][
'bits_per_sample'] =
$info[
'la'][
'bits_per_sample'];
231 break;
232
233 default:
234 if (substr($rawdata, $offset, 2) == 'LA') {
235 $info[
'error'][] =
'This version of GetId3Core() ['.$this->getid3->version().
'] does not support LA version '.substr($rawdata, $offset + 2, 1).
'.'.substr($rawdata, $offset + 3, 1).
' which this appears to be - check http://getid3.sourceforge.net for updates.';
236 } else {
237 $info[
'error'][] =
'Not a LA (Lossless-Audio) file';
238 }
239
240 return false;
241 break;
242 }
243
244 $info[
'audio'][
'channels'] =
$info[
'la'][
'channels'];
245 $info[
'audio'][
'sample_rate'] = (int)
$info[
'la'][
'sample_rate'];
246 $info[
'audio'][
'encoder'] =
'LA v'.$info[
'la'][
'version'];
247
248 return true;
249 }
fseek($bytes, $whence=SEEK_SET)
static LittleEndian2Int($byteword, $signed=false)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')