PageRenderTime 55ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/application/libraries/getid3/module.audio-video.riff.php

https://github.com/libis/Flandrica
PHP | 2391 lines | 1858 code | 404 blank | 129 comment | 248 complexity | fb6c7610710749b4a70742c09517cf5d MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP version 5 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 2002-2009 James Heinrich, Allan Hansen |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2 of the GPL license, |
  8. // | that is bundled with this package in the file license.txt and is |
  9. // | available through the world-wide-web at the following url: |
  10. // | http://www.gnu.org/copyleft/gpl.html |
  11. // +----------------------------------------------------------------------+
  12. // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
  13. // +----------------------------------------------------------------------+
  14. // | Authors: James Heinrich <infoŘgetid3*org> |
  15. // | Allan Hansen <ahŘartemis*dk> |
  16. // +----------------------------------------------------------------------+
  17. // | module.audio-video.riff.php |
  18. // | module for analyzing RIFF files: |
  19. // | Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack3, 8SVX |
  20. // | dependencies: module.audio.mp3.php (optional) |
  21. // | module.audio.ac3.php (optional) |
  22. // | module.audio.dts.php (optional) |
  23. // | module.audio-video.mpeg.php (optional) |
  24. // +----------------------------------------------------------------------+
  25. //
  26. // $Id: module.audio-video.riff.php,v 1.10 2006/12/03 20:13:17 ah Exp $
  27. class getid3_riff extends getid3_handler
  28. {
  29. private $endian_function = 'LittleEndian2Int';
  30. public function Analyze() {
  31. $getid3 = $this->getid3;
  32. $getid3->info['riff']['raw'] = array ();
  33. $info_riff = &$getid3->info['riff'];
  34. $info_riff_raw = &$info_riff['raw'];
  35. $info_audio = &$getid3->info['audio'];
  36. $info_video = &$getid3->info['video'];
  37. $info_avdataoffset = &$getid3->info['avdataoffset'];
  38. $info_avdataend = &$getid3->info['avdataend'];
  39. $info_audio_dataformat = &$info_audio['dataformat'];
  40. $info_riff_audio = &$info_riff['audio'];
  41. $info_riff_video = &$info_riff['video'];
  42. $original['avdataend'] = $info_avdataend;
  43. $this->fseek($info_avdataoffset, SEEK_SET);
  44. $riff_header = $this->fread(12);
  45. $riff_sub_type = substr($riff_header, 8, 4);
  46. switch (substr($riff_header, 0, 4)) {
  47. case 'FORM':
  48. $getid3->info['fileformat'] = 'aiff';
  49. $this->endian_function = 'BigEndian2Int';
  50. $riff_header_size = getid3_lib::BigEndian2Int(substr($riff_header, 4, 4));
  51. $info_riff[$riff_sub_type] = $this->ParseRIFF($info_avdataoffset + 12, $info_avdataoffset + $riff_header_size);
  52. $info_riff['header_size'] = $riff_header_size;
  53. break;
  54. case 'RIFF':
  55. case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
  56. case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
  57. if ($riff_sub_type == 'RMP3') {
  58. $riff_sub_type = 'WAVE';
  59. }
  60. $getid3->info['fileformat'] = 'riff';
  61. $this->endian_function = 'LittleEndian2Int';
  62. $riff_header_size = getid3_lib::LittleEndian2Int(substr($riff_header, 4, 4));
  63. $info_riff[$riff_sub_type] = $this->ParseRIFF($info_avdataoffset + 12, $info_avdataoffset + $riff_header_size);
  64. $info_riff['header_size'] = $riff_header_size;
  65. if ($riff_sub_type == 'WAVE') {
  66. $info_riff_wave = &$info_riff['WAVE'];
  67. }
  68. break;
  69. default:
  70. throw new getid3_exception('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$riff_sub_type.'" instead');
  71. }
  72. $endian_function = $this->endian_function;
  73. $stream_index = 0;
  74. switch ($riff_sub_type) {
  75. case 'WAVE':
  76. if (empty($info_audio['bitrate_mode'])) {
  77. $info_audio['bitrate_mode'] = 'cbr';
  78. }
  79. if (empty($info_audio_dataformat)) {
  80. $info_audio_dataformat = 'wav';
  81. }
  82. if (isset($info_riff_wave['data'][0]['offset'])) {
  83. $info_avdataoffset = $info_riff_wave['data'][0]['offset'] + 8;
  84. $info_avdataend = $info_avdataoffset + $info_riff_wave['data'][0]['size'];
  85. }
  86. if (isset($info_riff_wave['fmt '][0]['data'])) {
  87. $info_riff_audio[$stream_index] = getid3_riff::RIFFparseWAVEFORMATex($info_riff_wave['fmt '][0]['data']);
  88. $info_audio['wformattag'] = $info_riff_audio[$stream_index]['raw']['wFormatTag'];
  89. $info_riff_raw['fmt '] = $info_riff_audio[$stream_index]['raw'];
  90. unset($info_riff_audio[$stream_index]['raw']);
  91. $info_audio['streams'][$stream_index] = $info_riff_audio[$stream_index];
  92. $info_audio = getid3_riff::array_merge_noclobber($info_audio, $info_riff_audio[$stream_index]);
  93. if (substr($info_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
  94. $getid3->warning('Audio codec = '.$info_audio['codec']);
  95. }
  96. $info_audio['bitrate'] = $info_riff_audio[$stream_index]['bitrate'];
  97. $getid3->info['playtime_seconds'] = (float)((($info_avdataend - $info_avdataoffset) * 8) / $info_audio['bitrate']);
  98. $info_audio['lossless'] = false;
  99. if (isset($info_riff_wave['data'][0]['offset']) && isset($info_riff_raw['fmt ']['wFormatTag'])) {
  100. switch ($info_riff_raw['fmt ']['wFormatTag']) {
  101. case 0x0001: // PCM
  102. $info_audio['lossless'] = true;
  103. break;
  104. case 0x2000: // AC-3
  105. $info_audio_dataformat = 'ac3';
  106. break;
  107. default:
  108. // do nothing
  109. break;
  110. }
  111. }
  112. $info_audio['streams'][$stream_index]['wformattag'] = $info_audio['wformattag'];
  113. $info_audio['streams'][$stream_index]['bitrate_mode'] = $info_audio['bitrate_mode'];
  114. $info_audio['streams'][$stream_index]['lossless'] = $info_audio['lossless'];
  115. $info_audio['streams'][$stream_index]['dataformat'] = $info_audio_dataformat;
  116. }
  117. if (isset($info_riff_wave['rgad'][0]['data'])) {
  118. // shortcuts
  119. $rgadData = &$info_riff_wave['rgad'][0]['data'];
  120. $info_riff_raw['rgad'] = array ('track'=>array(), 'album'=>array());
  121. $info_riff_raw_rgad = &$info_riff_raw['rgad'];
  122. $info_riff_raw_rgad_track = &$info_riff_raw_rgad['track'];
  123. $info_riff_raw_rgad_album = &$info_riff_raw_rgad['album'];
  124. $info_riff_raw_rgad['fPeakAmplitude'] = getid3_riff::BigEndian2Float(strrev(substr($rgadData, 0, 4))); // LittleEndian2Float()
  125. $info_riff_raw_rgad['nRadioRgAdjust'] = getid3_lib::$endian_function(substr($rgadData, 4, 2));
  126. $info_riff_raw_rgad['nAudiophileRgAdjust'] = getid3_lib::$endian_function(substr($rgadData, 6, 2));
  127. $n_track_rg_adjust_bit_string = str_pad(decbin($info_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
  128. $n_album_rg_adjust_bit_string = str_pad(decbin($info_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
  129. $info_riff_raw_rgad_track['name'] = bindec(substr($n_track_rg_adjust_bit_string, 0, 3));
  130. $info_riff_raw_rgad_track['originator'] = bindec(substr($n_track_rg_adjust_bit_string, 3, 3));
  131. $info_riff_raw_rgad_track['signbit'] = bindec($n_track_rg_adjust_bit_string[6]);
  132. $info_riff_raw_rgad_track['adjustment'] = bindec(substr($n_track_rg_adjust_bit_string, 7, 9));
  133. $info_riff_raw_rgad_album['name'] = bindec(substr($n_album_rg_adjust_bit_string, 0, 3));
  134. $info_riff_raw_rgad_album['originator'] = bindec(substr($n_album_rg_adjust_bit_string, 3, 3));
  135. $info_riff_raw_rgad_album['signbit'] = bindec($n_album_rg_adjust_bit_string[6]);
  136. $info_riff_raw_rgad_album['adjustment'] = bindec(substr($n_album_rg_adjust_bit_string, 7, 9));
  137. $info_riff['rgad']['peakamplitude'] = $info_riff_raw_rgad['fPeakAmplitude'];
  138. if (($info_riff_raw_rgad_track['name'] != 0) && ($info_riff_raw_rgad_track['originator'] != 0)) {
  139. $info_riff['rgad']['track']['name'] = getid3_lib_replaygain::NameLookup($info_riff_raw_rgad_track['name']);
  140. $info_riff['rgad']['track']['originator'] = getid3_lib_replaygain::OriginatorLookup($info_riff_raw_rgad_track['originator']);
  141. $info_riff['rgad']['track']['adjustment'] = getid3_lib_replaygain::AdjustmentLookup($info_riff_raw_rgad_track['adjustment'], $info_riff_raw_rgad_track['signbit']);
  142. }
  143. if (($info_riff_raw_rgad_album['name'] != 0) && ($info_riff_raw_rgad_album['originator'] != 0)) {
  144. $info_riff['rgad']['album']['name'] = getid3_lib_replaygain::NameLookup($info_riff_raw_rgad_album['name']);
  145. $info_riff['rgad']['album']['originator'] = getid3_lib_replaygain::OriginatorLookup($info_riff_raw_rgad_album['originator']);
  146. $info_riff['rgad']['album']['adjustment'] = getid3_lib_replaygain::AdjustmentLookup($info_riff_raw_rgad_album['adjustment'], $info_riff_raw_rgad_album['signbit']);
  147. }
  148. }
  149. if (isset($info_riff_wave['fact'][0]['data'])) {
  150. $info_riff_raw['fact']['NumberOfSamples'] = getid3_lib::$endian_function(substr($info_riff_wave['fact'][0]['data'], 0, 4));
  151. // This should be a good way of calculating exact playtime, but some sample files have had incorrect number of samples, so cannot use this method
  152. // if (!empty($info_riff_raw['fmt ']['nSamplesPerSec'])) {
  153. // $getid3->info['playtime_seconds'] = (float)$info_riff_raw['fact']['NumberOfSamples'] / $info_riff_raw['fmt ']['nSamplesPerSec'];
  154. // }
  155. }
  156. if (!empty($info_riff_raw['fmt ']['nAvgBytesPerSec'])) {
  157. $info_audio['bitrate'] = (int)$info_riff_raw['fmt ']['nAvgBytesPerSec'] * 8;
  158. }
  159. if (isset($info_riff_wave['bext'][0]['data'])) {
  160. $info_riff_wave_bext_0 = &$info_riff_wave['bext'][0];
  161. getid3_lib::ReadSequence('LittleEndian2Int', $info_riff_wave_bext_0, $info_riff_wave_bext_0['data'], 0,
  162. array (
  163. 'title' => -256,
  164. 'author' => -32,
  165. 'reference' => -32,
  166. 'origin_date' => -10,
  167. 'origin_time' => -8,
  168. 'time_reference' => 8,
  169. 'bwf_version' => 1,
  170. 'reserved' => 254
  171. )
  172. );
  173. foreach (array ('title', 'author', 'reference') as $key) {
  174. $info_riff_wave_bext_0[$key] = trim($info_riff_wave_bext_0[$key]);
  175. }
  176. $info_riff_wave_bext_0['coding_history'] = explode("\r\n", trim(substr($info_riff_wave_bext_0['data'], 601)));
  177. $info_riff_wave_bext_0['origin_date_unix'] = gmmktime(substr($info_riff_wave_bext_0['origin_time'], 0, 2),
  178. substr($info_riff_wave_bext_0['origin_time'], 3, 2),
  179. substr($info_riff_wave_bext_0['origin_time'], 6, 2),
  180. substr($info_riff_wave_bext_0['origin_date'], 5, 2),
  181. substr($info_riff_wave_bext_0['origin_date'], 8, 2),
  182. substr($info_riff_wave_bext_0['origin_date'], 0, 4));
  183. $info_riff['comments']['author'][] = $info_riff_wave_bext_0['author'];
  184. $info_riff['comments']['title'][] = $info_riff_wave_bext_0['title'];
  185. }
  186. if (isset($info_riff_wave['MEXT'][0]['data'])) {
  187. $info_riff_wave_mext_0 = &$info_riff_wave['MEXT'][0];
  188. $info_riff_wave_mext_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_mext_0['data'], 0, 2));
  189. $info_riff_wave_mext_0['flags']['homogenous'] = (bool)($info_riff_wave_mext_0['raw']['sound_information'] & 0x0001);
  190. if ($info_riff_wave_mext_0['flags']['homogenous']) {
  191. $info_riff_wave_mext_0['flags']['padding'] = ($info_riff_wave_mext_0['raw']['sound_information'] & 0x0002) ? false : true;
  192. $info_riff_wave_mext_0['flags']['22_or_44'] = (bool)($info_riff_wave_mext_0['raw']['sound_information'] & 0x0004);
  193. $info_riff_wave_mext_0['flags']['free_format'] = (bool)($info_riff_wave_mext_0['raw']['sound_information'] & 0x0008);
  194. $info_riff_wave_mext_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_mext_0['data'], 2, 2));
  195. }
  196. $info_riff_wave_mext_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_mext_0['data'], 6, 2));
  197. $info_riff_wave_mext_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_mext_0['data'], 8, 2));
  198. $info_riff_wave_mext_0['flags']['anciliary_data_left'] = (bool)($info_riff_wave_mext_0['raw']['anciliary_data_def'] & 0x0001);
  199. $info_riff_wave_mext_0['flags']['anciliary_data_free'] = (bool)($info_riff_wave_mext_0['raw']['anciliary_data_def'] & 0x0002);
  200. $info_riff_wave_mext_0['flags']['anciliary_data_right'] = (bool)($info_riff_wave_mext_0['raw']['anciliary_data_def'] & 0x0004);
  201. }
  202. if (isset($info_riff_wave['cart'][0]['data'])) {
  203. $info_riff_wave_cart_0 = &$info_riff_wave['cart'][0];
  204. getid3_lib::ReadSequence('LittleEndian2Int', $info_riff_wave_cart_0, $info_riff_wave_cart_0['data'], 0,
  205. array (
  206. 'version' => -4,
  207. 'title' => -64,
  208. 'artist' => -64,
  209. 'cut_id' => -64,
  210. 'client_id' => -64,
  211. 'category' => -64,
  212. 'classification' => -64,
  213. 'out_cue' => -64,
  214. 'start_date' => -10,
  215. 'start_time' => -8,
  216. 'end_date' => -10,
  217. 'end_time' => -8,
  218. 'producer_app_id' => -64,
  219. 'producer_app_version' => -64,
  220. 'user_defined_text' => -64,
  221. )
  222. );
  223. foreach (array ('artist', 'cut_id', 'client_id', 'category', 'classification', 'out_cue', 'start_date', 'start_time', 'end_date', 'end_time', 'producer_app_id', 'producer_app_version', 'user_defined_text') as $key) {
  224. $info_riff_wave_cart_0[$key] = trim($info_riff_wave_cart_0[$key]);
  225. }
  226. $info_riff_wave_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_cart_0['data'], 680, 4), true);
  227. for ($i = 0; $i < 8; $i++) {
  228. $info_riff_wave_cart_0['post_time'][$i]['usage_fourcc'] = substr($info_riff_wave_cart_0['data'], 684 + ($i * 8), 4);
  229. $info_riff_wave_cart_0['post_time'][$i]['timer_value'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_cart_0['data'], 684 + ($i * 8) + 4, 4));
  230. }
  231. $info_riff_wave_cart_0['url'] = trim(substr($info_riff_wave_cart_0['data'], 748, 1024));
  232. $info_riff_wave_cart_0['tag_text'] = explode("\r\n", trim(substr($info_riff_wave_cart_0['data'], 1772)));
  233. $info_riff['comments']['artist'][] = $info_riff_wave_cart_0['artist'];
  234. $info_riff['comments']['title'][] = $info_riff_wave_cart_0['title'];
  235. }
  236. if (isset($info_riff_wave['SNDM'][0]['data'])) {
  237. // SoundMiner metadata
  238. // shortcuts
  239. $info_riff_wave_SNDM_0 = &$info_riff_wave['SNDM'][0];
  240. $info_riff_wave_SNDM_0_data = &$info_riff_wave_SNDM_0['data'];
  241. $SNDM_startoffset = 0;
  242. $SNDM_endoffset = $info_riff_wave_SNDM_0['size'];
  243. while ($SNDM_startoffset < $SNDM_endoffset) {
  244. $SNDM_thisTagOffset = 0;
  245. $SNDM_thisTagSize = getid3_lib::BigEndian2Int(substr($info_riff_wave_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4));
  246. $SNDM_thisTagOffset += 4;
  247. $SNDM_thisTagKey = substr($info_riff_wave_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4);
  248. $SNDM_thisTagOffset += 4;
  249. $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int(substr($info_riff_wave_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
  250. $SNDM_thisTagOffset += 2;
  251. $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($info_riff_wave_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
  252. $SNDM_thisTagOffset += 2;
  253. $SNDM_thisTagDataText = substr($info_riff_wave_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize);
  254. $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
  255. if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
  256. $getid3->warning('RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($info_riff_wave_SNDM_0['offset'] + $SNDM_startoffset).')');
  257. break;
  258. } elseif ($SNDM_thisTagSize <= 0) {
  259. $getid3->warning('RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($info_riff_wave_SNDM_0['offset'] + $SNDM_startoffset).')');
  260. break;
  261. }
  262. $SNDM_startoffset += $SNDM_thisTagSize;
  263. $info_riff_wave_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
  264. $parsedkey = $this->RIFFwaveSNDMtagLookup($SNDM_thisTagKey);
  265. if ($parsedkey) {
  266. $info_riff_wave_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
  267. } else {
  268. $getid3->warning('RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($info_riff_wave_SNDM_0['offset'] + $SNDM_startoffset).')');
  269. }
  270. }
  271. $tagmapping = array(
  272. 'tracktitle'=>'title',
  273. 'category' =>'genre',
  274. 'cdtitle' =>'album',
  275. 'tracktitle'=>'title',
  276. );
  277. foreach ($tagmapping as $fromkey => $tokey) {
  278. if (isset($info_riff_wave_SNDM_0['parsed'][$fromkey])) {
  279. $info_riff['comments'][$tokey][] = $info_riff_wave_SNDM_0['parsed'][$fromkey];
  280. }
  281. }
  282. }
  283. if (!isset($info_audio['bitrate']) && isset($info_riff_audio[$stream_index]['bitrate'])) {
  284. $info_audio['bitrate'] = $info_riff_audio[$stream_index]['bitrate'];
  285. $getid3->info['playtime_seconds'] = (float)((($info_avdataend - $info_avdataoffset) * 8) / $info_audio['bitrate']);
  286. }
  287. if (@$getid3->info['wavpack']) {
  288. if (!$this->data_string_flag) {
  289. $info_audio_dataformat = 'wavpack';
  290. $info_audio['bitrate_mode'] = 'vbr';
  291. $info_audio['encoder'] = 'WavPack v'.$getid3->info['wavpack']['version'];
  292. // Reset to the way it was - RIFF parsing will have messed this up
  293. $info_avdataend = $original['avdataend'];
  294. $info_audio['bitrate'] = (($info_avdataend - $info_avdataoffset) * 8) / $getid3->info['playtime_seconds'];
  295. $this->fseek($info_avdataoffset - 44, SEEK_SET);
  296. $riff_data = $this->fread(44);
  297. $orignal_riff_header_size = getid3_lib::LittleEndian2Int(substr($riff_data, 4, 4)) + 8;
  298. $orignal_riff_data_size = getid3_lib::LittleEndian2Int(substr($riff_data, 40, 4)) + 44;
  299. if ($orignal_riff_header_size > $orignal_riff_data_size) {
  300. $info_avdataend -= ($orignal_riff_header_size - $orignal_riff_data_size);
  301. $this->fseek($info_avdataend, SEEK_SET);
  302. $riff_data .= $this->fread($orignal_riff_header_size - $orignal_riff_data_size);
  303. }
  304. // move the data chunk after all other chunks (if any)
  305. // so that the RIFF parser doesn't see EOF when trying
  306. // to skip over the data chunk
  307. $riff_data = substr($riff_data, 0, 36).substr($riff_data, 44).substr($riff_data, 36, 8);
  308. // Save audio info key
  309. $saved_info_audio = $info_audio;
  310. // Analyze riff_data
  311. $this->AnalyzeString($riff_data);
  312. // Restore info key
  313. $info_audio = $saved_info_audio;
  314. }
  315. }
  316. if (isset($info_riff_raw['fmt ']['wFormatTag'])) {
  317. switch ($info_riff_raw['fmt ']['wFormatTag']) {
  318. case 0x08AE: // ClearJump LiteWave
  319. $info_audio['bitrate_mode'] = 'vbr';
  320. $info_audio_dataformat = 'litewave';
  321. //typedef struct tagSLwFormat {
  322. // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags
  323. // DWORD m_dwScale; // scale factor for lossy compression
  324. // DWORD m_dwBlockSize; // number of samples in encoded blocks
  325. // WORD m_wQuality; // alias for the scale factor
  326. // WORD m_wMarkDistance; // distance between marks in bytes
  327. // WORD m_wReserved;
  328. //
  329. // //following paramters are ignored if CF_FILESRC is not set
  330. // DWORD m_dwOrgSize; // original file size in bytes
  331. // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file
  332. // DWORD m_dwRiffChunkSize; // riff chunk size in the original file
  333. //
  334. // PCMWAVEFORMAT m_OrgWf; // original wave format
  335. // }SLwFormat, *PSLwFormat;
  336. $info_riff['litewave']['raw'] = array ();
  337. $info_riff_litewave = &$info_riff['litewave'];
  338. $info_riff_litewave_raw = &$info_riff_litewave['raw'];
  339. getid3_lib::ReadSequence('LittleEndian2Int', $info_riff_litewave_raw, $info_riff_wave['fmt '][0]['data'], 18,
  340. array (
  341. 'compression_method' => 1,
  342. 'compression_flags' => 1,
  343. 'm_dwScale' => 4,
  344. 'm_dwBlockSize' => 4,
  345. 'm_wQuality' => 2,
  346. 'm_wMarkDistance' => 2,
  347. 'm_wReserved' => 2,
  348. 'm_dwOrgSize' => 4,
  349. 'm_bFactExists' => 2,
  350. 'm_dwRiffChunkSize' => 4
  351. )
  352. );
  353. //$info_riff_litewave['quality_factor'] = intval(round((2000 - $info_riff_litewave_raw['m_dwScale']) / 20));
  354. $info_riff_litewave['quality_factor'] = $info_riff_litewave_raw['m_wQuality'];
  355. $info_riff_litewave['flags']['raw_source'] = ($info_riff_litewave_raw['compression_flags'] & 0x01) ? false : true;
  356. $info_riff_litewave['flags']['vbr_blocksize'] = ($info_riff_litewave_raw['compression_flags'] & 0x02) ? false : true;
  357. $info_riff_litewave['flags']['seekpoints'] = (bool)($info_riff_litewave_raw['compression_flags'] & 0x04);
  358. $info_audio['lossless'] = (($info_riff_litewave_raw['m_wQuality'] == 100) ? true : false);
  359. $info_audio['encoder_options'] = '-q'.$info_riff_litewave['quality_factor'];
  360. break;
  361. }
  362. }
  363. if ($info_avdataend > $getid3->info['filesize']) {
  364. switch (@$info_audio_dataformat) {
  365. case 'wavpack': // WavPack
  366. case 'lpac': // LPAC
  367. case 'ofr': // OptimFROG
  368. case 'ofs': // OptimFROG DualStream
  369. // lossless compressed audio formats that keep original RIFF headers - skip warning
  370. break;
  371. case 'litewave':
  372. if (($info_avdataend - $getid3->info['filesize']) == 1) {
  373. // LiteWave appears to incorrectly *not* pad actual output file
  374. // to nearest WORD boundary so may appear to be short by one
  375. // byte, in which case - skip warning
  376. } else {
  377. // Short by more than one byte, throw warning
  378. $getid3->warning('Probably truncated file - expecting '.$info_riff[$riff_sub_type]['data'][0]['size'].' bytes of data, only found '.($getid3->info['filesize'] - $info_avdataoffset).' (short by '.($info_riff[$riff_sub_type]['data'][0]['size'] - ($getid3->info['filesize'] - $info_avdataoffset)).' bytes)');
  379. }
  380. break;
  381. default:
  382. if ((($info_avdataend - $getid3->info['filesize']) == 1) && (($info_riff[$riff_sub_type]['data'][0]['size'] % 2) == 0) && ((($getid3->info['filesize'] - $info_avdataoffset) % 2) == 1)) {
  383. // output file appears to be incorrectly *not* padded to nearest WORD boundary
  384. // Output less severe warning
  385. $getid3->warning('File should probably be padded to nearest WORD boundary, but it is not (expecting '.$info_riff[$riff_sub_type]['data'][0]['size'].' bytes of data, only found '.($getid3->info['filesize'] - $info_avdataoffset).' therefore short by '.($info_riff[$riff_sub_type]['data'][0]['size'] - ($getid3->info['filesize'] - $info_avdataoffset)).' bytes)');
  386. $info_avdataend = $getid3->info['filesize'];
  387. break;
  388. }
  389. // Short by more than one byte, throw warning
  390. $getid3->warning('Probably truncated file - expecting '.$info_riff[$riff_sub_type]['data'][0]['size'].' bytes of data, only found '.($getid3->info['filesize'] - $info_avdataoffset).' (short by '.($info_riff[$riff_sub_type]['data'][0]['size'] - ($getid3->info['filesize'] - $info_avdataoffset)).' bytes)');
  391. $info_avdataend = $getid3->info['filesize'];
  392. break;
  393. }
  394. }
  395. if (!empty($getid3->info['mpeg']['audio']['LAME']['audio_bytes'])) {
  396. if ((($info_avdataend - $info_avdataoffset) - $getid3->info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
  397. $info_avdataend--;
  398. $getid3->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
  399. }
  400. }
  401. if (@$info_audio_dataformat == 'ac3') {
  402. unset($info_audio['bits_per_sample']);
  403. if (!empty($getid3->info['ac3']['bitrate']) && ($getid3->info['ac3']['bitrate'] != $info_audio['bitrate'])) {
  404. $info_audio['bitrate'] = $getid3->info['ac3']['bitrate'];
  405. }
  406. }
  407. break;
  408. case 'AVI ':
  409. $info_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
  410. $info_video['dataformat'] = 'avi';
  411. $getid3->info['mime_type'] = 'video/avi';
  412. if (isset($info_riff[$riff_sub_type]['movi']['offset'])) {
  413. $info_avdataoffset = $info_riff[$riff_sub_type]['movi']['offset'] + 8;
  414. $info_avdataend = $info_avdataoffset + $info_riff[$riff_sub_type]['movi']['size'];
  415. if ($info_avdataend > $getid3->info['filesize']) {
  416. $getid3->warning('Probably truncated file - expecting '.$info_riff[$riff_sub_type]['movi']['size'].' bytes of data, only found '.($getid3->info['filesize'] - $info_avdataoffset).' (short by '.($info_riff[$riff_sub_type]['movi']['size'] - ($getid3->info['filesize'] - $info_avdataoffset)).' bytes)');
  417. $info_avdataend = $getid3->info['filesize'];
  418. }
  419. }
  420. if (isset($info_riff['AVI ']['hdrl']['avih'][$stream_index]['data'])) {
  421. $avihData = $info_riff['AVI ']['hdrl']['avih'][$stream_index]['data'];
  422. $info_riff_raw['avih'] = array ();
  423. $info_riff_raw_avih = &$info_riff_raw['avih'];
  424. getid3_lib::ReadSequence($this->endian_function, $info_riff_raw_avih, $avihData, 0,
  425. array (
  426. 'dwMicroSecPerFrame' => 4, // frame display rate (or 0L)
  427. 'dwMaxBytesPerSec' => 4, // max. transfer rate
  428. 'dwPaddingGranularity' => 4, // pad to multiples of this size; normally 2K.
  429. 'dwFlags' => 4, // the ever-present flags
  430. 'dwTotalFrames' => 4, // # frames in file
  431. 'dwInitialFrames' => 4,
  432. 'dwStreams' => 4,
  433. 'dwSuggestedBufferSize' => 4,
  434. 'dwWidth' => 4,
  435. 'dwHeight' => 4,
  436. 'dwScale' => 4,
  437. 'dwRate' => 4,
  438. 'dwStart' => 4,
  439. 'dwLength' => 4
  440. )
  441. );
  442. $info_riff_raw_avih['flags']['hasindex'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00000010);
  443. $info_riff_raw_avih['flags']['mustuseindex'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00000020);
  444. $info_riff_raw_avih['flags']['interleaved'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00000100);
  445. $info_riff_raw_avih['flags']['trustcktype'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00000800);
  446. $info_riff_raw_avih['flags']['capturedfile'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00010000);
  447. $info_riff_raw_avih['flags']['copyrighted'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00020010);
  448. $info_riff_video[$stream_index] = array ();
  449. $info_riff_video_current = &$info_riff_video[$stream_index];
  450. if ($info_riff_raw_avih['dwWidth'] > 0) {
  451. $info_riff_video_current['frame_width'] = $info_riff_raw_avih['dwWidth'];
  452. $info_video['resolution_x'] = $info_riff_video_current['frame_width'];
  453. }
  454. if ($info_riff_raw_avih['dwHeight'] > 0) {
  455. $info_riff_video_current['frame_height'] = $info_riff_raw_avih['dwHeight'];
  456. $info_video['resolution_y'] = $info_riff_video_current['frame_height'];
  457. }
  458. if ($info_riff_raw_avih['dwTotalFrames'] > 0) {
  459. $info_riff_video_current['total_frames'] = $info_riff_raw_avih['dwTotalFrames'];
  460. $info_video['total_frames'] = $info_riff_video_current['total_frames'];
  461. }
  462. $info_riff_video_current['frame_rate'] = round(1000000 / $info_riff_raw_avih['dwMicroSecPerFrame'], 3);
  463. $info_video['frame_rate'] = $info_riff_video_current['frame_rate'];
  464. }
  465. if (isset($info_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
  466. if (is_array($info_riff['AVI ']['hdrl']['strl']['strh'])) {
  467. for ($i = 0; $i < count($info_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
  468. if (isset($info_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
  469. $strh_data = $info_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
  470. $strh_fcc_type = substr($strh_data, 0, 4);
  471. if (isset($info_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
  472. $strf_data = $info_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
  473. // shortcut
  474. $info_riff_raw_strf_strh_fcc_type_stream_index = &$info_riff_raw['strf'][$strh_fcc_type][$stream_index];
  475. switch ($strh_fcc_type) {
  476. case 'auds':
  477. $info_audio['bitrate_mode'] = 'cbr';
  478. $info_audio_dataformat = 'wav';
  479. if (isset($info_riff_audio) && is_array($info_riff_audio)) {
  480. $stream_index = count($info_riff_audio);
  481. }
  482. $info_riff_audio[$stream_index] = getid3_riff::RIFFparseWAVEFORMATex($strf_data);
  483. $info_audio['wformattag'] = $info_riff_audio[$stream_index]['raw']['wFormatTag'];
  484. // shortcut
  485. $info_audio['streams'][$stream_index] = $info_riff_audio[$stream_index];
  486. $info_audio_streams_currentstream = &$info_audio['streams'][$stream_index];
  487. if (@$info_audio_streams_currentstream['bits_per_sample'] === 0) {
  488. unset($info_audio_streams_currentstream['bits_per_sample']);
  489. }
  490. $info_audio_streams_currentstream['wformattag'] = $info_audio_streams_currentstream['raw']['wFormatTag'];
  491. unset($info_audio_streams_currentstream['raw']);
  492. // shortcut
  493. $info_riff_raw['strf'][$strh_fcc_type][$stream_index] = $info_riff_audio[$stream_index]['raw'];
  494. unset($info_riff_audio[$stream_index]['raw']);
  495. $info_audio = getid3_riff::array_merge_noclobber($info_audio, $info_riff_audio[$stream_index]);
  496. $info_audio['lossless'] = false;
  497. switch ($info_riff_raw_strf_strh_fcc_type_stream_index['wFormatTag']) {
  498. case 0x0001: // PCM
  499. $info_audio_dataformat = 'wav';
  500. $info_audio['lossless'] = true;
  501. break;
  502. case 0x0050: // MPEG Layer 2 or Layer 1
  503. $info_audio_dataformat = 'mp2'; // Assume Layer-2
  504. break;
  505. case 0x0055: // MPEG Layer 3
  506. $info_audio_dataformat = 'mp3';
  507. break;
  508. case 0x00FF: // AAC
  509. $info_audio_dataformat = 'aac';
  510. break;
  511. case 0x0161: // Windows Media v7 / v8 / v9
  512. case 0x0162: // Windows Media Professional v9
  513. case 0x0163: // Windows Media Lossess v9
  514. $info_audio_dataformat = 'wma';
  515. break;
  516. case 0x2000: // AC-3
  517. $info_audio_dataformat = 'ac3';
  518. break;
  519. case 0x2001: // DTS
  520. $info_audio_dataformat = 'dts';
  521. break;
  522. default:
  523. $info_audio_dataformat = 'wav';
  524. break;
  525. }
  526. $info_audio_streams_currentstream['dataformat'] = $info_audio_dataformat;
  527. $info_audio_streams_currentstream['lossless'] = $info_audio['lossless'];
  528. $info_audio_streams_currentstream['bitrate_mode'] = $info_audio['bitrate_mode'];
  529. break;
  530. case 'iavs':
  531. case 'vids':
  532. // shortcut
  533. $info_riff_raw['strh'][$i] = array ();
  534. $info_riff_raw_strh_current = &$info_riff_raw['strh'][$i];
  535. getid3_lib::ReadSequence($this->endian_function, $info_riff_raw_strh_current, $strh_data, 0,
  536. array (
  537. 'fccType' => -4, // same as $strh_fcc_type;
  538. 'fccHandler' => -4,
  539. 'dwFlags' => 4, // Contains AVITF_* flags
  540. 'wPriority' => 2,
  541. 'wLanguage' => 2,
  542. 'dwInitialFrames' => 4,
  543. 'dwScale' => 4,
  544. 'dwRate' => 4,
  545. 'dwStart' => 4,
  546. 'dwLength' => 4,
  547. 'dwSuggestedBufferSize' => 4,
  548. 'dwQuality' => 4,
  549. 'dwSampleSize' => 4,
  550. 'rcFrame' => 4
  551. )
  552. );
  553. $info_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($info_riff_raw_strh_current['fccHandler']);
  554. $info_video['fourcc'] = $info_riff_raw_strh_current['fccHandler'];
  555. if (!$info_riff_video_current['codec'] && isset($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']) && getid3_riff::RIFFfourccLookup($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc'])) {
  556. $info_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']);
  557. $info_video['fourcc'] = $info_riff_raw_strf_strh_fcc_type_stream_index['fourcc'];
  558. }
  559. $info_video['codec'] = $info_riff_video_current['codec'];
  560. $info_video['pixel_aspect_ratio'] = (float)1;
  561. switch ($info_riff_raw_strh_current['fccHandler']) {
  562. case 'HFYU': // Huffman Lossless Codec
  563. case 'IRAW': // Intel YUV Uncompressed
  564. case 'YUY2': // Uncompressed YUV 4:2:2
  565. $info_video['lossless'] = true;
  566. break;
  567. default:
  568. $info_video['lossless'] = false;
  569. break;
  570. }
  571. switch ($strh_fcc_type) {
  572. case 'vids':
  573. getid3_lib::ReadSequence($this->endian_function, $info_riff_raw_strf_strh_fcc_type_stream_index, $strf_data, 0,
  574. array (
  575. 'biSize' => 4, // number of bytes required by the BITMAPINFOHEADER structure
  576. 'biWidth' => 4, // width of the bitmap in pixels
  577. 'biHeight' => 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
  578. 'biPlanes' => 2, // number of color planes on the target device. In most cases this value must be set to 1
  579. 'biBitCount' => 2, // Specifies the number of bits per pixels
  580. 'fourcc' => -4, //
  581. 'biSizeImage' => 4, // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
  582. 'biXPelsPerMeter' => 4, // horizontal resolution, in pixels per metre, of the target device
  583. 'biYPelsPerMeter' => 4, // vertical resolution, in pixels per metre, of the target device
  584. 'biClrUsed' => 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
  585. 'biClrImportant' => 4 // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
  586. )
  587. );
  588. $info_video['bits_per_sample'] = $info_riff_raw_strf_strh_fcc_type_stream_index['biBitCount'];
  589. if ($info_riff_video_current['codec'] == 'DV') {
  590. $info_riff_video_current['dv_type'] = 2;
  591. }
  592. break;
  593. case 'iavs':
  594. $info_riff_video_current['dv_type'] = 1;
  595. break;
  596. }
  597. break;
  598. default:
  599. $getid3->warning('Unhandled fccType for stream ('.$i.'): "'.$strh_fcc_type.'"');
  600. break;
  601. }
  602. }
  603. }
  604. if (isset($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']) && getid3_riff::RIFFfourccLookup($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc'])) {
  605. $info_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']);
  606. $info_video['codec'] = $info_riff_video_current['codec'];
  607. $info_video['fourcc'] = $info_riff_raw_strf_strh_fcc_type_stream_index['fourcc'];
  608. switch ($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']) {
  609. case 'HFYU': // Huffman Lossless Codec
  610. case 'IRAW': // Intel YUV Uncompressed
  611. case 'YUY2': // Uncompressed YUV 4:2:2
  612. $info_video['lossless'] = true;
  613. $info_video['bits_per_sample'] = 24;
  614. break;
  615. default:
  616. $info_video['lossless'] = false;
  617. $info_video['bits_per_sample'] = 24;
  618. break;
  619. }
  620. }
  621. }
  622. }
  623. }
  624. break;
  625. case 'CDDA':
  626. $info_audio['bitrate_mode'] = 'cbr';
  627. $info_audio_dataformat = 'cda';
  628. $info_audio['lossless'] = true;
  629. unset($getid3->info['mime_type']);
  630. $info_avdataoffset = 44;
  631. if (isset($info_riff['CDDA']['fmt '][0]['data'])) {
  632. $info_riff_cdda_fmt_0 = &$info_riff['CDDA']['fmt '][0];
  633. getid3_lib::ReadSequence($this->endian_function, $info_riff_cdda_fmt_0, $info_riff_cdda_fmt_0['data'], 0,
  634. array (
  635. 'unknown1' => 2,
  636. 'track_num' => 2,
  637. 'disc_id' => 4,
  638. 'start_offset_frame' => 4,
  639. 'playtime_frames' => 4,
  640. 'unknown6' => 4,
  641. 'unknown7' => 4
  642. )
  643. );
  644. $info_riff_cdda_fmt_0['start_offset_seconds'] = (float)$info_riff_cdda_fmt_0['start_offset_frame'] / 75;
  645. $info_riff_cdda_fmt_0['playtime_seconds'] = (float)$info_riff_cdda_fmt_0['playtime_frames'] / 75;
  646. $getid3->info['comments']['track'] = $info_riff_cdda_fmt_0['track_num'];
  647. $getid3->info['playtime_seconds'] = $info_riff_cdda_fmt_0['playtime_seconds'];
  648. // hardcoded data for CD-audio
  649. $info_audio['sample_rate'] = 44100;
  650. $info_audio['channels'] = 2;
  651. $info_audio['bits_per_sample'] = 16;
  652. $info_audio['bitrate'] = $info_audio['sample_rate'] * $info_audio['channels'] * $info_audio['bits_per_sample'];
  653. $info_audio['bitrate_mode'] = 'cbr';
  654. }
  655. break;
  656. case 'AIFF':
  657. case 'AIFC':
  658. $info_audio['bitrate_mode'] = 'cbr';
  659. $info_audio_dataformat = 'aiff';
  660. $info_audio['lossless'] = true;
  661. $getid3->info['mime_type'] = 'audio/x-aiff';
  662. if (isset($info_riff[$riff_sub_type]['SSND'][0]['offset'])) {
  663. $info_avdataoffset = $info_riff[$riff_sub_type]['SSND'][0]['offset'] + 8;
  664. $info_avdataend = $info_avdataoffset + $info_riff[$riff_sub_type]['SSND'][0]['size'];
  665. if ($info_avdataend > $getid3->info['filesize']) {
  666. if (($info_avdataend == ($getid3->info['filesize'] + 1)) && (($getid3->info['filesize'] % 2) == 1)) {
  667. // structures rounded to 2-byte boundary, but dumb encoders
  668. // forget to pad end of file to make this actually work
  669. } else {
  670. $getid3->warning('Probable truncated AIFF file: expecting '.$info_riff[$riff_sub_type]['SSND'][0]['size'].' bytes of audio data, only '.($getid3->info['filesize'] - $info_avdataoffset).' bytes found');
  671. }
  672. $info_avdataend = $getid3->info['filesize'];
  673. }
  674. }
  675. if (isset($info_riff[$riff_sub_type]['COMM'][0]['data'])) {
  676. // shortcut
  677. $info_riff_RIFFsubtype_COMM_0_data = &$info_riff[$riff_sub_type]['COMM'][0]['data'];
  678. $info_riff_audio['channels'] = getid3_lib::BigEndianSyncSafe2Int(substr($info_riff_RIFFsubtype_COMM_0_data, 0, 2));
  679. $info_riff_audio['total_samples'] = getid3_lib::BigEndian2Int( substr($info_riff_RIFFsubtype_COMM_0_data, 2, 4));
  680. $info_riff_audio['bits_per_sample'] = getid3_lib::BigEndianSyncSafe2Int(substr($info_riff_RIFFsubtype_COMM_0_data, 6, 2));
  681. $info_riff_audio['sample_rate'] = (int)getid3_riff::BigEndian2Float(substr($info_riff_RIFFsubtype_COMM_0_data, 8, 10));
  682. if ($info_riff[$riff_sub_type]['COMM'][0]['size'] > 18) {
  683. $info_riff_audio['codec_fourcc'] = substr($info_riff_RIFFsubtype_COMM_0_data, 18, 4);
  684. $codec_name_size = getid3_lib::BigEndian2Int(substr($info_riff_RIFFsubtype_COMM_0_data, 22, 1));
  685. $info_riff_audio['codec_name'] = substr($info_riff_RIFFsubtype_COMM_0_data, 23, $codec_name_size);
  686. switch ($info_riff_audio['codec_name']) {
  687. case 'NONE':
  688. $info_audio['codec'] = 'Pulse Code Modulation (PCM)';
  689. $info_audio['lossless'] = true;
  690. break;
  691. case '':
  692. switch ($info_riff_audio['codec_fourcc']) {
  693. // http://developer.apple.com/qa/snd/snd07.html
  694. case 'sowt':
  695. $info_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
  696. $info_audio['lossless'] = true;
  697. break;
  698. case 'twos':
  699. $info_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
  700. $info_audio['lossless'] = true;
  701. break;
  702. default:
  703. break;
  704. }
  705. break;
  706. default:
  707. $info_audio['codec'] = $info_riff_audio['codec_name'];
  708. $info_audio['lossless'] = false;
  709. break;
  710. }
  711. }
  712. $info_audio['channels'] = $info_riff_audio['channels'];
  713. if ($info_riff_audio['bits_per_sample'] > 0) {
  714. $info_audio['bits_per_sample'] = $info_riff_audio['bits_per_sample'];
  715. }
  716. $info_audio['sample_rate'] = $info_riff_audio['sample_rate'];
  717. $getid3->info['playtime_seconds'] = $info_riff_audio['total_samples'] / $info_audio['sample_rate'];
  718. }
  719. if (isset($info_riff[$riff_sub_type]['COMT'])) {
  720. $comment_count = getid3_lib::BigEndian2Int(substr($info_riff[$riff_sub_type]['COMT'][0]['data'], 0, 2));
  721. $offset = 2;
  722. for ($i = 0; $i < $comment_count; $i++) {
  723. $getid3->info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int( substr($info_riff[$riff_sub_type]['COMT'][0]['data'], $offset, 4));
  724. $offset += 4;
  725. $getid3->info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndianSyncSafe2Int(substr($info_riff[$riff_sub_type]['COMT'][0]['data'], $offset, 2));
  726. $offset += 2;
  727. $comment_length = getid3_lib::BigEndian2Int( substr($info_riff[$riff_sub_type]['COMT'][0]['data'], $offset, 2));
  728. $offset += 2;
  729. $getid3->info['comments_raw'][$i]['comment'] = substr($info_riff[$riff_sub_type]['COMT'][0]['data'], $offset, $comment_length);
  730. $offset += $comment_length;
  731. $getid3->info['comments_raw'][$i]['timestamp_unix'] = getid3_riff::DateMac2Unix($getid3->info['comments_raw'][$i]['timestamp']);
  732. $info_riff['comments']['comment'][] = $getid3->info['comments_raw'][$i]['comment'];
  733. }
  734. }
  735. foreach (array ('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment') as $key => $value) {
  736. if (isset($info_riff[$riff_sub_type][$key][0]['data'])) {
  737. $info_riff['comments'][$value][] = $info_riff[$riff_sub_type][$key][0]['data'];
  738. }
  739. }
  740. break;
  741. case '8SVX':
  742. $info_audio['bitrate_mode'] = 'cbr';
  743. $info_audio_dataformat = '8svx';
  744. $info_audio['bits_per_sample'] = 8;
  745. $info_audio['channels'] = 1; // overridden below, if need be
  746. $getid3->info['mime_type'] = 'audio/x-aiff';
  747. if (isset($info_riff[$riff_sub_type]['BODY'][0]['offset'])) {
  748. $info_avdataoffset = $info_riff[$riff_sub_type]['BODY'][0]['offset'] + 8;
  749. $info_avdataend = $info_avdataoffset + $info_riff[$riff_sub_type]['BODY'][0]['size'];
  750. if ($info_avdataend > $getid3->info['filesize']) {
  751. $getid3->warning('Probable truncated AIFF file: expecting '.$info_riff[$riff_sub_type]['BODY'][0]['size'].' bytes of audio data, only '.($getid3->info['filesize'] - $info_avdataoffset).' bytes found');
  752. }
  753. }
  754. if (isset($info_riff[$riff_sub_type]['VHDR'][0]['offset'])) {
  755. // shortcut
  756. $info_riff_riff_sub_type_vhdr_0 = &$info_riff[$riff_sub_type]['VHDR'][0];
  757. getid3_lib::ReadSequence('BigEndian2Int', $info_riff_riff_sub_type_vhdr_0, $info_riff_riff_sub_type_vhdr_0['data'], 0,
  758. array (
  759. 'oneShotHiSamples' => 4,
  760. 'repeatHiSamples' => 4,
  761. 'samplesPerHiCycle' => 4,
  762. 'samplesPerSec' => 2,
  763. 'ctOctave' => 1,
  764. 'sCompression' => 1,
  765. 'Volume' => -4
  766. )
  767. );
  768. $info_riff_riff_sub_type_vhdr_0['Volume'] = getid3_riff::FixedPoint16_16($info_riff_riff_sub_type_vhdr_0['Volume']);
  769. $info_audio['sample_rate'] = $info_riff_riff_sub_type_vhdr_0['samplesPerSec'];
  770. switch ($info_riff_riff_sub_type_vhdr_0['sCompression']) {
  771. case 0:
  772. $info_audio['codec'] = 'Pulse Code Modulation (PCM)';
  773. $info_audio['lossless'] = true;
  774. $actual_bits_per_sample = 8;
  775. break;
  776. case 1:
  777. $info_audio['codec'] = 'Fibonacci-delta encoding';
  778. $info_audio['lossless'] = false;
  779. $actual_bits_per_sample = 4;
  780. break;
  781. default:
  782. $getid3->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"');
  783. break;
  784. }
  785. }
  786. if (isset($info_riff[$riff_sub_type]['CHAN'][0]['data'])) {
  787. $ChannelsIndex = getid3_lib::BigEndian2Int(substr($info_riff[$riff_sub_type]['CHAN'][0]['data'], 0, 4));
  788. switch ($ChannelsIndex) {
  789. case 6: // Stereo
  790. $info_audio['channels'] = 2;
  791. break;
  792. case 2: // Left channel only
  793. case 4: // Right channel only
  794. $info_audio['channels'] = 1;
  795. break;
  796. default:
  797. $getid3->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"');
  798. break;
  799. }
  800. }
  801. foreach (array ('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment') as $key => $value) {
  802. if (isset($info_riff[$riff_sub_type][$key][0]['data'])) {
  803. $info_riff['comments'][$value][] = $info_riff[$riff_sub_type][$key][0]['data'];
  804. }
  805. }
  806. $info_audio['bitrate'] = $info_audio['sample_rate'] * $actual_bits_per_sample * $info_audio['channels'];
  807. if (!empty($info_audio['bitrate'])) {
  808. $getid3->info['playtime_seconds'] = ($info_avdataend - $info_avdataoffset) / ($info_audio['bitrate'] / 8);
  809. }
  810. break;
  811. case 'CDXA':
  812. $getid3->info['mime_type'] = 'video/mpeg';
  813. if (!empty($info_riff['CDXA']['data'][0]['size'])) {
  814. $GETID3_ERRORARRAY = &$getid3->info['warning'];
  815. if (!$getid3->include_module_optional('audio-video.mpeg')) {
  816. $getid3->warning('MPEG skipped because mpeg module is missing.');
  817. }
  818. else {
  819. // Clone getid3 - messing with offsets - better safe than sorry
  820. $clone = clone $getid3;
  821. // Analyse
  822. $mpeg = new getid3_mpeg($clone);
  823. $mpeg->Analyze();
  824. // Import from clone and destroy
  825. $getid3->info['audio'] = $clone->info['audio'];
  826. $getid3->info['video'] = $clone->info['video'];
  827. $getid3->info['mpeg'] = $clone->info['mpeg'];
  828. $getid3->info['warning'] = $clone->info['warning'];
  829. unset($clone);
  830. }
  831. }
  832. break;
  833. default:
  834. throw new getid3_exception('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$riff_sub_type.'" instead');
  835. }
  836. if (@$info_riff_raw['fmt ']['wFormatTag'] == 1) {
  837. // http://www.mega-nerd.com/erikd/Blog/Windiots/dts.html
  838. $this->fseek($getid3->info['avdataoffset'], SEEK_SET);
  839. $bytes4 = $this->fread(4);
  840. // DTSWAV
  841. if (preg_match('/^\xFF\x1F\x00\xE8/s', $bytes4)) {
  842. $info_audio_dataformat = 'dts';
  843. }
  844. // DTS, but this probably shouldn't happen
  845. elseif (preg_match('/^\x7F\xFF\x80\x01/s', $bytes4)) {
  846. $info_audio_dataformat = 'dts';
  847. }
  848. }
  849. if (@is_array($info_riff_wave['DISP'])) {
  850. $info_riff['comments']['title'][] = trim(substr($info_riff_wave['DISP'][count($info_riff_wave['DISP']) - 1]['data'], 4));
  851. }
  852. if (@is_array($info_riff_wave['INFO'])) {
  853. getid3_riff::RIFFCommentsParse($info_riff_wave['INFO'], $info_riff['comments']);
  854. }
  855. if (isset($info_riff_wave['INFO']) && is_array($info_riff_wave['INFO'])) {
  856. foreach (array ('IARL' => 'archivallocation', 'IART' => 'artist', 'ICDS' => 'costumedesigner', 'ICMS' => 'commissionedby', 'ICMT' => 'comment', 'ICNT' => 'country', 'ICOP' => 'copyright', 'ICRD' => 'creationdate', 'IDIM' => 'dimensions', 'IDIT' => 'digitizationdate', 'IDPI' => 'resolution', 'IDST' => 'distributor', 'IEDT' => 'editor', 'IENG' => 'engineers', 'IFRM' => 'accountofparts', 'IGNR' => 'genre', 'IKEY' => 'keywords', 'ILGT' => 'lightness', 'ILNG' => 'language', 'IMED' => 'orignalmedium', 'IMUS' => 'composer', 'INAM' => 'title', 'IPDS' => 'productiondesigner', 'IPLT' => 'palette', 'IPRD' => 'product', 'IPRO' => 'producer', 'IPRT' => 'part', 'IRTD' => 'rating', 'ISBJ' => 'subject', 'ISFT' => 'software', 'ISGN' => 'secondarygenre', 'ISHP' => 'sharpness', 'ISRC' => 'sourcesupplier', 'ISRF' => 'digitizationsource', 'ISTD' => 'productionstudio', 'ISTR' => 'starring', 'ITC…

Large files files are truncated, but you can click here to view the full file