eaf4677b by David LaPalomento

Capture NIT so we generate less warnings

When a NIT was present, we would warn about unrecognized PIDs every time it was encountered. Capture the PID value so we can silently ignore it. Add a test case for NIT parsing.
1 parent ef1c74f6
...@@ -221,9 +221,9 @@ ...@@ -221,9 +221,9 @@
221 patTableId, // :int 221 patTableId, // :int
222 patCurrentNextIndicator, // Boolean 222 patCurrentNextIndicator, // Boolean
223 patSectionLength, // :uint 223 patSectionLength, // :uint
224 patNumEntries, // :uint 224 programNumber, // :uint
225 patNumPrograms, // :uint 225 programPid, // :uint
226 patProgramOffset, // :uint 226 patEntriesEnd, // :uint
227 227
228 pesPacketSize, // :int, 228 pesPacketSize, // :int,
229 dataAlignmentIndicator, // :Boolean, 229 dataAlignmentIndicator, // :Boolean,
...@@ -296,6 +296,8 @@ ...@@ -296,6 +296,8 @@
296 if (patCurrentNextIndicator) { 296 if (patCurrentNextIndicator) {
297 // section_length specifies the number of bytes following 297 // section_length specifies the number of bytes following
298 // 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
299 patSectionLength = (data[offset + 1] & 0x0F) << 8 | data[offset + 2]; 301 patSectionLength = (data[offset + 1] & 0x0F) << 8 | data[offset + 2];
300 // 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
301 // map table entry 303 // map table entry
...@@ -303,28 +305,22 @@ ...@@ -303,28 +305,22 @@
303 305
304 // we don't handle streams with more than one program, so 306 // we don't handle streams with more than one program, so
305 // raise an exception if we encounter one 307 // raise an exception if we encounter one
306 // section_length = rest of header + (n * entry length) + CRC 308 patEntriesEnd = offset + (patSectionLength - 5 - 4);
307 // = 5 + (n * 4) + 4 309 for (; offset < patEntriesEnd; offset += 4) {
308 patNumEntries = (patSectionLength - 5 - 4) / 4; 310 programNumber = (data[offset] << 8 | data[offset + 1]);
309 patNumPrograms = 0; 311 programPid = (data[offset + 2] & 0x1F) << 8 | data[offset + 3];
310 patProgramOffset = offset; 312 // network PID program number equals 0
311 for (var entryIndex = 0; entryIndex < patNumEntries; entryIndex++) { 313 // this is primarily an artifact of EBU DVB and can be ignored
312 // network PID program number equals 0 and can be ignored 314 if (programNumber === 0) {
313 if (((data[offset + 4*entryIndex]) << 8 | data[offset + 4*entryIndex + 1]) > 0) { 315 self.stream.networkPid = programPid;
314 patNumPrograms++; 316 } else if (self.stream.pmtPid === undefined) {
315 patProgramOffset = offset + 4*entryIndex; 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");
316 } 322 }
317 } 323 }
318 if (patNumPrograms !== 1) {
319 throw new Error("TS has more that 1 program");
320 }
321 else {
322 offset = patProgramOffset;
323 }
324
325 // the Program Map Table (PMT) associates the underlying
326 // video and audio streams with a unique PID
327 self.stream.pmtPid = (data[offset + 2] & 0x1F) << 8 | data[offset + 3];
328 } 324 }
329 } else if (pid === self.stream.programMapTable[STREAM_TYPES.h264] || 325 } else if (pid === self.stream.programMapTable[STREAM_TYPES.h264] ||
330 pid === self.stream.programMapTable[STREAM_TYPES.adts] || 326 pid === self.stream.programMapTable[STREAM_TYPES.adts] ||
...@@ -477,6 +473,8 @@ ...@@ -477,6 +473,8 @@
477 } 473 }
478 } 474 }
479 // We could test the CRC here to detect corruption with extra CPU cost 475 // We could test the CRC here to detect corruption with extra CPU cost
476 } else if (self.stream.networkPid === pid) {
477 // network information specific data (NIT) packet
480 } else if (0x0011 === pid) { 478 } else if (0x0011 === pid) {
481 // Service Description Table 479 // Service Description Table
482 } else if (0x1FFF === pid) { 480 } else if (0x1FFF === pid) {
......
...@@ -121,13 +121,26 @@ ...@@ -121,13 +121,26 @@
121 makePat = function(options) { 121 makePat = function(options) {
122 var 122 var
123 result = [], 123 result = [],
124 programEntries = [],
125 sectionLength,
124 k; 126 k;
125 127
128 // build the program entries first
129 for (k in options.programs) {
130 // program_number
131 programEntries.push((k & 0xFF00) >>> 8);
132 programEntries.push(k & 0x00FF);
133 // reserved program_map_pid
134 programEntries.push((options.programs[k] & 0x1f00) >>> 8);
135 programEntries.push(options.programs[k] & 0xff);
136 }
137 sectionLength = programEntries.length + 5 + 4;
138
126 // table_id 139 // table_id
127 result.push(0x00); 140 result.push(0x00);
128 // section_syntax_indicator '0' reserved section_length 141 // section_syntax_indicator '0' reserved section_length
129 result.push(0x80); 142 result.push(0x80 | ((0x300 & sectionLength) >>> 8));
130 result.push(0x0d); // section_length for one program 143 result.push(0xff & sectionLength); // section_length
131 // transport_stream_id 144 // transport_stream_id
132 result.push(0x00); 145 result.push(0x00);
133 result.push(0x00); 146 result.push(0x00);
...@@ -137,14 +150,8 @@ ...@@ -137,14 +150,8 @@
137 result.push(0x00); 150 result.push(0x00);
138 // last_section_number 151 // last_section_number
139 result.push(0x00); 152 result.push(0x00);
140 for (k in options.programs) { 153 // program entries
141 // program_number 154 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; 155 return result;
149 }; 156 };
150 157
...@@ -211,6 +218,17 @@ ...@@ -211,6 +218,17 @@
211 strictEqual(parser.stream.programMapTable[adtsType], 0x03, 'audio is PID 3'); 218 strictEqual(parser.stream.programMapTable[adtsType], 0x03, 'audio is PID 3');
212 }); 219 });
213 220
221 test('ignores network information specific data (NIT) in the PAT', function() {
222 parser.parseSegmentBinaryData(new Uint8Array(makePacket({
223 programs: {
224 0x01: [0x01],
225 0x00: [0x00] // a NIT has a reserved PID of 0x00
226 }
227 })));
228
229 ok(true, 'did not throw when a NIT is encountered');
230 });
231
214 test('recognizes metadata streams', function() { 232 test('recognizes metadata streams', function() {
215 parser.parseSegmentBinaryData(new Uint8Array(makePacket({ 233 parser.parseSegmentBinaryData(new Uint8Array(makePacket({
216 programs: { 234 programs: {
......