ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
module.audio-video.riff.php
Go to the documentation of this file.
1 <?php
4 // available at http://getid3.sourceforge.net //
5 // or http://www.getid3.org //
7 // See readme.txt for more details //
9 // //
10 // module.audio-video.riff.php //
11 // module for analyzing RIFF files //
12 // multiple formats supported by this module: //
13 // Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX //
14 // dependencies: module.audio.mp3.php //
15 // module.audio.ac3.php (optional) //
16 // ///
18 
19 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
20 
22 {
23 
24  function getid3_riff(&$fd, &$ThisFileInfo) {
25 
26  // initialize these values to an empty array, otherwise they default to NULL
27  // and you can't append array values to a NULL value
28  $ThisFileInfo['riff'] = array('raw'=>array());
29 
30  // Shortcuts
31  $thisfile_riff = &$ThisFileInfo['riff'];
32  $thisfile_riff_raw = &$thisfile_riff['raw'];
33  $thisfile_audio = &$ThisFileInfo['audio'];
34  $thisfile_video = &$ThisFileInfo['video'];
35  $thisfile_avdataoffset = &$ThisFileInfo['avdataoffset'];
36  $thisfile_avdataend = &$ThisFileInfo['avdataend'];
37  $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
38  $thisfile_riff_audio = &$thisfile_riff['audio'];
39  $thisfile_riff_video = &$thisfile_riff['video'];
40 
41 
42  $Original['avdataoffset'] = $thisfile_avdataoffset;
43  $Original['avdataend'] = $thisfile_avdataend;
44 
45  fseek($fd, $thisfile_avdataoffset, SEEK_SET);
46  $RIFFheader = fread($fd, 12);
47  $RIFFsubtype = substr($RIFFheader, 8, 4);
48  switch (substr($RIFFheader, 0, 4)) {
49  case 'FORM':
50  $ThisFileInfo['fileformat'] = 'aiff';
51  $RIFFheaderSize = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
52  $thisfile_riff[$RIFFsubtype] = getid3_riff::ParseRIFF($fd, $thisfile_avdataoffset + 12, $thisfile_avdataoffset + $RIFFheaderSize, $ThisFileInfo);
53  $thisfile_riff['header_size'] = $RIFFheaderSize;
54  break;
55 
56  case 'RIFF':
57  case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
58  case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
59  if ($RIFFsubtype == 'RMP3') {
60  // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
61  $RIFFsubtype = 'WAVE';
62  }
63 
64  $ThisFileInfo['fileformat'] = 'riff';
65  $RIFFheaderSize = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
66  $thisfile_riff[$RIFFsubtype] = getid3_riff::ParseRIFF($fd, $thisfile_avdataoffset + 12, $thisfile_avdataoffset + $RIFFheaderSize, $ThisFileInfo);
67  $thisfile_riff['header_size'] = $RIFFheaderSize;
68  if ($RIFFsubtype == 'WAVE') {
69  $thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
70  }
71  break;
72 
73  default:
74  $ThisFileInfo['error'][] = 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead';
75  unset($ThisFileInfo['fileformat']);
76  return false;
77  break;
78  }
79 
80  $streamindex = 0;
81  switch ($RIFFsubtype) {
82  case 'WAVE':
83  if (empty($thisfile_audio['bitrate_mode'])) {
84  $thisfile_audio['bitrate_mode'] = 'cbr';
85  }
86  if (empty($thisfile_audio_dataformat)) {
87  $thisfile_audio_dataformat = 'wav';
88  }
89 
90  if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
91  $thisfile_avdataoffset = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
92  $thisfile_avdataend = $thisfile_avdataoffset + $thisfile_riff_WAVE['data'][0]['size'];
93  }
94  if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
95 
96  $thisfile_riff_audio[$streamindex] = getid3_riff::RIFFparseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
97  $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
98  if (@$thisfile_riff_audio[$streamindex]['bitrate'] == 0) {
99  $ThisFileInfo['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
100  return false;
101  }
102  $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
103  unset($thisfile_riff_audio[$streamindex]['raw']);
104  $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
105 
106  $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
107  if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
108  $ThisFileInfo['warning'][] = 'Audio codec = '.$thisfile_audio['codec'];
109  }
110  $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
111 
112  $ThisFileInfo['playtime_seconds'] = (float) ((($thisfile_avdataend - $thisfile_avdataoffset) * 8) / $thisfile_audio['bitrate']);
113 
114  $thisfile_audio['lossless'] = false;
115  if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
116  switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
117 
118  case 0x0001: // PCM
119  $thisfile_audio['lossless'] = true;
120  break;
121 
122  case 0x2000: // AC-3
123  $thisfile_audio_dataformat = 'ac3';
124  break;
125 
126  default:
127  // do nothing
128  break;
129 
130  }
131  }
132  $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
133  $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
134  $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless'];
135  $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat;
136  }
137 
138  if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
139 
140  // shortcuts
141  $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data'];
142  $thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array());
143  $thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad'];
144  $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track'];
145  $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album'];
146 
147  $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4));
148  $thisfile_riff_raw_rgad['nRadioRgAdjust'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($rgadData, 4, 2));
149  $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($rgadData, 6, 2));
150 
151  $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
152  $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
153  $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
154  $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
155  $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
156  $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
157  $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
158  $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
159  $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
160  $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
161 
162  $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
163  if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) {
164  $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
165  $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
166  $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
167  }
168  if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) {
169  $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
170  $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
171  $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
172  }
173  }
174 
175  if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
176  $thisfile_riff_raw['fact']['NumberOfSamples'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
177 
178  // This should be a good way of calculating exact playtime,
179  // but some sample files have had incorrect number of samples,
180  // so cannot use this method
181 
182  // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
183  // $ThisFileInfo['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
184  // }
185  }
186  if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
187  $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
188  }
189 
190  if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
191  // shortcut
192  $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
193 
194  $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
195  $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
196  $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
197  $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
198  $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
199  $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
200  $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1));
201  $thisfile_riff_WAVE_bext_0['reserved'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 347, 254));
202  $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
203 
204  $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime(
205  substr($thisfile_riff_WAVE_bext_0['origin_time'], 0, 2),
206  substr($thisfile_riff_WAVE_bext_0['origin_time'], 3, 2),
207  substr($thisfile_riff_WAVE_bext_0['origin_time'], 6, 2),
208  substr($thisfile_riff_WAVE_bext_0['origin_date'], 5, 2),
209  substr($thisfile_riff_WAVE_bext_0['origin_date'], 8, 2),
210  substr($thisfile_riff_WAVE_bext_0['origin_date'], 0, 4));
211 
212  $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
213  $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
214  }
215 
216  if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
217  // shortcut
218  $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0];
219 
220  $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
221  $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001);
222  if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
223  $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true;
224  $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004);
225  $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008);
226 
227  $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
228  }
229  $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
230  $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
231  $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001);
232  $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002);
233  $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004);
234  }
235 
236  if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
237  // shortcut
238  $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0];
239 
240  $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4);
241  $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64));
242  $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64));
243  $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
244  $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
245  $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
246  $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
247  $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
248  $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
249  $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8));
250  $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
251  $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8));
252  $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
253  $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
254  $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
255  $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true);
256  for ($i = 0; $i < 8; $i++) {
257  $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4);
258  $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8) + 4, 4));
259  }
260  $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
261  $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
262 
263  $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
264  $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
265  }
266 
267  if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
268  $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
269  $ThisFileInfo['playtime_seconds'] = (float) ((($thisfile_avdataend - $thisfile_avdataoffset) * 8) / $thisfile_audio['bitrate']);
270  }
271 
272  if (!empty($ThisFileInfo['wavpack'])) {
273  $thisfile_audio_dataformat = 'wavpack';
274  $thisfile_audio['bitrate_mode'] = 'vbr';
275  $thisfile_audio['encoder'] = 'WavPack v'.$ThisFileInfo['wavpack']['version'];
276 
277  // Reset to the way it was - RIFF parsing will have messed this up
278  $thisfile_avdataend = $Original['avdataend'];
279  $thisfile_audio['bitrate'] = (($thisfile_avdataend - $thisfile_avdataoffset) * 8) / $ThisFileInfo['playtime_seconds'];
280 
281  fseek($fd, $thisfile_avdataoffset - 44, SEEK_SET);
282  $RIFFdata = fread($fd, 44);
283  $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
284  $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
285 
286  if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
287  $thisfile_avdataend -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
288  fseek($fd, $thisfile_avdataend, SEEK_SET);
289  $RIFFdata .= fread($fd, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
290  }
291 
292  // move the data chunk after all other chunks (if any)
293  // so that the RIFF parser doesn't see EOF when trying
294  // to skip over the data chunk
295  $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
296  getid3_riff::ParseRIFFdata($RIFFdata, $ThisFileInfo);
297  }
298 
299  if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
300  switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
301  case 0x08AE: // ClearJump LiteWave
302  $thisfile_audio['bitrate_mode'] = 'vbr';
303  $thisfile_audio_dataformat = 'litewave';
304 
305  //typedef struct tagSLwFormat {
306  // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags
307  // DWORD m_dwScale; // scale factor for lossy compression
308  // DWORD m_dwBlockSize; // number of samples in encoded blocks
309  // WORD m_wQuality; // alias for the scale factor
310  // WORD m_wMarkDistance; // distance between marks in bytes
311  // WORD m_wReserved;
312  //
313  // //following paramters are ignored if CF_FILESRC is not set
314  // DWORD m_dwOrgSize; // original file size in bytes
315  // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file
316  // DWORD m_dwRiffChunkSize; // riff chunk size in the original file
317  //
318  // PCMWAVEFORMAT m_OrgWf; // original wave format
319  // }SLwFormat, *PSLwFormat;
320 
321  // shortcut
322  $thisfile_riff['litewave']['raw'] = array();
323  $thisfile_riff_litewave = &$thisfile_riff['litewave'];
324  $thisfile_riff_litewave_raw = &$thisfile_riff_litewave['raw'];
325 
326  $thisfile_riff_litewave_raw['compression_method'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 18, 1));
327  $thisfile_riff_litewave_raw['compression_flags'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 19, 1));
328  $thisfile_riff_litewave_raw['m_dwScale'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 20, 4));
329  $thisfile_riff_litewave_raw['m_dwBlockSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 24, 4));
330  $thisfile_riff_litewave_raw['m_wQuality'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 28, 2));
331  $thisfile_riff_litewave_raw['m_wMarkDistance'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 30, 2));
332  $thisfile_riff_litewave_raw['m_wReserved'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 32, 2));
333  $thisfile_riff_litewave_raw['m_dwOrgSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 34, 4));
334  $thisfile_riff_litewave_raw['m_bFactExists'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 38, 2));
335  $thisfile_riff_litewave_raw['m_dwRiffChunkSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 40, 4));
336 
337  //$thisfile_riff_litewave['quality_factor'] = intval(round((2000 - $thisfile_riff_litewave_raw['m_dwScale']) / 20));
338  $thisfile_riff_litewave['quality_factor'] = $thisfile_riff_litewave_raw['m_wQuality'];
339 
340  $thisfile_riff_litewave['flags']['raw_source'] = ($thisfile_riff_litewave_raw['compression_flags'] & 0x01) ? false : true;
341  $thisfile_riff_litewave['flags']['vbr_blocksize'] = ($thisfile_riff_litewave_raw['compression_flags'] & 0x02) ? false : true;
342  $thisfile_riff_litewave['flags']['seekpoints'] = (bool) ($thisfile_riff_litewave_raw['compression_flags'] & 0x04);
343 
344  $thisfile_audio['lossless'] = (($thisfile_riff_litewave_raw['m_wQuality'] == 100) ? true : false);
345  $thisfile_audio['encoder_options'] = '-q'.$thisfile_riff_litewave['quality_factor'];
346  break;
347 
348  default:
349  break;
350  }
351  }
352  if ($thisfile_avdataend > $ThisFileInfo['filesize']) {
353  switch (@$thisfile_audio_dataformat) {
354  case 'wavpack': // WavPack
355  case 'lpac': // LPAC
356  case 'ofr': // OptimFROG
357  case 'ofs': // OptimFROG DualStream
358  // lossless compressed audio formats that keep original RIFF headers - skip warning
359  break;
360 
361  case 'litewave':
362  if (($thisfile_avdataend - $ThisFileInfo['filesize']) == 1) {
363  // LiteWave appears to incorrectly *not* pad actual output file
364  // to nearest WORD boundary so may appear to be short by one
365  // byte, in which case - skip warning
366  } else {
367  // Short by more than one byte, throw warning
368  $ThisFileInfo['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($ThisFileInfo['filesize'] - $thisfile_avdataoffset).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($ThisFileInfo['filesize'] - $thisfile_avdataoffset)).' bytes)';
369  $thisfile_avdataend = $ThisFileInfo['filesize'];
370  }
371  break;
372 
373  default:
374  if ((($thisfile_avdataend - $ThisFileInfo['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($ThisFileInfo['filesize'] - $thisfile_avdataoffset) % 2) == 1)) {
375  // output file appears to be incorrectly *not* padded to nearest WORD boundary
376  // Output less severe warning
377  $ThisFileInfo['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($ThisFileInfo['filesize'] - $thisfile_avdataoffset).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($ThisFileInfo['filesize'] - $thisfile_avdataoffset)).' bytes)';
378  $thisfile_avdataend = $ThisFileInfo['filesize'];
379  break;
380  }
381  // Short by more than one byte, throw warning
382  $ThisFileInfo['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($ThisFileInfo['filesize'] - $thisfile_avdataoffset).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($ThisFileInfo['filesize'] - $thisfile_avdataoffset)).' bytes)';
383  $thisfile_avdataend = $ThisFileInfo['filesize'];
384  break;
385  }
386  }
387  if (!empty($ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'])) {
388  if ((($thisfile_avdataend - $thisfile_avdataoffset) - $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
389  $thisfile_avdataend--;
390  $ThisFileInfo['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
391  }
392  }
393  if (@$thisfile_audio_dataformat == 'ac3') {
394  unset($thisfile_audio['bits_per_sample']);
395  if (!empty($ThisFileInfo['ac3']['bitrate']) && ($ThisFileInfo['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
396  $thisfile_audio['bitrate'] = $ThisFileInfo['ac3']['bitrate'];
397  }
398  }
399  break;
400 
401  case 'AVI ':
402  $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
403  $thisfile_video['dataformat'] = 'avi';
404  $ThisFileInfo['mime_type'] = 'video/avi';
405 
406  if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
407  $thisfile_avdataoffset = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
408  $thisfile_avdataend = $thisfile_avdataoffset + $thisfile_riff[$RIFFsubtype]['movi']['size'];
409  if ($thisfile_avdataend > $ThisFileInfo['filesize']) {
410  $ThisFileInfo['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['movi']['size'].' bytes of data, only found '.($ThisFileInfo['filesize'] - $thisfile_avdataoffset).' (short by '.($thisfile_riff[$RIFFsubtype]['movi']['size'] - ($ThisFileInfo['filesize'] - $thisfile_avdataoffset)).' bytes)';
411  $thisfile_avdataend = $ThisFileInfo['filesize'];
412  }
413  }
414 
415  if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
416  $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
417 
418  // shortcut
419  $thisfile_riff_raw['avih'] = array();
420  $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
421 
422  $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 0, 4)); // frame display rate (or 0L)
423  if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
424  $ThisFileInfo['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
425  return false;
426  }
427  $thisfile_riff_raw_avih['dwMaxBytesPerSec'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 4, 4)); // max. transfer rate
428  $thisfile_riff_raw_avih['dwPaddingGranularity'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 8, 4)); // pad to multiples of this size; normally 2K.
429  $thisfile_riff_raw_avih['dwFlags'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 12, 4)); // the ever-present flags
430  $thisfile_riff_raw_avih['dwTotalFrames'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 16, 4)); // # frames in file
431  $thisfile_riff_raw_avih['dwInitialFrames'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 20, 4));
432  $thisfile_riff_raw_avih['dwStreams'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 24, 4));
433  $thisfile_riff_raw_avih['dwSuggestedBufferSize'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 28, 4));
434  $thisfile_riff_raw_avih['dwWidth'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 32, 4));
435  $thisfile_riff_raw_avih['dwHeight'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 36, 4));
436  $thisfile_riff_raw_avih['dwScale'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 40, 4));
437  $thisfile_riff_raw_avih['dwRate'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 44, 4));
438  $thisfile_riff_raw_avih['dwStart'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 48, 4));
439  $thisfile_riff_raw_avih['dwLength'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 52, 4));
440 
441  $thisfile_riff_raw_avih['flags']['hasindex'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x00000010);
442  $thisfile_riff_raw_avih['flags']['mustuseindex'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x00000020);
443  $thisfile_riff_raw_avih['flags']['interleaved'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x00000100);
444  $thisfile_riff_raw_avih['flags']['trustcktype'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x00000800);
445  $thisfile_riff_raw_avih['flags']['capturedfile'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x00010000);
446  $thisfile_riff_raw_avih['flags']['copyrighted'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x00020010);
447 
448  // shortcut
449  $thisfile_riff_video[$streamindex] = array();
450  $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
451 
452  if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
453  $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
454  $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width'];
455  }
456  if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
457  $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
458  $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height'];
459  }
460  if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
461  $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
462  $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames'];
463  }
464 
465  $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
466  $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
467  }
468  if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
469  if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
470  for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
471  if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
472  $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
473  $strhfccType = substr($strhData, 0, 4);
474 
475  if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
476  $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
477 
478  // shortcut
479  $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
480 
481  switch ($strhfccType) {
482  case 'auds':
483  $thisfile_audio['bitrate_mode'] = 'cbr';
484  $thisfile_audio_dataformat = 'wav';
485  if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
486  $streamindex = count($thisfile_riff_audio);
487  }
488 
489  $thisfile_riff_audio[$streamindex] = getid3_riff::RIFFparseWAVEFORMATex($strfData);
490  $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
491 
492  // shortcut
493  $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
494  $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex];
495 
496  if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
497  unset($thisfile_audio_streams_currentstream['bits_per_sample']);
498  }
499  $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
500  unset($thisfile_audio_streams_currentstream['raw']);
501 
502  // shortcut
503  $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
504 
505  unset($thisfile_riff_audio[$streamindex]['raw']);
506  $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
507 
508  $thisfile_audio['lossless'] = false;
509  switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
510  case 0x0001: // PCM
511  $thisfile_audio_dataformat = 'wav';
512  $thisfile_audio['lossless'] = true;
513  break;
514 
515  case 0x0050: // MPEG Layer 2 or Layer 1
516  $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
517  break;
518 
519  case 0x0055: // MPEG Layer 3
520  $thisfile_audio_dataformat = 'mp3';
521  break;
522 
523  case 0x00FF: // AAC
524  $thisfile_audio_dataformat = 'aac';
525  break;
526 
527  case 0x0161: // Windows Media v7 / v8 / v9
528  case 0x0162: // Windows Media Professional v9
529  case 0x0163: // Windows Media Lossess v9
530  $thisfile_audio_dataformat = 'wma';
531  break;
532 
533  case 0x2000: // AC-3
534  $thisfile_audio_dataformat = 'ac3';
535  break;
536 
537  case 0x2001: // DTS
538  $thisfile_audio_dataformat = 'dts';
539  break;
540 
541  default:
542  $thisfile_audio_dataformat = 'wav';
543  break;
544  }
545  $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat;
546  $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless'];
547  $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
548  break;
549 
550 
551  case 'iavs':
552  case 'vids':
553  // shortcut
554  $thisfile_riff_raw['strh'][$i] = array();
555  $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i];
556 
557  $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType;
558  $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4);
559  $thisfile_riff_raw_strh_current['dwFlags'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 8, 4)); // Contains AVITF_* flags
560  $thisfile_riff_raw_strh_current['wPriority'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 12, 2));
561  $thisfile_riff_raw_strh_current['wLanguage'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 14, 2));
562  $thisfile_riff_raw_strh_current['dwInitialFrames'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 16, 4));
563  $thisfile_riff_raw_strh_current['dwScale'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 20, 4));
564  $thisfile_riff_raw_strh_current['dwRate'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 24, 4));
565  $thisfile_riff_raw_strh_current['dwStart'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 28, 4));
566  $thisfile_riff_raw_strh_current['dwLength'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 32, 4));
567  $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 36, 4));
568  $thisfile_riff_raw_strh_current['dwQuality'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 40, 4));
569  $thisfile_riff_raw_strh_current['dwSampleSize'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 44, 4));
570  $thisfile_riff_raw_strh_current['rcFrame'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 48, 4));
571 
572  $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
573  $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler'];
574  if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
575  $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
576  $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
577  }
578  $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
579  $thisfile_video['pixel_aspect_ratio'] = (float) 1;
580  switch ($thisfile_riff_raw_strh_current['fccHandler']) {
581  case 'HFYU': // Huffman Lossless Codec
582  case 'IRAW': // Intel YUV Uncompressed
583  case 'YUY2': // Uncompressed YUV 4:2:2
584  $thisfile_video['lossless'] = true;
585  break;
586 
587  default:
588  $thisfile_video['lossless'] = false;
589  break;
590  }
591 
592  switch ($strhfccType) {
593  case 'vids':
594  $thisfile_riff_raw_strf_strhfccType_streamindex['biSize'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 0, 4)); // number of bytes required by the BITMAPINFOHEADER structure
595  $thisfile_riff_raw_strf_strhfccType_streamindex['biWidth'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 4, 4)); // width of the bitmap in pixels
596  $thisfile_riff_raw_strf_strhfccType_streamindex['biHeight'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 8, 4)); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
597  $thisfile_riff_raw_strf_strhfccType_streamindex['biPlanes'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 12, 2)); // number of color planes on the target device. In most cases this value must be set to 1
598  $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 14, 2)); // Specifies the number of bits per pixels
599  $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'] = substr($strfData, 16, 4); //
600  $thisfile_riff_raw_strf_strhfccType_streamindex['biSizeImage'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 20, 4)); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
601  $thisfile_riff_raw_strf_strhfccType_streamindex['biXPelsPerMeter'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 24, 4)); // horizontal resolution, in pixels per metre, of the target device
602  $thisfile_riff_raw_strf_strhfccType_streamindex['biYPelsPerMeter'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 28, 4)); // vertical resolution, in pixels per metre, of the target device
603  $thisfile_riff_raw_strf_strhfccType_streamindex['biClrUsed'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 32, 4)); // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
604  $thisfile_riff_raw_strf_strhfccType_streamindex['biClrImportant'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 36, 4)); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
605 
606  $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
607 
608  if ($thisfile_riff_video_current['codec'] == 'DV') {
609  $thisfile_riff_video_current['dv_type'] = 2;
610  }
611  break;
612 
613  case 'iavs':
614  $thisfile_riff_video_current['dv_type'] = 1;
615  break;
616  }
617  break;
618 
619  default:
620  $ThisFileInfo['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"';
621  break;
622 
623  }
624  }
625  }
626 
627  if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
628 
629  $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
630  $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
631  $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
632 
633  switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
634  case 'HFYU': // Huffman Lossless Codec
635  case 'IRAW': // Intel YUV Uncompressed
636  case 'YUY2': // Uncompressed YUV 4:2:2
637  $thisfile_video['lossless'] = true;
638  $thisfile_video['bits_per_sample'] = 24;
639  break;
640 
641  default:
642  $thisfile_video['lossless'] = false;
643  $thisfile_video['bits_per_sample'] = 24;
644  break;
645  }
646 
647  }
648  }
649  }
650  }
651  break;
652 
653  case 'CDDA':
654  $thisfile_audio['bitrate_mode'] = 'cbr';
655  $thisfile_audio_dataformat = 'cda';
656  $thisfile_audio['lossless'] = true;
657  unset($ThisFileInfo['mime_type']);
658 
659  $thisfile_avdataoffset = 44;
660 
661  if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
662  // shortcut
663  $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0];
664 
665  $thisfile_riff_CDDA_fmt_0['unknown1'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2));
666  $thisfile_riff_CDDA_fmt_0['track_num'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2));
667  $thisfile_riff_CDDA_fmt_0['disc_id'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4));
668  $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4));
669  $thisfile_riff_CDDA_fmt_0['playtime_frames'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
670  $thisfile_riff_CDDA_fmt_0['unknown6'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
671  $thisfile_riff_CDDA_fmt_0['unknown7'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
672 
673  $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
674  $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
675  $ThisFileInfo['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
676  $ThisFileInfo['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
677 
678  // hardcoded data for CD-audio
679  $thisfile_audio['sample_rate'] = 44100;
680  $thisfile_audio['channels'] = 2;
681  $thisfile_audio['bits_per_sample'] = 16;
682  $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
683  $thisfile_audio['bitrate_mode'] = 'cbr';
684  }
685  break;
686 
687 
688  case 'AIFF':
689  case 'AIFC':
690  $thisfile_audio['bitrate_mode'] = 'cbr';
691  $thisfile_audio_dataformat = 'aiff';
692  $thisfile_audio['lossless'] = true;
693  $ThisFileInfo['mime_type'] = 'audio/x-aiff';
694 
695  if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
696  $thisfile_avdataoffset = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
697  $thisfile_avdataend = $thisfile_avdataoffset + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
698  if ($thisfile_avdataend > $ThisFileInfo['filesize']) {
699  if (($thisfile_avdataend == ($ThisFileInfo['filesize'] + 1)) && (($ThisFileInfo['filesize'] % 2) == 1)) {
700  // structures rounded to 2-byte boundary, but dumb encoders
701  // forget to pad end of file to make this actually work
702  } else {
703  $ThisFileInfo['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($ThisFileInfo['filesize'] - $thisfile_avdataoffset).' bytes found';
704  }
705  $thisfile_avdataend = $ThisFileInfo['filesize'];
706  }
707  }
708 
709  if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
710 
711  // shortcut
712  $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
713 
714  $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true);
715  $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false);
716  $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true);
717  $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10));
718 
719  if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
720  $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
721  $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false);
722  $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize);
723  switch ($thisfile_riff_audio['codec_name']) {
724  case 'NONE':
725  $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
726  $thisfile_audio['lossless'] = true;
727  break;
728 
729  case '':
730  switch ($thisfile_riff_audio['codec_fourcc']) {
731  // http://developer.apple.com/qa/snd/snd07.html
732  case 'sowt':
733  $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
734  $thisfile_audio['lossless'] = true;
735  break;
736 
737  case 'twos':
738  $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
739  $thisfile_audio['lossless'] = true;
740  break;
741 
742  default:
743  break;
744  }
745  break;
746 
747  default:
748  $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
749  $thisfile_audio['lossless'] = false;
750  break;
751  }
752  }
753 
754  $thisfile_audio['channels'] = $thisfile_riff_audio['channels'];
755  if ($thisfile_riff_audio['bits_per_sample'] > 0) {
756  $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
757  }
758  $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
759  if ($thisfile_audio['sample_rate'] == 0) {
760  $ThisFileInfo['error'][] = 'Corrupted AIFF file: sample_rate == zero';
761  return false;
762  }
763  $ThisFileInfo['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
764  }
765 
766  if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
767  $offset = 0;
768  $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
769  $offset += 2;
770  for ($i = 0; $i < $CommentCount; $i++) {
771  $ThisFileInfo['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
772  $offset += 4;
773  $ThisFileInfo['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
774  $offset += 2;
775  $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
776  $offset += 2;
777  $ThisFileInfo['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
778  $offset += $CommentLength;
779 
780  $ThisFileInfo['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($ThisFileInfo['comments_raw'][$i]['timestamp']);
781  $thisfile_riff['comments']['comment'][] = $ThisFileInfo['comments_raw'][$i]['comment'];
782  }
783  }
784 
785  $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
786  foreach ($CommentsChunkNames as $key => $value) {
787  if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
788  $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
789  }
790  }
791  break;
792 
793  case '8SVX':
794  $thisfile_audio['bitrate_mode'] = 'cbr';
795  $thisfile_audio_dataformat = '8svx';
796  $thisfile_audio['bits_per_sample'] = 8;
797  $thisfile_audio['channels'] = 1; // overridden below, if need be
798  $ThisFileInfo['mime_type'] = 'audio/x-aiff';
799 
800  if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
801  $thisfile_avdataoffset = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
802  $thisfile_avdataend = $thisfile_avdataoffset + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
803  if ($thisfile_avdataend > $ThisFileInfo['filesize']) {
804  $ThisFileInfo['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($ThisFileInfo['filesize'] - $thisfile_avdataoffset).' bytes found';
805  }
806  }
807 
808  if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
809  // shortcut
810  $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0];
811 
812  $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4));
813  $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4));
814  $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4));
815  $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
816  $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
817  $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
818  $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
819 
820  $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
821 
822  switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
823  case 0:
824  $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
825  $thisfile_audio['lossless'] = true;
826  $ActualBitsPerSample = 8;
827  break;
828 
829  case 1:
830  $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
831  $thisfile_audio['lossless'] = false;
832  $ActualBitsPerSample = 4;
833  break;
834 
835  default:
836  $ThisFileInfo['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"';
837  break;
838  }
839  }
840 
841  if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
842  $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
843  switch ($ChannelsIndex) {
844  case 6: // Stereo
845  $thisfile_audio['channels'] = 2;
846  break;
847 
848  case 2: // Left channel only
849  case 4: // Right channel only
850  $thisfile_audio['channels'] = 1;
851  break;
852 
853  default:
854  $ThisFileInfo['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"';
855  break;
856  }
857 
858  }
859 
860  $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
861  foreach ($CommentsChunkNames as $key => $value) {
862  if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
863  $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
864  }
865  }
866 
867  $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
868  if (!empty($thisfile_audio['bitrate'])) {
869  $ThisFileInfo['playtime_seconds'] = ($thisfile_avdataend - $thisfile_avdataoffset) / ($thisfile_audio['bitrate'] / 8);
870  }
871  break;
872 
873 
874  case 'CDXA':
875  $ThisFileInfo['mime_type'] = 'video/mpeg';
876  if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
877  $GETID3_ERRORARRAY = &$ThisFileInfo['warning'];
878  if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, false)) {
879  $dummy = $ThisFileInfo;
880  $dummy['error'] = array();
881  $mpeg_scanner = new getid3_mpeg($fd, $dummy);
882  if (empty($dummy['error'])) {
883  $ThisFileInfo['audio'] = $dummy['audio'];
884  $ThisFileInfo['video'] = $dummy['video'];
885  $ThisFileInfo['mpeg'] = $dummy['mpeg'];
886  $ThisFileInfo['warning'] = $dummy['warning'];
887  }
888  }
889  }
890  break;
891 
892 
893  default:
894  $ThisFileInfo['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';
895  unset($ThisFileInfo['fileformat']);
896  break;
897  }
898 
899  if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
900  $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
901  }
902  if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
903  $this->RIFFcommentsParse($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
904  }
905 
906  if (empty($thisfile_audio['encoder']) && !empty($ThisFileInfo['mpeg']['audio']['LAME']['short_version'])) {
907  $thisfile_audio['encoder'] = $ThisFileInfo['mpeg']['audio']['LAME']['short_version'];
908  }
909 
910  if (!isset($ThisFileInfo['playtime_seconds'])) {
911  $ThisFileInfo['playtime_seconds'] = 0;
912  }
913  if (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
914  $ThisFileInfo['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
915  }
916 
917  if ($ThisFileInfo['playtime_seconds'] > 0) {
918  if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
919 
920  if (!isset($ThisFileInfo['bitrate'])) {
921  $ThisFileInfo['bitrate'] = ((($thisfile_avdataend - $thisfile_avdataoffset) / $ThisFileInfo['playtime_seconds']) * 8);
922  }
923 
924  } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
925 
926  if (!isset($thisfile_audio['bitrate'])) {
927  $thisfile_audio['bitrate'] = ((($thisfile_avdataend - $thisfile_avdataoffset) / $ThisFileInfo['playtime_seconds']) * 8);
928  }
929 
930  } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
931 
932  if (!isset($thisfile_video['bitrate'])) {
933  $thisfile_video['bitrate'] = ((($thisfile_avdataend - $thisfile_avdataoffset) / $ThisFileInfo['playtime_seconds']) * 8);
934  }
935 
936  }
937  }
938 
939 
940  if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($ThisFileInfo['playtime_seconds'] > 0)) {
941 
942  $ThisFileInfo['bitrate'] = ((($thisfile_avdataend - $thisfile_avdataoffset) / $ThisFileInfo['playtime_seconds']) * 8);
943  $thisfile_audio['bitrate'] = 0;
944  $thisfile_video['bitrate'] = $ThisFileInfo['bitrate'];
945  foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
946  $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
947  $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
948  }
949  if ($thisfile_video['bitrate'] <= 0) {
950  unset($thisfile_video['bitrate']);
951  }
952  if ($thisfile_audio['bitrate'] <= 0) {
953  unset($thisfile_audio['bitrate']);
954  }
955  }
956 
957  if (isset($ThisFileInfo['mpeg']['audio'])) {
958  $thisfile_audio_dataformat = 'mp'.$ThisFileInfo['mpeg']['audio']['layer'];
959  $thisfile_audio['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
960  $thisfile_audio['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
961  $thisfile_audio['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'];
962  $thisfile_audio['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitrate_mode']);
963  if (!empty($ThisFileInfo['mpeg']['audio']['codec'])) {
964  $thisfile_audio['codec'] = $ThisFileInfo['mpeg']['audio']['codec'].' '.$thisfile_audio['codec'];
965  }
966  if (!empty($thisfile_audio['streams'])) {
967  foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
968  if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
969  $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate'];
970  $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels'];
971  $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
972  $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
973  $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec'];
974  }
975  }
976  }
977  $thisfile_audio['encoder_options'] = getid3_mp3::GuessEncoderOptions($ThisFileInfo);
978  }
979 
980 
981  if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) {
982  switch ($thisfile_audio_dataformat) {
983  case 'ac3':
984  // ignore bits_per_sample
985  break;
986 
987  default:
988  $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
989  break;
990  }
991  }
992 
993 
994  if (empty($thisfile_riff_raw)) {
995  unset($thisfile_riff['raw']);
996  }
997  if (empty($thisfile_riff_audio)) {
998  unset($thisfile_riff['audio']);
999  }
1000  if (empty($thisfile_riff_video)) {
1001  unset($thisfile_riff['video']);
1002  }
1003 
1004  return true;
1005  }
1006 
1007 
1008  function RIFFcommentsParse(&$RIFFinfoArray, &$CommentsTargetArray) {
1009  $RIFFinfoKeyLookup = array(
1010  'IARL'=>'archivallocation',
1011  'IART'=>'artist',
1012  'ICDS'=>'costumedesigner',
1013  'ICMS'=>'commissionedby',
1014  'ICMT'=>'comment',
1015  'ICNT'=>'country',
1016  'ICOP'=>'copyright',
1017  'ICRD'=>'creationdate',
1018  'IDIM'=>'dimensions',
1019  'IDIT'=>'digitizationdate',
1020  'IDPI'=>'resolution',
1021  'IDST'=>'distributor',
1022  'IEDT'=>'editor',
1023  'IENG'=>'engineers',
1024  'IFRM'=>'accountofparts',
1025  'IGNR'=>'genre',
1026  'IKEY'=>'keywords',
1027  'ILGT'=>'lightness',
1028  'ILNG'=>'language',
1029  'IMED'=>'orignalmedium',
1030  'IMUS'=>'composer',
1031  'INAM'=>'title',
1032  'IPDS'=>'productiondesigner',
1033  'IPLT'=>'palette',
1034  'IPRD'=>'product',
1035  'IPRO'=>'producer',
1036  'IPRT'=>'part',
1037  'IRTD'=>'rating',
1038  'ISBJ'=>'subject',
1039  'ISFT'=>'software',
1040  'ISGN'=>'secondarygenre',
1041  'ISHP'=>'sharpness',
1042  'ISRC'=>'sourcesupplier',
1043  'ISRF'=>'digitizationsource',
1044  'ISTD'=>'productionstudio',
1045  'ISTR'=>'starring',
1046  'ITCH'=>'encoded_by',
1047  'IWEB'=>'url',
1048  'IWRI'=>'writer'
1049  );
1050  foreach ($RIFFinfoKeyLookup as $key => $value) {
1051  if (isset($RIFFinfoArray[$key])) {
1052  foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
1053  if (trim($commentdata['data']) != '') {
1054  @$CommentsTargetArray[$value][] = trim($commentdata['data']);
1055  }
1056  }
1057  }
1058  }
1059  return true;
1060  }
1061 
1062  function ParseRIFF(&$fd, $startoffset, $maxoffset, &$ThisFileInfo) {
1063 
1064  $maxoffset = min($maxoffset, $ThisFileInfo['avdataend']);
1065 
1066  $RIFFchunk = false;
1067 
1068  fseek($fd, $startoffset, SEEK_SET);
1069 
1070  while (ftell($fd) < $maxoffset) {
1071  $chunkname = fread($fd, 4);
1072  if (strlen($chunkname) < 4) {
1073  $ThisFileInfo['error'][] = 'Expecting chunk name at offset '.(ftell($fd) - 4).' but found nothing. Aborting RIFF parsing.';
1074  break;
1075  }
1076 
1077  $chunksize = getid3_riff::EitherEndian2Int($ThisFileInfo, fread($fd, 4));
1078  if ($chunksize == 0) {
1079  $ThisFileInfo['error'][] = 'Chunk size at offset '.(ftell($fd) - 4).' is zero. Aborting RIFF parsing.';
1080  break;
1081  }
1082  if (($chunksize % 2) != 0) {
1083  // all structures are packed on word boundaries
1084  $chunksize++;
1085  }
1086 
1087  switch ($chunkname) {
1088  case 'LIST':
1089  $listname = fread($fd, 4);
1090  switch ($listname) {
1091  case 'movi':
1092  case 'rec ':
1093  $RIFFchunk[$listname]['offset'] = ftell($fd) - 4;
1094  $RIFFchunk[$listname]['size'] = $chunksize;
1095 
1096  static $ParsedAudioStream = false;
1097  if ($ParsedAudioStream) {
1098 
1099  // skip over
1100 
1101  } else {
1102 
1103  $WhereWeWere = ftell($fd);
1104  $AudioChunkHeader = fread($fd, 12);
1105  $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2);
1106  $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2);
1107  $AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
1108 
1109  if ($AudioChunkStreamType == 'wb') {
1110  $FirstFourBytes = substr($AudioChunkHeader, 8, 4);
1111  if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) {
1112 
1113  // MP3
1114  if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
1115  $dummy = $ThisFileInfo;
1116  $dummy['avdataoffset'] = ftell($fd) - 4;
1117  $dummy['avdataend'] = ftell($fd) + $AudioChunkSize;
1118  getid3_mp3::getOnlyMPEGaudioInfo($fd, $dummy, $dummy['avdataoffset'], false);
1119  if (isset($dummy['mpeg']['audio'])) {
1120  $ThisFileInfo = $dummy;
1121  $ThisFileInfo['audio']['dataformat'] = 'mp'.$ThisFileInfo['mpeg']['audio']['layer'];
1122  $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
1123  $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
1124  $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'];
1125  $ThisFileInfo['bitrate'] = $ThisFileInfo['audio']['bitrate'];
1126  $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitrate_mode']);
1127  }
1128  }
1129 
1130  } elseif (preg_match('/^\x0B\x77/s', $FirstFourBytes)) {
1131 
1132  // AC3
1133  $GETID3_ERRORARRAY = &$ThisFileInfo['warning'];
1134  if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, false)) {
1135 
1136  $dummy = $ThisFileInfo;
1137  $dummy['avdataoffset'] = ftell($fd) - 4;
1138  $dummy['avdataend'] = ftell($fd) + $AudioChunkSize;
1139  $dummy['error'] = array();
1140  $ac3_tag = new getid3_ac3($fd, $dummy);
1141  if (empty($dummy['error'])) {
1142  $ThisFileInfo['audio'] = $dummy['audio'];
1143  $ThisFileInfo['ac3'] = $dummy['ac3'];
1144  $ThisFileInfo['warning'] = $dummy['warning'];
1145  }
1146 
1147  }
1148 
1149  }
1150 
1151  }
1152 
1153  $ParsedAudioStream = true;
1154  fseek($fd, $WhereWeWere, SEEK_SET);
1155 
1156  }
1157  fseek($fd, $chunksize - 4, SEEK_CUR);
1158  break;
1159 
1160  default:
1161  if (!isset($RIFFchunk[$listname])) {
1162  $RIFFchunk[$listname] = array();
1163  }
1164  $LISTchunkParent = $listname;
1165  $LISTchunkMaxOffset = ftell($fd) - 4 + $chunksize;
1166  if ($parsedChunk = getid3_riff::ParseRIFF($fd, ftell($fd), ftell($fd) + $chunksize - 4, $ThisFileInfo)) {
1167  $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
1168  }
1169  break;
1170  }
1171  break;
1172 
1173  default:
1174  $thisindex = 0;
1175  if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
1176  $thisindex = count($RIFFchunk[$chunkname]);
1177  }
1178  $RIFFchunk[$chunkname][$thisindex]['offset'] = ftell($fd) - 8;
1179  $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize;
1180  switch ($chunkname) {
1181  case 'data':
1182  $ThisFileInfo['avdataoffset'] = ftell($fd);
1183  $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $chunksize;
1184 
1185  $RIFFdataChunkContentsTest = fread($fd, 36);
1186 
1187  if ((strlen($RIFFdataChunkContentsTest) > 0) && preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($RIFFdataChunkContentsTest, 0, 4))) {
1188 
1189  // Probably is MP3 data
1190  if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($RIFFdataChunkContentsTest, 0, 4))) {
1191  getid3_mp3::getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $RIFFchunk[$chunkname][$thisindex]['offset'], false);
1192  }
1193 
1194  } elseif ((strlen($RIFFdataChunkContentsTest) > 0) && (substr($RIFFdataChunkContentsTest, 0, 2) == "\x0B\x77")) {
1195 
1196  // This is probably AC-3 data
1197  $GETID3_ERRORARRAY = &$ThisFileInfo['warning'];
1198  if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, false)) {
1199 
1200  $dummy = $ThisFileInfo;
1201  $dummy['avdataoffset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
1202  $dummy['avdataend'] = $dummy['avdataoffset'] + $RIFFchunk[$chunkname][$thisindex]['size'];
1203  $dummy['error'] = array();
1204 
1205  $ac3_tag = new getid3_ac3($fd, $dummy);
1206  if (empty($dummy['error'])) {
1207  $ThisFileInfo['audio'] = $dummy['audio'];
1208  $ThisFileInfo['ac3'] = $dummy['ac3'];
1209  $ThisFileInfo['warning'] = $dummy['warning'];
1210  }
1211 
1212  }
1213 
1214  } elseif ((strlen($RIFFdataChunkContentsTest) > 0) && (substr($RIFFdataChunkContentsTest, 8, 2) == "\x77\x0B")) {
1215 
1216  // Dolby Digital WAV
1217  // AC-3 content, but not encoded in same format as normal AC-3 file
1218  // For one thing, byte order is swapped
1219 
1220  $GETID3_ERRORARRAY = &$ThisFileInfo['warning'];
1221  if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, false)) {
1222 
1223  // ok to use tmpfile here - only 56 bytes
1224  if ($fd_temp = tmpfile()) {
1225 
1226  for ($i = 0; $i < 28; $i += 2) {
1227  // swap byte order
1228  fwrite($fd_temp, substr($RIFFdataChunkContentsTest, 8 + $i + 1, 1));
1229  fwrite($fd_temp, substr($RIFFdataChunkContentsTest, 8 + $i + 0, 1));
1230  }
1231 
1232  $dummy = $ThisFileInfo;
1233  $dummy['avdataoffset'] = 0;
1234  $dummy['avdataend'] = 20;
1235  $dummy['error'] = array();
1236  $ac3_tag = new getid3_ac3($fd_temp, $dummy);
1237  fclose($fd_temp);
1238  if (empty($dummy['error'])) {
1239  $ThisFileInfo['audio'] = $dummy['audio'];
1240  $ThisFileInfo['ac3'] = $dummy['ac3'];
1241  $ThisFileInfo['warning'] = $dummy['warning'];
1242  } else {
1243  $ThisFileInfo['error'][] = 'Errors parsing DolbyDigital WAV: '.explode(';', $dummy['error']);
1244  }
1245 
1246  } else {
1247 
1248  $ThisFileInfo['error'][] = 'Could not create temporary file to analyze DolbyDigital WAV';
1249 
1250  }
1251 
1252  }
1253 
1254  } elseif ((strlen($RIFFdataChunkContentsTest) > 0) && (substr($RIFFdataChunkContentsTest, 0, 4) == 'wvpk')) {
1255 
1256  // This is WavPack data
1257  $ThisFileInfo['wavpack']['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
1258  $ThisFileInfo['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($RIFFdataChunkContentsTest, 4, 4));
1259  getid3_riff::RIFFparseWavPackHeader(substr($RIFFdataChunkContentsTest, 8, 28), $ThisFileInfo);
1260 
1261  } else {
1262 
1263  // This is some other kind of data (quite possibly just PCM)
1264  // do nothing special, just skip it
1265 
1266  }
1267  fseek($fd, $RIFFchunk[$chunkname][$thisindex]['offset'] + 8 + $chunksize, SEEK_SET);
1268  break;
1269 
1270  case 'bext':
1271  case 'cart':
1272  case 'fmt ':
1273  case 'MEXT':
1274  case 'DISP':
1275  // always read data in
1276  $RIFFchunk[$chunkname][$thisindex]['data'] = fread($fd, $chunksize);
1277  break;
1278 
1279  default:
1280  if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
1281  $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
1282  $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
1283  unset($RIFFchunk[$chunkname][$thisindex]['offset']);
1284  unset($RIFFchunk[$chunkname][$thisindex]['size']);
1285  if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
1286  unset($RIFFchunk[$chunkname][$thisindex]);
1287  }
1288  if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
1289  unset($RIFFchunk[$chunkname]);
1290  }
1291  $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = fread($fd, $chunksize);
1292  } elseif ($chunksize < 2048) {
1293  // only read data in if smaller than 2kB
1294  $RIFFchunk[$chunkname][$thisindex]['data'] = fread($fd, $chunksize);
1295  } else {
1296  fseek($fd, $chunksize, SEEK_CUR);
1297  }
1298  break;
1299  }
1300  break;
1301 
1302  }
1303 
1304  }
1305 
1306  return $RIFFchunk;
1307  }
1308 
1309 
1310  function ParseRIFFdata(&$RIFFdata, &$ThisFileInfo) {
1311  if ($RIFFdata) {
1312 
1313  $tempfile = tempnam('*', 'getID3');
1314  $fp_temp = fopen($tempfile, "wb");
1315  $RIFFdataLength = strlen($RIFFdata);
1316  $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4);
1317  for ($i = 0; $i < 4; $i++) {
1318  $RIFFdata{$i + 4} = $NewLengthString{$i};
1319  }
1320  fwrite($fp_temp, $RIFFdata);
1321  fclose($fp_temp);
1322 
1323  $fp_temp = fopen($tempfile, "rb");
1324  $dummy = array('filesize'=>$RIFFdataLength, 'filenamepath'=>$ThisFileInfo['filenamepath'], 'tags'=>$ThisFileInfo['tags'], 'avdataoffset'=>0, 'avdataend'=>$RIFFdataLength, 'warning'=>$ThisFileInfo['warning'], 'error'=>$ThisFileInfo['error'], 'comments'=>$ThisFileInfo['comments'], 'audio'=>(isset($ThisFileInfo['audio']) ? $ThisFileInfo['audio'] : array()), 'video'=>(isset($ThisFileInfo['video']) ? $ThisFileInfo['video'] : array()));
1325  $riff = new getid3_riff($fp_temp, $dummy);
1326  $ThisFileInfo['riff'] = $dummy['riff'];
1327  $ThisFileInfo['warning'] = $dummy['warning'];
1328  $ThisFileInfo['error'] = $dummy['error'];
1329  $ThisFileInfo['tags'] = $dummy['tags'];
1330  $ThisFileInfo['comments'] = $dummy['comments'];
1331  fclose($fp_temp);
1332  unlink($tempfile);
1333  return true;
1334  }
1335  return false;
1336  }
1337 
1338 
1339  function RIFFparseWAVEFORMATex($WaveFormatExData) {
1340  // shortcut
1341  $WaveFormatEx['raw'] = array();
1342  $WaveFormatEx_raw = &$WaveFormatEx['raw'];
1343 
1344  $WaveFormatEx_raw['wFormatTag'] = getid3_lib::LittleEndian2Int(substr($WaveFormatExData, 0, 2));
1345  $WaveFormatEx_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($WaveFormatExData, 2, 2));
1346  $WaveFormatEx_raw['nSamplesPerSec'] = getid3_lib::LittleEndian2Int(substr($WaveFormatExData, 4, 4));
1347  $WaveFormatEx_raw['nAvgBytesPerSec'] = getid3_lib::LittleEndian2Int(substr($WaveFormatExData, 8, 4));
1348  $WaveFormatEx_raw['nBlockAlign'] = getid3_lib::LittleEndian2Int(substr($WaveFormatExData, 12, 2));
1349  $WaveFormatEx_raw['wBitsPerSample'] = getid3_lib::LittleEndian2Int(substr($WaveFormatExData, 14, 2));
1350  if (strlen($WaveFormatExData) > 16) {
1351  $WaveFormatEx_raw['cbSize'] = getid3_lib::LittleEndian2Int(substr($WaveFormatExData, 16, 2));
1352  }
1353 
1354  $WaveFormatEx['codec'] = getid3_riff::RIFFwFormatTagLookup($WaveFormatEx_raw['wFormatTag']);
1355  $WaveFormatEx['channels'] = $WaveFormatEx_raw['nChannels'];
1356  $WaveFormatEx['sample_rate'] = $WaveFormatEx_raw['nSamplesPerSec'];
1357  $WaveFormatEx['bitrate'] = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8;
1358  $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample'];
1359 
1360  return $WaveFormatEx;
1361  }
1362 
1363 
1364  function RIFFparseWavPackHeader($WavPackChunkData, &$ThisFileInfo) {
1365  // typedef struct {
1366  // char ckID [4];
1367  // long ckSize;
1368  // short version;
1369  // short bits; // added for version 2.00
1370  // short flags, shift; // added for version 3.00
1371  // long total_samples, crc, crc2;
1372  // char extension [4], extra_bc, extras [3];
1373  // } WavpackHeader;
1374 
1375  // shortcut
1376  $ThisFileInfo['wavpack'] = array();
1377  $thisfile_wavpack = &$ThisFileInfo['wavpack'];
1378 
1379  $thisfile_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 0, 2));
1380  if ($thisfile_wavpack['version'] >= 2) {
1381  $thisfile_wavpack['bits'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 2, 2));
1382  }
1383  if ($thisfile_wavpack['version'] >= 3) {
1384  $thisfile_wavpack['flags_raw'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 4, 2));
1385  $thisfile_wavpack['shift'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 6, 2));
1386  $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 8, 4));
1387  $thisfile_wavpack['crc1'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4));
1388  $thisfile_wavpack['crc2'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4));
1389  $thisfile_wavpack['extension'] = substr($WavPackChunkData, 20, 4);
1390  $thisfile_wavpack['extra_bc'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1));
1391  for ($i = 0; $i <= 2; $i++) {
1392  $thisfile_wavpack['extras'][] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1));
1393  }
1394 
1395  // shortcut
1396  $thisfile_wavpack['flags'] = array();
1397  $thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
1398 
1399  $thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001);
1400  $thisfile_wavpack_flags['fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002);
1401  $thisfile_wavpack_flags['raw_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004);
1402  $thisfile_wavpack_flags['calc_noise'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008);
1403  $thisfile_wavpack_flags['high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010);
1404  $thisfile_wavpack_flags['3_byte_samples'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020);
1405  $thisfile_wavpack_flags['over_20_bits'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040);
1406  $thisfile_wavpack_flags['use_wvc'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080);
1407  $thisfile_wavpack_flags['noiseshaping'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100);
1408  $thisfile_wavpack_flags['very_fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200);
1409  $thisfile_wavpack_flags['new_high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400);
1410  $thisfile_wavpack_flags['cancel_extreme'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800);
1411  $thisfile_wavpack_flags['cross_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000);
1412  $thisfile_wavpack_flags['new_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000);
1413  $thisfile_wavpack_flags['joint_stereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000);
1414  $thisfile_wavpack_flags['extra_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000);
1415  $thisfile_wavpack_flags['override_noiseshape'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000);
1416  $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000);
1417  $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000);
1418  $thisfile_wavpack_flags['create_exe'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000);
1419  }
1420 
1421  return true;
1422  }
1423 
1424  function RIFFwFormatTagLookup($wFormatTag) {
1425 
1426  $begin = __LINE__;
1427 
1590  return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
1591 
1592  }
1593 
1594 
1595  function RIFFfourccLookup($fourcc) {
1596 
1597  $begin = __LINE__;
1598 
1982  return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
1983  }
1984 
1985 
1986  function EitherEndian2Int(&$ThisFileInfo, $byteword, $signed=false) {
1987  if ($ThisFileInfo['fileformat'] == 'riff') {
1988  return getid3_lib::LittleEndian2Int($byteword, $signed);
1989  }
1990  return getid3_lib::BigEndian2Int($byteword, false, $signed);
1991  }
1992 
1993 }
1994 
1995 ?>