PageRenderTime 61ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/holyfield/getid3
PHP | 2128 lines | 1817 code | 179 blank | 132 comment | 168 complexity | 39948e0652f76cc9045d7e55f51e9452 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. /////////////////////////////////////////////////////////////////
  7. // See readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  9. // //
  10. // module.audio-video.quicktime.php //
  11. // module for analyzing Quicktime and MP3-in-MP4 files //
  12. // dependencies: module.audio.mp3.php //
  13. // ///
  14. /////////////////////////////////////////////////////////////////
  15. getid3_lib::IncludeDependency ( GETID3_INCLUDEPATH . 'module.audio.mp3.php', __FILE__, true );
  16. class getid3_quicktime extends getid3_handler {
  17. var $ReturnAtomData = true;
  18. var $ParseAllPossibleAtoms = false;
  19. function Analyze() {
  20. $info = &$this->getid3->info;
  21. $info ['fileformat'] = 'quicktime';
  22. $info ['quicktime'] ['hinting'] = false;
  23. $info ['quicktime'] ['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
  24. fseek ( $this->getid3->fp, $info ['avdataoffset'], SEEK_SET );
  25. $offset = 0;
  26. $atomcounter = 0;
  27. while ( $offset < $info ['avdataend'] ) {
  28. if (! getid3_lib::intValueSupported ( $offset )) {
  29. $info ['error'] [] = 'Unable to parse atom at offset ' . $offset . ' because beyond ' . round ( PHP_INT_MAX / 1073741824 ) . 'GB limit of PHP filesystem functions';
  30. break;
  31. }
  32. fseek ( $this->getid3->fp, $offset, SEEK_SET );
  33. $AtomHeader = fread ( $this->getid3->fp, 8 );
  34. $atomsize = getid3_lib::BigEndian2Int ( substr ( $AtomHeader, 0, 4 ) );
  35. $atomname = substr ( $AtomHeader, 4, 4 );
  36. // 64-bit MOV patch by jlegateØktnc*com
  37. if ($atomsize == 1) {
  38. $atomsize = getid3_lib::BigEndian2Int ( fread ( $this->getid3->fp, 8 ) );
  39. }
  40. $info ['quicktime'] [$atomname] ['name'] = $atomname;
  41. $info ['quicktime'] [$atomname] ['size'] = $atomsize;
  42. $info ['quicktime'] [$atomname] ['offset'] = $offset;
  43. if (($offset + $atomsize) > $info ['avdataend']) {
  44. $info ['error'] [] = 'Atom at offset ' . $offset . ' claims to go beyond end-of-file (length: ' . $atomsize . ' bytes)';
  45. return false;
  46. }
  47. if ($atomsize == 0) {
  48. // Furthermore, for historical reasons the list of atoms is optionally
  49. // terminated by a 32-bit integer set to 0. If you are writing a program
  50. // to read user data atoms, you should allow for the terminating 0.
  51. break;
  52. }
  53. switch ($atomname) {
  54. case 'mdat' : // Media DATa atom
  55. // 'mdat' contains the actual data for the audio/video
  56. if (($atomsize > 8) && (! isset ( $info ['avdataend_tmp'] ) || ($info ['quicktime'] [$atomname] ['size'] > ($info ['avdataend_tmp'] - $info ['avdataoffset'])))) {
  57. $info ['avdataoffset'] = $info ['quicktime'] [$atomname] ['offset'] + 8;
  58. $OldAVDataEnd = $info ['avdataend'];
  59. $info ['avdataend'] = $info ['quicktime'] [$atomname] ['offset'] + $info ['quicktime'] [$atomname] ['size'];
  60. $getid3_temp = new getID3 ();
  61. $getid3_temp->openfile ( $this->getid3->filename );
  62. $getid3_temp->info ['avdataoffset'] = $info ['avdataoffset'];
  63. $getid3_temp->info ['avdataend'] = $info ['avdataend'];
  64. $getid3_mp3 = new getid3_mp3 ( $getid3_temp );
  65. if ($getid3_mp3->MPEGaudioHeaderValid ( $getid3_mp3->MPEGaudioHeaderDecode ( fread ( $this->getid3->fp, 4 ) ) )) {
  66. $getid3_mp3->getOnlyMPEGaudioInfo ( $getid3_temp->info ['avdataoffset'], false );
  67. if (! empty ( $getid3_temp->info ['warning'] )) {
  68. foreach ( $getid3_temp->info ['warning'] as $value ) {
  69. $info ['warning'] [] = $value;
  70. }
  71. }
  72. if (! empty ( $getid3_temp->info ['mpeg'] )) {
  73. $info ['mpeg'] = $getid3_temp->info ['mpeg'];
  74. if (isset ( $info ['mpeg'] ['audio'] )) {
  75. $info ['audio'] ['dataformat'] = 'mp3';
  76. $info ['audio'] ['codec'] = (! empty ( $info ['mpeg'] ['audio'] ['encoder'] ) ? $info ['mpeg'] ['audio'] ['encoder'] : (! empty ( $info ['mpeg'] ['audio'] ['codec'] ) ? $info ['mpeg'] ['audio'] ['codec'] : (! empty ( $info ['mpeg'] ['audio'] ['LAME'] ) ? 'LAME' : 'mp3')));
  77. $info ['audio'] ['sample_rate'] = $info ['mpeg'] ['audio'] ['sample_rate'];
  78. $info ['audio'] ['channels'] = $info ['mpeg'] ['audio'] ['channels'];
  79. $info ['audio'] ['bitrate'] = $info ['mpeg'] ['audio'] ['bitrate'];
  80. $info ['audio'] ['bitrate_mode'] = strtolower ( $info ['mpeg'] ['audio'] ['bitrate_mode'] );
  81. $info ['bitrate'] = $info ['audio'] ['bitrate'];
  82. }
  83. }
  84. }
  85. unset ( $getid3_mp3, $getid3_temp );
  86. $info ['avdataend'] = $OldAVDataEnd;
  87. unset ( $OldAVDataEnd );
  88. }
  89. break;
  90. case 'free' : // FREE space atom
  91. case 'skip' : // SKIP atom
  92. case 'wide' : // 64-bit expansion placeholder atom
  93. // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
  94. break;
  95. default :
  96. $atomHierarchy = array ();
  97. $info ['quicktime'] [$atomname] = $this->QuicktimeParseAtom ( $atomname, $atomsize, fread ( $this->getid3->fp, $atomsize ), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms );
  98. break;
  99. }
  100. $offset += $atomsize;
  101. $atomcounter ++;
  102. }
  103. if (! empty ( $info ['avdataend_tmp'] )) {
  104. // this value is assigned to a temp value and then erased because
  105. // otherwise any atoms beyond the 'mdat' atom would not get parsed
  106. $info ['avdataend'] = $info ['avdataend_tmp'];
  107. unset ( $info ['avdataend_tmp'] );
  108. }
  109. if (! isset ( $info ['bitrate'] ) && isset ( $info ['playtime_seconds'] )) {
  110. $info ['bitrate'] = (($info ['avdataend'] - $info ['avdataoffset']) * 8) / $info ['playtime_seconds'];
  111. }
  112. if (isset ( $info ['bitrate'] ) && ! isset ( $info ['audio'] ['bitrate'] ) && ! isset ( $info ['quicktime'] ['video'] )) {
  113. $info ['audio'] ['bitrate'] = $info ['bitrate'];
  114. }
  115. if (! empty ( $info ['playtime_seconds'] ) && ! isset ( $info ['video'] ['frame_rate'] ) && ! empty ( $info ['quicktime'] ['stts_framecount'] )) {
  116. foreach ( $info ['quicktime'] ['stts_framecount'] as $key => $samples_count ) {
  117. $samples_per_second = $samples_count / $info ['playtime_seconds'];
  118. if ($samples_per_second > 240) {
  119. // has to be audio samples
  120. } else {
  121. $info ['video'] ['frame_rate'] = $samples_per_second;
  122. break;
  123. }
  124. }
  125. }
  126. if (($info ['audio'] ['dataformat'] == 'mp4') && empty ( $info ['video'] ['resolution_x'] )) {
  127. $info ['fileformat'] = 'mp4';
  128. $info ['mime_type'] = 'audio/mp4';
  129. unset ( $info ['video'] ['dataformat'] );
  130. }
  131. if (! $this->ReturnAtomData) {
  132. unset ( $info ['quicktime'] ['moov'] );
  133. }
  134. if (empty ( $info ['audio'] ['dataformat'] ) && ! empty ( $info ['quicktime'] ['audio'] )) {
  135. $info ['audio'] ['dataformat'] = 'quicktime';
  136. }
  137. if (empty ( $info ['video'] ['dataformat'] ) && ! empty ( $info ['quicktime'] ['video'] )) {
  138. $info ['video'] ['dataformat'] = 'quicktime';
  139. }
  140. return true;
  141. }
  142. function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
  143. // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
  144. $info = &$this->getid3->info;
  145. $atom_parent = array_pop ( $atomHierarchy );
  146. array_push ( $atomHierarchy, $atomname );
  147. $atom_structure ['hierarchy'] = implode ( ' ', $atomHierarchy );
  148. $atom_structure ['name'] = $atomname;
  149. $atom_structure ['size'] = $atomsize;
  150. $atom_structure ['offset'] = $baseoffset;
  151. //echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'<br>';
  152. //echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'<br><br>';
  153. switch ($atomname) {
  154. case 'moov' : // MOVie container atom
  155. case 'trak' : // TRAcK container atom
  156. case 'clip' : // CLIPping container atom
  157. case 'matt' : // track MATTe container atom
  158. case 'edts' : // EDiTS container atom
  159. case 'tref' : // Track REFerence container atom
  160. case 'mdia' : // MeDIA container atom
  161. case 'minf' : // Media INFormation container atom
  162. case 'dinf' : // Data INFormation container atom
  163. case 'udta' : // User DaTA container atom
  164. case 'cmov' : // Compressed MOVie container atom
  165. case 'rmra' : // Reference Movie Record Atom
  166. case 'rmda' : // Reference Movie Descriptor Atom
  167. case 'gmhd' : // Generic Media info HeaDer atom (seen on QTVR)
  168. $atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
  169. break;
  170. case 'ilst' : // Item LiST container atom
  171. $atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
  172. // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
  173. $allnumericnames = true;
  174. foreach ( $atom_structure ['subatoms'] as $subatomarray ) {
  175. if (! is_integer ( $subatomarray ['name'] ) || (count ( $subatomarray ['subatoms'] ) != 1)) {
  176. $allnumericnames = false;
  177. break;
  178. }
  179. }
  180. if ($allnumericnames) {
  181. $newData = array ();
  182. foreach ( $atom_structure ['subatoms'] as $subatomarray ) {
  183. foreach ( $subatomarray ['subatoms'] as $newData_subatomarray ) {
  184. unset ( $newData_subatomarray ['hierarchy'], $newData_subatomarray ['name'] );
  185. $newData [$subatomarray ['name']] = $newData_subatomarray;
  186. break;
  187. }
  188. }
  189. $atom_structure ['data'] = $newData;
  190. unset ( $atom_structure ['subatoms'] );
  191. }
  192. break;
  193. case "\x00\x00\x00\x01" :
  194. case "\x00\x00\x00\x02" :
  195. case "\x00\x00\x00\x03" :
  196. case "\x00\x00\x00\x04" :
  197. case "\x00\x00\x00\x05" :
  198. $atomname = getid3_lib::BigEndian2Int ( $atomname );
  199. $atom_structure ['name'] = $atomname;
  200. $atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
  201. break;
  202. case 'stbl' : // Sample TaBLe container atom
  203. $atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
  204. $isVideo = false;
  205. $framerate = 0;
  206. $framecount = 0;
  207. foreach ( $atom_structure ['subatoms'] as $key => $value_array ) {
  208. if (isset ( $value_array ['sample_description_table'] )) {
  209. foreach ( $value_array ['sample_description_table'] as $key2 => $value_array2 ) {
  210. if (isset ( $value_array2 ['data_format'] )) {
  211. switch ($value_array2 ['data_format']) {
  212. case 'avc1' :
  213. case 'mp4v' :
  214. // video data
  215. $isVideo = true;
  216. break;
  217. case 'mp4a' :
  218. // audio data
  219. break;
  220. }
  221. }
  222. }
  223. } elseif (isset ( $value_array ['time_to_sample_table'] )) {
  224. foreach ( $value_array ['time_to_sample_table'] as $key2 => $value_array2 ) {
  225. if (isset ( $value_array2 ['sample_count'] ) && isset ( $value_array2 ['sample_duration'] ) && ($value_array2 ['sample_duration'] > 0)) {
  226. $framerate = round ( $info ['quicktime'] ['time_scale'] / $value_array2 ['sample_duration'], 3 );
  227. $framecount = $value_array2 ['sample_count'];
  228. }
  229. }
  230. }
  231. }
  232. if ($isVideo && $framerate) {
  233. $info ['quicktime'] ['video'] ['frame_rate'] = $framerate;
  234. $info ['video'] ['frame_rate'] = $info ['quicktime'] ['video'] ['frame_rate'];
  235. }
  236. if ($isVideo && $framecount) {
  237. $info ['quicktime'] ['video'] ['frame_count'] = $framecount;
  238. }
  239. break;
  240. case 'aART' : // Album ARTist
  241. case 'catg' : // CaTeGory
  242. case 'covr' : // COVeR artwork
  243. case 'cpil' : // ComPILation
  244. case 'cprt' : // CoPyRighT
  245. case 'desc' : // DESCription
  246. case 'disk' : // DISK number
  247. case 'egid' : // Episode Global ID
  248. case 'gnre' : // GeNRE
  249. case 'keyw' : // KEYWord
  250. case 'ldes' :
  251. case 'pcst' : // PodCaST
  252. case 'pgap' : // GAPless Playback
  253. case 'purd' : // PURchase Date
  254. case 'purl' : // Podcast URL
  255. case 'rati' :
  256. case 'rndu' :
  257. case 'rpdu' :
  258. case 'rtng' : // RaTiNG
  259. case 'stik' :
  260. case 'tmpo' : // TeMPO (BPM)
  261. case 'trkn' : // TRacK Number
  262. case 'tves' : // TV EpiSode
  263. case 'tvnn' : // TV Network Name
  264. case 'tvsh' : // TV SHow Name
  265. case 'tvsn' : // TV SeasoN
  266. case 'akID' : // iTunes store account type
  267. case 'apID' :
  268. case 'atID' :
  269. case 'cmID' :
  270. case 'cnID' :
  271. case 'geID' :
  272. case 'plID' :
  273. case 'sfID' : // iTunes store country
  274. case '©alb' : // ALBum
  275. case '©art' : // ARTist
  276. case '©ART' :
  277. case '©aut' :
  278. case '©cmt' : // CoMmenT
  279. case '©com' : // COMposer
  280. case '©cpy' :
  281. case '©day' : // content created year
  282. case '©dir' :
  283. case '©ed1' :
  284. case '©ed2' :
  285. case '©ed3' :
  286. case '©ed4' :
  287. case '©ed5' :
  288. case '©ed6' :
  289. case '©ed7' :
  290. case '©ed8' :
  291. case '©ed9' :
  292. case '©enc' :
  293. case '©fmt' :
  294. case '©gen' : // GENre
  295. case '©grp' : // GRouPing
  296. case '©hst' :
  297. case '©inf' :
  298. case '©lyr' : // LYRics
  299. case '©mak' :
  300. case '©mod' :
  301. case '©nam' : // full NAMe
  302. case '©ope' :
  303. case '©PRD' :
  304. case '©prd' :
  305. case '©prf' :
  306. case '©req' :
  307. case '©src' :
  308. case '©swr' :
  309. case '©too' : // encoder
  310. case '©trk' : // TRacK
  311. case '©url' :
  312. case '©wrn' :
  313. case '©wrt' : // WRiTer
  314. case '----' : // itunes specific
  315. if ($atom_parent == 'udta') {
  316. // User data atom handler
  317. $atom_structure ['data_length'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 2 ) );
  318. $atom_structure ['language_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 2, 2 ) );
  319. $atom_structure ['data'] = substr ( $atom_data, 4 );
  320. $atom_structure ['language'] = $this->QuicktimeLanguageLookup ( $atom_structure ['language_id'] );
  321. if (empty ( $info ['comments'] ['language'] ) || (! in_array ( $atom_structure ['language'], $info ['comments'] ['language'] ))) {
  322. $info ['comments'] ['language'] [] = $atom_structure ['language'];
  323. }
  324. } else {
  325. // Apple item list box atom handler
  326. $atomoffset = 0;
  327. if (substr ( $atom_data, 2, 2 ) == "\x10\xB5") {
  328. // not sure what it means, but observed on iPhone4 data.
  329. // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
  330. while ( $atomoffset < strlen ( $atom_data ) ) {
  331. $boxsmallsize = getid3_lib::BigEndian2Int ( substr ( $atom_data, $atomoffset, 2 ) );
  332. $boxsmalltype = substr ( $atom_data, $atomoffset + 2, 2 );
  333. $boxsmalldata = substr ( $atom_data, $atomoffset + 4, $boxsmallsize );
  334. switch ($boxsmalltype) {
  335. case "\x10\xB5" :
  336. $atom_structure ['data'] = $boxsmalldata;
  337. break;
  338. default :
  339. $info ['warning'] [] = 'Unknown QuickTime smallbox type: "' . getid3_lib::PrintHexBytes ( $boxsmalltype ) . '" at offset ' . $baseoffset;
  340. $atom_structure ['data'] = $atom_data;
  341. break;
  342. }
  343. $atomoffset += (4 + $boxsmallsize);
  344. }
  345. } else {
  346. while ( $atomoffset < strlen ( $atom_data ) ) {
  347. $boxsize = getid3_lib::BigEndian2Int ( substr ( $atom_data, $atomoffset, 4 ) );
  348. $boxtype = substr ( $atom_data, $atomoffset + 4, 4 );
  349. $boxdata = substr ( $atom_data, $atomoffset + 8, $boxsize - 8 );
  350. switch ($boxtype) {
  351. case 'mean' :
  352. case 'name' :
  353. $atom_structure [$boxtype] = substr ( $boxdata, 4 );
  354. break;
  355. case 'data' :
  356. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 0, 1 ) );
  357. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 1, 3 ) );
  358. switch ($atom_structure ['flags_raw']) {
  359. case 0 : // data flag
  360. case 21 : // tmpo/cpil flag
  361. switch ($atomname) {
  362. case 'cpil' :
  363. case 'pcst' :
  364. case 'pgap' :
  365. $atom_structure ['data'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 1 ) );
  366. break;
  367. case 'tmpo' :
  368. $atom_structure ['data'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 2 ) );
  369. break;
  370. case 'disk' :
  371. case 'trkn' :
  372. $num = getid3_lib::BigEndian2Int ( substr ( $boxdata, 10, 2 ) );
  373. $num_total = getid3_lib::BigEndian2Int ( substr ( $boxdata, 12, 2 ) );
  374. $atom_structure ['data'] = empty ( $num ) ? '' : $num;
  375. $atom_structure ['data'] .= empty ( $num_total ) ? '' : '/' . $num_total;
  376. break;
  377. case 'gnre' :
  378. $GenreID = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 4 ) );
  379. $atom_structure ['data'] = getid3_id3v1::LookupGenreName ( $GenreID - 1 );
  380. break;
  381. case 'rtng' :
  382. $atom_structure [$atomname] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 1 ) );
  383. $atom_structure ['data'] = $this->QuicktimeContentRatingLookup ( $atom_structure [$atomname] );
  384. break;
  385. case 'stik' :
  386. $atom_structure [$atomname] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 1 ) );
  387. $atom_structure ['data'] = $this->QuicktimeSTIKLookup ( $atom_structure [$atomname] );
  388. break;
  389. case 'sfID' :
  390. $atom_structure [$atomname] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 4 ) );
  391. $atom_structure ['data'] = $this->QuicktimeStoreFrontCodeLookup ( $atom_structure [$atomname] );
  392. break;
  393. case 'egid' :
  394. case 'purl' :
  395. $atom_structure ['data'] = substr ( $boxdata, 8 );
  396. break;
  397. default :
  398. $atom_structure ['data'] = getid3_lib::BigEndian2Int ( substr ( $boxdata, 8, 4 ) );
  399. }
  400. break;
  401. case 1 : // text flag
  402. case 13 : // image flag
  403. default :
  404. $atom_structure ['data'] = substr ( $boxdata, 8 );
  405. break;
  406. }
  407. break;
  408. default :
  409. $info ['warning'] [] = 'Unknown QuickTime box type: "' . getid3_lib::PrintHexBytes ( $boxtype ) . '" at offset ' . $baseoffset;
  410. $atom_structure ['data'] = $atom_data;
  411. }
  412. $atomoffset += $boxsize;
  413. }
  414. }
  415. }
  416. $this->CopyToAppropriateCommentsSection ( $atomname, $atom_structure ['data'], $atom_structure ['name'] );
  417. break;
  418. case 'play' : // auto-PLAY atom
  419. $atom_structure ['autoplay'] = ( bool ) getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  420. $info ['quicktime'] ['autoplay'] = $atom_structure ['autoplay'];
  421. break;
  422. case 'WLOC' : // Window LOCation atom
  423. $atom_structure ['location_x'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 2 ) );
  424. $atom_structure ['location_y'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 2, 2 ) );
  425. break;
  426. case 'LOOP' : // LOOPing atom
  427. case 'SelO' : // play SELection Only atom
  428. case 'AllF' : // play ALL Frames atom
  429. $atom_structure ['data'] = getid3_lib::BigEndian2Int ( $atom_data );
  430. break;
  431. case 'name' : //
  432. case 'MCPS' : // Media Cleaner PRo
  433. case '@PRM' : // adobe PReMiere version
  434. case '@PRQ' : // adobe PRemiere Quicktime version
  435. $atom_structure ['data'] = $atom_data;
  436. break;
  437. case 'cmvd' : // Compressed MooV Data atom
  438. // Code by ubergeekØubergeek*tv based on information from
  439. // http://developer.apple.com/quicktime/icefloe/dispatch012.html
  440. $atom_structure ['unCompressedSize'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 4 ) );
  441. $CompressedFileData = substr ( $atom_data, 4 );
  442. if (($UncompressedHeader = @gzuncompress ( $CompressedFileData )) != false) {
  443. $atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms );
  444. } else {
  445. $info ['warning'] [] = 'Error decompressing compressed MOV atom at offset ' . $atom_structure ['offset'];
  446. }
  447. break;
  448. case 'dcom' : // Data COMpression atom
  449. $atom_structure ['compression_id'] = $atom_data;
  450. $atom_structure ['compression_text'] = $this->QuicktimeDCOMLookup ( $atom_data );
  451. break;
  452. case 'rdrf' : // Reference movie Data ReFerence atom
  453. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  454. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) );
  455. $atom_structure ['flags'] ['internal_data'] = ( bool ) ($atom_structure ['flags_raw'] & 0x000001);
  456. $atom_structure ['reference_type_name'] = substr ( $atom_data, 4, 4 );
  457. $atom_structure ['reference_length'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
  458. switch ($atom_structure ['reference_type_name']) {
  459. case 'url ' :
  460. $atom_structure ['url'] = $this->NoNullString ( substr ( $atom_data, 12 ) );
  461. break;
  462. case 'alis' :
  463. $atom_structure ['file_alias'] = substr ( $atom_data, 12 );
  464. break;
  465. case 'rsrc' :
  466. $atom_structure ['resource_alias'] = substr ( $atom_data, 12 );
  467. break;
  468. default :
  469. $atom_structure ['data'] = substr ( $atom_data, 12 );
  470. break;
  471. }
  472. break;
  473. case 'rmqu' : // Reference Movie QUality atom
  474. $atom_structure ['movie_quality'] = getid3_lib::BigEndian2Int ( $atom_data );
  475. break;
  476. case 'rmcs' : // Reference Movie Cpu Speed atom
  477. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  478. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  479. $atom_structure ['cpu_speed_rating'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
  480. break;
  481. case 'rmvc' : // Reference Movie Version Check atom
  482. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  483. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  484. $atom_structure ['gestalt_selector'] = substr ( $atom_data, 4, 4 );
  485. $atom_structure ['gestalt_value_mask'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
  486. $atom_structure ['gestalt_value'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 4 ) );
  487. $atom_structure ['gestalt_check_type'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 14, 2 ) );
  488. break;
  489. case 'rmcd' : // Reference Movie Component check atom
  490. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  491. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  492. $atom_structure ['component_type'] = substr ( $atom_data, 4, 4 );
  493. $atom_structure ['component_subtype'] = substr ( $atom_data, 8, 4 );
  494. $atom_structure ['component_manufacturer'] = substr ( $atom_data, 12, 4 );
  495. $atom_structure ['component_flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 16, 4 ) );
  496. $atom_structure ['component_flags_mask'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 20, 4 ) );
  497. $atom_structure ['component_min_version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 24, 4 ) );
  498. break;
  499. case 'rmdr' : // Reference Movie Data Rate atom
  500. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  501. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  502. $atom_structure ['data_rate'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  503. $atom_structure ['data_rate_bps'] = $atom_structure ['data_rate'] * 10;
  504. break;
  505. case 'rmla' : // Reference Movie Language Atom
  506. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  507. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  508. $atom_structure ['language_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
  509. $atom_structure ['language'] = $this->QuicktimeLanguageLookup ( $atom_structure ['language_id'] );
  510. if (empty ( $info ['comments'] ['language'] ) || (! in_array ( $atom_structure ['language'], $info ['comments'] ['language'] ))) {
  511. $info ['comments'] ['language'] [] = $atom_structure ['language'];
  512. }
  513. break;
  514. case 'rmla' : // Reference Movie Language Atom
  515. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  516. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  517. $atom_structure ['track_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
  518. break;
  519. case 'ptv ' : // Print To Video - defines a movie's full screen mode
  520. // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
  521. $atom_structure ['display_size_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 2 ) );
  522. $atom_structure ['reserved_1'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 2, 2 ) ); // hardcoded: 0x0000
  523. $atom_structure ['reserved_2'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) ); // hardcoded: 0x0000
  524. $atom_structure ['slide_show_flag'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 1 ) );
  525. $atom_structure ['play_on_open_flag'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 7, 1 ) );
  526. $atom_structure ['flags'] ['play_on_open'] = ( bool ) $atom_structure ['play_on_open_flag'];
  527. $atom_structure ['flags'] ['slide_show'] = ( bool ) $atom_structure ['slide_show_flag'];
  528. $ptv_lookup [0] = 'normal';
  529. $ptv_lookup [1] = 'double';
  530. $ptv_lookup [2] = 'half';
  531. $ptv_lookup [3] = 'full';
  532. $ptv_lookup [4] = 'current';
  533. if (isset ( $ptv_lookup [$atom_structure ['display_size_raw']] )) {
  534. $atom_structure ['display_size'] = $ptv_lookup [$atom_structure ['display_size_raw']];
  535. } else {
  536. $info ['warning'] [] = 'unknown "ptv " display constant (' . $atom_structure ['display_size_raw'] . ')';
  537. }
  538. break;
  539. case 'stsd' : // Sample Table Sample Description atom
  540. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  541. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  542. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  543. $stsdEntriesDataOffset = 8;
  544. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  545. $atom_structure ['sample_description_table'] [$i] ['size'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stsdEntriesDataOffset, 4 ) );
  546. $stsdEntriesDataOffset += 4;
  547. $atom_structure ['sample_description_table'] [$i] ['data_format'] = substr ( $atom_data, $stsdEntriesDataOffset, 4 );
  548. $stsdEntriesDataOffset += 4;
  549. $atom_structure ['sample_description_table'] [$i] ['reserved'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stsdEntriesDataOffset, 6 ) );
  550. $stsdEntriesDataOffset += 6;
  551. $atom_structure ['sample_description_table'] [$i] ['reference_index'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stsdEntriesDataOffset, 2 ) );
  552. $stsdEntriesDataOffset += 2;
  553. $atom_structure ['sample_description_table'] [$i] ['data'] = substr ( $atom_data, $stsdEntriesDataOffset, ($atom_structure ['sample_description_table'] [$i] ['size'] - 4 - 4 - 6 - 2) );
  554. $stsdEntriesDataOffset += ($atom_structure ['sample_description_table'] [$i] ['size'] - 4 - 4 - 6 - 2);
  555. $atom_structure ['sample_description_table'] [$i] ['encoder_version'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 0, 2 ) );
  556. $atom_structure ['sample_description_table'] [$i] ['encoder_revision'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 2, 2 ) );
  557. $atom_structure ['sample_description_table'] [$i] ['encoder_vendor'] = substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 4, 4 );
  558. switch ($atom_structure ['sample_description_table'] [$i] ['encoder_vendor']) {
  559. case "\x00\x00\x00\x00" :
  560. // audio atom
  561. $atom_structure ['sample_description_table'] [$i] ['audio_channels'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 8, 2 ) );
  562. $atom_structure ['sample_description_table'] [$i] ['audio_bit_depth'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 10, 2 ) );
  563. $atom_structure ['sample_description_table'] [$i] ['audio_compression_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 12, 2 ) );
  564. $atom_structure ['sample_description_table'] [$i] ['audio_packet_size'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 14, 2 ) );
  565. $atom_structure ['sample_description_table'] [$i] ['audio_sample_rate'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 16, 4 ) );
  566. switch ($atom_structure ['sample_description_table'] [$i] ['data_format']) {
  567. case 'avc1' :
  568. case 'mp4v' :
  569. $info ['fileformat'] = 'mp4';
  570. $info ['video'] ['fourcc'] = $atom_structure ['sample_description_table'] [$i] ['data_format'];
  571. //$info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] does not fully support MPEG-4 audio/video streams'; // 2011-02-18: why am I warning about this again? What's not supported?
  572. break;
  573. case 'qtvr' :
  574. $info ['video'] ['dataformat'] = 'quicktimevr';
  575. break;
  576. case 'mp4a' :
  577. default :
  578. $info ['quicktime'] ['audio'] ['codec'] = $this->QuicktimeAudioCodecLookup ( $atom_structure ['sample_description_table'] [$i] ['data_format'] );
  579. $info ['quicktime'] ['audio'] ['sample_rate'] = $atom_structure ['sample_description_table'] [$i] ['audio_sample_rate'];
  580. $info ['quicktime'] ['audio'] ['channels'] = $atom_structure ['sample_description_table'] [$i] ['audio_channels'];
  581. $info ['quicktime'] ['audio'] ['bit_depth'] = $atom_structure ['sample_description_table'] [$i] ['audio_bit_depth'];
  582. $info ['audio'] ['codec'] = $info ['quicktime'] ['audio'] ['codec'];
  583. $info ['audio'] ['sample_rate'] = $info ['quicktime'] ['audio'] ['sample_rate'];
  584. $info ['audio'] ['channels'] = $info ['quicktime'] ['audio'] ['channels'];
  585. $info ['audio'] ['bits_per_sample'] = $info ['quicktime'] ['audio'] ['bit_depth'];
  586. switch ($atom_structure ['sample_description_table'] [$i] ['data_format']) {
  587. case 'raw ' : // PCM
  588. case 'alac' : // Apple Lossless Audio Codec
  589. $info ['audio'] ['lossless'] = true;
  590. break;
  591. default :
  592. $info ['audio'] ['lossless'] = false;
  593. break;
  594. }
  595. break;
  596. }
  597. break;
  598. default :
  599. switch ($atom_structure ['sample_description_table'] [$i] ['data_format']) {
  600. case 'mp4s' :
  601. $info ['fileformat'] = 'mp4';
  602. break;
  603. default :
  604. // video atom
  605. $atom_structure ['sample_description_table'] [$i] ['video_temporal_quality'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 8, 4 ) );
  606. $atom_structure ['sample_description_table'] [$i] ['video_spatial_quality'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 12, 4 ) );
  607. $atom_structure ['sample_description_table'] [$i] ['video_frame_width'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 16, 2 ) );
  608. $atom_structure ['sample_description_table'] [$i] ['video_frame_height'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 18, 2 ) );
  609. $atom_structure ['sample_description_table'] [$i] ['video_resolution_x'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 20, 4 ) );
  610. $atom_structure ['sample_description_table'] [$i] ['video_resolution_y'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 24, 4 ) );
  611. $atom_structure ['sample_description_table'] [$i] ['video_data_size'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 28, 4 ) );
  612. $atom_structure ['sample_description_table'] [$i] ['video_frame_count'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 32, 2 ) );
  613. $atom_structure ['sample_description_table'] [$i] ['video_encoder_name_len'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 34, 1 ) );
  614. $atom_structure ['sample_description_table'] [$i] ['video_encoder_name'] = substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 35, $atom_structure ['sample_description_table'] [$i] ['video_encoder_name_len'] );
  615. $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_depth'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 66, 2 ) );
  616. $atom_structure ['sample_description_table'] [$i] ['video_color_table_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_structure ['sample_description_table'] [$i] ['data'], 68, 2 ) );
  617. $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_type'] = (($atom_structure ['sample_description_table'] [$i] ['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
  618. $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_name'] = $this->QuicktimeColorNameLookup ( $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_depth'] );
  619. if ($atom_structure ['sample_description_table'] [$i] ['video_pixel_color_name'] != 'invalid') {
  620. $info ['quicktime'] ['video'] ['codec_fourcc'] = $atom_structure ['sample_description_table'] [$i] ['data_format'];
  621. $info ['quicktime'] ['video'] ['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup ( $atom_structure ['sample_description_table'] [$i] ['data_format'] );
  622. $info ['quicktime'] ['video'] ['codec'] = (($atom_structure ['sample_description_table'] [$i] ['video_encoder_name_len'] > 0) ? $atom_structure ['sample_description_table'] [$i] ['video_encoder_name'] : $atom_structure ['sample_description_table'] [$i] ['data_format']);
  623. $info ['quicktime'] ['video'] ['color_depth'] = $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_depth'];
  624. $info ['quicktime'] ['video'] ['color_depth_name'] = $atom_structure ['sample_description_table'] [$i] ['video_pixel_color_name'];
  625. $info ['video'] ['codec'] = $info ['quicktime'] ['video'] ['codec'];
  626. $info ['video'] ['bits_per_sample'] = $info ['quicktime'] ['video'] ['color_depth'];
  627. }
  628. $info ['video'] ['lossless'] = false;
  629. $info ['video'] ['pixel_aspect_ratio'] = ( float ) 1;
  630. break;
  631. }
  632. break;
  633. }
  634. switch (strtolower ( $atom_structure ['sample_description_table'] [$i] ['data_format'] )) {
  635. case 'mp4a' :
  636. $info ['audio'] ['dataformat'] = 'mp4';
  637. $info ['quicktime'] ['audio'] ['codec'] = 'mp4';
  638. break;
  639. case '3ivx' :
  640. case '3iv1' :
  641. case '3iv2' :
  642. $info ['video'] ['dataformat'] = '3ivx';
  643. break;
  644. case 'xvid' :
  645. $info ['video'] ['dataformat'] = 'xvid';
  646. break;
  647. case 'mp4v' :
  648. $info ['video'] ['dataformat'] = 'mpeg4';
  649. break;
  650. case 'divx' :
  651. case 'div1' :
  652. case 'div2' :
  653. case 'div3' :
  654. case 'div4' :
  655. case 'div5' :
  656. case 'div6' :
  657. $info ['video'] ['dataformat'] = 'divx';
  658. break;
  659. default :
  660. // do nothing
  661. break;
  662. }
  663. unset ( $atom_structure ['sample_description_table'] [$i] ['data'] );
  664. }
  665. break;
  666. case 'stts' : // Sample Table Time-to-Sample atom
  667. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  668. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  669. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  670. $sttsEntriesDataOffset = 8;
  671. //$FrameRateCalculatorArray = array();
  672. $frames_count = 0;
  673. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  674. $atom_structure ['time_to_sample_table'] [$i] ['sample_count'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $sttsEntriesDataOffset, 4 ) );
  675. $sttsEntriesDataOffset += 4;
  676. $atom_structure ['time_to_sample_table'] [$i] ['sample_duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $sttsEntriesDataOffset, 4 ) );
  677. $sttsEntriesDataOffset += 4;
  678. $frames_count += $atom_structure ['time_to_sample_table'] [$i] ['sample_count'];
  679. // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
  680. //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
  681. // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
  682. // if ($stts_new_framerate <= 60) {
  683. // // some atoms have durations of "1" giving a very large framerate, which probably is not right
  684. // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
  685. // }
  686. //}
  687. //
  688. //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
  689. }
  690. $info ['quicktime'] ['stts_framecount'] [] = $frames_count;
  691. //$sttsFramesTotal = 0;
  692. //$sttsSecondsTotal = 0;
  693. //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
  694. // if (($frames_per_second > 60) || ($frames_per_second < 1)) {
  695. // // not video FPS information, probably audio information
  696. // $sttsFramesTotal = 0;
  697. // $sttsSecondsTotal = 0;
  698. // break;
  699. // }
  700. // $sttsFramesTotal += $frame_count;
  701. // $sttsSecondsTotal += $frame_count / $frames_per_second;
  702. //}
  703. //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
  704. // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
  705. // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
  706. // }
  707. //}
  708. break;
  709. case 'stss' : // Sample Table Sync Sample (key frames) atom
  710. if ($ParseAllPossibleAtoms) {
  711. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  712. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  713. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  714. $stssEntriesDataOffset = 8;
  715. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  716. $atom_structure ['time_to_sample_table'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stssEntriesDataOffset, 4 ) );
  717. $stssEntriesDataOffset += 4;
  718. }
  719. }
  720. break;
  721. case 'stsc' : // Sample Table Sample-to-Chunk atom
  722. if ($ParseAllPossibleAtoms) {
  723. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  724. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  725. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  726. $stscEntriesDataOffset = 8;
  727. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  728. $atom_structure ['sample_to_chunk_table'] [$i] ['first_chunk'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stscEntriesDataOffset, 4 ) );
  729. $stscEntriesDataOffset += 4;
  730. $atom_structure ['sample_to_chunk_table'] [$i] ['samples_per_chunk'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stscEntriesDataOffset, 4 ) );
  731. $stscEntriesDataOffset += 4;
  732. $atom_structure ['sample_to_chunk_table'] [$i] ['sample_description'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stscEntriesDataOffset, 4 ) );
  733. $stscEntriesDataOffset += 4;
  734. }
  735. }
  736. break;
  737. case 'stsz' : // Sample Table SiZe atom
  738. if ($ParseAllPossibleAtoms) {
  739. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  740. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  741. $atom_structure ['sample_size'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  742. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
  743. $stszEntriesDataOffset = 12;
  744. if ($atom_structure ['sample_size'] == 0) {
  745. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  746. $atom_structure ['sample_size_table'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stszEntriesDataOffset, 4 ) );
  747. $stszEntriesDataOffset += 4;
  748. }
  749. }
  750. }
  751. break;
  752. case 'stco' : // Sample Table Chunk Offset atom
  753. if ($ParseAllPossibleAtoms) {
  754. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  755. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  756. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  757. $stcoEntriesDataOffset = 8;
  758. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  759. $atom_structure ['chunk_offset_table'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stcoEntriesDataOffset, 4 ) );
  760. $stcoEntriesDataOffset += 4;
  761. }
  762. }
  763. break;
  764. case 'co64' : // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
  765. if ($ParseAllPossibleAtoms) {
  766. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  767. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  768. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  769. $stcoEntriesDataOffset = 8;
  770. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  771. $atom_structure ['chunk_offset_table'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $stcoEntriesDataOffset, 8 ) );
  772. $stcoEntriesDataOffset += 8;
  773. }
  774. }
  775. break;
  776. case 'dref' : // Data REFerence atom
  777. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  778. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  779. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  780. $drefDataOffset = 8;
  781. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  782. $atom_structure ['data_references'] [$i] ['size'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $drefDataOffset, 4 ) );
  783. $drefDataOffset += 4;
  784. $atom_structure ['data_references'] [$i] ['type'] = substr ( $atom_data, $drefDataOffset, 4 );
  785. $drefDataOffset += 4;
  786. $atom_structure ['data_references'] [$i] ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $drefDataOffset, 1 ) );
  787. $drefDataOffset += 1;
  788. $atom_structure ['data_references'] [$i] ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $drefDataOffset, 3 ) ); // hardcoded: 0x0000
  789. $drefDataOffset += 3;
  790. $atom_structure ['data_references'] [$i] ['data'] = substr ( $atom_data, $drefDataOffset, ($atom_structure ['data_references'] [$i] ['size'] - 4 - 4 - 1 - 3) );
  791. $drefDataOffset += ($atom_structure ['data_references'] [$i] ['size'] - 4 - 4 - 1 - 3);
  792. $atom_structure ['data_references'] [$i] ['flags'] ['self_reference'] = ( bool ) ($atom_structure ['data_references'] [$i] ['flags_raw'] & 0x001);
  793. }
  794. break;
  795. case 'gmin' : // base Media INformation atom
  796. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  797. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  798. $atom_structure ['graphics_mode'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
  799. $atom_structure ['opcolor_red'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 2 ) );
  800. $atom_structure ['opcolor_green'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 2 ) );
  801. $atom_structure ['opcolor_blue'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 10, 2 ) );
  802. $atom_structure ['balance'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 2 ) );
  803. $atom_structure ['reserved'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 14, 2 ) );
  804. break;
  805. case 'smhd' : // Sound Media information HeaDer atom
  806. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  807. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  808. $atom_structure ['balance'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
  809. $atom_structure ['reserved'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 2 ) );
  810. break;
  811. case 'vmhd' : // Video Media information HeaDer atom
  812. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  813. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) );
  814. $atom_structure ['graphics_mode'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) );
  815. $atom_structure ['opcolor_red'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 2 ) );
  816. $atom_structure ['opcolor_green'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 2 ) );
  817. $atom_structure ['opcolor_blue'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 10, 2 ) );
  818. $atom_structure ['flags'] ['no_lean_ahead'] = ( bool ) ($atom_structure ['flags_raw'] & 0x001);
  819. break;
  820. case 'hdlr' : // HanDLeR reference atom
  821. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  822. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  823. $atom_structure ['component_type'] = substr ( $atom_data, 4, 4 );
  824. $atom_structure ['component_subtype'] = substr ( $atom_data, 8, 4 );
  825. $atom_structure ['component_manufacturer'] = substr ( $atom_data, 12, 4 );
  826. $atom_structure ['component_flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 16, 4 ) );
  827. $atom_structure ['component_flags_mask'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 20, 4 ) );
  828. $atom_structure ['component_name'] = $this->Pascal2String ( substr ( $atom_data, 24 ) );
  829. if (($atom_structure ['component_subtype'] == 'STpn') && ($atom_structure ['component_manufacturer'] == 'zzzz')) {
  830. $info ['video'] ['dataformat'] = 'quicktimevr';
  831. }
  832. break;
  833. case 'mdhd' : // MeDia HeaDer atom
  834. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  835. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  836. $atom_structure ['creation_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  837. $atom_structure ['modify_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
  838. $atom_structure ['time_scale'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 4 ) );
  839. $atom_structure ['duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 16, 4 ) );
  840. $atom_structure ['language_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 20, 2 ) );
  841. $atom_structure ['quality'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 22, 2 ) );
  842. if ($atom_structure ['time_scale'] == 0) {
  843. $info ['error'] [] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
  844. return false;
  845. }
  846. $info ['quicktime'] ['time_scale'] = (isset ( $info ['quicktime'] ['time_scale'] ) ? max ( $info ['quicktime'] ['time_scale'], $atom_structure ['time_scale'] ) : $atom_structure ['time_scale']);
  847. $atom_structure ['creation_time_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['creation_time'] );
  848. $atom_structure ['modify_time_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['modify_time'] );
  849. $atom_structure ['playtime_seconds'] = $atom_structure ['duration'] / $atom_structure ['time_scale'];
  850. $atom_structure ['language'] = $this->QuicktimeLanguageLookup ( $atom_structure ['language_id'] );
  851. if (empty ( $info ['comments'] ['language'] ) || (! in_array ( $atom_structure ['language'], $info ['comments'] ['language'] ))) {
  852. $info ['comments'] ['language'] [] = $atom_structure ['language'];
  853. }
  854. break;
  855. case 'pnot' : // Preview atom
  856. $atom_structure ['modification_date'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 4 ) ); // "standard Macintosh format"
  857. $atom_structure ['version_number'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) ); // hardcoded: 0x00
  858. $atom_structure ['atom_type'] = substr ( $atom_data, 6, 4 ); // usually: 'PICT'
  859. $atom_structure ['atom_index'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 10, 2 ) ); // usually: 0x01
  860. $atom_structure ['modification_date_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['modification_date'] );
  861. break;
  862. case 'crgn' : // Clipping ReGioN atom
  863. $atom_structure ['region_size'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 2 ) ); // The Region size, Region boundary box,
  864. $atom_structure ['boundary_box'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 2, 8 ) ); // and Clipping region data fields
  865. $atom_structure ['clipping_data'] = substr ( $atom_data, 10 ); // constitute a QuickDraw region.
  866. break;
  867. case 'load' : // track LOAD settings atom
  868. $atom_structure ['preload_start_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 4 ) );
  869. $atom_structure ['preload_duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  870. $atom_structure ['preload_flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
  871. $atom_structure ['default_hints_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 4 ) );
  872. $atom_structure ['default_hints'] ['double_buffer'] = ( bool ) ($atom_structure ['default_hints_raw'] & 0x0020);
  873. $atom_structure ['default_hints'] ['high_quality'] = ( bool ) ($atom_structure ['default_hints_raw'] & 0x0100);
  874. break;
  875. case 'tmcd' : // TiMe CoDe atom
  876. case 'chap' : // CHAPter list atom
  877. case 'sync' : // SYNChronization atom
  878. case 'scpt' : // tranSCriPT atom
  879. case 'ssrc' : // non-primary SouRCe atom
  880. for($i = 0; $i < (strlen ( $atom_data ) % 4); $i ++) {
  881. $atom_structure ['track_id'] [$i] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $i * 4, 4 ) );
  882. }
  883. break;
  884. case 'elst' : // Edit LiST atom
  885. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  886. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  887. $atom_structure ['number_entries'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  888. for($i = 0; $i < $atom_structure ['number_entries']; $i ++) {
  889. $atom_structure ['edit_list'] [$i] ['track_duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8 + ($i * 12) + 0, 4 ) );
  890. $atom_structure ['edit_list'] [$i] ['media_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8 + ($i * 12) + 4, 4 ) );
  891. $atom_structure ['edit_list'] [$i] ['media_rate'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 8 + ($i * 12) + 8, 4 ) );
  892. }
  893. break;
  894. case 'kmat' : // compressed MATte atom
  895. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  896. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) ); // hardcoded: 0x0000
  897. $atom_structure ['matte_data_raw'] = substr ( $atom_data, 4 );
  898. break;
  899. case 'ctab' : // Color TABle atom
  900. $atom_structure ['color_table_seed'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 4 ) ); // hardcoded: 0x00000000
  901. $atom_structure ['color_table_flags'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 2 ) ); // hardcoded: 0x8000
  902. $atom_structure ['color_table_size'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 6, 2 ) ) + 1;
  903. for($colortableentry = 0; $colortableentry < $atom_structure ['color_table_size']; $colortableentry ++) {
  904. $atom_structure ['color_table'] [$colortableentry] ['alpha'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8 + ($colortableentry * 8) + 0, 2 ) );
  905. $atom_structure ['color_table'] [$colortableentry] ['red'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8 + ($colortableentry * 8) + 2, 2 ) );
  906. $atom_structure ['color_table'] [$colortableentry] ['green'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8 + ($colortableentry * 8) + 4, 2 ) );
  907. $atom_structure ['color_table'] [$colortableentry] ['blue'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8 + ($colortableentry * 8) + 6, 2 ) );
  908. }
  909. break;
  910. case 'mvhd' : // MoVie HeaDer atom
  911. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  912. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) );
  913. $atom_structure ['creation_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  914. $atom_structure ['modify_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
  915. $atom_structure ['time_scale'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 4 ) );
  916. $atom_structure ['duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 16, 4 ) );
  917. $atom_structure ['preferred_rate'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 20, 4 ) );
  918. $atom_structure ['preferred_volume'] = getid3_lib::FixedPoint8_8 ( substr ( $atom_data, 24, 2 ) );
  919. $atom_structure ['reserved'] = substr ( $atom_data, 26, 10 );
  920. $atom_structure ['matrix_a'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 36, 4 ) );
  921. $atom_structure ['matrix_b'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 40, 4 ) );
  922. $atom_structure ['matrix_u'] = getid3_lib::FixedPoint2_30 ( substr ( $atom_data, 44, 4 ) );
  923. $atom_structure ['matrix_c'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 48, 4 ) );
  924. $atom_structure ['matrix_d'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 52, 4 ) );
  925. $atom_structure ['matrix_v'] = getid3_lib::FixedPoint2_30 ( substr ( $atom_data, 56, 4 ) );
  926. $atom_structure ['matrix_x'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 60, 4 ) );
  927. $atom_structure ['matrix_y'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 64, 4 ) );
  928. $atom_structure ['matrix_w'] = getid3_lib::FixedPoint2_30 ( substr ( $atom_data, 68, 4 ) );
  929. $atom_structure ['preview_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 72, 4 ) );
  930. $atom_structure ['preview_duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 76, 4 ) );
  931. $atom_structure ['poster_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 80, 4 ) );
  932. $atom_structure ['selection_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 84, 4 ) );
  933. $atom_structure ['selection_duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 88, 4 ) );
  934. $atom_structure ['current_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 92, 4 ) );
  935. $atom_structure ['next_track_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 96, 4 ) );
  936. if ($atom_structure ['time_scale'] == 0) {
  937. $info ['error'] [] = 'Corrupt Quicktime file: mvhd.time_scale == zero';
  938. return false;
  939. }
  940. $atom_structure ['creation_time_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['creation_time'] );
  941. $atom_structure ['modify_time_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['modify_time'] );
  942. $info ['quicktime'] ['time_scale'] = (isset ( $info ['quicktime'] ['time_scale'] ) ? max ( $info ['quicktime'] ['time_scale'], $atom_structure ['time_scale'] ) : $atom_structure ['time_scale']);
  943. $info ['quicktime'] ['display_scale'] = $atom_structure ['matrix_a'];
  944. $info ['playtime_seconds'] = $atom_structure ['duration'] / $atom_structure ['time_scale'];
  945. break;
  946. case 'tkhd' : // TracK HeaDer atom
  947. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  948. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) );
  949. $atom_structure ['creation_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  950. $atom_structure ['modify_time'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 8, 4 ) );
  951. $atom_structure ['trackid'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 12, 4 ) );
  952. $atom_structure ['reserved1'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 16, 4 ) );
  953. $atom_structure ['duration'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 20, 4 ) );
  954. $atom_structure ['reserved2'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 24, 8 ) );
  955. $atom_structure ['layer'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 32, 2 ) );
  956. $atom_structure ['alternate_group'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 34, 2 ) );
  957. $atom_structure ['volume'] = getid3_lib::FixedPoint8_8 ( substr ( $atom_data, 36, 2 ) );
  958. $atom_structure ['reserved3'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 38, 2 ) );
  959. $atom_structure ['matrix_a'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 40, 4 ) );
  960. $atom_structure ['matrix_b'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 44, 4 ) );
  961. $atom_structure ['matrix_u'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 48, 4 ) );
  962. $atom_structure ['matrix_c'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 52, 4 ) );
  963. $atom_structure ['matrix_d'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 56, 4 ) );
  964. $atom_structure ['matrix_v'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 60, 4 ) );
  965. $atom_structure ['matrix_x'] = getid3_lib::FixedPoint2_30 ( substr ( $atom_data, 64, 4 ) );
  966. $atom_structure ['matrix_y'] = getid3_lib::FixedPoint2_30 ( substr ( $atom_data, 68, 4 ) );
  967. $atom_structure ['matrix_w'] = getid3_lib::FixedPoint2_30 ( substr ( $atom_data, 72, 4 ) );
  968. $atom_structure ['width'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 76, 4 ) );
  969. $atom_structure ['height'] = getid3_lib::FixedPoint16_16 ( substr ( $atom_data, 80, 4 ) );
  970. $atom_structure ['flags'] ['enabled'] = ( bool ) ($atom_structure ['flags_raw'] & 0x0001);
  971. $atom_structure ['flags'] ['in_movie'] = ( bool ) ($atom_structure ['flags_raw'] & 0x0002);
  972. $atom_structure ['flags'] ['in_preview'] = ( bool ) ($atom_structure ['flags_raw'] & 0x0004);
  973. $atom_structure ['flags'] ['in_poster'] = ( bool ) ($atom_structure ['flags_raw'] & 0x0008);
  974. $atom_structure ['creation_time_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['creation_time'] );
  975. $atom_structure ['modify_time_unix'] = getid3_lib::DateMac2Unix ( $atom_structure ['modify_time'] );
  976. if ($atom_structure ['flags'] ['enabled'] == 1) {
  977. if (! isset ( $info ['video'] ['resolution_x'] ) || ! isset ( $info ['video'] ['resolution_y'] )) {
  978. $info ['video'] ['resolution_x'] = $atom_structure ['width'];
  979. $info ['video'] ['resolution_y'] = $atom_structure ['height'];
  980. }
  981. $info ['video'] ['resolution_x'] = max ( $info ['video'] ['resolution_x'], $atom_structure ['width'] );
  982. $info ['video'] ['resolution_y'] = max ( $info ['video'] ['resolution_y'], $atom_structure ['height'] );
  983. $info ['quicktime'] ['video'] ['resolution_x'] = $info ['video'] ['resolution_x'];
  984. $info ['quicktime'] ['video'] ['resolution_y'] = $info ['video'] ['resolution_y'];
  985. } else {
  986. if (isset ( $info ['video'] ['resolution_x'] )) {
  987. unset ( $info ['video'] ['resolution_x'] );
  988. }
  989. if (isset ( $info ['video'] ['resolution_y'] )) {
  990. unset ( $info ['video'] ['resolution_y'] );
  991. }
  992. if (isset ( $info ['quicktime'] ['video'] )) {
  993. unset ( $info ['quicktime'] ['video'] );
  994. }
  995. }
  996. break;
  997. case 'iods' : // Initial Object DeScriptor atom
  998. // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
  999. // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
  1000. $offset = 0;
  1001. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 1 ) );
  1002. $offset += 1;
  1003. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 3 ) );
  1004. $offset += 3;
  1005. $atom_structure ['mp4_iod_tag'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 1 ) );
  1006. $offset += 1;
  1007. $atom_structure ['length'] = $this->quicktime_read_mp4_descr_length ( $atom_data, $offset );
  1008. //$offset already adjusted by quicktime_read_mp4_descr_length()
  1009. $atom_structure ['object_descriptor_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 2 ) );
  1010. $offset += 2;
  1011. $atom_structure ['od_profile_level'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 1 ) );
  1012. $offset += 1;
  1013. $atom_structure ['scene_profile_level'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 1 ) );
  1014. $offset += 1;
  1015. $atom_structure ['audio_profile_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 1 ) );
  1016. $offset += 1;
  1017. $atom_structure ['video_profile_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 1 ) );
  1018. $offset += 1;
  1019. $atom_structure ['graphics_profile_level'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 1 ) );
  1020. $offset += 1;
  1021. $atom_structure ['num_iods_tracks'] = ($atom_structure ['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields
  1022. for($i = 0; $i < $atom_structure ['num_iods_tracks']; $i ++) {
  1023. $atom_structure ['track'] [$i] ['ES_ID_IncTag'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 1 ) );
  1024. $offset += 1;
  1025. $atom_structure ['track'] [$i] ['length'] = $this->quicktime_read_mp4_descr_length ( $atom_data, $offset );
  1026. //$offset already adjusted by quicktime_read_mp4_descr_length()
  1027. $atom_structure ['track'] [$i] ['track_id'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 4 ) );
  1028. $offset += 4;
  1029. }
  1030. $atom_structure ['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName ( $atom_structure ['audio_profile_id'] );
  1031. $atom_structure ['video_profile_name'] = $this->QuicktimeIODSvideoProfileName ( $atom_structure ['video_profile_id'] );
  1032. break;
  1033. case 'ftyp' : // FileTYPe (?) atom (for MP4 it seems)
  1034. $atom_structure ['signature'] = substr ( $atom_data, 0, 4 );
  1035. $atom_structure ['unknown_1'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4, 4 ) );
  1036. $atom_structure ['fourcc'] = substr ( $atom_data, 8, 4 );
  1037. break;
  1038. case 'mdat' : // Media DATa atom
  1039. case 'free' : // FREE space atom
  1040. case 'skip' : // SKIP atom
  1041. case 'wide' : // 64-bit expansion placeholder atom
  1042. // 'mdat' data is too big to deal with, contains no useful metadata
  1043. // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
  1044. // When writing QuickTime files, it is sometimes necessary to update an atom's size.
  1045. // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
  1046. // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
  1047. // puts an 8-byte placeholder atom before any atoms it may have to update the size of.
  1048. // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
  1049. // placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
  1050. // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
  1051. break;
  1052. case 'nsav' : // NoSAVe atom
  1053. // http://developer.apple.com/technotes/tn/tn2038.html
  1054. $atom_structure ['data'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 4 ) );
  1055. break;
  1056. case 'ctyp' : // Controller TYPe atom (seen on QTVR)
  1057. // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
  1058. // some controller names are:
  1059. // 0x00 + 'std' for linear movie
  1060. // 'none' for no controls
  1061. $atom_structure ['ctyp'] = substr ( $atom_data, 0, 4 );
  1062. $info ['quicktime'] ['controller'] = $atom_structure ['ctyp'];
  1063. switch ($atom_structure ['ctyp']) {
  1064. case 'qtvr' :
  1065. $info ['video'] ['dataformat'] = 'quicktimevr';
  1066. break;
  1067. }
  1068. break;
  1069. case 'pano' : // PANOrama track (seen on QTVR)
  1070. $atom_structure ['pano'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 4 ) );
  1071. break;
  1072. case 'hint' : // HINT track
  1073. case 'hinf' : //
  1074. case 'hinv' : //
  1075. case 'hnti' : //
  1076. $info ['quicktime'] ['hinting'] = true;
  1077. break;
  1078. case 'imgt' : // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
  1079. for($i = 0; $i < ($atom_structure ['size'] - 8); $i += 4) {
  1080. $atom_structure ['imgt'] [] = getid3_lib::BigEndian2Int ( substr ( $atom_data, $i, 4 ) );
  1081. }
  1082. break;
  1083. // Observed-but-not-handled atom types are just listed here to prevent warnings being generated
  1084. case 'FXTC' : // Something to do with Adobe After Effects (?)
  1085. case 'PrmA' :
  1086. case 'code' :
  1087. case 'FIEL' : // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
  1088. case 'tapt' : // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
  1089. // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838]
  1090. // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
  1091. // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
  1092. case 'ctts' : // STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
  1093. case 'cslg' : // STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
  1094. case 'sdtp' : // STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
  1095. case 'stps' : // STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
  1096. //$atom_structure['data'] = $atom_data;
  1097. break;
  1098. case '©xyz' : // GPS latitude+longitude+altitude
  1099. $atom_structure ['data'] = $atom_data;
  1100. if (preg_match ( '#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches )) {
  1101. @list ( $all, $latitude, $longitude, $altitude ) = $matches;
  1102. $info ['quicktime'] ['comments'] ['gps_latitude'] [] = floatval ( $latitude );
  1103. $info ['quicktime'] ['comments'] ['gps_longitude'] [] = floatval ( $longitude );
  1104. if (! empty ( $altitude )) {
  1105. $info ['quicktime'] ['comments'] ['gps_altitude'] [] = floatval ( $altitude );
  1106. }
  1107. } else {
  1108. $info ['warning'] [] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset ' . $baseoffset . '. Please report as getID3() bug.';
  1109. }
  1110. break;
  1111. case 'NCDT' :
  1112. // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
  1113. // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
  1114. $atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( $atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms );
  1115. break;
  1116. case 'NCTH' : // Nikon Camera THumbnail image
  1117. case 'NCVW' : // Nikon Camera preVieW image
  1118. // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
  1119. if (preg_match ( '/^\xFF\xD8\xFF/', $atom_data )) {
  1120. $atom_structure ['data'] = $atom_data;
  1121. $atom_structure ['image_mime'] = 'image/jpeg';
  1122. $atom_structure ['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
  1123. $info ['quicktime'] ['comments'] ['picture'] [] = array (
  1124. 'image_mime' => $atom_structure ['image_mime'],
  1125. 'data' => $atom_data,
  1126. 'description' => $atom_structure ['description'] );
  1127. }
  1128. break;
  1129. case 'NCHD' : // MakerNoteVersion
  1130. // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
  1131. $atom_structure ['data'] = $atom_data;
  1132. break;
  1133. case 'NCTG' : // NikonTags
  1134. // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
  1135. $atom_structure ['data'] = $this->QuicktimeParseNikonNCTG ( $atom_data );
  1136. break;
  1137. case 'NCDB' : // NikonTags
  1138. // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
  1139. $atom_structure ['data'] = $atom_data;
  1140. break;
  1141. case "\x00\x00\x00\x00" :
  1142. case 'meta' : // METAdata atom
  1143. // some kind of metacontainer, may contain a big data dump such as:
  1144. // mdta keys  mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst   data DEApple 0  (data DE2011-05-11T17:54:04+0200 2  *data DE+52.4936+013.3897+040.247/   data DE4.3.1  data DEiPhone 4
  1145. // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
  1146. $atom_structure ['version'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 0, 1 ) );
  1147. $atom_structure ['flags_raw'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 1, 3 ) );
  1148. $atom_structure ['subatoms'] = $this->QuicktimeParseContainerAtom ( substr ( $atom_data, 4 ), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms );
  1149. //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
  1150. break;
  1151. case 'data' : // metaDATA atom
  1152. // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
  1153. $atom_structure ['language'] = substr ( $atom_data, 4 + 0, 2 );
  1154. $atom_structure ['unknown'] = getid3_lib::BigEndian2Int ( substr ( $atom_data, 4 + 2, 2 ) );
  1155. $atom_structure ['data'] = substr ( $atom_data, 4 + 4 );
  1156. break;
  1157. default :
  1158. $info ['warning'] [] = 'Unknown QuickTime atom type: "' . getid3_lib::PrintHexBytes ( $atomname ) . '" at offset ' . $baseoffset;
  1159. $atom_structure ['data'] = $atom_data;
  1160. break;
  1161. }
  1162. array_pop ( $atomHierarchy );
  1163. return $atom_structure;
  1164. }
  1165. function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
  1166. //echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'<br><br>';
  1167. $atom_structure = false;
  1168. $subatomoffset = 0;
  1169. $subatomcounter = 0;
  1170. if ((strlen ( $atom_data ) == 4) && (getid3_lib::BigEndian2Int ( $atom_data ) == 0x00000000)) {
  1171. return false;
  1172. }
  1173. while ( $subatomoffset < strlen ( $atom_data ) ) {
  1174. $subatomsize = getid3_lib::BigEndian2Int ( substr ( $atom_data, $subatomoffset + 0, 4 ) );
  1175. $subatomname = substr ( $atom_data, $subatomoffset + 4, 4 );
  1176. $subatomdata = substr ( $atom_data, $subatomoffset + 8, $subatomsize - 8 );
  1177. if ($subatomsize == 0) {
  1178. // Furthermore, for historical reasons the list of atoms is optionally
  1179. // terminated by a 32-bit integer set to 0. If you are writing a program
  1180. // to read user data atoms, you should allow for the terminating 0.
  1181. return $atom_structure;
  1182. }
  1183. $atom_structure [$subatomcounter] = $this->QuicktimeParseAtom ( $subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms );
  1184. $subatomoffset += $subatomsize;
  1185. $subatomcounter ++;
  1186. }
  1187. return $atom_structure;
  1188. }
  1189. function quicktime_read_mp4_descr_length($data, &$offset) {
  1190. // http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
  1191. $num_bytes = 0;
  1192. $length = 0;
  1193. do {
  1194. $b = ord ( substr ( $data, $offset ++, 1 ) );
  1195. $length = ($length << 7) | ($b & 0x7F);
  1196. } while ( ($b & 0x80) && ($num_bytes ++ < 4) );
  1197. return $length;
  1198. }
  1199. function QuicktimeLanguageLookup($languageid) {
  1200. static $QuicktimeLanguageLookup = array ();
  1201. if (empty ( $QuicktimeLanguageLookup )) {
  1202. $QuicktimeLanguageLookup [0] = 'English';
  1203. $QuicktimeLanguageLookup [1] = 'French';
  1204. $QuicktimeLanguageLookup [2] = 'German';
  1205. $QuicktimeLanguageLookup [3] = 'Italian';
  1206. $QuicktimeLanguageLookup [4] = 'Dutch';
  1207. $QuicktimeLanguageLookup [5] = 'Swedish';
  1208. $QuicktimeLanguageLookup [6] = 'Spanish';
  1209. $QuicktimeLanguageLookup [7] = 'Danish';
  1210. $QuicktimeLanguageLookup [8] = 'Portuguese';
  1211. $QuicktimeLanguageLookup [9] = 'Norwegian';
  1212. $QuicktimeLanguageLookup [10] = 'Hebrew';
  1213. $QuicktimeLanguageLookup [11] = 'Japanese';
  1214. $QuicktimeLanguageLookup [12] = 'Arabic';
  1215. $QuicktimeLanguageLookup [13] = 'Finnish';
  1216. $QuicktimeLanguageLookup [14] = 'Greek';
  1217. $QuicktimeLanguageLookup [15] = 'Icelandic';
  1218. $QuicktimeLanguageLookup [16] = 'Maltese';
  1219. $QuicktimeLanguageLookup [17] = 'Turkish';
  1220. $QuicktimeLanguageLookup [18] = 'Croatian';
  1221. $QuicktimeLanguageLookup [19] = 'Chinese (Traditional)';
  1222. $QuicktimeLanguageLookup [20] = 'Urdu';
  1223. $QuicktimeLanguageLookup [21] = 'Hindi';
  1224. $QuicktimeLanguageLookup [22] = 'Thai';
  1225. $QuicktimeLanguageLookup [23] = 'Korean';
  1226. $QuicktimeLanguageLookup [24] = 'Lithuanian';
  1227. $QuicktimeLanguageLookup [25] = 'Polish';
  1228. $QuicktimeLanguageLookup [26] = 'Hungarian';
  1229. $QuicktimeLanguageLookup [27] = 'Estonian';
  1230. $QuicktimeLanguageLookup [28] = 'Lettish';
  1231. $QuicktimeLanguageLookup [28] = 'Latvian';
  1232. $QuicktimeLanguageLookup [29] = 'Saamisk';
  1233. $QuicktimeLanguageLookup [29] = 'Lappish';
  1234. $QuicktimeLanguageLookup [30] = 'Faeroese';
  1235. $QuicktimeLanguageLookup [31] = 'Farsi';
  1236. $QuicktimeLanguageLookup [31] = 'Persian';
  1237. $QuicktimeLanguageLookup [32] = 'Russian';
  1238. $QuicktimeLanguageLookup [33] = 'Chinese (Simplified)';
  1239. $QuicktimeLanguageLookup [34] = 'Flemish';
  1240. $QuicktimeLanguageLookup [35] = 'Irish';
  1241. $QuicktimeLanguageLookup [36] = 'Albanian';
  1242. $QuicktimeLanguageLookup [37] = 'Romanian';
  1243. $QuicktimeLanguageLookup [38] = 'Czech';
  1244. $QuicktimeLanguageLookup [39] = 'Slovak';
  1245. $QuicktimeLanguageLookup [40] = 'Slovenian';
  1246. $QuicktimeLanguageLookup [41] = 'Yiddish';
  1247. $QuicktimeLanguageLookup [42] = 'Serbian';
  1248. $QuicktimeLanguageLookup [43] = 'Macedonian';
  1249. $QuicktimeLanguageLookup [44] = 'Bulgarian';
  1250. $QuicktimeLanguageLookup [45] = 'Ukrainian';
  1251. $QuicktimeLanguageLookup [46] = 'Byelorussian';
  1252. $QuicktimeLanguageLookup [47] = 'Uzbek';
  1253. $QuicktimeLanguageLookup [48] = 'Kazakh';
  1254. $QuicktimeLanguageLookup [49] = 'Azerbaijani';
  1255. $QuicktimeLanguageLookup [50] = 'AzerbaijanAr';
  1256. $QuicktimeLanguageLookup [51] = 'Armenian';
  1257. $QuicktimeLanguageLookup [52] = 'Georgian';
  1258. $QuicktimeLanguageLookup [53] = 'Moldavian';
  1259. $QuicktimeLanguageLookup [54] = 'Kirghiz';
  1260. $QuicktimeLanguageLookup [55] = 'Tajiki';
  1261. $QuicktimeLanguageLookup [56] = 'Turkmen';
  1262. $QuicktimeLanguageLookup [57] = 'Mongolian';
  1263. $QuicktimeLanguageLookup [58] = 'MongolianCyr';
  1264. $QuicktimeLanguageLookup [59] = 'Pashto';
  1265. $QuicktimeLanguageLookup [60] = 'Kurdish';
  1266. $QuicktimeLanguageLookup [61] = 'Kashmiri';
  1267. $QuicktimeLanguageLookup [62] = 'Sindhi';
  1268. $QuicktimeLanguageLookup [63] = 'Tibetan';
  1269. $QuicktimeLanguageLookup [64] = 'Nepali';
  1270. $QuicktimeLanguageLookup [65] = 'Sanskrit';
  1271. $QuicktimeLanguageLookup [66] = 'Marathi';
  1272. $QuicktimeLanguageLookup [67] = 'Bengali';
  1273. $QuicktimeLanguageLookup [68] = 'Assamese';
  1274. $QuicktimeLanguageLookup [69] = 'Gujarati';
  1275. $QuicktimeLanguageLookup [70] = 'Punjabi';
  1276. $QuicktimeLanguageLookup [71] = 'Oriya';
  1277. $QuicktimeLanguageLookup [72] = 'Malayalam';
  1278. $QuicktimeLanguageLookup [73] = 'Kannada';
  1279. $QuicktimeLanguageLookup [74] = 'Tamil';
  1280. $QuicktimeLanguageLookup [75] = 'Telugu';
  1281. $QuicktimeLanguageLookup [76] = 'Sinhalese';
  1282. $QuicktimeLanguageLookup [77] = 'Burmese';
  1283. $QuicktimeLanguageLookup [78] = 'Khmer';
  1284. $QuicktimeLanguageLookup [79] = 'Lao';
  1285. $QuicktimeLanguageLookup [80] = 'Vietnamese';
  1286. $QuicktimeLanguageLookup [81] = 'Indonesian';
  1287. $QuicktimeLanguageLookup [82] = 'Tagalog';
  1288. $QuicktimeLanguageLookup [83] = 'MalayRoman';
  1289. $QuicktimeLanguageLookup [84] = 'MalayArabic';
  1290. $QuicktimeLanguageLookup [85] = 'Amharic';
  1291. $QuicktimeLanguageLookup [86] = 'Tigrinya';
  1292. $QuicktimeLanguageLookup [87] = 'Galla';
  1293. $QuicktimeLanguageLookup [87] = 'Oromo';
  1294. $QuicktimeLanguageLookup [88] = 'Somali';
  1295. $QuicktimeLanguageLookup [89] = 'Swahili';
  1296. $QuicktimeLanguageLookup [90] = 'Ruanda';
  1297. $QuicktimeLanguageLookup [91] = 'Rundi';
  1298. $QuicktimeLanguageLookup [92] = 'Chewa';
  1299. $QuicktimeLanguageLookup [93] = 'Malagasy';
  1300. $QuicktimeLanguageLookup [94] = 'Esperanto';
  1301. $QuicktimeLanguageLookup [128] = 'Welsh';
  1302. $QuicktimeLanguageLookup [129] = 'Basque';
  1303. $QuicktimeLanguageLookup [130] = 'Catalan';
  1304. $QuicktimeLanguageLookup [131] = 'Latin';
  1305. $QuicktimeLanguageLookup [132] = 'Quechua';
  1306. $QuicktimeLanguageLookup [133] = 'Guarani';
  1307. $QuicktimeLanguageLookup [134] = 'Aymara';
  1308. $QuicktimeLanguageLookup [135] = 'Tatar';
  1309. $QuicktimeLanguageLookup [136] = 'Uighur';
  1310. $QuicktimeLanguageLookup [137] = 'Dzongkha';
  1311. $QuicktimeLanguageLookup [138] = 'JavaneseRom';
  1312. }
  1313. return (isset ( $QuicktimeLanguageLookup [$languageid] ) ? $QuicktimeLanguageLookup [$languageid] : 'invalid');
  1314. }
  1315. function QuicktimeVideoCodecLookup($codecid) {
  1316. static $QuicktimeVideoCodecLookup = array ();
  1317. if (empty ( $QuicktimeVideoCodecLookup )) {
  1318. $QuicktimeVideoCodecLookup ['.SGI'] = 'SGI';
  1319. $QuicktimeVideoCodecLookup ['3IV1'] = '3ivx MPEG-4 v1';
  1320. $QuicktimeVideoCodecLookup ['3IV2'] = '3ivx MPEG-4 v2';
  1321. $QuicktimeVideoCodecLookup ['3IVX'] = '3ivx MPEG-4';
  1322. $QuicktimeVideoCodecLookup ['8BPS'] = 'Planar RGB';
  1323. $QuicktimeVideoCodecLookup ['avc1'] = 'H.264/MPEG-4 AVC';
  1324. $QuicktimeVideoCodecLookup ['avr '] = 'AVR-JPEG';
  1325. $QuicktimeVideoCodecLookup ['b16g'] = '16Gray';
  1326. $QuicktimeVideoCodecLookup ['b32a'] = '32AlphaGray';
  1327. $QuicktimeVideoCodecLookup ['b48r'] = '48RGB';
  1328. $QuicktimeVideoCodecLookup ['b64a'] = '64ARGB';
  1329. $QuicktimeVideoCodecLookup ['base'] = 'Base';
  1330. $QuicktimeVideoCodecLookup ['clou'] = 'Cloud';
  1331. $QuicktimeVideoCodecLookup ['cmyk'] = 'CMYK';
  1332. $QuicktimeVideoCodecLookup ['cvid'] = 'Cinepak';
  1333. $QuicktimeVideoCodecLookup ['dmb1'] = 'OpenDML JPEG';
  1334. $QuicktimeVideoCodecLookup ['dvc '] = 'DVC-NTSC';
  1335. $QuicktimeVideoCodecLookup ['dvcp'] = 'DVC-PAL';
  1336. $QuicktimeVideoCodecLookup ['dvpn'] = 'DVCPro-NTSC';
  1337. $QuicktimeVideoCodecLookup ['dvpp'] = 'DVCPro-PAL';
  1338. $QuicktimeVideoCodecLookup ['fire'] = 'Fire';
  1339. $QuicktimeVideoCodecLookup ['flic'] = 'FLC';
  1340. $QuicktimeVideoCodecLookup ['gif '] = 'GIF';
  1341. $QuicktimeVideoCodecLookup ['h261'] = 'H261';
  1342. $QuicktimeVideoCodecLookup ['h263'] = 'H263';
  1343. $QuicktimeVideoCodecLookup ['IV41'] = 'Indeo4';
  1344. $QuicktimeVideoCodecLookup ['jpeg'] = 'JPEG';
  1345. $QuicktimeVideoCodecLookup ['kpcd'] = 'PhotoCD';
  1346. $QuicktimeVideoCodecLookup ['mjpa'] = 'Motion JPEG-A';
  1347. $QuicktimeVideoCodecLookup ['mjpb'] = 'Motion JPEG-B';
  1348. $QuicktimeVideoCodecLookup ['msvc'] = 'Microsoft Video1';
  1349. $QuicktimeVideoCodecLookup ['myuv'] = 'MPEG YUV420';
  1350. $QuicktimeVideoCodecLookup ['path'] = 'Vector';
  1351. $QuicktimeVideoCodecLookup ['png '] = 'PNG';
  1352. $QuicktimeVideoCodecLookup ['PNTG'] = 'MacPaint';
  1353. $QuicktimeVideoCodecLookup ['qdgx'] = 'QuickDrawGX';
  1354. $QuicktimeVideoCodecLookup ['qdrw'] = 'QuickDraw';
  1355. $QuicktimeVideoCodecLookup ['raw '] = 'RAW';
  1356. $QuicktimeVideoCodecLookup ['ripl'] = 'WaterRipple';
  1357. $QuicktimeVideoCodecLookup ['rpza'] = 'Video';
  1358. $QuicktimeVideoCodecLookup ['smc '] = 'Graphics';
  1359. $QuicktimeVideoCodecLookup ['SVQ1'] = 'Sorenson Video 1';
  1360. $QuicktimeVideoCodecLookup ['SVQ1'] = 'Sorenson Video 3';
  1361. $QuicktimeVideoCodecLookup ['syv9'] = 'Sorenson YUV9';
  1362. $QuicktimeVideoCodecLookup ['tga '] = 'Targa';
  1363. $QuicktimeVideoCodecLookup ['tiff'] = 'TIFF';
  1364. $QuicktimeVideoCodecLookup ['WRAW'] = 'Windows RAW';
  1365. $QuicktimeVideoCodecLookup ['WRLE'] = 'BMP';
  1366. $QuicktimeVideoCodecLookup ['y420'] = 'YUV420';
  1367. $QuicktimeVideoCodecLookup ['yuv2'] = 'ComponentVideo';
  1368. $QuicktimeVideoCodecLookup ['yuvs'] = 'ComponentVideoUnsigned';
  1369. $QuicktimeVideoCodecLookup ['yuvu'] = 'ComponentVideoSigned';
  1370. }
  1371. return (isset ( $QuicktimeVideoCodecLookup [$codecid] ) ? $QuicktimeVideoCodecLookup [$codecid] : '');
  1372. }
  1373. function QuicktimeAudioCodecLookup($codecid) {
  1374. static $QuicktimeAudioCodecLookup = array ();
  1375. if (empty ( $QuicktimeAudioCodecLookup )) {
  1376. $QuicktimeAudioCodecLookup ['.mp3'] = 'Fraunhofer MPEG Layer-III alias';
  1377. $QuicktimeAudioCodecLookup ['aac '] = 'ISO/IEC 14496-3 AAC';
  1378. $QuicktimeAudioCodecLookup ['agsm'] = 'Apple GSM 10:1';
  1379. $QuicktimeAudioCodecLookup ['alac'] = 'Apple Lossless Audio Codec';
  1380. $QuicktimeAudioCodecLookup ['alaw'] = 'A-law 2:1';
  1381. $QuicktimeAudioCodecLookup ['conv'] = 'Sample Format';
  1382. $QuicktimeAudioCodecLookup ['dvca'] = 'DV';
  1383. $QuicktimeAudioCodecLookup ['dvi '] = 'DV 4:1';
  1384. $QuicktimeAudioCodecLookup ['eqal'] = 'Frequency Equalizer';
  1385. $QuicktimeAudioCodecLookup ['fl32'] = '32-bit Floating Point';
  1386. $QuicktimeAudioCodecLookup ['fl64'] = '64-bit Floating Point';
  1387. $QuicktimeAudioCodecLookup ['ima4'] = 'Interactive Multimedia Association 4:1';
  1388. $QuicktimeAudioCodecLookup ['in24'] = '24-bit Integer';
  1389. $QuicktimeAudioCodecLookup ['in32'] = '32-bit Integer';
  1390. $QuicktimeAudioCodecLookup ['lpc '] = 'LPC 23:1';
  1391. $QuicktimeAudioCodecLookup ['MAC3'] = 'Macintosh Audio Compression/Expansion (MACE) 3:1';
  1392. $QuicktimeAudioCodecLookup ['MAC6'] = 'Macintosh Audio Compression/Expansion (MACE) 6:1';
  1393. $QuicktimeAudioCodecLookup ['mixb'] = '8-bit Mixer';
  1394. $QuicktimeAudioCodecLookup ['mixw'] = '16-bit Mixer';
  1395. $QuicktimeAudioCodecLookup ['mp4a'] = 'ISO/IEC 14496-3 AAC';
  1396. $QuicktimeAudioCodecLookup ['MS' . "\x00\x02"] = 'Microsoft ADPCM';
  1397. $QuicktimeAudioCodecLookup ['MS' . "\x00\x11"] = 'DV IMA';
  1398. $QuicktimeAudioCodecLookup ['MS' . "\x00\x55"] = 'Fraunhofer MPEG Layer III';
  1399. $QuicktimeAudioCodecLookup ['NONE'] = 'No Encoding';
  1400. $QuicktimeAudioCodecLookup ['Qclp'] = 'Qualcomm PureVoice';
  1401. $QuicktimeAudioCodecLookup ['QDM2'] = 'QDesign Music 2';
  1402. $QuicktimeAudioCodecLookup ['QDMC'] = 'QDesign Music 1';
  1403. $QuicktimeAudioCodecLookup ['ratb'] = '8-bit Rate';
  1404. $QuicktimeAudioCodecLookup ['ratw'] = '16-bit Rate';
  1405. $QuicktimeAudioCodecLookup ['raw '] = 'raw PCM';
  1406. $QuicktimeAudioCodecLookup ['sour'] = 'Sound Source';
  1407. $QuicktimeAudioCodecLookup ['sowt'] = 'signed/two\'s complement (Little Endian)';
  1408. $QuicktimeAudioCodecLookup ['str1'] = 'Iomega MPEG layer II';
  1409. $QuicktimeAudioCodecLookup ['str2'] = 'Iomega MPEG *layer II';
  1410. $QuicktimeAudioCodecLookup ['str3'] = 'Iomega MPEG **layer II';
  1411. $QuicktimeAudioCodecLookup ['str4'] = 'Iomega MPEG ***layer II';
  1412. $QuicktimeAudioCodecLookup ['twos'] = 'signed/two\'s complement (Big Endian)';
  1413. $QuicktimeAudioCodecLookup ['ulaw'] = 'mu-law 2:1';
  1414. }
  1415. return (isset ( $QuicktimeAudioCodecLookup [$codecid] ) ? $QuicktimeAudioCodecLookup [$codecid] : '');
  1416. }
  1417. function QuicktimeDCOMLookup($compressionid) {
  1418. static $QuicktimeDCOMLookup = array ();
  1419. if (empty ( $QuicktimeDCOMLookup )) {
  1420. $QuicktimeDCOMLookup ['zlib'] = 'ZLib Deflate';
  1421. $QuicktimeDCOMLookup ['adec'] = 'Apple Compression';
  1422. }
  1423. return (isset ( $QuicktimeDCOMLookup [$compressionid] ) ? $QuicktimeDCOMLookup [$compressionid] : '');
  1424. }
  1425. function QuicktimeColorNameLookup($colordepthid) {
  1426. static $QuicktimeColorNameLookup = array ();
  1427. if (empty ( $QuicktimeColorNameLookup )) {
  1428. $QuicktimeColorNameLookup [1] = '2-color (monochrome)';
  1429. $QuicktimeColorNameLookup [2] = '4-color';
  1430. $QuicktimeColorNameLookup [4] = '16-color';
  1431. $QuicktimeColorNameLookup [8] = '256-color';
  1432. $QuicktimeColorNameLookup [16] = 'thousands (16-bit color)';
  1433. $QuicktimeColorNameLookup [24] = 'millions (24-bit color)';
  1434. $QuicktimeColorNameLookup [32] = 'millions+ (32-bit color)';
  1435. $QuicktimeColorNameLookup [33] = 'black & white';
  1436. $QuicktimeColorNameLookup [34] = '4-gray';
  1437. $QuicktimeColorNameLookup [36] = '16-gray';
  1438. $QuicktimeColorNameLookup [40] = '256-gray';
  1439. }
  1440. return (isset ( $QuicktimeColorNameLookup [$colordepthid] ) ? $QuicktimeColorNameLookup [$colordepthid] : 'invalid');
  1441. }
  1442. function QuicktimeSTIKLookup($stik) {
  1443. static $QuicktimeSTIKLookup = array ();
  1444. if (empty ( $QuicktimeSTIKLookup )) {
  1445. $QuicktimeSTIKLookup [0] = 'Movie';
  1446. $QuicktimeSTIKLookup [1] = 'Normal';
  1447. $QuicktimeSTIKLookup [2] = 'Audiobook';
  1448. $QuicktimeSTIKLookup [5] = 'Whacked Bookmark';
  1449. $QuicktimeSTIKLookup [6] = 'Music Video';
  1450. $QuicktimeSTIKLookup [9] = 'Short Film';
  1451. $QuicktimeSTIKLookup [10] = 'TV Show';
  1452. $QuicktimeSTIKLookup [11] = 'Booklet';
  1453. $QuicktimeSTIKLookup [14] = 'Ringtone';
  1454. $QuicktimeSTIKLookup [21] = 'Podcast';
  1455. }
  1456. return (isset ( $QuicktimeSTIKLookup [$stik] ) ? $QuicktimeSTIKLookup [$stik] : 'invalid');
  1457. }
  1458. function QuicktimeIODSaudioProfileName($audio_profile_id) {
  1459. static $QuicktimeIODSaudioProfileNameLookup = array ();
  1460. if (empty ( $QuicktimeIODSaudioProfileNameLookup )) {
  1461. $QuicktimeIODSaudioProfileNameLookup = array (
  1462. 0x00 => 'ISO Reserved (0x00)',
  1463. 0x01 => 'Main Audio Profile @ Level 1',
  1464. 0x02 => 'Main Audio Profile @ Level 2',
  1465. 0x03 => 'Main Audio Profile @ Level 3',
  1466. 0x04 => 'Main Audio Profile @ Level 4',
  1467. 0x05 => 'Scalable Audio Profile @ Level 1',
  1468. 0x06 => 'Scalable Audio Profile @ Level 2',
  1469. 0x07 => 'Scalable Audio Profile @ Level 3',
  1470. 0x08 => 'Scalable Audio Profile @ Level 4',
  1471. 0x09 => 'Speech Audio Profile @ Level 1',
  1472. 0x0A => 'Speech Audio Profile @ Level 2',
  1473. 0x0B => 'Synthetic Audio Profile @ Level 1',
  1474. 0x0C => 'Synthetic Audio Profile @ Level 2',
  1475. 0x0D => 'Synthetic Audio Profile @ Level 3',
  1476. 0x0E => 'High Quality Audio Profile @ Level 1',
  1477. 0x0F => 'High Quality Audio Profile @ Level 2',
  1478. 0x10 => 'High Quality Audio Profile @ Level 3',
  1479. 0x11 => 'High Quality Audio Profile @ Level 4',
  1480. 0x12 => 'High Quality Audio Profile @ Level 5',
  1481. 0x13 => 'High Quality Audio Profile @ Level 6',
  1482. 0x14 => 'High Quality Audio Profile @ Level 7',
  1483. 0x15 => 'High Quality Audio Profile @ Level 8',
  1484. 0x16 => 'Low Delay Audio Profile @ Level 1',
  1485. 0x17 => 'Low Delay Audio Profile @ Level 2',
  1486. 0x18 => 'Low Delay Audio Profile @ Level 3',
  1487. 0x19 => 'Low Delay Audio Profile @ Level 4',
  1488. 0x1A => 'Low Delay Audio Profile @ Level 5',
  1489. 0x1B => 'Low Delay Audio Profile @ Level 6',
  1490. 0x1C => 'Low Delay Audio Profile @ Level 7',
  1491. 0x1D => 'Low Delay Audio Profile @ Level 8',
  1492. 0x1E => 'Natural Audio Profile @ Level 1',
  1493. 0x1F => 'Natural Audio Profile @ Level 2',
  1494. 0x20 => 'Natural Audio Profile @ Level 3',
  1495. 0x21 => 'Natural Audio Profile @ Level 4',
  1496. 0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
  1497. 0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
  1498. 0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
  1499. 0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
  1500. 0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
  1501. 0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
  1502. 0x28 => 'AAC Profile @ Level 1',
  1503. 0x29 => 'AAC Profile @ Level 2',
  1504. 0x2A => 'AAC Profile @ Level 4',
  1505. 0x2B => 'AAC Profile @ Level 5',
  1506. 0x2C => 'High Efficiency AAC Profile @ Level 2',
  1507. 0x2D => 'High Efficiency AAC Profile @ Level 3',
  1508. 0x2E => 'High Efficiency AAC Profile @ Level 4',
  1509. 0x2F => 'High Efficiency AAC Profile @ Level 5',
  1510. 0xFE => 'Not part of MPEG-4 audio profiles',
  1511. 0xFF => 'No audio capability required' );
  1512. }
  1513. return (isset ( $QuicktimeIODSaudioProfileNameLookup [$audio_profile_id] ) ? $QuicktimeIODSaudioProfileNameLookup [$audio_profile_id] : 'ISO Reserved / User Private');
  1514. }
  1515. function QuicktimeIODSvideoProfileName($video_profile_id) {
  1516. static $QuicktimeIODSvideoProfileNameLookup = array ();
  1517. if (empty ( $QuicktimeIODSvideoProfileNameLookup )) {
  1518. $QuicktimeIODSvideoProfileNameLookup = array (
  1519. 0x00 => 'Reserved (0x00) Profile',
  1520. 0x01 => 'Simple Profile @ Level 1',
  1521. 0x02 => 'Simple Profile @ Level 2',
  1522. 0x03 => 'Simple Profile @ Level 3',
  1523. 0x08 => 'Simple Profile @ Level 0',
  1524. 0x10 => 'Simple Scalable Profile @ Level 0',
  1525. 0x11 => 'Simple Scalable Profile @ Level 1',
  1526. 0x12 => 'Simple Scalable Profile @ Level 2',
  1527. 0x15 => 'AVC/H264 Profile',
  1528. 0x21 => 'Core Profile @ Level 1',
  1529. 0x22 => 'Core Profile @ Level 2',
  1530. 0x32 => 'Main Profile @ Level 2',
  1531. 0x33 => 'Main Profile @ Level 3',
  1532. 0x34 => 'Main Profile @ Level 4',
  1533. 0x42 => 'N-bit Profile @ Level 2',
  1534. 0x51 => 'Scalable Texture Profile @ Level 1',
  1535. 0x61 => 'Simple Face Animation Profile @ Level 1',
  1536. 0x62 => 'Simple Face Animation Profile @ Level 2',
  1537. 0x63 => 'Simple FBA Profile @ Level 1',
  1538. 0x64 => 'Simple FBA Profile @ Level 2',
  1539. 0x71 => 'Basic Animated Texture Profile @ Level 1',
  1540. 0x72 => 'Basic Animated Texture Profile @ Level 2',
  1541. 0x81 => 'Hybrid Profile @ Level 1',
  1542. 0x82 => 'Hybrid Profile @ Level 2',
  1543. 0x91 => 'Advanced Real Time Simple Profile @ Level 1',
  1544. 0x92 => 'Advanced Real Time Simple Profile @ Level 2',
  1545. 0x93 => 'Advanced Real Time Simple Profile @ Level 3',
  1546. 0x94 => 'Advanced Real Time Simple Profile @ Level 4',
  1547. 0xA1 => 'Core Scalable Profile @ Level1',
  1548. 0xA2 => 'Core Scalable Profile @ Level2',
  1549. 0xA3 => 'Core Scalable Profile @ Level3',
  1550. 0xB1 => 'Advanced Coding Efficiency Profile @ Level 1',
  1551. 0xB2 => 'Advanced Coding Efficiency Profile @ Level 2',
  1552. 0xB3 => 'Advanced Coding Efficiency Profile @ Level 3',
  1553. 0xB4 => 'Advanced Coding Efficiency Profile @ Level 4',
  1554. 0xC1 => 'Advanced Core Profile @ Level 1',
  1555. 0xC2 => 'Advanced Core Profile @ Level 2',
  1556. 0xD1 => 'Advanced Scalable Texture @ Level1',
  1557. 0xD2 => 'Advanced Scalable Texture @ Level2',
  1558. 0xE1 => 'Simple Studio Profile @ Level 1',
  1559. 0xE2 => 'Simple Studio Profile @ Level 2',
  1560. 0xE3 => 'Simple Studio Profile @ Level 3',
  1561. 0xE4 => 'Simple Studio Profile @ Level 4',
  1562. 0xE5 => 'Core Studio Profile @ Level 1',
  1563. 0xE6 => 'Core Studio Profile @ Level 2',
  1564. 0xE7 => 'Core Studio Profile @ Level 3',
  1565. 0xE8 => 'Core Studio Profile @ Level 4',
  1566. 0xF0 => 'Advanced Simple Profile @ Level 0',
  1567. 0xF1 => 'Advanced Simple Profile @ Level 1',
  1568. 0xF2 => 'Advanced Simple Profile @ Level 2',
  1569. 0xF3 => 'Advanced Simple Profile @ Level 3',
  1570. 0xF4 => 'Advanced Simple Profile @ Level 4',
  1571. 0xF5 => 'Advanced Simple Profile @ Level 5',
  1572. 0xF7 => 'Advanced Simple Profile @ Level 3b',
  1573. 0xF8 => 'Fine Granularity Scalable Profile @ Level 0',
  1574. 0xF9 => 'Fine Granularity Scalable Profile @ Level 1',
  1575. 0xFA => 'Fine Granularity Scalable Profile @ Level 2',
  1576. 0xFB => 'Fine Granularity Scalable Profile @ Level 3',
  1577. 0xFC => 'Fine Granularity Scalable Profile @ Level 4',
  1578. 0xFD => 'Fine Granularity Scalable Profile @ Level 5',
  1579. 0xFE => 'Not part of MPEG-4 Visual profiles',
  1580. 0xFF => 'No visual capability required' );
  1581. }
  1582. return (isset ( $QuicktimeIODSvideoProfileNameLookup [$video_profile_id] ) ? $QuicktimeIODSvideoProfileNameLookup [$video_profile_id] : 'ISO Reserved Profile');
  1583. }
  1584. function QuicktimeContentRatingLookup($rtng) {
  1585. static $QuicktimeContentRatingLookup = array ();
  1586. if (empty ( $QuicktimeContentRatingLookup )) {
  1587. $QuicktimeContentRatingLookup [0] = 'None';
  1588. $QuicktimeContentRatingLookup [2] = 'Clean';
  1589. $QuicktimeContentRatingLookup [4] = 'Explicit';
  1590. }
  1591. return (isset ( $QuicktimeContentRatingLookup [$rtng] ) ? $QuicktimeContentRatingLookup [$rtng] : 'invalid');
  1592. }
  1593. function QuicktimeStoreAccountTypeLookup($akid) {
  1594. static $QuicktimeStoreAccountTypeLookup = array ();
  1595. if (empty ( $QuicktimeStoreAccountTypeLookup )) {
  1596. $QuicktimeStoreAccountTypeLookup [0] = 'iTunes';
  1597. $QuicktimeStoreAccountTypeLookup [1] = 'AOL';
  1598. }
  1599. return (isset ( $QuicktimeStoreAccountTypeLookup [$akid] ) ? $QuicktimeStoreAccountTypeLookup [$akid] : 'invalid');
  1600. }
  1601. function QuicktimeStoreFrontCodeLookup($sfid) {
  1602. static $QuicktimeStoreFrontCodeLookup = array ();
  1603. if (empty ( $QuicktimeStoreFrontCodeLookup )) {
  1604. $QuicktimeStoreFrontCodeLookup [143460] = 'Australia';
  1605. $QuicktimeStoreFrontCodeLookup [143445] = 'Austria';
  1606. $QuicktimeStoreFrontCodeLookup [143446] = 'Belgium';
  1607. $QuicktimeStoreFrontCodeLookup [143455] = 'Canada';
  1608. $QuicktimeStoreFrontCodeLookup [143458] = 'Denmark';
  1609. $QuicktimeStoreFrontCodeLookup [143447] = 'Finland';
  1610. $QuicktimeStoreFrontCodeLookup [143442] = 'France';
  1611. $QuicktimeStoreFrontCodeLookup [143443] = 'Germany';
  1612. $QuicktimeStoreFrontCodeLookup [143448] = 'Greece';
  1613. $QuicktimeStoreFrontCodeLookup [143449] = 'Ireland';
  1614. $QuicktimeStoreFrontCodeLookup [143450] = 'Italy';
  1615. $QuicktimeStoreFrontCodeLookup [143462] = 'Japan';
  1616. $QuicktimeStoreFrontCodeLookup [143451] = 'Luxembourg';
  1617. $QuicktimeStoreFrontCodeLookup [143452] = 'Netherlands';
  1618. $QuicktimeStoreFrontCodeLookup [143461] = 'New Zealand';
  1619. $QuicktimeStoreFrontCodeLookup [143457] = 'Norway';
  1620. $QuicktimeStoreFrontCodeLookup [143453] = 'Portugal';
  1621. $QuicktimeStoreFrontCodeLookup [143454] = 'Spain';
  1622. $QuicktimeStoreFrontCodeLookup [143456] = 'Sweden';
  1623. $QuicktimeStoreFrontCodeLookup [143459] = 'Switzerland';
  1624. $QuicktimeStoreFrontCodeLookup [143444] = 'United Kingdom';
  1625. $QuicktimeStoreFrontCodeLookup [143441] = 'United States';
  1626. }
  1627. return (isset ( $QuicktimeStoreFrontCodeLookup [$sfid] ) ? $QuicktimeStoreFrontCodeLookup [$sfid] : 'invalid');
  1628. }
  1629. function QuicktimeParseNikonNCTG($atom_data) {
  1630. // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
  1631. // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
  1632. // Data is stored as records of:
  1633. // * 4 bytes record type
  1634. // * 2 bytes size of data field type:
  1635. // 0x0001 = flag (size field *= 1-byte)
  1636. // 0x0002 = char (size field *= 1-byte)
  1637. // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
  1638. // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
  1639. // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
  1640. // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????
  1641. // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????
  1642. // * 2 bytes data size field
  1643. // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
  1644. // all integers are stored BigEndian
  1645. $NCTGtagName = array (
  1646. 0x00000001 => 'Make',
  1647. 0x00000002 => 'Model',
  1648. 0x00000003 => 'Software',
  1649. 0x00000011 => 'CreateDate',
  1650. 0x00000012 => 'DateTimeOriginal',
  1651. 0x00000013 => 'FrameCount',
  1652. 0x00000016 => 'FrameRate',
  1653. 0x00000022 => 'FrameWidth',
  1654. 0x00000023 => 'FrameHeight',
  1655. 0x00000032 => 'AudioChannels',
  1656. 0x00000033 => 'AudioBitsPerSample',
  1657. 0x00000034 => 'AudioSampleRate',
  1658. 0x02000001 => 'MakerNoteVersion',
  1659. 0x02000005 => 'WhiteBalance',
  1660. 0x0200000b => 'WhiteBalanceFineTune',
  1661. 0x0200001e => 'ColorSpace',
  1662. 0x02000023 => 'PictureControlData',
  1663. 0x02000024 => 'WorldTime',
  1664. 0x02000032 => 'UnknownInfo',
  1665. 0x02000083 => 'LensType',
  1666. 0x02000084 => 'Lens' );
  1667. $offset = 0;
  1668. $datalength = strlen ( $atom_data );
  1669. $parsed = array ();
  1670. while ( $offset < $datalength ) {
  1671. //echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'<br>';
  1672. $record_type = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 4 ) );
  1673. $offset += 4;
  1674. $data_size_type = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 2 ) );
  1675. $offset += 2;
  1676. $data_size = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, 2 ) );
  1677. $offset += 2;
  1678. switch ($data_size_type) {
  1679. case 0x0001 : // 0x0001 = flag (size field *= 1-byte)
  1680. $data = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset, $data_size * 1 ) );
  1681. $offset += ($data_size * 1);
  1682. break;
  1683. case 0x0002 : // 0x0002 = char (size field *= 1-byte)
  1684. $data = substr ( $atom_data, $offset, $data_size * 1 );
  1685. $offset += ($data_size * 1);
  1686. $data = rtrim ( $data, "\x00" );
  1687. break;
  1688. case 0x0003 : // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
  1689. $data = '';
  1690. for($i = $data_size - 1; $i >= 0; $i --) {
  1691. $data .= substr ( $atom_data, $offset + ($i * 2), 2 );
  1692. }
  1693. $data = getid3_lib::BigEndian2Int ( $data );
  1694. $offset += ($data_size * 2);
  1695. break;
  1696. case 0x0004 : // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
  1697. $data = '';
  1698. for($i = $data_size - 1; $i >= 0; $i --) {
  1699. $data .= substr ( $atom_data, $offset + ($i * 4), 4 );
  1700. }
  1701. $data = getid3_lib::BigEndian2Int ( $data );
  1702. $offset += ($data_size * 4);
  1703. break;
  1704. case 0x0005 : // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
  1705. $data = array ();
  1706. for($i = 0; $i < $data_size; $i ++) {
  1707. $numerator = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset + ($i * 8) + 0, 4 ) );
  1708. $denomninator = getid3_lib::BigEndian2Int ( substr ( $atom_data, $offset + ($i * 8) + 4, 4 ) );
  1709. if ($denomninator == 0) {
  1710. $data [$i] = false;
  1711. } else {
  1712. $data [$i] = ( double ) $numerator / $denomninator;
  1713. }
  1714. }
  1715. $offset += (8 * $data_size);
  1716. if (count ( $data ) == 1) {
  1717. $data = $data [0];
  1718. }
  1719. break;
  1720. case 0x0007 : // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????
  1721. $data = substr ( $atom_data, $offset, $data_size * 1 );
  1722. $offset += ($data_size * 1);
  1723. break;
  1724. case 0x0008 : // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????
  1725. $data = substr ( $atom_data, $offset, $data_size * 2 );
  1726. $offset += ($data_size * 2);
  1727. break;
  1728. default :
  1729. echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: ' . $data_size_type . '<br>';
  1730. break 2;
  1731. }
  1732. switch ($record_type) {
  1733. case 0x00000011 : // CreateDate
  1734. case 0x00000012 : // DateTimeOriginal
  1735. $data = strtotime ( $data );
  1736. break;
  1737. case 0x0200001e : // ColorSpace
  1738. switch ($data) {
  1739. case 1 :
  1740. $data = 'sRGB';
  1741. break;
  1742. case 2 :
  1743. $data = 'Adobe RGB';
  1744. break;
  1745. }
  1746. break;
  1747. case 0x02000023 : // PictureControlData
  1748. $PictureControlAdjust = array (
  1749. 0 => 'default',
  1750. 1 => 'quick',
  1751. 2 => 'full' );
  1752. $FilterEffect = array (
  1753. 0x80 => 'off',
  1754. 0x81 => 'yellow',
  1755. 0x82 => 'orange',
  1756. 0x83 => 'red',
  1757. 0x84 => 'green',
  1758. 0xff => 'n/a' );
  1759. $ToningEffect = array (
  1760. 0x80 => 'b&w',
  1761. 0x81 => 'sepia',
  1762. 0x82 => 'cyanotype',
  1763. 0x83 => 'red',
  1764. 0x84 => 'yellow',
  1765. 0x85 => 'green',
  1766. 0x86 => 'blue-green',
  1767. 0x87 => 'blue',
  1768. 0x88 => 'purple-blue',
  1769. 0x89 => 'red-purple',
  1770. 0xff => 'n/a' );
  1771. $data = array (
  1772. 'PictureControlVersion' => substr ( $data, 0, 4 ),
  1773. 'PictureControlName' => rtrim ( substr ( $data, 4, 20 ), "\x00" ),
  1774. 'PictureControlBase' => rtrim ( substr ( $data, 24, 20 ), "\x00" ),
  1775. //'?' => substr($data, 44, 4),
  1776. 'PictureControlAdjust' => $PictureControlAdjust [ord ( substr ( $data, 48, 1 ) )],
  1777. 'PictureControlQuickAdjust' => ord ( substr ( $data, 49, 1 ) ),
  1778. 'Sharpness' => ord ( substr ( $data, 50, 1 ) ),
  1779. 'Contrast' => ord ( substr ( $data, 51, 1 ) ),
  1780. 'Brightness' => ord ( substr ( $data, 52, 1 ) ),
  1781. 'Saturation' => ord ( substr ( $data, 53, 1 ) ),
  1782. 'HueAdjustment' => ord ( substr ( $data, 54, 1 ) ),
  1783. 'FilterEffect' => $FilterEffect [ord ( substr ( $data, 55, 1 ) )],
  1784. 'ToningEffect' => $ToningEffect [ord ( substr ( $data, 56, 1 ) )],
  1785. 'ToningSaturation' => ord ( substr ( $data, 57, 1 ) ) );
  1786. break;
  1787. case 0x02000024 : // WorldTime
  1788. // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
  1789. // timezone is stored as offset from GMT in minutes
  1790. $timezone = getid3_lib::BigEndian2Int ( substr ( $data, 0, 2 ) );
  1791. if ($timezone & 0x8000) {
  1792. $timezone = 0 - (0x10000 - $timezone);
  1793. }
  1794. $timezone /= 60;
  1795. $dst = ( bool ) getid3_lib::BigEndian2Int ( substr ( $data, 2, 1 ) );
  1796. switch (getid3_lib::BigEndian2Int ( substr ( $data, 3, 1 ) )) {
  1797. case 2 :
  1798. $datedisplayformat = 'D/M/Y';
  1799. break;
  1800. case 1 :
  1801. $datedisplayformat = 'M/D/Y';
  1802. break;
  1803. case 0 :
  1804. default :
  1805. $datedisplayformat = 'Y/M/D';
  1806. break;
  1807. }
  1808. $data = array (
  1809. 'timezone' => floatval ( $timezone ),
  1810. 'dst' => $dst,
  1811. 'display' => $datedisplayformat );
  1812. break;
  1813. case 0x02000083 : // LensType
  1814. $data = array (
  1815. //'_' => $data,
  1816. 'mf' => ( bool ) ($data & 0x01),
  1817. 'd' => ( bool ) ($data & 0x02),
  1818. 'g' => ( bool ) ($data & 0x04),
  1819. 'vr' => ( bool ) ($data & 0x08) );
  1820. break;
  1821. }
  1822. $tag_name = (isset ( $NCTGtagName [$record_type] ) ? $NCTGtagName [$record_type] : '0x' . str_pad ( dechex ( $record_type ), 8, '0', STR_PAD_LEFT ));
  1823. $parsed [$tag_name] = $data;
  1824. }
  1825. return $parsed;
  1826. }
  1827. function CopyToAppropriateCommentsSection($keyname, $data, $boxname = '') {
  1828. static $handyatomtranslatorarray = array ();
  1829. if (empty ( $handyatomtranslatorarray )) {
  1830. $handyatomtranslatorarray ['©cpy'] = 'copyright';
  1831. $handyatomtranslatorarray ['©day'] = 'creation_date'; // iTunes 4.0
  1832. $handyatomtranslatorarray ['©dir'] = 'director';
  1833. $handyatomtranslatorarray ['©ed1'] = 'edit1';
  1834. $handyatomtranslatorarray ['©ed2'] = 'edit2';
  1835. $handyatomtranslatorarray ['©ed3'] = 'edit3';
  1836. $handyatomtranslatorarray ['©ed4'] = 'edit4';
  1837. $handyatomtranslatorarray ['©ed5'] = 'edit5';
  1838. $handyatomtranslatorarray ['©ed6'] = 'edit6';
  1839. $handyatomtranslatorarray ['©ed7'] = 'edit7';
  1840. $handyatomtranslatorarray ['©ed8'] = 'edit8';
  1841. $handyatomtranslatorarray ['©ed9'] = 'edit9';
  1842. $handyatomtranslatorarray ['©fmt'] = 'format';
  1843. $handyatomtranslatorarray ['©inf'] = 'information';
  1844. $handyatomtranslatorarray ['©prd'] = 'producer';
  1845. $handyatomtranslatorarray ['©prf'] = 'performers';
  1846. $handyatomtranslatorarray ['©req'] = 'system_requirements';
  1847. $handyatomtranslatorarray ['©src'] = 'source_credit';
  1848. $handyatomtranslatorarray ['©wrt'] = 'writer';
  1849. // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
  1850. $handyatomtranslatorarray ['©nam'] = 'title'; // iTunes 4.0
  1851. $handyatomtranslatorarray ['©cmt'] = 'comment'; // iTunes 4.0
  1852. $handyatomtranslatorarray ['©wrn'] = 'warning';
  1853. $handyatomtranslatorarray ['©hst'] = 'host_computer';
  1854. $handyatomtranslatorarray ['©mak'] = 'make';
  1855. $handyatomtranslatorarray ['©mod'] = 'model';
  1856. $handyatomtranslatorarray ['©PRD'] = 'product';
  1857. $handyatomtranslatorarray ['©swr'] = 'software';
  1858. $handyatomtranslatorarray ['©aut'] = 'author';
  1859. $handyatomtranslatorarray ['©ART'] = 'artist';
  1860. $handyatomtranslatorarray ['©trk'] = 'track';
  1861. $handyatomtranslatorarray ['©alb'] = 'album'; // iTunes 4.0
  1862. $handyatomtranslatorarray ['©com'] = 'comment';
  1863. $handyatomtranslatorarray ['©gen'] = 'genre'; // iTunes 4.0
  1864. $handyatomtranslatorarray ['©ope'] = 'composer';
  1865. $handyatomtranslatorarray ['©url'] = 'url';
  1866. $handyatomtranslatorarray ['©enc'] = 'encoder';
  1867. // http://atomicparsley.sourceforge.net/mpeg-4files.html
  1868. $handyatomtranslatorarray ['©art'] = 'artist'; // iTunes 4.0
  1869. $handyatomtranslatorarray ['aART'] = 'album_artist';
  1870. $handyatomtranslatorarray ['trkn'] = 'track_number'; // iTunes 4.0
  1871. $handyatomtranslatorarray ['disk'] = 'disc_number'; // iTunes 4.0
  1872. $handyatomtranslatorarray ['gnre'] = 'genre'; // iTunes 4.0
  1873. $handyatomtranslatorarray ['©too'] = 'encoder'; // iTunes 4.0
  1874. $handyatomtranslatorarray ['tmpo'] = 'bpm'; // iTunes 4.0
  1875. $handyatomtranslatorarray ['cprt'] = 'copyright'; // iTunes 4.0?
  1876. $handyatomtranslatorarray ['cpil'] = 'compilation'; // iTunes 4.0
  1877. $handyatomtranslatorarray ['covr'] = 'picture'; // iTunes 4.0
  1878. $handyatomtranslatorarray ['rtng'] = 'rating'; // iTunes 4.0
  1879. $handyatomtranslatorarray ['©grp'] = 'grouping'; // iTunes 4.2
  1880. $handyatomtranslatorarray ['stik'] = 'stik'; // iTunes 4.9
  1881. $handyatomtranslatorarray ['pcst'] = 'podcast'; // iTunes 4.9
  1882. $handyatomtranslatorarray ['catg'] = 'category'; // iTunes 4.9
  1883. $handyatomtranslatorarray ['keyw'] = 'keyword'; // iTunes 4.9
  1884. $handyatomtranslatorarray ['purl'] = 'podcast_url'; // iTunes 4.9
  1885. $handyatomtranslatorarray ['egid'] = 'episode_guid'; // iTunes 4.9
  1886. $handyatomtranslatorarray ['desc'] = 'description'; // iTunes 5.0
  1887. $handyatomtranslatorarray ['©lyr'] = 'lyrics'; // iTunes 5.0
  1888. $handyatomtranslatorarray ['tvnn'] = 'tv_network_name'; // iTunes 6.0
  1889. $handyatomtranslatorarray ['tvsh'] = 'tv_show_name'; // iTunes 6.0
  1890. $handyatomtranslatorarray ['tvsn'] = 'tv_season'; // iTunes 6.0
  1891. $handyatomtranslatorarray ['tves'] = 'tv_episode'; // iTunes 6.0
  1892. $handyatomtranslatorarray ['purd'] = 'purchase_date'; // iTunes 6.0.2
  1893. $handyatomtranslatorarray ['pgap'] = 'gapless_playback'; // iTunes 7.0
  1894. // http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
  1895. // boxnames:
  1896. $handyatomtranslatorarray ['iTunSMPB'] = 'iTunSMPB';
  1897. $handyatomtranslatorarray ['iTunNORM'] = 'iTunNORM';
  1898. $handyatomtranslatorarray ['Encoding Params'] = 'Encoding Params';
  1899. $handyatomtranslatorarray ['replaygain_track_gain'] = 'replaygain_track_gain';
  1900. $handyatomtranslatorarray ['replaygain_track_peak'] = 'replaygain_track_peak';
  1901. $handyatomtranslatorarray ['replaygain_track_minmax'] = 'replaygain_track_minmax';
  1902. $handyatomtranslatorarray ['MusicIP PUID'] = 'MusicIP PUID';
  1903. $handyatomtranslatorarray ['MusicBrainz Artist Id'] = 'MusicBrainz Artist Id';
  1904. $handyatomtranslatorarray ['MusicBrainz Album Id'] = 'MusicBrainz Album Id';
  1905. $handyatomtranslatorarray ['MusicBrainz Album Artist Id'] = 'MusicBrainz Album Artist Id';
  1906. $handyatomtranslatorarray ['MusicBrainz Track Id'] = 'MusicBrainz Track Id';
  1907. $handyatomtranslatorarray ['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id';
  1908. }
  1909. $info = &$this->getid3->info;
  1910. $comment_key = '';
  1911. if ($boxname && ($boxname != $keyname) && isset ( $handyatomtranslatorarray [$boxname] )) {
  1912. $comment_key = $handyatomtranslatorarray [$boxname];
  1913. } elseif (isset ( $handyatomtranslatorarray [$keyname] )) {
  1914. $comment_key = $handyatomtranslatorarray [$keyname];
  1915. }
  1916. if ($comment_key) {
  1917. if ($comment_key == 'picture') {
  1918. if (! is_array ( $data )) {
  1919. $image_mime = '';
  1920. if (preg_match ( '#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $data )) {
  1921. $image_mime = 'image/png';
  1922. } elseif (preg_match ( '#^\xFF\xD8\xFF#', $data )) {
  1923. $image_mime = 'image/jpeg';
  1924. } elseif (preg_match ( '#^GIF#', $data )) {
  1925. $image_mime = 'image/gif';
  1926. } elseif (preg_match ( '#^BM#', $data )) {
  1927. $image_mime = 'image/bmp';
  1928. }
  1929. $data = array (
  1930. 'data' => $data,
  1931. 'image_mime' => $image_mime );
  1932. }
  1933. }
  1934. $info ['quicktime'] ['comments'] [$comment_key] [] = $data;
  1935. }
  1936. return true;
  1937. }
  1938. function NoNullString($nullterminatedstring) {
  1939. // remove the single null terminator on null terminated strings
  1940. if (substr ( $nullterminatedstring, strlen ( $nullterminatedstring ) - 1, 1 ) === "\x00") {
  1941. return substr ( $nullterminatedstring, 0, strlen ( $nullterminatedstring ) - 1 );
  1942. }
  1943. return $nullterminatedstring;
  1944. }
  1945. function Pascal2String($pascalstring) {
  1946. // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
  1947. return substr ( $pascalstring, 1 );
  1948. }
  1949. }