rlm@3
|
1 <?php
|
rlm@3
|
2 // +----------------------------------------------------------------------+
|
rlm@3
|
3 // | PHP version 5 |
|
rlm@3
|
4 // +----------------------------------------------------------------------+
|
rlm@3
|
5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
|
rlm@3
|
6 // +----------------------------------------------------------------------+
|
rlm@3
|
7 // | This source file is subject to version 2 of the GPL license, |
|
rlm@3
|
8 // | that is bundled with this package in the file license.txt and is |
|
rlm@3
|
9 // | available through the world-wide-web at the following url: |
|
rlm@3
|
10 // | http://www.gnu.org/copyleft/gpl.html |
|
rlm@3
|
11 // +----------------------------------------------------------------------+
|
rlm@3
|
12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
|
rlm@3
|
13 // +----------------------------------------------------------------------+
|
rlm@3
|
14 // | Authors: James Heinrich <infoØgetid3*org> |
|
rlm@3
|
15 // | Allan Hansen <ahØartemis*dk> |
|
rlm@3
|
16 // +----------------------------------------------------------------------+
|
rlm@3
|
17 // | module.audio-video.real.php |
|
rlm@3
|
18 // | Module for analyzing Real Audio/Video files |
|
rlm@3
|
19 // | dependencies: module.audio-video.riff.php |
|
rlm@3
|
20 // +----------------------------------------------------------------------+
|
rlm@3
|
21 //
|
rlm@3
|
22 // $Id: module.audio-video.real.php,v 1.4 2006/11/02 10:48:00 ah Exp $
|
rlm@3
|
23
|
rlm@3
|
24
|
rlm@3
|
25
|
rlm@3
|
26 class getid3_real extends getid3_handler
|
rlm@3
|
27 {
|
rlm@3
|
28
|
rlm@3
|
29 public function Analyze() {
|
rlm@3
|
30
|
rlm@3
|
31 $getid3 = $this->getid3;
|
rlm@3
|
32
|
rlm@3
|
33 $getid3->include_module('audio-video.riff');
|
rlm@3
|
34
|
rlm@3
|
35 $getid3->info['fileformat'] = 'real';
|
rlm@3
|
36 $getid3->info['bitrate'] = 0;
|
rlm@3
|
37 $getid3->info['playtime_seconds'] = 0;
|
rlm@3
|
38
|
rlm@3
|
39 fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET);
|
rlm@3
|
40 $chunk_counter = 0;
|
rlm@3
|
41
|
rlm@3
|
42 while (ftell($getid3->fp) < $getid3->info['avdataend']) {
|
rlm@3
|
43
|
rlm@3
|
44 $chunk_data = fread($getid3->fp, 8);
|
rlm@3
|
45 $chunk_name = substr($chunk_data, 0, 4);
|
rlm@3
|
46 $chunk_size = getid3_lib::BigEndian2Int(substr($chunk_data, 4, 4));
|
rlm@3
|
47
|
rlm@3
|
48 if ($chunk_name == '.ra'."\xFD") {
|
rlm@3
|
49 $chunk_data .= fread($getid3->fp, $chunk_size - 8);
|
rlm@3
|
50
|
rlm@3
|
51 if ($this->ParseOldRAheader(substr($chunk_data, 0, 128), $getid3->info['real']['old_ra_header'])) {
|
rlm@3
|
52
|
rlm@3
|
53 $getid3->info['audio']['dataformat'] = 'real';
|
rlm@3
|
54 $getid3->info['audio']['lossless'] = false;
|
rlm@3
|
55 $getid3->info['audio']['sample_rate'] = $getid3->info['real']['old_ra_header']['sample_rate'];
|
rlm@3
|
56 $getid3->info['audio']['bits_per_sample'] = $getid3->info['real']['old_ra_header']['bits_per_sample'];
|
rlm@3
|
57 $getid3->info['audio']['channels'] = $getid3->info['real']['old_ra_header']['channels'];
|
rlm@3
|
58
|
rlm@3
|
59 $getid3->info['playtime_seconds'] = 60 * ($getid3->info['real']['old_ra_header']['audio_bytes'] / $getid3->info['real']['old_ra_header']['bytes_per_minute']);
|
rlm@3
|
60 $getid3->info['audio']['bitrate'] = 8 * ($getid3->info['real']['old_ra_header']['audio_bytes'] / $getid3->info['playtime_seconds']);
|
rlm@3
|
61 $getid3->info['audio']['codec'] = $this->RealAudioCodecFourCClookup($getid3->info['real']['old_ra_header']['fourcc'], $getid3->info['audio']['bitrate']);
|
rlm@3
|
62
|
rlm@3
|
63 foreach ($getid3->info['real']['old_ra_header']['comments'] as $key => $value_array) {
|
rlm@3
|
64
|
rlm@3
|
65 if (strlen(trim($value_array[0])) > 0) {
|
rlm@3
|
66 $getid3->info['real']['comments'][$key][] = trim($value_array[0]);
|
rlm@3
|
67 }
|
rlm@3
|
68 }
|
rlm@3
|
69 return true;
|
rlm@3
|
70 }
|
rlm@3
|
71
|
rlm@3
|
72 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
|
73 }
|
rlm@3
|
74
|
rlm@3
|
75 $getid3->info['real']['chunks'][$chunk_counter] = array ();
|
rlm@3
|
76 $info_real_chunks_current_chunk = &$getid3->info['real']['chunks'][$chunk_counter];
|
rlm@3
|
77
|
rlm@3
|
78 $info_real_chunks_current_chunk['name'] = $chunk_name;
|
rlm@3
|
79 $info_real_chunks_current_chunk['offset'] = ftell($getid3->fp) - 8;
|
rlm@3
|
80 $info_real_chunks_current_chunk['length'] = $chunk_size;
|
rlm@3
|
81
|
rlm@3
|
82 if (($info_real_chunks_current_chunk['offset'] + $info_real_chunks_current_chunk['length']) > $getid3->info['avdataend']) {
|
rlm@3
|
83 $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
|
84 return false;
|
rlm@3
|
85 }
|
rlm@3
|
86
|
rlm@3
|
87 if ($chunk_size > (getid3::FREAD_BUFFER_SIZE + 8)) {
|
rlm@3
|
88 $chunk_data .= fread($getid3->fp, getid3::FREAD_BUFFER_SIZE - 8);
|
rlm@3
|
89 fseek($getid3->fp, $info_real_chunks_current_chunk['offset'] + $chunk_size, SEEK_SET);
|
rlm@3
|
90
|
rlm@3
|
91 } elseif(($chunk_size - 8) > 0) {
|
rlm@3
|
92 $chunk_data .= fread($getid3->fp, $chunk_size - 8);
|
rlm@3
|
93 }
|
rlm@3
|
94 $offset = 8;
|
rlm@3
|
95
|
rlm@3
|
96 switch ($chunk_name) {
|
rlm@3
|
97
|
rlm@3
|
98 case '.RMF': // RealMedia File Header
|
rlm@3
|
99
|
rlm@3
|
100 $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
101 $offset += 2;
|
rlm@3
|
102
|
rlm@3
|
103 switch ($info_real_chunks_current_chunk['object_version']) {
|
rlm@3
|
104
|
rlm@3
|
105 case 0:
|
rlm@3
|
106 $info_real_chunks_current_chunk['file_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4));
|
rlm@3
|
107 $offset += 4;
|
rlm@3
|
108
|
rlm@3
|
109 $info_real_chunks_current_chunk['headers_count'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4));
|
rlm@3
|
110 $offset += 4;
|
rlm@3
|
111 break;
|
rlm@3
|
112
|
rlm@3
|
113 default:
|
rlm@3
|
114 //$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
|
115 break;
|
rlm@3
|
116
|
rlm@3
|
117 }
|
rlm@3
|
118 break;
|
rlm@3
|
119
|
rlm@3
|
120
|
rlm@3
|
121 case 'PROP': // Properties Header
|
rlm@3
|
122
|
rlm@3
|
123 $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
124 $offset += 2;
|
rlm@3
|
125
|
rlm@3
|
126 if ($info_real_chunks_current_chunk['object_version'] == 0) {
|
rlm@3
|
127
|
rlm@3
|
128 getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset,
|
rlm@3
|
129 array (
|
rlm@3
|
130 'max_bit_rate' => 4,
|
rlm@3
|
131 'avg_bit_rate' => 4,
|
rlm@3
|
132 'max_packet_size' => 4,
|
rlm@3
|
133 'avg_packet_size' => 4,
|
rlm@3
|
134 'num_packets' => 4,
|
rlm@3
|
135 'duration' => 4,
|
rlm@3
|
136 'preroll' => 4,
|
rlm@3
|
137 'index_offset' => 4,
|
rlm@3
|
138 'data_offset' => 4,
|
rlm@3
|
139 'num_streams' => 2,
|
rlm@3
|
140 'flags_raw' => 2
|
rlm@3
|
141 )
|
rlm@3
|
142 );
|
rlm@3
|
143 $offset += 40;
|
rlm@3
|
144
|
rlm@3
|
145 $getid3->info['playtime_seconds'] = $info_real_chunks_current_chunk['duration'] / 1000;
|
rlm@3
|
146 if ($info_real_chunks_current_chunk['duration'] > 0) {
|
rlm@3
|
147 $getid3->info['bitrate'] += $info_real_chunks_current_chunk['avg_bit_rate'];
|
rlm@3
|
148 }
|
rlm@3
|
149
|
rlm@3
|
150 $info_real_chunks_current_chunk['flags']['save_enabled'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0001);
|
rlm@3
|
151 $info_real_chunks_current_chunk['flags']['perfect_play'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0002);
|
rlm@3
|
152 $info_real_chunks_current_chunk['flags']['live_broadcast'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0004);
|
rlm@3
|
153 }
|
rlm@3
|
154 break;
|
rlm@3
|
155
|
rlm@3
|
156
|
rlm@3
|
157 case 'MDPR': // Media Properties Header
|
rlm@3
|
158
|
rlm@3
|
159 $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
160 $offset += 2;
|
rlm@3
|
161
|
rlm@3
|
162 if ($info_real_chunks_current_chunk['object_version'] == 0) {
|
rlm@3
|
163
|
rlm@3
|
164 getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset,
|
rlm@3
|
165 array (
|
rlm@3
|
166 'stream_number' => 2,
|
rlm@3
|
167 'max_bit_rate' => 4,
|
rlm@3
|
168 'avg_bit_rate' => 4,
|
rlm@3
|
169 'max_packet_size' => 4,
|
rlm@3
|
170 'avg_packet_size' => 4,
|
rlm@3
|
171 'start_time' => 4,
|
rlm@3
|
172 'preroll' => 4,
|
rlm@3
|
173 'duration' => 4,
|
rlm@3
|
174 'stream_name_size' => 1
|
rlm@3
|
175 )
|
rlm@3
|
176 );
|
rlm@3
|
177 $offset += 31;
|
rlm@3
|
178
|
rlm@3
|
179 $info_real_chunks_current_chunk['stream_name'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['stream_name_size']);
|
rlm@3
|
180 $offset += $info_real_chunks_current_chunk['stream_name_size'];
|
rlm@3
|
181
|
rlm@3
|
182 $info_real_chunks_current_chunk['mime_type_size'] = getid3_lib::BigEndian2Int($chunk_data{$offset++});
|
rlm@3
|
183
|
rlm@3
|
184 $info_real_chunks_current_chunk['mime_type'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['mime_type_size']);
|
rlm@3
|
185 $offset += $info_real_chunks_current_chunk['mime_type_size'];
|
rlm@3
|
186
|
rlm@3
|
187 $info_real_chunks_current_chunk['type_specific_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4));
|
rlm@3
|
188 $offset += 4;
|
rlm@3
|
189
|
rlm@3
|
190 $info_real_chunks_current_chunk['type_specific_data'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['type_specific_len']);
|
rlm@3
|
191 $offset += $info_real_chunks_current_chunk['type_specific_len'];
|
rlm@3
|
192
|
rlm@3
|
193 $info_real_chunks_current_chunk_typespecificdata = &$info_real_chunks_current_chunk['type_specific_data'];
|
rlm@3
|
194
|
rlm@3
|
195 switch ($info_real_chunks_current_chunk['mime_type']) {
|
rlm@3
|
196
|
rlm@3
|
197 case 'video/x-pn-realvideo':
|
rlm@3
|
198 case 'video/x-pn-multirate-realvideo':
|
rlm@3
|
199 // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
|
rlm@3
|
200
|
rlm@3
|
201 $info_real_chunks_current_chunk['video_info'] = array ();
|
rlm@3
|
202 $info_real_chunks_current_chunk_video_info = &$info_real_chunks_current_chunk['video_info'];
|
rlm@3
|
203
|
rlm@3
|
204 getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk_video_info, $info_real_chunks_current_chunk_typespecificdata, 0,
|
rlm@3
|
205 array (
|
rlm@3
|
206 'dwSize' => 4,
|
rlm@3
|
207 'fourcc1' => -4,
|
rlm@3
|
208 'fourcc2' => -4,
|
rlm@3
|
209 'width' => 2,
|
rlm@3
|
210 'height' => 2,
|
rlm@3
|
211 'bits_per_sample' => 2,
|
rlm@3
|
212 'IGNORE-unknown1' => 2,
|
rlm@3
|
213 'IGNORE-unknown2' => 2,
|
rlm@3
|
214 'frames_per_second' => 2,
|
rlm@3
|
215 'IGNORE-unknown3' => 2,
|
rlm@3
|
216 'IGNORE-unknown4' => 2,
|
rlm@3
|
217 'IGNORE-unknown5' => 2,
|
rlm@3
|
218 'IGNORE-unknown6' => 2,
|
rlm@3
|
219 'IGNORE-unknown7' => 2,
|
rlm@3
|
220 'IGNORE-unknown8' => 2,
|
rlm@3
|
221 'IGNORE-unknown9' => 2
|
rlm@3
|
222 )
|
rlm@3
|
223 );
|
rlm@3
|
224
|
rlm@3
|
225 $info_real_chunks_current_chunk_video_info['codec'] = getid3_riff::RIFFfourccLookup($info_real_chunks_current_chunk_video_info['fourcc2']);
|
rlm@3
|
226
|
rlm@3
|
227 $getid3->info['video']['resolution_x'] = $info_real_chunks_current_chunk_video_info['width'];
|
rlm@3
|
228 $getid3->info['video']['resolution_y'] = $info_real_chunks_current_chunk_video_info['height'];
|
rlm@3
|
229 $getid3->info['video']['frame_rate'] = (float)$info_real_chunks_current_chunk_video_info['frames_per_second'];
|
rlm@3
|
230 $getid3->info['video']['codec'] = $info_real_chunks_current_chunk_video_info['codec'];
|
rlm@3
|
231 $getid3->info['video']['bits_per_sample'] = $info_real_chunks_current_chunk_video_info['bits_per_sample'];
|
rlm@3
|
232 break;
|
rlm@3
|
233
|
rlm@3
|
234
|
rlm@3
|
235 case 'audio/x-pn-realaudio':
|
rlm@3
|
236 case 'audio/x-pn-multirate-realaudio':
|
rlm@3
|
237
|
rlm@3
|
238 $this->ParseOldRAheader($info_real_chunks_current_chunk_typespecificdata, $info_real_chunks_current_chunk['parsed_audio_data']);
|
rlm@3
|
239
|
rlm@3
|
240 $getid3->info['audio']['sample_rate'] = $info_real_chunks_current_chunk['parsed_audio_data']['sample_rate'];
|
rlm@3
|
241 $getid3->info['audio']['bits_per_sample'] = $info_real_chunks_current_chunk['parsed_audio_data']['bits_per_sample'];
|
rlm@3
|
242 $getid3->info['audio']['channels'] = $info_real_chunks_current_chunk['parsed_audio_data']['channels'];
|
rlm@3
|
243
|
rlm@3
|
244 if (!empty($getid3->info['audio']['dataformat'])) {
|
rlm@3
|
245 foreach ($getid3->info['audio'] as $key => $value) {
|
rlm@3
|
246 if ($key != 'streams') {
|
rlm@3
|
247 $getid3->info['audio']['streams'][$info_real_chunks_current_chunk['stream_number']][$key] = $value;
|
rlm@3
|
248 }
|
rlm@3
|
249 }
|
rlm@3
|
250 }
|
rlm@3
|
251 break;
|
rlm@3
|
252
|
rlm@3
|
253
|
rlm@3
|
254 case 'logical-fileinfo':
|
rlm@3
|
255
|
rlm@3
|
256 $info_real_chunks_current_chunk['logical_fileinfo']['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 0, 4));
|
rlm@3
|
257 // $info_real_chunks_current_chunk['logical_fileinfo']['IGNORE-unknown1'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 4, 4));
|
rlm@3
|
258 $info_real_chunks_current_chunk['logical_fileinfo']['num_tags'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 8, 4));
|
rlm@3
|
259 // $info_real_chunks_current_chunk['logical_fileinfo']['IGNORE-unknown2'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 12, 4));
|
rlm@3
|
260 break;
|
rlm@3
|
261
|
rlm@3
|
262 }
|
rlm@3
|
263
|
rlm@3
|
264
|
rlm@3
|
265 if (empty($getid3->info['playtime_seconds'])) {
|
rlm@3
|
266 $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
|
267 }
|
rlm@3
|
268
|
rlm@3
|
269 if ($info_real_chunks_current_chunk['duration'] > 0) {
|
rlm@3
|
270
|
rlm@3
|
271 switch ($info_real_chunks_current_chunk['mime_type']) {
|
rlm@3
|
272
|
rlm@3
|
273 case 'audio/x-pn-realaudio':
|
rlm@3
|
274 case 'audio/x-pn-multirate-realaudio':
|
rlm@3
|
275
|
rlm@3
|
276 $getid3->info['audio']['bitrate'] = (isset($getid3->info['audio']['bitrate']) ? $getid3->info['audio']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate'];
|
rlm@3
|
277 $getid3->info['audio']['codec'] = $this->RealAudioCodecFourCClookup($info_real_chunks_current_chunk['parsed_audio_data']['fourcc'], $getid3->info['audio']['bitrate']);
|
rlm@3
|
278 $getid3->info['audio']['dataformat'] = 'real';
|
rlm@3
|
279 $getid3->info['audio']['lossless'] = false;
|
rlm@3
|
280 break;
|
rlm@3
|
281
|
rlm@3
|
282
|
rlm@3
|
283 case 'video/x-pn-realvideo':
|
rlm@3
|
284 case 'video/x-pn-multirate-realvideo':
|
rlm@3
|
285
|
rlm@3
|
286 $getid3->info['video']['bitrate'] = (isset($getid3->info['video']['bitrate']) ? $getid3->info['video']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate'];
|
rlm@3
|
287 $getid3->info['video']['bitrate_mode'] = 'cbr';
|
rlm@3
|
288 $getid3->info['video']['dataformat'] = 'real';
|
rlm@3
|
289 $getid3->info['video']['lossless'] = false;
|
rlm@3
|
290 $getid3->info['video']['pixel_aspect_ratio'] = (float)1;
|
rlm@3
|
291 break;
|
rlm@3
|
292
|
rlm@3
|
293
|
rlm@3
|
294 case 'audio/x-ralf-mpeg4-generic':
|
rlm@3
|
295
|
rlm@3
|
296 $getid3->info['audio']['bitrate'] = (isset($getid3->info['audio']['bitrate']) ? $getid3->info['audio']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate'];
|
rlm@3
|
297 $getid3->info['audio']['codec'] = 'RealAudio Lossless';
|
rlm@3
|
298 $getid3->info['audio']['dataformat'] = 'real';
|
rlm@3
|
299 $getid3->info['audio']['lossless'] = true;
|
rlm@3
|
300 break;
|
rlm@3
|
301
|
rlm@3
|
302 }
|
rlm@3
|
303
|
rlm@3
|
304 $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
|
305 }
|
rlm@3
|
306 }
|
rlm@3
|
307 break;
|
rlm@3
|
308
|
rlm@3
|
309
|
rlm@3
|
310 case 'CONT': // Content Description Header (text comments)
|
rlm@3
|
311
|
rlm@3
|
312 $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
313 $offset += 2;
|
rlm@3
|
314
|
rlm@3
|
315 if ($info_real_chunks_current_chunk['object_version'] == 0) {
|
rlm@3
|
316
|
rlm@3
|
317 $info_real_chunks_current_chunk['title_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
318 $offset += 2;
|
rlm@3
|
319
|
rlm@3
|
320 $info_real_chunks_current_chunk['title'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['title_len']);
|
rlm@3
|
321 $offset += $info_real_chunks_current_chunk['title_len'];
|
rlm@3
|
322
|
rlm@3
|
323 $info_real_chunks_current_chunk['artist_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
324 $offset += 2;
|
rlm@3
|
325
|
rlm@3
|
326 $info_real_chunks_current_chunk['artist'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['artist_len']);
|
rlm@3
|
327 $offset += $info_real_chunks_current_chunk['artist_len'];
|
rlm@3
|
328
|
rlm@3
|
329 $info_real_chunks_current_chunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
330 $offset += 2;
|
rlm@3
|
331
|
rlm@3
|
332 $info_real_chunks_current_chunk['copyright'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['copyright_len']);
|
rlm@3
|
333 $offset += $info_real_chunks_current_chunk['copyright_len'];
|
rlm@3
|
334
|
rlm@3
|
335 $info_real_chunks_current_chunk['comment_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
336 $offset += 2;
|
rlm@3
|
337
|
rlm@3
|
338 $info_real_chunks_current_chunk['comment'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['comment_len']);
|
rlm@3
|
339 $offset += $info_real_chunks_current_chunk['comment_len'];
|
rlm@3
|
340
|
rlm@3
|
341 foreach (array ('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment') as $key => $val) {
|
rlm@3
|
342 if ($info_real_chunks_current_chunk[$key]) {
|
rlm@3
|
343 $getid3->info['real']['comments'][$val][] = trim($info_real_chunks_current_chunk[$key]);
|
rlm@3
|
344 }
|
rlm@3
|
345 }
|
rlm@3
|
346 }
|
rlm@3
|
347 break;
|
rlm@3
|
348
|
rlm@3
|
349
|
rlm@3
|
350 case 'DATA': // Data Chunk Header
|
rlm@3
|
351
|
rlm@3
|
352 // do nothing
|
rlm@3
|
353 break;
|
rlm@3
|
354
|
rlm@3
|
355
|
rlm@3
|
356 case 'INDX': // Index Section Header
|
rlm@3
|
357
|
rlm@3
|
358 $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2));
|
rlm@3
|
359 $offset += 2;
|
rlm@3
|
360
|
rlm@3
|
361 if ($info_real_chunks_current_chunk['object_version'] == 0) {
|
rlm@3
|
362
|
rlm@3
|
363 getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset,
|
rlm@3
|
364 array (
|
rlm@3
|
365 'num_indices' => 4,
|
rlm@3
|
366 'stream_number' => 2,
|
rlm@3
|
367 'next_index_header' => 4
|
rlm@3
|
368 )
|
rlm@3
|
369 );
|
rlm@3
|
370 $offset += 10;
|
rlm@3
|
371
|
rlm@3
|
372 if ($info_real_chunks_current_chunk['next_index_header'] == 0) {
|
rlm@3
|
373 // last index chunk found, ignore rest of file
|
rlm@3
|
374 break 2;
|
rlm@3
|
375 } else {
|
rlm@3
|
376 // non-last index chunk, seek to next index chunk (skipping actual index data)
|
rlm@3
|
377 fseek($getid3->fp, $info_real_chunks_current_chunk['next_index_header'], SEEK_SET);
|
rlm@3
|
378 }
|
rlm@3
|
379 }
|
rlm@3
|
380 break;
|
rlm@3
|
381
|
rlm@3
|
382
|
rlm@3
|
383 default:
|
rlm@3
|
384 $getid3->warning('Unhandled RealMedia chunk "'.$chunk_name.'" at offset '.$info_real_chunks_current_chunk['offset']);
|
rlm@3
|
385 break;
|
rlm@3
|
386 }
|
rlm@3
|
387 $chunk_counter++;
|
rlm@3
|
388 }
|
rlm@3
|
389
|
rlm@3
|
390 if (!empty($getid3->info['audio']['streams'])) {
|
rlm@3
|
391
|
rlm@3
|
392 $getid3->info['audio']['bitrate'] = 0;
|
rlm@3
|
393
|
rlm@3
|
394 foreach ($getid3->info['audio']['streams'] as $key => $value_array) {
|
rlm@3
|
395 $getid3->info['audio']['bitrate'] += $value_array['bitrate'];
|
rlm@3
|
396 }
|
rlm@3
|
397 }
|
rlm@3
|
398
|
rlm@3
|
399 return true;
|
rlm@3
|
400 }
|
rlm@3
|
401
|
rlm@3
|
402
|
rlm@3
|
403
|
rlm@3
|
404 public static function ParseOldRAheader($old_ra_header_data, &$parsed_array) {
|
rlm@3
|
405
|
rlm@3
|
406 // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
|
rlm@3
|
407
|
rlm@3
|
408 $parsed_array = array ();
|
rlm@3
|
409 $parsed_array['magic'] = substr($old_ra_header_data, 0, 4);
|
rlm@3
|
410
|
rlm@3
|
411 if ($parsed_array['magic'] != '.ra'."\xFD") {
|
rlm@3
|
412 return false;
|
rlm@3
|
413 }
|
rlm@3
|
414
|
rlm@3
|
415 $parsed_array['version1'] = getid3_lib::BigEndian2Int(substr($old_ra_header_data, 4, 2));
|
rlm@3
|
416
|
rlm@3
|
417 if ($parsed_array['version1'] < 3) {
|
rlm@3
|
418
|
rlm@3
|
419 return false;
|
rlm@3
|
420 }
|
rlm@3
|
421
|
rlm@3
|
422 if ($parsed_array['version1'] == 3) {
|
rlm@3
|
423
|
rlm@3
|
424 $parsed_array['fourcc1'] = '.ra3';
|
rlm@3
|
425 $parsed_array['bits_per_sample'] = 16; // hard-coded for old versions?
|
rlm@3
|
426 $parsed_array['sample_rate'] = 8000; // hard-coded for old versions?
|
rlm@3
|
427
|
rlm@3
|
428 getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 6,
|
rlm@3
|
429 array (
|
rlm@3
|
430 'header_size' => 2,
|
rlm@3
|
431 'channels' => 2, // always 1 (?)
|
rlm@3
|
432 'IGNORE-unknown1' => 2,
|
rlm@3
|
433 'IGNORE-unknown2' => 2,
|
rlm@3
|
434 'IGNORE-unknown3' => 2,
|
rlm@3
|
435 'bytes_per_minute' => 2,
|
rlm@3
|
436 'audio_bytes' => 4,
|
rlm@3
|
437 )
|
rlm@3
|
438 );
|
rlm@3
|
439
|
rlm@3
|
440 $parsed_array['comments_raw'] = substr($old_ra_header_data, 22, $parsed_array['header_size'] - 22 + 1); // not including null terminator
|
rlm@3
|
441
|
rlm@3
|
442 $comment_offset = 0;
|
rlm@3
|
443
|
rlm@3
|
444 foreach (array ('title', 'artist', 'copyright') as $name) {
|
rlm@3
|
445 $comment_length = getid3_lib::BigEndian2Int($parsed_array['comments_raw']{$comment_offset++});
|
rlm@3
|
446 $parsed_array['comments'][$name][]= substr($parsed_array['comments_raw'], $comment_offset, $comment_length);
|
rlm@3
|
447 $comment_offset += $comment_length;
|
rlm@3
|
448 }
|
rlm@3
|
449
|
rlm@3
|
450 $comment_offset++; // final null terminator (?)
|
rlm@3
|
451 $comment_offset++; // fourcc length (?) should be 4
|
rlm@3
|
452
|
rlm@3
|
453 $parsed_array['fourcc'] = substr($old_ra_header_data, 23 + $comment_offset, 4);
|
rlm@3
|
454
|
rlm@3
|
455
|
rlm@3
|
456 } elseif ($parsed_array['version1'] <= 5) {
|
rlm@3
|
457
|
rlm@3
|
458 getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 6,
|
rlm@3
|
459 array (
|
rlm@3
|
460 'IGNORE-unknown1' => 2,
|
rlm@3
|
461 'fourcc1' => -4,
|
rlm@3
|
462 'file_size' => 4,
|
rlm@3
|
463 'version2' => 2,
|
rlm@3
|
464 'header_size' => 4,
|
rlm@3
|
465 'codec_flavor_id' => 2,
|
rlm@3
|
466 'coded_frame_size' => 4,
|
rlm@3
|
467 'audio_bytes' => 4,
|
rlm@3
|
468 'bytes_per_minute' => 4,
|
rlm@3
|
469 'IGNORE-unknown5' => 4,
|
rlm@3
|
470 'sub_packet_h' => 2,
|
rlm@3
|
471 'frame_size' => 2,
|
rlm@3
|
472 'sub_packet_size' => 2,
|
rlm@3
|
473 'IGNORE-unknown6' => 2
|
rlm@3
|
474 )
|
rlm@3
|
475 );
|
rlm@3
|
476
|
rlm@3
|
477 switch ($parsed_array['version1']) {
|
rlm@3
|
478
|
rlm@3
|
479 case 4:
|
rlm@3
|
480
|
rlm@3
|
481 getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 48,
|
rlm@3
|
482 array (
|
rlm@3
|
483 'sample_rate' => 2,
|
rlm@3
|
484 'IGNORE-unknown8' => 2,
|
rlm@3
|
485 'bits_per_sample' => 2,
|
rlm@3
|
486 'channels' => 2,
|
rlm@3
|
487 'length_fourcc2' => 1,
|
rlm@3
|
488 'fourcc2' => -4,
|
rlm@3
|
489 'length_fourcc3' => 1,
|
rlm@3
|
490 'fourcc3' => -4,
|
rlm@3
|
491 'IGNORE-unknown9' => 1,
|
rlm@3
|
492 'IGNORE-unknown10' => 2,
|
rlm@3
|
493 )
|
rlm@3
|
494 );
|
rlm@3
|
495
|
rlm@3
|
496 $parsed_array['comments_raw'] = substr($old_ra_header_data, 69, $parsed_array['header_size'] - 69 + 16);
|
rlm@3
|
497
|
rlm@3
|
498 $comment_offset = 0;
|
rlm@3
|
499
|
rlm@3
|
500 foreach (array ('title', 'artist', 'copyright') as $name) {
|
rlm@3
|
501 $comment_length = getid3_lib::BigEndian2Int($parsed_array['comments_raw']{$comment_offset++});
|
rlm@3
|
502 $parsed_array['comments'][$name][]= substr($parsed_array['comments_raw'], $comment_offset, $comment_length);
|
rlm@3
|
503 $comment_offset += $comment_length;
|
rlm@3
|
504 }
|
rlm@3
|
505 break;
|
rlm@3
|
506
|
rlm@3
|
507
|
rlm@3
|
508 case 5:
|
rlm@3
|
509
|
rlm@3
|
510 getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 48,
|
rlm@3
|
511 array (
|
rlm@3
|
512 'sample_rate' => 4,
|
rlm@3
|
513 'sample_rate2' => 4,
|
rlm@3
|
514 'bits_per_sample' => 4,
|
rlm@3
|
515 'channels' => 2,
|
rlm@3
|
516 'genr' => -4,
|
rlm@3
|
517 'fourcc3' => -4,
|
rlm@3
|
518 )
|
rlm@3
|
519 );
|
rlm@3
|
520 $parsed_array['comments'] = array ();
|
rlm@3
|
521 break;
|
rlm@3
|
522
|
rlm@3
|
523 }
|
rlm@3
|
524
|
rlm@3
|
525 $parsed_array['fourcc'] = $parsed_array['fourcc3'];
|
rlm@3
|
526
|
rlm@3
|
527 }
|
rlm@3
|
528
|
rlm@3
|
529 foreach ($parsed_array['comments'] as $key => $value) {
|
rlm@3
|
530
|
rlm@3
|
531 if ($parsed_array['comments'][$key][0] === false) {
|
rlm@3
|
532 $parsed_array['comments'][$key][0] = '';
|
rlm@3
|
533 }
|
rlm@3
|
534 }
|
rlm@3
|
535
|
rlm@3
|
536 return true;
|
rlm@3
|
537 }
|
rlm@3
|
538
|
rlm@3
|
539
|
rlm@3
|
540
|
rlm@3
|
541 public static function RealAudioCodecFourCClookup($fourcc, $bitrate) {
|
rlm@3
|
542
|
rlm@3
|
543 // http://www.its.msstate.edu/net/real/reports/config/tags.stats
|
rlm@3
|
544 // http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html
|
rlm@3
|
545
|
rlm@3
|
546 static $lookup;
|
rlm@3
|
547
|
rlm@3
|
548 if (empty($lookup)) {
|
rlm@3
|
549 $lookup['14_4'][8000] = 'RealAudio v2 (14.4kbps)';
|
rlm@3
|
550 $lookup['14.4'][8000] = 'RealAudio v2 (14.4kbps)';
|
rlm@3
|
551 $lookup['lpcJ'][8000] = 'RealAudio v2 (14.4kbps)';
|
rlm@3
|
552 $lookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)';
|
rlm@3
|
553 $lookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)';
|
rlm@3
|
554 $lookup['sipr'][4933] = 'RealAudio v4 (5kbps Voice)';
|
rlm@3
|
555 $lookup['sipr'][6444] = 'RealAudio v4 (6.5kbps Voice)';
|
rlm@3
|
556 $lookup['sipr'][8444] = 'RealAudio v4 (8.5kbps Voice)';
|
rlm@3
|
557 $lookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)';
|
rlm@3
|
558 $lookup['dnet'][8000] = 'RealAudio v3 (8kbps Music)';
|
rlm@3
|
559 $lookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)';
|
rlm@3
|
560 $lookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)';
|
rlm@3
|
561 $lookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)';
|
rlm@3
|
562 $lookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)';
|
rlm@3
|
563 $lookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)';
|
rlm@3
|
564 $lookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)';
|
rlm@3
|
565 $lookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)';
|
rlm@3
|
566 $lookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)';
|
rlm@3
|
567 $lookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)';
|
rlm@3
|
568
|
rlm@3
|
569 $lookup['dnet'][0] = 'RealAudio v3';
|
rlm@3
|
570 $lookup['sipr'][0] = 'RealAudio v4';
|
rlm@3
|
571 $lookup['cook'][0] = 'RealAudio G2';
|
rlm@3
|
572 $lookup['atrc'][0] = 'RealAudio 8';
|
rlm@3
|
573 }
|
rlm@3
|
574
|
rlm@3
|
575 $round_bitrate = intval(round($bitrate));
|
rlm@3
|
576
|
rlm@3
|
577 if (isset($lookup[$fourcc][$round_bitrate])) {
|
rlm@3
|
578 return $lookup[$fourcc][$round_bitrate];
|
rlm@3
|
579 }
|
rlm@3
|
580
|
rlm@3
|
581 if (isset($lookup[$fourcc][0])) {
|
rlm@3
|
582 return $lookup[$fourcc][0];
|
rlm@3
|
583 }
|
rlm@3
|
584
|
rlm@3
|
585 return $fourcc;
|
rlm@3
|
586 }
|
rlm@3
|
587
|
rlm@3
|
588 }
|
rlm@3
|
589
|
rlm@3
|
590
|
rlm@3
|
591 ?> |