e6559cce by David LaPalomento

Add an sdtp box to each traf

Working examples of segmented mp4s have included an sdtp box, even though it's duplicative of information in the trun box. It's easy to generate however, so add it to the inspector and generator, and update the transmuxer tests to expect sane output.
1 parent 3e86d199
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
2 'use strict'; 2 'use strict';
3 3
4 var box, dinf, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd, trak, 4 var box, dinf, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd, trak,
5 tkhd, mdia, mdhd, hdlr, stbl, stsd, styp, traf, trex, trun, types, 5 tkhd, mdia, mdhd, hdlr, sdtp, stbl, stsd, styp, traf, trex, trun,
6 MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR, AUDIO_HDLR, 6 types, MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR,
7 HDLR_TYPES, VMHD, DREF, STCO, STSC, STSZ, STTS, Uint8Array, 7 AUDIO_HDLR, HDLR_TYPES, VMHD, DREF, STCO, STSC, STSZ, STTS,
8 DataView; 8 Uint8Array, DataView;
9 9
10 Uint8Array = window.Uint8Array; 10 Uint8Array = window.Uint8Array;
11 DataView = window.DataView; 11 DataView = window.DataView;
...@@ -30,6 +30,7 @@ DataView = window.DataView; ...@@ -30,6 +30,7 @@ DataView = window.DataView;
30 moov: [], 30 moov: [],
31 mvex: [], 31 mvex: [],
32 mvhd: [], 32 mvhd: [],
33 sdtp: [],
33 stbl: [], 34 stbl: [],
34 stco: [], 35 stco: [],
35 stsc: [], 36 stsc: [],
...@@ -276,6 +277,27 @@ mvhd = function(duration) { ...@@ -276,6 +277,27 @@ mvhd = function(duration) {
276 return box(types.mvhd, bytes); 277 return box(types.mvhd, bytes);
277 }; 278 };
278 279
280 sdtp = function(track) {
281 var
282 samples = track.samples || [],
283 bytes = new Uint8Array(4 + samples.length),
284 sample,
285 i;
286
287 // leave the full box header (4 bytes) all zero
288
289 // write the sample table
290 for (i = 0; i < samples.length; i++) {
291 sample = samples[i];
292 bytes[i + 4] = (sample.flags.dependsOn << 4) |
293 (sample.flags.isDependedOn << 2) |
294 (sample.flags.hasRedundancy);
295 }
296
297 return box(types.sdtp,
298 bytes);
299 };
300
279 stbl = function(track) { 301 stbl = function(track) {
280 return box(types.stbl, 302 return box(types.stbl,
281 stsd(track), 303 stsd(track),
...@@ -414,7 +436,8 @@ traf = function(track) { ...@@ -414,7 +436,8 @@ traf = function(track) {
414 0x00, 0x00, 0x00, // flags 436 0x00, 0x00, 0x00, // flags
415 0x00, 0x00, 0x00, 0x00 // baseMediaDecodeTime 437 0x00, 0x00, 0x00, 0x00 // baseMediaDecodeTime
416 ])), 438 ])),
417 trun(track)); 439 trun(track),
440 sdtp(track));
418 }; 441 };
419 442
420 /** 443 /**
......
...@@ -307,8 +307,8 @@ test('generates a minimal moof', function() { ...@@ -307,8 +307,8 @@ test('generates a minimal moof', function() {
307 size: 10, 307 size: 10,
308 flags: { 308 flags: {
309 isLeading: 0, 309 isLeading: 0,
310 dependsOn: 0, 310 dependsOn: 2,
311 isDependedOn: 0, 311 isDependedOn: 1,
312 hasRedundancy: 0, 312 hasRedundancy: 0,
313 paddingValue: 0, 313 paddingValue: 0,
314 isNonSyncSample: 0, 314 isNonSyncSample: 0,
...@@ -320,7 +320,7 @@ test('generates a minimal moof', function() { ...@@ -320,7 +320,7 @@ test('generates a minimal moof', function() {
320 size: 11, 320 size: 11,
321 flags: { 321 flags: {
322 isLeading: 0, 322 isLeading: 0,
323 dependsOn: 0, 323 dependsOn: 1,
324 isDependedOn: 0, 324 isDependedOn: 0,
325 hasRedundancy: 0, 325 hasRedundancy: 0,
326 paddingValue: 0, 326 paddingValue: 0,
...@@ -331,7 +331,8 @@ test('generates a minimal moof', function() { ...@@ -331,7 +331,8 @@ test('generates a minimal moof', function() {
331 }] 331 }]
332 }]), 332 }]),
333 moof = videojs.inspectMp4(data), 333 moof = videojs.inspectMp4(data),
334 trun; 334 trun,
335 sdtp;
335 336
336 equal(moof.length, 1, 'generated one box'); 337 equal(moof.length, 1, 'generated one box');
337 equal(moof[0].type, 'moof', 'generated a moof box'); 338 equal(moof[0].type, 'moof', 'generated a moof box');
...@@ -339,7 +340,7 @@ test('generates a minimal moof', function() { ...@@ -339,7 +340,7 @@ test('generates a minimal moof', function() {
339 equal(moof[0].boxes[0].type, 'mfhd', 'generated an mfhd box'); 340 equal(moof[0].boxes[0].type, 'mfhd', 'generated an mfhd box');
340 equal(moof[0].boxes[0].sequenceNumber, 7, 'included the sequence_number'); 341 equal(moof[0].boxes[0].sequenceNumber, 7, 'included the sequence_number');
341 equal(moof[0].boxes[1].type, 'traf', 'generated a traf box'); 342 equal(moof[0].boxes[1].type, 'traf', 'generated a traf box');
342 equal(moof[0].boxes[1].boxes.length, 3, 'generated track fragment info'); 343 equal(moof[0].boxes[1].boxes.length, 4, 'generated track fragment info');
343 equal(moof[0].boxes[1].boxes[0].type, 'tfhd', 'generated a tfhd box'); 344 equal(moof[0].boxes[1].boxes[0].type, 'tfhd', 'generated a tfhd box');
344 equal(moof[0].boxes[1].boxes[0].trackId, 17, 'wrote the first track id'); 345 equal(moof[0].boxes[1].boxes[0].trackId, 17, 'wrote the first track id');
345 equal(moof[0].boxes[1].boxes[0].baseDataOffset, undefined, 'did not set a base data offset'); 346 equal(moof[0].boxes[1].boxes[0].baseDataOffset, undefined, 'did not set a base data offset');
...@@ -358,8 +359,8 @@ test('generates a minimal moof', function() { ...@@ -358,8 +359,8 @@ test('generates a minimal moof', function() {
358 equal(trun.samples[0].size, 10, 'wrote a sample size'); 359 equal(trun.samples[0].size, 10, 'wrote a sample size');
359 deepEqual(trun.samples[0].flags, { 360 deepEqual(trun.samples[0].flags, {
360 isLeading: 0, 361 isLeading: 0,
361 dependsOn: 0, 362 dependsOn: 2,
362 isDependedOn: 0, 363 isDependedOn: 1,
363 hasRedundancy: 0, 364 hasRedundancy: 0,
364 paddingValue: 0, 365 paddingValue: 0,
365 isNonSyncSample: 0, 366 isNonSyncSample: 0,
...@@ -371,7 +372,7 @@ test('generates a minimal moof', function() { ...@@ -371,7 +372,7 @@ test('generates a minimal moof', function() {
371 equal(trun.samples[1].size, 11, 'wrote a sample size'); 372 equal(trun.samples[1].size, 11, 'wrote a sample size');
372 deepEqual(trun.samples[1].flags, { 373 deepEqual(trun.samples[1].flags, {
373 isLeading: 0, 374 isLeading: 0,
374 dependsOn: 0, 375 dependsOn: 1,
375 isDependedOn: 0, 376 isDependedOn: 0,
376 hasRedundancy: 0, 377 hasRedundancy: 0,
377 paddingValue: 0, 378 paddingValue: 0,
...@@ -379,6 +380,20 @@ test('generates a minimal moof', function() { ...@@ -379,6 +380,20 @@ test('generates a minimal moof', function() {
379 degradationPriority: 9 380 degradationPriority: 9
380 }, 'wrote the sample flags'); 381 }, 'wrote the sample flags');
381 equal(trun.samples[1].compositionTimeOffset, 1000, 'wrote the composition time offset'); 382 equal(trun.samples[1].compositionTimeOffset, 1000, 'wrote the composition time offset');
383
384 sdtp = moof[0].boxes[1].boxes[3];
385 equal(sdtp.type, 'sdtp', 'generated an sdtp box');
386 equal(sdtp.samples.length, 2, 'wrote two samples');
387 deepEqual(sdtp.samples[0], {
388 dependsOn: 2,
389 isDependedOn: 1,
390 hasRedundancy: 0
391 }, 'wrote the sample data table');
392 deepEqual(sdtp.samples[1], {
393 dependsOn: 1,
394 isDependedOn: 0,
395 hasRedundancy: 0
396 }, 'wrote the sample data table');
382 }); 397 });
383 398
384 test('can generate a traf without samples', function() { 399 test('can generate a traf without samples', function() {
......
...@@ -782,13 +782,13 @@ test('can parse an sdtp', function() { ...@@ -782,13 +782,13 @@ test('can parse an sdtp', function() {
782 flags: new Uint8Array([0, 0, 0]), 782 flags: new Uint8Array([0, 0, 0]),
783 size: 14, 783 size: 14,
784 samples: [{ 784 samples: [{
785 sampleDependsOn: 1, 785 dependsOn: 1,
786 sampleIsDependedOn: 1, 786 isDependedOn: 1,
787 sampleHasRedundancy: 1 787 hasRedundancy: 1
788 }, { 788 }, {
789 sampleDependsOn: 2, 789 dependsOn: 2,
790 sampleIsDependedOn: 1, 790 isDependedOn: 1,
791 sampleHasRedundancy: 3 791 hasRedundancy: 3
792 }] 792 }]
793 }]); 793 }]);
794 }); 794 });
......
...@@ -287,9 +287,9 @@ var ...@@ -287,9 +287,9 @@ var
287 287
288 for (i = 4; i < data.byteLength; i++) { 288 for (i = 4; i < data.byteLength; i++) {
289 result.samples.push({ 289 result.samples.push({
290 sampleDependsOn: (data[i] & 0x30) >> 4, 290 dependsOn: (data[i] & 0x30) >> 4,
291 sampleIsDependedOn: (data[i] & 0x0c) >> 2, 291 isDependedOn: (data[i] & 0x0c) >> 2,
292 sampleHasRedundancy: data[i] & 0x03 292 hasRedundancy: data[i] & 0x03
293 }); 293 });
294 } 294 }
295 return result; 295 return result;
......
...@@ -874,8 +874,9 @@ validateTrack = function(track, metadata) { ...@@ -874,8 +874,9 @@ validateTrack = function(track, metadata) {
874 }; 874 };
875 875
876 validateTrackFragment = function(track, metadata) { 876 validateTrackFragment = function(track, metadata) {
877 var tfhd, trun, i, sample; 877 var tfhd, trun, sdtp, i, sample;
878 equal(track.type, 'traf', 'wrote a track fragment'); 878 equal(track.type, 'traf', 'wrote a track fragment');
879 equal(track.boxes.length, 4, 'wrote four track fragment children');
879 tfhd = track.boxes[0]; 880 tfhd = track.boxes[0];
880 equal(tfhd.type, 'tfhd', 'wrote a track fragment header'); 881 equal(tfhd.type, 'tfhd', 'wrote a track fragment header');
881 equal(tfhd.trackId, metadata.trackId, 'wrote the track id'); 882 equal(tfhd.trackId, metadata.trackId, 'wrote the track id');
...@@ -902,6 +903,24 @@ validateTrackFragment = function(track, metadata) { ...@@ -902,6 +903,24 @@ validateTrackFragment = function(track, metadata) {
902 equal(sample.flags.hasRedundancy, 0, 'sample redundancy is unknown'); 903 equal(sample.flags.hasRedundancy, 0, 'sample redundancy is unknown');
903 equal(sample.flags.degradationPriority, 0, 'sample degradation priority is zero'); 904 equal(sample.flags.degradationPriority, 0, 'sample degradation priority is zero');
904 } 905 }
906
907 sdtp = track.boxes[3];
908 equal(trun.samples.length,
909 sdtp.samples.length,
910 'wrote an equal number of trun and sdtp samples');
911 for (i = 0; i < sdtp.samples.length; i++) {
912 sample = sdtp.samples[i];
913 notEqual(sample.dependsOn, 0, 'sample dependency is not unknown');
914 equal(trun.samples[i].flags.dependsOn,
915 sample.dependsOn,
916 'wrote a consistent dependsOn');
917 equal(trun.samples[i].flags.isDependedOn,
918 sample.isDependedOn,
919 'wrote a consistent isDependedOn');
920 equal(trun.samples[i].flags.hasRedundancy,
921 sample.hasRedundancy,
922 'wrote a consistent hasRedundancy');
923 }
905 }; 924 };
906 925
907 test('parses an example mp2t file and generates media segments', function() { 926 test('parses an example mp2t file and generates media segments', function() {
......