[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ID3/ -> module.audio-video.flv.php (source)

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


Generated: Sun Sep 15 01:00:03 2019 Cross-referenced by PHPXref 0.7.1