/** * @param type $BlockData * * @return bool */ private function parseVORBIS_COMMENT($BlockData) { $info =& $this->getid3->info; $getid3_ogg = new Ogg($this->getid3); if ($this->isDependencyFor('matroska')) { $getid3_ogg->data_string_flag = true; $getid3_ogg->data_string = $this->data_string; } $getid3_ogg->ParseVorbisComments(); if (isset($info['ogg'])) { unset($info['ogg']['comments_raw']); $info['flac']['VORBIS_COMMENT'] = $info['ogg']; unset($info['ogg']); } unset($getid3_ogg); return true; }
/** * @return bool */ public function analyze() { $info =& $this->getid3->info; // parse container try { $this->parseEBML($info); } catch (DefaultException $e) { $info['error'][] = 'EBML parser: ' . $e->getMessage(); } // calculate playtime if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { foreach ($info['matroska']['info'] as $key => $infoarray) { if (isset($infoarray['Duration'])) { // TimecodeScale is how many nanoseconds each Duration unit is $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000); break; } } } // extract tags if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) { foreach ($info['matroska']['tags'] as $key => $infoarray) { $this->ExtractCommentsSimpleTag($infoarray); } } // process tracks if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) { foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) { $track_info = array(); $track_info['dataformat'] = self::MatroskaCodecIDtoCommonName($trackarray['CodecID']); $track_info['default'] = isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true; if (isset($trackarray['Name'])) { $track_info['name'] = $trackarray['Name']; } switch ($trackarray['TrackType']) { case 1: // Video $track_info['resolution_x'] = $trackarray['PixelWidth']; $track_info['resolution_y'] = $trackarray['PixelHeight']; if (isset($trackarray['DisplayWidth'])) { $track_info['display_x'] = $trackarray['DisplayWidth']; } if (isset($trackarray['DisplayHeight'])) { $track_info['display_y'] = $trackarray['DisplayHeight']; } if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } switch ($trackarray['CodecID']) { case 'V_MS/VFW/FOURCC': if (!class_exists('GetId3\\Module\\AudioVideo\\Riff')) { $this->getid3->warning('Unable to parse codec private data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "' . str_replace('_', DIRECTORY_SEPARATOR, 'GetId3\\Module\\AudioVideo\\Riff') . '.php"'); break; } $parsed = Riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']); $track_info['codec'] = Riff::RIFFfourccLookup($parsed['fourcc']); $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed; break; /*case 'V_MPEG4/ISO/AVC': $h264['profile'] = GetId3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 1, 1)); $h264['level'] = GetId3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 3, 1)); $rn = GetId3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 4, 1)); $h264['NALUlength'] = ($rn & 3) + 1; $rn = GetId3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 5, 1)); $nsps = ($rn & 31); $offset = 6; for ($i = 0; $i < $nsps; $i ++) { $length = GetId3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2)); $h264['SPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length); $offset += 2 + $length; } $npps = GetId3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 1)); $offset += 1; for ($i = 0; $i < $npps; $i ++) { $length = GetId3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2)); $h264['PPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length); $offset += 2 + $length; } $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $h264; break;*/ } $info['video']['streams'][] = $track_info; break; case 2: // Audio $track_info['sample_rate'] = isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0; $track_info['channels'] = isset($trackarray['Channels']) ? $trackarray['Channels'] : 1; $track_info['language'] = isset($trackarray['Language']) ? $trackarray['Language'] : 'eng'; if (isset($trackarray['BitDepth'])) { $track_info['bits_per_sample'] = $trackarray['BitDepth']; } if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } switch ($trackarray['CodecID']) { case 'A_PCM/INT/LIT': case 'A_PCM/INT/BIG': $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth']; break; case 'A_AC3': case 'A_DTS': case 'A_MPEG/L3': case 'A_MPEG/L2': case 'A_FLAC': $class = 'Helpers\\GetId3\\Module\\Audio\\' . ucfirst($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']); if (!class_exists($class)) { $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio.' . $track_info['dataformat'] . '.php"'); break; } if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) { $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because $info[matroska][track_data_offsets][' . $trackarray['TrackNumber'] . '] not set'); break; } // create temp instance $getid3_temp = new GetId3Core(); if ($track_info['dataformat'] != 'flac') { $getid3_temp->openfile($this->getid3->filename); } $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset']; if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') { $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length']; } // analyze $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat']; $getid3_audio = new $class($getid3_temp, __CLASS__); if ($track_info['dataformat'] == 'flac') { $getid3_audio->AnalyzeString($trackarray['CodecPrivate']); } else { $getid3_audio->analyze(); } if (!empty($getid3_temp->info[$header_data_key])) { $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key]; if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) { foreach ($getid3_temp->info['audio'] as $key => $value) { $track_info[$key] = $value; } } } else { $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because ' . $class . '::Analyze() failed at offset ' . $getid3_temp->info['avdataoffset']); } // copy errors and warnings if (!empty($getid3_temp->info['error'])) { foreach ($getid3_temp->info['error'] as $newerror) { $this->getid3->warning($class . '() says: [' . $newerror . ']'); } } if (!empty($getid3_temp->info['warning'])) { foreach ($getid3_temp->info['warning'] as $newerror) { if ($track_info['dataformat'] == 'mp3' && preg_match('/^Probable truncated file: expecting \\d+ bytes of audio data, only found \\d+ \\(short by \\d+ bytes\\)$/', $newerror)) { // LAME/Xing header is probably set, but audio data is chunked into Matroska file and near-impossible to verify if audio stream is complete, so ignore useless warning continue; } $this->getid3->warning($class . '() says: [' . $newerror . ']'); } } unset($getid3_temp, $getid3_audio); break; case 'A_AAC': case 'A_AAC/MPEG2/LC': case 'A_AAC/MPEG4/LC': case 'A_AAC/MPEG4/LC/SBR': $this->getid3->warning($trackarray['CodecID'] . ' audio data contains no header, audio/video bitrates can\'t be calculated'); break; case 'A_VORBIS': if (!isset($trackarray['CodecPrivate'])) { $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because CodecPrivate data not set'); break; } $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1); if ($vorbis_offset === false) { $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because CodecPrivate data does not contain "vorbis" keyword'); break; } $vorbis_offset -= 1; if (!class_exists('Helpers\\GetId3\\Module\\Audio\\Ogg')) { $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "Helpers\\GetId3\\Module\\Audio\\Ogg.php"'); break; } // create temp instance $getid3_temp = new GetId3Core(); // analyze $getid3_ogg = new Ogg($getid3_temp); $oggpageinfo['page_seqno'] = 0; $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo); if (!empty($getid3_temp->info['ogg'])) { $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg']; if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) { foreach ($getid3_temp->info['audio'] as $key => $value) { $track_info[$key] = $value; } } } // copy errors and warnings if (!empty($getid3_temp->info['error'])) { foreach ($getid3_temp->info['error'] as $newerror) { $this->getid3->warning('getid3_ogg() says: [' . $newerror . ']'); } } if (!empty($getid3_temp->info['warning'])) { foreach ($getid3_temp->info['warning'] as $newerror) { $this->getid3->warning('getid3_ogg() says: [' . $newerror . ']'); } } if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) { $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal']; } unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset); break; case 'A_MS/ACM': if (!class_exists('GetId3\\Module\\AudioVideo\\Riff')) { $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "' . str_replace('_', DIRECTORY_SEPARATOR, 'GetId3\\Module\\AudioVideo\\Riff') . '.php"'); break; } $parsed = Riff::RIFFparseWAVEFORMATex($trackarray['CodecPrivate']); foreach ($parsed as $key => $value) { if ($key != 'raw') { $track_info[$key] = $value; } } $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed; break; default: $this->getid3->warning('Unhandled audio type "' . (isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '') . '"'); } $info['audio']['streams'][] = $track_info; break; } } if (!empty($info['video']['streams'])) { $info['video'] = self::getDefaultStreamInfo($info['video']['streams']); } if (!empty($info['audio']['streams'])) { $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']); } } // determine mime type if (!empty($info['video']['streams'])) { $info['mime_type'] = $info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska'; } elseif (!empty($info['audio']['streams'])) { $info['mime_type'] = $info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska'; } elseif (isset($info['mime_type'])) { unset($info['mime_type']); } return true; }