File indexing completed on 2024-12-22 05:33:11

0001 <?php
0002 /////////////////////////////////////////////////////////////////
0003 /// getID3() by James Heinrich <info@getid3.org>               //
0004 //  available at http://getid3.sourceforge.net                 //
0005 //            or http://www.getid3.org                         //
0006 //          also https://github.com/JamesHeinrich/getID3       //
0007 /////////////////////////////////////////////////////////////////
0008 // See readme.txt for more details                             //
0009 /////////////////////////////////////////////////////////////////
0010 //                                                             //
0011 // module.audio-video.real.php                                 //
0012 // module for analyzing Real Audio/Video files                 //
0013 // dependencies: module.audio-video.riff.php                   //
0014 //                                                            ///
0015 /////////////////////////////////////////////////////////////////
0016 
0017 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
0018 
0019 class getid3_real extends getid3_handler
0020 {
0021 
0022   public function Analyze() {
0023     $info = &$this->getid3->info;
0024 
0025     $info['fileformat']       = 'real';
0026     $info['bitrate']          = 0;
0027     $info['playtime_seconds'] = 0;
0028 
0029     $this->fseek($info['avdataoffset']);
0030     $ChunkCounter = 0;
0031     while ($this->ftell() < $info['avdataend']) {
0032       $ChunkData  = $this->fread(8);
0033       $ChunkName  =                           substr($ChunkData, 0, 4);
0034       $ChunkSize  = getid3_lib::BigEndian2Int(substr($ChunkData, 4, 4));
0035 
0036       if ($ChunkName == '.ra'."\xFD") {
0037         $ChunkData .= $this->fread($ChunkSize - 8);
0038         if ($this->ParseOldRAheader(substr($ChunkData, 0, 128), $info['real']['old_ra_header'])) {
0039           $info['audio']['dataformat']      = 'real';
0040           $info['audio']['lossless']        = false;
0041           $info['audio']['sample_rate']     = $info['real']['old_ra_header']['sample_rate'];
0042           $info['audio']['bits_per_sample'] = $info['real']['old_ra_header']['bits_per_sample'];
0043           $info['audio']['channels']        = $info['real']['old_ra_header']['channels'];
0044 
0045           $info['playtime_seconds']         = 60 * ($info['real']['old_ra_header']['audio_bytes'] / $info['real']['old_ra_header']['bytes_per_minute']);
0046           $info['audio']['bitrate']         =  8 * ($info['real']['old_ra_header']['audio_bytes'] / $info['playtime_seconds']);
0047           $info['audio']['codec']           = $this->RealAudioCodecFourCClookup($info['real']['old_ra_header']['fourcc'], $info['audio']['bitrate']);
0048 
0049           foreach ($info['real']['old_ra_header']['comments'] as $key => $valuearray) {
0050             if (strlen(trim($valuearray[0])) > 0) {
0051               $info['real']['comments'][$key][] = trim($valuearray[0]);
0052             }
0053           }
0054           return true;
0055         }
0056         $info['error'][] = 'There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org';
0057         unset($info['bitrate']);
0058         unset($info['playtime_seconds']);
0059         return false;
0060       }
0061 
0062       // shortcut
0063       $info['real']['chunks'][$ChunkCounter] = array();
0064       $thisfile_real_chunks_currentchunk = &$info['real']['chunks'][$ChunkCounter];
0065 
0066       $thisfile_real_chunks_currentchunk['name']   = $ChunkName;
0067       $thisfile_real_chunks_currentchunk['offset'] = $this->ftell() - 8;
0068       $thisfile_real_chunks_currentchunk['length'] = $ChunkSize;
0069       if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $info['avdataend']) {
0070         $info['warning'][] = 'Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file';
0071         return false;
0072       }
0073 
0074       if ($ChunkSize > ($this->getid3->fread_buffer_size() + 8)) {
0075 
0076         $ChunkData .= $this->fread($this->getid3->fread_buffer_size() - 8);
0077         $this->fseek($thisfile_real_chunks_currentchunk['offset'] + $ChunkSize);
0078 
0079       } elseif(($ChunkSize - 8) > 0) {
0080 
0081         $ChunkData .= $this->fread($ChunkSize - 8);
0082 
0083       }
0084       $offset = 8;
0085 
0086       switch ($ChunkName) {
0087 
0088         case '.RMF': // RealMedia File Header
0089           $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0090           $offset += 2;
0091           switch ($thisfile_real_chunks_currentchunk['object_version']) {
0092 
0093             case 0:
0094               $thisfile_real_chunks_currentchunk['file_version']  = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0095               $offset += 4;
0096               $thisfile_real_chunks_currentchunk['headers_count'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0097               $offset += 4;
0098               break;
0099 
0100             default:
0101               //$info['warning'][] = 'Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)';
0102               break;
0103 
0104           }
0105           break;
0106 
0107 
0108         case 'PROP': // Properties Header
0109           $thisfile_real_chunks_currentchunk['object_version']      = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0110           $offset += 2;
0111           if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
0112             $thisfile_real_chunks_currentchunk['max_bit_rate']    = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0113             $offset += 4;
0114             $thisfile_real_chunks_currentchunk['avg_bit_rate']    = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0115             $offset += 4;
0116             $thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0117             $offset += 4;
0118             $thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0119             $offset += 4;
0120             $thisfile_real_chunks_currentchunk['num_packets']     = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0121             $offset += 4;
0122             $thisfile_real_chunks_currentchunk['duration']        = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0123             $offset += 4;
0124             $thisfile_real_chunks_currentchunk['preroll']         = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0125             $offset += 4;
0126             $thisfile_real_chunks_currentchunk['index_offset']    = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0127             $offset += 4;
0128             $thisfile_real_chunks_currentchunk['data_offset']     = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0129             $offset += 4;
0130             $thisfile_real_chunks_currentchunk['num_streams']     = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0131             $offset += 2;
0132             $thisfile_real_chunks_currentchunk['flags_raw']       = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0133             $offset += 2;
0134             $info['playtime_seconds'] = $thisfile_real_chunks_currentchunk['duration'] / 1000;
0135             if ($thisfile_real_chunks_currentchunk['duration'] > 0) {
0136               $info['bitrate'] += $thisfile_real_chunks_currentchunk['avg_bit_rate'];
0137             }
0138             $thisfile_real_chunks_currentchunk['flags']['save_enabled']   = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0001);
0139             $thisfile_real_chunks_currentchunk['flags']['perfect_play']   = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0002);
0140             $thisfile_real_chunks_currentchunk['flags']['live_broadcast'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0004);
0141           }
0142           break;
0143 
0144         case 'MDPR': // Media Properties Header
0145           $thisfile_real_chunks_currentchunk['object_version']         = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0146           $offset += 2;
0147           if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
0148             $thisfile_real_chunks_currentchunk['stream_number']      = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0149             $offset += 2;
0150             $thisfile_real_chunks_currentchunk['max_bit_rate']       = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0151             $offset += 4;
0152             $thisfile_real_chunks_currentchunk['avg_bit_rate']       = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0153             $offset += 4;
0154             $thisfile_real_chunks_currentchunk['max_packet_size']    = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0155             $offset += 4;
0156             $thisfile_real_chunks_currentchunk['avg_packet_size']    = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0157             $offset += 4;
0158             $thisfile_real_chunks_currentchunk['start_time']         = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0159             $offset += 4;
0160             $thisfile_real_chunks_currentchunk['preroll']            = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0161             $offset += 4;
0162             $thisfile_real_chunks_currentchunk['duration']           = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0163             $offset += 4;
0164             $thisfile_real_chunks_currentchunk['stream_name_size']   = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1));
0165             $offset += 1;
0166             $thisfile_real_chunks_currentchunk['stream_name']        = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['stream_name_size']);
0167             $offset += $thisfile_real_chunks_currentchunk['stream_name_size'];
0168             $thisfile_real_chunks_currentchunk['mime_type_size']     = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1));
0169             $offset += 1;
0170             $thisfile_real_chunks_currentchunk['mime_type']          = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['mime_type_size']);
0171             $offset += $thisfile_real_chunks_currentchunk['mime_type_size'];
0172             $thisfile_real_chunks_currentchunk['type_specific_len']  = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0173             $offset += 4;
0174             $thisfile_real_chunks_currentchunk['type_specific_data'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['type_specific_len']);
0175             $offset += $thisfile_real_chunks_currentchunk['type_specific_len'];
0176 
0177             // shortcut
0178             $thisfile_real_chunks_currentchunk_typespecificdata = &$thisfile_real_chunks_currentchunk['type_specific_data'];
0179 
0180             switch ($thisfile_real_chunks_currentchunk['mime_type']) {
0181               case 'video/x-pn-realvideo':
0182               case 'video/x-pn-multirate-realvideo':
0183                 // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
0184 
0185                 // shortcut
0186                 $thisfile_real_chunks_currentchunk['video_info'] = array();
0187                 $thisfile_real_chunks_currentchunk_videoinfo     = &$thisfile_real_chunks_currentchunk['video_info'];
0188 
0189                 $thisfile_real_chunks_currentchunk_videoinfo['dwSize']            = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata,  0, 4));
0190                 $thisfile_real_chunks_currentchunk_videoinfo['fourcc1']           =                           substr($thisfile_real_chunks_currentchunk_typespecificdata,  4, 4);
0191                 $thisfile_real_chunks_currentchunk_videoinfo['fourcc2']           =                           substr($thisfile_real_chunks_currentchunk_typespecificdata,  8, 4);
0192                 $thisfile_real_chunks_currentchunk_videoinfo['width']             = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 12, 2));
0193                 $thisfile_real_chunks_currentchunk_videoinfo['height']            = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 14, 2));
0194                 $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample']   = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 16, 2));
0195                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown1']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 18, 2));
0196                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown2']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 20, 2));
0197                 $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 22, 2));
0198                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown3']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 24, 2));
0199                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown4']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 26, 2));
0200                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown5']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 28, 2));
0201                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown6']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 30, 2));
0202                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown7']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 32, 2));
0203                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown8']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 34, 2));
0204                 //$thisfile_real_chunks_currentchunk_videoinfo['unknown9']          = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 36, 2));
0205 
0206                 $thisfile_real_chunks_currentchunk_videoinfo['codec'] = getid3_riff::fourccLookup($thisfile_real_chunks_currentchunk_videoinfo['fourcc2']);
0207 
0208                 $info['video']['resolution_x']    =         $thisfile_real_chunks_currentchunk_videoinfo['width'];
0209                 $info['video']['resolution_y']    =         $thisfile_real_chunks_currentchunk_videoinfo['height'];
0210                 $info['video']['frame_rate']      = (float) $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'];
0211                 $info['video']['codec']           =         $thisfile_real_chunks_currentchunk_videoinfo['codec'];
0212                 $info['video']['bits_per_sample'] =         $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'];
0213                 break;
0214 
0215               case 'audio/x-pn-realaudio':
0216               case 'audio/x-pn-multirate-realaudio':
0217                 $this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk['parsed_audio_data']);
0218 
0219                 $info['audio']['sample_rate']     = $thisfile_real_chunks_currentchunk['parsed_audio_data']['sample_rate'];
0220                 $info['audio']['bits_per_sample'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['bits_per_sample'];
0221                 $info['audio']['channels']        = $thisfile_real_chunks_currentchunk['parsed_audio_data']['channels'];
0222                 if (!empty($info['audio']['dataformat'])) {
0223                   foreach ($info['audio'] as $key => $value) {
0224                     if ($key != 'streams') {
0225                       $info['audio']['streams'][$thisfile_real_chunks_currentchunk['stream_number']][$key] = $value;
0226                     }
0227                   }
0228                 }
0229                 break;
0230 
0231               case 'logical-fileinfo':
0232                 // shortcut
0233                 $thisfile_real_chunks_currentchunk['logical_fileinfo'] = array();
0234                 $thisfile_real_chunks_currentchunk_logicalfileinfo     = &$thisfile_real_chunks_currentchunk['logical_fileinfo'];
0235 
0236                 $thisfile_real_chunks_currentchunk_logicalfileinfo_offset = 0;
0237                 $thisfile_real_chunks_currentchunk_logicalfileinfo['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
0238                 $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
0239 
0240                 //$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown1']                = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
0241                 $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
0242 
0243                 $thisfile_real_chunks_currentchunk_logicalfileinfo['num_tags']                = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
0244                 $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
0245 
0246                 //$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown2']                = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
0247                 $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
0248 
0249                 //$thisfile_real_chunks_currentchunk_logicalfileinfo['d']                       = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 1));
0250 
0251                 //$thisfile_real_chunks_currentchunk_logicalfileinfo['one_type'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata,     $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
0252                 //$thisfile_real_chunks_currentchunk_logicalfileinfo_thislength  = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 4 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 2));
0253                 //$thisfile_real_chunks_currentchunk_logicalfileinfo['one']      =                           substr($thisfile_real_chunks_currentchunk_typespecificdata, 6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength);
0254                 //$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += (6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength);
0255 
0256                 break;
0257 
0258             }
0259 
0260 
0261             if (empty($info['playtime_seconds'])) {
0262               $info['playtime_seconds'] = max($info['playtime_seconds'], ($thisfile_real_chunks_currentchunk['duration'] + $thisfile_real_chunks_currentchunk['start_time']) / 1000);
0263             }
0264             if ($thisfile_real_chunks_currentchunk['duration'] > 0) {
0265               switch ($thisfile_real_chunks_currentchunk['mime_type']) {
0266                 case 'audio/x-pn-realaudio':
0267                 case 'audio/x-pn-multirate-realaudio':
0268                   $info['audio']['bitrate']    = (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
0269                   $info['audio']['codec']      = $this->RealAudioCodecFourCClookup($thisfile_real_chunks_currentchunk['parsed_audio_data']['fourcc'], $info['audio']['bitrate']);
0270                   $info['audio']['dataformat'] = 'real';
0271                   $info['audio']['lossless']   = false;
0272                   break;
0273 
0274                 case 'video/x-pn-realvideo':
0275                 case 'video/x-pn-multirate-realvideo':
0276                   $info['video']['bitrate']            = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
0277                   $info['video']['bitrate_mode']       = 'cbr';
0278                   $info['video']['dataformat']         = 'real';
0279                   $info['video']['lossless']           = false;
0280                   $info['video']['pixel_aspect_ratio'] = (float) 1;
0281                   break;
0282 
0283                 case 'audio/x-ralf-mpeg4-generic':
0284                   $info['audio']['bitrate']    = (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
0285                   $info['audio']['codec']      = 'RealAudio Lossless';
0286                   $info['audio']['dataformat'] = 'real';
0287                   $info['audio']['lossless']   = true;
0288                   break;
0289               }
0290               $info['bitrate'] = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0);
0291             }
0292           }
0293           break;
0294 
0295         case 'CONT': // Content Description Header (text comments)
0296           $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0297           $offset += 2;
0298           if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
0299             $thisfile_real_chunks_currentchunk['title_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0300             $offset += 2;
0301             $thisfile_real_chunks_currentchunk['title'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['title_len']);
0302             $offset += $thisfile_real_chunks_currentchunk['title_len'];
0303 
0304             $thisfile_real_chunks_currentchunk['artist_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0305             $offset += 2;
0306             $thisfile_real_chunks_currentchunk['artist'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['artist_len']);
0307             $offset += $thisfile_real_chunks_currentchunk['artist_len'];
0308 
0309             $thisfile_real_chunks_currentchunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0310             $offset += 2;
0311             $thisfile_real_chunks_currentchunk['copyright'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['copyright_len']);
0312             $offset += $thisfile_real_chunks_currentchunk['copyright_len'];
0313 
0314             $thisfile_real_chunks_currentchunk['comment_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0315             $offset += 2;
0316             $thisfile_real_chunks_currentchunk['comment'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['comment_len']);
0317             $offset += $thisfile_real_chunks_currentchunk['comment_len'];
0318 
0319 
0320             $commentkeystocopy = array('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment');
0321             foreach ($commentkeystocopy as $key => $val) {
0322               if ($thisfile_real_chunks_currentchunk[$key]) {
0323                 $info['real']['comments'][$val][] = trim($thisfile_real_chunks_currentchunk[$key]);
0324               }
0325             }
0326 
0327           }
0328           break;
0329 
0330 
0331         case 'DATA': // Data Chunk Header
0332           // do nothing
0333           break;
0334 
0335         case 'INDX': // Index Section Header
0336           $thisfile_real_chunks_currentchunk['object_version']        = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0337           $offset += 2;
0338           if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
0339             $thisfile_real_chunks_currentchunk['num_indices']       = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0340             $offset += 4;
0341             $thisfile_real_chunks_currentchunk['stream_number']     = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
0342             $offset += 2;
0343             $thisfile_real_chunks_currentchunk['next_index_header'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
0344             $offset += 4;
0345 
0346             if ($thisfile_real_chunks_currentchunk['next_index_header'] == 0) {
0347               // last index chunk found, ignore rest of file
0348               break 2;
0349             } else {
0350               // non-last index chunk, seek to next index chunk (skipping actual index data)
0351               $this->fseek($thisfile_real_chunks_currentchunk['next_index_header']);
0352             }
0353           }
0354           break;
0355 
0356         default:
0357           $info['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset'];
0358           break;
0359       }
0360       $ChunkCounter++;
0361     }
0362 
0363     if (!empty($info['audio']['streams'])) {
0364       $info['audio']['bitrate'] = 0;
0365       foreach ($info['audio']['streams'] as $key => $valuearray) {
0366         $info['audio']['bitrate'] += $valuearray['bitrate'];
0367       }
0368     }
0369 
0370     return true;
0371   }
0372 
0373 
0374   public function ParseOldRAheader($OldRAheaderData, &$ParsedArray) {
0375     // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
0376 
0377     $ParsedArray = array();
0378     $ParsedArray['magic'] = substr($OldRAheaderData, 0, 4);
0379     if ($ParsedArray['magic'] != '.ra'."\xFD") {
0380       return false;
0381     }
0382     $ParsedArray['version1']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData,  4, 2));
0383 
0384     if ($ParsedArray['version1'] < 3) {
0385 
0386       return false;
0387 
0388     } elseif ($ParsedArray['version1'] == 3) {
0389 
0390       $ParsedArray['fourcc1']          = '.ra3';
0391       $ParsedArray['bits_per_sample']  = 16;   // hard-coded for old versions?
0392       $ParsedArray['sample_rate']      = 8000; // hard-coded for old versions?
0393 
0394       $ParsedArray['header_size']      = getid3_lib::BigEndian2Int(substr($OldRAheaderData,  6, 2));
0395       $ParsedArray['channels']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData,  8, 2)); // always 1 (?)
0396       //$ParsedArray['unknown1']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 10, 2));
0397       //$ParsedArray['unknown2']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 2));
0398       //$ParsedArray['unknown3']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 14, 2));
0399       $ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2));
0400       $ParsedArray['audio_bytes']      = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4));
0401       $ParsedArray['comments_raw']     =                           substr($OldRAheaderData, 22, $ParsedArray['header_size'] - 22 + 1); // not including null terminator
0402 
0403       $commentoffset = 0;
0404       $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
0405       $ParsedArray['comments']['title'][]     = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
0406       $commentoffset += $commentlength;
0407 
0408       $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
0409       $ParsedArray['comments']['artist'][]    = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
0410       $commentoffset += $commentlength;
0411 
0412       $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
0413       $ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
0414       $commentoffset += $commentlength;
0415 
0416       $commentoffset++; // final null terminator (?)
0417       $commentoffset++; // fourcc length (?) should be 4
0418       $ParsedArray['fourcc']           =                           substr($OldRAheaderData, 23 + $commentoffset, 4);
0419 
0420     } elseif ($ParsedArray['version1'] <= 5) {
0421 
0422       //$ParsedArray['unknown1']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData,  6, 2));
0423       $ParsedArray['fourcc1']          =                           substr($OldRAheaderData,  8, 4);
0424       $ParsedArray['file_size']        = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 4));
0425       $ParsedArray['version2']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2));
0426       $ParsedArray['header_size']      = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4));
0427       $ParsedArray['codec_flavor_id']  = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 22, 2));
0428       $ParsedArray['coded_frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 24, 4));
0429       $ParsedArray['audio_bytes']      = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 28, 4));
0430       $ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 32, 4));
0431       //$ParsedArray['unknown5']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 36, 4));
0432       $ParsedArray['sub_packet_h']     = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 40, 2));
0433       $ParsedArray['frame_size']       = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 42, 2));
0434       $ParsedArray['sub_packet_size']  = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 44, 2));
0435       //$ParsedArray['unknown6']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 46, 2));
0436 
0437       switch ($ParsedArray['version1']) {
0438 
0439         case 4:
0440           $ParsedArray['sample_rate']      = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 2));
0441           //$ParsedArray['unknown8']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 50, 2));
0442           $ParsedArray['bits_per_sample']  = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 2));
0443           $ParsedArray['channels']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 54, 2));
0444           $ParsedArray['length_fourcc2']   = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 1));
0445           $ParsedArray['fourcc2']          =                           substr($OldRAheaderData, 57, 4);
0446           $ParsedArray['length_fourcc3']   = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 61, 1));
0447           $ParsedArray['fourcc3']          =                           substr($OldRAheaderData, 62, 4);
0448           //$ParsedArray['unknown9']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 66, 1));
0449           //$ParsedArray['unknown10']        = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 67, 2));
0450           $ParsedArray['comments_raw']     =                           substr($OldRAheaderData, 69, $ParsedArray['header_size'] - 69 + 16);
0451 
0452           $commentoffset = 0;
0453           $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
0454           $ParsedArray['comments']['title'][]     = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
0455           $commentoffset += $commentlength;
0456 
0457           $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
0458           $ParsedArray['comments']['artist'][]    = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
0459           $commentoffset += $commentlength;
0460 
0461           $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
0462           $ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
0463           $commentoffset += $commentlength;
0464           break;
0465 
0466         case 5:
0467           $ParsedArray['sample_rate']      = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 4));
0468           $ParsedArray['sample_rate2']     = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 4));
0469           $ParsedArray['bits_per_sample']  = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 4));
0470           $ParsedArray['channels']         = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 60, 2));
0471           $ParsedArray['genr']             =                           substr($OldRAheaderData, 62, 4);
0472           $ParsedArray['fourcc3']          =                           substr($OldRAheaderData, 66, 4);
0473           $ParsedArray['comments']         = array();
0474           break;
0475       }
0476       $ParsedArray['fourcc'] = $ParsedArray['fourcc3'];
0477 
0478     }
0479     foreach ($ParsedArray['comments'] as $key => $value) {
0480       if ($ParsedArray['comments'][$key][0] === false) {
0481         $ParsedArray['comments'][$key][0] = '';
0482       }
0483     }
0484 
0485     return true;
0486   }
0487 
0488   public function RealAudioCodecFourCClookup($fourcc, $bitrate) {
0489     static $RealAudioCodecFourCClookup = array();
0490     if (empty($RealAudioCodecFourCClookup)) {
0491       // http://www.its.msstate.edu/net/real/reports/config/tags.stats
0492       // http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html
0493 
0494       $RealAudioCodecFourCClookup['14_4'][8000]  = 'RealAudio v2 (14.4kbps)';
0495       $RealAudioCodecFourCClookup['14.4'][8000]  = 'RealAudio v2 (14.4kbps)';
0496       $RealAudioCodecFourCClookup['lpcJ'][8000]  = 'RealAudio v2 (14.4kbps)';
0497       $RealAudioCodecFourCClookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)';
0498       $RealAudioCodecFourCClookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)';
0499       $RealAudioCodecFourCClookup['sipr'][4933]  = 'RealAudio v4 (5kbps Voice)';
0500       $RealAudioCodecFourCClookup['sipr'][6444]  = 'RealAudio v4 (6.5kbps Voice)';
0501       $RealAudioCodecFourCClookup['sipr'][8444]  = 'RealAudio v4 (8.5kbps Voice)';
0502       $RealAudioCodecFourCClookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)';
0503       $RealAudioCodecFourCClookup['dnet'][8000]  = 'RealAudio v3 (8kbps Music)';
0504       $RealAudioCodecFourCClookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)';
0505       $RealAudioCodecFourCClookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)';
0506       $RealAudioCodecFourCClookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)';
0507       $RealAudioCodecFourCClookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)';
0508       $RealAudioCodecFourCClookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)';
0509       $RealAudioCodecFourCClookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)';
0510       $RealAudioCodecFourCClookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)';
0511       $RealAudioCodecFourCClookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)';
0512       $RealAudioCodecFourCClookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)';
0513 
0514       $RealAudioCodecFourCClookup['dnet'][0] = 'RealAudio v3';
0515       $RealAudioCodecFourCClookup['sipr'][0] = 'RealAudio v4';
0516       $RealAudioCodecFourCClookup['cook'][0] = 'RealAudio G2';
0517       $RealAudioCodecFourCClookup['atrc'][0] = 'RealAudio 8';
0518     }
0519     $roundbitrate = intval(round($bitrate));
0520     if (isset($RealAudioCodecFourCClookup[$fourcc][$roundbitrate])) {
0521       return $RealAudioCodecFourCClookup[$fourcc][$roundbitrate];
0522     } elseif (isset($RealAudioCodecFourCClookup[$fourcc][0])) {
0523       return $RealAudioCodecFourCClookup[$fourcc][0];
0524     }
0525     return $fourcc;
0526   }
0527 
0528 }