rlm@3: <?php
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | PHP version 5                                                        |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | This source file is subject to version 2 of the GPL license,         |
rlm@3: // | that is bundled with this package in the file license.txt and is     |
rlm@3: // | available through the world-wide-web at the following url:           |
rlm@3: // | http://www.gnu.org/copyleft/gpl.html                                 |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
rlm@3: // +----------------------------------------------------------------------+
rlm@3: // | Authors: James Heinrich <infoØgetid3*org>                            |
rlm@3: // |          Allan Hansen <ahØartemis*dk>                                |
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: ?>