Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 23 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
MP4Reader | |
0.00% |
0 / 23 |
|
0.00% |
0 / 10 |
182 | |
0.00% |
0 / 1 |
readInt | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
read64 | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
read32 | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
read24 | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
read16 | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
read8 | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
readType | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
readBox | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
findBox | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
expectBox | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | /** |
3 | * .m3u8 playlist generation for HLS (HTTP Live Streaming) |
4 | * |
5 | * @file |
6 | * @ingroup HLS |
7 | */ |
8 | |
9 | namespace MediaWiki\TimedMediaHandler\HLS; |
10 | |
11 | use Exception; |
12 | |
13 | /** |
14 | * Adds MP4/ISO BMFF/QuickTime box decoding to the stream reader, |
15 | * making it easy to read media files with mixes of hierarchical |
16 | * boxes-within-boxes and straight data (usually all big-endian). |
17 | * |
18 | * Because the relevant ISO standards are not redistributable, |
19 | * artisinal 3rd-party documentation was sourced via web searches. |
20 | */ |
21 | class MP4Reader extends StreamReader { |
22 | |
23 | /** |
24 | * Read big-endian int |
25 | */ |
26 | protected function readInt( int $bytes, int $padto, string $code ): int { |
27 | $bytes = $this->read( $bytes ); |
28 | $padded = str_pad( $bytes, $padto, "\x00", STR_PAD_LEFT ); |
29 | $data = unpack( "{$code}val", $padded ); |
30 | return $data['val']; |
31 | } |
32 | |
33 | /** |
34 | * Read a 64-bit unsigned big-endian integer. |
35 | * @throws Exception on i/o error |
36 | * @throws ShortReadException on end of file |
37 | */ |
38 | public function read64(): int { |
39 | return $this->readInt( 8, 8, 'J' ); |
40 | } |
41 | |
42 | /** |
43 | * Read a 32-bit unsigned big-endian integer. |
44 | * @throws Exception on i/o error |
45 | * @throws ShortReadException on end of file |
46 | */ |
47 | public function read32(): int { |
48 | return $this->readInt( 4, 4, 'N' ); |
49 | } |
50 | |
51 | /** |
52 | * Read a 24-bit unsigned big-endian integer. |
53 | * @throws Exception on i/o error |
54 | * @throws ShortReadException on end of file |
55 | */ |
56 | public function read24(): int { |
57 | return $this->readInt( 3, 4, 'N' ); |
58 | } |
59 | |
60 | /** |
61 | * Read a 16-bit unsigned big-endian integer. |
62 | * @throws Exception on i/o error |
63 | * @throws ShortReadException on end of file |
64 | */ |
65 | public function read16(): int { |
66 | return $this->readInt( 2, 2, 'n' ); |
67 | } |
68 | |
69 | /** |
70 | * Read an 8-bit unsigned integer. |
71 | * @throws Exception on i/o error |
72 | * @throws ShortReadException on end of file |
73 | */ |
74 | public function read8(): int { |
75 | $byte = $this->read( 1 ); |
76 | return ord( $byte ); |
77 | } |
78 | |
79 | /** |
80 | * Read a 4-byte box type code. |
81 | * @throws Exception on i/o error |
82 | * @throws ShortReadException on end of file |
83 | */ |
84 | public function readType(): string { |
85 | return $this->read( 4 ); |
86 | } |
87 | |
88 | /** |
89 | * Read box metadata and return it as a sub-stream object. |
90 | * @throws Exception on i/o error |
91 | * @throws ShortReadException if no matching box found |
92 | */ |
93 | public function readBox(): MP4Box { |
94 | $start = $this->pos(); |
95 | $size = $this->read32(); |
96 | $type = $this->readType(); |
97 | $this->pos = $start + $size; |
98 | return new MP4Box( $this->file, $start, $size, $type ); |
99 | } |
100 | |
101 | /** |
102 | * Search through a series of boxes, discarding sibling boxes |
103 | * until the requested type is found. |
104 | * |
105 | * Returns null on end of input. |
106 | * |
107 | * @throws Exception on i/o error |
108 | */ |
109 | public function findBox( string $type ): ?MP4Box { |
110 | try { |
111 | return $this->expectBox( $type ); |
112 | } catch ( ShortReadException $e ) { |
113 | return null; |
114 | } |
115 | } |
116 | |
117 | /** |
118 | * Search through a series of boxes, discarding sibling boxes |
119 | * until the requested type is found. |
120 | * |
121 | * Same as findBox but throws if no match is found. |
122 | * |
123 | * @throws Exception on i/o error |
124 | * @throws ShortReadException if no matching box found |
125 | */ |
126 | public function expectBox( string $type ): MP4Box { |
127 | while ( true ) { |
128 | // will throw eventually |
129 | $box = $this->readBox(); |
130 | if ( $box->type === $type ) { |
131 | return $box; |
132 | } |
133 | } |
134 | } |
135 | } |