Edit File by line
/home/zeestwma/ceyloniy.../wp-inclu.../ID3
File: module.audio-video.quicktime.php
<?php
[0] Fix | Delete
[1] Fix | Delete
/////////////////////////////////////////////////////////////////
[2] Fix | Delete
/// getID3() by James Heinrich <info@getid3.org> //
[3] Fix | Delete
// available at https://github.com/JamesHeinrich/getID3 //
[4] Fix | Delete
// or https://www.getid3.org //
[5] Fix | Delete
// or http://getid3.sourceforge.net //
[6] Fix | Delete
// see readme.txt for more details //
[7] Fix | Delete
/////////////////////////////////////////////////////////////////
[8] Fix | Delete
// //
[9] Fix | Delete
// module.audio-video.quicktime.php //
[10] Fix | Delete
// module for analyzing Quicktime and MP3-in-MP4 files //
[11] Fix | Delete
// dependencies: module.audio.mp3.php //
[12] Fix | Delete
// dependencies: module.tag.id3v2.php //
[13] Fix | Delete
// ///
[14] Fix | Delete
/////////////////////////////////////////////////////////////////
[15] Fix | Delete
[16] Fix | Delete
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
[17] Fix | Delete
exit;
[18] Fix | Delete
}
[19] Fix | Delete
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
[20] Fix | Delete
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); // needed for ISO 639-2 language code lookup
[21] Fix | Delete
[22] Fix | Delete
class getid3_quicktime extends getid3_handler
[23] Fix | Delete
{
[24] Fix | Delete
[25] Fix | Delete
/** audio-video.quicktime
[26] Fix | Delete
* return all parsed data from all atoms if true, otherwise just returned parsed metadata
[27] Fix | Delete
*
[28] Fix | Delete
* @var bool
[29] Fix | Delete
*/
[30] Fix | Delete
public $ReturnAtomData = false;
[31] Fix | Delete
[32] Fix | Delete
/** audio-video.quicktime
[33] Fix | Delete
* return all parsed data from all atoms if true, otherwise just returned parsed metadata
[34] Fix | Delete
*
[35] Fix | Delete
* @var bool
[36] Fix | Delete
*/
[37] Fix | Delete
public $ParseAllPossibleAtoms = false;
[38] Fix | Delete
[39] Fix | Delete
/**
[40] Fix | Delete
* real ugly, but so is the QuickTime structure that stores keys and values in different multi-nested locations that are hard to relate to each other
[41] Fix | Delete
* https://github.com/JamesHeinrich/getID3/issues/214
[42] Fix | Delete
*
[43] Fix | Delete
* @var int
[44] Fix | Delete
*/
[45] Fix | Delete
private $metaDATAkey = 1;
[46] Fix | Delete
[47] Fix | Delete
/**
[48] Fix | Delete
* @return bool
[49] Fix | Delete
*/
[50] Fix | Delete
public function Analyze() {
[51] Fix | Delete
$info = &$this->getid3->info;
[52] Fix | Delete
[53] Fix | Delete
$this->metaDATAkey = 1;
[54] Fix | Delete
$info['fileformat'] = 'quicktime';
[55] Fix | Delete
$info['quicktime']['hinting'] = false;
[56] Fix | Delete
$info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
[57] Fix | Delete
[58] Fix | Delete
$this->fseek($info['avdataoffset']);
[59] Fix | Delete
[60] Fix | Delete
$offset = 0;
[61] Fix | Delete
$atomcounter = 0;
[62] Fix | Delete
$atom_data_read_buffer_size = $info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : $this->getid3->option_fread_buffer_size * 1024; // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]
[63] Fix | Delete
while ($offset < $info['avdataend']) {
[64] Fix | Delete
if (!getid3_lib::intValueSupported($offset)) {
[65] Fix | Delete
$this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions');
[66] Fix | Delete
break;
[67] Fix | Delete
}
[68] Fix | Delete
$this->fseek($offset);
[69] Fix | Delete
$AtomHeader = $this->fread(8);
[70] Fix | Delete
[71] Fix | Delete
// https://github.com/JamesHeinrich/getID3/issues/382
[72] Fix | Delete
// Atom sizes are stored as 32-bit number in most cases, but sometimes (notably for "mdat")
[73] Fix | Delete
// a 64-bit value is required, in which case the normal 32-bit size field is set to 0x00000001
[74] Fix | Delete
// and the 64-bit "real" size value is the next 8 bytes.
[75] Fix | Delete
$atom_size_extended_bytes = 0;
[76] Fix | Delete
$atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
[77] Fix | Delete
$atomname = substr($AtomHeader, 4, 4);
[78] Fix | Delete
if ($atomsize == 1) {
[79] Fix | Delete
$atom_size_extended_bytes = 8;
[80] Fix | Delete
$atomsize = getid3_lib::BigEndian2Int($this->fread($atom_size_extended_bytes));
[81] Fix | Delete
}
[82] Fix | Delete
[83] Fix | Delete
if (($offset + $atomsize) > $info['avdataend']) {
[84] Fix | Delete
$info['quicktime'][$atomname]['name'] = $atomname;
[85] Fix | Delete
$info['quicktime'][$atomname]['size'] = $atomsize;
[86] Fix | Delete
$info['quicktime'][$atomname]['offset'] = $offset;
[87] Fix | Delete
$this->error('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)');
[88] Fix | Delete
return false;
[89] Fix | Delete
}
[90] Fix | Delete
if ($atomsize == 0) {
[91] Fix | Delete
// Furthermore, for historical reasons the list of atoms is optionally
[92] Fix | Delete
// terminated by a 32-bit integer set to 0. If you are writing a program
[93] Fix | Delete
// to read user data atoms, you should allow for the terminating 0.
[94] Fix | Delete
$info['quicktime'][$atomname]['name'] = $atomname;
[95] Fix | Delete
$info['quicktime'][$atomname]['size'] = $atomsize;
[96] Fix | Delete
$info['quicktime'][$atomname]['offset'] = $offset;
[97] Fix | Delete
break;
[98] Fix | Delete
}
[99] Fix | Delete
$atomHierarchy = array();
[100] Fix | Delete
$parsedAtomData = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize - $atom_size_extended_bytes, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
[101] Fix | Delete
$parsedAtomData['name'] = $atomname;
[102] Fix | Delete
$parsedAtomData['size'] = $atomsize;
[103] Fix | Delete
$parsedAtomData['offset'] = $offset;
[104] Fix | Delete
if ($atom_size_extended_bytes) {
[105] Fix | Delete
$parsedAtomData['xsize_bytes'] = $atom_size_extended_bytes;
[106] Fix | Delete
}
[107] Fix | Delete
if (in_array($atomname, array('uuid'))) {
[108] Fix | Delete
@$info['quicktime'][$atomname][] = $parsedAtomData;
[109] Fix | Delete
} else {
[110] Fix | Delete
$info['quicktime'][$atomname] = $parsedAtomData;
[111] Fix | Delete
}
[112] Fix | Delete
[113] Fix | Delete
$offset += $atomsize;
[114] Fix | Delete
$atomcounter++;
[115] Fix | Delete
}
[116] Fix | Delete
[117] Fix | Delete
if (!empty($info['avdataend_tmp'])) {
[118] Fix | Delete
// this value is assigned to a temp value and then erased because
[119] Fix | Delete
// otherwise any atoms beyond the 'mdat' atom would not get parsed
[120] Fix | Delete
$info['avdataend'] = $info['avdataend_tmp'];
[121] Fix | Delete
unset($info['avdataend_tmp']);
[122] Fix | Delete
}
[123] Fix | Delete
[124] Fix | Delete
if (isset($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
[125] Fix | Delete
$durations = $this->quicktime_time_to_sample_table($info);
[126] Fix | Delete
for ($i = 0; $i < count($info['quicktime']['comments']['chapters']); $i++) {
[127] Fix | Delete
$bookmark = array();
[128] Fix | Delete
$bookmark['title'] = $info['quicktime']['comments']['chapters'][$i];
[129] Fix | Delete
if (isset($durations[$i])) {
[130] Fix | Delete
$bookmark['duration_sample'] = $durations[$i]['sample_duration'];
[131] Fix | Delete
if ($i > 0) {
[132] Fix | Delete
$bookmark['start_sample'] = $info['quicktime']['bookmarks'][($i - 1)]['start_sample'] + $info['quicktime']['bookmarks'][($i - 1)]['duration_sample'];
[133] Fix | Delete
} else {
[134] Fix | Delete
$bookmark['start_sample'] = 0;
[135] Fix | Delete
}
[136] Fix | Delete
if ($time_scale = $this->quicktime_bookmark_time_scale($info)) {
[137] Fix | Delete
$bookmark['duration_seconds'] = $bookmark['duration_sample'] / $time_scale;
[138] Fix | Delete
$bookmark['start_seconds'] = $bookmark['start_sample'] / $time_scale;
[139] Fix | Delete
}
[140] Fix | Delete
}
[141] Fix | Delete
$info['quicktime']['bookmarks'][] = $bookmark;
[142] Fix | Delete
}
[143] Fix | Delete
}
[144] Fix | Delete
[145] Fix | Delete
if (isset($info['quicktime']['temp_meta_key_names'])) {
[146] Fix | Delete
unset($info['quicktime']['temp_meta_key_names']);
[147] Fix | Delete
}
[148] Fix | Delete
[149] Fix | Delete
if (!empty($info['quicktime']['comments']['location.ISO6709'])) {
[150] Fix | Delete
// https://en.wikipedia.org/wiki/ISO_6709
[151] Fix | Delete
foreach ($info['quicktime']['comments']['location.ISO6709'] as $ISO6709string) {
[152] Fix | Delete
$ISO6709parsed = array('latitude'=>false, 'longitude'=>false, 'altitude'=>false);
[153] Fix | Delete
if (preg_match('#^([\\+\\-])([0-9]{2}|[0-9]{4}|[0-9]{6})(\\.[0-9]+)?([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?(([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?)?/$#', $ISO6709string, $matches)) {
[154] Fix | Delete
@list($dummy, $lat_sign, $lat_deg, $lat_deg_dec, $lon_sign, $lon_deg, $lon_deg_dec, $dummy, $alt_sign, $alt_deg, $alt_deg_dec) = $matches;
[155] Fix | Delete
[156] Fix | Delete
if (strlen($lat_deg) == 2) { // [+-]DD.D
[157] Fix | Delete
$ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (float) (ltrim($lat_deg, '0').$lat_deg_dec);
[158] Fix | Delete
} elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M
[159] Fix | Delete
$ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (int) ltrim(substr($lat_deg, 0, 2), '0') + ((float) (ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec) / 60);
[160] Fix | Delete
} elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S
[161] Fix | Delete
$ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (int) ltrim(substr($lat_deg, 0, 2), '0') + ((int) ltrim(substr($lat_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec) / 3600);
[162] Fix | Delete
}
[163] Fix | Delete
[164] Fix | Delete
if (strlen($lon_deg) == 3) { // [+-]DDD.D
[165] Fix | Delete
$ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (float) (ltrim($lon_deg, '0').$lon_deg_dec);
[166] Fix | Delete
} elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M
[167] Fix | Delete
$ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (int) ltrim(substr($lon_deg, 0, 2), '0') + ((float) (ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec) / 60);
[168] Fix | Delete
} elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S
[169] Fix | Delete
$ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (int) ltrim(substr($lon_deg, 0, 2), '0') + ((int) ltrim(substr($lon_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec) / 3600);
[170] Fix | Delete
}
[171] Fix | Delete
[172] Fix | Delete
if (strlen($alt_deg) == 3) { // [+-]DDD.D
[173] Fix | Delete
$ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (float) (ltrim($alt_deg, '0').$alt_deg_dec);
[174] Fix | Delete
} elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M
[175] Fix | Delete
$ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (int) ltrim(substr($alt_deg, 0, 2), '0') + ((float) (ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec) / 60);
[176] Fix | Delete
} elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S
[177] Fix | Delete
$ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (int) ltrim(substr($alt_deg, 0, 2), '0') + ((int) ltrim(substr($alt_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec) / 3600);
[178] Fix | Delete
}
[179] Fix | Delete
[180] Fix | Delete
foreach (array('latitude', 'longitude', 'altitude') as $key) {
[181] Fix | Delete
if ($ISO6709parsed[$key] !== false) {
[182] Fix | Delete
$value = (($lat_sign == '-') ? -1 : 1) * floatval($ISO6709parsed[$key]);
[183] Fix | Delete
if (!isset($info['quicktime']['comments']['gps_'.$key]) || !in_array($value, $info['quicktime']['comments']['gps_'.$key])) {
[184] Fix | Delete
@$info['quicktime']['comments']['gps_'.$key][] = (($lat_sign == '-') ? -1 : 1) * floatval($ISO6709parsed[$key]);
[185] Fix | Delete
}
[186] Fix | Delete
}
[187] Fix | Delete
}
[188] Fix | Delete
}
[189] Fix | Delete
if ($ISO6709parsed['latitude'] === false) {
[190] Fix | Delete
$this->warning('location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug');
[191] Fix | Delete
}
[192] Fix | Delete
break;
[193] Fix | Delete
}
[194] Fix | Delete
}
[195] Fix | Delete
[196] Fix | Delete
if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) {
[197] Fix | Delete
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
[198] Fix | Delete
}
[199] Fix | Delete
if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
[200] Fix | Delete
$info['audio']['bitrate'] = $info['bitrate'];
[201] Fix | Delete
}
[202] Fix | Delete
if (!empty($info['bitrate']) && !empty($info['audio']['bitrate']) && empty($info['video']['bitrate']) && !empty($info['video']['frame_rate']) && !empty($info['video']['resolution_x']) && ($info['bitrate'] > $info['audio']['bitrate'])) {
[203] Fix | Delete
$info['video']['bitrate'] = $info['bitrate'] - $info['audio']['bitrate'];
[204] Fix | Delete
}
[205] Fix | Delete
if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
[206] Fix | Delete
foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
[207] Fix | Delete
$samples_per_second = $samples_count / $info['playtime_seconds'];
[208] Fix | Delete
if ($samples_per_second > 240) {
[209] Fix | Delete
// has to be audio samples
[210] Fix | Delete
} else {
[211] Fix | Delete
$info['video']['frame_rate'] = $samples_per_second;
[212] Fix | Delete
break;
[213] Fix | Delete
}
[214] Fix | Delete
}
[215] Fix | Delete
}
[216] Fix | Delete
if ($info['audio']['dataformat'] == 'mp4') {
[217] Fix | Delete
$info['fileformat'] = 'mp4';
[218] Fix | Delete
if (empty($info['video']['resolution_x'])) {
[219] Fix | Delete
$info['mime_type'] = 'audio/mp4';
[220] Fix | Delete
unset($info['video']['dataformat']);
[221] Fix | Delete
} else {
[222] Fix | Delete
$info['mime_type'] = 'video/mp4';
[223] Fix | Delete
}
[224] Fix | Delete
}
[225] Fix | Delete
if (!empty($info['quicktime']['ftyp']['signature']) && in_array($info['quicktime']['ftyp']['signature'], array('heic','heix','hevc','hevx','heim','heis','hevm','hevs'))) {
[226] Fix | Delete
if ($info['mime_type'] == 'video/quicktime') { // default value, as we
[227] Fix | Delete
// https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format
[228] Fix | Delete
$this->error('HEIF files not currently supported');
[229] Fix | Delete
switch ($info['quicktime']['ftyp']['signature']) {
[230] Fix | Delete
// https://github.com/strukturag/libheif/issues/83 (comment by Dirk Farin 2018-09-14)
[231] Fix | Delete
case 'heic': // the usual HEIF images
[232] Fix | Delete
case 'heix': // 10bit images, or anything that uses h265 with range extension
[233] Fix | Delete
case 'hevc': // brands for image sequences
[234] Fix | Delete
case 'hevx': // brands for image sequences
[235] Fix | Delete
case 'heim': // multiview
[236] Fix | Delete
case 'heis': // scalable
[237] Fix | Delete
case 'hevm': // multiview sequence
[238] Fix | Delete
case 'hevs': // scalable sequence
[239] Fix | Delete
$info['fileformat'] = 'heif';
[240] Fix | Delete
$info['mime_type'] = 'image/heif';
[241] Fix | Delete
break;
[242] Fix | Delete
}
[243] Fix | Delete
}
[244] Fix | Delete
}
[245] Fix | Delete
[246] Fix | Delete
if (!$this->ReturnAtomData) {
[247] Fix | Delete
unset($info['quicktime']['moov']);
[248] Fix | Delete
}
[249] Fix | Delete
[250] Fix | Delete
if (empty($info['audio']['dataformat']) && !empty($info['quicktime']['audio'])) {
[251] Fix | Delete
$info['audio']['dataformat'] = 'quicktime';
[252] Fix | Delete
}
[253] Fix | Delete
if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
[254] Fix | Delete
$info['video']['dataformat'] = 'quicktime';
[255] Fix | Delete
}
[256] Fix | Delete
if (isset($info['video']) && ($info['mime_type'] == 'audio/mp4') && empty($info['video']['resolution_x']) && empty($info['video']['resolution_y'])) {
[257] Fix | Delete
unset($info['video']);
[258] Fix | Delete
}
[259] Fix | Delete
[260] Fix | Delete
return true;
[261] Fix | Delete
}
[262] Fix | Delete
[263] Fix | Delete
/**
[264] Fix | Delete
* @param string $atomname
[265] Fix | Delete
* @param int $atomsize
[266] Fix | Delete
* @param string $atom_data
[267] Fix | Delete
* @param int $baseoffset
[268] Fix | Delete
* @param array $atomHierarchy
[269] Fix | Delete
* @param bool $ParseAllPossibleAtoms
[270] Fix | Delete
*
[271] Fix | Delete
* @return array|false
[272] Fix | Delete
*/
[273] Fix | Delete
public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
[274] Fix | Delete
// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
[275] Fix | Delete
// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
[276] Fix | Delete
[277] Fix | Delete
$info = &$this->getid3->info;
[278] Fix | Delete
[279] Fix | Delete
$atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see https://www.getid3.org/phpBB3/viewtopic.php?t=1717
[280] Fix | Delete
array_push($atomHierarchy, $atomname);
[281] Fix | Delete
$atom_structure = array();
[282] Fix | Delete
$atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
[283] Fix | Delete
$atom_structure['name'] = $atomname;
[284] Fix | Delete
$atom_structure['size'] = $atomsize;
[285] Fix | Delete
$atom_structure['offset'] = $baseoffset;
[286] Fix | Delete
if (substr($atomname, 0, 3) == "\x00\x00\x00") {
[287] Fix | Delete
// https://github.com/JamesHeinrich/getID3/issues/139
[288] Fix | Delete
$atomname = getid3_lib::BigEndian2Int($atomname);
[289] Fix | Delete
$atom_structure['name'] = $atomname;
[290] Fix | Delete
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
[291] Fix | Delete
} else {
[292] Fix | Delete
switch ($atomname) {
[293] Fix | Delete
case 'moov': // MOVie container atom
[294] Fix | Delete
case 'moof': // MOvie Fragment box
[295] Fix | Delete
case 'trak': // TRAcK container atom
[296] Fix | Delete
case 'traf': // TRAck Fragment box
[297] Fix | Delete
case 'clip': // CLIPping container atom
[298] Fix | Delete
case 'matt': // track MATTe container atom
[299] Fix | Delete
case 'edts': // EDiTS container atom
[300] Fix | Delete
case 'tref': // Track REFerence container atom
[301] Fix | Delete
case 'mdia': // MeDIA container atom
[302] Fix | Delete
case 'minf': // Media INFormation container atom
[303] Fix | Delete
case 'dinf': // Data INFormation container atom
[304] Fix | Delete
case 'nmhd': // Null Media HeaDer container atom
[305] Fix | Delete
case 'udta': // User DaTA container atom
[306] Fix | Delete
case 'cmov': // Compressed MOVie container atom
[307] Fix | Delete
case 'rmra': // Reference Movie Record Atom
[308] Fix | Delete
case 'rmda': // Reference Movie Descriptor Atom
[309] Fix | Delete
case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
[310] Fix | Delete
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
[311] Fix | Delete
break;
[312] Fix | Delete
[313] Fix | Delete
case 'ilst': // Item LiST container atom
[314] Fix | Delete
if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) {
[315] Fix | Delete
// some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
[316] Fix | Delete
$allnumericnames = true;
[317] Fix | Delete
foreach ($atom_structure['subatoms'] as $subatomarray) {
[318] Fix | Delete
if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
[319] Fix | Delete
$allnumericnames = false;
[320] Fix | Delete
break;
[321] Fix | Delete
}
[322] Fix | Delete
}
[323] Fix | Delete
if ($allnumericnames) {
[324] Fix | Delete
$newData = array();
[325] Fix | Delete
foreach ($atom_structure['subatoms'] as $subatomarray) {
[326] Fix | Delete
foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
[327] Fix | Delete
unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
[328] Fix | Delete
$newData[$subatomarray['name']] = $newData_subatomarray;
[329] Fix | Delete
break;
[330] Fix | Delete
}
[331] Fix | Delete
}
[332] Fix | Delete
$atom_structure['data'] = $newData;
[333] Fix | Delete
unset($atom_structure['subatoms']);
[334] Fix | Delete
}
[335] Fix | Delete
}
[336] Fix | Delete
break;
[337] Fix | Delete
[338] Fix | Delete
case 'stbl': // Sample TaBLe container atom
[339] Fix | Delete
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
[340] Fix | Delete
$isVideo = false;
[341] Fix | Delete
$framerate = 0;
[342] Fix | Delete
$framecount = 0;
[343] Fix | Delete
foreach ($atom_structure['subatoms'] as $key => $value_array) {
[344] Fix | Delete
if (isset($value_array['sample_description_table'])) {
[345] Fix | Delete
foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
[346] Fix | Delete
if (isset($value_array2['data_format'])) {
[347] Fix | Delete
switch ($value_array2['data_format']) {
[348] Fix | Delete
case 'avc1':
[349] Fix | Delete
case 'mp4v':
[350] Fix | Delete
// video data
[351] Fix | Delete
$isVideo = true;
[352] Fix | Delete
break;
[353] Fix | Delete
case 'mp4a':
[354] Fix | Delete
// audio data
[355] Fix | Delete
break;
[356] Fix | Delete
}
[357] Fix | Delete
}
[358] Fix | Delete
}
[359] Fix | Delete
} elseif (isset($value_array['time_to_sample_table'])) {
[360] Fix | Delete
foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
[361] Fix | Delete
if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0) && !empty($info['quicktime']['time_scale'])) {
[362] Fix | Delete
$framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
[363] Fix | Delete
$framecount = $value_array2['sample_count'];
[364] Fix | Delete
}
[365] Fix | Delete
}
[366] Fix | Delete
}
[367] Fix | Delete
}
[368] Fix | Delete
if ($isVideo && $framerate) {
[369] Fix | Delete
$info['quicktime']['video']['frame_rate'] = $framerate;
[370] Fix | Delete
$info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
[371] Fix | Delete
}
[372] Fix | Delete
if ($isVideo && $framecount) {
[373] Fix | Delete
$info['quicktime']['video']['frame_count'] = $framecount;
[374] Fix | Delete
}
[375] Fix | Delete
break;
[376] Fix | Delete
[377] Fix | Delete
[378] Fix | Delete
case "\xA9".'alb': // ALBum
[379] Fix | Delete
case "\xA9".'ART': //
[380] Fix | Delete
case "\xA9".'art': // ARTist
[381] Fix | Delete
case "\xA9".'aut': //
[382] Fix | Delete
case "\xA9".'cmt': // CoMmenT
[383] Fix | Delete
case "\xA9".'com': // COMposer
[384] Fix | Delete
case "\xA9".'cpy': //
[385] Fix | Delete
case "\xA9".'day': // content created year
[386] Fix | Delete
case "\xA9".'dir': //
[387] Fix | Delete
case "\xA9".'ed1': //
[388] Fix | Delete
case "\xA9".'ed2': //
[389] Fix | Delete
case "\xA9".'ed3': //
[390] Fix | Delete
case "\xA9".'ed4': //
[391] Fix | Delete
case "\xA9".'ed5': //
[392] Fix | Delete
case "\xA9".'ed6': //
[393] Fix | Delete
case "\xA9".'ed7': //
[394] Fix | Delete
case "\xA9".'ed8': //
[395] Fix | Delete
case "\xA9".'ed9': //
[396] Fix | Delete
case "\xA9".'enc': //
[397] Fix | Delete
case "\xA9".'fmt': //
[398] Fix | Delete
case "\xA9".'gen': // GENre
[399] Fix | Delete
case "\xA9".'grp': // GRouPing
[400] Fix | Delete
case "\xA9".'hst': //
[401] Fix | Delete
case "\xA9".'inf': //
[402] Fix | Delete
case "\xA9".'lyr': // LYRics
[403] Fix | Delete
case "\xA9".'mak': //
[404] Fix | Delete
case "\xA9".'mod': //
[405] Fix | Delete
case "\xA9".'nam': // full NAMe
[406] Fix | Delete
case "\xA9".'ope': //
[407] Fix | Delete
case "\xA9".'PRD': //
[408] Fix | Delete
case "\xA9".'prf': //
[409] Fix | Delete
case "\xA9".'req': //
[410] Fix | Delete
case "\xA9".'src': //
[411] Fix | Delete
case "\xA9".'swr': //
[412] Fix | Delete
case "\xA9".'too': // encoder
[413] Fix | Delete
case "\xA9".'trk': // TRacK
[414] Fix | Delete
case "\xA9".'url': //
[415] Fix | Delete
case "\xA9".'wrn': //
[416] Fix | Delete
case "\xA9".'wrt': // WRiTer
[417] Fix | Delete
case '----': // itunes specific
[418] Fix | Delete
case 'aART': // Album ARTist
[419] Fix | Delete
case 'akID': // iTunes store account type
[420] Fix | Delete
case 'apID': // Purchase Account
[421] Fix | Delete
case 'atID': //
[422] Fix | Delete
case 'catg': // CaTeGory
[423] Fix | Delete
case 'cmID': //
[424] Fix | Delete
case 'cnID': //
[425] Fix | Delete
case 'covr': // COVeR artwork
[426] Fix | Delete
case 'cpil': // ComPILation
[427] Fix | Delete
case 'cprt': // CoPyRighT
[428] Fix | Delete
case 'desc': // DESCription
[429] Fix | Delete
case 'disk': // DISK number
[430] Fix | Delete
case 'egid': // Episode Global ID
[431] Fix | Delete
case 'geID': //
[432] Fix | Delete
case 'gnre': // GeNRE
[433] Fix | Delete
case 'hdvd': // HD ViDeo
[434] Fix | Delete
case 'keyw': // KEYWord
[435] Fix | Delete
case 'ldes': // Long DEScription
[436] Fix | Delete
case 'pcst': // PodCaST
[437] Fix | Delete
case 'pgap': // GAPless Playback
[438] Fix | Delete
case 'plID': //
[439] Fix | Delete
case 'purd': // PURchase Date
[440] Fix | Delete
case 'purl': // Podcast URL
[441] Fix | Delete
case 'rati': //
[442] Fix | Delete
case 'rndu': //
[443] Fix | Delete
case 'rpdu': //
[444] Fix | Delete
case 'rtng': // RaTiNG
[445] Fix | Delete
case 'sfID': // iTunes store country
[446] Fix | Delete
case 'soaa': // SOrt Album Artist
[447] Fix | Delete
case 'soal': // SOrt ALbum
[448] Fix | Delete
case 'soar': // SOrt ARtist
[449] Fix | Delete
case 'soco': // SOrt COmposer
[450] Fix | Delete
case 'sonm': // SOrt NaMe
[451] Fix | Delete
case 'sosn': // SOrt Show Name
[452] Fix | Delete
case 'stik': //
[453] Fix | Delete
case 'tmpo': // TeMPO (BPM)
[454] Fix | Delete
case 'trkn': // TRacK Number
[455] Fix | Delete
case 'tven': // tvEpisodeID
[456] Fix | Delete
case 'tves': // TV EpiSode
[457] Fix | Delete
case 'tvnn': // TV Network Name
[458] Fix | Delete
case 'tvsh': // TV SHow Name
[459] Fix | Delete
case 'tvsn': // TV SeasoN
[460] Fix | Delete
if ($atom_parent == 'udta') {
[461] Fix | Delete
// User data atom handler
[462] Fix | Delete
$atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
[463] Fix | Delete
$atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
[464] Fix | Delete
$atom_structure['data'] = substr($atom_data, 4);
[465] Fix | Delete
[466] Fix | Delete
$atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
[467] Fix | Delete
if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
[468] Fix | Delete
$info['comments']['language'][] = $atom_structure['language'];
[469] Fix | Delete
}
[470] Fix | Delete
} else {
[471] Fix | Delete
// Apple item list box atom handler
[472] Fix | Delete
$atomoffset = 0;
[473] Fix | Delete
if (substr($atom_data, 2, 2) == "\x10\xB5") {
[474] Fix | Delete
// not sure what it means, but observed on iPhone4 data.
[475] Fix | Delete
// Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
[476] Fix | Delete
while ($atomoffset < strlen($atom_data)) {
[477] Fix | Delete
$boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2));
[478] Fix | Delete
$boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
[479] Fix | Delete
$boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
[480] Fix | Delete
if ($boxsmallsize <= 1) {
[481] Fix | Delete
$this->warning('Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
[482] Fix | Delete
$atom_structure['data'] = null;
[483] Fix | Delete
$atomoffset = strlen($atom_data);
[484] Fix | Delete
break;
[485] Fix | Delete
}
[486] Fix | Delete
switch ($boxsmalltype) {
[487] Fix | Delete
case "\x10\xB5":
[488] Fix | Delete
$atom_structure['data'] = $boxsmalldata;
[489] Fix | Delete
break;
[490] Fix | Delete
default:
[491] Fix | Delete
$this->warning('Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset);
[492] Fix | Delete
$atom_structure['data'] = $atom_data;
[493] Fix | Delete
break;
[494] Fix | Delete
}
[495] Fix | Delete
$atomoffset += (4 + $boxsmallsize);
[496] Fix | Delete
}
[497] Fix | Delete
} else {
[498] Fix | Delete
while ($atomoffset < strlen($atom_data)) {
[499] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function