Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
MP4Reader
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 10
182
0.00% covered (danger)
0.00%
0 / 1
 readInt
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 read64
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 read32
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 read24
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 read16
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 read8
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 readType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 readBox
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 findBox
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 expectBox
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
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
9namespace MediaWiki\TimedMediaHandler\HLS;
10
11use 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 */
21class 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}