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