85ee7214 by David LaPalomento

Get init segments working with real metadata

Parse and pass along additional track info from the sequence parameter set.
1 parent 0816934b
1 (function(window, videojs, undefined) { 1 (function(window, videojs, undefined) {
2 'use strict'; 2 'use strict';
3 3
4 var box, dinf, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd, trak, tkhd, mdia, mdhd, hdlr, stbl, 4 var box, dinf, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd, trak,
5 stsd, styp, types, MAJOR_BRAND, MINOR_VERSION, VIDEO_HDLR, AUDIO_HDLR, HDLR_TYPES, VMHD, DREF, STCO, STSC, STSZ, STTS, TREX, 5 tkhd, mdia, mdhd, hdlr, stbl, stsd, styp, trex, types,
6 Uint8Array, DataView; 6 MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR, AUDIO_HDLR,
7 HDLR_TYPES, VMHD, DREF, STCO, STSC, STSZ, STTS, Uint8Array,
8 DataView;
7 9
8 Uint8Array = window.Uint8Array; 10 Uint8Array = window.Uint8Array;
9 DataView = window.DataView; 11 DataView = window.DataView;
...@@ -60,6 +62,12 @@ DataView = window.DataView; ...@@ -60,6 +62,12 @@ DataView = window.DataView;
60 'o'.charCodeAt(0), 62 'o'.charCodeAt(0),
61 'm'.charCodeAt(0) 63 'm'.charCodeAt(0)
62 ]); 64 ]);
65 AVC1_BRAND = new Uint8Array([
66 'a'.charCodeAt(0),
67 'v'.charCodeAt(0),
68 'c'.charCodeAt(0),
69 '1'.charCodeAt(0)
70 ]);
63 MINOR_VERSION = new Uint8Array([0, 0, 0, 1]); 71 MINOR_VERSION = new Uint8Array([0, 0, 0, 1]);
64 VIDEO_HDLR = new Uint8Array([ 72 VIDEO_HDLR = new Uint8Array([
65 0x00, // version 0 73 0x00, // version 0
...@@ -98,15 +106,6 @@ DataView = window.DataView; ...@@ -98,15 +106,6 @@ DataView = window.DataView;
98 0x00, // version 0 106 0x00, // version 0
99 0x00, 0x00, 0x01 // entry_flags 107 0x00, 0x00, 0x01 // entry_flags
100 ]); 108 ]);
101 TREX = new Uint8Array([
102 0x00, // version 0
103 0x00, 0x00, 0x00, // flags
104 0x00, 0x00, 0x00, 0x01, // track_ID
105 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
106 0x00, 0x00, 0x00, 0x00, // default_sample_duration
107 0x00, 0x00, 0x00, 0x00, // default_sample_size
108 0x00, 0x01, 0x00, 0x01 // default_sample_flags
109 ]);
110 STCO = new Uint8Array([ 109 STCO = new Uint8Array([
111 0x00, // version 110 0x00, // version
112 0x00, 0x00, 0x00, // flags 111 0x00, 0x00, 0x00, // flags
...@@ -160,7 +159,7 @@ dinf = function() { ...@@ -160,7 +159,7 @@ dinf = function() {
160 }; 159 };
161 160
162 ftyp = function() { 161 ftyp = function() {
163 return box(types.ftyp, MAJOR_BRAND, MINOR_VERSION, MAJOR_BRAND); 162 return box(types.ftyp, MAJOR_BRAND, MINOR_VERSION, MAJOR_BRAND, AVC1_BRAND);
164 }; 163 };
165 164
166 hdlr = function(type) { 165 hdlr = function(type) {
...@@ -185,8 +184,8 @@ mdhd = function(duration) { ...@@ -185,8 +184,8 @@ mdhd = function(duration) {
185 0x00, 0x00 184 0x00, 0x00
186 ])); 185 ]));
187 }; 186 };
188 mdia = function(duration, width, height, type) { 187 mdia = function(track) {
189 return box(types.mdia, mdhd(duration), hdlr(type), minf(width, height)); 188 return box(types.mdia, mdhd(track.duration), hdlr(track.type), minf(track));
190 }; 189 };
191 mfhd = function(sequenceNumber) { 190 mfhd = function(sequenceNumber) {
192 return box(types.mfhd, new Uint8Array([ 191 return box(types.mfhd, new Uint8Array([
...@@ -198,8 +197,8 @@ mfhd = function(sequenceNumber) { ...@@ -198,8 +197,8 @@ mfhd = function(sequenceNumber) {
198 sequenceNumber & 0xFF, // sequence_number 197 sequenceNumber & 0xFF, // sequence_number
199 ])); 198 ]));
200 }; 199 };
201 minf = function(width, height) { 200 minf = function(track) {
202 return box(types.minf, box(types.vmhd, VMHD), dinf(), stbl(width, height)); 201 return box(types.minf, box(types.vmhd, VMHD), dinf(), stbl(track));
203 }; 202 };
204 moof = function(sequenceNumber, tracks) { 203 moof = function(sequenceNumber, tracks) {
205 var 204 var
...@@ -233,10 +232,17 @@ moov = function(tracks) { ...@@ -233,10 +232,17 @@ moov = function(tracks) {
233 boxes[i] = trak(tracks[i]); 232 boxes[i] = trak(tracks[i]);
234 } 233 }
235 234
236 return box.apply(null, [types.moov, mvhd(0xffffffff)].concat(boxes).concat(mvex())); 235 return box.apply(null, [types.moov, mvhd(0xffffffff)].concat(boxes).concat(mvex(tracks)));
237 }; 236 };
238 mvex = function() { 237 mvex = function(tracks) {
239 return box(types.mvex, box(types.trex, TREX)); 238 var
239 i = tracks.length,
240 boxes = [];
241
242 while (i--) {
243 boxes[i] = trex(tracks[i]);
244 }
245 return box.apply(null, [types.mvex].concat(boxes));
240 }; 246 };
241 mvhd = function(duration) { 247 mvhd = function(duration) {
242 var 248 var
...@@ -270,21 +276,41 @@ mvhd = function(duration) { ...@@ -270,21 +276,41 @@ mvhd = function(duration) {
270 0x00, 0x00, 0x00, 0x00, 276 0x00, 0x00, 0x00, 0x00,
271 0x00, 0x00, 0x00, 0x00, 277 0x00, 0x00, 0x00, 0x00,
272 0x00, 0x00, 0x00, 0x00, // pre_defined 278 0x00, 0x00, 0x00, 0x00, // pre_defined
273 0x00, 0x00, 0x00, 0x01 // next_track_ID 279 0xff, 0xff, 0xff, 0xff // next_track_ID
274 ]); 280 ]);
275 return box(types.mvhd, bytes); 281 return box(types.mvhd, bytes);
276 }; 282 };
277 283
278 stbl = function(width, height) { 284 stbl = function(track) {
279 return box(types.stbl, 285 return box(types.stbl,
280 stsd(width, height), 286 stsd(track),
281 box(types.stts, STTS), 287 box(types.stts, STTS),
282 box(types.stsc, STSC), 288 box(types.stsc, STSC),
283 box(types.stsz, STSZ), 289 box(types.stsz, STSZ),
284 box(types.stco, STCO)); 290 box(types.stco, STCO));
285 }; 291 };
286 292
287 stsd = function(width, height) { 293 stsd = function(track) {
294 var sequenceParameterSets = [], pictureParameterSets = [], i;
295
296 if (track.type === 'audio') {
297 return box(types.stsd);
298 }
299
300 // assemble the SPSs
301 for (i = 0; i < track.sps.length; i++) {
302 sequenceParameterSets.push((track.sps[i].byteLength & 0xFF00) >>> 8);
303 sequenceParameterSets.push((track.sps[i].byteLength & 0xFF)); // sequenceParameterSetLength
304 sequenceParameterSets = sequenceParameterSets.concat(Array.prototype.slice.call(track.sps[i])); // SPS
305 }
306
307 // assemble the PPSs
308 for (i = 0; i < track.pps.length; i++) {
309 pictureParameterSets.push((track.pps[i].byteLength & 0xFF00) >>> 8);
310 pictureParameterSets.push((track.pps[i].byteLength & 0xFF));
311 pictureParameterSets = pictureParameterSets.concat(Array.prototype.slice.call(track.pps[i]));
312 }
313
288 return box(types.stsd, new Uint8Array([ 314 return box(types.stsd, new Uint8Array([
289 0x00, // version 0 315 0x00, // version 0
290 0x00, 0x00, 0x00, // flags 316 0x00, 0x00, 0x00, // flags
...@@ -298,10 +324,10 @@ stsd = function(width, height) { ...@@ -298,10 +324,10 @@ stsd = function(width, height) {
298 0x00, 0x00, 0x00, 0x00, 324 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 325 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, // pre_defined 326 0x00, 0x00, 0x00, 0x00, // pre_defined
301 (width & 0xff00) >> 8, 327 (track.width & 0xff00) >> 8,
302 width & 0xff, // width 328 track.width & 0xff, // width
303 (height & 0xff00) >> 8, 329 (track.height & 0xff00) >> 8,
304 height & 0xff, // height 330 track.height & 0xff, // height
305 0x00, 0x48, 0x00, 0x00, // horizresolution 331 0x00, 0x48, 0x00, 0x00, // horizresolution
306 0x00, 0x48, 0x00, 0x00, // vertresolution 332 0x00, 0x48, 0x00, 0x00, // vertresolution
307 0x00, 0x00, 0x00, 0x00, // reserved 333 0x00, 0x00, 0x00, 0x00, // reserved
...@@ -319,18 +345,15 @@ stsd = function(width, height) { ...@@ -319,18 +345,15 @@ stsd = function(width, height) {
319 0x11, 0x11]), // pre_defined = -1 345 0x11, 0x11]), // pre_defined = -1
320 box(types.avcC, new Uint8Array([ 346 box(types.avcC, new Uint8Array([
321 0x01, // configurationVersion 347 0x01, // configurationVersion
322 0x4d, // AVCProfileIndication?? 348 track.profileIdc, // AVCProfileIndication
323 0x40, // profile_compatibility 349 track.profileCompatibility, // profile_compatibility
324 0x20, // AVCLevelIndication 350 track.levelIdc, // AVCLevelIndication
325 0xff, // lengthSizeMinusOne 351 0xff // lengthSizeMinusOne
326 0xe1, // numOfSequenceParameterSets 352 ].concat([
327 0x00, 0x0c, // sequenceParameterSetLength 353 track.sps.length // numOfSequenceParameterSets
328 0x67, 0x4d, 0x40, 0x20, 354 ]).concat(sequenceParameterSets).concat([
329 0x96, 0x52, 0x80, 0xa0, 355 track.pps.length // numOfPictureParameterSets
330 0x0b, 0x76, 0x02, 0x05, // SPS 356 ]).concat(pictureParameterSets))), // "PPS"
331 0x01, // numOfPictureParameterSets
332 0x00, 0x04, // pictureParameterSetLength
333 0x68, 0xef, 0x38, 0x80])), // "PPS"
334 box(types.btrt, new Uint8Array([ 357 box(types.btrt, new Uint8Array([
335 0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB 358 0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB
336 0x00, 0x2d, 0xc6, 0xc0, // maxBitrate 359 0x00, 0x2d, 0xc6, 0xc0, // maxBitrate
...@@ -390,7 +413,22 @@ trak = function(track) { ...@@ -390,7 +413,22 @@ trak = function(track) {
390 track.duration = track.duration || 0xffffffff; 413 track.duration = track.duration || 0xffffffff;
391 return box(types.trak, 414 return box(types.trak,
392 tkhd(track), 415 tkhd(track),
393 mdia(track.duration, track.width, track.height, track.type)); 416 mdia(track));
417 };
418
419 trex = function(track) {
420 return box(types.trex, new Uint8Array([
421 0x00, // version 0
422 0x00, 0x00, 0x00, // flags
423 (track.id & 0xFF000000) >> 24,
424 (track.id & 0xFF0000) >> 16,
425 (track.id & 0xFF00) >> 8,
426 (track.id & 0xFF), // track_ID
427 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
428 0x00, 0x00, 0x00, 0x00, // default_sample_duration
429 0x00, 0x00, 0x00, 0x00, // default_sample_size
430 0x00, 0x01, 0x00, 0x01 // default_sample_flags
431 ]));
394 }; 432 };
395 433
396 window.videojs.mp4 = { 434 window.videojs.mp4 = {
......
...@@ -497,7 +497,10 @@ H264Stream = function() { ...@@ -497,7 +497,10 @@ H264Stream = function() {
497 497
498 case 0x07: 498 case 0x07:
499 event.nalUnitType = 'seq_parameter_set_rbsp'; 499 event.nalUnitType = 'seq_parameter_set_rbsp';
500 event.dimensions = readSequenceParameterSet(data.subarray(1)); 500 event.config = readSequenceParameterSet(data.subarray(1));
501 break;
502 case 0x08:
503 event.nalUnitType = 'pic_parameter_set_rbsp';
501 break; 504 break;
502 505
503 default: 506 default:
...@@ -541,8 +544,9 @@ H264Stream = function() { ...@@ -541,8 +544,9 @@ H264Stream = function() {
541 * properties. A sequence parameter set is the H264 metadata that 544 * properties. A sequence parameter set is the H264 metadata that
542 * describes the properties of upcoming video frames. 545 * describes the properties of upcoming video frames.
543 * @param data {Uint8Array} the bytes of a sequence parameter set 546 * @param data {Uint8Array} the bytes of a sequence parameter set
544 * @return {object} an object with width and height properties 547 * @return {object} an object with configuration parsed from the
545 * specifying the dimensions of the associated video frames. 548 * sequence parameter set, including the dimensions of the
549 * associated video frames.
546 */ 550 */
547 readSequenceParameterSet = function(data) { 551 readSequenceParameterSet = function(data) {
548 var 552 var
...@@ -550,16 +554,19 @@ H264Stream = function() { ...@@ -550,16 +554,19 @@ H264Stream = function() {
550 frameCropRightOffset = 0, 554 frameCropRightOffset = 0,
551 frameCropTopOffset = 0, 555 frameCropTopOffset = 0,
552 frameCropBottomOffset = 0, 556 frameCropBottomOffset = 0,
553 expGolombDecoder, profileIdc, chromaFormatIdc, picOrderCntType, 557 expGolombDecoder, profileIdc, levelIdc, profileCompatibility,
558 chromaFormatIdc, picOrderCntType,
554 numRefFramesInPicOrderCntCycle, picWidthInMbsMinus1, 559 numRefFramesInPicOrderCntCycle, picWidthInMbsMinus1,
555 picHeightInMapUnitsMinus1, frameMbsOnlyFlag, 560 picHeightInMapUnitsMinus1,
561 frameMbsOnlyFlag,
556 scalingListCount, 562 scalingListCount,
557 i; 563 i;
558 564
559 expGolombDecoder = new videojs.Hls.ExpGolomb(data); 565 expGolombDecoder = new videojs.Hls.ExpGolomb(data);
560 profileIdc = expGolombDecoder.readUnsignedByte(); // profile_idc 566 profileIdc = expGolombDecoder.readUnsignedByte(); // profile_idc
561 // constraint_set[0-5]_flag, u(1), reserved_zero_2bits u(2), level_idc u()8 567 profileCompatibility = expGolombDecoder.readBits(5); // constraint_set[0-5]_flag
562 expGolombDecoder.skipBits(16); 568 expGolombDecoder.skipBits(3); // u(1), reserved_zero_2bits u(2)
569 levelIdc = expGolombDecoder.readUnsignedByte(); // level_idc u(8)
563 expGolombDecoder.skipUnsignedExpGolomb(); // seq_parameter_set_id 570 expGolombDecoder.skipUnsignedExpGolomb(); // seq_parameter_set_id
564 571
565 // some profiles have more optional data we don't need 572 // some profiles have more optional data we don't need
...@@ -628,6 +635,9 @@ H264Stream = function() { ...@@ -628,6 +635,9 @@ H264Stream = function() {
628 } 635 }
629 636
630 return { 637 return {
638 profileIdc: profileIdc,
639 levelIdc: levelIdc,
640 profileCompatibility: profileCompatibility,
631 width: ((picWidthInMbsMinus1 + 1) * 16) - frameCropLeftOffset * 2 - frameCropRightOffset * 2, 641 width: ((picWidthInMbsMinus1 + 1) * 16) - frameCropLeftOffset * 2 - frameCropRightOffset * 2,
632 height: ((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - (frameCropTopOffset * 2) - (frameCropBottomOffset * 2) 642 height: ((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - (frameCropTopOffset * 2) - (frameCropBottomOffset * 2)
633 }; 643 };
...@@ -644,7 +654,8 @@ Transmuxer = function() { ...@@ -644,7 +654,8 @@ Transmuxer = function() {
644 videoSamples = [], 654 videoSamples = [],
645 videoSamplesSize = 0, 655 videoSamplesSize = 0,
646 tracks, 656 tracks,
647 dimensions, 657 config,
658 pps,
648 659
649 packetStream, parseStream, programStream, aacStream, h264Stream, 660 packetStream, parseStream, programStream, aacStream, h264Stream,
650 661
...@@ -673,21 +684,43 @@ Transmuxer = function() { ...@@ -673,21 +684,43 @@ Transmuxer = function() {
673 videoSamples.length) { 684 videoSamples.length) {
674 //flushVideo(); 685 //flushVideo();
675 } 686 }
676 // generate an init segment once all the metadata is available 687 // record the track config
677 if (data.nalUnitType === 'seq_parameter_set_rbsp' && 688 if (data.nalUnitType === 'seq_parameter_set_rbsp' &&
678 !dimensions) { 689 !config) {
679 dimensions = data.dimensions; 690 config = data.config;
680 691
681 i = tracks.length; 692 i = tracks.length;
682 while (i--) { 693 while (i--) {
683 if (tracks[i].type === 'video') { 694 if (tracks[i].type === 'video') {
684 tracks[i].width = dimensions.width; 695 tracks[i].width = config.width;
685 tracks[i].height = dimensions.height; 696 tracks[i].height = config.height;
697 tracks[i].sps = [data.data];
698 tracks[i].profileIdc = config.profileIdc;
699 tracks[i].levelIdc = config.levelIdc;
700 tracks[i].profileCompatibility = config.profileCompatibility;
686 } 701 }
687 } 702 }
688 self.trigger('data', { 703 // generate an init segment once all the metadata is available
689 data: videojs.mp4.initSegment(tracks) 704 if (pps) {
690 }); 705 self.trigger('data', {
706 data: videojs.mp4.initSegment(tracks)
707 });
708 }
709 }
710 if (data.nalUnitType === 'pic_parameter_set_rbsp' &&
711 !pps) {
712 pps = data.data;i = tracks.length;
713
714 while (i--) {
715 if (tracks[i].type === 'video') {
716 tracks[i].pps = [data.data];
717 }
718 }
719 if (config) {
720 self.trigger('data', {
721 data: videojs.mp4.initSegment(tracks)
722 });
723 }
691 } 724 }
692 725
693 // buffer video until we encounter a new access unit (aka the next frame) 726 // buffer video until we encounter a new access unit (aka the next frame)
......
...@@ -46,7 +46,12 @@ test('generates a moov', function() { ...@@ -46,7 +46,12 @@ test('generates a moov', function() {
46 duration: 100, 46 duration: 100,
47 width: 600, 47 width: 600,
48 height: 300, 48 height: 300,
49 type: 'video' 49 type: 'video',
50 profileIdc: 3,
51 levelIdc: 5,
52 profileCompatibility: 7,
53 sps: [new Uint8Array([0, 1, 2]), new Uint8Array([3, 4, 5])],
54 pps: [new Uint8Array([6, 7, 8])]
50 }]); 55 }]);
51 56
52 ok(data, 'box is not null'); 57 ok(data, 'box is not null');
...@@ -60,6 +65,7 @@ test('generates a moov', function() { ...@@ -60,6 +65,7 @@ test('generates a moov', function() {
60 mvhd = boxes[0].boxes[0]; 65 mvhd = boxes[0].boxes[0];
61 equal(mvhd.type, 'mvhd', 'generated a mvhd'); 66 equal(mvhd.type, 'mvhd', 'generated a mvhd');
62 equal(mvhd.duration, 0xffffffff, 'wrote the maximum movie header duration'); 67 equal(mvhd.duration, 0xffffffff, 'wrote the maximum movie header duration');
68 equal(mvhd.nextTrackId, 0xffffffff, 'wrote the max next track id');
63 69
64 equal(boxes[0].boxes[1].type, 'trak', 'generated a trak'); 70 equal(boxes[0].boxes[1].type, 'trak', 'generated a trak');
65 equal(boxes[0].boxes[1].boxes.length, 2, 'generated two track sub boxes'); 71 equal(boxes[0].boxes[1].boxes.length, 2, 'generated two track sub boxes');
...@@ -119,15 +125,15 @@ test('generates a moov', function() { ...@@ -119,15 +125,15 @@ test('generates a moov', function() {
119 equal(minf.boxes[2].type, 'stbl', 'generates an stbl type'); 125 equal(minf.boxes[2].type, 'stbl', 'generates an stbl type');
120 deepEqual({ 126 deepEqual({
121 type: 'stbl', 127 type: 'stbl',
122 size: 233, 128 size: 228,
123 boxes: [{ 129 boxes: [{
124 type: 'stsd', 130 type: 'stsd',
125 size: 157, 131 size: 152,
126 version: 0, 132 version: 0,
127 flags: new Uint8Array([0, 0, 0]), 133 flags: new Uint8Array([0, 0, 0]),
128 sampleDescriptions: [{ 134 sampleDescriptions: [{
129 type: 'avc1', 135 type: 'avc1',
130 size: 141, 136 size: 136,
131 dataReferenceIndex: 1, 137 dataReferenceIndex: 1,
132 width: 600, 138 width: 600,
133 height: 300, 139 height: 300,
...@@ -137,19 +143,19 @@ test('generates a moov', function() { ...@@ -137,19 +143,19 @@ test('generates a moov', function() {
137 depth: 24, 143 depth: 24,
138 config: [{ 144 config: [{
139 type: 'avcC', 145 type: 'avcC',
140 size: 35, 146 size: 30,
141 configurationVersion: 1, 147 configurationVersion: 1,
142 avcProfileIndication: 0x4d, 148 avcProfileIndication: 3,
143 profileCompatibility: 0x40, 149 avcLevelIndication: 5,
144 avcLevelIndication: 0x20, 150 profileCompatibility: 7,
145 lengthSizeMinusOne: 3, 151 lengthSizeMinusOne: 3,
146 sps: [new Uint8Array([ 152 sps: [new Uint8Array([
147 0x67, 0x4d, 0x40, 0x20, 153 0, 1, 2
148 0x96, 0x52, 0x80, 0xa0, 154 ]), new Uint8Array([
149 0x0b, 0x76, 0x02, 0x05 155 3, 4, 5
150 ])], 156 ])],
151 pps: [new Uint8Array([ 157 pps: [new Uint8Array([
152 0x68, 0xef, 0x38, 0x80 158 6, 7, 8
153 ])] 159 ])]
154 }, { 160 }, {
155 type: 'btrt', 161 type: 'btrt',
...@@ -198,7 +204,7 @@ test('generates a moov', function() { ...@@ -198,7 +204,7 @@ test('generates a moov', function() {
198 size: 32, 204 size: 32,
199 version: 0, 205 version: 0,
200 flags: new Uint8Array([0, 0, 0]), 206 flags: new Uint8Array([0, 0, 0]),
201 trackId: 1, 207 trackId: 7,
202 defaultSampleDescriptionIndex: 1, 208 defaultSampleDescriptionIndex: 1,
203 defaultSampleDuration: 0, 209 defaultSampleDuration: 0,
204 defaultSampleSize: 0, 210 defaultSampleSize: 0,
...@@ -237,7 +243,9 @@ test('generates a video hdlr', function() { ...@@ -237,7 +243,9 @@ test('generates a video hdlr', function() {
237 duration: 100, 243 duration: 100,
238 width: 600, 244 width: 600,
239 height: 300, 245 height: 300,
240 type: 'video' 246 type: 'video',
247 sps: [],
248 pps: []
241 }]); 249 }]);
242 250
243 ok(data, 'box is not null'); 251 ok(data, 'box is not null');
...@@ -256,7 +264,9 @@ test('generates an initialization segment', function() { ...@@ -256,7 +264,9 @@ test('generates an initialization segment', function() {
256 id: 1, 264 id: 1,
257 width: 600, 265 width: 600,
258 height: 300, 266 height: 300,
259 type: 'video' 267 type: 'video',
268 sps: [new Uint8Array([0])],
269 pps: [new Uint8Array([1])]
260 }, { 270 }, {
261 id: 2, 271 id: 2,
262 type: 'audio' 272 type: 'audio'
......
...@@ -750,6 +750,18 @@ test('parses nal unit types', function() { ...@@ -750,6 +750,18 @@ test('parses nal unit types', function() {
750 h264Stream.end(); 750 h264Stream.end();
751 ok(data, 'generated a data event'); 751 ok(data, 'generated a data event');
752 equal(data.nalUnitType, 'seq_parameter_set_rbsp', 'identified a sequence parameter set'); 752 equal(data.nalUnitType, 'seq_parameter_set_rbsp', 'identified a sequence parameter set');
753
754 data = null;
755 h264Stream.push({
756 type: 'video',
757 data: new Uint8Array([
758 0x00, 0x00, 0x00, 0x01,
759 0x08, 0x01
760 ])
761 });
762 h264Stream.end();
763 ok(data, 'generated a data event');
764 equal(data.nalUnitType, 'pic_parameter_set_rbsp', 'identified a picture parameter set');
753 }); 765 });
754 766
755 module('Transmuxer', { 767 module('Transmuxer', {
...@@ -775,7 +787,7 @@ test('generates an init segment', function() { ...@@ -775,7 +787,7 @@ test('generates an init segment', function() {
775 ], true))); 787 ], true)));
776 transmuxer.end(); 788 transmuxer.end();
777 789
778 equal(segments.length, 2, 'has an init segment'); 790 equal(segments.length, 1, 'has an init segment');
779 }); 791 });
780 792
781 test('buffers video samples until ended', function() { 793 test('buffers video samples until ended', function() {
......