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