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