2
// +----------------------------------------------------------------------+
4
// +----------------------------------------------------------------------+
5
// | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
6
// +----------------------------------------------------------------------+
7
// | This source file is subject to version 2 of the GPL license, |
8
// | that is bundled with this package in the file license.txt and is |
9
// | available through the world-wide-web at the following url: |
10
// | http://www.gnu.org/copyleft/gpl.html |
11
// +----------------------------------------------------------------------+
12
// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
13
// +----------------------------------------------------------------------+
14
// | Authors: James Heinrich <info�getid3*org> |
15
// | Allan Hansen <ah�artemis*dk> |
16
// +----------------------------------------------------------------------+
17
// | module.archive.gzip.php |
18
// | module for analyzing GZIP files |
19
// | dependencies: NONE |
20
// +----------------------------------------------------------------------+
21
// | FLV module by Seth Kaufman <seth�whirl-i.gig*com> |
23
// | * version 0.1 (26 June 2005) |
25
// | minor modifications by James Heinrich <info�getid3*org> |
26
// | * version 0.1.1 (15 July 2005) |
28
// | Support for On2 VP6 codec and meta information by |
29
// | Steve Webster <steve.webster�featurecreep*com> |
30
// | * version 0.2 (22 February 2006) |
32
// | Modified to not read entire file into memory |
33
// | by James Heinrich <info�getid3*org> |
34
// | * version 0.3 (15 June 2006) |
36
// | Modifications by Allan Hansen <ah�artemis*dk> |
37
// | Adapted module for PHP5 and getID3 2.0.0. |
38
// +----------------------------------------------------------------------+
40
// $Id: module.audio-video.flv.php,v 1.7 2006/11/10 11:20:12 ah Exp $
44
class getid3_flv extends getid3_handler
52
const VIDEO_SCREEN = 3;
56
public function Analyze()
58
$info = &$this->getid3->info;
60
$info['flv'] = array ();
61
$info_flv = &$info['flv'];
63
fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
65
$flv_data_length = $info['avdataend'] - $info['avdataoffset'];
66
$flv_header = fread($this->getid3->fp, 5);
68
$info['fileformat'] = 'flv';
69
$info_flv['header']['signature'] = substr($flv_header, 0, 3);
70
$info_flv['header']['version'] = getid3_lib::BigEndian2Int(substr($flv_header, 3, 1));
71
$type_flags = getid3_lib::BigEndian2Int(substr($flv_header, 4, 1));
73
$info_flv['header']['hasAudio'] = (bool) ($type_flags & 0x04);
74
$info_flv['header']['hasVideo'] = (bool) ($type_flags & 0x01);
76
$frame_size_data_length = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4));
77
$flv_header_frame_length = 9;
78
if ($frame_size_data_length > $flv_header_frame_length) {
79
fseek($this->getid3->fp, $frame_size_data_length - $flv_header_frame_length, SEEK_CUR);
83
while ((ftell($this->getid3->fp) + 1) < $info['avdataend']) {
85
$this_tag_header = fread($this->getid3->fp, 16);
87
$previous_tag_length = getid3_lib::BigEndian2Int(substr($this_tag_header, 0, 4));
88
$tag_type = getid3_lib::BigEndian2Int(substr($this_tag_header, 4, 1));
89
$data_length = getid3_lib::BigEndian2Int(substr($this_tag_header, 5, 3));
90
$timestamp = getid3_lib::BigEndian2Int(substr($this_tag_header, 8, 3));
91
$last_header_byte = getid3_lib::BigEndian2Int(substr($this_tag_header, 15, 1));
92
$next_offset = ftell($this->getid3->fp) - 1 + $data_length;
96
case getid3_flv::TAG_AUDIO:
97
if (!isset($info_flv['audio']['audioFormat'])) {
98
$info_flv['audio']['audioFormat'] = $last_header_byte & 0x07;
99
$info_flv['audio']['audioRate'] = ($last_header_byte & 0x30) / 0x10;
100
$info_flv['audio']['audioSampleSize'] = ($last_header_byte & 0x40) / 0x40;
101
$info_flv['audio']['audioType'] = ($last_header_byte & 0x80) / 0x80;
106
case getid3_flv::TAG_VIDEO:
107
if (!isset($info_flv['video']['videoCodec'])) {
108
$info_flv['video']['videoCodec'] = $last_header_byte & 0x07;
110
$flv_video_header = fread($this->getid3->fp, 11);
112
if ($info_flv['video']['videoCodec'] != getid3_flv::VIDEO_VP6) {
114
$picture_size_type = (getid3_lib::BigEndian2Int(substr($flv_video_header, 3, 2))) >> 7;
115
$picture_size_type = $picture_size_type & 0x0007;
116
$info_flv['header']['videoSizeType'] = $picture_size_type;
118
switch ($picture_size_type) {
120
$picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 5, 2));
121
$picture_size_enc <<= 1;
122
$info['video']['resolution_x'] = ($picture_size_enc & 0xFF00) >> 8;
123
$picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 6, 2));
124
$picture_size_enc <<= 1;
125
$info['video']['resolution_y'] = ($picture_size_enc & 0xFF00) >> 8;
129
$picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 5, 4));
130
$picture_size_enc <<= 1;
131
$info['video']['resolution_x'] = ($picture_size_enc & 0xFFFF0000) >> 16;
133
$picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 7, 4));
134
$picture_size_enc <<= 1;
135
$info['video']['resolution_y'] = ($picture_size_enc & 0xFFFF0000) >> 16;
139
$info['video']['resolution_x'] = 352;
140
$info['video']['resolution_y'] = 288;
144
$info['video']['resolution_x'] = 176;
145
$info['video']['resolution_y'] = 144;
149
$info['video']['resolution_x'] = 128;
150
$info['video']['resolution_y'] = 96;
154
$info['video']['resolution_x'] = 320;
155
$info['video']['resolution_y'] = 240;
159
$info['video']['resolution_x'] = 160;
160
$info['video']['resolution_y'] = 120;
164
$info['video']['resolution_x'] = 0;
165
$info['video']['resolution_y'] = 0;
174
case getid3_flv::TAG_META:
176
fseek($this->getid3->fp, -1, SEEK_CUR);
177
$reader = new AMFReader(new AMFStream(fread($this->getid3->fp, $data_length)));
178
$event_name = $reader->readData();
179
$info['meta'][$event_name] = $reader->readData();
182
$info['video']['frame_rate'] = @$info['meta']['onMetaData']['framerate'];
183
$info['video']['resolution_x'] = @$info['meta']['onMetaData']['width'];
184
$info['video']['resolution_y'] = @$info['meta']['onMetaData']['height'];
192
if ($timestamp > $duration) {
193
$duration = $timestamp;
196
fseek($this->getid3->fp, $next_offset, SEEK_SET);
199
if ($info['playtime_seconds'] = $duration / 1000) {
200
$info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'];
203
if ($info_flv['header']['hasAudio']) {
204
$info['audio']['codec'] = $this->FLVaudioFormat($info_flv['audio']['audioFormat']);
205
$info['audio']['sample_rate'] = $this->FLVaudioRate($info_flv['audio']['audioRate']);
206
$info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info_flv['audio']['audioSampleSize']);
208
$info['audio']['channels'] = $info_flv['audio']['audioType'] + 1; // 0=mono,1=stereo
209
$info['audio']['lossless'] = ($info_flv['audio']['audioFormat'] ? false : true); // 0=uncompressed
210
$info['audio']['dataformat'] = 'flv';
212
if (@$info_flv['header']['hasVideo']) {
213
$info['video']['codec'] = $this->FLVvideoCodec($info_flv['video']['videoCodec']);
214
$info['video']['dataformat'] = 'flv';
215
$info['video']['lossless'] = false;
222
public static function FLVaudioFormat($id) {
224
static $lookup = array(
228
5 => 'Nellymoser 8kHz mono',
231
return (@$lookup[$id] ? @$lookup[$id] : false);
235
public static function FLVaudioRate($id) {
237
static $lookup = array(
243
return (@$lookup[$id] ? @$lookup[$id] : false);
247
public static function FLVaudioBitDepth($id) {
249
static $lookup = array(
253
return (@$lookup[$id] ? @$lookup[$id] : false);
257
public static function FLVvideoCodec($id) {
259
static $lookup = array(
260
getid3_flv::VIDEO_H263 => 'Sorenson H.263',
261
getid3_flv::VIDEO_SCREEN => 'Screen video',
262
getid3_flv::VIDEO_VP6 => 'On2 VP6',
264
return (@$lookup[$id] ? @$lookup[$id] : false);
276
public function AMFStream($bytes) {
278
$this->bytes = $bytes;
283
public function readByte() {
285
return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
289
public function readInt() {
291
return ($this->readByte() << 8) + $this->readByte();
295
public function readLong() {
297
return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
301
public function readDouble() {
303
return getid3_lib::BigEndian2Float($this->read(8));
307
public function readUTF() {
309
$length = $this->readInt();
310
return $this->read($length);
314
public function readLongUTF() {
316
$length = $this->readLong();
317
return $this->read($length);
321
public function read($length) {
323
$val = substr($this->bytes, $this->pos, $length);
324
$this->pos += $length;
329
public function peekByte() {
332
$val = $this->readByte();
338
public function peekInt() {
341
$val = $this->readInt();
347
public function peekLong() {
350
$val = $this->readLong();
356
public function peekDouble() {
359
$val = $this->readDouble();
365
public function peekUTF() {
368
$val = $this->readUTF();
374
public function peekLongUTF() {
377
$val = $this->readLongUTF();
389
public function __construct($stream) {
391
$this->stream = $stream;
395
public function readData() {
399
$type = $this->stream->readByte();
404
$value = $this->readDouble();
409
$value = $this->readBoolean();
414
$value = $this->readString();
419
$value = $this->readObject();
429
$value = $this->readMixedArray();
434
$value = $this->readArray();
439
$value = $this->readDate();
444
$value = $this->readLongString();
447
// XML (handled as string)
449
$value = $this->readXML();
452
// Typed object (handled as object)
454
$value = $this->readTypedObject();
459
$value = '(unknown or unsupported data type)';
467
public function readDouble() {
469
return $this->stream->readDouble();
473
public function readBoolean() {
475
return $this->stream->readByte() == 1;
479
public function readString() {
481
return $this->stream->readUTF();
485
public function readObject() {
487
// Get highest numerical index - ignored
488
$highestIndex = $this->stream->readLong();
492
while ($key = $this->stream->readUTF()) {
493
// Mixed array record ends with empty string (0x00 0x00) and 0x09
494
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
496
$this->stream->readByte();
500
$data[$key] = $this->readData();
507
public function readMixedArray() {
509
// Get highest numerical index - ignored
510
$highestIndex = $this->stream->readLong();
514
while ($key = $this->stream->readUTF()) {
515
// Mixed array record ends with empty string (0x00 0x00) and 0x09
516
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
518
$this->stream->readByte();
522
if (is_numeric($key)) {
526
$data[$key] = $this->readData();
533
public function readArray() {
535
$length = $this->stream->readLong();
539
for ($i = 0; $i < count($length); $i++) {
540
$data[] = $this->readData();
547
public function readDate() {
549
$timestamp = $this->stream->readDouble();
550
$timezone = $this->stream->readInt();
555
public function readLongString() {
557
return $this->stream->readLongUTF();
561
public function readXML() {
563
return $this->stream->readLongUTF();
567
public function readTypedObject() {
569
$className = $this->stream->readUTF();
570
return $this->readObject();
b'\\ No newline at end of file'