module.audio-video.riff.php 131 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at https://github.com/JamesHeinrich/getID3 //
  5. // or https://www.getid3.org //
  6. // or http://getid3.sourceforge.net //
  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 //
  16. // module.audio.dts.php //
  17. // ///
  18. /////////////////////////////////////////////////////////////////
  19. /**
  20. * @todo Parse AC-3/DTS audio inside WAVE correctly
  21. * @todo Rewrite RIFF parser totally
  22. */
  23. if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
  24. exit;
  25. }
  26. getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
  27. getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
  28. getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
  29. class getid3_riff extends getid3_handler
  30. {
  31. protected $container = 'riff'; // default
  32. /**
  33. * @return bool
  34. *
  35. * @throws getid3_exception
  36. */
  37. public function Analyze() {
  38. $info = &$this->getid3->info;
  39. // initialize these values to an empty array, otherwise they default to NULL
  40. // and you can't append array values to a NULL value
  41. $info['riff'] = array('raw'=>array());
  42. // Shortcuts
  43. $thisfile_riff = &$info['riff'];
  44. $thisfile_riff_raw = &$thisfile_riff['raw'];
  45. $thisfile_audio = &$info['audio'];
  46. $thisfile_video = &$info['video'];
  47. $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
  48. $thisfile_riff_audio = &$thisfile_riff['audio'];
  49. $thisfile_riff_video = &$thisfile_riff['video'];
  50. $thisfile_riff_WAVE = array();
  51. $Original['avdataoffset'] = $info['avdataoffset'];
  52. $Original['avdataend'] = $info['avdataend'];
  53. $this->fseek($info['avdataoffset']);
  54. $RIFFheader = $this->fread(12);
  55. $offset = $this->ftell();
  56. $RIFFtype = substr($RIFFheader, 0, 4);
  57. $RIFFsize = substr($RIFFheader, 4, 4);
  58. $RIFFsubtype = substr($RIFFheader, 8, 4);
  59. switch ($RIFFtype) {
  60. case 'FORM': // AIFF, AIFC
  61. //$info['fileformat'] = 'aiff';
  62. $this->container = 'aiff';
  63. $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
  64. $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
  65. break;
  66. case 'RIFF': // AVI, WAV, etc
  67. case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
  68. case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
  69. //$info['fileformat'] = 'riff';
  70. $this->container = 'riff';
  71. $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
  72. if ($RIFFsubtype == 'RMP3') {
  73. // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
  74. $RIFFsubtype = 'WAVE';
  75. }
  76. if ($RIFFsubtype != 'AMV ') {
  77. // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
  78. // Handled separately in ParseRIFFAMV()
  79. $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
  80. }
  81. if (($info['avdataend'] - $info['filesize']) == 1) {
  82. // LiteWave appears to incorrectly *not* pad actual output file
  83. // to nearest WORD boundary so may appear to be short by one
  84. // byte, in which case - skip warning
  85. $info['avdataend'] = $info['filesize'];
  86. }
  87. $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset
  88. while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
  89. try {
  90. $this->fseek($nextRIFFoffset);
  91. } catch (getid3_exception $e) {
  92. if ($e->getCode() == 10) {
  93. //$this->warning('RIFF parser: '.$e->getMessage());
  94. $this->error('AVI extends beyond '.round(PHP_INT_MAX / 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong');
  95. $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present');
  96. break;
  97. } else {
  98. throw $e;
  99. }
  100. }
  101. $nextRIFFheader = $this->fread(12);
  102. if ($nextRIFFoffset == ($info['avdataend'] - 1)) {
  103. if (substr($nextRIFFheader, 0, 1) == "\x00") {
  104. // RIFF padded to WORD boundary, we're actually already at the end
  105. break;
  106. }
  107. }
  108. $nextRIFFheaderID = substr($nextRIFFheader, 0, 4);
  109. $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
  110. $nextRIFFtype = substr($nextRIFFheader, 8, 4);
  111. $chunkdata = array();
  112. $chunkdata['offset'] = $nextRIFFoffset + 8;
  113. $chunkdata['size'] = $nextRIFFsize;
  114. $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
  115. switch ($nextRIFFheaderID) {
  116. case 'RIFF':
  117. $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
  118. if (!isset($thisfile_riff[$nextRIFFtype])) {
  119. $thisfile_riff[$nextRIFFtype] = array();
  120. }
  121. $thisfile_riff[$nextRIFFtype][] = $chunkdata;
  122. break;
  123. case 'AMV ':
  124. unset($info['riff']);
  125. $info['amv'] = $this->ParseRIFFAMV($chunkdata['offset'] + 4, $nextRIFFoffset);
  126. break;
  127. case 'JUNK':
  128. // ignore
  129. $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
  130. break;
  131. case 'IDVX':
  132. $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunkdata['size']));
  133. break;
  134. default:
  135. if ($info['filesize'] == ($chunkdata['offset'] - 8 + 128)) {
  136. $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12);
  137. if (substr($DIVXTAG, -7) == 'DIVXTAG') {
  138. // 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
  139. $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway');
  140. $info['divxtag']['comments'] = self::ParseDIVXTAG($DIVXTAG);
  141. break 2;
  142. }
  143. }
  144. $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file');
  145. break 2;
  146. }
  147. }
  148. if ($RIFFsubtype == 'WAVE') {
  149. $thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
  150. }
  151. break;
  152. default:
  153. $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
  154. //unset($info['fileformat']);
  155. return false;
  156. }
  157. $streamindex = 0;
  158. switch ($RIFFsubtype) {
  159. // http://en.wikipedia.org/wiki/Wav
  160. case 'WAVE':
  161. $info['fileformat'] = 'wav';
  162. if (empty($thisfile_audio['bitrate_mode'])) {
  163. $thisfile_audio['bitrate_mode'] = 'cbr';
  164. }
  165. if (empty($thisfile_audio_dataformat)) {
  166. $thisfile_audio_dataformat = 'wav';
  167. }
  168. if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
  169. $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
  170. $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size'];
  171. }
  172. if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
  173. $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
  174. $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
  175. if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
  176. $this->error('Corrupt RIFF file: bitrate_audio == zero');
  177. return false;
  178. }
  179. $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
  180. unset($thisfile_riff_audio[$streamindex]['raw']);
  181. $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
  182. $thisfile_audio = (array) getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
  183. if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
  184. $this->warning('Audio codec = '.$thisfile_audio['codec']);
  185. }
  186. $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
  187. if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV)
  188. $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
  189. }
  190. $thisfile_audio['lossless'] = false;
  191. if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
  192. switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
  193. case 0x0001: // PCM
  194. $thisfile_audio['lossless'] = true;
  195. break;
  196. case 0x2000: // AC-3
  197. $thisfile_audio_dataformat = 'ac3';
  198. break;
  199. default:
  200. // do nothing
  201. break;
  202. }
  203. }
  204. $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
  205. $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
  206. $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless'];
  207. $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat;
  208. }
  209. if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
  210. // shortcuts
  211. $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data'];
  212. $thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array());
  213. $thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad'];
  214. $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track'];
  215. $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album'];
  216. $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4));
  217. $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2));
  218. $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2));
  219. $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
  220. $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
  221. $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
  222. $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
  223. $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
  224. $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
  225. $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
  226. $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
  227. $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
  228. $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
  229. $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
  230. if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) {
  231. $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
  232. $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
  233. $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
  234. }
  235. if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) {
  236. $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
  237. $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
  238. $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
  239. }
  240. }
  241. if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
  242. $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
  243. // This should be a good way of calculating exact playtime,
  244. // but some sample files have had incorrect number of samples,
  245. // so cannot use this method
  246. // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
  247. // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
  248. // }
  249. }
  250. if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
  251. $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
  252. }
  253. if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
  254. // shortcut
  255. $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
  256. $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
  257. $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
  258. $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
  259. $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
  260. $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
  261. $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
  262. $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1));
  263. $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254);
  264. $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
  265. if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
  266. if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
  267. list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date;
  268. list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
  269. $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']);
  270. } else {
  271. $this->warning('RIFF.WAVE.BEXT.origin_time is invalid');
  272. }
  273. } else {
  274. $this->warning('RIFF.WAVE.BEXT.origin_date is invalid');
  275. }
  276. $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
  277. $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
  278. }
  279. if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
  280. // shortcut
  281. $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0];
  282. $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
  283. $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001);
  284. if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
  285. $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true;
  286. $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004);
  287. $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008);
  288. $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
  289. }
  290. $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
  291. $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
  292. $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001);
  293. $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002);
  294. $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004);
  295. }
  296. if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
  297. // shortcut
  298. $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0];
  299. $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4);
  300. $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64));
  301. $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64));
  302. $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
  303. $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
  304. $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
  305. $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
  306. $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
  307. $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
  308. $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8));
  309. $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
  310. $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8));
  311. $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
  312. $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
  313. $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
  314. $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true);
  315. for ($i = 0; $i < 8; $i++) {
  316. $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4);
  317. $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));
  318. }
  319. $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
  320. $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
  321. $thisfile_riff['comments']['tag_text'][] = substr($thisfile_riff_WAVE_cart_0['data'], 1772);
  322. $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
  323. $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
  324. }
  325. if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
  326. // SoundMiner metadata
  327. // shortcuts
  328. $thisfile_riff_WAVE_SNDM_0 = &$thisfile_riff_WAVE['SNDM'][0];
  329. $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data'];
  330. $SNDM_startoffset = 0;
  331. $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size'];
  332. while ($SNDM_startoffset < $SNDM_endoffset) {
  333. $SNDM_thisTagOffset = 0;
  334. $SNDM_thisTagSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4));
  335. $SNDM_thisTagOffset += 4;
  336. $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4);
  337. $SNDM_thisTagOffset += 4;
  338. $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
  339. $SNDM_thisTagOffset += 2;
  340. $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
  341. $SNDM_thisTagOffset += 2;
  342. $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize);
  343. $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
  344. if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
  345. $this->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).')');
  346. break;
  347. } elseif ($SNDM_thisTagSize <= 0) {
  348. $this->warning('RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
  349. break;
  350. }
  351. $SNDM_startoffset += $SNDM_thisTagSize;
  352. $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
  353. if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) {
  354. $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
  355. } else {
  356. $this->warning('RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
  357. }
  358. }
  359. $tagmapping = array(
  360. 'tracktitle'=>'title',
  361. 'category' =>'genre',
  362. 'cdtitle' =>'album',
  363. );
  364. foreach ($tagmapping as $fromkey => $tokey) {
  365. if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
  366. $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
  367. }
  368. }
  369. }
  370. if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) {
  371. // requires functions simplexml_load_string and get_object_vars
  372. if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
  373. $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
  374. if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
  375. @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']);
  376. $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
  377. }
  378. if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
  379. @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']);
  380. $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
  381. }
  382. if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
  383. $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
  384. $timestamp_sample_rate = (is_array($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) ? max($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) : $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']); // XML could possibly contain more than one TIMESTAMP_SAMPLE_RATE tag, returning as array instead of integer [why? does it make sense? perhaps doesn't matter but getID3 needs to deal with it] - see https://github.com/JamesHeinrich/getID3/issues/105
  385. $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate;
  386. $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
  387. $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60);
  388. $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
  389. $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
  390. $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
  391. $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
  392. unset($samples_since_midnight, $timestamp_sample_rate, $h, $m, $s, $f);
  393. }
  394. unset($parsedXML);
  395. }
  396. }
  397. if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
  398. $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
  399. $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
  400. }
  401. if (!empty($info['wavpack'])) {
  402. $thisfile_audio_dataformat = 'wavpack';
  403. $thisfile_audio['bitrate_mode'] = 'vbr';
  404. $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version'];
  405. // Reset to the way it was - RIFF parsing will have messed this up
  406. $info['avdataend'] = $Original['avdataend'];
  407. $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
  408. $this->fseek($info['avdataoffset'] - 44);
  409. $RIFFdata = $this->fread(44);
  410. $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
  411. $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
  412. if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
  413. $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
  414. $this->fseek($info['avdataend']);
  415. $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
  416. }
  417. // move the data chunk after all other chunks (if any)
  418. // so that the RIFF parser doesn't see EOF when trying
  419. // to skip over the data chunk
  420. $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
  421. $getid3_riff = new getid3_riff($this->getid3);
  422. $getid3_riff->ParseRIFFdata($RIFFdata);
  423. unset($getid3_riff);
  424. }
  425. if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
  426. switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
  427. case 0x0001: // PCM
  428. if (!empty($info['ac3'])) {
  429. // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
  430. $thisfile_audio['wformattag'] = 0x2000;
  431. $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']);
  432. $thisfile_audio['lossless'] = false;
  433. $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
  434. $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate'];
  435. }
  436. if (!empty($info['dts'])) {
  437. // Dolby DTS files masquerade as PCM-WAV, but they're not
  438. $thisfile_audio['wformattag'] = 0x2001;
  439. $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']);
  440. $thisfile_audio['lossless'] = false;
  441. $thisfile_audio['bitrate'] = $info['dts']['bitrate'];
  442. $thisfile_audio['sample_rate'] = $info['dts']['sample_rate'];
  443. }
  444. break;
  445. case 0x08AE: // ClearJump LiteWave
  446. $thisfile_audio['bitrate_mode'] = 'vbr';
  447. $thisfile_audio_dataformat = 'litewave';
  448. //typedef struct tagSLwFormat {
  449. // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags
  450. // DWORD m_dwScale; // scale factor for lossy compression
  451. // DWORD m_dwBlockSize; // number of samples in encoded blocks
  452. // WORD m_wQuality; // alias for the scale factor
  453. // WORD m_wMarkDistance; // distance between marks in bytes
  454. // WORD m_wReserved;
  455. //
  456. // //following paramters are ignored if CF_FILESRC is not set
  457. // DWORD m_dwOrgSize; // original file size in bytes
  458. // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file
  459. // DWORD m_dwRiffChunkSize; // riff chunk size in the original file
  460. //
  461. // PCMWAVEFORMAT m_OrgWf; // original wave format
  462. // }SLwFormat, *PSLwFormat;
  463. // shortcut
  464. $thisfile_riff['litewave']['raw'] = array();
  465. $riff_litewave = &$thisfile_riff['litewave'];
  466. $riff_litewave_raw = &$riff_litewave['raw'];
  467. $flags = array(
  468. 'compression_method' => 1,
  469. 'compression_flags' => 1,
  470. 'm_dwScale' => 4,
  471. 'm_dwBlockSize' => 4,
  472. 'm_wQuality' => 2,
  473. 'm_wMarkDistance' => 2,
  474. 'm_wReserved' => 2,
  475. 'm_dwOrgSize' => 4,
  476. 'm_bFactExists' => 2,
  477. 'm_dwRiffChunkSize' => 4,
  478. );
  479. $litewave_offset = 18;
  480. foreach ($flags as $flag => $length) {
  481. $riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length));
  482. $litewave_offset += $length;
  483. }
  484. //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20));
  485. $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality'];
  486. $riff_litewave['flags']['raw_source'] = ($riff_litewave_raw['compression_flags'] & 0x01) ? false : true;
  487. $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ? false : true;
  488. $riff_litewave['flags']['seekpoints'] = (bool) ($riff_litewave_raw['compression_flags'] & 0x04);
  489. $thisfile_audio['lossless'] = (($riff_litewave_raw['m_wQuality'] == 100) ? true : false);
  490. $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor'];
  491. break;
  492. default:
  493. break;
  494. }
  495. }
  496. if ($info['avdataend'] > $info['filesize']) {
  497. switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') {
  498. case 'wavpack': // WavPack
  499. case 'lpac': // LPAC
  500. case 'ofr': // OptimFROG
  501. case 'ofs': // OptimFROG DualStream
  502. // lossless compressed audio formats that keep original RIFF headers - skip warning
  503. break;
  504. case 'litewave':
  505. if (($info['avdataend'] - $info['filesize']) == 1) {
  506. // LiteWave appears to incorrectly *not* pad actual output file
  507. // to nearest WORD boundary so may appear to be short by one
  508. // byte, in which case - skip warning
  509. } else {
  510. // Short by more than one byte, throw warning
  511. $this->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)');
  512. $info['avdataend'] = $info['filesize'];
  513. }
  514. break;
  515. default:
  516. if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) {
  517. // output file appears to be incorrectly *not* padded to nearest WORD boundary
  518. // Output less severe warning
  519. $this->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)');
  520. $info['avdataend'] = $info['filesize'];
  521. } else {
  522. // Short by more than one byte, throw warning
  523. $this->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)');
  524. $info['avdataend'] = $info['filesize'];
  525. }
  526. break;
  527. }
  528. }
  529. if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
  530. if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
  531. $info['avdataend']--;
  532. $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
  533. }
  534. }
  535. if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
  536. unset($thisfile_audio['bits_per_sample']);
  537. if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
  538. $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
  539. }
  540. }
  541. break;
  542. // http://en.wikipedia.org/wiki/Audio_Video_Interleave
  543. case 'AVI ':
  544. $info['fileformat'] = 'avi';
  545. $info['mime_type'] = 'video/avi';
  546. $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
  547. $thisfile_video['dataformat'] = 'avi';
  548. $thisfile_riff_video_current = array();
  549. if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
  550. $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
  551. if (isset($thisfile_riff['AVIX'])) {
  552. $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size'];
  553. } else {
  554. $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
  555. }
  556. if ($info['avdataend'] > $info['filesize']) {
  557. $this->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)');
  558. $info['avdataend'] = $info['filesize'];
  559. }
  560. }
  561. if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
  562. //$bIndexType = array(
  563. // 0x00 => 'AVI_INDEX_OF_INDEXES',
  564. // 0x01 => 'AVI_INDEX_OF_CHUNKS',
  565. // 0x80 => 'AVI_INDEX_IS_DATA',
  566. //);
  567. //$bIndexSubtype = array(
  568. // 0x01 => array(
  569. // 0x01 => 'AVI_INDEX_2FIELD',
  570. // ),
  571. //);
  572. foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
  573. $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
  574. $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd, 0, 2));
  575. $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($ahsisd, 2, 1));
  576. $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($ahsisd, 3, 1));
  577. $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($ahsisd, 4, 4));
  578. $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($ahsisd, 8, 4);
  579. $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($ahsisd, 12, 4));
  580. //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name'] = $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
  581. //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
  582. unset($ahsisd);
  583. }
  584. }
  585. if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
  586. $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
  587. // shortcut
  588. $thisfile_riff_raw['avih'] = array();
  589. $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
  590. $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L)
  591. if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
  592. $this->error('Corrupt RIFF file: avih.dwMicroSecPerFrame == zero');
  593. return false;
  594. }
  595. $flags = array(
  596. 'dwMaxBytesPerSec', // max. transfer rate
  597. 'dwPaddingGranularity', // pad to multiples of this size; normally 2K.
  598. 'dwFlags', // the ever-present flags
  599. 'dwTotalFrames', // # frames in file
  600. 'dwInitialFrames', //
  601. 'dwStreams', //
  602. 'dwSuggestedBufferSize', //
  603. 'dwWidth', //
  604. 'dwHeight', //
  605. 'dwScale', //
  606. 'dwRate', //
  607. 'dwStart', //
  608. 'dwLength', //
  609. );
  610. $avih_offset = 4;
  611. foreach ($flags as $flag) {
  612. $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4));
  613. $avih_offset += 4;
  614. }
  615. $flags = array(
  616. 'hasindex' => 0x00000010,
  617. 'mustuseindex' => 0x00000020,
  618. 'interleaved' => 0x00000100,
  619. 'trustcktype' => 0x00000800,
  620. 'capturedfile' => 0x00010000,
  621. 'copyrighted' => 0x00020010,
  622. );
  623. foreach ($flags as $flag => $value) {
  624. $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
  625. }
  626. // shortcut
  627. $thisfile_riff_video[$streamindex] = array();
  628. /** @var array $thisfile_riff_video_current */
  629. $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
  630. if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
  631. $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
  632. $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width'];
  633. }
  634. if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
  635. $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
  636. $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height'];
  637. }
  638. if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
  639. $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
  640. $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames'];
  641. }
  642. $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
  643. $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
  644. }
  645. if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
  646. if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
  647. for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
  648. if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
  649. $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
  650. $strhfccType = substr($strhData, 0, 4);
  651. if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
  652. $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
  653. // shortcut
  654. $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
  655. switch ($strhfccType) {
  656. case 'auds':
  657. $thisfile_audio['bitrate_mode'] = 'cbr';
  658. $thisfile_audio_dataformat = 'wav';
  659. if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
  660. $streamindex = count($thisfile_riff_audio);
  661. }
  662. $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($strfData);
  663. $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
  664. // shortcut
  665. $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
  666. $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex];
  667. if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
  668. unset($thisfile_audio_streams_currentstream['bits_per_sample']);
  669. }
  670. $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
  671. unset($thisfile_audio_streams_currentstream['raw']);
  672. // shortcut
  673. $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
  674. unset($thisfile_riff_audio[$streamindex]['raw']);
  675. $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
  676. $thisfile_audio['lossless'] = false;
  677. switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
  678. case 0x0001: // PCM
  679. $thisfile_audio_dataformat = 'wav';
  680. $thisfile_audio['lossless'] = true;
  681. break;
  682. case 0x0050: // MPEG Layer 2 or Layer 1
  683. $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
  684. break;
  685. case 0x0055: // MPEG Layer 3
  686. $thisfile_audio_dataformat = 'mp3';
  687. break;
  688. case 0x00FF: // AAC
  689. $thisfile_audio_dataformat = 'aac';
  690. break;
  691. case 0x0161: // Windows Media v7 / v8 / v9
  692. case 0x0162: // Windows Media Professional v9
  693. case 0x0163: // Windows Media Lossess v9
  694. $thisfile_audio_dataformat = 'wma';
  695. break;
  696. case 0x2000: // AC-3
  697. $thisfile_audio_dataformat = 'ac3';
  698. break;
  699. case 0x2001: // DTS
  700. $thisfile_audio_dataformat = 'dts';
  701. break;
  702. default:
  703. $thisfile_audio_dataformat = 'wav';
  704. break;
  705. }
  706. $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat;
  707. $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless'];
  708. $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
  709. break;
  710. case 'iavs':
  711. case 'vids':
  712. // shortcut
  713. $thisfile_riff_raw['strh'][$i] = array();
  714. $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i];
  715. $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType;
  716. $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4);
  717. $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4)); // Contains AVITF_* flags
  718. $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2));
  719. $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2));
  720. $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4));
  721. $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4));
  722. $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4));
  723. $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4));
  724. $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4));
  725. $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4));
  726. $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4));
  727. $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4));
  728. $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4));
  729. $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
  730. $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler'];
  731. if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
  732. $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
  733. $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
  734. }
  735. $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
  736. $thisfile_video['pixel_aspect_ratio'] = (float) 1;
  737. switch ($thisfile_riff_raw_strh_current['fccHandler']) {
  738. case 'HFYU': // Huffman Lossless Codec
  739. case 'IRAW': // Intel YUV Uncompressed
  740. case 'YUY2': // Uncompressed YUV 4:2:2
  741. $thisfile_video['lossless'] = true;
  742. break;
  743. default:
  744. $thisfile_video['lossless'] = false;
  745. break;
  746. }
  747. switch ($strhfccType) {
  748. case 'vids':
  749. $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($this->container == 'riff'));
  750. $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
  751. if ($thisfile_riff_video_current['codec'] == 'DV') {
  752. $thisfile_riff_video_current['dv_type'] = 2;
  753. }
  754. break;
  755. case 'iavs':
  756. $thisfile_riff_video_current['dv_type'] = 1;
  757. break;
  758. }
  759. break;
  760. default:
  761. $this->warning('Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"');
  762. break;
  763. }
  764. }
  765. }
  766. if (isset($thisfile_riff_raw_strf_strhfccType_streamindex) && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
  767. $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
  768. if (self::fourccLookup($thisfile_video['fourcc'])) {
  769. $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']);
  770. $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
  771. }
  772. switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
  773. case 'HFYU': // Huffman Lossless Codec
  774. case 'IRAW': // Intel YUV Uncompressed
  775. case 'YUY2': // Uncompressed YUV 4:2:2
  776. $thisfile_video['lossless'] = true;
  777. //$thisfile_video['bits_per_sample'] = 24;
  778. break;
  779. default:
  780. $thisfile_video['lossless'] = false;
  781. //$thisfile_video['bits_per_sample'] = 24;
  782. break;
  783. }
  784. }
  785. }
  786. }
  787. }
  788. break;
  789. case 'AMV ':
  790. $info['fileformat'] = 'amv';
  791. $info['mime_type'] = 'video/amv';
  792. $thisfile_video['bitrate_mode'] = 'vbr'; // it's MJPEG, presumably contant-quality encoding, thereby VBR
  793. $thisfile_video['dataformat'] = 'mjpeg';
  794. $thisfile_video['codec'] = 'mjpeg';
  795. $thisfile_video['lossless'] = false;
  796. $thisfile_video['bits_per_sample'] = 24;
  797. $thisfile_audio['dataformat'] = 'adpcm';
  798. $thisfile_audio['lossless'] = false;
  799. break;
  800. // http://en.wikipedia.org/wiki/CD-DA
  801. case 'CDDA':
  802. $info['fileformat'] = 'cda';
  803. unset($info['mime_type']);
  804. $thisfile_audio_dataformat = 'cda';
  805. $info['avdataoffset'] = 44;
  806. if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
  807. // shortcut
  808. $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0];
  809. $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2));
  810. $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2));
  811. $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4));
  812. $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4));
  813. $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
  814. $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
  815. $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
  816. $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
  817. $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
  818. $info['comments']['track_number'] = $thisfile_riff_CDDA_fmt_0['track_num'];
  819. $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
  820. // hardcoded data for CD-audio
  821. $thisfile_audio['lossless'] = true;
  822. $thisfile_audio['sample_rate'] = 44100;
  823. $thisfile_audio['channels'] = 2;
  824. $thisfile_audio['bits_per_sample'] = 16;
  825. $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
  826. $thisfile_audio['bitrate_mode'] = 'cbr';
  827. }
  828. break;
  829. // http://en.wikipedia.org/wiki/AIFF
  830. case 'AIFF':
  831. case 'AIFC':
  832. $info['fileformat'] = 'aiff';
  833. $info['mime_type'] = 'audio/x-aiff';
  834. $thisfile_audio['bitrate_mode'] = 'cbr';
  835. $thisfile_audio_dataformat = 'aiff';
  836. $thisfile_audio['lossless'] = true;
  837. if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
  838. $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
  839. $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
  840. if ($info['avdataend'] > $info['filesize']) {
  841. if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) {
  842. // structures rounded to 2-byte boundary, but dumb encoders
  843. // forget to pad end of file to make this actually work
  844. } else {
  845. $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
  846. }
  847. $info['avdataend'] = $info['filesize'];
  848. }
  849. }
  850. if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
  851. // shortcut
  852. $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
  853. $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true);
  854. $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false);
  855. $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true);
  856. $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10));
  857. if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
  858. $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
  859. $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false);
  860. $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize);
  861. switch ($thisfile_riff_audio['codec_name']) {
  862. case 'NONE':
  863. $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
  864. $thisfile_audio['lossless'] = true;
  865. break;
  866. case '':
  867. switch ($thisfile_riff_audio['codec_fourcc']) {
  868. // http://developer.apple.com/qa/snd/snd07.html
  869. case 'sowt':
  870. $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
  871. $thisfile_audio['lossless'] = true;
  872. break;
  873. case 'twos':
  874. $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
  875. $thisfile_audio['lossless'] = true;
  876. break;
  877. default:
  878. break;
  879. }
  880. break;
  881. default:
  882. $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
  883. $thisfile_audio['lossless'] = false;
  884. break;
  885. }
  886. }
  887. $thisfile_audio['channels'] = $thisfile_riff_audio['channels'];
  888. if ($thisfile_riff_audio['bits_per_sample'] > 0) {
  889. $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
  890. }
  891. $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
  892. if ($thisfile_audio['sample_rate'] == 0) {
  893. $this->error('Corrupted AIFF file: sample_rate == zero');
  894. return false;
  895. }
  896. $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
  897. }
  898. if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
  899. $offset = 0;
  900. $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
  901. $offset += 2;
  902. for ($i = 0; $i < $CommentCount; $i++) {
  903. $info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
  904. $offset += 4;
  905. $info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
  906. $offset += 2;
  907. $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
  908. $offset += 2;
  909. $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
  910. $offset += $CommentLength;
  911. $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']);
  912. $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment'];
  913. }
  914. }
  915. $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
  916. foreach ($CommentsChunkNames as $key => $value) {
  917. if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
  918. $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
  919. }
  920. }
  921. /*
  922. if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
  923. getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
  924. $getid3_temp = new getID3();
  925. $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
  926. $getid3_id3v2 = new getid3_id3v2($getid3_temp);
  927. $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
  928. if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
  929. $info['id3v2'] = $getid3_temp->info['id3v2'];
  930. }
  931. unset($getid3_temp, $getid3_id3v2);
  932. }
  933. */
  934. break;
  935. // http://en.wikipedia.org/wiki/8SVX
  936. case '8SVX':
  937. $info['fileformat'] = '8svx';
  938. $info['mime_type'] = 'audio/8svx';
  939. $thisfile_audio['bitrate_mode'] = 'cbr';
  940. $thisfile_audio_dataformat = '8svx';
  941. $thisfile_audio['bits_per_sample'] = 8;
  942. $thisfile_audio['channels'] = 1; // overridden below, if need be
  943. $ActualBitsPerSample = 0;
  944. if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
  945. $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
  946. $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
  947. if ($info['avdataend'] > $info['filesize']) {
  948. $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
  949. }
  950. }
  951. if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
  952. // shortcut
  953. $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0];
  954. $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4));
  955. $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4));
  956. $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4));
  957. $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
  958. $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
  959. $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
  960. $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
  961. $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
  962. switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
  963. case 0:
  964. $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
  965. $thisfile_audio['lossless'] = true;
  966. $ActualBitsPerSample = 8;
  967. break;
  968. case 1:
  969. $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
  970. $thisfile_audio['lossless'] = false;
  971. $ActualBitsPerSample = 4;
  972. break;
  973. default:
  974. $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.$thisfile_riff_RIFFsubtype_VHDR_0['sCompression'].'"');
  975. break;
  976. }
  977. }
  978. if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
  979. $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
  980. switch ($ChannelsIndex) {
  981. case 6: // Stereo
  982. $thisfile_audio['channels'] = 2;
  983. break;
  984. case 2: // Left channel only
  985. case 4: // Right channel only
  986. $thisfile_audio['channels'] = 1;
  987. break;
  988. default:
  989. $this->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"');
  990. break;
  991. }
  992. }
  993. $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
  994. foreach ($CommentsChunkNames as $key => $value) {
  995. if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
  996. $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
  997. }
  998. }
  999. $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
  1000. if (!empty($thisfile_audio['bitrate'])) {
  1001. $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
  1002. }
  1003. break;
  1004. case 'CDXA':
  1005. $info['fileformat'] = 'vcd'; // Asume Video CD
  1006. $info['mime_type'] = 'video/mpeg';
  1007. if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
  1008. getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
  1009. $getid3_temp = new getID3();
  1010. $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
  1011. $getid3_mpeg = new getid3_mpeg($getid3_temp);
  1012. $getid3_mpeg->Analyze();
  1013. if (empty($getid3_temp->info['error'])) {
  1014. $info['audio'] = $getid3_temp->info['audio'];
  1015. $info['video'] = $getid3_temp->info['video'];
  1016. $info['mpeg'] = $getid3_temp->info['mpeg'];
  1017. $info['warning'] = $getid3_temp->info['warning'];
  1018. }
  1019. unset($getid3_temp, $getid3_mpeg);
  1020. }
  1021. break;
  1022. case 'WEBP':
  1023. // https://developers.google.com/speed/webp/docs/riff_container
  1024. // https://tools.ietf.org/html/rfc6386
  1025. // https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
  1026. $info['fileformat'] = 'webp';
  1027. $info['mime_type'] = 'image/webp';
  1028. if (!empty($thisfile_riff['WEBP']['VP8 '][0]['size'])) {
  1029. $old_offset = $this->ftell();
  1030. $this->fseek($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8); // 4 bytes "VP8 " + 4 bytes chunk size
  1031. $WEBP_VP8_header = $this->fread(10);
  1032. $this->fseek($old_offset);
  1033. if (substr($WEBP_VP8_header, 3, 3) == "\x9D\x01\x2A") {
  1034. $thisfile_riff['WEBP']['VP8 '][0]['keyframe'] = !(getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x800000);
  1035. $thisfile_riff['WEBP']['VP8 '][0]['version'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x700000) >> 20;
  1036. $thisfile_riff['WEBP']['VP8 '][0]['show_frame'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x080000);
  1037. $thisfile_riff['WEBP']['VP8 '][0]['data_bytes'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x07FFFF) >> 0;
  1038. $thisfile_riff['WEBP']['VP8 '][0]['scale_x'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0xC000) >> 14;
  1039. $thisfile_riff['WEBP']['VP8 '][0]['width'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0x3FFF);
  1040. $thisfile_riff['WEBP']['VP8 '][0]['scale_y'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0xC000) >> 14;
  1041. $thisfile_riff['WEBP']['VP8 '][0]['height'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0x3FFF);
  1042. $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8 '][0]['width'];
  1043. $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8 '][0]['height'];
  1044. } else {
  1045. $this->error('Expecting 9D 01 2A at offset '.($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8 + 3).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8_header, 3, 3)).'"');
  1046. }
  1047. }
  1048. if (!empty($thisfile_riff['WEBP']['VP8L'][0]['size'])) {
  1049. $old_offset = $this->ftell();
  1050. $this->fseek($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8); // 4 bytes "VP8L" + 4 bytes chunk size
  1051. $WEBP_VP8L_header = $this->fread(10);
  1052. $this->fseek($old_offset);
  1053. if (substr($WEBP_VP8L_header, 0, 1) == "\x2F") {
  1054. $width_height_flags = getid3_lib::LittleEndian2Bin(substr($WEBP_VP8L_header, 1, 4));
  1055. $thisfile_riff['WEBP']['VP8L'][0]['width'] = bindec(substr($width_height_flags, 18, 14)) + 1;
  1056. $thisfile_riff['WEBP']['VP8L'][0]['height'] = bindec(substr($width_height_flags, 4, 14)) + 1;
  1057. $thisfile_riff['WEBP']['VP8L'][0]['alpha_is_used'] = (bool) bindec(substr($width_height_flags, 3, 1));
  1058. $thisfile_riff['WEBP']['VP8L'][0]['version'] = bindec(substr($width_height_flags, 0, 3));
  1059. $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8L'][0]['width'];
  1060. $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8L'][0]['height'];
  1061. } else {
  1062. $this->error('Expecting 2F at offset '.($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8L_header, 0, 1)).'"');
  1063. }
  1064. }
  1065. break;
  1066. default:
  1067. $this->error('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead');
  1068. //unset($info['fileformat']);
  1069. }
  1070. switch ($RIFFsubtype) {
  1071. case 'WAVE':
  1072. case 'AIFF':
  1073. case 'AIFC':
  1074. $ID3v2_key_good = 'id3 ';
  1075. $ID3v2_keys_bad = array('ID3 ', 'tag ');
  1076. foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
  1077. if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
  1078. $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
  1079. $this->warning('mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"');
  1080. }
  1081. }
  1082. if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
  1083. getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
  1084. $getid3_temp = new getID3();
  1085. $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
  1086. $getid3_id3v2 = new getid3_id3v2($getid3_temp);
  1087. $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
  1088. if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
  1089. $info['id3v2'] = $getid3_temp->info['id3v2'];
  1090. }
  1091. unset($getid3_temp, $getid3_id3v2);
  1092. }
  1093. break;
  1094. }
  1095. if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
  1096. $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
  1097. }
  1098. if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
  1099. self::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
  1100. }
  1101. if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
  1102. self::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
  1103. }
  1104. if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
  1105. $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
  1106. }
  1107. if (!isset($info['playtime_seconds'])) {
  1108. $info['playtime_seconds'] = 0;
  1109. }
  1110. if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
  1111. // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
  1112. $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
  1113. } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
  1114. $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
  1115. }
  1116. if ($info['playtime_seconds'] > 0) {
  1117. if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
  1118. if (!isset($info['bitrate'])) {
  1119. $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
  1120. }
  1121. } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
  1122. if (!isset($thisfile_audio['bitrate'])) {
  1123. $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
  1124. }
  1125. } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
  1126. if (!isset($thisfile_video['bitrate'])) {
  1127. $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
  1128. }
  1129. }
  1130. }
  1131. if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) {
  1132. $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
  1133. $thisfile_audio['bitrate'] = 0;
  1134. $thisfile_video['bitrate'] = $info['bitrate'];
  1135. foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
  1136. $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
  1137. $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
  1138. }
  1139. if ($thisfile_video['bitrate'] <= 0) {
  1140. unset($thisfile_video['bitrate']);
  1141. }
  1142. if ($thisfile_audio['bitrate'] <= 0) {
  1143. unset($thisfile_audio['bitrate']);
  1144. }
  1145. }
  1146. if (isset($info['mpeg']['audio'])) {
  1147. $thisfile_audio_dataformat = 'mp'.$info['mpeg']['audio']['layer'];
  1148. $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
  1149. $thisfile_audio['channels'] = $info['mpeg']['audio']['channels'];
  1150. $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate'];
  1151. $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
  1152. if (!empty($info['mpeg']['audio']['codec'])) {
  1153. $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec'];
  1154. }
  1155. if (!empty($thisfile_audio['streams'])) {
  1156. foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
  1157. if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
  1158. $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate'];
  1159. $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels'];
  1160. $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
  1161. $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
  1162. $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec'];
  1163. }
  1164. }
  1165. }
  1166. $getid3_mp3 = new getid3_mp3($this->getid3);
  1167. $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
  1168. unset($getid3_mp3);
  1169. }
  1170. if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) {
  1171. switch ($thisfile_audio_dataformat) {
  1172. case 'ac3':
  1173. // ignore bits_per_sample
  1174. break;
  1175. default:
  1176. $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
  1177. break;
  1178. }
  1179. }
  1180. if (empty($thisfile_riff_raw)) {
  1181. unset($thisfile_riff['raw']);
  1182. }
  1183. if (empty($thisfile_riff_audio)) {
  1184. unset($thisfile_riff['audio']);
  1185. }
  1186. if (empty($thisfile_riff_video)) {
  1187. unset($thisfile_riff['video']);
  1188. }
  1189. return true;
  1190. }
  1191. /**
  1192. * @param int $startoffset
  1193. * @param int $maxoffset
  1194. *
  1195. * @return array|false
  1196. *
  1197. * @throws Exception
  1198. * @throws getid3_exception
  1199. */
  1200. public function ParseRIFFAMV($startoffset, $maxoffset) {
  1201. // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
  1202. // https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation
  1203. //typedef struct _amvmainheader {
  1204. //FOURCC fcc; // 'amvh'
  1205. //DWORD cb;
  1206. //DWORD dwMicroSecPerFrame;
  1207. //BYTE reserve[28];
  1208. //DWORD dwWidth;
  1209. //DWORD dwHeight;
  1210. //DWORD dwSpeed;
  1211. //DWORD reserve0;
  1212. //DWORD reserve1;
  1213. //BYTE bTimeSec;
  1214. //BYTE bTimeMin;
  1215. //WORD wTimeHour;
  1216. //} AMVMAINHEADER;
  1217. $info = &$this->getid3->info;
  1218. $RIFFchunk = false;
  1219. try {
  1220. $this->fseek($startoffset);
  1221. $maxoffset = min($maxoffset, $info['avdataend']);
  1222. $AMVheader = $this->fread(284);
  1223. if (substr($AMVheader, 0, 8) != 'hdrlamvh') {
  1224. throw new Exception('expecting "hdrlamv" at offset '.($startoffset + 0).', found "'.substr($AMVheader, 0, 8).'"');
  1225. }
  1226. if (substr($AMVheader, 8, 4) != "\x38\x00\x00\x00") { // "amvh" chunk size, hardcoded to 0x38 = 56 bytes
  1227. throw new Exception('expecting "0x38000000" at offset '.($startoffset + 8).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 8, 4)).'"');
  1228. }
  1229. $RIFFchunk = array();
  1230. $RIFFchunk['amvh']['us_per_frame'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 12, 4));
  1231. $RIFFchunk['amvh']['reserved28'] = substr($AMVheader, 16, 28); // null? reserved?
  1232. $RIFFchunk['amvh']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 44, 4));
  1233. $RIFFchunk['amvh']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 48, 4));
  1234. $RIFFchunk['amvh']['frame_rate_int'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 52, 4));
  1235. $RIFFchunk['amvh']['reserved0'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 56, 4)); // 1? reserved?
  1236. $RIFFchunk['amvh']['reserved1'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 60, 4)); // 0? reserved?
  1237. $RIFFchunk['amvh']['runtime_sec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 64, 1));
  1238. $RIFFchunk['amvh']['runtime_min'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 65, 1));
  1239. $RIFFchunk['amvh']['runtime_hrs'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 66, 2));
  1240. $info['video']['frame_rate'] = 1000000 / $RIFFchunk['amvh']['us_per_frame'];
  1241. $info['video']['resolution_x'] = $RIFFchunk['amvh']['resolution_x'];
  1242. $info['video']['resolution_y'] = $RIFFchunk['amvh']['resolution_y'];
  1243. $info['playtime_seconds'] = ($RIFFchunk['amvh']['runtime_hrs'] * 3600) + ($RIFFchunk['amvh']['runtime_min'] * 60) + $RIFFchunk['amvh']['runtime_sec'];
  1244. // the rest is all hardcoded(?) and does not appear to be useful until you get to audio info at offset 256, even then everything is probably hardcoded
  1245. if (substr($AMVheader, 68, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x38\x00\x00\x00") {
  1246. throw new Exception('expecting "LIST<0x00000000>strlstrh<0x38000000>" at offset '.($startoffset + 68).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 68, 20)).'"');
  1247. }
  1248. // followed by 56 bytes of null: substr($AMVheader, 88, 56) -> 144
  1249. if (substr($AMVheader, 144, 8) != 'strf'."\x24\x00\x00\x00") {
  1250. throw new Exception('expecting "strf<0x24000000>" at offset '.($startoffset + 144).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 144, 8)).'"');
  1251. }
  1252. // followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180
  1253. if (substr($AMVheader, 188, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x30\x00\x00\x00") {
  1254. throw new Exception('expecting "LIST<0x00000000>strlstrh<0x30000000>" at offset '.($startoffset + 188).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 188, 20)).'"');
  1255. }
  1256. // followed by 48 bytes of null: substr($AMVheader, 208, 48) -> 256
  1257. if (substr($AMVheader, 256, 8) != 'strf'."\x14\x00\x00\x00") {
  1258. throw new Exception('expecting "strf<0x14000000>" at offset '.($startoffset + 256).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 256, 8)).'"');
  1259. }
  1260. // followed by 20 bytes of a modified WAVEFORMATEX:
  1261. // typedef struct {
  1262. // WORD wFormatTag; //(Fixme: this is equal to PCM's 0x01 format code)
  1263. // WORD nChannels; //(Fixme: this is always 1)
  1264. // DWORD nSamplesPerSec; //(Fixme: for all known sample files this is equal to 22050)
  1265. // DWORD nAvgBytesPerSec; //(Fixme: for all known sample files this is equal to 44100)
  1266. // WORD nBlockAlign; //(Fixme: this seems to be 2 in AMV files, is this correct ?)
  1267. // WORD wBitsPerSample; //(Fixme: this seems to be 16 in AMV files instead of the expected 4)
  1268. // WORD cbSize; //(Fixme: this seems to be 0 in AMV files)
  1269. // WORD reserved;
  1270. // } WAVEFORMATEX;
  1271. $RIFFchunk['strf']['wformattag'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 264, 2));
  1272. $RIFFchunk['strf']['nchannels'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 266, 2));
  1273. $RIFFchunk['strf']['nsamplespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 268, 4));
  1274. $RIFFchunk['strf']['navgbytespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 272, 4));
  1275. $RIFFchunk['strf']['nblockalign'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 276, 2));
  1276. $RIFFchunk['strf']['wbitspersample'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 278, 2));
  1277. $RIFFchunk['strf']['cbsize'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 280, 2));
  1278. $RIFFchunk['strf']['reserved'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 282, 2));
  1279. $info['audio']['lossless'] = false;
  1280. $info['audio']['sample_rate'] = $RIFFchunk['strf']['nsamplespersec'];
  1281. $info['audio']['channels'] = $RIFFchunk['strf']['nchannels'];
  1282. $info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample'];
  1283. $info['audio']['bitrate'] = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample'];
  1284. $info['audio']['bitrate_mode'] = 'cbr';
  1285. } catch (getid3_exception $e) {
  1286. if ($e->getCode() == 10) {
  1287. $this->warning('RIFFAMV parser: '.$e->getMessage());
  1288. } else {
  1289. throw $e;
  1290. }
  1291. }
  1292. return $RIFFchunk;
  1293. }
  1294. /**
  1295. * @param int $startoffset
  1296. * @param int $maxoffset
  1297. *
  1298. * @return array|false
  1299. * @throws getid3_exception
  1300. */
  1301. public function ParseRIFF($startoffset, $maxoffset) {
  1302. $info = &$this->getid3->info;
  1303. $RIFFchunk = false;
  1304. $FoundAllChunksWeNeed = false;
  1305. try {
  1306. $this->fseek($startoffset);
  1307. $maxoffset = min($maxoffset, $info['avdataend']);
  1308. while ($this->ftell() < $maxoffset) {
  1309. $chunknamesize = $this->fread(8);
  1310. //$chunkname = substr($chunknamesize, 0, 4);
  1311. $chunkname = str_replace("\x00", '_', substr($chunknamesize, 0, 4)); // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult
  1312. $chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4));
  1313. //if (strlen(trim($chunkname, "\x00")) < 4) {
  1314. if (strlen($chunkname) < 4) {
  1315. $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.');
  1316. break;
  1317. }
  1318. if (($chunksize == 0) && ($chunkname != 'JUNK')) {
  1319. $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.');
  1320. break;
  1321. }
  1322. if (($chunksize % 2) != 0) {
  1323. // all structures are packed on word boundaries
  1324. $chunksize++;
  1325. }
  1326. switch ($chunkname) {
  1327. case 'LIST':
  1328. $listname = $this->fread(4);
  1329. if (preg_match('#^(movi|rec )$#i', $listname)) {
  1330. $RIFFchunk[$listname]['offset'] = $this->ftell() - 4;
  1331. $RIFFchunk[$listname]['size'] = $chunksize;
  1332. if (!$FoundAllChunksWeNeed) {
  1333. $WhereWeWere = $this->ftell();
  1334. $AudioChunkHeader = $this->fread(12);
  1335. $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2);
  1336. $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2);
  1337. $AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
  1338. if ($AudioChunkStreamType == 'wb') {
  1339. $FirstFourBytes = substr($AudioChunkHeader, 8, 4);
  1340. if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) {
  1341. // MP3
  1342. if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
  1343. $getid3_temp = new getID3();
  1344. $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
  1345. $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
  1346. $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
  1347. $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
  1348. $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
  1349. if (isset($getid3_temp->info['mpeg']['audio'])) {
  1350. $info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio'];
  1351. $info['audio'] = $getid3_temp->info['audio'];
  1352. $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
  1353. $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
  1354. $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
  1355. $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
  1356. $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
  1357. //$info['bitrate'] = $info['audio']['bitrate'];
  1358. }
  1359. unset($getid3_temp, $getid3_mp3);
  1360. }
  1361. } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
  1362. // AC3
  1363. $getid3_temp = new getID3();
  1364. $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
  1365. $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
  1366. $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
  1367. $getid3_ac3 = new getid3_ac3($getid3_temp);
  1368. $getid3_ac3->Analyze();
  1369. if (empty($getid3_temp->info['error'])) {
  1370. $info['audio'] = $getid3_temp->info['audio'];
  1371. $info['ac3'] = $getid3_temp->info['ac3'];
  1372. if (!empty($getid3_temp->info['warning'])) {
  1373. foreach ($getid3_temp->info['warning'] as $key => $value) {
  1374. $this->warning($value);
  1375. }
  1376. }
  1377. }
  1378. unset($getid3_temp, $getid3_ac3);
  1379. }
  1380. }
  1381. $FoundAllChunksWeNeed = true;
  1382. $this->fseek($WhereWeWere);
  1383. }
  1384. $this->fseek($chunksize - 4, SEEK_CUR);
  1385. } else {
  1386. if (!isset($RIFFchunk[$listname])) {
  1387. $RIFFchunk[$listname] = array();
  1388. }
  1389. $LISTchunkParent = $listname;
  1390. $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize;
  1391. if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
  1392. $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
  1393. }
  1394. }
  1395. break;
  1396. default:
  1397. if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
  1398. $this->fseek($chunksize, SEEK_CUR);
  1399. break;
  1400. }
  1401. $thisindex = 0;
  1402. if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
  1403. $thisindex = count($RIFFchunk[$chunkname]);
  1404. }
  1405. $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
  1406. $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize;
  1407. switch ($chunkname) {
  1408. case 'data':
  1409. $info['avdataoffset'] = $this->ftell();
  1410. $info['avdataend'] = $info['avdataoffset'] + $chunksize;
  1411. $testData = $this->fread(36);
  1412. if ($testData === '') {
  1413. break;
  1414. }
  1415. if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
  1416. // Probably is MP3 data
  1417. if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
  1418. $getid3_temp = new getID3();
  1419. $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
  1420. $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
  1421. $getid3_temp->info['avdataend'] = $info['avdataend'];
  1422. $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
  1423. $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
  1424. if (empty($getid3_temp->info['error'])) {
  1425. $info['audio'] = $getid3_temp->info['audio'];
  1426. $info['mpeg'] = $getid3_temp->info['mpeg'];
  1427. }
  1428. unset($getid3_temp, $getid3_mp3);
  1429. }
  1430. } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {
  1431. // This is probably AC-3 data
  1432. $getid3_temp = new getID3();
  1433. if ($isRegularAC3) {
  1434. $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
  1435. $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
  1436. $getid3_temp->info['avdataend'] = $info['avdataend'];
  1437. }
  1438. $getid3_ac3 = new getid3_ac3($getid3_temp);
  1439. if ($isRegularAC3) {
  1440. $getid3_ac3->Analyze();
  1441. } else {
  1442. // Dolby Digital WAV
  1443. // AC-3 content, but not encoded in same format as normal AC-3 file
  1444. // For one thing, byte order is swapped
  1445. $ac3_data = '';
  1446. for ($i = 0; $i < 28; $i += 2) {
  1447. $ac3_data .= substr($testData, 8 + $i + 1, 1);
  1448. $ac3_data .= substr($testData, 8 + $i + 0, 1);
  1449. }
  1450. $getid3_ac3->AnalyzeString($ac3_data);
  1451. }
  1452. if (empty($getid3_temp->info['error'])) {
  1453. $info['audio'] = $getid3_temp->info['audio'];
  1454. $info['ac3'] = $getid3_temp->info['ac3'];
  1455. if (!empty($getid3_temp->info['warning'])) {
  1456. foreach ($getid3_temp->info['warning'] as $newerror) {
  1457. $this->warning('getid3_ac3() says: ['.$newerror.']');
  1458. }
  1459. }
  1460. }
  1461. unset($getid3_temp, $getid3_ac3);
  1462. } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) {
  1463. // This is probably DTS data
  1464. $getid3_temp = new getID3();
  1465. $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
  1466. $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
  1467. $getid3_dts = new getid3_dts($getid3_temp);
  1468. $getid3_dts->Analyze();
  1469. if (empty($getid3_temp->info['error'])) {
  1470. $info['audio'] = $getid3_temp->info['audio'];
  1471. $info['dts'] = $getid3_temp->info['dts'];
  1472. $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing
  1473. if (!empty($getid3_temp->info['warning'])) {
  1474. foreach ($getid3_temp->info['warning'] as $newerror) {
  1475. $this->warning('getid3_dts() says: ['.$newerror.']');
  1476. }
  1477. }
  1478. }
  1479. unset($getid3_temp, $getid3_dts);
  1480. } elseif (substr($testData, 0, 4) == 'wvpk') {
  1481. // This is WavPack data
  1482. $info['wavpack']['offset'] = $info['avdataoffset'];
  1483. $info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4));
  1484. $this->parseWavPackHeader(substr($testData, 8, 28));
  1485. } else {
  1486. // This is some other kind of data (quite possibly just PCM)
  1487. // do nothing special, just skip it
  1488. }
  1489. $nextoffset = $info['avdataend'];
  1490. $this->fseek($nextoffset);
  1491. break;
  1492. case 'iXML':
  1493. case 'bext':
  1494. case 'cart':
  1495. case 'fmt ':
  1496. case 'strh':
  1497. case 'strf':
  1498. case 'indx':
  1499. case 'MEXT':
  1500. case 'DISP':
  1501. // always read data in
  1502. case 'JUNK':
  1503. // should be: never read data in
  1504. // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc)
  1505. if ($chunksize < 1048576) {
  1506. if ($chunksize > 0) {
  1507. $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
  1508. if ($chunkname == 'JUNK') {
  1509. if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) {
  1510. // only keep text characters [chr(32)-chr(127)]
  1511. $info['riff']['comments']['junk'][] = trim($matches[1]);
  1512. }
  1513. // but if nothing there, ignore
  1514. // remove the key in either case
  1515. unset($RIFFchunk[$chunkname][$thisindex]['data']);
  1516. }
  1517. }
  1518. } else {
  1519. $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data');
  1520. $this->fseek($chunksize, SEEK_CUR);
  1521. }
  1522. break;
  1523. //case 'IDVX':
  1524. // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
  1525. // break;
  1526. case 'scot':
  1527. // https://cmsdk.com/node-js/adding-scot-chunk-to-wav-file.html
  1528. $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
  1529. $RIFFchunk[$chunkname][$thisindex]['parsed']['alter'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 0, 1);
  1530. $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 1, 1);
  1531. $RIFFchunk[$chunkname][$thisindex]['parsed']['artnum'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 2, 2));
  1532. $RIFFchunk[$chunkname][$thisindex]['parsed']['title'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 4, 43); // "name" in other documentation
  1533. $RIFFchunk[$chunkname][$thisindex]['parsed']['copy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 47, 4);
  1534. $RIFFchunk[$chunkname][$thisindex]['parsed']['padd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 51, 1);
  1535. $RIFFchunk[$chunkname][$thisindex]['parsed']['asclen'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 52, 5);
  1536. $RIFFchunk[$chunkname][$thisindex]['parsed']['startseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 57, 2));
  1537. $RIFFchunk[$chunkname][$thisindex]['parsed']['starthundredths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 59, 2));
  1538. $RIFFchunk[$chunkname][$thisindex]['parsed']['endseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 61, 2));
  1539. $RIFFchunk[$chunkname][$thisindex]['parsed']['endhundreths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 63, 2));
  1540. $RIFFchunk[$chunkname][$thisindex]['parsed']['sdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 65, 6);
  1541. $RIFFchunk[$chunkname][$thisindex]['parsed']['kdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 71, 6);
  1542. $RIFFchunk[$chunkname][$thisindex]['parsed']['start_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 77, 1);
  1543. $RIFFchunk[$chunkname][$thisindex]['parsed']['kill_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 78, 1);
  1544. $RIFFchunk[$chunkname][$thisindex]['parsed']['digital'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 79, 1);
  1545. $RIFFchunk[$chunkname][$thisindex]['parsed']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 80, 2));
  1546. $RIFFchunk[$chunkname][$thisindex]['parsed']['stereo'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 82, 1);
  1547. $RIFFchunk[$chunkname][$thisindex]['parsed']['compress'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 83, 1);
  1548. $RIFFchunk[$chunkname][$thisindex]['parsed']['eomstrt'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 84, 4));
  1549. $RIFFchunk[$chunkname][$thisindex]['parsed']['eomlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 88, 2));
  1550. $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib2'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 90, 4));
  1551. $RIFFchunk[$chunkname][$thisindex]['parsed']['future1'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 94, 12);
  1552. $RIFFchunk[$chunkname][$thisindex]['parsed']['catfontcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 106, 4));
  1553. $RIFFchunk[$chunkname][$thisindex]['parsed']['catcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 110, 4));
  1554. $RIFFchunk[$chunkname][$thisindex]['parsed']['segeompos'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 114, 4));
  1555. $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_startsecs'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 118, 2));
  1556. $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_starthunds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 120, 2));
  1557. $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 122, 3);
  1558. $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 125, 4);
  1559. $RIFFchunk[$chunkname][$thisindex]['parsed']['priorpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 129, 1);
  1560. $RIFFchunk[$chunkname][$thisindex]['parsed']['postcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 130, 3);
  1561. $RIFFchunk[$chunkname][$thisindex]['parsed']['postcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 133, 4);
  1562. $RIFFchunk[$chunkname][$thisindex]['parsed']['postpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 137, 1);
  1563. $RIFFchunk[$chunkname][$thisindex]['parsed']['hrcanplay'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 138, 21);
  1564. $RIFFchunk[$chunkname][$thisindex]['parsed']['future2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 159, 108);
  1565. $RIFFchunk[$chunkname][$thisindex]['parsed']['artist'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 267, 34);
  1566. $RIFFchunk[$chunkname][$thisindex]['parsed']['comment'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 301, 34); // "trivia" in other documentation
  1567. $RIFFchunk[$chunkname][$thisindex]['parsed']['intro'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 335, 2);
  1568. $RIFFchunk[$chunkname][$thisindex]['parsed']['end'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 337, 1);
  1569. $RIFFchunk[$chunkname][$thisindex]['parsed']['year'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 338, 4);
  1570. $RIFFchunk[$chunkname][$thisindex]['parsed']['obsolete2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 342, 1);
  1571. $RIFFchunk[$chunkname][$thisindex]['parsed']['rec_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 343, 1);
  1572. $RIFFchunk[$chunkname][$thisindex]['parsed']['rdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 344, 6);
  1573. $RIFFchunk[$chunkname][$thisindex]['parsed']['mpeg_bitrate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 350, 2));
  1574. $RIFFchunk[$chunkname][$thisindex]['parsed']['pitch'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 352, 2));
  1575. $RIFFchunk[$chunkname][$thisindex]['parsed']['playlevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 354, 2));
  1576. $RIFFchunk[$chunkname][$thisindex]['parsed']['lenvalid'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 356, 1);
  1577. $RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 357, 4));
  1578. $RIFFchunk[$chunkname][$thisindex]['parsed']['newplaylevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 361, 2));
  1579. $RIFFchunk[$chunkname][$thisindex]['parsed']['chopsize'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 363, 4));
  1580. $RIFFchunk[$chunkname][$thisindex]['parsed']['vteomovr'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 367, 4));
  1581. $RIFFchunk[$chunkname][$thisindex]['parsed']['desiredlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 371, 4));
  1582. $RIFFchunk[$chunkname][$thisindex]['parsed']['triggers'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 375, 4));
  1583. $RIFFchunk[$chunkname][$thisindex]['parsed']['fillout'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 379, 33);
  1584. foreach (array('title', 'artist', 'comment') as $key) {
  1585. if (trim($RIFFchunk[$chunkname][$thisindex]['parsed'][$key])) {
  1586. $info['riff']['comments'][$key] = array($RIFFchunk[$chunkname][$thisindex]['parsed'][$key]);
  1587. }
  1588. }
  1589. if ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] && !empty($info['filesize']) && ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] != $info['filesize'])) {
  1590. $this->warning('RIFF.WAVE.scot.filelength ('.$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'].') different from actual filesize ('.$info['filesize'].')');
  1591. }
  1592. break;
  1593. default:
  1594. if (!empty($LISTchunkParent) && isset($LISTchunkMaxOffset) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
  1595. $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
  1596. $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
  1597. unset($RIFFchunk[$chunkname][$thisindex]['offset']);
  1598. unset($RIFFchunk[$chunkname][$thisindex]['size']);
  1599. if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
  1600. unset($RIFFchunk[$chunkname][$thisindex]);
  1601. }
  1602. if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
  1603. unset($RIFFchunk[$chunkname]);
  1604. }
  1605. $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
  1606. } elseif ($chunksize < 2048) {
  1607. // only read data in if smaller than 2kB
  1608. $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
  1609. } else {
  1610. $this->fseek($chunksize, SEEK_CUR);
  1611. }
  1612. break;
  1613. }
  1614. break;
  1615. }
  1616. }
  1617. } catch (getid3_exception $e) {
  1618. if ($e->getCode() == 10) {
  1619. $this->warning('RIFF parser: '.$e->getMessage());
  1620. } else {
  1621. throw $e;
  1622. }
  1623. }
  1624. return $RIFFchunk;
  1625. }
  1626. /**
  1627. * @param string $RIFFdata
  1628. *
  1629. * @return bool
  1630. */
  1631. public function ParseRIFFdata(&$RIFFdata) {
  1632. $info = &$this->getid3->info;
  1633. if ($RIFFdata) {
  1634. $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
  1635. $fp_temp = fopen($tempfile, 'wb');
  1636. $RIFFdataLength = strlen($RIFFdata);
  1637. $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4);
  1638. for ($i = 0; $i < 4; $i++) {
  1639. $RIFFdata[($i + 4)] = $NewLengthString[$i];
  1640. }
  1641. fwrite($fp_temp, $RIFFdata);
  1642. fclose($fp_temp);
  1643. $getid3_temp = new getID3();
  1644. $getid3_temp->openfile($tempfile);
  1645. $getid3_temp->info['filesize'] = $RIFFdataLength;
  1646. $getid3_temp->info['filenamepath'] = $info['filenamepath'];
  1647. $getid3_temp->info['tags'] = $info['tags'];
  1648. $getid3_temp->info['warning'] = $info['warning'];
  1649. $getid3_temp->info['error'] = $info['error'];
  1650. $getid3_temp->info['comments'] = $info['comments'];
  1651. $getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : array());
  1652. $getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : array());
  1653. $getid3_riff = new getid3_riff($getid3_temp);
  1654. $getid3_riff->Analyze();
  1655. $info['riff'] = $getid3_temp->info['riff'];
  1656. $info['warning'] = $getid3_temp->info['warning'];
  1657. $info['error'] = $getid3_temp->info['error'];
  1658. $info['tags'] = $getid3_temp->info['tags'];
  1659. $info['comments'] = $getid3_temp->info['comments'];
  1660. unset($getid3_riff, $getid3_temp);
  1661. unlink($tempfile);
  1662. }
  1663. return false;
  1664. }
  1665. /**
  1666. * @param array $RIFFinfoArray
  1667. * @param array $CommentsTargetArray
  1668. *
  1669. * @return bool
  1670. */
  1671. public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
  1672. $RIFFinfoKeyLookup = array(
  1673. 'IARL'=>'archivallocation',
  1674. 'IART'=>'artist',
  1675. 'ICDS'=>'costumedesigner',
  1676. 'ICMS'=>'commissionedby',
  1677. 'ICMT'=>'comment',
  1678. 'ICNT'=>'country',
  1679. 'ICOP'=>'copyright',
  1680. 'ICRD'=>'creationdate',
  1681. 'IDIM'=>'dimensions',
  1682. 'IDIT'=>'digitizationdate',
  1683. 'IDPI'=>'resolution',
  1684. 'IDST'=>'distributor',
  1685. 'IEDT'=>'editor',
  1686. 'IENG'=>'engineers',
  1687. 'IFRM'=>'accountofparts',
  1688. 'IGNR'=>'genre',
  1689. 'IKEY'=>'keywords',
  1690. 'ILGT'=>'lightness',
  1691. 'ILNG'=>'language',
  1692. 'IMED'=>'orignalmedium',
  1693. 'IMUS'=>'composer',
  1694. 'INAM'=>'title',
  1695. 'IPDS'=>'productiondesigner',
  1696. 'IPLT'=>'palette',
  1697. 'IPRD'=>'product',
  1698. 'IPRO'=>'producer',
  1699. 'IPRT'=>'part',
  1700. 'IRTD'=>'rating',
  1701. 'ISBJ'=>'subject',
  1702. 'ISFT'=>'software',
  1703. 'ISGN'=>'secondarygenre',
  1704. 'ISHP'=>'sharpness',
  1705. 'ISRC'=>'sourcesupplier',
  1706. 'ISRF'=>'digitizationsource',
  1707. 'ISTD'=>'productionstudio',
  1708. 'ISTR'=>'starring',
  1709. 'ITCH'=>'encoded_by',
  1710. 'IWEB'=>'url',
  1711. 'IWRI'=>'writer',
  1712. '____'=>'comment',
  1713. );
  1714. foreach ($RIFFinfoKeyLookup as $key => $value) {
  1715. if (isset($RIFFinfoArray[$key])) {
  1716. foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
  1717. if (trim($commentdata['data']) != '') {
  1718. if (isset($CommentsTargetArray[$value])) {
  1719. $CommentsTargetArray[$value][] = trim($commentdata['data']);
  1720. } else {
  1721. $CommentsTargetArray[$value] = array(trim($commentdata['data']));
  1722. }
  1723. }
  1724. }
  1725. }
  1726. }
  1727. return true;
  1728. }
  1729. /**
  1730. * @param string $WaveFormatExData
  1731. *
  1732. * @return array
  1733. */
  1734. public static function parseWAVEFORMATex($WaveFormatExData) {
  1735. // shortcut
  1736. $WaveFormatEx = array();
  1737. $WaveFormatEx['raw'] = array();
  1738. $WaveFormatEx_raw = &$WaveFormatEx['raw'];
  1739. $WaveFormatEx_raw['wFormatTag'] = substr($WaveFormatExData, 0, 2);
  1740. $WaveFormatEx_raw['nChannels'] = substr($WaveFormatExData, 2, 2);
  1741. $WaveFormatEx_raw['nSamplesPerSec'] = substr($WaveFormatExData, 4, 4);
  1742. $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData, 8, 4);
  1743. $WaveFormatEx_raw['nBlockAlign'] = substr($WaveFormatExData, 12, 2);
  1744. $WaveFormatEx_raw['wBitsPerSample'] = substr($WaveFormatExData, 14, 2);
  1745. if (strlen($WaveFormatExData) > 16) {
  1746. $WaveFormatEx_raw['cbSize'] = substr($WaveFormatExData, 16, 2);
  1747. }
  1748. $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw);
  1749. $WaveFormatEx['codec'] = self::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']);
  1750. $WaveFormatEx['channels'] = $WaveFormatEx_raw['nChannels'];
  1751. $WaveFormatEx['sample_rate'] = $WaveFormatEx_raw['nSamplesPerSec'];
  1752. $WaveFormatEx['bitrate'] = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8;
  1753. $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample'];
  1754. return $WaveFormatEx;
  1755. }
  1756. /**
  1757. * @param string $WavPackChunkData
  1758. *
  1759. * @return bool
  1760. */
  1761. public function parseWavPackHeader($WavPackChunkData) {
  1762. // typedef struct {
  1763. // char ckID [4];
  1764. // long ckSize;
  1765. // short version;
  1766. // short bits; // added for version 2.00
  1767. // short flags, shift; // added for version 3.00
  1768. // long total_samples, crc, crc2;
  1769. // char extension [4], extra_bc, extras [3];
  1770. // } WavpackHeader;
  1771. // shortcut
  1772. $info = &$this->getid3->info;
  1773. $info['wavpack'] = array();
  1774. $thisfile_wavpack = &$info['wavpack'];
  1775. $thisfile_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 0, 2));
  1776. if ($thisfile_wavpack['version'] >= 2) {
  1777. $thisfile_wavpack['bits'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 2, 2));
  1778. }
  1779. if ($thisfile_wavpack['version'] >= 3) {
  1780. $thisfile_wavpack['flags_raw'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 4, 2));
  1781. $thisfile_wavpack['shift'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 6, 2));
  1782. $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 8, 4));
  1783. $thisfile_wavpack['crc1'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4));
  1784. $thisfile_wavpack['crc2'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4));
  1785. $thisfile_wavpack['extension'] = substr($WavPackChunkData, 20, 4);
  1786. $thisfile_wavpack['extra_bc'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1));
  1787. for ($i = 0; $i <= 2; $i++) {
  1788. $thisfile_wavpack['extras'][] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1));
  1789. }
  1790. // shortcut
  1791. $thisfile_wavpack['flags'] = array();
  1792. $thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
  1793. $thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001);
  1794. $thisfile_wavpack_flags['fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002);
  1795. $thisfile_wavpack_flags['raw_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004);
  1796. $thisfile_wavpack_flags['calc_noise'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008);
  1797. $thisfile_wavpack_flags['high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010);
  1798. $thisfile_wavpack_flags['3_byte_samples'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020);
  1799. $thisfile_wavpack_flags['over_20_bits'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040);
  1800. $thisfile_wavpack_flags['use_wvc'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080);
  1801. $thisfile_wavpack_flags['noiseshaping'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100);
  1802. $thisfile_wavpack_flags['very_fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200);
  1803. $thisfile_wavpack_flags['new_high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400);
  1804. $thisfile_wavpack_flags['cancel_extreme'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800);
  1805. $thisfile_wavpack_flags['cross_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000);
  1806. $thisfile_wavpack_flags['new_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000);
  1807. $thisfile_wavpack_flags['joint_stereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000);
  1808. $thisfile_wavpack_flags['extra_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000);
  1809. $thisfile_wavpack_flags['override_noiseshape'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000);
  1810. $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000);
  1811. $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000);
  1812. $thisfile_wavpack_flags['create_exe'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000);
  1813. }
  1814. return true;
  1815. }
  1816. /**
  1817. * @param string $BITMAPINFOHEADER
  1818. * @param bool $littleEndian
  1819. *
  1820. * @return array
  1821. */
  1822. public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
  1823. $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
  1824. $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels
  1825. $parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
  1826. $parsed['biPlanes'] = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1
  1827. $parsed['biBitCount'] = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels
  1828. $parsed['biSizeImage'] = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
  1829. $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device
  1830. $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device
  1831. $parsed['biClrUsed'] = substr($BITMAPINFOHEADER, 32, 4); // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
  1832. $parsed['biClrImportant'] = substr($BITMAPINFOHEADER, 36, 4); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
  1833. $parsed = array_map('getid3_lib::'.($littleEndian ? 'Little' : 'Big').'Endian2Int', $parsed);
  1834. $parsed['fourcc'] = substr($BITMAPINFOHEADER, 16, 4); // compression identifier
  1835. return $parsed;
  1836. }
  1837. /**
  1838. * @param string $DIVXTAG
  1839. * @param bool $raw
  1840. *
  1841. * @return array
  1842. */
  1843. public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
  1844. // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
  1845. // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
  1846. // 'Byte Layout: '1111111111111111
  1847. // '32 for Movie - 1 '1111111111111111
  1848. // '28 for Author - 6 '6666666666666666
  1849. // '4 for year - 2 '6666666666662222
  1850. // '3 for genre - 3 '7777777777777777
  1851. // '48 for Comments - 7 '7777777777777777
  1852. // '1 for Rating - 4 '7777777777777777
  1853. // '5 for Future Additions - 0 '333400000DIVXTAG
  1854. // '128 bytes total
  1855. static $DIVXTAGgenre = array(
  1856. 0 => 'Action',
  1857. 1 => 'Action/Adventure',
  1858. 2 => 'Adventure',
  1859. 3 => 'Adult',
  1860. 4 => 'Anime',
  1861. 5 => 'Cartoon',
  1862. 6 => 'Claymation',
  1863. 7 => 'Comedy',
  1864. 8 => 'Commercial',
  1865. 9 => 'Documentary',
  1866. 10 => 'Drama',
  1867. 11 => 'Home Video',
  1868. 12 => 'Horror',
  1869. 13 => 'Infomercial',
  1870. 14 => 'Interactive',
  1871. 15 => 'Mystery',
  1872. 16 => 'Music Video',
  1873. 17 => 'Other',
  1874. 18 => 'Religion',
  1875. 19 => 'Sci Fi',
  1876. 20 => 'Thriller',
  1877. 21 => 'Western',
  1878. ),
  1879. $DIVXTAGrating = array(
  1880. 0 => 'Unrated',
  1881. 1 => 'G',
  1882. 2 => 'PG',
  1883. 3 => 'PG-13',
  1884. 4 => 'R',
  1885. 5 => 'NC-17',
  1886. );
  1887. $parsed = array();
  1888. $parsed['title'] = trim(substr($DIVXTAG, 0, 32));
  1889. $parsed['artist'] = trim(substr($DIVXTAG, 32, 28));
  1890. $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4)));
  1891. $parsed['comment'] = trim(substr($DIVXTAG, 64, 48));
  1892. $parsed['genre_id'] = intval(trim(substr($DIVXTAG, 112, 3)));
  1893. $parsed['rating_id'] = ord(substr($DIVXTAG, 115, 1));
  1894. //$parsed['padding'] = substr($DIVXTAG, 116, 5); // 5-byte null
  1895. //$parsed['magic'] = substr($DIVXTAG, 121, 7); // "DIVXTAG"
  1896. $parsed['genre'] = (isset($DIVXTAGgenre[$parsed['genre_id']]) ? $DIVXTAGgenre[$parsed['genre_id']] : $parsed['genre_id']);
  1897. $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ? $DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']);
  1898. if (!$raw) {
  1899. unset($parsed['genre_id'], $parsed['rating_id']);
  1900. foreach ($parsed as $key => $value) {
  1901. if (empty($value)) {
  1902. unset($parsed[$key]);
  1903. }
  1904. }
  1905. }
  1906. foreach ($parsed as $tag => $value) {
  1907. $parsed[$tag] = array($value);
  1908. }
  1909. return $parsed;
  1910. }
  1911. /**
  1912. * @param string $tagshortname
  1913. *
  1914. * @return string
  1915. */
  1916. public static function waveSNDMtagLookup($tagshortname) {
  1917. $begin = __LINE__;
  1918. /** This is not a comment!
  1919. ©kwd keywords
  1920. ©BPM bpm
  1921. ©trt tracktitle
  1922. ©des description
  1923. ©gen category
  1924. ©fin featuredinstrument
  1925. ©LID longid
  1926. ©bex bwdescription
  1927. ©pub publisher
  1928. ©cdt cdtitle
  1929. ©alb library
  1930. ©com composer
  1931. */
  1932. return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
  1933. }
  1934. /**
  1935. * @param int $wFormatTag
  1936. *
  1937. * @return string
  1938. */
  1939. public static function wFormatTagLookup($wFormatTag) {
  1940. $begin = __LINE__;
  1941. /** This is not a comment!
  1942. 0x0000 Microsoft Unknown Wave Format
  1943. 0x0001 Pulse Code Modulation (PCM)
  1944. 0x0002 Microsoft ADPCM
  1945. 0x0003 IEEE Float
  1946. 0x0004 Compaq Computer VSELP
  1947. 0x0005 IBM CVSD
  1948. 0x0006 Microsoft A-Law
  1949. 0x0007 Microsoft mu-Law
  1950. 0x0008 Microsoft DTS
  1951. 0x0010 OKI ADPCM
  1952. 0x0011 Intel DVI/IMA ADPCM
  1953. 0x0012 Videologic MediaSpace ADPCM
  1954. 0x0013 Sierra Semiconductor ADPCM
  1955. 0x0014 Antex Electronics G.723 ADPCM
  1956. 0x0015 DSP Solutions DigiSTD
  1957. 0x0016 DSP Solutions DigiFIX
  1958. 0x0017 Dialogic OKI ADPCM
  1959. 0x0018 MediaVision ADPCM
  1960. 0x0019 Hewlett-Packard CU
  1961. 0x0020 Yamaha ADPCM
  1962. 0x0021 Speech Compression Sonarc
  1963. 0x0022 DSP Group TrueSpeech
  1964. 0x0023 Echo Speech EchoSC1
  1965. 0x0024 Audiofile AF36
  1966. 0x0025 Audio Processing Technology APTX
  1967. 0x0026 AudioFile AF10
  1968. 0x0027 Prosody 1612
  1969. 0x0028 LRC
  1970. 0x0030 Dolby AC2
  1971. 0x0031 Microsoft GSM 6.10
  1972. 0x0032 MSNAudio
  1973. 0x0033 Antex Electronics ADPCME
  1974. 0x0034 Control Resources VQLPC
  1975. 0x0035 DSP Solutions DigiREAL
  1976. 0x0036 DSP Solutions DigiADPCM
  1977. 0x0037 Control Resources CR10
  1978. 0x0038 Natural MicroSystems VBXADPCM
  1979. 0x0039 Crystal Semiconductor IMA ADPCM
  1980. 0x003A EchoSC3
  1981. 0x003B Rockwell ADPCM
  1982. 0x003C Rockwell Digit LK
  1983. 0x003D Xebec
  1984. 0x0040 Antex Electronics G.721 ADPCM
  1985. 0x0041 G.728 CELP
  1986. 0x0042 MSG723
  1987. 0x0050 MPEG Layer-2 or Layer-1
  1988. 0x0052 RT24
  1989. 0x0053 PAC
  1990. 0x0055 MPEG Layer-3
  1991. 0x0059 Lucent G.723
  1992. 0x0060 Cirrus
  1993. 0x0061 ESPCM
  1994. 0x0062 Voxware
  1995. 0x0063 Canopus Atrac
  1996. 0x0064 G.726 ADPCM
  1997. 0x0065 G.722 ADPCM
  1998. 0x0066 DSAT
  1999. 0x0067 DSAT Display
  2000. 0x0069 Voxware Byte Aligned
  2001. 0x0070 Voxware AC8
  2002. 0x0071 Voxware AC10
  2003. 0x0072 Voxware AC16
  2004. 0x0073 Voxware AC20
  2005. 0x0074 Voxware MetaVoice
  2006. 0x0075 Voxware MetaSound
  2007. 0x0076 Voxware RT29HW
  2008. 0x0077 Voxware VR12
  2009. 0x0078 Voxware VR18
  2010. 0x0079 Voxware TQ40
  2011. 0x0080 Softsound
  2012. 0x0081 Voxware TQ60
  2013. 0x0082 MSRT24
  2014. 0x0083 G.729A
  2015. 0x0084 MVI MV12
  2016. 0x0085 DF G.726
  2017. 0x0086 DF GSM610
  2018. 0x0088 ISIAudio
  2019. 0x0089 Onlive
  2020. 0x0091 SBC24
  2021. 0x0092 Dolby AC3 SPDIF
  2022. 0x0093 MediaSonic G.723
  2023. 0x0094 Aculab PLC Prosody 8kbps
  2024. 0x0097 ZyXEL ADPCM
  2025. 0x0098 Philips LPCBB
  2026. 0x0099 Packed
  2027. 0x00FF AAC
  2028. 0x0100 Rhetorex ADPCM
  2029. 0x0101 IBM mu-law
  2030. 0x0102 IBM A-law
  2031. 0x0103 IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)
  2032. 0x0111 Vivo G.723
  2033. 0x0112 Vivo Siren
  2034. 0x0123 Digital G.723
  2035. 0x0125 Sanyo LD ADPCM
  2036. 0x0130 Sipro Lab Telecom ACELP NET
  2037. 0x0131 Sipro Lab Telecom ACELP 4800
  2038. 0x0132 Sipro Lab Telecom ACELP 8V3
  2039. 0x0133 Sipro Lab Telecom G.729
  2040. 0x0134 Sipro Lab Telecom G.729A
  2041. 0x0135 Sipro Lab Telecom Kelvin
  2042. 0x0140 Windows Media Video V8
  2043. 0x0150 Qualcomm PureVoice
  2044. 0x0151 Qualcomm HalfRate
  2045. 0x0155 Ring Zero Systems TUB GSM
  2046. 0x0160 Microsoft Audio 1
  2047. 0x0161 Windows Media Audio V7 / V8 / V9
  2048. 0x0162 Windows Media Audio Professional V9
  2049. 0x0163 Windows Media Audio Lossless V9
  2050. 0x0200 Creative Labs ADPCM
  2051. 0x0202 Creative Labs Fastspeech8
  2052. 0x0203 Creative Labs Fastspeech10
  2053. 0x0210 UHER Informatic GmbH ADPCM
  2054. 0x0220 Quarterdeck
  2055. 0x0230 I-link Worldwide VC
  2056. 0x0240 Aureal RAW Sport
  2057. 0x0250 Interactive Products HSX
  2058. 0x0251 Interactive Products RPELP
  2059. 0x0260 Consistent Software CS2
  2060. 0x0270 Sony SCX
  2061. 0x0300 Fujitsu FM Towns Snd
  2062. 0x0400 BTV Digital
  2063. 0x0401 Intel Music Coder
  2064. 0x0450 QDesign Music
  2065. 0x0680 VME VMPCM
  2066. 0x0681 AT&T Labs TPC
  2067. 0x08AE ClearJump LiteWave
  2068. 0x1000 Olivetti GSM
  2069. 0x1001 Olivetti ADPCM
  2070. 0x1002 Olivetti CELP
  2071. 0x1003 Olivetti SBC
  2072. 0x1004 Olivetti OPR
  2073. 0x1100 Lernout & Hauspie Codec (0x1100)
  2074. 0x1101 Lernout & Hauspie CELP Codec (0x1101)
  2075. 0x1102 Lernout & Hauspie SBC Codec (0x1102)
  2076. 0x1103 Lernout & Hauspie SBC Codec (0x1103)
  2077. 0x1104 Lernout & Hauspie SBC Codec (0x1104)
  2078. 0x1400 Norris
  2079. 0x1401 AT&T ISIAudio
  2080. 0x1500 Soundspace Music Compression
  2081. 0x181C VoxWare RT24 Speech
  2082. 0x1FC4 NCT Soft ALF2CD (www.nctsoft.com)
  2083. 0x2000 Dolby AC3
  2084. 0x2001 Dolby DTS
  2085. 0x2002 WAVE_FORMAT_14_4
  2086. 0x2003 WAVE_FORMAT_28_8
  2087. 0x2004 WAVE_FORMAT_COOK
  2088. 0x2005 WAVE_FORMAT_DNET
  2089. 0x674F Ogg Vorbis 1
  2090. 0x6750 Ogg Vorbis 2
  2091. 0x6751 Ogg Vorbis 3
  2092. 0x676F Ogg Vorbis 1+
  2093. 0x6770 Ogg Vorbis 2+
  2094. 0x6771 Ogg Vorbis 3+
  2095. 0x7A21 GSM-AMR (CBR, no SID)
  2096. 0x7A22 GSM-AMR (VBR, including SID)
  2097. 0xFFFE WAVE_FORMAT_EXTENSIBLE
  2098. 0xFFFF WAVE_FORMAT_DEVELOPMENT
  2099. */
  2100. return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
  2101. }
  2102. /**
  2103. * @param string $fourcc
  2104. *
  2105. * @return string
  2106. */
  2107. public static function fourccLookup($fourcc) {
  2108. $begin = __LINE__;
  2109. /** This is not a comment!
  2110. swot http://developer.apple.com/qa/snd/snd07.html
  2111. ____ No Codec (____)
  2112. _BIT BI_BITFIELDS (Raw RGB)
  2113. _JPG JPEG compressed
  2114. _PNG PNG compressed W3C/ISO/IEC (RFC-2083)
  2115. _RAW Full Frames (Uncompressed)
  2116. _RGB Raw RGB Bitmap
  2117. _RL4 RLE 4bpp RGB
  2118. _RL8 RLE 8bpp RGB
  2119. 3IV1 3ivx MPEG-4 v1
  2120. 3IV2 3ivx MPEG-4 v2
  2121. 3IVX 3ivx MPEG-4
  2122. AASC Autodesk Animator
  2123. ABYR Kensington ?ABYR?
  2124. AEMI Array Microsystems VideoONE MPEG1-I Capture
  2125. AFLC Autodesk Animator FLC
  2126. AFLI Autodesk Animator FLI
  2127. AMPG Array Microsystems VideoONE MPEG
  2128. ANIM Intel RDX (ANIM)
  2129. AP41 AngelPotion Definitive
  2130. ASV1 Asus Video v1
  2131. ASV2 Asus Video v2
  2132. ASVX Asus Video 2.0 (audio)
  2133. AUR2 AuraVision Aura 2 Codec - YUV 4:2:2
  2134. AURA AuraVision Aura 1 Codec - YUV 4:1:1
  2135. AVDJ Independent JPEG Group\'s codec (AVDJ)
  2136. AVRN Independent JPEG Group\'s codec (AVRN)
  2137. AYUV 4:4:4 YUV (AYUV)
  2138. AZPR Quicktime Apple Video (AZPR)
  2139. BGR Raw RGB32
  2140. BLZ0 Blizzard DivX MPEG-4
  2141. BTVC Conexant Composite Video
  2142. BINK RAD Game Tools Bink Video
  2143. BT20 Conexant Prosumer Video
  2144. BTCV Conexant Composite Video Codec
  2145. BW10 Data Translation Broadway MPEG Capture
  2146. CC12 Intel YUV12
  2147. CDVC Canopus DV
  2148. CFCC Digital Processing Systems DPS Perception
  2149. CGDI Microsoft Office 97 Camcorder Video
  2150. CHAM Winnov Caviara Champagne
  2151. CJPG Creative WebCam JPEG
  2152. CLJR Cirrus Logic YUV 4:1:1
  2153. CMYK Common Data Format in Printing (Colorgraph)
  2154. CPLA Weitek 4:2:0 YUV Planar
  2155. CRAM Microsoft Video 1 (CRAM)
  2156. cvid Radius Cinepak
  2157. CVID Radius Cinepak
  2158. CWLT Microsoft Color WLT DIB
  2159. CYUV Creative Labs YUV
  2160. CYUY ATI YUV
  2161. D261 H.261
  2162. D263 H.263
  2163. DIB Device Independent Bitmap
  2164. DIV1 FFmpeg OpenDivX
  2165. DIV2 Microsoft MPEG-4 v1/v2
  2166. DIV3 DivX ;-) MPEG-4 v3.x Low-Motion
  2167. DIV4 DivX ;-) MPEG-4 v3.x Fast-Motion
  2168. DIV5 DivX MPEG-4 v5.x
  2169. DIV6 DivX ;-) (MS MPEG-4 v3.x)
  2170. DIVX DivX MPEG-4 v4 (OpenDivX / Project Mayo)
  2171. divx DivX MPEG-4
  2172. DMB1 Matrox Rainbow Runner hardware MJPEG
  2173. DMB2 Paradigm MJPEG
  2174. DSVD ?DSVD?
  2175. DUCK Duck TrueMotion 1.0
  2176. DPS0 DPS/Leitch Reality Motion JPEG
  2177. DPSC DPS/Leitch PAR Motion JPEG
  2178. DV25 Matrox DVCPRO codec
  2179. DV50 Matrox DVCPRO50 codec
  2180. DVC IEC 61834 and SMPTE 314M (DVC/DV Video)
  2181. DVCP IEC 61834 and SMPTE 314M (DVC/DV Video)
  2182. DVHD IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps
  2183. DVMA Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com)
  2184. DVSL IEC Standard DV compressed in SD (SDL)
  2185. DVAN ?DVAN?
  2186. DVE2 InSoft DVE-2 Videoconferencing
  2187. dvsd IEC 61834 and SMPTE 314M DVC/DV Video
  2188. DVSD IEC 61834 and SMPTE 314M DVC/DV Video
  2189. DVX1 Lucent DVX1000SP Video Decoder
  2190. DVX2 Lucent DVX2000S Video Decoder
  2191. DVX3 Lucent DVX3000S Video Decoder
  2192. DX50 DivX v5
  2193. DXT1 Microsoft DirectX Compressed Texture (DXT1)
  2194. DXT2 Microsoft DirectX Compressed Texture (DXT2)
  2195. DXT3 Microsoft DirectX Compressed Texture (DXT3)
  2196. DXT4 Microsoft DirectX Compressed Texture (DXT4)
  2197. DXT5 Microsoft DirectX Compressed Texture (DXT5)
  2198. DXTC Microsoft DirectX Compressed Texture (DXTC)
  2199. DXTn Microsoft DirectX Compressed Texture (DXTn)
  2200. EM2V Etymonix MPEG-2 I-frame (www.etymonix.com)
  2201. EKQ0 Elsa ?EKQ0?
  2202. ELK0 Elsa ?ELK0?
  2203. ESCP Eidos Escape
  2204. ETV1 eTreppid Video ETV1
  2205. ETV2 eTreppid Video ETV2
  2206. ETVC eTreppid Video ETVC
  2207. FLIC Autodesk FLI/FLC Animation
  2208. FLV1 Sorenson Spark
  2209. FLV4 On2 TrueMotion VP6
  2210. FRWT Darim Vision Forward Motion JPEG (www.darvision.com)
  2211. FRWU Darim Vision Forward Uncompressed (www.darvision.com)
  2212. FLJP D-Vision Field Encoded Motion JPEG
  2213. FPS1 FRAPS v1
  2214. FRWA SoftLab-Nsk Forward Motion JPEG w/ alpha channel
  2215. FRWD SoftLab-Nsk Forward Motion JPEG
  2216. FVF1 Iterated Systems Fractal Video Frame
  2217. GLZW Motion LZW (gabest@freemail.hu)
  2218. GPEG Motion JPEG (gabest@freemail.hu)
  2219. GWLT Microsoft Greyscale WLT DIB
  2220. H260 Intel ITU H.260 Videoconferencing
  2221. H261 Intel ITU H.261 Videoconferencing
  2222. H262 Intel ITU H.262 Videoconferencing
  2223. H263 Intel ITU H.263 Videoconferencing
  2224. H264 Intel ITU H.264 Videoconferencing
  2225. H265 Intel ITU H.265 Videoconferencing
  2226. H266 Intel ITU H.266 Videoconferencing
  2227. H267 Intel ITU H.267 Videoconferencing
  2228. H268 Intel ITU H.268 Videoconferencing
  2229. H269 Intel ITU H.269 Videoconferencing
  2230. HFYU Huffman Lossless Codec
  2231. HMCR Rendition Motion Compensation Format (HMCR)
  2232. HMRR Rendition Motion Compensation Format (HMRR)
  2233. I263 FFmpeg I263 decoder
  2234. IF09 Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane")
  2235. IUYV Interlaced version of UYVY (www.leadtools.com)
  2236. IY41 Interlaced version of Y41P (www.leadtools.com)
  2237. IYU1 12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard
  2238. IYU2 24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard
  2239. IYUV Planar YUV format (8-bpp Y plane, followed by 8-bpp 2×2 U and V planes)
  2240. i263 Intel ITU H.263 Videoconferencing (i263)
  2241. I420 Intel Indeo 4
  2242. IAN Intel Indeo 4 (RDX)
  2243. ICLB InSoft CellB Videoconferencing
  2244. IGOR Power DVD
  2245. IJPG Intergraph JPEG
  2246. ILVC Intel Layered Video
  2247. ILVR ITU-T H.263+
  2248. IPDV I-O Data Device Giga AVI DV Codec
  2249. IR21 Intel Indeo 2.1
  2250. IRAW Intel YUV Uncompressed
  2251. IV30 Intel Indeo 3.0
  2252. IV31 Intel Indeo 3.1
  2253. IV32 Ligos Indeo 3.2
  2254. IV33 Ligos Indeo 3.3
  2255. IV34 Ligos Indeo 3.4
  2256. IV35 Ligos Indeo 3.5
  2257. IV36 Ligos Indeo 3.6
  2258. IV37 Ligos Indeo 3.7
  2259. IV38 Ligos Indeo 3.8
  2260. IV39 Ligos Indeo 3.9
  2261. IV40 Ligos Indeo Interactive 4.0
  2262. IV41 Ligos Indeo Interactive 4.1
  2263. IV42 Ligos Indeo Interactive 4.2
  2264. IV43 Ligos Indeo Interactive 4.3
  2265. IV44 Ligos Indeo Interactive 4.4
  2266. IV45 Ligos Indeo Interactive 4.5
  2267. IV46 Ligos Indeo Interactive 4.6
  2268. IV47 Ligos Indeo Interactive 4.7
  2269. IV48 Ligos Indeo Interactive 4.8
  2270. IV49 Ligos Indeo Interactive 4.9
  2271. IV50 Ligos Indeo Interactive 5.0
  2272. JBYR Kensington ?JBYR?
  2273. JPEG Still Image JPEG DIB
  2274. JPGL Pegasus Lossless Motion JPEG
  2275. KMVC Team17 Software Karl Morton\'s Video Codec
  2276. LSVM Vianet Lighting Strike Vmail (Streaming) (www.vianet.com)
  2277. LEAD LEAD Video Codec
  2278. Ljpg LEAD MJPEG Codec
  2279. MDVD Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de)
  2280. MJPA Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com)
  2281. MJPB Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com)
  2282. MMES Matrox MPEG-2 I-frame
  2283. MP2v Microsoft S-Mpeg 4 version 1 (MP2v)
  2284. MP42 Microsoft S-Mpeg 4 version 2 (MP42)
  2285. MP43 Microsoft S-Mpeg 4 version 3 (MP43)
  2286. MP4S Microsoft S-Mpeg 4 version 3 (MP4S)
  2287. MP4V FFmpeg MPEG-4
  2288. MPG1 FFmpeg MPEG 1/2
  2289. MPG2 FFmpeg MPEG 1/2
  2290. MPG3 FFmpeg DivX ;-) (MS MPEG-4 v3)
  2291. MPG4 Microsoft MPEG-4
  2292. MPGI Sigma Designs MPEG
  2293. MPNG PNG images decoder
  2294. MSS1 Microsoft Windows Screen Video
  2295. MSZH LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
  2296. M261 Microsoft H.261
  2297. M263 Microsoft H.263
  2298. M4S2 Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2)
  2299. m4s2 Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2)
  2300. MC12 ATI Motion Compensation Format (MC12)
  2301. MCAM ATI Motion Compensation Format (MCAM)
  2302. MJ2C Morgan Multimedia Motion JPEG2000
  2303. mJPG IBM Motion JPEG w/ Huffman Tables
  2304. MJPG Microsoft Motion JPEG DIB
  2305. MP42 Microsoft MPEG-4 (low-motion)
  2306. MP43 Microsoft MPEG-4 (fast-motion)
  2307. MP4S Microsoft MPEG-4 (MP4S)
  2308. mp4s Microsoft MPEG-4 (mp4s)
  2309. MPEG Chromatic Research MPEG-1 Video I-Frame
  2310. MPG4 Microsoft MPEG-4 Video High Speed Compressor
  2311. MPGI Sigma Designs MPEG
  2312. MRCA FAST Multimedia Martin Regen Codec
  2313. MRLE Microsoft Run Length Encoding
  2314. MSVC Microsoft Video 1
  2315. MTX1 Matrox ?MTX1?
  2316. MTX2 Matrox ?MTX2?
  2317. MTX3 Matrox ?MTX3?
  2318. MTX4 Matrox ?MTX4?
  2319. MTX5 Matrox ?MTX5?
  2320. MTX6 Matrox ?MTX6?
  2321. MTX7 Matrox ?MTX7?
  2322. MTX8 Matrox ?MTX8?
  2323. MTX9 Matrox ?MTX9?
  2324. MV12 Motion Pixels Codec (old)
  2325. MWV1 Aware Motion Wavelets
  2326. nAVI SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm)
  2327. NT00 NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com)
  2328. NUV1 NuppelVideo
  2329. NTN1 Nogatech Video Compression 1
  2330. NVS0 nVidia GeForce Texture (NVS0)
  2331. NVS1 nVidia GeForce Texture (NVS1)
  2332. NVS2 nVidia GeForce Texture (NVS2)
  2333. NVS3 nVidia GeForce Texture (NVS3)
  2334. NVS4 nVidia GeForce Texture (NVS4)
  2335. NVS5 nVidia GeForce Texture (NVS5)
  2336. NVT0 nVidia GeForce Texture (NVT0)
  2337. NVT1 nVidia GeForce Texture (NVT1)
  2338. NVT2 nVidia GeForce Texture (NVT2)
  2339. NVT3 nVidia GeForce Texture (NVT3)
  2340. NVT4 nVidia GeForce Texture (NVT4)
  2341. NVT5 nVidia GeForce Texture (NVT5)
  2342. PIXL MiroXL, Pinnacle PCTV
  2343. PDVC I-O Data Device Digital Video Capture DV codec
  2344. PGVV Radius Video Vision
  2345. PHMO IBM Photomotion
  2346. PIM1 MPEG Realtime (Pinnacle Cards)
  2347. PIM2 Pegasus Imaging ?PIM2?
  2348. PIMJ Pegasus Imaging Lossless JPEG
  2349. PVEZ Horizons Technology PowerEZ
  2350. PVMM PacketVideo Corporation MPEG-4
  2351. PVW2 Pegasus Imaging Wavelet Compression
  2352. Q1.0 Q-Team\'s QPEG 1.0 (www.q-team.de)
  2353. Q1.1 Q-Team\'s QPEG 1.1 (www.q-team.de)
  2354. QPEG Q-Team QPEG 1.0
  2355. qpeq Q-Team QPEG 1.1
  2356. RGB Raw BGR32
  2357. RGBA Raw RGB w/ Alpha
  2358. RMP4 REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com)
  2359. ROQV Id RoQ File Video Decoder
  2360. RPZA Quicktime Apple Video (RPZA)
  2361. RUD0 Rududu video codec (http://rududu.ifrance.com/rududu/)
  2362. RV10 RealVideo 1.0 (aka RealVideo 5.0)
  2363. RV13 RealVideo 1.0 (RV13)
  2364. RV20 RealVideo G2
  2365. RV30 RealVideo 8
  2366. RV40 RealVideo 9
  2367. RGBT Raw RGB w/ Transparency
  2368. RLE Microsoft Run Length Encoder
  2369. RLE4 Run Length Encoded (4bpp, 16-color)
  2370. RLE8 Run Length Encoded (8bpp, 256-color)
  2371. RT21 Intel Indeo RealTime Video 2.1
  2372. rv20 RealVideo G2
  2373. rv30 RealVideo 8
  2374. RVX Intel RDX (RVX )
  2375. SMC Apple Graphics (SMC )
  2376. SP54 Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2
  2377. SPIG Radius Spigot
  2378. SVQ3 Sorenson Video 3 (Apple Quicktime 5)
  2379. s422 Tekram VideoCap C210 YUV 4:2:2
  2380. SDCC Sun Communication Digital Camera Codec
  2381. SFMC CrystalNet Surface Fitting Method
  2382. SMSC Radius SMSC
  2383. SMSD Radius SMSD
  2384. smsv WorldConnect Wavelet Video
  2385. SPIG Radius Spigot
  2386. SPLC Splash Studios ACM Audio Codec (www.splashstudios.net)
  2387. SQZ2 Microsoft VXTreme Video Codec V2
  2388. STVA ST Microelectronics CMOS Imager Data (Bayer)
  2389. STVB ST Microelectronics CMOS Imager Data (Nudged Bayer)
  2390. STVC ST Microelectronics CMOS Imager Data (Bunched)
  2391. STVX ST Microelectronics CMOS Imager Data (Extended CODEC Data Format)
  2392. STVY ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data)
  2393. SV10 Sorenson Video R1
  2394. SVQ1 Sorenson Video
  2395. T420 Toshiba YUV 4:2:0
  2396. TM2A Duck TrueMotion Archiver 2.0 (www.duck.com)
  2397. TVJP Pinnacle/Truevision Targa 2000 board (TVJP)
  2398. TVMJ Pinnacle/Truevision Targa 2000 board (TVMJ)
  2399. TY0N Tecomac Low-Bit Rate Codec (www.tecomac.com)
  2400. TY2C Trident Decompression Driver
  2401. TLMS TeraLogic Motion Intraframe Codec (TLMS)
  2402. TLST TeraLogic Motion Intraframe Codec (TLST)
  2403. TM20 Duck TrueMotion 2.0
  2404. TM2X Duck TrueMotion 2X
  2405. TMIC TeraLogic Motion Intraframe Codec (TMIC)
  2406. TMOT Horizons Technology TrueMotion S
  2407. tmot Horizons TrueMotion Video Compression
  2408. TR20 Duck TrueMotion RealTime 2.0
  2409. TSCC TechSmith Screen Capture Codec
  2410. TV10 Tecomac Low-Bit Rate Codec
  2411. TY2N Trident ?TY2N?
  2412. U263 UB Video H.263/H.263+/H.263++ Decoder
  2413. UMP4 UB Video MPEG 4 (www.ubvideo.com)
  2414. UYNV Nvidia UYVY packed 4:2:2
  2415. UYVP Evans & Sutherland YCbCr 4:2:2 extended precision
  2416. UCOD eMajix.com ClearVideo
  2417. ULTI IBM Ultimotion
  2418. UYVY UYVY packed 4:2:2
  2419. V261 Lucent VX2000S
  2420. VIFP VFAPI Reader Codec (www.yks.ne.jp/~hori/)
  2421. VIV1 FFmpeg H263+ decoder
  2422. VIV2 Vivo H.263
  2423. VQC2 Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf)
  2424. VTLP Alaris VideoGramPiX
  2425. VYU9 ATI YUV (VYU9)
  2426. VYUY ATI YUV (VYUY)
  2427. V261 Lucent VX2000S
  2428. V422 Vitec Multimedia 24-bit YUV 4:2:2 Format
  2429. V655 Vitec Multimedia 16-bit YUV 4:2:2 Format
  2430. VCR1 ATI Video Codec 1
  2431. VCR2 ATI Video Codec 2
  2432. VCR3 ATI VCR 3.0
  2433. VCR4 ATI VCR 4.0
  2434. VCR5 ATI VCR 5.0
  2435. VCR6 ATI VCR 6.0
  2436. VCR7 ATI VCR 7.0
  2437. VCR8 ATI VCR 8.0
  2438. VCR9 ATI VCR 9.0
  2439. VDCT Vitec Multimedia Video Maker Pro DIB
  2440. VDOM VDOnet VDOWave
  2441. VDOW VDOnet VDOLive (H.263)
  2442. VDTZ Darim Vison VideoTizer YUV
  2443. VGPX Alaris VideoGramPiX
  2444. VIDS Vitec Multimedia YUV 4:2:2 CCIR 601 for V422
  2445. VIVO Vivo H.263 v2.00
  2446. vivo Vivo H.263
  2447. VIXL Miro/Pinnacle Video XL
  2448. VLV1 VideoLogic/PURE Digital Videologic Capture
  2449. VP30 On2 VP3.0
  2450. VP31 On2 VP3.1
  2451. VP6F On2 TrueMotion VP6
  2452. VX1K Lucent VX1000S Video Codec
  2453. VX2K Lucent VX2000S Video Codec
  2454. VXSP Lucent VX1000SP Video Codec
  2455. WBVC Winbond W9960
  2456. WHAM Microsoft Video 1 (WHAM)
  2457. WINX Winnov Software Compression
  2458. WJPG AverMedia Winbond JPEG
  2459. WMV1 Windows Media Video V7
  2460. WMV2 Windows Media Video V8
  2461. WMV3 Windows Media Video V9
  2462. WNV1 Winnov Hardware Compression
  2463. XYZP Extended PAL format XYZ palette (www.riff.org)
  2464. x263 Xirlink H.263
  2465. XLV0 NetXL Video Decoder
  2466. XMPG Xing MPEG (I-Frame only)
  2467. XVID XviD MPEG-4 (www.xvid.org)
  2468. XXAN ?XXAN?
  2469. YU92 Intel YUV (YU92)
  2470. YUNV Nvidia Uncompressed YUV 4:2:2
  2471. YUVP Extended PAL format YUV palette (www.riff.org)
  2472. Y211 YUV 2:1:1 Packed
  2473. Y411 YUV 4:1:1 Packed
  2474. Y41B Weitek YUV 4:1:1 Planar
  2475. Y41P Brooktree PC1 YUV 4:1:1 Packed
  2476. Y41T Brooktree PC1 YUV 4:1:1 with transparency
  2477. Y42B Weitek YUV 4:2:2 Planar
  2478. Y42T Brooktree UYUV 4:2:2 with transparency
  2479. Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
  2480. Y800 Simple, single Y plane for monochrome images
  2481. Y8 Grayscale video
  2482. YC12 Intel YUV 12 codec
  2483. YUV8 Winnov Caviar YUV8
  2484. YUV9 Intel YUV9
  2485. YUY2 Uncompressed YUV 4:2:2
  2486. YUYV Canopus YUV
  2487. YV12 YVU12 Planar
  2488. YVU9 Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes)
  2489. YVYU YVYU 4:2:2 Packed
  2490. ZLIB Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
  2491. ZPEG Metheus Video Zipper
  2492. */
  2493. return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
  2494. }
  2495. /**
  2496. * @param string $byteword
  2497. * @param bool $signed
  2498. *
  2499. * @return int|float|false
  2500. */
  2501. private function EitherEndian2Int($byteword, $signed=false) {
  2502. if ($this->container == 'riff') {
  2503. return getid3_lib::LittleEndian2Int($byteword, $signed);
  2504. }
  2505. return getid3_lib::BigEndian2Int($byteword, false, $signed);
  2506. }
  2507. }