PageRenderTime 72ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/holyfield/wpgetid
PHP | 2134 lines | 1784 code | 218 blank | 132 comment | 167 complexity | 6dbcd9a47b8edcc6dd0a73750e81a685 MD5 | raw file

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

  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. /////////////////////////////////////////////////////////////////
  7. // See readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  9. // //
  10. // module.audio-video.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. {
  18. var $ReturnAtomData = true;
  19. var $ParseAllPossibleAtoms = false;
  20. function Analyze() {
  21. $info = &$this->getid3->info;
  22. $info['fileformat'] = 'quicktime';
  23. $info['quicktime']['hinting'] = false;
  24. $info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
  25. fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
  26. $offset = 0;
  27. $atomcounter = 0;
  28. while ($offset < $info['avdataend']) {
  29. if (!getid3_lib::intValueSupported($offset)) {
  30. $info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';
  31. break;
  32. }
  33. fseek($this->getid3->fp, $offset, SEEK_SET);
  34. $AtomHeader = fread($this->getid3->fp, 8);
  35. $atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
  36. $atomname = substr($AtomHeader, 4, 4);
  37. // 64-bit MOV patch by jlegateŘktnc*com
  38. if ($atomsize == 1) {
  39. $atomsize = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 8));
  40. }
  41. $info['quicktime'][$atomname]['name'] = $atomname;
  42. $info['quicktime'][$atomname]['size'] = $atomsize;
  43. $info['quicktime'][$atomname]['offset'] = $offset;
  44. if (($offset + $atomsize) > $info['avdataend']) {
  45. $info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)';
  46. return false;
  47. }
  48. if ($atomsize == 0) {
  49. // Furthermore, for historical reasons the list of atoms is optionally
  50. // terminated by a 32-bit integer set to 0. If you are writing a program
  51. // to read user data atoms, you should allow for the terminating 0.
  52. break;
  53. }
  54. switch ($atomname) {
  55. case 'mdat': // Media DATa atom
  56. // 'mdat' contains the actual data for the audio/video
  57. if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
  58. $info['avdataoffset'] = $info['quicktime'][$atomname]['offset'] + 8;
  59. $OldAVDataEnd = $info['avdataend'];
  60. $info['avdataend'] = $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
  61. $getid3_temp = new getID3();
  62. $getid3_temp->openfile($this->getid3->filename);
  63. $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
  64. $getid3_temp->info['avdataend'] = $info['avdataend'];
  65. $getid3_mp3 = new getid3_mp3($getid3_temp);
  66. if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode(fread($this->getid3->fp, 4)))) {
  67. $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
  68. if (!empty($getid3_temp->info['warning'])) {
  69. foreach ($getid3_temp->info['warning'] as $value) {
  70. $info['warning'][] = $value;
  71. }
  72. }
  73. if (!empty($getid3_temp->info['mpeg'])) {
  74. $info['mpeg'] = $getid3_temp->info['mpeg'];
  75. if (isset($info['mpeg']['audio'])) {
  76. $info['audio']['dataformat'] = 'mp3';
  77. $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')));
  78. $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
  79. $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
  80. $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
  81. $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
  82. $info['bitrate'] = $info['audio']['bitrate'];
  83. }
  84. }
  85. }
  86. unset($getid3_mp3, $getid3_temp);
  87. $info['avdataend'] = $OldAVDataEnd;
  88. unset($OldAVDataEnd);
  89. }
  90. break;
  91. case 'free': // FREE space atom
  92. case 'skip': // SKIP atom
  93. case 'wide': // 64-bit expansion placeholder atom
  94. // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
  95. break;
  96. default:
  97. $atomHierarchy = array();
  98. $info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, fread($this->getid3->fp, $atomsize), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
  99. break;
  100. }
  101. $offset += $atomsize;
  102. $atomcounter++;
  103. }
  104. if (!empty($info['avdataend_tmp'])) {
  105. // this value is assigned to a temp value and then erased because
  106. // otherwise any atoms beyond the 'mdat' atom would not get parsed
  107. $info['avdataend'] = $info['avdataend_tmp'];
  108. unset($info['avdataend_tmp']);
  109. }
  110. if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
  111. $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
  112. }
  113. if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
  114. $info['audio']['bitrate'] = $info['bitrate'];
  115. }
  116. if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
  117. foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
  118. $samples_per_second = $samples_count / $info['playtime_seconds'];
  119. if ($samples_per_second > 240) {
  120. // has to be audio samples
  121. } else {
  122. $info['video']['frame_rate'] = $samples_per_second;
  123. break;
  124. }
  125. }
  126. }
  127. if (($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) {
  128. $info['fileformat'] = 'mp4';
  129. $info['mime_type'] = 'audio/mp4';
  130. unset($info['video']['dataformat']);
  131. }
  132. if (!$this->ReturnAtomData) {
  133. unset($info['quicktime']['moov']);
  134. }
  135. if (empty($info['audio']['dataformat']) && !empty($info['quicktime']['audio'])) {
  136. $info['audio']['dataformat'] = 'quicktime';
  137. }
  138. if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
  139. $info['video']['dataformat'] = 'quicktime';
  140. }
  141. return true;
  142. }
  143. function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
  144. // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
  145. $info = &$this->getid3->info;
  146. $atom_parent = array_pop($atomHierarchy);
  147. array_push($atomHierarchy, $atomname);
  148. $atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
  149. $atom_structure['name'] = $atomname;
  150. $atom_structure['size'] = $atomsize;
  151. $atom_structure['offset'] = $baseoffset;
  152. //echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'<br>';
  153. //echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'<br><br>';
  154. switch ($atomname) {
  155. case 'moov': // MOVie container atom
  156. case 'trak': // TRAcK container atom
  157. case 'clip': // CLIPping container atom
  158. case 'matt': // track MATTe container atom
  159. case 'edts': // EDiTS container atom
  160. case 'tref': // Track REFerence container atom
  161. case 'mdia': // MeDIA container atom
  162. case 'minf': // Media INFormation container atom
  163. case 'dinf': // Data INFormation container atom
  164. case 'udta': // User DaTA container atom
  165. case 'cmov': // Compressed MOVie container atom
  166. case 'rmra': // Reference Movie Record Atom
  167. case 'rmda': // Reference Movie Descriptor Atom
  168. case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
  169. $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
  170. break;
  171. case 'ilst': // Item LiST container atom
  172. $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
  173. // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
  174. $allnumericnames = true;
  175. foreach ($atom_structure['subatoms'] as $subatomarray) {
  176. if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
  177. $allnumericnames = false;
  178. break;
  179. }
  180. }
  181. if ($allnumericnames) {
  182. $newData = array();
  183. foreach ($atom_structure['subatoms'] as $subatomarray) {
  184. foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
  185. unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
  186. $newData[$subatomarray['name']] = $newData_subatomarray;
  187. break;
  188. }
  189. }
  190. $atom_structure['data'] = $newData;
  191. unset($atom_structure['subatoms']);
  192. }
  193. break;
  194. case "\x00\x00\x00\x01":
  195. case "\x00\x00\x00\x02":
  196. case "\x00\x00\x00\x03":
  197. case "\x00\x00\x00\x04":
  198. case "\x00\x00\x00\x05":
  199. $atomname = getid3_lib::BigEndian2Int($atomname);
  200. $atom_structure['name'] = $atomname;
  201. $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
  202. break;
  203. case 'stbl': // Sample TaBLe container atom
  204. $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
  205. $isVideo = false;
  206. $framerate = 0;
  207. $framecount = 0;
  208. foreach ($atom_structure['subatoms'] as $key => $value_array) {
  209. if (isset($value_array['sample_description_table'])) {
  210. foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
  211. if (isset($value_array2['data_format'])) {
  212. switch ($value_array2['data_format']) {
  213. case 'avc1':
  214. case 'mp4v':
  215. // video data
  216. $isVideo = true;
  217. break;
  218. case 'mp4a':
  219. // audio data
  220. break;
  221. }
  222. }
  223. }
  224. } elseif (isset($value_array['time_to_sample_table'])) {
  225. foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
  226. if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {
  227. $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
  228. $framecount = $value_array2['sample_count'];
  229. }
  230. }
  231. }
  232. }
  233. if ($isVideo && $framerate) {
  234. $info['quicktime']['video']['frame_rate'] = $framerate;
  235. $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
  236. }
  237. if ($isVideo && $framecount) {
  238. $info['quicktime']['video']['frame_count'] = $framecount;
  239. }
  240. break;
  241. case 'aART': // Album ARTist
  242. case 'catg': // CaTeGory
  243. case 'covr': // COVeR artwork
  244. case 'cpil': // ComPILation
  245. case 'cprt': // CoPyRighT
  246. case 'desc': // DESCription
  247. case 'disk': // DISK number
  248. case 'egid': // Episode Global ID
  249. case 'gnre': // GeNRE
  250. case 'keyw': // KEYWord
  251. case 'ldes':
  252. case 'pcst': // PodCaST
  253. case 'pgap': // GAPless Playback
  254. case 'purd': // PURchase Date
  255. case 'purl': // Podcast URL
  256. case 'rati':
  257. case 'rndu':
  258. case 'rpdu':
  259. case 'rtng': // RaTiNG
  260. case 'stik':
  261. case 'tmpo': // TeMPO (BPM)
  262. case 'trkn': // TRacK Number
  263. case 'tves': // TV EpiSode
  264. case 'tvnn': // TV Network Name
  265. case 'tvsh': // TV SHow Name
  266. case 'tvsn': // TV SeasoN
  267. case 'akID': // iTunes store account type
  268. case 'apID':
  269. case 'atID':
  270. case 'cmID':
  271. case 'cnID':
  272. case 'geID':
  273. case 'plID':
  274. case 'sfID': // iTunes store country
  275. case 'Šalb': // ALBum
  276. case 'Šart': // ARTist
  277. case 'ŠART':
  278. case 'Šaut':
  279. case 'Šcmt': // CoMmenT
  280. case 'Šcom': // COMposer
  281. case 'Šcpy':
  282. case 'Šday': // content created year
  283. case 'Šdir':
  284. case 'Šed1':
  285. case 'Šed2':
  286. case 'Šed3':
  287. case 'Šed4':
  288. case 'Šed5':
  289. case 'Šed6':
  290. case 'Šed7':
  291. case 'Šed8':
  292. case 'Šed9':
  293. case 'Šenc':
  294. case 'Šfmt':
  295. case 'Šgen': // GENre
  296. case 'Šgrp': // GRouPing
  297. case 'Šhst':
  298. case 'Šinf':
  299. case 'Šlyr': // LYRics
  300. case 'Šmak':
  301. case 'Šmod':
  302. case 'Šnam': // full NAMe
  303. case 'Šope':
  304. case 'ŠPRD':
  305. case 'Šprd':
  306. case 'Šprf':
  307. case 'Šreq':
  308. case 'Šsrc':
  309. case 'Šswr':
  310. case 'Štoo': // encoder
  311. case 'Štrk': // TRacK
  312. case 'Šurl':
  313. case 'Šwrn':
  314. case 'Šwrt': // WRiTer
  315. case '----': // itunes specific
  316. if ($atom_parent == 'udta') {
  317. // User data atom handler
  318. $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
  319. $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
  320. $atom_structure['data'] = substr($atom_data, 4);
  321. $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
  322. if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
  323. $info['comments']['language'][] = $atom_structure['language'];
  324. }
  325. } else {
  326. // Apple item list box atom handler
  327. $atomoffset = 0;
  328. if (substr($atom_data, 2, 2) == "\x10\xB5") {
  329. // not sure what it means, but observed on iPhone4 data.
  330. // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
  331. while ($atomoffset < strlen($atom_data)) {
  332. $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2));
  333. $boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
  334. $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
  335. switch ($boxsmalltype) {
  336. case "\x10\xB5":
  337. $atom_structure['data'] = $boxsmalldata;
  338. break;
  339. default:
  340. $info['warning'][] = 'Unknown QuickTime smallbox type: "'.getid3_lib::PrintHexBytes($boxsmalltype).'" at offset '.$baseoffset;
  341. $atom_structure['data'] = $atom_data;
  342. break;
  343. }
  344. $atomoffset += (4 + $boxsmallsize);
  345. }
  346. } else {
  347. while ($atomoffset < strlen($atom_data)) {
  348. $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4));
  349. $boxtype = substr($atom_data, $atomoffset + 4, 4);
  350. $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8);
  351. switch ($boxtype) {
  352. case 'mean':
  353. case 'name':
  354. $atom_structure[$boxtype] = substr($boxdata, 4);
  355. break;
  356. case 'data':
  357. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1));
  358. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3));
  359. switch ($atom_structure['flags_raw']) {
  360. case 0: // data flag
  361. case 21: // tmpo/cpil flag
  362. switch ($atomname) {
  363. case 'cpil':
  364. case 'pcst':
  365. case 'pgap':
  366. $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
  367. break;
  368. case 'tmpo':
  369. $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
  370. break;
  371. case 'disk':
  372. case 'trkn':
  373. $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
  374. $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
  375. $atom_structure['data'] = empty($num) ? '' : $num;
  376. $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total;
  377. break;
  378. case 'gnre':
  379. $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
  380. $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1);
  381. break;
  382. case 'rtng':
  383. $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
  384. $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
  385. break;
  386. case 'stik':
  387. $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
  388. $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
  389. break;
  390. case 'sfID':
  391. $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
  392. $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
  393. break;
  394. case 'egid':
  395. case 'purl':
  396. $atom_structure['data'] = substr($boxdata, 8);
  397. break;
  398. default:
  399. $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
  400. }
  401. break;
  402. case 1: // text flag
  403. case 13: // image flag
  404. default:
  405. $atom_structure['data'] = substr($boxdata, 8);
  406. break;
  407. }
  408. break;
  409. default:
  410. $info['warning'][] = 'Unknown QuickTime box type: "'.getid3_lib::PrintHexBytes($boxtype).'" at offset '.$baseoffset;
  411. $atom_structure['data'] = $atom_data;
  412. }
  413. $atomoffset += $boxsize;
  414. }
  415. }
  416. }
  417. $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
  418. break;
  419. case 'play': // auto-PLAY atom
  420. $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  421. $info['quicktime']['autoplay'] = $atom_structure['autoplay'];
  422. break;
  423. case 'WLOC': // Window LOCation atom
  424. $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
  425. $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
  426. break;
  427. case 'LOOP': // LOOPing atom
  428. case 'SelO': // play SELection Only atom
  429. case 'AllF': // play ALL Frames atom
  430. $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);
  431. break;
  432. case 'name': //
  433. case 'MCPS': // Media Cleaner PRo
  434. case '@PRM': // adobe PReMiere version
  435. case '@PRQ': // adobe PRemiere Quicktime version
  436. $atom_structure['data'] = $atom_data;
  437. break;
  438. case 'cmvd': // Compressed MooV Data atom
  439. // Code by ubergeekŘubergeek*tv based on information from
  440. // http://developer.apple.com/quicktime/icefloe/dispatch012.html
  441. $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
  442. $CompressedFileData = substr($atom_data, 4);
  443. if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
  444. $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
  445. } else {
  446. $info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset'];
  447. }
  448. break;
  449. case 'dcom': // Data COMpression atom
  450. $atom_structure['compression_id'] = $atom_data;
  451. $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
  452. break;
  453. case 'rdrf': // Reference movie Data ReFerence atom
  454. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  455. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
  456. $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);
  457. $atom_structure['reference_type_name'] = substr($atom_data, 4, 4);
  458. $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
  459. switch ($atom_structure['reference_type_name']) {
  460. case 'url ':
  461. $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12));
  462. break;
  463. case 'alis':
  464. $atom_structure['file_alias'] = substr($atom_data, 12);
  465. break;
  466. case 'rsrc':
  467. $atom_structure['resource_alias'] = substr($atom_data, 12);
  468. break;
  469. default:
  470. $atom_structure['data'] = substr($atom_data, 12);
  471. break;
  472. }
  473. break;
  474. case 'rmqu': // Reference Movie QUality atom
  475. $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);
  476. break;
  477. case 'rmcs': // Reference Movie Cpu Speed atom
  478. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  479. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  480. $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
  481. break;
  482. case 'rmvc': // Reference Movie Version Check atom
  483. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  484. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  485. $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4);
  486. $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
  487. $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
  488. $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
  489. break;
  490. case 'rmcd': // Reference Movie Component check atom
  491. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  492. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  493. $atom_structure['component_type'] = substr($atom_data, 4, 4);
  494. $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
  495. $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
  496. $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
  497. $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
  498. $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));
  499. break;
  500. case 'rmdr': // Reference Movie Data Rate atom
  501. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  502. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  503. $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  504. $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
  505. break;
  506. case 'rmla': // Reference Movie Language Atom
  507. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  508. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  509. $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
  510. $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
  511. if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
  512. $info['comments']['language'][] = $atom_structure['language'];
  513. }
  514. break;
  515. case 'rmla': // Reference Movie Language Atom
  516. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  517. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  518. $atom_structure['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
  519. break;
  520. case 'ptv ': // Print To Video - defines a movie's full screen mode
  521. // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
  522. $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
  523. $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000
  524. $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000
  525. $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1));
  526. $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1));
  527. $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
  528. $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];
  529. $ptv_lookup[0] = 'normal';
  530. $ptv_lookup[1] = 'double';
  531. $ptv_lookup[2] = 'half';
  532. $ptv_lookup[3] = 'full';
  533. $ptv_lookup[4] = 'current';
  534. if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
  535. $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
  536. } else {
  537. $info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')';
  538. }
  539. break;
  540. case 'stsd': // Sample Table Sample Description atom
  541. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  542. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  543. $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  544. $stsdEntriesDataOffset = 8;
  545. for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
  546. $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
  547. $stsdEntriesDataOffset += 4;
  548. $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4);
  549. $stsdEntriesDataOffset += 4;
  550. $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
  551. $stsdEntriesDataOffset += 6;
  552. $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
  553. $stsdEntriesDataOffset += 2;
  554. $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
  555. $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
  556. $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2));
  557. $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2));
  558. $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4);
  559. switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
  560. case "\x00\x00\x00\x00":
  561. // audio atom
  562. $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2));
  563. $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2));
  564. $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2));
  565. $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2));
  566. $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4));
  567. switch ($atom_structure['sample_description_table'][$i]['data_format']) {
  568. case 'avc1':
  569. case 'mp4v':
  570. $info['fileformat'] = 'mp4';
  571. $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
  572. //$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?
  573. break;
  574. case 'qtvr':
  575. $info['video']['dataformat'] = 'quicktimevr';
  576. break;
  577. case 'mp4a':
  578. default:
  579. $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
  580. $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
  581. $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels'];
  582. $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
  583. $info['audio']['codec'] = $info['quicktime']['audio']['codec'];
  584. $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate'];
  585. $info['audio']['channels'] = $info['quicktime']['audio']['channels'];
  586. $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth'];
  587. switch ($atom_structure['sample_description_table'][$i]['data_format']) {
  588. case 'raw ': // PCM
  589. case 'alac': // Apple Lossless Audio Codec
  590. $info['audio']['lossless'] = true;
  591. break;
  592. default:
  593. $info['audio']['lossless'] = false;
  594. break;
  595. }
  596. break;
  597. }
  598. break;
  599. default:
  600. switch ($atom_structure['sample_description_table'][$i]['data_format']) {
  601. case 'mp4s':
  602. $info['fileformat'] = 'mp4';
  603. break;
  604. default:
  605. // video atom
  606. $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
  607. $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
  608. $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
  609. $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
  610. $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4));
  611. $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
  612. $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
  613. $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2));
  614. $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1));
  615. $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']);
  616. $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2));
  617. $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2));
  618. $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
  619. $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
  620. if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
  621. $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
  622. $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
  623. $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']);
  624. $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
  625. $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
  626. $info['video']['codec'] = $info['quicktime']['video']['codec'];
  627. $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
  628. }
  629. $info['video']['lossless'] = false;
  630. $info['video']['pixel_aspect_ratio'] = (float) 1;
  631. break;
  632. }
  633. break;
  634. }
  635. switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
  636. case 'mp4a':
  637. $info['audio']['dataformat'] = 'mp4';
  638. $info['quicktime']['audio']['codec'] = 'mp4';
  639. break;
  640. case '3ivx':
  641. case '3iv1':
  642. case '3iv2':
  643. $info['video']['dataformat'] = '3ivx';
  644. break;
  645. case 'xvid':
  646. $info['video']['dataformat'] = 'xvid';
  647. break;
  648. case 'mp4v':
  649. $info['video']['dataformat'] = 'mpeg4';
  650. break;
  651. case 'divx':
  652. case 'div1':
  653. case 'div2':
  654. case 'div3':
  655. case 'div4':
  656. case 'div5':
  657. case 'div6':
  658. $info['video']['dataformat'] = 'divx';
  659. break;
  660. default:
  661. // do nothing
  662. break;
  663. }
  664. unset($atom_structure['sample_description_table'][$i]['data']);
  665. }
  666. break;
  667. case 'stts': // Sample Table Time-to-Sample atom
  668. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  669. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  670. $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  671. $sttsEntriesDataOffset = 8;
  672. //$FrameRateCalculatorArray = array();
  673. $frames_count = 0;
  674. for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
  675. $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
  676. $sttsEntriesDataOffset += 4;
  677. $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
  678. $sttsEntriesDataOffset += 4;
  679. $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
  680. // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
  681. //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
  682. // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
  683. // if ($stts_new_framerate <= 60) {
  684. // // some atoms have durations of "1" giving a very large framerate, which probably is not right
  685. // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
  686. // }
  687. //}
  688. //
  689. //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
  690. }
  691. $info['quicktime']['stts_framecount'][] = $frames_count;
  692. //$sttsFramesTotal = 0;
  693. //$sttsSecondsTotal = 0;
  694. //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
  695. // if (($frames_per_second > 60) || ($frames_per_second < 1)) {
  696. // // not video FPS information, probably audio information
  697. // $sttsFramesTotal = 0;
  698. // $sttsSecondsTotal = 0;
  699. // break;
  700. // }
  701. // $sttsFramesTotal += $frame_count;
  702. // $sttsSecondsTotal += $frame_count / $frames_per_second;
  703. //}
  704. //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
  705. // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
  706. // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
  707. // }
  708. //}
  709. break;
  710. case 'stss': // Sample Table Sync Sample (key frames) atom
  711. if ($ParseAllPossibleAtoms) {
  712. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  713. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  714. $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  715. $stssEntriesDataOffset = 8;
  716. for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
  717. $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
  718. $stssEntriesDataOffset += 4;
  719. }
  720. }
  721. break;
  722. case 'stsc': // Sample Table Sample-to-Chunk atom
  723. if ($ParseAllPossibleAtoms) {
  724. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  725. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  726. $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  727. $stscEntriesDataOffset = 8;
  728. for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
  729. $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
  730. $stscEntriesDataOffset += 4;
  731. $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
  732. $stscEntriesDataOffset += 4;
  733. $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
  734. $stscEntriesDataOffset += 4;
  735. }
  736. }
  737. break;
  738. case 'stsz': // Sample Table SiZe atom
  739. if ($ParseAllPossibleAtoms) {
  740. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  741. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  742. $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  743. $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
  744. $stszEntriesDataOffset = 12;
  745. if ($atom_structure['sample_size'] == 0) {
  746. for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
  747. $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
  748. $stszEntriesDataOffset += 4;
  749. }
  750. }
  751. }
  752. break;
  753. case 'stco': // Sample Table Chunk Offset atom
  754. if ($ParseAllPossibleAtoms) {
  755. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  756. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  757. $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  758. $stcoEntriesDataOffset = 8;
  759. for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
  760. $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
  761. $stcoEntriesDataOffset += 4;
  762. }
  763. }
  764. break;
  765. case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
  766. if ($ParseAllPossibleAtoms) {
  767. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  768. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  769. $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  770. $stcoEntriesDataOffset = 8;
  771. for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
  772. $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
  773. $stcoEntriesDataOffset += 8;
  774. }
  775. }
  776. break;
  777. case 'dref': // Data REFerence atom
  778. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  779. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  780. $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  781. $drefDataOffset = 8;
  782. for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
  783. $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
  784. $drefDataOffset += 4;
  785. $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);
  786. $drefDataOffset += 4;
  787. $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1));
  788. $drefDataOffset += 1;
  789. $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000
  790. $drefDataOffset += 3;
  791. $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
  792. $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
  793. $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
  794. }
  795. break;
  796. case 'gmin': // base Media INformation atom
  797. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  798. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  799. $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
  800. $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
  801. $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
  802. $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
  803. $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));
  804. $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
  805. break;
  806. case 'smhd': // Sound Media information HeaDer atom
  807. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  808. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  809. $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
  810. $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
  811. break;
  812. case 'vmhd': // Video Media information HeaDer atom
  813. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  814. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
  815. $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
  816. $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
  817. $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
  818. $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
  819. $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001);
  820. break;
  821. case 'hdlr': // HanDLeR reference atom
  822. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  823. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  824. $atom_structure['component_type'] = substr($atom_data, 4, 4);
  825. $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
  826. $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
  827. $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
  828. $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
  829. $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24));
  830. if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
  831. $info['video']['dataformat'] = 'quicktimevr';
  832. }
  833. break;
  834. case 'mdhd': // MeDia HeaDer atom
  835. $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
  836. $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
  837. $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
  838. $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
  839. $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
  840. $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
  841. $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));
  842. $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
  843. if ($atom_structure['time_scale'] == 0) {
  844. $info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
  845. return false;
  846. }
  847. $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
  848. $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
  849. $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
  850. $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
  851. $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
  852. if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
  853. $info['comments']['language'][] = $atom_structure['language'];
  854. }
  855. break;
  856. case 'pnot': // Preview atom
  857. $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format"
  858. $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00
  859. $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'
  860. $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
  861. $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
  862. break;
  863. case 'crgn': // Clipping ReGioN atom
  864. $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box,
  865. $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields
  866. $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region.
  867. break;
  868. case 'load': // trac…

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