PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/holyfield/getid3
PHP | 2128 lines | 1817 code | 179 blank | 132 comment | 168 complexity | 39948e0652f76cc9045d7e55f51e9452 MD5 | raw file
Possible License(s): GPL-2.0

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

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