PageRenderTime 53ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 1ms

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

https://bitbucket.org/holyfield/getid3
PHP | 2410 lines | 1442 code | 248 blank | 720 comment | 298 complexity | ea51b9b326e29ec6aeb499bc6d871067 MD5 | raw file
Possible License(s): GPL-2.0

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

  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. /////////////////////////////////////////////////////////////////
  7. // See readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  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. // module.audio.dts.php (optional) //
  17. // ///
  18. /////////////////////////////////////////////////////////////////
  19. getid3_lib::IncludeDependency ( GETID3_INCLUDEPATH . 'module.audio.mp3.php', __FILE__, true );
  20. class getid3_riff extends getid3_handler {
  21. function Analyze() {
  22. $info = &$this->getid3->info;
  23. // initialize these values to an empty array, otherwise they default to NULL
  24. // and you can't append array values to a NULL value
  25. $info ['riff'] = array (
  26. 'raw' => array () );
  27. // Shortcuts
  28. $thisfile_riff = &$info ['riff'];
  29. $thisfile_riff_raw = &$thisfile_riff ['raw'];
  30. $thisfile_audio = &$info ['audio'];
  31. $thisfile_video = &$info ['video'];
  32. $thisfile_audio_dataformat = &$thisfile_audio ['dataformat'];
  33. $thisfile_riff_audio = &$thisfile_riff ['audio'];
  34. $thisfile_riff_video = &$thisfile_riff ['video'];
  35. $Original ['avdataoffset'] = $info ['avdataoffset'];
  36. $Original ['avdataend'] = $info ['avdataend'];
  37. fseek ( $this->getid3->fp, $info ['avdataoffset'], SEEK_SET );
  38. $RIFFheader = fread ( $this->getid3->fp, 12 );
  39. $RIFFsubtype = substr ( $RIFFheader, 8, 4 );
  40. switch (substr ( $RIFFheader, 0, 4 )) {
  41. case 'FORM' :
  42. $info ['fileformat'] = 'aiff';
  43. $thisfile_riff ['header_size'] = $this->EitherEndian2Int ( substr ( $RIFFheader, 4, 4 ) );
  44. $thisfile_riff [$RIFFsubtype] = $this->ParseRIFF ( $info ['avdataoffset'] + 12, $info ['avdataoffset'] + $thisfile_riff ['header_size'] );
  45. break;
  46. case 'RIFF' : // AVI, WAV, etc
  47. case 'SDSS' : // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
  48. case 'RMP3' : // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
  49. $info ['fileformat'] = 'riff';
  50. $thisfile_riff ['header_size'] = $this->EitherEndian2Int ( substr ( $RIFFheader, 4, 4 ) );
  51. if ($RIFFsubtype == 'RMP3') {
  52. // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
  53. $RIFFsubtype = 'WAVE';
  54. }
  55. $thisfile_riff [$RIFFsubtype] = $this->ParseRIFF ( $info ['avdataoffset'] + 12, $info ['avdataoffset'] + $thisfile_riff ['header_size'] );
  56. if (($info ['avdataend'] - $info ['filesize']) == 1) {
  57. // LiteWave appears to incorrectly *not* pad actual output file
  58. // to nearest WORD boundary so may appear to be short by one
  59. // byte, in which case - skip warning
  60. $info ['avdataend'] = $info ['filesize'];
  61. }
  62. $nextRIFFoffset = $Original ['avdataoffset'] + 8 + $thisfile_riff ['header_size']; // 8 = "RIFF" + 32-bit offset
  63. while ( $nextRIFFoffset < min ( $info ['filesize'], $info ['avdataend'] ) ) {
  64. if (! getid3_lib::intValueSupported ( $nextRIFFoffset + 1024 )) {
  65. $info ['error'] [] = 'AVI extends beyond ' . round ( PHP_INT_MAX / 1073741824 ) . 'GB and PHP filesystem functions cannot read that far, playtime is probably wrong';
  66. $info ['warning'] [] = '[avdataend] value may be incorrect, multiple AVIX chunks may be present';
  67. break;
  68. } else {
  69. fseek ( $this->getid3->fp, $nextRIFFoffset, SEEK_SET );
  70. $nextRIFFheader = fread ( $this->getid3->fp, 12 );
  71. if ($nextRIFFoffset == ($info ['avdataend'] - 1)) {
  72. if (substr ( $nextRIFFheader, 0, 1 ) == "\x00") {
  73. // RIFF padded to WORD boundary, we're actually already at the end
  74. break;
  75. }
  76. }
  77. $nextRIFFheaderID = substr ( $nextRIFFheader, 0, 4 );
  78. $nextRIFFsize = $this->EitherEndian2Int ( substr ( $nextRIFFheader, 4, 4 ) );
  79. $nextRIFFtype = substr ( $nextRIFFheader, 8, 4 );
  80. $chunkdata = array ();
  81. $chunkdata ['offset'] = $nextRIFFoffset + 8;
  82. $chunkdata ['size'] = $nextRIFFsize;
  83. $nextRIFFoffset = $chunkdata ['offset'] + $chunkdata ['size'];
  84. switch ($nextRIFFheaderID) {
  85. case 'RIFF' :
  86. $info ['avdataend'] = $nextRIFFoffset;
  87. if (! getid3_lib::intValueSupported ( $info ['avdataend'] )) {
  88. $info ['error'] [] = 'AVI extends beyond ' . round ( PHP_INT_MAX / 1073741824 ) . 'GB and PHP filesystem functions cannot read that far, playtime is probably wrong';
  89. $info ['warning'] [] = '[avdataend] value may be incorrect, multiple AVIX chunks may be present';
  90. }
  91. $chunkdata ['chunks'] = $this->ParseRIFF ( $chunkdata ['offset'] + 4, $chunkdata ['offset'] + $chunkdata ['size'] );
  92. if (! isset ( $thisfile_riff [$nextRIFFtype] )) {
  93. $thisfile_riff [$nextRIFFtype] = array ();
  94. }
  95. $thisfile_riff [$nextRIFFtype] [] = $chunkdata;
  96. break;
  97. case 'JUNK' :
  98. // ignore
  99. $thisfile_riff [$nextRIFFheaderID] [] = $chunkdata;
  100. break;
  101. default :
  102. if ($info ['filesize'] == ($chunkdata ['offset'] - 8 + 128)) {
  103. $DIVXTAG = $nextRIFFheader . fread ( $this->getid3->fp, 128 - 12 );
  104. if (substr ( $DIVXTAG, - 7 ) == 'DIVXTAG') {
  105. // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file
  106. $info ['warning'] [] = 'Found wrongly-structured DIVXTAG at offset ' . (ftell ( $this->getid3->fp ) - 128 + 12) . ', parsing anyway';
  107. $thisfile_riff ['DIVXTAG'] = $this->ParseDIVXTAG ( $DIVXTAG );
  108. foreach ( $thisfile_riff ['DIVXTAG'] as $key => $value ) {
  109. if ($value && ! preg_match ( '#_id$#', $key )) {
  110. $thisfile_riff ['comments'] [$key] [] = $value;
  111. }
  112. }
  113. break 2;
  114. }
  115. }
  116. $info ['warning'] [] = 'expecting "RIFF" or "JUNK" at ' . $nextRIFFoffset . ', found ' . getid3_lib::PrintHexBytes ( substr ( $nextRIFFheader, 0, 4 ) ) . ' - skipping rest of file';
  117. break 2;
  118. }
  119. }
  120. }
  121. if ($RIFFsubtype == 'WAVE') {
  122. $thisfile_riff_WAVE = &$thisfile_riff ['WAVE'];
  123. }
  124. break;
  125. default :
  126. $info ['error'] [] = 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "' . $RIFFsubtype . '" instead';
  127. unset ( $info ['fileformat'] );
  128. return false;
  129. break;
  130. }
  131. $streamindex = 0;
  132. switch ($RIFFsubtype) {
  133. case 'WAVE' :
  134. if (empty ( $thisfile_audio ['bitrate_mode'] )) {
  135. $thisfile_audio ['bitrate_mode'] = 'cbr';
  136. }
  137. if (empty ( $thisfile_audio_dataformat )) {
  138. $thisfile_audio_dataformat = 'wav';
  139. }
  140. if (isset ( $thisfile_riff_WAVE ['data'] [0] ['offset'] )) {
  141. $info ['avdataoffset'] = $thisfile_riff_WAVE ['data'] [0] ['offset'] + 8;
  142. $info ['avdataend'] = $info ['avdataoffset'] + $thisfile_riff_WAVE ['data'] [0] ['size'];
  143. }
  144. if (isset ( $thisfile_riff_WAVE ['fmt '] [0] ['data'] )) {
  145. $thisfile_riff_audio [$streamindex] = getid3_riff::RIFFparseWAVEFORMATex ( $thisfile_riff_WAVE ['fmt '] [0] ['data'] );
  146. $thisfile_audio ['wformattag'] = $thisfile_riff_audio [$streamindex] ['raw'] ['wFormatTag'];
  147. if (! isset ( $thisfile_riff_audio [$streamindex] ['bitrate'] ) || ($thisfile_riff_audio [$streamindex] ['bitrate'] == 0)) {
  148. $info ['error'] [] = 'Corrupt RIFF file: bitrate_audio == zero';
  149. return false;
  150. }
  151. $thisfile_riff_raw ['fmt '] = $thisfile_riff_audio [$streamindex] ['raw'];
  152. unset ( $thisfile_riff_audio [$streamindex] ['raw'] );
  153. $thisfile_audio ['streams'] [$streamindex] = $thisfile_riff_audio [$streamindex];
  154. $thisfile_audio = getid3_lib::array_merge_noclobber ( $thisfile_audio, $thisfile_riff_audio [$streamindex] );
  155. if (substr ( $thisfile_audio ['codec'], 0, strlen ( 'unknown: 0x' ) ) == 'unknown: 0x') {
  156. $info ['warning'] [] = 'Audio codec = ' . $thisfile_audio ['codec'];
  157. }
  158. $thisfile_audio ['bitrate'] = $thisfile_riff_audio [$streamindex] ['bitrate'];
  159. $info ['playtime_seconds'] = ( float ) ((($info ['avdataend'] - $info ['avdataoffset']) * 8) / $thisfile_audio ['bitrate']);
  160. $thisfile_audio ['lossless'] = false;
  161. if (isset ( $thisfile_riff_WAVE ['data'] [0] ['offset'] ) && isset ( $thisfile_riff_raw ['fmt '] ['wFormatTag'] )) {
  162. switch ($thisfile_riff_raw ['fmt '] ['wFormatTag']) {
  163. case 0x0001 : // PCM
  164. $thisfile_audio ['lossless'] = true;
  165. break;
  166. case 0x2000 : // AC-3
  167. $thisfile_audio_dataformat = 'ac3';
  168. break;
  169. default :
  170. // do nothing
  171. break;
  172. }
  173. }
  174. $thisfile_audio ['streams'] [$streamindex] ['wformattag'] = $thisfile_audio ['wformattag'];
  175. $thisfile_audio ['streams'] [$streamindex] ['bitrate_mode'] = $thisfile_audio ['bitrate_mode'];
  176. $thisfile_audio ['streams'] [$streamindex] ['lossless'] = $thisfile_audio ['lossless'];
  177. $thisfile_audio ['streams'] [$streamindex] ['dataformat'] = $thisfile_audio_dataformat;
  178. }
  179. if (isset ( $thisfile_riff_WAVE ['rgad'] [0] ['data'] )) {
  180. // shortcuts
  181. $rgadData = &$thisfile_riff_WAVE ['rgad'] [0] ['data'];
  182. $thisfile_riff_raw ['rgad'] = array (
  183. 'track' => array (),
  184. 'album' => array () );
  185. $thisfile_riff_raw_rgad = &$thisfile_riff_raw ['rgad'];
  186. $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad ['track'];
  187. $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad ['album'];
  188. $thisfile_riff_raw_rgad ['fPeakAmplitude'] = getid3_lib::LittleEndian2Float ( substr ( $rgadData, 0, 4 ) );
  189. $thisfile_riff_raw_rgad ['nRadioRgAdjust'] = $this->EitherEndian2Int ( substr ( $rgadData, 4, 2 ) );
  190. $thisfile_riff_raw_rgad ['nAudiophileRgAdjust'] = $this->EitherEndian2Int ( substr ( $rgadData, 6, 2 ) );
  191. $nRadioRgAdjustBitstring = str_pad ( getid3_lib::Dec2Bin ( $thisfile_riff_raw_rgad ['nRadioRgAdjust'] ), 16, '0', STR_PAD_LEFT );
  192. $nAudiophileRgAdjustBitstring = str_pad ( getid3_lib::Dec2Bin ( $thisfile_riff_raw_rgad ['nAudiophileRgAdjust'] ), 16, '0', STR_PAD_LEFT );
  193. $thisfile_riff_raw_rgad_track ['name'] = getid3_lib::Bin2Dec ( substr ( $nRadioRgAdjustBitstring, 0, 3 ) );
  194. $thisfile_riff_raw_rgad_track ['originator'] = getid3_lib::Bin2Dec ( substr ( $nRadioRgAdjustBitstring, 3, 3 ) );
  195. $thisfile_riff_raw_rgad_track ['signbit'] = getid3_lib::Bin2Dec ( substr ( $nRadioRgAdjustBitstring, 6, 1 ) );
  196. $thisfile_riff_raw_rgad_track ['adjustment'] = getid3_lib::Bin2Dec ( substr ( $nRadioRgAdjustBitstring, 7, 9 ) );
  197. $thisfile_riff_raw_rgad_album ['name'] = getid3_lib::Bin2Dec ( substr ( $nAudiophileRgAdjustBitstring, 0, 3 ) );
  198. $thisfile_riff_raw_rgad_album ['originator'] = getid3_lib::Bin2Dec ( substr ( $nAudiophileRgAdjustBitstring, 3, 3 ) );
  199. $thisfile_riff_raw_rgad_album ['signbit'] = getid3_lib::Bin2Dec ( substr ( $nAudiophileRgAdjustBitstring, 6, 1 ) );
  200. $thisfile_riff_raw_rgad_album ['adjustment'] = getid3_lib::Bin2Dec ( substr ( $nAudiophileRgAdjustBitstring, 7, 9 ) );
  201. $thisfile_riff ['rgad'] ['peakamplitude'] = $thisfile_riff_raw_rgad ['fPeakAmplitude'];
  202. if (($thisfile_riff_raw_rgad_track ['name'] != 0) && ($thisfile_riff_raw_rgad_track ['originator'] != 0)) {
  203. $thisfile_riff ['rgad'] ['track'] ['name'] = getid3_lib::RGADnameLookup ( $thisfile_riff_raw_rgad_track ['name'] );
  204. $thisfile_riff ['rgad'] ['track'] ['originator'] = getid3_lib::RGADoriginatorLookup ( $thisfile_riff_raw_rgad_track ['originator'] );
  205. $thisfile_riff ['rgad'] ['track'] ['adjustment'] = getid3_lib::RGADadjustmentLookup ( $thisfile_riff_raw_rgad_track ['adjustment'], $thisfile_riff_raw_rgad_track ['signbit'] );
  206. }
  207. if (($thisfile_riff_raw_rgad_album ['name'] != 0) && ($thisfile_riff_raw_rgad_album ['originator'] != 0)) {
  208. $thisfile_riff ['rgad'] ['album'] ['name'] = getid3_lib::RGADnameLookup ( $thisfile_riff_raw_rgad_album ['name'] );
  209. $thisfile_riff ['rgad'] ['album'] ['originator'] = getid3_lib::RGADoriginatorLookup ( $thisfile_riff_raw_rgad_album ['originator'] );
  210. $thisfile_riff ['rgad'] ['album'] ['adjustment'] = getid3_lib::RGADadjustmentLookup ( $thisfile_riff_raw_rgad_album ['adjustment'], $thisfile_riff_raw_rgad_album ['signbit'] );
  211. }
  212. }
  213. if (isset ( $thisfile_riff_WAVE ['fact'] [0] ['data'] )) {
  214. $thisfile_riff_raw ['fact'] ['NumberOfSamples'] = $this->EitherEndian2Int ( substr ( $thisfile_riff_WAVE ['fact'] [0] ['data'], 0, 4 ) );
  215. // This should be a good way of calculating exact playtime,
  216. // but some sample files have had incorrect number of samples,
  217. // so cannot use this method
  218. // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
  219. // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
  220. // }
  221. }
  222. if (! empty ( $thisfile_riff_raw ['fmt '] ['nAvgBytesPerSec'] )) {
  223. $thisfile_audio ['bitrate'] = getid3_lib::CastAsInt ( $thisfile_riff_raw ['fmt '] ['nAvgBytesPerSec'] * 8 );
  224. }
  225. if (isset ( $thisfile_riff_WAVE ['bext'] [0] ['data'] )) {
  226. // shortcut
  227. $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE ['bext'] [0];
  228. $thisfile_riff_WAVE_bext_0 ['title'] = trim ( substr ( $thisfile_riff_WAVE_bext_0 ['data'], 0, 256 ) );
  229. $thisfile_riff_WAVE_bext_0 ['author'] = trim ( substr ( $thisfile_riff_WAVE_bext_0 ['data'], 256, 32 ) );
  230. $thisfile_riff_WAVE_bext_0 ['reference'] = trim ( substr ( $thisfile_riff_WAVE_bext_0 ['data'], 288, 32 ) );
  231. $thisfile_riff_WAVE_bext_0 ['origin_date'] = substr ( $thisfile_riff_WAVE_bext_0 ['data'], 320, 10 );
  232. $thisfile_riff_WAVE_bext_0 ['origin_time'] = substr ( $thisfile_riff_WAVE_bext_0 ['data'], 330, 8 );
  233. $thisfile_riff_WAVE_bext_0 ['time_reference'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE_bext_0 ['data'], 338, 8 ) );
  234. $thisfile_riff_WAVE_bext_0 ['bwf_version'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE_bext_0 ['data'], 346, 1 ) );
  235. $thisfile_riff_WAVE_bext_0 ['reserved'] = substr ( $thisfile_riff_WAVE_bext_0 ['data'], 347, 254 );
  236. $thisfile_riff_WAVE_bext_0 ['coding_history'] = explode ( "\r\n", trim ( substr ( $thisfile_riff_WAVE_bext_0 ['data'], 601 ) ) );
  237. if (preg_match ( '#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0 ['origin_date'], $matches_bext_date )) {
  238. if (preg_match ( '#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0 ['origin_time'], $matches_bext_time )) {
  239. list ( $dummy, $bext_timestamp ['year'], $bext_timestamp ['month'], $bext_timestamp ['day'] ) = $matches_bext_date;
  240. list ( $dummy, $bext_timestamp ['hour'], $bext_timestamp ['minute'], $bext_timestamp ['second'] ) = $matches_bext_time;
  241. $thisfile_riff_WAVE_bext_0 ['origin_date_unix'] = gmmktime ( $bext_timestamp ['hour'], $bext_timestamp ['minute'], $bext_timestamp ['second'], $bext_timestamp ['month'], $bext_timestamp ['day'], $bext_timestamp ['year'] );
  242. } else {
  243. $info ['warning'] [] = 'RIFF.WAVE.BEXT.origin_time is invalid';
  244. }
  245. } else {
  246. $info ['warning'] [] = 'RIFF.WAVE.BEXT.origin_date is invalid';
  247. }
  248. $thisfile_riff ['comments'] ['author'] [] = $thisfile_riff_WAVE_bext_0 ['author'];
  249. $thisfile_riff ['comments'] ['title'] [] = $thisfile_riff_WAVE_bext_0 ['title'];
  250. }
  251. if (isset ( $thisfile_riff_WAVE ['MEXT'] [0] ['data'] )) {
  252. // shortcut
  253. $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE ['MEXT'] [0];
  254. $thisfile_riff_WAVE_MEXT_0 ['raw'] ['sound_information'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE_MEXT_0 ['data'], 0, 2 ) );
  255. $thisfile_riff_WAVE_MEXT_0 ['flags'] ['homogenous'] = ( bool ) ($thisfile_riff_WAVE_MEXT_0 ['raw'] ['sound_information'] & 0x0001);
  256. if ($thisfile_riff_WAVE_MEXT_0 ['flags'] ['homogenous']) {
  257. $thisfile_riff_WAVE_MEXT_0 ['flags'] ['padding'] = ($thisfile_riff_WAVE_MEXT_0 ['raw'] ['sound_information'] & 0x0002) ? false : true;
  258. $thisfile_riff_WAVE_MEXT_0 ['flags'] ['22_or_44'] = ( bool ) ($thisfile_riff_WAVE_MEXT_0 ['raw'] ['sound_information'] & 0x0004);
  259. $thisfile_riff_WAVE_MEXT_0 ['flags'] ['free_format'] = ( bool ) ($thisfile_riff_WAVE_MEXT_0 ['raw'] ['sound_information'] & 0x0008);
  260. $thisfile_riff_WAVE_MEXT_0 ['nominal_frame_size'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE_MEXT_0 ['data'], 2, 2 ) );
  261. }
  262. $thisfile_riff_WAVE_MEXT_0 ['anciliary_data_length'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE_MEXT_0 ['data'], 6, 2 ) );
  263. $thisfile_riff_WAVE_MEXT_0 ['raw'] ['anciliary_data_def'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE_MEXT_0 ['data'], 8, 2 ) );
  264. $thisfile_riff_WAVE_MEXT_0 ['flags'] ['anciliary_data_left'] = ( bool ) ($thisfile_riff_WAVE_MEXT_0 ['raw'] ['anciliary_data_def'] & 0x0001);
  265. $thisfile_riff_WAVE_MEXT_0 ['flags'] ['anciliary_data_free'] = ( bool ) ($thisfile_riff_WAVE_MEXT_0 ['raw'] ['anciliary_data_def'] & 0x0002);
  266. $thisfile_riff_WAVE_MEXT_0 ['flags'] ['anciliary_data_right'] = ( bool ) ($thisfile_riff_WAVE_MEXT_0 ['raw'] ['anciliary_data_def'] & 0x0004);
  267. }
  268. if (isset ( $thisfile_riff_WAVE ['cart'] [0] ['data'] )) {
  269. // shortcut
  270. $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE ['cart'] [0];
  271. $thisfile_riff_WAVE_cart_0 ['version'] = substr ( $thisfile_riff_WAVE_cart_0 ['data'], 0, 4 );
  272. $thisfile_riff_WAVE_cart_0 ['title'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 4, 64 ) );
  273. $thisfile_riff_WAVE_cart_0 ['artist'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 68, 64 ) );
  274. $thisfile_riff_WAVE_cart_0 ['cut_id'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 132, 64 ) );
  275. $thisfile_riff_WAVE_cart_0 ['client_id'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 196, 64 ) );
  276. $thisfile_riff_WAVE_cart_0 ['category'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 260, 64 ) );
  277. $thisfile_riff_WAVE_cart_0 ['classification'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 324, 64 ) );
  278. $thisfile_riff_WAVE_cart_0 ['out_cue'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 388, 64 ) );
  279. $thisfile_riff_WAVE_cart_0 ['start_date'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 452, 10 ) );
  280. $thisfile_riff_WAVE_cart_0 ['start_time'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 462, 8 ) );
  281. $thisfile_riff_WAVE_cart_0 ['end_date'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 470, 10 ) );
  282. $thisfile_riff_WAVE_cart_0 ['end_time'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 480, 8 ) );
  283. $thisfile_riff_WAVE_cart_0 ['producer_app_id'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 488, 64 ) );
  284. $thisfile_riff_WAVE_cart_0 ['producer_app_version'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 552, 64 ) );
  285. $thisfile_riff_WAVE_cart_0 ['user_defined_text'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 616, 64 ) );
  286. $thisfile_riff_WAVE_cart_0 ['zero_db_reference'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 680, 4 ), true );
  287. for($i = 0; $i < 8; $i ++) {
  288. $thisfile_riff_WAVE_cart_0 ['post_time'] [$i] ['usage_fourcc'] = substr ( $thisfile_riff_WAVE_cart_0 ['data'], 684 + ($i * 8), 4 );
  289. $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 ) );
  290. }
  291. $thisfile_riff_WAVE_cart_0 ['url'] = trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 748, 1024 ) );
  292. $thisfile_riff_WAVE_cart_0 ['tag_text'] = explode ( "\r\n", trim ( substr ( $thisfile_riff_WAVE_cart_0 ['data'], 1772 ) ) );
  293. $thisfile_riff ['comments'] ['artist'] [] = $thisfile_riff_WAVE_cart_0 ['artist'];
  294. $thisfile_riff ['comments'] ['title'] [] = $thisfile_riff_WAVE_cart_0 ['title'];
  295. }
  296. if (isset ( $thisfile_riff_WAVE ['SNDM'] [0] ['data'] )) {
  297. // SoundMiner metadata
  298. // shortcuts
  299. $thisfile_riff_WAVE_SNDM_0 = &$thisfile_riff_WAVE ['SNDM'] [0];
  300. $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0 ['data'];
  301. $SNDM_startoffset = 0;
  302. $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0 ['size'];
  303. while ( $SNDM_startoffset < $SNDM_endoffset ) {
  304. $SNDM_thisTagOffset = 0;
  305. $SNDM_thisTagSize = getid3_lib::BigEndian2Int ( substr ( $thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4 ) );
  306. $SNDM_thisTagOffset += 4;
  307. $SNDM_thisTagKey = substr ( $thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4 );
  308. $SNDM_thisTagOffset += 4;
  309. $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int ( substr ( $thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2 ) );
  310. $SNDM_thisTagOffset += 2;
  311. $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int ( substr ( $thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2 ) );
  312. $SNDM_thisTagOffset += 2;
  313. $SNDM_thisTagDataText = substr ( $thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize );
  314. $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
  315. if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
  316. $info ['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 ' . ($thisfile_riff_WAVE_SNDM_0 ['offset'] + $SNDM_startoffset) . ')';
  317. break;
  318. } elseif ($SNDM_thisTagSize <= 0) {
  319. $info ['warning'] [] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset ' . $SNDM_startoffset . ' (file offset ' . ($thisfile_riff_WAVE_SNDM_0 ['offset'] + $SNDM_startoffset) . ')';
  320. break;
  321. }
  322. $SNDM_startoffset += $SNDM_thisTagSize;
  323. $thisfile_riff_WAVE_SNDM_0 ['parsed_raw'] [$SNDM_thisTagKey] = $SNDM_thisTagDataText;
  324. if (($parsedkey = $this->RIFFwaveSNDMtagLookup ( $SNDM_thisTagKey )) != false) {
  325. $thisfile_riff_WAVE_SNDM_0 ['parsed'] [$parsedkey] = $SNDM_thisTagDataText;
  326. } else {
  327. $info ['warning'] [] = 'RIFF.WAVE.SNDM contains unknown tag "' . $SNDM_thisTagKey . '" at offset ' . $SNDM_startoffset . ' (file offset ' . ($thisfile_riff_WAVE_SNDM_0 ['offset'] + $SNDM_startoffset) . ')';
  328. }
  329. }
  330. $tagmapping = array (
  331. 'tracktitle' => 'title',
  332. 'category' => 'genre',
  333. 'cdtitle' => 'album',
  334. 'tracktitle' => 'title' );
  335. foreach ( $tagmapping as $fromkey => $tokey ) {
  336. if (isset ( $thisfile_riff_WAVE_SNDM_0 ['parsed'] [$fromkey] )) {
  337. $thisfile_riff ['comments'] [$tokey] [] = $thisfile_riff_WAVE_SNDM_0 ['parsed'] [$fromkey];
  338. }
  339. }
  340. }
  341. if (isset ( $thisfile_riff_WAVE ['iXML'] [0] ['data'] )) {
  342. // requires functions simplexml_load_string and get_object_vars
  343. if (($parsedXML = getid3_lib::XML2array ( $thisfile_riff_WAVE ['iXML'] [0] ['data'] )) != false) {
  344. $thisfile_riff_WAVE ['iXML'] [0] ['parsed'] = $parsedXML;
  345. if (isset ( $parsedXML ['SPEED'] ['MASTER_SPEED'] )) {
  346. @list ( $numerator, $denominator ) = explode ( '/', $parsedXML ['SPEED'] ['MASTER_SPEED'] );
  347. $thisfile_riff_WAVE ['iXML'] [0] ['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
  348. }
  349. if (isset ( $parsedXML ['SPEED'] ['TIMECODE_RATE'] )) {
  350. @list ( $numerator, $denominator ) = explode ( '/', $parsedXML ['SPEED'] ['TIMECODE_RATE'] );
  351. $thisfile_riff_WAVE ['iXML'] [0] ['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
  352. }
  353. if (isset ( $parsedXML ['SPEED'] ['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'] ) && ! empty ( $parsedXML ['SPEED'] ['TIMESTAMP_SAMPLE_RATE'] ) && ! empty ( $thisfile_riff_WAVE ['iXML'] [0] ['timecode_rate'] )) {
  354. $samples_since_midnight = floatval ( ltrim ( $parsedXML ['SPEED'] ['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'] . $parsedXML ['SPEED'] ['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0' ) );
  355. $thisfile_riff_WAVE ['iXML'] [0] ['timecode_seconds'] = $samples_since_midnight / $parsedXML ['SPEED'] ['TIMESTAMP_SAMPLE_RATE'];
  356. $h = floor ( $thisfile_riff_WAVE ['iXML'] [0] ['timecode_seconds'] / 3600 );
  357. $m = floor ( ($thisfile_riff_WAVE ['iXML'] [0] ['timecode_seconds'] - ($h * 3600)) / 60 );
  358. $s = floor ( $thisfile_riff_WAVE ['iXML'] [0] ['timecode_seconds'] - ($h * 3600) - ($m * 60) );
  359. $f = ($thisfile_riff_WAVE ['iXML'] [0] ['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE ['iXML'] [0] ['timecode_rate'];
  360. $thisfile_riff_WAVE ['iXML'] [0] ['timecode_string'] = sprintf ( '%02d:%02d:%02d:%05.2f', $h, $m, $s, $f );
  361. $thisfile_riff_WAVE ['iXML'] [0] ['timecode_string_round'] = sprintf ( '%02d:%02d:%02d:%02d', $h, $m, $s, round ( $f ) );
  362. }
  363. unset ( $parsedXML );
  364. }
  365. }
  366. if (! isset ( $thisfile_audio ['bitrate'] ) && isset ( $thisfile_riff_audio [$streamindex] ['bitrate'] )) {
  367. $thisfile_audio ['bitrate'] = $thisfile_riff_audio [$streamindex] ['bitrate'];
  368. $info ['playtime_seconds'] = ( float ) ((($info ['avdataend'] - $info ['avdataoffset']) * 8) / $thisfile_audio ['bitrate']);
  369. }
  370. if (! empty ( $info ['wavpack'] )) {
  371. $thisfile_audio_dataformat = 'wavpack';
  372. $thisfile_audio ['bitrate_mode'] = 'vbr';
  373. $thisfile_audio ['encoder'] = 'WavPack v' . $info ['wavpack'] ['version'];
  374. // Reset to the way it was - RIFF parsing will have messed this up
  375. $info ['avdataend'] = $Original ['avdataend'];
  376. $thisfile_audio ['bitrate'] = (($info ['avdataend'] - $info ['avdataoffset']) * 8) / $info ['playtime_seconds'];
  377. fseek ( $this->getid3->fp, $info ['avdataoffset'] - 44, SEEK_SET );
  378. $RIFFdata = fread ( $this->getid3->fp, 44 );
  379. $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int ( substr ( $RIFFdata, 4, 4 ) ) + 8;
  380. $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int ( substr ( $RIFFdata, 40, 4 ) ) + 44;
  381. if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
  382. $info ['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
  383. fseek ( $this->getid3->fp, $info ['avdataend'], SEEK_SET );
  384. $RIFFdata .= fread ( $this->getid3->fp, $OrignalRIFFheaderSize - $OrignalRIFFdataSize );
  385. }
  386. // move the data chunk after all other chunks (if any)
  387. // so that the RIFF parser doesn't see EOF when trying
  388. // to skip over the data chunk
  389. $RIFFdata = substr ( $RIFFdata, 0, 36 ) . substr ( $RIFFdata, 44 ) . substr ( $RIFFdata, 36, 8 );
  390. $getid3_riff = new getid3_riff ( $this->getid3 );
  391. $getid3_riff->ParseRIFFdata ( $RIFFdata );
  392. unset ( $getid3_riff );
  393. }
  394. if (isset ( $thisfile_riff_raw ['fmt '] ['wFormatTag'] )) {
  395. switch ($thisfile_riff_raw ['fmt '] ['wFormatTag']) {
  396. case 0x0001 : // PCM
  397. if (! empty ( $info ['ac3'] )) {
  398. // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
  399. $thisfile_audio ['wformattag'] = 0x2000;
  400. $thisfile_audio ['codec'] = $this->RIFFwFormatTagLookup ( $thisfile_audio ['wformattag'] );
  401. $thisfile_audio ['lossless'] = false;
  402. $thisfile_audio ['bitrate'] = $info ['ac3'] ['bitrate'];
  403. $thisfile_audio ['sample_rate'] = $info ['ac3'] ['sample_rate'];
  404. }
  405. break;
  406. case 0x08AE : // ClearJump LiteWave
  407. $thisfile_audio ['bitrate_mode'] = 'vbr';
  408. $thisfile_audio_dataformat = 'litewave';
  409. //typedef struct tagSLwFormat {
  410. // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags
  411. // DWORD m_dwScale; // scale factor for lossy compression
  412. // DWORD m_dwBlockSize; // number of samples in encoded blocks
  413. // WORD m_wQuality; // alias for the scale factor
  414. // WORD m_wMarkDistance; // distance between marks in bytes
  415. // WORD m_wReserved;
  416. //
  417. // //following paramters are ignored if CF_FILESRC is not set
  418. // DWORD m_dwOrgSize; // original file size in bytes
  419. // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file
  420. // DWORD m_dwRiffChunkSize; // riff chunk size in the original file
  421. //
  422. // PCMWAVEFORMAT m_OrgWf; // original wave format
  423. // }SLwFormat, *PSLwFormat;
  424. // shortcut
  425. $thisfile_riff ['litewave'] ['raw'] = array ();
  426. $thisfile_riff_litewave = &$thisfile_riff ['litewave'];
  427. $thisfile_riff_litewave_raw = &$thisfile_riff_litewave ['raw'];
  428. $thisfile_riff_litewave_raw ['compression_method'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 18, 1 ) );
  429. $thisfile_riff_litewave_raw ['compression_flags'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 19, 1 ) );
  430. $thisfile_riff_litewave_raw ['m_dwScale'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 20, 4 ) );
  431. $thisfile_riff_litewave_raw ['m_dwBlockSize'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 24, 4 ) );
  432. $thisfile_riff_litewave_raw ['m_wQuality'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 28, 2 ) );
  433. $thisfile_riff_litewave_raw ['m_wMarkDistance'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 30, 2 ) );
  434. $thisfile_riff_litewave_raw ['m_wReserved'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 32, 2 ) );
  435. $thisfile_riff_litewave_raw ['m_dwOrgSize'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 34, 4 ) );
  436. $thisfile_riff_litewave_raw ['m_bFactExists'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 38, 2 ) );
  437. $thisfile_riff_litewave_raw ['m_dwRiffChunkSize'] = getid3_lib::LittleEndian2Int ( substr ( $thisfile_riff_WAVE ['fmt '] [0] ['data'], 40, 4 ) );
  438. //$thisfile_riff_litewave['quality_factor'] = intval(round((2000 - $thisfile_riff_litewave_raw['m_dwScale']) / 20));
  439. $thisfile_riff_litewave ['quality_factor'] = $thisfile_riff_litewave_raw ['m_wQuality'];
  440. $thisfile_riff_litewave ['flags'] ['raw_source'] = ($thisfile_riff_litewave_raw ['compression_flags'] & 0x01) ? false : true;
  441. $thisfile_riff_litewave ['flags'] ['vbr_blocksize'] = ($thisfile_riff_litewave_raw ['compression_flags'] & 0x02) ? false : true;
  442. $thisfile_riff_litewave ['flags'] ['seekpoints'] = ( bool ) ($thisfile_riff_litewave_raw ['compression_flags'] & 0x04);
  443. $thisfile_audio ['lossless'] = (($thisfile_riff_litewave_raw ['m_wQuality'] == 100) ? true : false);
  444. $thisfile_audio ['encoder_options'] = '-q' . $thisfile_riff_litewave ['quality_factor'];
  445. break;
  446. default :
  447. break;
  448. }
  449. }
  450. if ($info ['avdataend'] > $info ['filesize']) {
  451. switch (! empty ( $thisfile_audio_dataformat ) ? $thisfile_audio_dataformat : '') {
  452. case 'wavpack' : // WavPack
  453. case 'lpac' : // LPAC
  454. case 'ofr' : // OptimFROG
  455. case 'ofs' : // OptimFROG DualStream
  456. // lossless compressed audio formats that keep original RIFF headers - skip warning
  457. break;
  458. case 'litewave' :
  459. if (($info ['avdataend'] - $info ['filesize']) == 1) {
  460. // LiteWave appears to incorrectly *not* pad actual output file
  461. // to nearest WORD boundary so may appear to be short by one
  462. // byte, in which case - skip warning
  463. } else {
  464. // Short by more than one byte, throw warning
  465. $info ['warning'] [] = 'Probably truncated file - expecting ' . $thisfile_riff [$RIFFsubtype] ['data'] [0] ['size'] . ' bytes of data, only found ' . ($info ['filesize'] - $info ['avdataoffset']) . ' (short by ' . ($thisfile_riff [$RIFFsubtype] ['data'] [0] ['size'] - ($info ['filesize'] - $info ['avdataoffset'])) . ' bytes)';
  466. $info ['avdataend'] = $info ['filesize'];
  467. }
  468. break;
  469. default :
  470. if ((($info ['avdataend'] - $info ['filesize']) == 1) && (($thisfile_riff [$RIFFsubtype] ['data'] [0] ['size'] % 2) == 0) && ((($info ['filesize'] - $info ['avdataoffset']) % 2) == 1)) {
  471. // output file appears to be incorrectly *not* padded to nearest WORD boundary
  472. // Output less severe warning
  473. $info ['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 ' . ($info ['filesize'] - $info ['avdataoffset']) . ' therefore short by ' . ($thisfile_riff [$RIFFsubtype] ['data'] [0] ['size'] - ($info ['filesize'] - $info ['avdataoffset'])) . ' bytes)';
  474. $info ['avdataend'] = $info ['filesize'];
  475. } else {
  476. // Short by more than one byte, throw warning
  477. $info ['warning'] [] = 'Probably truncated file - expecting ' . $thisfile_riff [$RIFFsubtype] ['data'] [0] ['size'] . ' bytes of data, only found ' . ($info ['filesize'] - $info ['avdataoffset']) . ' (short by ' . ($thisfile_riff [$RIFFsubtype] ['data'] [0] ['size'] - ($info ['filesize'] - $info ['avdataoffset'])) . ' bytes)';
  478. $info ['avdataend'] = $info ['filesize'];
  479. }
  480. break;
  481. }
  482. }
  483. if (! empty ( $info ['mpeg'] ['audio'] ['LAME'] ['audio_bytes'] )) {
  484. if ((($info ['avdataend'] - $info ['avdataoffset']) - $info ['mpeg'] ['audio'] ['LAME'] ['audio_bytes']) == 1) {
  485. $info ['avdataend'] --;
  486. $info ['warning'] [] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
  487. }
  488. }
  489. if (isset ( $thisfile_audio_dataformat ) && ($thisfile_audio_dataformat == 'ac3')) {
  490. unset ( $thisfile_audio ['bits_per_sample'] );
  491. if (! empty ( $info ['ac3'] ['bitrate'] ) && ($info ['ac3'] ['bitrate'] != $thisfile_audio ['bitrate'])) {
  492. $thisfile_audio ['bitrate'] = $info ['ac3'] ['bitrate'];
  493. }
  494. }
  495. break;
  496. case 'AVI ' :
  497. $thisfile_video ['bitrate_mode'] = 'vbr'; // maybe not, but probably
  498. $thisfile_video ['dataformat'] = 'avi';
  499. $info ['mime_type'] = 'video/avi';
  500. if (isset ( $thisfile_riff [$RIFFsubtype] ['movi'] ['offset'] )) {
  501. $info ['avdataoffset'] = $thisfile_riff [$RIFFsubtype] ['movi'] ['offset'] + 8;
  502. if (isset ( $thisfile_riff ['AVIX'] )) {
  503. $info ['avdataend'] = $thisfile_riff ['AVIX'] [(count ( $thisfile_riff ['AVIX'] ) - 1)] ['chunks'] ['movi'] ['offset'] + $thisfile_riff ['AVIX'] [(count ( $thisfile_riff ['AVIX'] ) - 1)] ['chunks'] ['movi'] ['size'];
  504. } else {
  505. $info ['avdataend'] = $thisfile_riff ['AVI '] ['movi'] ['offset'] + $thisfile_riff ['AVI '] ['movi'] ['size'];
  506. }
  507. if ($info ['avdataend'] > $info ['filesize']) {
  508. $info ['warning'] [] = 'Probably truncated file - expecting ' . ($info ['avdataend'] - $info ['avdataoffset']) . ' bytes of data, only found ' . ($info ['filesize'] - $info ['avdataoffset']) . ' (short by ' . ($info ['avdataend'] - $info ['filesize']) . ' bytes)';
  509. $info ['avdataend'] = $info ['filesize'];
  510. }
  511. }
  512. if (isset ( $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['indx'] )) {
  513. //$bIndexType = array(
  514. // 0x00 => 'AVI_INDEX_OF_INDEXES',
  515. // 0x01 => 'AVI_INDEX_OF_CHUNKS',
  516. // 0x80 => 'AVI_INDEX_IS_DATA',
  517. //);
  518. //$bIndexSubtype = array(
  519. // 0x01 => array(
  520. // 0x01 => 'AVI_INDEX_2FIELD',
  521. // ),
  522. //);
  523. foreach ( $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['indx'] as $streamnumber => $steamdataarray ) {
  524. $thisfile_riff_avi_hdrl_strl_indx_stream_data = &$thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['indx'] [$streamnumber] ['data'];
  525. $thisfile_riff_raw ['indx'] [$streamnumber] ['wLongsPerEntry'] = $this->EitherEndian2Int ( substr ( $thisfile_riff_avi_hdrl_strl_indx_stream_data, 0, 2 ) );
  526. $thisfile_riff_raw ['indx'] [$streamnumber] ['bIndexSubType'] = $this->EitherEndian2Int ( substr ( $thisfile_riff_avi_hdrl_strl_indx_stream_data, 2, 1 ) );
  527. $thisfile_riff_raw ['indx'] [$streamnumber] ['bIndexType'] = $this->EitherEndian2Int ( substr ( $thisfile_riff_avi_hdrl_strl_indx_stream_data, 3, 1 ) );
  528. $thisfile_riff_raw ['indx'] [$streamnumber] ['nEntriesInUse'] = $this->EitherEndian2Int ( substr ( $thisfile_riff_avi_hdrl_strl_indx_stream_data, 4, 4 ) );
  529. $thisfile_riff_raw ['indx'] [$streamnumber] ['dwChunkId'] = substr ( $thisfile_riff_avi_hdrl_strl_indx_stream_data, 8, 4 );
  530. $thisfile_riff_raw ['indx'] [$streamnumber] ['dwReserved'] = $this->EitherEndian2Int ( substr ( $thisfile_riff_avi_hdrl_strl_indx_stream_data, 12, 4 ) );
  531. //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name'] = $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
  532. //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
  533. unset ( $thisfile_riff_avi_hdrl_strl_indx_stream_data );
  534. }
  535. }
  536. if (isset ( $thisfile_riff ['AVI '] ['hdrl'] ['avih'] [$streamindex] ['data'] )) {
  537. $avihData = $thisfile_riff ['AVI '] ['hdrl'] ['avih'] [$streamindex] ['data'];
  538. // shortcut
  539. $thisfile_riff_raw ['avih'] = array ();
  540. $thisfile_riff_raw_avih = &$thisfile_riff_raw ['avih'];
  541. $thisfile_riff_raw_avih ['dwMicroSecPerFrame'] = $this->EitherEndian2Int ( substr ( $avihData, 0, 4 ) ); // frame display rate (or 0L)
  542. if ($thisfile_riff_raw_avih ['dwMicroSecPerFrame'] == 0) {
  543. $info ['error'] [] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
  544. return false;
  545. }
  546. $thisfile_riff_raw_avih ['dwMaxBytesPerSec'] = $this->EitherEndian2Int ( substr ( $avihData, 4, 4 ) ); // max. transfer rate
  547. $thisfile_riff_raw_avih ['dwPaddingGranularity'] = $this->EitherEndian2Int ( substr ( $avihData, 8, 4 ) ); // pad to multiples of this size; normally 2K.
  548. $thisfile_riff_raw_avih ['dwFlags'] = $this->EitherEndian2Int ( substr ( $avihData, 12, 4 ) ); // the ever-present flags
  549. $thisfile_riff_raw_avih ['dwTotalFrames'] = $this->EitherEndian2Int ( substr ( $avihData, 16, 4 ) ); // # frames in file
  550. $thisfile_riff_raw_avih ['dwInitialFrames'] = $this->EitherEndian2Int ( substr ( $avihData, 20, 4 ) );
  551. $thisfile_riff_raw_avih ['dwStreams'] = $this->EitherEndian2Int ( substr ( $avihData, 24, 4 ) );
  552. $thisfile_riff_raw_avih ['dwSuggestedBufferSize'] = $this->EitherEndian2Int ( substr ( $avihData, 28, 4 ) );
  553. $thisfile_riff_raw_avih ['dwWidth'] = $this->EitherEndian2Int ( substr ( $avihData, 32, 4 ) );
  554. $thisfile_riff_raw_avih ['dwHeight'] = $this->EitherEndian2Int ( substr ( $avihData, 36, 4 ) );
  555. $thisfile_riff_raw_avih ['dwScale'] = $this->EitherEndian2Int ( substr ( $avihData, 40, 4 ) );
  556. $thisfile_riff_raw_avih ['dwRate'] = $this->EitherEndian2Int ( substr ( $avihData, 44, 4 ) );
  557. $thisfile_riff_raw_avih ['dwStart'] = $this->EitherEndian2Int ( substr ( $avihData, 48, 4 ) );
  558. $thisfile_riff_raw_avih ['dwLength'] = $this->EitherEndian2Int ( substr ( $avihData, 52, 4 ) );
  559. $thisfile_riff_raw_avih ['flags'] ['hasindex'] = ( bool ) ($thisfile_riff_raw_avih ['dwFlags'] & 0x00000010);
  560. $thisfile_riff_raw_avih ['flags'] ['mustuseindex'] = ( bool ) ($thisfile_riff_raw_avih ['dwFlags'] & 0x00000020);
  561. $thisfile_riff_raw_avih ['flags'] ['interleaved'] = ( bool ) ($thisfile_riff_raw_avih ['dwFlags'] & 0x00000100);
  562. $thisfile_riff_raw_avih ['flags'] ['trustcktype'] = ( bool ) ($thisfile_riff_raw_avih ['dwFlags'] & 0x00000800);
  563. $thisfile_riff_raw_avih ['flags'] ['capturedfile'] = ( bool ) ($thisfile_riff_raw_avih ['dwFlags'] & 0x00010000);
  564. $thisfile_riff_raw_avih ['flags'] ['copyrighted'] = ( bool ) ($thisfile_riff_raw_avih ['dwFlags'] & 0x00020010);
  565. // shortcut
  566. $thisfile_riff_video [$streamindex] = array ();
  567. $thisfile_riff_video_current = &$thisfile_riff_video [$streamindex];
  568. if ($thisfile_riff_raw_avih ['dwWidth'] > 0) {
  569. $thisfile_riff_video_current ['frame_width'] = $thisfile_riff_raw_avih ['dwWidth'];
  570. $thisfile_video ['resolution_x'] = $thisfile_riff_video_current ['frame_width'];
  571. }
  572. if ($thisfile_riff_raw_avih ['dwHeight'] > 0) {
  573. $thisfile_riff_video_current ['frame_height'] = $thisfile_riff_raw_avih ['dwHeight'];
  574. $thisfile_video ['resolution_y'] = $thisfile_riff_video_current ['frame_height'];
  575. }
  576. if ($thisfile_riff_raw_avih ['dwTotalFrames'] > 0) {
  577. $thisfile_riff_video_current ['total_frames'] = $thisfile_riff_raw_avih ['dwTotalFrames'];
  578. $thisfile_video ['total_frames'] = $thisfile_riff_video_current ['total_frames'];
  579. }
  580. $thisfile_riff_video_current ['frame_rate'] = round ( 1000000 / $thisfile_riff_raw_avih ['dwMicroSecPerFrame'], 3 );
  581. $thisfile_video ['frame_rate'] = $thisfile_riff_video_current ['frame_rate'];
  582. }
  583. if (isset ( $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['strh'] [0] ['data'] )) {
  584. if (is_array ( $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['strh'] )) {
  585. for($i = 0; $i < count ( $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['strh'] ); $i ++) {
  586. if (isset ( $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['strh'] [$i] ['data'] )) {
  587. $strhData = $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['strh'] [$i] ['data'];
  588. $strhfccType = substr ( $strhData, 0, 4 );
  589. if (isset ( $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['strf'] [$i] ['data'] )) {
  590. $strfData = $thisfile_riff ['AVI '] ['hdrl'] ['strl'] ['strf'] [$i] ['data'];
  591. // shortcut
  592. $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw ['strf'] [$strhfccType] [$streamindex];
  593. switch ($strhfccType) {
  594. case 'auds' :
  595. $thisfile_audio ['bitrate_mode'] = 'cbr';
  596. $thisfile_audio_dataformat = 'wav';
  597. if (isset ( $thisfile_riff_audio ) && is_array ( $thisfile_riff_audio )) {
  598. $streamindex = count ( $thisfile_riff_audio );
  599. }
  600. $thisfile_riff_audio [$streamindex] = getid3_riff::RIFFparseWAVEFORMATex ( $strfData );
  601. $thisfile_audio ['wformattag'] = $thisfile_riff_audio [$streamindex] ['raw'] ['wFormatTag'];
  602. // shortcut
  603. $thisfile_audio ['streams'] [$streamindex] = $thisfile_riff_audio [$streamindex];
  604. $thisfile_audio_streams_currentstream = &$thisfile_audio ['streams'] [$streamindex];
  605. if ($thisfile_audio_streams_currentstream ['bits_per_sample'] == 0) {
  606. unset ( $thisfile_audio_streams_currentstream ['bits_per_sample'] );
  607. }
  608. $thisfile_audio_streams_currentstream ['wformattag'] = $thisfile_audio_streams_currentstream ['raw'] ['wFormatTag'];
  609. unset ( $thisfile_audio_streams_currentstream ['raw'] );
  610. // shortcut
  611. $thisfile_riff_raw ['strf'] [$strhfccType] [$streamindex] = $thisfile_riff_audio [$streamindex] ['raw'];
  612. unset ( $thisfile_riff_audio [$streamindex] ['raw'] );
  613. $thisfile_audio = getid3_lib::array_merge_noclobber ( $thisfile_audio, $thisfile_riff_audio [$streamindex] );
  614. $thisfile_audio ['lossless'] = false;
  615. switch ($thisfile_riff_raw_strf_strhfccType_streamindex ['wFormatTag']) {
  616. case 0x0001 : // PCM
  617. $thisfile_audio_dataformat = 'wav';
  618. $thisfile_audio ['lossless'] = true;
  619. break;
  620. case 0x0050 : // MPEG Layer 2 or Layer 1
  621. $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
  622. break;
  623. case 0x0055 : // MPEG Layer 3
  624. $thisfile_audio_dataformat = 'mp3';
  625. break;
  626. case 0x00FF : // AAC
  627. $thisfile_audio_dataformat = 'aac';
  628. break;
  629. case 0x0161 : // Windows Media v7 / v8 / v9
  630. case 0x0162 : // Windows Media Professional v9
  631. case 0x0163 : // Windows Media Lossess v9
  632. $thisfile_audio_dataformat = 'wma';
  633. break;
  634. case 0x2000 : // AC-3
  635. $thisfile_audio_dataformat = 'ac3';
  636. break;
  637. case 0x2001 : // DTS
  638. $thisfile_audio_dataformat = 'dts';
  639. break;
  640. default :
  641. $thisfile_audio_dataformat = 'wav';
  642. break;
  643. }
  644. $thisfile_audio_streams_currentstream ['dataformat'] = $thisfile_audio_dataformat;
  645. $thisfile_audio_streams_currentstream ['lossless'] = $thisfile_audio ['lossless'];
  646. $thisfile_audio_streams_currentstream ['bitrate_mode'] = $thisfile_audio ['bitrate_mode'];
  647. break;
  648. case 'iavs' :
  649. case 'vids' :
  650. // shortcut
  651. $thisfile_riff_raw ['strh'] [$i] = array ();
  652. $thisfile_riff_raw_strh_current = &$thisfile_riff_raw ['strh'] [$i];
  653. $thisfile_riff_raw_strh_current ['fccType'] = substr ( $strhData, 0, 4 ); // same as $strhfccType;
  654. $thisfile_riff_raw_strh_current ['fccHandler'] = substr ( $strhData, 4, 4 );
  655. $thisfile_riff_raw_strh_current ['dwFlags'] = $this->EitherEndian2Int ( substr ( $strhData, 8, 4 ) ); // Contains AVITF_* flags
  656. $thisfile_riff_raw_strh_current ['wPriority'] = $this->EitherEndian2Int ( substr ( $strhData, 12, 2 ) );
  657. $thisfile_riff_raw_strh_current ['wLanguage'] = $this->EitherEndian2Int ( substr ( $strhData, 14, 2 ) );
  658. $thisfile_riff_raw_strh_current ['dwInitialFrames'] = $this->EitherEndian2Int ( substr ( $strhData, 16, 4 ) );
  659. $thisfile_riff_raw_strh_current ['dwScale'] = $this->EitherEndian2Int ( substr ( $strhData, 20, 4 ) );
  660. $thisfile_riff_raw_strh_current ['dwRate'] = $this->EitherEndian2Int ( substr ( $strhData, 24, 4 ) );
  661. $thisfile_riff_raw_strh_current ['dwStart'] = $this->EitherEndian2Int ( substr ( $strhData, 28, 4 ) );
  662. $thisfile_riff_raw_strh_current ['dwLength'] = $this->EitherEndian2Int ( substr ( $strhData, 32, 4 ) );
  663. $thisfile_riff_raw_strh_current ['dwSuggestedBufferSize'] = $this->EitherEndian2Int ( substr ( $strhData, 36, 4 ) );
  664. $thisfile_riff_raw_strh_current ['dwQuality'] = $this->EitherEndian2Int ( substr ( $strhData, 40, 4 ) );
  665. $thisfile_riff_raw_strh_current ['dwSampleSize'] = $this->EitherEndian2Int ( substr ( $strhData, 44, 4 ) );
  666. $thisfile_riff_raw_strh_current ['rcFrame'] = $this->EitherEndian2Int ( substr ( $strhData, 48, 4 ) );
  667. $thisfile_riff_video_current ['codec'] = getid3_riff::RIFFfourccLookup ( $thisfile_riff_raw_strh_current ['fccHandler'] );
  668. $thisfile_video ['fourcc'] = $thisfile_riff_raw_strh_current ['fccHandler'];
  669. if (! $thisfile_riff_video_current ['codec'] && isset ( $thisfile_riff_raw_strf_strhfccType_streamindex ['fourcc'] ) && getid3_riff::RIFFfourccLookup ( $thisfile_riff_raw_strf_strhfccType_streamindex ['fourcc'] )) {
  670. $thisfile_riff_video_current ['codec'] = getid3_riff::RIFFfourccLookup ( $thisfile_riff_raw_strf_strhfccType_streamindex ['fourcc'] );
  671. $thisfile_video ['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex ['fourcc'];
  672. }
  673. $thisfile_video ['codec'] = $thisfile_riff_video_current ['codec'];
  674. $thisfile_video ['pixel_aspect_ratio'] = ( float ) 1;
  675. switch ($thisfile_riff_raw_strh_current ['fccHandler']) {
  676. case 'HFYU' : // Huffman Lossless Codec
  677. case 'IRAW' : // Intel YUV Uncompressed
  678. case 'YUY2' : // Uncompressed YUV 4:2:2
  679. $thisfile_video ['lossless'] = true;
  680. break;
  681. default :
  682. $thisfile_video ['lossless'] = false;
  683. break;
  684. }
  685. switch ($strhfccType) {
  686. case 'vids' :
  687. $thisfile_riff_raw_strf_strhfccType_streamindex = getid3_riff::ParseBITMAPINFOHEADER ( substr ( $strfData, 0, 40 ), ($info ['fileformat'] == 'riff') );
  688. //echo '<pre>'.print_r($thisfile_riff_raw_strf_strhfccType_streamindex, true).'</pre>';
  689. $thisfile_video ['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex ['biBitCount'];
  690. if ($thisfile_riff_video_current ['codec'] == 'DV') {
  691. $thisfile_riff_video_current ['dv_type'] = 2;
  692. }
  693. break;
  694. case 'iavs' :
  695. $thisfile_riff_video_current ['dv_type'] = 1;
  696. break;
  697. }
  698. break;
  699. defa

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