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