666609bd by David LaPalomento

Generate an mfhd with a valid sequence number

Allow sequence numbers to be passed in during moof generation. Hook up the transmuxer to specify increasing sequence numbers as media segments are built.
1 parent 49e93b2e
1 (function(window, videojs, undefined) { 1 (function(window, videojs, undefined) {
2 'use strict'; 2 'use strict';
3 3
4 var box, dinf, ftyp, mdat, minf, moof, moov, mvex, mvhd, trak, tkhd, mdia, mdhd, hdlr, stbl, 4 var box, dinf, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd, trak, tkhd, mdia, mdhd, hdlr, stbl,
5 stsd, styp, types, MAJOR_BRAND, MINOR_VERSION, VIDEO_HDLR, AUDIO_HDLR, HDLR_TYPES, VMHD, DREF, STCO, STSC, STSZ, STTS, TREX, 5 stsd, styp, types, MAJOR_BRAND, MINOR_VERSION, VIDEO_HDLR, AUDIO_HDLR, HDLR_TYPES, VMHD, DREF, STCO, STSC, STSZ, STTS, TREX,
6 Uint8Array, DataView; 6 Uint8Array, DataView;
7 7
...@@ -188,10 +188,20 @@ mdhd = function(duration) { ...@@ -188,10 +188,20 @@ mdhd = function(duration) {
188 mdia = function(duration, width, height, type) { 188 mdia = function(duration, width, height, type) {
189 return box(types.mdia, mdhd(duration), hdlr(type), minf(width, height)); 189 return box(types.mdia, mdhd(duration), hdlr(type), minf(width, height));
190 }; 190 };
191 mfhd = function(sequenceNumber) {
192 return box(types.mfhd, new Uint8Array([
193 0x00,
194 0x00, 0x00, 0x00, // flags
195 (sequenceNumber & 0xFF000000) >> 24,
196 (sequenceNumber & 0xFF0000) >> 16,
197 (sequenceNumber & 0xFF00) >> 8,
198 sequenceNumber & 0xFF, // sequence_number
199 ]));
200 };
191 minf = function(width, height) { 201 minf = function(width, height) {
192 return box(types.minf, box(types.vmhd, VMHD), dinf(), stbl(width, height)); 202 return box(types.minf, box(types.vmhd, VMHD), dinf(), stbl(width, height));
193 }; 203 };
194 moof = function(tracks) { 204 moof = function(sequenceNumber, tracks) {
195 var 205 var
196 trafCall = [], 206 trafCall = [],
197 i = tracks.length; 207 i = tracks.length;
...@@ -208,7 +218,7 @@ moof = function(tracks) { ...@@ -208,7 +218,7 @@ moof = function(tracks) {
208 } 218 }
209 trafCall.unshift(types.traf); 219 trafCall.unshift(types.traf);
210 return box(types.moof, 220 return box(types.moof,
211 box(types.mfhd), 221 mfhd(sequenceNumber),
212 box.apply(null, trafCall)); 222 box.apply(null, trafCall));
213 }; 223 };
214 moov = function(duration, width, height, type) { 224 moov = function(duration, width, height, type) {
......
...@@ -421,7 +421,10 @@ H264Stream.prototype = new videojs.Hls.Stream(); ...@@ -421,7 +421,10 @@ H264Stream.prototype = new videojs.Hls.Stream();
421 421
422 422
423 Transmuxer = function() { 423 Transmuxer = function() {
424 var self = this, packetStream, parseStream, programStream, aacStream, h264Stream; 424 var
425 self = this,
426 sequenceNumber = 0,
427 packetStream, parseStream, programStream, aacStream, h264Stream;
425 Transmuxer.prototype.init.call(this); 428 Transmuxer.prototype.init.call(this);
426 429
427 // set up the parsing pipeline 430 // set up the parsing pipeline
...@@ -443,10 +446,15 @@ Transmuxer = function() { ...@@ -443,10 +446,15 @@ Transmuxer = function() {
443 }); 446 });
444 h264Stream.on('data', function(data) { 447 h264Stream.on('data', function(data) {
445 var 448 var
446 moof = mp4.moof([]), 449 moof = mp4.moof(sequenceNumber, []),
447 mdat = mp4.mdat(data.data), 450 mdat = mp4.mdat(data.data),
451 // it would be great to allocate this array up front instead of
452 // throwing away hundreds of media segment fragments
448 boxes = new Uint8Array(moof.byteLength + mdat.byteLength); 453 boxes = new Uint8Array(moof.byteLength + mdat.byteLength);
449 454
455 // bump the sequence number for next time
456 sequenceNumber++;
457
450 boxes.set(moof); 458 boxes.set(moof);
451 boxes.set(mdat, moof.byteLength); 459 boxes.set(mdat, moof.byteLength);
452 460
......
...@@ -246,7 +246,7 @@ test('generates an initialization segment', function() { ...@@ -246,7 +246,7 @@ test('generates an initialization segment', function() {
246 246
247 test('generates a minimal moof', function() { 247 test('generates a minimal moof', function() {
248 var 248 var
249 data = mp4.moof([{ 249 data = mp4.moof(7, [{
250 trackId: 1 250 trackId: 1
251 }, { 251 }, {
252 trackId: 2 252 trackId: 2
...@@ -257,6 +257,7 @@ test('generates a minimal moof', function() { ...@@ -257,6 +257,7 @@ test('generates a minimal moof', function() {
257 equal(moof[0].type, 'moof', 'generated a moof box'); 257 equal(moof[0].type, 'moof', 'generated a moof box');
258 equal(moof[0].boxes.length, 2, 'generated two child boxes'); 258 equal(moof[0].boxes.length, 2, 'generated two child boxes');
259 equal(moof[0].boxes[0].type, 'mfhd', 'generated an mfhd box'); 259 equal(moof[0].boxes[0].type, 'mfhd', 'generated an mfhd box');
260 equal(moof[0].boxes[0].sequenceNumber, 7, 'included the sequence_number');
260 equal(moof[0].boxes[1].type, 'traf', 'generated a traf box'); 261 equal(moof[0].boxes[1].type, 'traf', 'generated a traf box');
261 equal(moof[0].boxes[1].boxes.length, 2, 'generated two fragment headers'); 262 equal(moof[0].boxes[1].boxes.length, 2, 'generated two fragment headers');
262 equal(moof[0].boxes[1].boxes[0].type, 'tfhd', 'generated a tfhd box'); 263 equal(moof[0].boxes[1].boxes[0].type, 'tfhd', 'generated a tfhd box');
...@@ -274,5 +275,4 @@ test('generates an mdat', function() { ...@@ -274,5 +275,4 @@ test('generates an mdat', function() {
274 deepEqual(mdat[0].byteLength, 4, 'encapsulated the data'); 275 deepEqual(mdat[0].byteLength, 4, 'encapsulated the data');
275 }); 276 });
276 277
277
278 })(window, window.videojs); 278 })(window, window.videojs);
......
...@@ -643,7 +643,10 @@ test('generates an init segment', function() { ...@@ -643,7 +643,10 @@ test('generates an init segment', function() {
643 }); 643 });
644 644
645 test('parses an example mp2t file and generates media segments', function() { 645 test('parses an example mp2t file and generates media segments', function() {
646 var segments = [], i, boxes; 646 var
647 segments = [],
648 sequenceNumber = window.Infinity,
649 i, boxes, mfhd, traf, mdat;
647 transmuxer.on('data', function(segment) { 650 transmuxer.on('data', function(segment) {
648 segments.push(segment); 651 segments.push(segment);
649 }); 652 });
...@@ -656,9 +659,16 @@ test('parses an example mp2t file and generates media segments', function() { ...@@ -656,9 +659,16 @@ test('parses an example mp2t file and generates media segments', function() {
656 boxes = videojs.inspectMp4(segments[i].data); 659 boxes = videojs.inspectMp4(segments[i].data);
657 equal(boxes.length, 2, 'segments are composed of two boxes'); 660 equal(boxes.length, 2, 'segments are composed of two boxes');
658 equal(boxes[0].type, 'moof', 'first box is a moof'); 661 equal(boxes[0].type, 'moof', 'first box is a moof');
659 equal(boxes[0].boxes.length, 2, 'moof has three children'); 662 equal(boxes[0].boxes.length, 2, 'the moof has two children');
660 equal(boxes[0].boxes[0].type, 'mfhd', 'mfhd is a child of the moof'); 663
661 equal(boxes[0].boxes[1].type, 'traf', 'traf is a child of the moof'); 664 mfhd = boxes[0].boxes[0];
665 equal(mfhd.type, 'mfhd', 'mfhd is a child of the moof');
666 ok(mfhd.sequenceNumber < sequenceNumber, 'sequence numbers are increasing');
667 sequenceNumber = mfhd.sequenceNumber;
668
669 traf = boxes[0].boxes[1];
670 equal(traf.type, 'traf', 'traf is a child of the moof');
671
662 equal(boxes[1].type, 'mdat', 'second box is an mdat'); 672 equal(boxes[1].type, 'mdat', 'second box is an mdat');
663 } 673 }
664 }); 674 });
......