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.
Showing
4 changed files
with
39 additions
and
11 deletions
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 | }); | ... | ... |
-
Please register or sign in to post a comment