rlm@3: | rlm@3: // | Allan Hansen | rlm@3: // +----------------------------------------------------------------------+ rlm@3: // | module.audio-video.real.php | rlm@3: // | Module for analyzing Real Audio/Video files | rlm@3: // | dependencies: module.audio-video.riff.php | rlm@3: // +----------------------------------------------------------------------+ rlm@3: // rlm@3: // $Id: module.audio-video.real.php,v 1.4 2006/11/02 10:48:00 ah Exp $ rlm@3: rlm@3: rlm@3: rlm@3: class getid3_real extends getid3_handler rlm@3: { rlm@3: rlm@3: public function Analyze() { rlm@3: rlm@3: $getid3 = $this->getid3; rlm@3: rlm@3: $getid3->include_module('audio-video.riff'); rlm@3: rlm@3: $getid3->info['fileformat'] = 'real'; rlm@3: $getid3->info['bitrate'] = 0; rlm@3: $getid3->info['playtime_seconds'] = 0; rlm@3: rlm@3: fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); rlm@3: $chunk_counter = 0; rlm@3: rlm@3: while (ftell($getid3->fp) < $getid3->info['avdataend']) { rlm@3: rlm@3: $chunk_data = fread($getid3->fp, 8); rlm@3: $chunk_name = substr($chunk_data, 0, 4); rlm@3: $chunk_size = getid3_lib::BigEndian2Int(substr($chunk_data, 4, 4)); rlm@3: rlm@3: if ($chunk_name == '.ra'."\xFD") { rlm@3: $chunk_data .= fread($getid3->fp, $chunk_size - 8); rlm@3: rlm@3: if ($this->ParseOldRAheader(substr($chunk_data, 0, 128), $getid3->info['real']['old_ra_header'])) { rlm@3: rlm@3: $getid3->info['audio']['dataformat'] = 'real'; rlm@3: $getid3->info['audio']['lossless'] = false; rlm@3: $getid3->info['audio']['sample_rate'] = $getid3->info['real']['old_ra_header']['sample_rate']; rlm@3: $getid3->info['audio']['bits_per_sample'] = $getid3->info['real']['old_ra_header']['bits_per_sample']; rlm@3: $getid3->info['audio']['channels'] = $getid3->info['real']['old_ra_header']['channels']; rlm@3: rlm@3: $getid3->info['playtime_seconds'] = 60 * ($getid3->info['real']['old_ra_header']['audio_bytes'] / $getid3->info['real']['old_ra_header']['bytes_per_minute']); rlm@3: $getid3->info['audio']['bitrate'] = 8 * ($getid3->info['real']['old_ra_header']['audio_bytes'] / $getid3->info['playtime_seconds']); rlm@3: $getid3->info['audio']['codec'] = $this->RealAudioCodecFourCClookup($getid3->info['real']['old_ra_header']['fourcc'], $getid3->info['audio']['bitrate']); rlm@3: rlm@3: foreach ($getid3->info['real']['old_ra_header']['comments'] as $key => $value_array) { rlm@3: rlm@3: if (strlen(trim($value_array[0])) > 0) { rlm@3: $getid3->info['real']['comments'][$key][] = trim($value_array[0]); rlm@3: } rlm@3: } rlm@3: return true; rlm@3: } rlm@3: rlm@3: throw new getid3_exception('There was a problem parsing this RealAudio file. Please submit it for analysis to http://www.getid3.org/upload/ or info@getid3.org'); rlm@3: } rlm@3: rlm@3: $getid3->info['real']['chunks'][$chunk_counter] = array (); rlm@3: $info_real_chunks_current_chunk = &$getid3->info['real']['chunks'][$chunk_counter]; rlm@3: rlm@3: $info_real_chunks_current_chunk['name'] = $chunk_name; rlm@3: $info_real_chunks_current_chunk['offset'] = ftell($getid3->fp) - 8; rlm@3: $info_real_chunks_current_chunk['length'] = $chunk_size; rlm@3: rlm@3: if (($info_real_chunks_current_chunk['offset'] + $info_real_chunks_current_chunk['length']) > $getid3->info['avdataend']) { rlm@3: $getid3->warning('Chunk "'.$info_real_chunks_current_chunk['name'].'" at offset '.$info_real_chunks_current_chunk['offset'].' claims to be '.$info_real_chunks_current_chunk['length'].' bytes long, which is beyond end of file'); rlm@3: return false; rlm@3: } rlm@3: rlm@3: if ($chunk_size > (getid3::FREAD_BUFFER_SIZE + 8)) { rlm@3: $chunk_data .= fread($getid3->fp, getid3::FREAD_BUFFER_SIZE - 8); rlm@3: fseek($getid3->fp, $info_real_chunks_current_chunk['offset'] + $chunk_size, SEEK_SET); rlm@3: rlm@3: } elseif(($chunk_size - 8) > 0) { rlm@3: $chunk_data .= fread($getid3->fp, $chunk_size - 8); rlm@3: } rlm@3: $offset = 8; rlm@3: rlm@3: switch ($chunk_name) { rlm@3: rlm@3: case '.RMF': // RealMedia File Header rlm@3: rlm@3: $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: switch ($info_real_chunks_current_chunk['object_version']) { rlm@3: rlm@3: case 0: rlm@3: $info_real_chunks_current_chunk['file_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4)); rlm@3: $offset += 4; rlm@3: rlm@3: $info_real_chunks_current_chunk['headers_count'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4)); rlm@3: $offset += 4; rlm@3: break; rlm@3: rlm@3: default: rlm@3: //$getid3->warning('Expected .RMF-object_version to be "0", actual value is "'.$info_real_chunks_current_chunk['object_version'].'" (should not be a problem)'; rlm@3: break; rlm@3: rlm@3: } rlm@3: break; rlm@3: rlm@3: rlm@3: case 'PROP': // Properties Header rlm@3: rlm@3: $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: if ($info_real_chunks_current_chunk['object_version'] == 0) { rlm@3: rlm@3: getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset, rlm@3: array ( rlm@3: 'max_bit_rate' => 4, rlm@3: 'avg_bit_rate' => 4, rlm@3: 'max_packet_size' => 4, rlm@3: 'avg_packet_size' => 4, rlm@3: 'num_packets' => 4, rlm@3: 'duration' => 4, rlm@3: 'preroll' => 4, rlm@3: 'index_offset' => 4, rlm@3: 'data_offset' => 4, rlm@3: 'num_streams' => 2, rlm@3: 'flags_raw' => 2 rlm@3: ) rlm@3: ); rlm@3: $offset += 40; rlm@3: rlm@3: $getid3->info['playtime_seconds'] = $info_real_chunks_current_chunk['duration'] / 1000; rlm@3: if ($info_real_chunks_current_chunk['duration'] > 0) { rlm@3: $getid3->info['bitrate'] += $info_real_chunks_current_chunk['avg_bit_rate']; rlm@3: } rlm@3: rlm@3: $info_real_chunks_current_chunk['flags']['save_enabled'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0001); rlm@3: $info_real_chunks_current_chunk['flags']['perfect_play'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0002); rlm@3: $info_real_chunks_current_chunk['flags']['live_broadcast'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0004); rlm@3: } rlm@3: break; rlm@3: rlm@3: rlm@3: case 'MDPR': // Media Properties Header rlm@3: rlm@3: $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: if ($info_real_chunks_current_chunk['object_version'] == 0) { rlm@3: rlm@3: getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset, rlm@3: array ( rlm@3: 'stream_number' => 2, rlm@3: 'max_bit_rate' => 4, rlm@3: 'avg_bit_rate' => 4, rlm@3: 'max_packet_size' => 4, rlm@3: 'avg_packet_size' => 4, rlm@3: 'start_time' => 4, rlm@3: 'preroll' => 4, rlm@3: 'duration' => 4, rlm@3: 'stream_name_size' => 1 rlm@3: ) rlm@3: ); rlm@3: $offset += 31; rlm@3: rlm@3: $info_real_chunks_current_chunk['stream_name'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['stream_name_size']); rlm@3: $offset += $info_real_chunks_current_chunk['stream_name_size']; rlm@3: rlm@3: $info_real_chunks_current_chunk['mime_type_size'] = getid3_lib::BigEndian2Int($chunk_data{$offset++}); rlm@3: rlm@3: $info_real_chunks_current_chunk['mime_type'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['mime_type_size']); rlm@3: $offset += $info_real_chunks_current_chunk['mime_type_size']; rlm@3: rlm@3: $info_real_chunks_current_chunk['type_specific_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4)); rlm@3: $offset += 4; rlm@3: rlm@3: $info_real_chunks_current_chunk['type_specific_data'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['type_specific_len']); rlm@3: $offset += $info_real_chunks_current_chunk['type_specific_len']; rlm@3: rlm@3: $info_real_chunks_current_chunk_typespecificdata = &$info_real_chunks_current_chunk['type_specific_data']; rlm@3: rlm@3: switch ($info_real_chunks_current_chunk['mime_type']) { rlm@3: rlm@3: case 'video/x-pn-realvideo': rlm@3: case 'video/x-pn-multirate-realvideo': rlm@3: // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html rlm@3: rlm@3: $info_real_chunks_current_chunk['video_info'] = array (); rlm@3: $info_real_chunks_current_chunk_video_info = &$info_real_chunks_current_chunk['video_info']; rlm@3: rlm@3: getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk_video_info, $info_real_chunks_current_chunk_typespecificdata, 0, rlm@3: array ( rlm@3: 'dwSize' => 4, rlm@3: 'fourcc1' => -4, rlm@3: 'fourcc2' => -4, rlm@3: 'width' => 2, rlm@3: 'height' => 2, rlm@3: 'bits_per_sample' => 2, rlm@3: 'IGNORE-unknown1' => 2, rlm@3: 'IGNORE-unknown2' => 2, rlm@3: 'frames_per_second' => 2, rlm@3: 'IGNORE-unknown3' => 2, rlm@3: 'IGNORE-unknown4' => 2, rlm@3: 'IGNORE-unknown5' => 2, rlm@3: 'IGNORE-unknown6' => 2, rlm@3: 'IGNORE-unknown7' => 2, rlm@3: 'IGNORE-unknown8' => 2, rlm@3: 'IGNORE-unknown9' => 2 rlm@3: ) rlm@3: ); rlm@3: rlm@3: $info_real_chunks_current_chunk_video_info['codec'] = getid3_riff::RIFFfourccLookup($info_real_chunks_current_chunk_video_info['fourcc2']); rlm@3: rlm@3: $getid3->info['video']['resolution_x'] = $info_real_chunks_current_chunk_video_info['width']; rlm@3: $getid3->info['video']['resolution_y'] = $info_real_chunks_current_chunk_video_info['height']; rlm@3: $getid3->info['video']['frame_rate'] = (float)$info_real_chunks_current_chunk_video_info['frames_per_second']; rlm@3: $getid3->info['video']['codec'] = $info_real_chunks_current_chunk_video_info['codec']; rlm@3: $getid3->info['video']['bits_per_sample'] = $info_real_chunks_current_chunk_video_info['bits_per_sample']; rlm@3: break; rlm@3: rlm@3: rlm@3: case 'audio/x-pn-realaudio': rlm@3: case 'audio/x-pn-multirate-realaudio': rlm@3: rlm@3: $this->ParseOldRAheader($info_real_chunks_current_chunk_typespecificdata, $info_real_chunks_current_chunk['parsed_audio_data']); rlm@3: rlm@3: $getid3->info['audio']['sample_rate'] = $info_real_chunks_current_chunk['parsed_audio_data']['sample_rate']; rlm@3: $getid3->info['audio']['bits_per_sample'] = $info_real_chunks_current_chunk['parsed_audio_data']['bits_per_sample']; rlm@3: $getid3->info['audio']['channels'] = $info_real_chunks_current_chunk['parsed_audio_data']['channels']; rlm@3: rlm@3: if (!empty($getid3->info['audio']['dataformat'])) { rlm@3: foreach ($getid3->info['audio'] as $key => $value) { rlm@3: if ($key != 'streams') { rlm@3: $getid3->info['audio']['streams'][$info_real_chunks_current_chunk['stream_number']][$key] = $value; rlm@3: } rlm@3: } rlm@3: } rlm@3: break; rlm@3: rlm@3: rlm@3: case 'logical-fileinfo': rlm@3: rlm@3: $info_real_chunks_current_chunk['logical_fileinfo']['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 0, 4)); rlm@3: // $info_real_chunks_current_chunk['logical_fileinfo']['IGNORE-unknown1'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 4, 4)); rlm@3: $info_real_chunks_current_chunk['logical_fileinfo']['num_tags'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 8, 4)); rlm@3: // $info_real_chunks_current_chunk['logical_fileinfo']['IGNORE-unknown2'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 12, 4)); rlm@3: break; rlm@3: rlm@3: } rlm@3: rlm@3: rlm@3: if (empty($getid3->info['playtime_seconds'])) { rlm@3: $getid3->info['playtime_seconds'] = max($getid3->info['playtime_seconds'], ($info_real_chunks_current_chunk['duration'] + $info_real_chunks_current_chunk['start_time']) / 1000); rlm@3: } rlm@3: rlm@3: if ($info_real_chunks_current_chunk['duration'] > 0) { rlm@3: rlm@3: switch ($info_real_chunks_current_chunk['mime_type']) { rlm@3: rlm@3: case 'audio/x-pn-realaudio': rlm@3: case 'audio/x-pn-multirate-realaudio': rlm@3: rlm@3: $getid3->info['audio']['bitrate'] = (isset($getid3->info['audio']['bitrate']) ? $getid3->info['audio']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate']; rlm@3: $getid3->info['audio']['codec'] = $this->RealAudioCodecFourCClookup($info_real_chunks_current_chunk['parsed_audio_data']['fourcc'], $getid3->info['audio']['bitrate']); rlm@3: $getid3->info['audio']['dataformat'] = 'real'; rlm@3: $getid3->info['audio']['lossless'] = false; rlm@3: break; rlm@3: rlm@3: rlm@3: case 'video/x-pn-realvideo': rlm@3: case 'video/x-pn-multirate-realvideo': rlm@3: rlm@3: $getid3->info['video']['bitrate'] = (isset($getid3->info['video']['bitrate']) ? $getid3->info['video']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate']; rlm@3: $getid3->info['video']['bitrate_mode'] = 'cbr'; rlm@3: $getid3->info['video']['dataformat'] = 'real'; rlm@3: $getid3->info['video']['lossless'] = false; rlm@3: $getid3->info['video']['pixel_aspect_ratio'] = (float)1; rlm@3: break; rlm@3: rlm@3: rlm@3: case 'audio/x-ralf-mpeg4-generic': rlm@3: rlm@3: $getid3->info['audio']['bitrate'] = (isset($getid3->info['audio']['bitrate']) ? $getid3->info['audio']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate']; rlm@3: $getid3->info['audio']['codec'] = 'RealAudio Lossless'; rlm@3: $getid3->info['audio']['dataformat'] = 'real'; rlm@3: $getid3->info['audio']['lossless'] = true; rlm@3: break; rlm@3: rlm@3: } rlm@3: rlm@3: $getid3->info['bitrate'] = (isset($getid3->info['video']['bitrate']) ? $getid3->info['video']['bitrate'] : 0) + (isset($getid3->info['audio']['bitrate']) ? $getid3->info['audio']['bitrate'] : 0); rlm@3: } rlm@3: } rlm@3: break; rlm@3: rlm@3: rlm@3: case 'CONT': // Content Description Header (text comments) rlm@3: rlm@3: $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: if ($info_real_chunks_current_chunk['object_version'] == 0) { rlm@3: rlm@3: $info_real_chunks_current_chunk['title_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: $info_real_chunks_current_chunk['title'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['title_len']); rlm@3: $offset += $info_real_chunks_current_chunk['title_len']; rlm@3: rlm@3: $info_real_chunks_current_chunk['artist_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: $info_real_chunks_current_chunk['artist'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['artist_len']); rlm@3: $offset += $info_real_chunks_current_chunk['artist_len']; rlm@3: rlm@3: $info_real_chunks_current_chunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: $info_real_chunks_current_chunk['copyright'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['copyright_len']); rlm@3: $offset += $info_real_chunks_current_chunk['copyright_len']; rlm@3: rlm@3: $info_real_chunks_current_chunk['comment_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: $info_real_chunks_current_chunk['comment'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['comment_len']); rlm@3: $offset += $info_real_chunks_current_chunk['comment_len']; rlm@3: rlm@3: foreach (array ('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment') as $key => $val) { rlm@3: if ($info_real_chunks_current_chunk[$key]) { rlm@3: $getid3->info['real']['comments'][$val][] = trim($info_real_chunks_current_chunk[$key]); rlm@3: } rlm@3: } rlm@3: } rlm@3: break; rlm@3: rlm@3: rlm@3: case 'DATA': // Data Chunk Header rlm@3: rlm@3: // do nothing rlm@3: break; rlm@3: rlm@3: rlm@3: case 'INDX': // Index Section Header rlm@3: rlm@3: $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); rlm@3: $offset += 2; rlm@3: rlm@3: if ($info_real_chunks_current_chunk['object_version'] == 0) { rlm@3: rlm@3: getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset, rlm@3: array ( rlm@3: 'num_indices' => 4, rlm@3: 'stream_number' => 2, rlm@3: 'next_index_header' => 4 rlm@3: ) rlm@3: ); rlm@3: $offset += 10; rlm@3: rlm@3: if ($info_real_chunks_current_chunk['next_index_header'] == 0) { rlm@3: // last index chunk found, ignore rest of file rlm@3: break 2; rlm@3: } else { rlm@3: // non-last index chunk, seek to next index chunk (skipping actual index data) rlm@3: fseek($getid3->fp, $info_real_chunks_current_chunk['next_index_header'], SEEK_SET); rlm@3: } rlm@3: } rlm@3: break; rlm@3: rlm@3: rlm@3: default: rlm@3: $getid3->warning('Unhandled RealMedia chunk "'.$chunk_name.'" at offset '.$info_real_chunks_current_chunk['offset']); rlm@3: break; rlm@3: } rlm@3: $chunk_counter++; rlm@3: } rlm@3: rlm@3: if (!empty($getid3->info['audio']['streams'])) { rlm@3: rlm@3: $getid3->info['audio']['bitrate'] = 0; rlm@3: rlm@3: foreach ($getid3->info['audio']['streams'] as $key => $value_array) { rlm@3: $getid3->info['audio']['bitrate'] += $value_array['bitrate']; rlm@3: } rlm@3: } rlm@3: rlm@3: return true; rlm@3: } rlm@3: rlm@3: rlm@3: rlm@3: public static function ParseOldRAheader($old_ra_header_data, &$parsed_array) { rlm@3: rlm@3: // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html rlm@3: rlm@3: $parsed_array = array (); rlm@3: $parsed_array['magic'] = substr($old_ra_header_data, 0, 4); rlm@3: rlm@3: if ($parsed_array['magic'] != '.ra'."\xFD") { rlm@3: return false; rlm@3: } rlm@3: rlm@3: $parsed_array['version1'] = getid3_lib::BigEndian2Int(substr($old_ra_header_data, 4, 2)); rlm@3: rlm@3: if ($parsed_array['version1'] < 3) { rlm@3: rlm@3: return false; rlm@3: } rlm@3: rlm@3: if ($parsed_array['version1'] == 3) { rlm@3: rlm@3: $parsed_array['fourcc1'] = '.ra3'; rlm@3: $parsed_array['bits_per_sample'] = 16; // hard-coded for old versions? rlm@3: $parsed_array['sample_rate'] = 8000; // hard-coded for old versions? rlm@3: rlm@3: getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 6, rlm@3: array ( rlm@3: 'header_size' => 2, rlm@3: 'channels' => 2, // always 1 (?) rlm@3: 'IGNORE-unknown1' => 2, rlm@3: 'IGNORE-unknown2' => 2, rlm@3: 'IGNORE-unknown3' => 2, rlm@3: 'bytes_per_minute' => 2, rlm@3: 'audio_bytes' => 4, rlm@3: ) rlm@3: ); rlm@3: rlm@3: $parsed_array['comments_raw'] = substr($old_ra_header_data, 22, $parsed_array['header_size'] - 22 + 1); // not including null terminator rlm@3: rlm@3: $comment_offset = 0; rlm@3: rlm@3: foreach (array ('title', 'artist', 'copyright') as $name) { rlm@3: $comment_length = getid3_lib::BigEndian2Int($parsed_array['comments_raw']{$comment_offset++}); rlm@3: $parsed_array['comments'][$name][]= substr($parsed_array['comments_raw'], $comment_offset, $comment_length); rlm@3: $comment_offset += $comment_length; rlm@3: } rlm@3: rlm@3: $comment_offset++; // final null terminator (?) rlm@3: $comment_offset++; // fourcc length (?) should be 4 rlm@3: rlm@3: $parsed_array['fourcc'] = substr($old_ra_header_data, 23 + $comment_offset, 4); rlm@3: rlm@3: rlm@3: } elseif ($parsed_array['version1'] <= 5) { rlm@3: rlm@3: getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 6, rlm@3: array ( rlm@3: 'IGNORE-unknown1' => 2, rlm@3: 'fourcc1' => -4, rlm@3: 'file_size' => 4, rlm@3: 'version2' => 2, rlm@3: 'header_size' => 4, rlm@3: 'codec_flavor_id' => 2, rlm@3: 'coded_frame_size' => 4, rlm@3: 'audio_bytes' => 4, rlm@3: 'bytes_per_minute' => 4, rlm@3: 'IGNORE-unknown5' => 4, rlm@3: 'sub_packet_h' => 2, rlm@3: 'frame_size' => 2, rlm@3: 'sub_packet_size' => 2, rlm@3: 'IGNORE-unknown6' => 2 rlm@3: ) rlm@3: ); rlm@3: rlm@3: switch ($parsed_array['version1']) { rlm@3: rlm@3: case 4: rlm@3: rlm@3: getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 48, rlm@3: array ( rlm@3: 'sample_rate' => 2, rlm@3: 'IGNORE-unknown8' => 2, rlm@3: 'bits_per_sample' => 2, rlm@3: 'channels' => 2, rlm@3: 'length_fourcc2' => 1, rlm@3: 'fourcc2' => -4, rlm@3: 'length_fourcc3' => 1, rlm@3: 'fourcc3' => -4, rlm@3: 'IGNORE-unknown9' => 1, rlm@3: 'IGNORE-unknown10' => 2, rlm@3: ) rlm@3: ); rlm@3: rlm@3: $parsed_array['comments_raw'] = substr($old_ra_header_data, 69, $parsed_array['header_size'] - 69 + 16); rlm@3: rlm@3: $comment_offset = 0; rlm@3: rlm@3: foreach (array ('title', 'artist', 'copyright') as $name) { rlm@3: $comment_length = getid3_lib::BigEndian2Int($parsed_array['comments_raw']{$comment_offset++}); rlm@3: $parsed_array['comments'][$name][]= substr($parsed_array['comments_raw'], $comment_offset, $comment_length); rlm@3: $comment_offset += $comment_length; rlm@3: } rlm@3: break; rlm@3: rlm@3: rlm@3: case 5: rlm@3: rlm@3: getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 48, rlm@3: array ( rlm@3: 'sample_rate' => 4, rlm@3: 'sample_rate2' => 4, rlm@3: 'bits_per_sample' => 4, rlm@3: 'channels' => 2, rlm@3: 'genr' => -4, rlm@3: 'fourcc3' => -4, rlm@3: ) rlm@3: ); rlm@3: $parsed_array['comments'] = array (); rlm@3: break; rlm@3: rlm@3: } rlm@3: rlm@3: $parsed_array['fourcc'] = $parsed_array['fourcc3']; rlm@3: rlm@3: } rlm@3: rlm@3: foreach ($parsed_array['comments'] as $key => $value) { rlm@3: rlm@3: if ($parsed_array['comments'][$key][0] === false) { rlm@3: $parsed_array['comments'][$key][0] = ''; rlm@3: } rlm@3: } rlm@3: rlm@3: return true; rlm@3: } rlm@3: rlm@3: rlm@3: rlm@3: public static function RealAudioCodecFourCClookup($fourcc, $bitrate) { rlm@3: rlm@3: // http://www.its.msstate.edu/net/real/reports/config/tags.stats rlm@3: // http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html rlm@3: rlm@3: static $lookup; rlm@3: rlm@3: if (empty($lookup)) { rlm@3: $lookup['14_4'][8000] = 'RealAudio v2 (14.4kbps)'; rlm@3: $lookup['14.4'][8000] = 'RealAudio v2 (14.4kbps)'; rlm@3: $lookup['lpcJ'][8000] = 'RealAudio v2 (14.4kbps)'; rlm@3: $lookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)'; rlm@3: $lookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)'; rlm@3: $lookup['sipr'][4933] = 'RealAudio v4 (5kbps Voice)'; rlm@3: $lookup['sipr'][6444] = 'RealAudio v4 (6.5kbps Voice)'; rlm@3: $lookup['sipr'][8444] = 'RealAudio v4 (8.5kbps Voice)'; rlm@3: $lookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)'; rlm@3: $lookup['dnet'][8000] = 'RealAudio v3 (8kbps Music)'; rlm@3: $lookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)'; rlm@3: $lookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)'; rlm@3: $lookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)'; rlm@3: $lookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)'; rlm@3: $lookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)'; rlm@3: $lookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)'; rlm@3: $lookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)'; rlm@3: $lookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)'; rlm@3: $lookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)'; rlm@3: rlm@3: $lookup['dnet'][0] = 'RealAudio v3'; rlm@3: $lookup['sipr'][0] = 'RealAudio v4'; rlm@3: $lookup['cook'][0] = 'RealAudio G2'; rlm@3: $lookup['atrc'][0] = 'RealAudio 8'; rlm@3: } rlm@3: rlm@3: $round_bitrate = intval(round($bitrate)); rlm@3: rlm@3: if (isset($lookup[$fourcc][$round_bitrate])) { rlm@3: return $lookup[$fourcc][$round_bitrate]; rlm@3: } rlm@3: rlm@3: if (isset($lookup[$fourcc][0])) { rlm@3: return $lookup[$fourcc][0]; rlm@3: } rlm@3: rlm@3: return $fourcc; rlm@3: } rlm@3: rlm@3: } rlm@3: rlm@3: rlm@3: ?>