source: extensions/charlies_content/getid3/getid3/module.audio-video.flv.php @ 3318

Last change on this file since 3318 was 3318, checked in by vdigital, 15 years ago

+ Add Charlies' content to depository

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1<?php
2// +----------------------------------------------------------------------+
3// | PHP version 5                                                        |
4// +----------------------------------------------------------------------+
5// | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
6// +----------------------------------------------------------------------+
7// | This source file is subject to version 2 of the GPL license,         |
8// | that is bundled with this package in the file license.txt and is     |
9// | available through the world-wide-web at the following url:           |
10// | http://www.gnu.org/copyleft/gpl.html                                 |
11// +----------------------------------------------------------------------+
12// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
13// +----------------------------------------------------------------------+
14// | Authors: James Heinrich <infoØgetid3*org>                            |
15// |          Allan Hansen <ahØartemis*dk>                                |
16// +----------------------------------------------------------------------+
17// | module.archive.gzip.php                                              |
18// | module for analyzing GZIP files                                      |
19// | dependencies: NONE                                                   |
20// +----------------------------------------------------------------------+
21// | FLV module by Seth Kaufman <sethØwhirl-i.gig*com>                    |
22// |                                                                      |
23// | * version 0.1 (26 June 2005)                                         |
24// |                                                                      |
25// | minor modifications by James Heinrich <infoØgetid3*org>              |
26// | * version 0.1.1 (15 July 2005)                                       |
27// |                                                                      |
28// | Support for On2 VP6 codec and meta information by                    |
29// | Steve Webster <steve.websterØfeaturecreep*com>                       |
30// | * version 0.2 (22 February 2006)                                     |
31// |                                                                      |
32// | Modified to not read entire file into memory                         |
33// | by James Heinrich <infoØgetid3*org>                                  |
34// | * version 0.3 (15 June 2006)                                         |
35// |                                                                      |
36// | Modifications by Allan Hansen <ahØartemis*dk>                        |
37// | Adapted module for PHP5 and getID3 2.0.0.                            |
38// +----------------------------------------------------------------------+
39//
40// $Id: module.audio-video.flv.php 3318 2009-05-20 21:54:10Z vdigital $
41
42
43
44class getid3_flv extends getid3_handler
45{
46   
47    const TAG_AUDIO    =  8;
48    const TAG_VIDEO    =  9;
49    const TAG_META     = 18;
50
51    const VIDEO_H263   = 2;
52    const VIDEO_SCREEN = 3;
53    const VIDEO_VP6    = 4;
54
55   
56        public function Analyze()
57        {
58            $info = &$this->getid3->info;
59           
60            $info['flv'] = array ();
61            $info_flv = &$info['flv'];
62           
63                fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
64
65                $flv_data_length = $info['avdataend'] - $info['avdataoffset'];
66                $flv_header = fread($this->getid3->fp, 5);
67
68                $info['fileformat'] = 'flv';
69                $info_flv['header']['signature'] =                           substr($flv_header, 0, 3);
70                $info_flv['header']['version']   = getid3_lib::BigEndian2Int(substr($flv_header, 3, 1));
71                $type_flags                      = getid3_lib::BigEndian2Int(substr($flv_header, 4, 1));
72
73                $info_flv['header']['hasAudio'] = (bool) ($type_flags & 0x04);
74                $info_flv['header']['hasVideo'] = (bool) ($type_flags & 0x01);
75
76                $frame_size_data_length = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4));
77                $flv_header_frame_length = 9;
78                if ($frame_size_data_length > $flv_header_frame_length) {
79                        fseek($this->getid3->fp, $frame_size_data_length - $flv_header_frame_length, SEEK_CUR);
80                }
81
82                $duration = 0;
83                while ((ftell($this->getid3->fp) + 1) < $info['avdataend']) {
84                       
85                        $this_tag_header = fread($this->getid3->fp, 16);
86
87                        $previous_tag_length = getid3_lib::BigEndian2Int(substr($this_tag_header,  0, 4));
88                        $tag_type            = getid3_lib::BigEndian2Int(substr($this_tag_header,  4, 1));
89                        $data_length         = getid3_lib::BigEndian2Int(substr($this_tag_header,  5, 3));
90                        $timestamp           = getid3_lib::BigEndian2Int(substr($this_tag_header,  8, 3));
91                        $last_header_byte    = getid3_lib::BigEndian2Int(substr($this_tag_header, 15, 1));
92                        $next_offset         = ftell($this->getid3->fp) - 1 + $data_length;
93
94                        switch ($tag_type) {
95                               
96                                case getid3_flv::TAG_AUDIO:
97                                        if (!isset($info_flv['audio']['audioFormat'])) {
98                                                $info_flv['audio']['audioFormat']     =  $last_header_byte & 0x07;
99                                                $info_flv['audio']['audioRate']       = ($last_header_byte & 0x30) / 0x10;
100                                                $info_flv['audio']['audioSampleSize'] = ($last_header_byte & 0x40) / 0x40;
101                                                $info_flv['audio']['audioType']       = ($last_header_byte & 0x80) / 0x80;
102                                        }
103                                        break;
104
105
106                                case getid3_flv::TAG_VIDEO:
107                                        if (!isset($info_flv['video']['videoCodec'])) {
108                                                $info_flv['video']['videoCodec'] = $last_header_byte & 0x07;
109
110                                                $flv_video_header = fread($this->getid3->fp, 11);
111
112                                                if ($info_flv['video']['videoCodec'] != getid3_flv::VIDEO_VP6) {
113
114                                                        $picture_size_type = (getid3_lib::BigEndian2Int(substr($flv_video_header, 3, 2))) >> 7;
115                                                        $picture_size_type = $picture_size_type & 0x0007;
116                                                        $info_flv['header']['videoSizeType'] = $picture_size_type;
117                                                       
118                                                        switch ($picture_size_type) {
119                                                                case 0:
120                                                                        $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 5, 2));
121                                                                        $picture_size_enc <<= 1;
122                                                                        $info['video']['resolution_x'] = ($picture_size_enc & 0xFF00) >> 8;
123                                                                        $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 6, 2));
124                                                                        $picture_size_enc <<= 1;
125                                                                        $info['video']['resolution_y'] = ($picture_size_enc & 0xFF00) >> 8;
126                                                                        break;
127
128                                                                case 1:
129                                                                        $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 5, 4));
130                                                                        $picture_size_enc <<= 1;
131                                                                        $info['video']['resolution_x'] = ($picture_size_enc & 0xFFFF0000) >> 16;
132
133                                                                        $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 7, 4));
134                                                                        $picture_size_enc <<= 1;
135                                                                        $info['video']['resolution_y'] = ($picture_size_enc & 0xFFFF0000) >> 16;
136                                                                        break;
137
138                                                                case 2:
139                                                                        $info['video']['resolution_x'] = 352;
140                                                                        $info['video']['resolution_y'] = 288;
141                                                                        break;
142
143                                                                case 3:
144                                                                        $info['video']['resolution_x'] = 176;
145                                                                        $info['video']['resolution_y'] = 144;
146                                                                        break;
147
148                                                                case 4:
149                                                                        $info['video']['resolution_x'] = 128;
150                                                                        $info['video']['resolution_y'] = 96;
151                                                                        break;
152
153                                                                case 5:
154                                                                        $info['video']['resolution_x'] = 320;
155                                                                        $info['video']['resolution_y'] = 240;
156                                                                        break;
157
158                                                                case 6:
159                                                                        $info['video']['resolution_x'] = 160;
160                                                                        $info['video']['resolution_y'] = 120;
161                                                                        break;
162
163                                                                default:
164                                                                        $info['video']['resolution_x'] = 0;
165                                                                        $info['video']['resolution_y'] = 0;
166                                                                        break;
167                                                        }
168                                                }
169                                        }
170                                        break;
171
172
173                                // Meta tag
174                                case getid3_flv::TAG_META:
175
176                                        fseek($this->getid3->fp, -1, SEEK_CUR);
177                                        $reader = new AMFReader(new AMFStream(fread($this->getid3->fp, $data_length)));
178                                        $event_name = $reader->readData();
179                                        $info['meta'][$event_name] = $reader->readData();
180                                        unset($reader);
181
182                                        $info['video']['frame_rate']   = @$info['meta']['onMetaData']['framerate'];
183                                        $info['video']['resolution_x'] = @$info['meta']['onMetaData']['width'];
184                                        $info['video']['resolution_y'] = @$info['meta']['onMetaData']['height'];
185                                        break;
186
187                                default:
188                                        // noop
189                                        break;
190                        }
191
192                        if ($timestamp > $duration) {
193                                $duration = $timestamp;
194                        }
195
196                        fseek($this->getid3->fp, $next_offset, SEEK_SET);
197                }
198
199                if ($info['playtime_seconds'] = $duration / 1000) {
200                    $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'];
201                }
202
203                if ($info_flv['header']['hasAudio']) {
204                        $info['audio']['codec']           = $this->FLVaudioFormat($info_flv['audio']['audioFormat']);
205                        $info['audio']['sample_rate']     = $this->FLVaudioRate($info_flv['audio']['audioRate']);
206                        $info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info_flv['audio']['audioSampleSize']);
207
208                        $info['audio']['channels']   = $info_flv['audio']['audioType'] + 1; // 0=mono,1=stereo
209                        $info['audio']['lossless']   = ($info_flv['audio']['audioFormat'] ? false : true); // 0=uncompressed
210                        $info['audio']['dataformat'] = 'flv';
211                }
212                if (@$info_flv['header']['hasVideo']) {
213                        $info['video']['codec']      = $this->FLVvideoCodec($info_flv['video']['videoCodec']);
214                        $info['video']['dataformat'] = 'flv';
215                        $info['video']['lossless']   = false;
216                }
217
218                return true;
219        }
220
221
222        public static function FLVaudioFormat($id) {
223           
224                static $lookup = array(
225                        0 => 'uncompressed',
226                        1 => 'ADPCM',
227                        2 => 'mp3',
228                        5 => 'Nellymoser 8kHz mono',
229                        6 => 'Nellymoser',
230                );
231                return (@$lookup[$id] ? @$lookup[$id] : false);
232        }
233
234
235        public static function FLVaudioRate($id) {
236           
237                static $lookup = array(
238                        0 =>  5500,
239                        1 => 11025,
240                        2 => 22050,
241                        3 => 44100,
242                );
243                return (@$lookup[$id] ? @$lookup[$id] : false);
244        }
245
246
247        public static function FLVaudioBitDepth($id) {
248           
249                static $lookup = array(
250                        0 =>  8,
251                        1 => 16,
252                );
253                return (@$lookup[$id] ? @$lookup[$id] : false);
254        }
255
256
257        public static function FLVvideoCodec($id) {
258           
259                static $lookup = array(
260                        getid3_flv::VIDEO_H263   => 'Sorenson H.263',
261                        getid3_flv::VIDEO_SCREEN => 'Screen video',
262                        getid3_flv::VIDEO_VP6    => 'On2 VP6',
263                );
264                return (@$lookup[$id] ? @$lookup[$id] : false);
265        }
266}
267
268
269
270class AMFStream 
271{
272        public $bytes;
273        public $pos;
274
275
276        public function AMFStream($bytes) {
277           
278                $this->bytes = $bytes;
279                $this->pos = 0;
280        }
281
282
283        public function readByte() {
284           
285                return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
286        }
287
288
289        public function readInt() {
290           
291                return ($this->readByte() << 8) + $this->readByte();
292        }
293
294
295        public function readLong() {
296           
297                return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
298        }
299
300
301        public function readDouble() {
302           
303                return getid3_lib::BigEndian2Float($this->read(8));
304        }
305
306
307        public function readUTF() {
308           
309                $length = $this->readInt();
310                return $this->read($length);
311        }
312
313
314        public function readLongUTF() {
315           
316                $length = $this->readLong();
317                return $this->read($length);
318        }
319
320
321        public function read($length) {
322
323                $val = substr($this->bytes, $this->pos, $length);
324                $this->pos += $length;
325                return $val;
326        }
327
328       
329        public function peekByte() {
330           
331                $pos = $this->pos;
332                $val = $this->readByte();
333                $this->pos = $pos;
334                return $val;
335        }
336
337
338        public function peekInt() {
339
340                $pos = $this->pos;
341                $val = $this->readInt();
342                $this->pos = $pos;
343                return $val;
344        }
345
346
347        public function peekLong() {
348           
349                $pos = $this->pos;
350                $val = $this->readLong();
351                $this->pos = $pos;
352                return $val;
353        }
354
355
356        public function peekDouble() { 
357           
358                $pos = $this->pos;
359                $val = $this->readDouble();
360                $this->pos = $pos;
361                return $val;
362        }
363
364
365        public function peekUTF() {
366           
367                $pos = $this->pos;
368                $val = $this->readUTF();
369                $this->pos = $pos;
370                return $val;
371        }
372
373
374        public function peekLongUTF() {
375           
376                $pos = $this->pos;
377                $val = $this->readLongUTF();
378                $this->pos = $pos;
379                return $val;
380        }
381}
382
383
384
385class AMFReader 
386{
387        public $stream;
388
389        public function __construct($stream) {
390           
391                $this->stream = $stream;
392        }
393
394
395        public function readData() {
396           
397                $value = null;
398
399                $type = $this->stream->readByte();
400
401                switch($type) {
402                        // Double
403                        case 0:
404                                $value = $this->readDouble();
405                        break;
406
407                        // Boolean
408                        case 1:
409                                $value = $this->readBoolean();
410                                break;
411
412                        // String
413                        case 2:
414                                $value = $this->readString();
415                                break;
416
417                        // Object
418                        case 3:
419                                $value = $this->readObject();
420                                break;
421
422                        // null
423                        case 6:
424                                return null;
425                                break;
426
427                        // Mixed array
428                        case 8:
429                                $value = $this->readMixedArray();
430                                break;
431
432                        // Array
433                        case 10:
434                                $value = $this->readArray();
435                                break;
436
437                        // Date
438                        case 11:
439                                $value = $this->readDate();
440                                break;
441
442                        // Long string
443                        case 13:
444                                $value = $this->readLongString();
445                                break;
446
447                        // XML (handled as string)
448                        case 15:
449                                $value = $this->readXML();
450                                break;
451
452                        // Typed object (handled as object)
453                        case 16:
454                                $value = $this->readTypedObject();
455                                break;
456
457                        // Long string
458                        default:
459                                $value = '(unknown or unsupported data type)';
460                        break;
461                }
462
463                return $value;
464        }
465
466
467        public function readDouble() {   
468           
469                return $this->stream->readDouble();
470        }
471
472
473        public function readBoolean() {
474           
475                return $this->stream->readByte() == 1;
476        }
477           
478           
479        public function readString() {
480           
481                return $this->stream->readUTF();
482        }
483
484
485        public function readObject() {
486           
487                // Get highest numerical index - ignored
488                $highestIndex = $this->stream->readLong();
489
490                $data = array();
491
492                while ($key = $this->stream->readUTF()) {
493                        // Mixed array record ends with empty string (0x00 0x00) and 0x09
494                        if (($key == '') && ($this->stream->peekByte() == 0x09)) {
495                                // Consume byte
496                                $this->stream->readByte();
497                                break;
498                        }
499
500                        $data[$key] = $this->readData();
501                }
502
503                return $data;
504        }
505
506
507        public function readMixedArray() {
508           
509                // Get highest numerical index - ignored
510                $highestIndex = $this->stream->readLong();
511
512                $data = array();
513
514                while ($key = $this->stream->readUTF()) {
515                        // Mixed array record ends with empty string (0x00 0x00) and 0x09
516                        if (($key == '') && ($this->stream->peekByte() == 0x09)) {
517                                // Consume byte
518                                $this->stream->readByte();
519                                break;
520                        }
521
522                        if (is_numeric($key)) {
523                                $key = (float) $key;
524                        }
525
526                        $data[$key] = $this->readData();
527                }
528
529                return $data;
530        }
531
532
533        public function readArray() {
534           
535                $length = $this->stream->readLong();
536
537                $data = array();
538
539                for ($i = 0; $i < count($length); $i++) {
540                        $data[] = $this->readData();
541                }
542
543                return $data;
544        }
545
546
547        public function readDate() {
548           
549                $timestamp = $this->stream->readDouble();
550                $timezone = $this->stream->readInt();
551                return $timestamp;
552        }
553
554
555        public function readLongString() {
556           
557                return $this->stream->readLongUTF();
558        }
559
560
561        public function readXML() {
562           
563                return $this->stream->readLongUTF();
564        }
565
566
567        public function readTypedObject() { 
568           
569                $className = $this->stream->readUTF();
570                return $this->readObject();
571        }
572}
573
574?>
Note: See TracBrowser for help on using the repository browser.