source: spip-zone/_plugins_/getID3/trunk/getid3/module.audio-video.flv.php @ 71835

Last change on this file since 71835 was 71835, checked in by kent1@…, 6 years ago

Upgrade de la lib en 1.9.5

Voir le changelog : http://www.getid3.org/source/changelog.txt

  • Property svn:executable set to *
File size: 22.7 KB
Line 
1<?php
2/////////////////////////////////////////////////////////////////
3/// getID3() by James Heinrich <info@getid3.org>               //
4//  available at http://getid3.sourceforge.net                 //
5//            or http://www.getid3.org                         //
6//                                                             //
7//  FLV module by Seth Kaufman <sethØwhirl-i-gig*com>          //
8//                                                             //
9//  * version 0.1 (26 June 2005)                               //
10//                                                             //
11//                                                             //
12//  * version 0.1.1 (15 July 2005)                             //
13//  minor modifications by James Heinrich <info@getid3.org>    //
14//                                                             //
15//  * version 0.2 (22 February 2006)                           //
16//  Support for On2 VP6 codec and meta information             //
17//    by Steve Webster <steve.websterØfeaturecreep*com>        //
18//                                                             //
19//  * version 0.3 (15 June 2006)                               //
20//  Modified to not read entire file into memory               //
21//    by James Heinrich <info@getid3.org>                      //
22//                                                             //
23//  * version 0.4 (07 December 2007)                           //
24//  Bugfixes for incorrectly parsed FLV dimensions             //
25//    and incorrect parsing of onMetaTag                       //
26//    by Evgeny Moysevich <moysevichØgmail*com>                //
27//                                                             //
28//  * version 0.5 (21 May 2009)                                //
29//  Fixed parsing of audio tags and added additional codec     //
30//    details. The duration is now read from onMetaTag (if     //
31//    exists), rather than parsing whole file                  //
32//    by Nigel Barnes <ngbarnesØhotmail*com>                   //
33//                                                             //
34//  * version 0.6 (24 May 2009)                                //
35//  Better parsing of files with h264 video                    //
36//    by Evgeny Moysevich <moysevichØgmail*com>                //
37//                                                             //
38//  * version 0.6.1 (30 May 2011)                              //
39//    prevent infinite loops in expGolombUe()                  //
40//                                                             //
41/////////////////////////////////////////////////////////////////
42//                                                             //
43// module.audio-video.flv.php                                  //
44// module for analyzing Shockwave Flash Video files            //
45// dependencies: NONE                                          //
46//                                                            ///
47/////////////////////////////////////////////////////////////////
48
49define('GETID3_FLV_TAG_AUDIO',          8);
50define('GETID3_FLV_TAG_VIDEO',          9);
51define('GETID3_FLV_TAG_META',          18);
52
53define('GETID3_FLV_VIDEO_H263',         2);
54define('GETID3_FLV_VIDEO_SCREEN',       3);
55define('GETID3_FLV_VIDEO_VP6FLV',       4);
56define('GETID3_FLV_VIDEO_VP6FLV_ALPHA', 5);
57define('GETID3_FLV_VIDEO_SCREENV2',     6);
58define('GETID3_FLV_VIDEO_H264',         7);
59
60define('H264_AVC_SEQUENCE_HEADER',          0);
61define('H264_PROFILE_BASELINE',            66);
62define('H264_PROFILE_MAIN',                77);
63define('H264_PROFILE_EXTENDED',            88);
64define('H264_PROFILE_HIGH',               100);
65define('H264_PROFILE_HIGH10',             110);
66define('H264_PROFILE_HIGH422',            122);
67define('H264_PROFILE_HIGH444',            144);
68define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
69
70class getid3_flv extends getid3_handler
71{
72        public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration
73
74        public function Analyze() {
75                $info = &$this->getid3->info;
76
77                fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
78
79                $FLVdataLength = $info['avdataend'] - $info['avdataoffset'];
80                $FLVheader = fread($this->getid3->fp, 5);
81
82                $info['fileformat'] = 'flv';
83                $info['flv']['header']['signature'] =                           substr($FLVheader, 0, 3);
84                $info['flv']['header']['version']   = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
85                $TypeFlags                          = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
86
87                $magic = 'FLV';
88                if ($info['flv']['header']['signature'] != $magic) {
89                        $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';
90                        unset($info['flv']);
91                        unset($info['fileformat']);
92                        return false;
93                }
94
95                $info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04);
96                $info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01);
97
98                $FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4));
99                $FLVheaderFrameLength = 9;
100                if ($FrameSizeDataLength > $FLVheaderFrameLength) {
101                        fseek($this->getid3->fp, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
102                }
103                $Duration = 0;
104                $found_video = false;
105                $found_audio = false;
106                $found_meta  = false;
107                $found_valid_meta_playtime = false;
108                $tagParseCount = 0;
109                $info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0);
110                $flv_framecount = &$info['flv']['framecount'];
111                while (((ftell($this->getid3->fp) + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime))  {
112                        $ThisTagHeader = fread($this->getid3->fp, 16);
113
114                        $PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader,  0, 4));
115                        $TagType           = getid3_lib::BigEndian2Int(substr($ThisTagHeader,  4, 1));
116                        $DataLength        = getid3_lib::BigEndian2Int(substr($ThisTagHeader,  5, 3));
117                        $Timestamp         = getid3_lib::BigEndian2Int(substr($ThisTagHeader,  8, 3));
118                        $LastHeaderByte    = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1));
119                        $NextOffset = ftell($this->getid3->fp) - 1 + $DataLength;
120                        if ($Timestamp > $Duration) {
121                                $Duration = $Timestamp;
122                        }
123
124                        $flv_framecount['total']++;
125                        switch ($TagType) {
126                                case GETID3_FLV_TAG_AUDIO:
127                                        $flv_framecount['audio']++;
128                                        if (!$found_audio) {
129                                                $found_audio = true;
130                                                $info['flv']['audio']['audioFormat']     = ($LastHeaderByte >> 4) & 0x0F;
131                                                $info['flv']['audio']['audioRate']       = ($LastHeaderByte >> 2) & 0x03;
132                                                $info['flv']['audio']['audioSampleSize'] = ($LastHeaderByte >> 1) & 0x01;
133                                                $info['flv']['audio']['audioType']       =  $LastHeaderByte       & 0x01;
134                                        }
135                                        break;
136
137                                case GETID3_FLV_TAG_VIDEO:
138                                        $flv_framecount['video']++;
139                                        if (!$found_video) {
140                                                $found_video = true;
141                                                $info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
142
143                                                $FLVvideoHeader = fread($this->getid3->fp, 11);
144
145                                                if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
146                                                        // this code block contributed by: moysevichØgmail*com
147
148                                                        $AVCPacketType = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 0, 1));
149                                                        if ($AVCPacketType == H264_AVC_SEQUENCE_HEADER) {
150                                                                //      read AVCDecoderConfigurationRecord
151                                                                $configurationVersion       = getid3_lib::BigEndian2Int(substr($FLVvideoHeader,  4, 1));
152                                                                $AVCProfileIndication       = getid3_lib::BigEndian2Int(substr($FLVvideoHeader,  5, 1));
153                                                                $profile_compatibility      = getid3_lib::BigEndian2Int(substr($FLVvideoHeader,  6, 1));
154                                                                $lengthSizeMinusOne         = getid3_lib::BigEndian2Int(substr($FLVvideoHeader,  7, 1));
155                                                                $numOfSequenceParameterSets = getid3_lib::BigEndian2Int(substr($FLVvideoHeader,  8, 1));
156
157                                                                if (($numOfSequenceParameterSets & 0x1F) != 0) {
158                                                                        //      there is at least one SequenceParameterSet
159                                                                        //      read size of the first SequenceParameterSet
160                                                                        //$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2));
161                                                                        $spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2));
162                                                                        //      read the first SequenceParameterSet
163                                                                        $sps = fread($this->getid3->fp, $spsSize);
164                                                                        if (strlen($sps) == $spsSize) { //      make sure that whole SequenceParameterSet was red
165                                                                                $spsReader = new AVCSequenceParameterSetReader($sps);
166                                                                                $spsReader->readData();
167                                                                                $info['video']['resolution_x'] = $spsReader->getWidth();
168                                                                                $info['video']['resolution_y'] = $spsReader->getHeight();
169                                                                        }
170                                                                }
171                                                        }
172                                                        // end: moysevichØgmail*com
173
174                                                } elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H263) {
175
176                                                        $PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7;
177                                                        $PictureSizeType = $PictureSizeType & 0x0007;
178                                                        $info['flv']['header']['videoSizeType'] = $PictureSizeType;
179                                                        switch ($PictureSizeType) {
180                                                                case 0:
181                                                                        //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
182                                                                        //$PictureSizeEnc <<= 1;
183                                                                        //$info['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
184                                                                        //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
185                                                                        //$PictureSizeEnc <<= 1;
186                                                                        //$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
187
188                                                                        $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2));
189                                                                        $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
190                                                                        $PictureSizeEnc['x'] >>= 7;
191                                                                        $PictureSizeEnc['y'] >>= 7;
192                                                                        $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF;
193                                                                        $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF;
194                                                                        break;
195
196                                                                case 1:
197                                                                        $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3));
198                                                                        $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3));
199                                                                        $PictureSizeEnc['x'] >>= 7;
200                                                                        $PictureSizeEnc['y'] >>= 7;
201                                                                        $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF;
202                                                                        $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF;
203                                                                        break;
204
205                                                                case 2:
206                                                                        $info['video']['resolution_x'] = 352;
207                                                                        $info['video']['resolution_y'] = 288;
208                                                                        break;
209
210                                                                case 3:
211                                                                        $info['video']['resolution_x'] = 176;
212                                                                        $info['video']['resolution_y'] = 144;
213                                                                        break;
214
215                                                                case 4:
216                                                                        $info['video']['resolution_x'] = 128;
217                                                                        $info['video']['resolution_y'] = 96;
218                                                                        break;
219
220                                                                case 5:
221                                                                        $info['video']['resolution_x'] = 320;
222                                                                        $info['video']['resolution_y'] = 240;
223                                                                        break;
224
225                                                                case 6:
226                                                                        $info['video']['resolution_x'] = 160;
227                                                                        $info['video']['resolution_y'] = 120;
228                                                                        break;
229
230                                                                default:
231                                                                        $info['video']['resolution_x'] = 0;
232                                                                        $info['video']['resolution_y'] = 0;
233                                                                        break;
234
235                                                        }
236                                                }
237                                                $info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y'];
238                                        }
239                                        break;
240
241                                // Meta tag
242                                case GETID3_FLV_TAG_META:
243                                        if (!$found_meta) {
244                                                $found_meta = true;
245                                                fseek($this->getid3->fp, -1, SEEK_CUR);
246                                                $datachunk = fread($this->getid3->fp, $DataLength);
247                                                $AMFstream = new AMFStream($datachunk);
248                                                $reader = new AMFReader($AMFstream);
249                                                $eventName = $reader->readData();
250                                                $info['flv']['meta'][$eventName] = $reader->readData();
251                                                unset($reader);
252
253                                                $copykeys = array('framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate');
254                                                foreach ($copykeys as $sourcekey => $destkey) {
255                                                        if (isset($info['flv']['meta']['onMetaData'][$sourcekey])) {
256                                                                switch ($sourcekey) {
257                                                                        case 'width':
258                                                                        case 'height':
259                                                                                $info['video'][$destkey] = intval(round($info['flv']['meta']['onMetaData'][$sourcekey]));
260                                                                                break;
261                                                                        case 'audiodatarate':
262                                                                                $info['audio'][$destkey] = getid3_lib::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000));
263                                                                                break;
264                                                                        case 'videodatarate':
265                                                                        case 'frame_rate':
266                                                                        default:
267                                                                                $info['video'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey];
268                                                                                break;
269                                                                }
270                                                        }
271                                                }
272                                                if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
273                                                        $found_valid_meta_playtime = true;
274                                                }
275                                        }
276                                        break;
277
278                                default:
279                                        // noop
280                                        break;
281                        }
282                        fseek($this->getid3->fp, $NextOffset, SEEK_SET);
283                }
284
285                $info['playtime_seconds'] = $Duration / 1000;
286                if ($info['playtime_seconds'] > 0) {
287                        $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
288                }
289
290                if ($info['flv']['header']['hasAudio']) {
291                        $info['audio']['codec']           =   $this->FLVaudioFormat($info['flv']['audio']['audioFormat']);
292                        $info['audio']['sample_rate']     =     $this->FLVaudioRate($info['flv']['audio']['audioRate']);
293                        $info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info['flv']['audio']['audioSampleSize']);
294
295                        $info['audio']['channels']   =  $info['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
296                        $info['audio']['lossless']   = ($info['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
297                        $info['audio']['dataformat'] = 'flv';
298                }
299                if (!empty($info['flv']['header']['hasVideo'])) {
300                        $info['video']['codec']      = $this->FLVvideoCodec($info['flv']['video']['videoCodec']);
301                        $info['video']['dataformat'] = 'flv';
302                        $info['video']['lossless']   = false;
303                }
304
305                // Set information from meta
306                if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
307                        $info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration'];
308                        $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
309                }
310                if (isset($info['flv']['meta']['onMetaData']['audiocodecid'])) {
311                        $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['meta']['onMetaData']['audiocodecid']);
312                }
313                if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) {
314                        $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['meta']['onMetaData']['videocodecid']);
315                }
316                return true;
317        }
318
319
320        public function FLVaudioFormat($id) {
321                $FLVaudioFormat = array(
322                        0  => 'Linear PCM, platform endian',
323                        1  => 'ADPCM',
324                        2  => 'mp3',
325                        3  => 'Linear PCM, little endian',
326                        4  => 'Nellymoser 16kHz mono',
327                        5  => 'Nellymoser 8kHz mono',
328                        6  => 'Nellymoser',
329                        7  => 'G.711A-law logarithmic PCM',
330                        8  => 'G.711 mu-law logarithmic PCM',
331                        9  => 'reserved',
332                        10 => 'AAC',
333                        11 => false, // unknown?
334                        12 => false, // unknown?
335                        13 => false, // unknown?
336                        14 => 'mp3 8kHz',
337                        15 => 'Device-specific sound',
338                );
339                return (isset($FLVaudioFormat[$id]) ? $FLVaudioFormat[$id] : false);
340        }
341
342        public function FLVaudioRate($id) {
343                $FLVaudioRate = array(
344                        0 =>  5500,
345                        1 => 11025,
346                        2 => 22050,
347                        3 => 44100,
348                );
349                return (isset($FLVaudioRate[$id]) ? $FLVaudioRate[$id] : false);
350        }
351
352        public function FLVaudioBitDepth($id) {
353                $FLVaudioBitDepth = array(
354                        0 =>  8,
355                        1 => 16,
356                );
357                return (isset($FLVaudioBitDepth[$id]) ? $FLVaudioBitDepth[$id] : false);
358        }
359
360        public function FLVvideoCodec($id) {
361                $FLVvideoCodec = array(
362                        GETID3_FLV_VIDEO_H263         => 'Sorenson H.263',
363                        GETID3_FLV_VIDEO_SCREEN       => 'Screen video',
364                        GETID3_FLV_VIDEO_VP6FLV       => 'On2 VP6',
365                        GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel',
366                        GETID3_FLV_VIDEO_SCREENV2     => 'Screen video v2',
367                        GETID3_FLV_VIDEO_H264         => 'Sorenson H.264',
368                );
369                return (isset($FLVvideoCodec[$id]) ? $FLVvideoCodec[$id] : false);
370        }
371}
372
373class AMFStream {
374        public $bytes;
375        public $pos;
376
377        public function AMFStream(&$bytes) {
378                $this->bytes =& $bytes;
379                $this->pos = 0;
380        }
381
382        public function readByte() {
383                return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
384        }
385
386        public function readInt() {
387                return ($this->readByte() << 8) + $this->readByte();
388        }
389
390        public function readLong() {
391                return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
392        }
393
394        public function readDouble() {
395                return getid3_lib::BigEndian2Float($this->read(8));
396        }
397
398        public function readUTF() {
399                $length = $this->readInt();
400                return $this->read($length);
401        }
402
403        public function readLongUTF() {
404                $length = $this->readLong();
405                return $this->read($length);
406        }
407
408        public function read($length) {
409                $val = substr($this->bytes, $this->pos, $length);
410                $this->pos += $length;
411                return $val;
412        }
413
414        public function peekByte() {
415                $pos = $this->pos;
416                $val = $this->readByte();
417                $this->pos = $pos;
418                return $val;
419        }
420
421        public function peekInt() {
422                $pos = $this->pos;
423                $val = $this->readInt();
424                $this->pos = $pos;
425                return $val;
426        }
427
428        public function peekLong() {
429                $pos = $this->pos;
430                $val = $this->readLong();
431                $this->pos = $pos;
432                return $val;
433        }
434
435        public function peekDouble() {
436                $pos = $this->pos;
437                $val = $this->readDouble();
438                $this->pos = $pos;
439                return $val;
440        }
441
442        public function peekUTF() {
443                $pos = $this->pos;
444                $val = $this->readUTF();
445                $this->pos = $pos;
446                return $val;
447        }
448
449        public function peekLongUTF() {
450                $pos = $this->pos;
451                $val = $this->readLongUTF();
452                $this->pos = $pos;
453                return $val;
454        }
455}
456
457class AMFReader {
458        public $stream;
459
460        public function AMFReader(&$stream) {
461                $this->stream =& $stream;
462        }
463
464        public function readData() {
465                $value = null;
466
467                $type = $this->stream->readByte();
468                switch ($type) {
469
470                        // Double
471                        case 0:
472                                $value = $this->readDouble();
473                        break;
474
475                        // Boolean
476                        case 1:
477                                $value = $this->readBoolean();
478                                break;
479
480                        // String
481                        case 2:
482                                $value = $this->readString();
483                                break;
484
485                        // Object
486                        case 3:
487                                $value = $this->readObject();
488                                break;
489
490                        // null
491                        case 6:
492                                return null;
493                                break;
494
495                        // Mixed array
496                        case 8:
497                                $value = $this->readMixedArray();
498                                break;
499
500                        // Array
501                        case 10:
502                                $value = $this->readArray();
503                                break;
504
505                        // Date
506                        case 11:
507                                $value = $this->readDate();
508                                break;
509
510                        // Long string
511                        case 13:
512                                $value = $this->readLongString();
513                                break;
514
515                        // XML (handled as string)
516                        case 15:
517                                $value = $this->readXML();
518                                break;
519
520                        // Typed object (handled as object)
521                        case 16:
522                                $value = $this->readTypedObject();
523                                break;
524
525                        // Long string
526                        default:
527                                $value = '(unknown or unsupported data type)';
528                        break;
529                }
530
531                return $value;
532        }
533
534        public function readDouble() {
535                return $this->stream->readDouble();
536        }
537
538        public function readBoolean() {
539                return $this->stream->readByte() == 1;
540        }
541
542        public function readString() {
543                return $this->stream->readUTF();
544        }
545
546        public function readObject() {
547                // Get highest numerical index - ignored
548//              $highestIndex = $this->stream->readLong();
549
550                $data = array();
551
552                while ($key = $this->stream->readUTF()) {
553                        $data[$key] = $this->readData();
554                }
555                // Mixed array record ends with empty string (0x00 0x00) and 0x09
556                if (($key == '') && ($this->stream->peekByte() == 0x09)) {
557                        // Consume byte
558                        $this->stream->readByte();
559                }
560                return $data;
561        }
562
563        public function readMixedArray() {
564                // Get highest numerical index - ignored
565                $highestIndex = $this->stream->readLong();
566
567                $data = array();
568
569                while ($key = $this->stream->readUTF()) {
570                        if (is_numeric($key)) {
571                                $key = (float) $key;
572                        }
573                        $data[$key] = $this->readData();
574                }
575                // Mixed array record ends with empty string (0x00 0x00) and 0x09
576                if (($key == '') && ($this->stream->peekByte() == 0x09)) {
577                        // Consume byte
578                        $this->stream->readByte();
579                }
580
581                return $data;
582        }
583
584        public function readArray() {
585                $length = $this->stream->readLong();
586                $data = array();
587
588                for ($i = 0; $i < $length; $i++) {
589                        $data[] = $this->readData();
590                }
591                return $data;
592        }
593
594        public function readDate() {
595                $timestamp = $this->stream->readDouble();
596                $timezone = $this->stream->readInt();
597                return $timestamp;
598        }
599
600        public function readLongString() {
601                return $this->stream->readLongUTF();
602        }
603
604        public function readXML() {
605                return $this->stream->readLongUTF();
606        }
607
608        public function readTypedObject() {
609                $className = $this->stream->readUTF();
610                return $this->readObject();
611        }
612}
613
614class AVCSequenceParameterSetReader {
615        public $sps;
616        public $start = 0;
617        public $currentBytes = 0;
618        public $currentBits = 0;
619        public $width;
620        public $height;
621
622        public function AVCSequenceParameterSetReader($sps) {
623                $this->sps = $sps;
624        }
625
626        public function readData() {
627                $this->skipBits(8);
628                $this->skipBits(8);
629                $profile = $this->getBits(8);   //      read profile
630                $this->skipBits(16);
631                $this->expGolombUe();   //      read sps id
632                if (in_array($profile, array(H264_PROFILE_HIGH, H264_PROFILE_HIGH10, H264_PROFILE_HIGH422, H264_PROFILE_HIGH444, H264_PROFILE_HIGH444_PREDICTIVE))) {
633                        if ($this->expGolombUe() == 3) {
634                                $this->skipBits(1);
635                        }
636                        $this->expGolombUe();
637                        $this->expGolombUe();
638                        $this->skipBits(1);
639                        if ($this->getBit()) {
640                                for ($i = 0; $i < 8; $i++) {
641                                        if ($this->getBit()) {
642                                                $size = $i < 6 ? 16 : 64;
643                                                $lastScale = 8;
644                                                $nextScale = 8;
645                                                for ($j = 0; $j < $size; $j++) {
646                                                        if ($nextScale != 0) {
647                                                                $deltaScale = $this->expGolombUe();
648                                                                $nextScale = ($lastScale + $deltaScale + 256) % 256;
649                                                        }
650                                                        if ($nextScale != 0) {
651                                                                $lastScale = $nextScale;
652                                                        }
653                                                }
654                                        }
655                                }
656                        }
657                }
658                $this->expGolombUe();
659                $pocType = $this->expGolombUe();
660                if ($pocType == 0) {
661                        $this->expGolombUe();
662                } elseif ($pocType == 1) {
663                        $this->skipBits(1);
664                        $this->expGolombSe();
665                        $this->expGolombSe();
666                        $pocCycleLength = $this->expGolombUe();
667                        for ($i = 0; $i < $pocCycleLength; $i++) {
668                                $this->expGolombSe();
669                        }
670                }
671                $this->expGolombUe();
672                $this->skipBits(1);
673                $this->width = ($this->expGolombUe() + 1) * 16;
674                $heightMap = $this->expGolombUe() + 1;
675                $this->height = (2 - $this->getBit()) * $heightMap * 16;
676        }
677
678        public function skipBits($bits) {
679                $newBits = $this->currentBits + $bits;
680                $this->currentBytes += (int)floor($newBits / 8);
681                $this->currentBits = $newBits % 8;
682        }
683
684        public function getBit() {
685                $result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
686                $this->skipBits(1);
687                return $result;
688        }
689
690        public function getBits($bits) {
691                $result = 0;
692                for ($i = 0; $i < $bits; $i++) {
693                        $result = ($result << 1) + $this->getBit();
694                }
695                return $result;
696        }
697
698        public function expGolombUe() {
699                $significantBits = 0;
700                $bit = $this->getBit();
701                while ($bit == 0) {
702                        $significantBits++;
703                        $bit = $this->getBit();
704
705                        if ($significantBits > 31) {
706                                // something is broken, this is an emergency escape to prevent infinite loops
707                                return 0;
708                        }
709                }
710                return (1 << $significantBits) + $this->getBits($significantBits) - 1;
711        }
712
713        public function expGolombSe() {
714                $result = $this->expGolombUe();
715                if (($result & 0x01) == 0) {
716                        return -($result >> 1);
717                } else {
718                        return ($result + 1) >> 1;
719                }
720        }
721
722        public function getWidth() {
723                return $this->width;
724        }
725
726        public function getHeight() {
727                return $this->height;
728        }
729}
Note: See TracBrowser for help on using the repository browser.