132 array_push($atomHierarchy, $atomname);
133 $atomstructure[
'hierarchy'] = implode(
' ', $atomHierarchy);
134 $atomstructure[
'name'] = $atomname;
135 $atomstructure[
'size'] = $atomsize;
136 $atomstructure[
'offset'] = $baseoffset;
154 $atomstructure[
'subatoms'] = $this->
QuicktimeParseContainerAtom($atomdata, $ThisFileInfo, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
196 $atomstructure[
'data'] = substr($atomdata, 4);
199 if (empty($ThisFileInfo[
'comments'][
'language']) || (!in_array($atomstructure[
'language'], $ThisFileInfo[
'comments'][
'language']))) {
200 $ThisFileInfo[
'comments'][
'language'][] = $atomstructure[
'language'];
209 $ThisFileInfo[
'quicktime'][
'autoplay'] = $atomstructure[
'autoplay'];
230 $atomstructure[
'data'] = $atomdata;
239 $CompressedFileData = substr($atomdata, 4);
240 if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
241 $atomstructure[
'subatoms'] = $this->
QuicktimeParseContainerAtom($UncompressedHeader, $ThisFileInfo, 0, $atomHierarchy, $ParseAllPossibleAtoms);
243 $ThisFileInfo[
'warning'][] =
'Error decompressing compressed MOV atom at offset '.$atomstructure[
'offset'];
249 $atomstructure[
'compression_id'] = $atomdata;
257 $atomstructure[
'flags'][
'internal_data'] = (bool) ($atomstructure[
'flags_raw'] & 0x000001);
259 $atomstructure[
'reference_type_name'] = substr($atomdata, 4, 4);
261 switch ($atomstructure[
'reference_type_name']) {
263 $atomstructure[
'url'] = $this->
NoNullString(substr($atomdata, 12));
267 $atomstructure[
'file_alias'] = substr($atomdata, 12);
271 $atomstructure[
'resource_alias'] = substr($atomdata, 12);
275 $atomstructure[
'data'] = substr($atomdata, 12);
296 $atomstructure[
'gestalt_selector'] = substr($atomdata, 4, 4);
306 $atomstructure[
'component_type'] = substr($atomdata, 4, 4);
307 $atomstructure[
'component_subtype'] = substr($atomdata, 8, 4);
308 $atomstructure[
'component_manufacturer'] = substr($atomdata, 12, 4);
320 $atomstructure[
'data_rate_bps'] = $atomstructure[
'data_rate'] * 10;
330 if (empty($ThisFileInfo[
'comments'][
'language']) || (!in_array($atomstructure[
'language'], $ThisFileInfo[
'comments'][
'language']))) {
331 $ThisFileInfo[
'comments'][
'language'][] = $atomstructure[
'language'];
351 $atomstructure[
'flags'][
'play_on_open'] = (bool) $atomstructure[
'play_on_open_flag'];
352 $atomstructure[
'flags'][
'slide_show'] = (bool) $atomstructure[
'slide_show_flag'];
354 $ptv_lookup[0] =
'normal';
355 $ptv_lookup[1] =
'double';
356 $ptv_lookup[2] =
'half';
357 $ptv_lookup[3] =
'full';
358 $ptv_lookup[4] =
'current';
359 if (isset($ptv_lookup[$atomstructure[
'display_size_raw']])) {
360 $atomstructure[
'display_size'] = $ptv_lookup[$atomstructure[
'display_size_raw']];
362 $ThisFileInfo[
'warning'][] =
'unknown "ptv " display constant ('.$atomstructure[
'display_size_raw'].
')';
371 $stsdEntriesDataOffset = 8;
372 for ($i = 0; $i < $atomstructure[
'number_entries']; $i++) {
373 $atomstructure[
'sample_description_table'][$i][
'size'] =
getid3_lib::BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 4));
374 $stsdEntriesDataOffset += 4;
375 $atomstructure[
'sample_description_table'][$i][
'data_format'] = substr($atomdata, $stsdEntriesDataOffset, 4);
376 $stsdEntriesDataOffset += 4;
377 $atomstructure[
'sample_description_table'][$i][
'reserved'] =
getid3_lib::BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 6));
378 $stsdEntriesDataOffset += 6;
379 $atomstructure[
'sample_description_table'][$i][
'reference_index'] =
getid3_lib::BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 2));
380 $stsdEntriesDataOffset += 2;
381 $atomstructure[
'sample_description_table'][$i][
'data'] = substr($atomdata, $stsdEntriesDataOffset, ($atomstructure[
'sample_description_table'][$i][
'size'] - 4 - 4 - 6 - 2));
382 $stsdEntriesDataOffset += ($atomstructure[
'sample_description_table'][$i][
'size'] - 4 - 4 - 6 - 2);
384 $atomstructure[
'sample_description_table'][$i][
'encoder_version'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 0, 2));
385 $atomstructure[
'sample_description_table'][$i][
'encoder_revision'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 2, 2));
386 $atomstructure[
'sample_description_table'][$i][
'encoder_vendor'] = substr($atomstructure[
'sample_description_table'][$i][
'data'], 4, 4);
388 switch ($atomstructure[
'sample_description_table'][$i][
'encoder_vendor']) {
390 case "\x00\x00\x00\x00":
392 $atomstructure[
'sample_description_table'][$i][
'audio_channels'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 8, 2));
393 $atomstructure[
'sample_description_table'][$i][
'audio_bit_depth'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 10, 2));
394 $atomstructure[
'sample_description_table'][$i][
'audio_compression_id'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 12, 2));
395 $atomstructure[
'sample_description_table'][$i][
'audio_packet_size'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 14, 2));
396 $atomstructure[
'sample_description_table'][$i][
'audio_sample_rate'] =
getid3_lib::FixedPoint16_16(substr($atomstructure[
'sample_description_table'][$i][
'data'], 16, 4));
398 switch ($atomstructure[
'sample_description_table'][$i][
'data_format']) {
400 $ThisFileInfo[
'fileformat'] =
'mp4';
401 $ThisFileInfo[
'error'][] =
'This version ('.GETID3_VERSION.
') of getID3() does not fully support MPEG-4 audio/video streams';
405 $ThisFileInfo[
'video'][
'dataformat'] =
'quicktimevr';
410 $ThisFileInfo[
'quicktime'][
'audio'][
'codec'] = $this->
QuicktimeAudioCodecLookup($atomstructure[
'sample_description_table'][$i][
'data_format']);
411 $ThisFileInfo[
'quicktime'][
'audio'][
'sample_rate'] = $atomstructure[
'sample_description_table'][$i][
'audio_sample_rate'];
412 $ThisFileInfo[
'quicktime'][
'audio'][
'channels'] = $atomstructure[
'sample_description_table'][$i][
'audio_channels'];
413 $ThisFileInfo[
'quicktime'][
'audio'][
'bit_depth'] = $atomstructure[
'sample_description_table'][$i][
'audio_bit_depth'];
414 $ThisFileInfo[
'audio'][
'codec'] = $ThisFileInfo[
'quicktime'][
'audio'][
'codec'];
415 $ThisFileInfo[
'audio'][
'sample_rate'] = $ThisFileInfo[
'quicktime'][
'audio'][
'sample_rate'];
416 $ThisFileInfo[
'audio'][
'channels'] = $ThisFileInfo[
'quicktime'][
'audio'][
'channels'];
417 $ThisFileInfo[
'audio'][
'bits_per_sample'] = $ThisFileInfo[
'quicktime'][
'audio'][
'bit_depth'];
418 switch ($atomstructure[
'sample_description_table'][$i][
'data_format']) {
421 $ThisFileInfo[
'audio'][
'lossless'] =
true;
424 $ThisFileInfo[
'audio'][
'lossless'] =
false;
432 switch ($atomstructure[
'sample_description_table'][$i][
'data_format']) {
434 $ThisFileInfo[
'fileformat'] =
'mp4';
439 $atomstructure[
'sample_description_table'][$i][
'video_temporal_quality'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 8, 4));
440 $atomstructure[
'sample_description_table'][$i][
'video_spatial_quality'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 12, 4));
441 $atomstructure[
'sample_description_table'][$i][
'video_frame_width'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 16, 2));
442 $atomstructure[
'sample_description_table'][$i][
'video_frame_height'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 18, 2));
443 $atomstructure[
'sample_description_table'][$i][
'video_resolution_x'] =
getid3_lib::FixedPoint16_16(substr($atomstructure[
'sample_description_table'][$i][
'data'], 20, 4));
444 $atomstructure[
'sample_description_table'][$i][
'video_resolution_y'] =
getid3_lib::FixedPoint16_16(substr($atomstructure[
'sample_description_table'][$i][
'data'], 24, 4));
445 $atomstructure[
'sample_description_table'][$i][
'video_data_size'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 28, 4));
446 $atomstructure[
'sample_description_table'][$i][
'video_frame_count'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 32, 2));
447 $atomstructure[
'sample_description_table'][$i][
'video_encoder_name_len'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 34, 1));
448 $atomstructure[
'sample_description_table'][$i][
'video_encoder_name'] = substr($atomstructure[
'sample_description_table'][$i][
'data'], 35, $atomstructure[
'sample_description_table'][$i][
'video_encoder_name_len']);
449 $atomstructure[
'sample_description_table'][$i][
'video_pixel_color_depth'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 66, 2));
450 $atomstructure[
'sample_description_table'][$i][
'video_color_table_id'] =
getid3_lib::BigEndian2Int(substr($atomstructure[
'sample_description_table'][$i][
'data'], 68, 2));
452 $atomstructure[
'sample_description_table'][$i][
'video_pixel_color_type'] = (($atomstructure[
'sample_description_table'][$i][
'video_pixel_color_depth'] > 32) ?
'grayscale' :
'color');
453 $atomstructure[
'sample_description_table'][$i][
'video_pixel_color_name'] = $this->
QuicktimeColorNameLookup($atomstructure[
'sample_description_table'][$i][
'video_pixel_color_depth']);
455 if ($atomstructure[
'sample_description_table'][$i][
'video_pixel_color_name'] !=
'invalid') {
456 $ThisFileInfo[
'quicktime'][
'video'][
'codec_fourcc'] = $atomstructure[
'sample_description_table'][$i][
'data_format'];
457 $ThisFileInfo[
'quicktime'][
'video'][
'codec_fourcc_lookup'] = $this->
QuicktimeVideoCodecLookup($atomstructure[
'sample_description_table'][$i][
'data_format']);
458 $ThisFileInfo[
'quicktime'][
'video'][
'codec'] = $atomstructure[
'sample_description_table'][$i][
'video_encoder_name'];
459 $ThisFileInfo[
'quicktime'][
'video'][
'color_depth'] = $atomstructure[
'sample_description_table'][$i][
'video_pixel_color_depth'];
460 $ThisFileInfo[
'quicktime'][
'video'][
'color_depth_name'] = $atomstructure[
'sample_description_table'][$i][
'video_pixel_color_name'];
462 $ThisFileInfo[
'video'][
'codec'] = $ThisFileInfo[
'quicktime'][
'video'][
'codec'];
463 $ThisFileInfo[
'video'][
'bits_per_sample'] = $ThisFileInfo[
'quicktime'][
'video'][
'color_depth'];
465 $ThisFileInfo[
'video'][
'lossless'] =
false;
466 $ThisFileInfo[
'video'][
'pixel_aspect_ratio'] = (float) 1;
471 switch (strtolower($atomstructure[
'sample_description_table'][$i][
'data_format'])) {
473 $ThisFileInfo[
'audio'][
'dataformat'] =
'mp4';
474 $ThisFileInfo[
'quicktime'][
'audio'][
'codec'] =
'mp4';
480 $ThisFileInfo[
'video'][
'dataformat'] =
'3ivx';
484 $ThisFileInfo[
'video'][
'dataformat'] =
'xvid';
488 $ThisFileInfo[
'video'][
'dataformat'] =
'mpeg4';
498 $TDIVXileInfo[
'video'][
'dataformat'] =
'divx';
505 unset($atomstructure[
'sample_description_table'][$i][
'data']);
515 $sttsEntriesDataOffset = 8;
516 $FrameRateCalculatorArray = array();
517 for ($i = 0; $i < $atomstructure[
'number_entries']; $i++) {
518 $atomstructure[
'time_to_sample_table'][$i][
'sample_count'] =
getid3_lib::BigEndian2Int(substr($atomdata, $sttsEntriesDataOffset, 4));
519 $sttsEntriesDataOffset += 4;
520 $atomstructure[
'time_to_sample_table'][$i][
'sample_duration'] =
getid3_lib::BigEndian2Int(substr($atomdata, $sttsEntriesDataOffset, 4));
521 $sttsEntriesDataOffset += 4;
523 if (!empty($ThisFileInfo[
'quicktime'][
'time_scale']) && (@$atomstructure[
'time_to_sample_table'][$i][
'sample_duration'] > 0)) {
524 $stts_new_framerate = $ThisFileInfo[
'quicktime'][
'time_scale'] / $atomstructure[
'time_to_sample_table'][$i][
'sample_duration'];
525 if ($stts_new_framerate <= 60) {
527 $ThisFileInfo[
'video'][
'frame_rate'] = max(@$ThisFileInfo[
'video'][
'frame_rate'], $stts_new_framerate);
554 if ($ParseAllPossibleAtoms) {
558 $stssEntriesDataOffset = 8;
559 for ($i = 0; $i < $atomstructure[
'number_entries']; $i++) {
561 $stssEntriesDataOffset += 4;
568 if ($ParseAllPossibleAtoms) {
572 $stscEntriesDataOffset = 8;
573 for ($i = 0; $i < $atomstructure[
'number_entries']; $i++) {
574 $atomstructure[
'sample_to_chunk_table'][$i][
'first_chunk'] =
getid3_lib::BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4));
575 $stscEntriesDataOffset += 4;
576 $atomstructure[
'sample_to_chunk_table'][$i][
'samples_per_chunk'] =
getid3_lib::BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4));
577 $stscEntriesDataOffset += 4;
578 $atomstructure[
'sample_to_chunk_table'][$i][
'sample_description'] =
getid3_lib::BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4));
579 $stscEntriesDataOffset += 4;
586 if ($ParseAllPossibleAtoms) {
591 $stszEntriesDataOffset = 12;
592 if ($atomstructure[
'sample_size'] == 0) {
593 for ($i = 0; $i < $atomstructure[
'number_entries']; $i++) {
595 $stszEntriesDataOffset += 4;
603 if ($ParseAllPossibleAtoms) {
607 $stcoEntriesDataOffset = 8;
608 for ($i = 0; $i < $atomstructure[
'number_entries']; $i++) {
610 $stcoEntriesDataOffset += 4;
621 for ($i = 0; $i < $atomstructure[
'number_entries']; $i++) {
623 $drefDataOffset += 4;
624 $atomstructure[
'data_references'][$i][
'type'] = substr($atomdata, $drefDataOffset, 4);
625 $drefDataOffset += 4;
627 $drefDataOffset += 1;
629 $drefDataOffset += 3;
630 $atomstructure[
'data_references'][$i][
'data'] = substr($atomdata, $drefDataOffset, ($atomstructure[
'data_references'][$i][
'size'] - 4 - 4 - 1 - 3));
631 $drefDataOffset += ($atomstructure[
'data_references'][$i][
'size'] - 4 - 4 - 1 - 3);
633 $atomstructure[
'data_references'][$i][
'flags'][
'self_reference'] = (bool) ($atomstructure[
'data_references'][$i][
'flags_raw'] & 0x001);
666 $atomstructure[
'flags'][
'no_lean_ahead'] = (bool) ($atomstructure[
'flags_raw'] & 0x001);
673 $atomstructure[
'component_type'] = substr($atomdata, 4, 4);
674 $atomstructure[
'component_subtype'] = substr($atomdata, 8, 4);
675 $atomstructure[
'component_manufacturer'] = substr($atomdata, 12, 4);
678 $atomstructure[
'component_name'] = $this->
Pascal2String(substr($atomdata, 24));
680 if (($atomstructure[
'component_subtype'] ==
'STpn') && ($atomstructure[
'component_manufacturer'] ==
'zzzz')) {
681 $ThisFileInfo[
'video'][
'dataformat'] =
'quicktimevr';
696 if ($atomstructure[
'time_scale'] == 0) {
697 $ThisFileInfo[
'error'][] =
'Corrupt Quicktime file: mdhd.time_scale == zero';
702 $atomstructure[
'playtime_seconds'] = $atomstructure[
'duration'] / $atomstructure[
'time_scale'];
704 if (empty($ThisFileInfo[
'comments'][
'language']) || (!in_array($atomstructure[
'language'], $ThisFileInfo[
'comments'][
'language']))) {
705 $ThisFileInfo[
'comments'][
'language'][] = $atomstructure[
'language'];
713 $atomstructure[
'atom_type'] = substr($atomdata, 6, 4);
723 $atomstructure[
'clipping_data'] = substr($atomdata, 10);
733 $atomstructure[
'default_hints'][
'double_buffer'] = (bool) ($atomstructure[
'default_hints_raw'] & 0x0020);
734 $atomstructure[
'default_hints'][
'high_quality'] = (bool) ($atomstructure[
'default_hints_raw'] & 0x0100);
743 for ($i = 0; $i < (strlen($atomdata) % 4); $i++) {
753 for ($i = 0; $i < $atomstructure[
'number_entries']; $i++ ) {
764 $atomstructure[
'matte_data_raw'] = substr($atomdata, 4);
772 for ($colortableentry = 0; $colortableentry < $atomstructure[
'color_table_size']; $colortableentry++) {
773 $atomstructure[
'color_table'][$colortableentry][
'alpha'] =
getid3_lib::BigEndian2Int(substr($atomdata, 8 + ($colortableentry * 8) + 0, 2));
774 $atomstructure[
'color_table'][$colortableentry][
'red'] =
getid3_lib::BigEndian2Int(substr($atomdata, 8 + ($colortableentry * 8) + 2, 2));
775 $atomstructure[
'color_table'][$colortableentry][
'green'] =
getid3_lib::BigEndian2Int(substr($atomdata, 8 + ($colortableentry * 8) + 4, 2));
776 $atomstructure[
'color_table'][$colortableentry][
'blue'] =
getid3_lib::BigEndian2Int(substr($atomdata, 8 + ($colortableentry * 8) + 6, 2));
790 $atomstructure[
'reserved'] = substr($atomdata, 26, 10);
808 if ($atomstructure[
'time_scale'] == 0) {
809 $ThisFileInfo[
'error'][] =
'Corrupt Quicktime file: mvhd.time_scale == zero';
814 $ThisFileInfo[
'quicktime'][
'time_scale'] = $atomstructure[
'time_scale'];
815 $ThisFileInfo[
'quicktime'][
'display_scale'] = $atomstructure[
'matrix_a'];
816 $ThisFileInfo[
'playtime_seconds'] = $atomstructure[
'duration'] / $atomstructure[
'time_scale'];
845 $atomstructure[
'flags'][
'enabled'] = (bool) ($atomstructure[
'flags_raw'] & 0x0001);
846 $atomstructure[
'flags'][
'in_movie'] = (bool) ($atomstructure[
'flags_raw'] & 0x0002);
847 $atomstructure[
'flags'][
'in_preview'] = (bool) ($atomstructure[
'flags_raw'] & 0x0004);
848 $atomstructure[
'flags'][
'in_poster'] = (bool) ($atomstructure[
'flags_raw'] & 0x0008);
852 if (!isset($ThisFileInfo[
'video'][
'resolution_x']) || !isset($ThisFileInfo[
'video'][
'resolution_y'])) {
853 $ThisFileInfo[
'video'][
'resolution_x'] = $atomstructure[
'width'];
854 $ThisFileInfo[
'video'][
'resolution_y'] = $atomstructure[
'height'];
856 if ($atomstructure[
'flags'][
'enabled'] == 1) {
857 $ThisFileInfo[
'video'][
'resolution_x'] = max($ThisFileInfo[
'video'][
'resolution_x'], $atomstructure[
'width']);
858 $ThisFileInfo[
'video'][
'resolution_y'] = max($ThisFileInfo[
'video'][
'resolution_y'], $atomstructure[
'height']);
860 if (!empty($ThisFileInfo[
'video'][
'resolution_x']) && !empty($ThisFileInfo[
'video'][
'resolution_y'])) {
861 $ThisFileInfo[
'quicktime'][
'video'][
'resolution_x'] = $ThisFileInfo[
'video'][
'resolution_x'];
862 $ThisFileInfo[
'quicktime'][
'video'][
'resolution_y'] = $ThisFileInfo[
'video'][
'resolution_y'];
864 unset($ThisFileInfo[
'video'][
'resolution_x']);
865 unset($ThisFileInfo[
'video'][
'resolution_y']);
866 unset($ThisFileInfo[
'quicktime'][
'video']);
873 $NextTagPosition = strpos($atomdata,
'�');
874 while ($NextTagPosition < strlen($atomdata)) {
876 if ($metaItemSize == -4) {
879 $metaItemRaw = substr($atomdata, $NextTagPosition, $metaItemSize);
880 $metaItemKey = substr($metaItemRaw, 0, 4);
881 $metaItemData = substr($metaItemRaw, 20);
882 $NextTagPosition += $metaItemSize + 4;
889 $atomstructure[
'signature'] = substr($atomdata, 0, 4);
891 $atomstructure[
'fourcc'] = substr($atomdata, 8, 4);
921 $atomstructure[
'ctyp'] = substr($atomdata, 0, 4);
922 switch ($atomstructure[
'ctyp']) {
924 $ThisFileInfo[
'video'][
'dataformat'] =
'quicktimevr';
937 $ThisFileInfo[
'quicktime'][
'hinting'] =
true;
941 for ($i = 0; $i < ($atomstructure[
'size'] - 8); $i += 4) {
952 $atomstructure[
'data'] = $atomdata;
956 $ThisFileInfo[
'warning'][] =
'Unknown QuickTime atom type: "'.$atomname.
'" at offset '.$baseoffset;
957 $atomstructure[
'data'] = $atomdata;
960 array_pop($atomHierarchy);
961 return $atomstructure;
CopyToAppropriateCommentsSection($keyname, $data, &$ThisFileInfo)
QuicktimeAudioCodecLookup($codecid)
FixedPoint16_16($rawdata)
QuicktimeColorNameLookup($colordepthid)
NoNullString($nullterminatedstring)
Pascal2String($pascalstring)
QuicktimeLanguageLookup($languageid)
QuicktimeParseContainerAtom($atomdata, &$ThisFileInfo, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms)
BigEndian2Int($byteword, $synchsafe=false, $signed=false)
QuicktimeVideoCodecLookup($codecid)
QuicktimeDCOMLookup($compressionid)