Add support for program info descriptors
We were assuming that the program_info_descriptors field in the program mapping table was always of zero length and would end up misaligned reading the table entries if that metadata was present. Also added helper functions for testing to generate mp2t packets.
Showing
2 changed files
with
141 additions
and
0 deletions
This diff is collapsed.
Click to expand it.
... | @@ -26,6 +26,9 @@ | ... | @@ -26,6 +26,9 @@ |
26 | 0x46, 0x4c, 0x56, 0x01, 0x05, 0x00, 0x00, 0x00, | 26 | 0x46, 0x4c, 0x56, 0x01, 0x05, 0x00, 0x00, 0x00, |
27 | 0x09, 0x00, 0x00, 0x00, 0x00 | 27 | 0x09, 0x00, 0x00, 0x00, 0x00 |
28 | ], | 28 | ], |
29 | |||
30 | extend = videojs.util.mergeOptions, | ||
31 | |||
29 | testAudioTag, | 32 | testAudioTag, |
30 | testVideoTag, | 33 | testVideoTag, |
31 | testScriptTag, | 34 | testScriptTag, |
... | @@ -51,6 +54,144 @@ | ... | @@ -51,6 +54,144 @@ |
51 | deepEqual(expectedHeader, header, 'the rest of the header is correct'); | 54 | deepEqual(expectedHeader, header, 'the rest of the header is correct'); |
52 | }); | 55 | }); |
53 | 56 | ||
57 | test('parses PMTs with program descriptors', function() { | ||
58 | var | ||
59 | makePmt = function(options) { | ||
60 | var | ||
61 | result = [], | ||
62 | entryCount = 0, | ||
63 | k, | ||
64 | sectionLength; | ||
65 | for (k in options.pids) { | ||
66 | entryCount++; | ||
67 | } | ||
68 | // table_id | ||
69 | result.push(0x02); | ||
70 | // section_syntax_indicator '0' reserved section_length | ||
71 | // 13 + (program_info_length) + (n * 5 + ES_info_length[n]) | ||
72 | sectionLength = 13 + (5 * entryCount) + 17; | ||
73 | result.push(0x80 | (0xF00 & sectionLength >>> 8)); | ||
74 | result.push(sectionLength & 0xFF); | ||
75 | // program_number | ||
76 | result.push(0x00); | ||
77 | result.push(0x01); | ||
78 | // reserved version_number current_next_indicator | ||
79 | result.push(0x01); | ||
80 | // section_number | ||
81 | result.push(0x00); | ||
82 | // last_section_number | ||
83 | result.push(0x00); | ||
84 | // reserved PCR_PID | ||
85 | result.push(0xe1); | ||
86 | result.push(0x00); | ||
87 | // reserved program_info_length | ||
88 | result.push(0xf0); | ||
89 | result.push(0x11); // hard-coded 17 byte descriptor | ||
90 | // program descriptors | ||
91 | result = result.concat([ | ||
92 | 0x25, 0x0f, 0xff, 0xff, | ||
93 | 0x49, 0x44, 0x33, 0x20, | ||
94 | 0xff, 0x49, 0x44, 0x33, | ||
95 | 0x20, 0x00, 0x1f, 0x00, | ||
96 | 0x01 | ||
97 | ]); | ||
98 | for (k in options.pids) { | ||
99 | // stream_type | ||
100 | result.push(options.pids[k]); | ||
101 | // reserved elementary_PID | ||
102 | result.push(0xe0 | (k & 0x1f00) >>> 8); | ||
103 | result.push(k & 0xff); | ||
104 | // reserved ES_info_length | ||
105 | result.push(0xf0); | ||
106 | result.push(0x00); // ES_info_length = 0 | ||
107 | } | ||
108 | // CRC_32 | ||
109 | result.push([0x00, 0x00, 0x00, 0x00]); // invalid CRC but we don't check it | ||
110 | return result; | ||
111 | }, | ||
112 | makePat = function(options) { | ||
113 | var | ||
114 | result = [], | ||
115 | k; | ||
116 | // table_id | ||
117 | result.push(0x00); | ||
118 | // section_syntax_indicator '0' reserved section_length | ||
119 | result.push(0x80); | ||
120 | result.push(0x0d); // section_length for one program | ||
121 | // transport_stream_id | ||
122 | result.push(0x00); | ||
123 | result.push(0x00); | ||
124 | // reserved version_number current_next_indicator | ||
125 | result.push(0x01); // current_next_indicator is 1 | ||
126 | // section_number | ||
127 | result.push(0x00); | ||
128 | // last_section_number | ||
129 | result.push(0x00); | ||
130 | for (k in options.programs) { | ||
131 | // program_number | ||
132 | result.push((k & 0xFF00) >>> 8); | ||
133 | result.push(k & 0x00FF); | ||
134 | // reserved program_map_pid | ||
135 | result.push((options.programs[k] & 0x1f00) >>> 8); | ||
136 | result.push(options.programs[k] & 0xff); | ||
137 | } | ||
138 | return result; | ||
139 | }, | ||
140 | makePsi = function(options) { | ||
141 | var result = []; | ||
142 | |||
143 | // pointer_field | ||
144 | if (options.payloadUnitStartIndicator) { | ||
145 | result.push(0x00); | ||
146 | } | ||
147 | if (options.programs) { | ||
148 | return result.concat(makePat(options)); | ||
149 | } | ||
150 | return result.concat(makePmt(options)); | ||
151 | }, | ||
152 | makePacket = function(options) { | ||
153 | var | ||
154 | result = [], | ||
155 | settings = extend({ | ||
156 | payloadUnitStartIndicator: true, | ||
157 | pid: 0x00 | ||
158 | }, options), | ||
159 | pid; | ||
160 | |||
161 | // header | ||
162 | // sync_byte | ||
163 | result.push(0x47); | ||
164 | // transport_error_indicator payload_unit_start_indicator transport_priority PID | ||
165 | result.push((settings.pid & 0x1f) << 8 | 0x40); | ||
166 | result.push(settings.pid & 0xff); | ||
167 | // transport_scrambling_control adaptation_field_control continuity_counter | ||
168 | result.push(0x10); | ||
169 | result = result.concat(makePsi(settings)); | ||
170 | |||
171 | // ensure the resulting packet is the correct size | ||
172 | result.length = videojs.hls.SegmentParser.MP2T_PACKET_LENGTH; | ||
173 | return result; | ||
174 | }, | ||
175 | h264Type = videojs.hls.SegmentParser.STREAM_TYPES.h264, | ||
176 | adtsType = videojs.hls.SegmentParser.STREAM_TYPES.adts; | ||
177 | |||
178 | parser.parseSegmentBinaryData(new Uint8Array(makePacket({ | ||
179 | programs: { | ||
180 | 0x01: [0x01] | ||
181 | } | ||
182 | }).concat(makePacket({ | ||
183 | pid: 0x01, | ||
184 | pids: { | ||
185 | 0x02: h264Type, // h264 video | ||
186 | 0x03: adtsType // adts audio | ||
187 | } | ||
188 | })))); | ||
189 | |||
190 | strictEqual(parser.stream.pmtPid, 0x01, 'PMT PID is 1'); | ||
191 | strictEqual(parser.stream.programMapTable[h264Type], 0x02, 'video is PID 2'); | ||
192 | strictEqual(parser.stream.programMapTable[adtsType], 0x03, 'audio is PID 3'); | ||
193 | }); | ||
194 | |||
54 | test('parses the first bipbop segment', function() { | 195 | test('parses the first bipbop segment', function() { |
55 | parser.parseSegmentBinaryData(window.bcSegment); | 196 | parser.parseSegmentBinaryData(window.bcSegment); |
56 | 197 | ... | ... |
-
Please register or sign in to post a comment