Merge pull request #288 from dmlap/ignore-nit2
Ignore nit2
Showing
2 changed files
with
76 additions
and
21 deletions
... | @@ -221,6 +221,9 @@ | ... | @@ -221,6 +221,9 @@ |
221 | patTableId, // :int | 221 | patTableId, // :int |
222 | patCurrentNextIndicator, // Boolean | 222 | patCurrentNextIndicator, // Boolean |
223 | patSectionLength, // :uint | 223 | patSectionLength, // :uint |
224 | programNumber, // :uint | ||
225 | programPid, // :uint | ||
226 | patEntriesEnd, // :uint | ||
224 | 227 | ||
225 | pesPacketSize, // :int, | 228 | pesPacketSize, // :int, |
226 | dataAlignmentIndicator, // :Boolean, | 229 | dataAlignmentIndicator, // :Boolean, |
... | @@ -293,6 +296,8 @@ | ... | @@ -293,6 +296,8 @@ |
293 | if (patCurrentNextIndicator) { | 296 | if (patCurrentNextIndicator) { |
294 | // section_length specifies the number of bytes following | 297 | // section_length specifies the number of bytes following |
295 | // its position to the end of this section | 298 | // its position to the end of this section |
299 | // section_length = rest of header + (n * entry length) + CRC | ||
300 | // = 5 + (n * 4) + 4 | ||
296 | patSectionLength = (data[offset + 1] & 0x0F) << 8 | data[offset + 2]; | 301 | patSectionLength = (data[offset + 1] & 0x0F) << 8 | data[offset + 2]; |
297 | // move past the rest of the PSI header to the first program | 302 | // move past the rest of the PSI header to the first program |
298 | // map table entry | 303 | // map table entry |
... | @@ -300,15 +305,22 @@ | ... | @@ -300,15 +305,22 @@ |
300 | 305 | ||
301 | // we don't handle streams with more than one program, so | 306 | // we don't handle streams with more than one program, so |
302 | // raise an exception if we encounter one | 307 | // raise an exception if we encounter one |
303 | // section_length = rest of header + (n * entry length) + CRC | 308 | patEntriesEnd = offset + (patSectionLength - 5 - 4); |
304 | // = 5 + (n * 4) + 4 | 309 | for (; offset < patEntriesEnd; offset += 4) { |
305 | if ((patSectionLength - 5 - 4) / 4 !== 1) { | 310 | programNumber = (data[offset] << 8 | data[offset + 1]); |
306 | throw new Error("TS has more that 1 program"); | 311 | programPid = (data[offset + 2] & 0x1F) << 8 | data[offset + 3]; |
312 | // network PID program number equals 0 | ||
313 | // this is primarily an artifact of EBU DVB and can be ignored | ||
314 | if (programNumber === 0) { | ||
315 | self.stream.networkPid = programPid; | ||
316 | } else if (self.stream.pmtPid === undefined) { | ||
317 | // the Program Map Table (PMT) associates the underlying | ||
318 | // video and audio streams with a unique PID | ||
319 | self.stream.pmtPid = programPid; | ||
320 | } else if (self.stream.pmtPid !== programPid) { | ||
321 | throw new Error("TS has more that 1 program"); | ||
322 | } | ||
307 | } | 323 | } |
308 | |||
309 | // the Program Map Table (PMT) associates the underlying | ||
310 | // video and audio streams with a unique PID | ||
311 | self.stream.pmtPid = (data[offset + 2] & 0x1F) << 8 | data[offset + 3]; | ||
312 | } | 324 | } |
313 | } else if (pid === self.stream.programMapTable[STREAM_TYPES.h264] || | 325 | } else if (pid === self.stream.programMapTable[STREAM_TYPES.h264] || |
314 | pid === self.stream.programMapTable[STREAM_TYPES.adts] || | 326 | pid === self.stream.programMapTable[STREAM_TYPES.adts] || |
... | @@ -425,6 +437,9 @@ | ... | @@ -425,6 +437,9 @@ |
425 | // rest of header + CRC = 9 + 4 | 437 | // rest of header + CRC = 9 + 4 |
426 | pmtSectionLength -= 13; | 438 | pmtSectionLength -= 13; |
427 | 439 | ||
440 | // capture the PID of PCR packets so we can ignore them if we see any | ||
441 | self.stream.programMapTable.pcrPid = (data[offset + 8] & 0x1f) << 8 | data[offset + 9]; | ||
442 | |||
428 | // align offset to the first entry in the PMT | 443 | // align offset to the first entry in the PMT |
429 | offset += 12 + pmtProgramDescriptorsLength; | 444 | offset += 12 + pmtProgramDescriptorsLength; |
430 | 445 | ||
... | @@ -461,10 +476,16 @@ | ... | @@ -461,10 +476,16 @@ |
461 | } | 476 | } |
462 | } | 477 | } |
463 | // We could test the CRC here to detect corruption with extra CPU cost | 478 | // We could test the CRC here to detect corruption with extra CPU cost |
479 | } else if (self.stream.networkPid === pid) { | ||
480 | // network information specific data (NIT) packet | ||
464 | } else if (0x0011 === pid) { | 481 | } else if (0x0011 === pid) { |
465 | // Service Description Table | 482 | // Service Description Table |
466 | } else if (0x1FFF === pid) { | 483 | } else if (0x1FFF === pid) { |
467 | // NULL packet | 484 | // NULL packet |
485 | } else if (self.stream.programMapTable.pcrPid) { | ||
486 | // program clock reference (PCR) PID for the primary program | ||
487 | // PTS values are sufficient to synchronize playback for us so | ||
488 | // we can safely ignore these | ||
468 | } else { | 489 | } else { |
469 | videojs.log("Unknown PID parsing TS packet: " + pid); | 490 | videojs.log("Unknown PID parsing TS packet: " + pid); |
470 | } | 491 | } | ... | ... |
... | @@ -64,12 +64,15 @@ | ... | @@ -64,12 +64,15 @@ |
64 | makePmt = function(options) { | 64 | makePmt = function(options) { |
65 | var | 65 | var |
66 | result = [], | 66 | result = [], |
67 | pcr = options.pcr || 0, | ||
67 | entryCount = 0, | 68 | entryCount = 0, |
68 | k, | 69 | k, |
69 | sectionLength; | 70 | sectionLength; |
70 | 71 | ||
71 | for (k in options.pids) { | 72 | for (k in options.pids) { |
72 | entryCount++; | 73 | if (k !== 'pcr') { |
74 | entryCount++; | ||
75 | } | ||
73 | } | 76 | } |
74 | // table_id | 77 | // table_id |
75 | result.push(0x02); | 78 | result.push(0x02); |
... | @@ -88,8 +91,8 @@ | ... | @@ -88,8 +91,8 @@ |
88 | // last_section_number | 91 | // last_section_number |
89 | result.push(0x00); | 92 | result.push(0x00); |
90 | // reserved PCR_PID | 93 | // reserved PCR_PID |
91 | result.push(0xe1); | 94 | result.push(0xe0 | (pcr & (0x1f << 8))); |
92 | result.push(0x00); | 95 | result.push(pcr & 0xff); |
93 | // reserved program_info_length | 96 | // reserved program_info_length |
94 | result.push(0xf0); | 97 | result.push(0xf0); |
95 | result.push(0x11); // hard-coded 17 byte descriptor | 98 | result.push(0x11); // hard-coded 17 byte descriptor |
... | @@ -121,13 +124,26 @@ | ... | @@ -121,13 +124,26 @@ |
121 | makePat = function(options) { | 124 | makePat = function(options) { |
122 | var | 125 | var |
123 | result = [], | 126 | result = [], |
127 | programEntries = [], | ||
128 | sectionLength, | ||
124 | k; | 129 | k; |
125 | 130 | ||
131 | // build the program entries first | ||
132 | for (k in options.programs) { | ||
133 | // program_number | ||
134 | programEntries.push((k & 0xFF00) >>> 8); | ||
135 | programEntries.push(k & 0x00FF); | ||
136 | // reserved program_map_pid | ||
137 | programEntries.push((options.programs[k] & 0x1f00) >>> 8); | ||
138 | programEntries.push(options.programs[k] & 0xff); | ||
139 | } | ||
140 | sectionLength = programEntries.length + 5 + 4; | ||
141 | |||
126 | // table_id | 142 | // table_id |
127 | result.push(0x00); | 143 | result.push(0x00); |
128 | // section_syntax_indicator '0' reserved section_length | 144 | // section_syntax_indicator '0' reserved section_length |
129 | result.push(0x80); | 145 | result.push(0x80 | ((0x300 & sectionLength) >>> 8)); |
130 | result.push(0x0d); // section_length for one program | 146 | result.push(0xff & sectionLength); // section_length |
131 | // transport_stream_id | 147 | // transport_stream_id |
132 | result.push(0x00); | 148 | result.push(0x00); |
133 | result.push(0x00); | 149 | result.push(0x00); |
... | @@ -137,14 +153,8 @@ | ... | @@ -137,14 +153,8 @@ |
137 | result.push(0x00); | 153 | result.push(0x00); |
138 | // last_section_number | 154 | // last_section_number |
139 | result.push(0x00); | 155 | result.push(0x00); |
140 | for (k in options.programs) { | 156 | // program entries |
141 | // program_number | 157 | result = result.concat(programEntries); |
142 | result.push((k & 0xFF00) >>> 8); | ||
143 | result.push(k & 0x00FF); | ||
144 | // reserved program_map_pid | ||
145 | result.push((options.programs[k] & 0x1f00) >>> 8); | ||
146 | result.push(options.programs[k] & 0xff); | ||
147 | } | ||
148 | return result; | 158 | return result; |
149 | }; | 159 | }; |
150 | 160 | ||
... | @@ -211,6 +221,30 @@ | ... | @@ -211,6 +221,30 @@ |
211 | strictEqual(parser.stream.programMapTable[adtsType], 0x03, 'audio is PID 3'); | 221 | strictEqual(parser.stream.programMapTable[adtsType], 0x03, 'audio is PID 3'); |
212 | }); | 222 | }); |
213 | 223 | ||
224 | test('ignores network information specific data (NIT) in the PAT', function() { | ||
225 | parser.parseSegmentBinaryData(new Uint8Array(makePacket({ | ||
226 | programs: { | ||
227 | 0x01: [0x01], | ||
228 | 0x00: [0x00] // a NIT has a reserved PID of 0x00 | ||
229 | } | ||
230 | }))); | ||
231 | |||
232 | ok(true, 'did not throw when a NIT is encountered'); | ||
233 | }); | ||
234 | |||
235 | test('ignores packets with PCR pids', function() { | ||
236 | parser.parseSegmentBinaryData(new Uint8Array(makePacket({ | ||
237 | programs: { | ||
238 | 0x01: [0x01] | ||
239 | } | ||
240 | }).concat(makePacket({ | ||
241 | pid: 0x01, | ||
242 | pcr: 0x02 | ||
243 | })))); | ||
244 | |||
245 | equal(parser.stream.programMapTable.pcrPid, 0x02, 'parsed the PCR pid'); | ||
246 | }); | ||
247 | |||
214 | test('recognizes metadata streams', function() { | 248 | test('recognizes metadata streams', function() { |
215 | parser.parseSegmentBinaryData(new Uint8Array(makePacket({ | 249 | parser.parseSegmentBinaryData(new Uint8Array(makePacket({ |
216 | programs: { | 250 | programs: { | ... | ... |
-
Please register or sign in to post a comment