PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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