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 @@
'use strict';
var box, dinf, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd, trak,
tkhd, mdia, mdhd, hdlr, stbl, stsd, styp, traf, trex, trun, types,
MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR, AUDIO_HDLR,
HDLR_TYPES, VMHD, DREF, STCO, STSC, STSZ, STTS, Uint8Array,
DataView;
tkhd, mdia, mdhd, hdlr, sdtp, stbl, stsd, styp, traf, trex, trun,
types, MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR,
AUDIO_HDLR, HDLR_TYPES, VMHD, DREF, STCO, STSC, STSZ, STTS,
Uint8Array, DataView;
Uint8Array = window.Uint8Array;
DataView = window.DataView;
......@@ -30,6 +30,7 @@ DataView = window.DataView;
moov: [],
mvex: [],
mvhd: [],
sdtp: [],
stbl: [],
stco: [],
stsc: [],
......@@ -276,6 +277,27 @@ mvhd = function(duration) {
return box(types.mvhd, bytes);
};
sdtp = function(track) {
var
samples = track.samples || [],
bytes = new Uint8Array(4 + samples.length),
sample,
i;
// leave the full box header (4 bytes) all zero
// write the sample table
for (i = 0; i < samples.length; i++) {
sample = samples[i];
bytes[i + 4] = (sample.flags.dependsOn << 4) |
(sample.flags.isDependedOn << 2) |
(sample.flags.hasRedundancy);
}
return box(types.sdtp,
bytes);
};
stbl = function(track) {
return box(types.stbl,
stsd(track),
......@@ -414,7 +436,8 @@ traf = function(track) {
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x00 // baseMediaDecodeTime
])),
trun(track));
trun(track),
sdtp(track));
};
/**
......
......@@ -307,8 +307,8 @@ test('generates a minimal moof', function() {
size: 10,
flags: {
isLeading: 0,
dependsOn: 0,
isDependedOn: 0,
dependsOn: 2,
isDependedOn: 1,
hasRedundancy: 0,
paddingValue: 0,
isNonSyncSample: 0,
......@@ -320,7 +320,7 @@ test('generates a minimal moof', function() {
size: 11,
flags: {
isLeading: 0,
dependsOn: 0,
dependsOn: 1,
isDependedOn: 0,
hasRedundancy: 0,
paddingValue: 0,
......@@ -331,7 +331,8 @@ test('generates a minimal moof', function() {
}]
}]),
moof = videojs.inspectMp4(data),
trun;
trun,
sdtp;
equal(moof.length, 1, 'generated one box');
equal(moof[0].type, 'moof', 'generated a moof box');
......@@ -339,7 +340,7 @@ test('generates a minimal moof', function() {
equal(moof[0].boxes[0].type, 'mfhd', 'generated an mfhd box');
equal(moof[0].boxes[0].sequenceNumber, 7, 'included the sequence_number');
equal(moof[0].boxes[1].type, 'traf', 'generated a traf box');
equal(moof[0].boxes[1].boxes.length, 3, 'generated track fragment info');
equal(moof[0].boxes[1].boxes.length, 4, 'generated track fragment info');
equal(moof[0].boxes[1].boxes[0].type, 'tfhd', 'generated a tfhd box');
equal(moof[0].boxes[1].boxes[0].trackId, 17, 'wrote the first track id');
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() {
equal(trun.samples[0].size, 10, 'wrote a sample size');
deepEqual(trun.samples[0].flags, {
isLeading: 0,
dependsOn: 0,
isDependedOn: 0,
dependsOn: 2,
isDependedOn: 1,
hasRedundancy: 0,
paddingValue: 0,
isNonSyncSample: 0,
......@@ -371,7 +372,7 @@ test('generates a minimal moof', function() {
equal(trun.samples[1].size, 11, 'wrote a sample size');
deepEqual(trun.samples[1].flags, {
isLeading: 0,
dependsOn: 0,
dependsOn: 1,
isDependedOn: 0,
hasRedundancy: 0,
paddingValue: 0,
......@@ -379,6 +380,20 @@ test('generates a minimal moof', function() {
degradationPriority: 9
}, 'wrote the sample flags');
equal(trun.samples[1].compositionTimeOffset, 1000, 'wrote the composition time offset');
sdtp = moof[0].boxes[1].boxes[3];
equal(sdtp.type, 'sdtp', 'generated an sdtp box');
equal(sdtp.samples.length, 2, 'wrote two samples');
deepEqual(sdtp.samples[0], {
dependsOn: 2,
isDependedOn: 1,
hasRedundancy: 0
}, 'wrote the sample data table');
deepEqual(sdtp.samples[1], {
dependsOn: 1,
isDependedOn: 0,
hasRedundancy: 0
}, 'wrote the sample data table');
});
test('can generate a traf without samples', function() {
......
......@@ -782,13 +782,13 @@ test('can parse an sdtp', function() {
flags: new Uint8Array([0, 0, 0]),
size: 14,
samples: [{
sampleDependsOn: 1,
sampleIsDependedOn: 1,
sampleHasRedundancy: 1
dependsOn: 1,
isDependedOn: 1,
hasRedundancy: 1
}, {
sampleDependsOn: 2,
sampleIsDependedOn: 1,
sampleHasRedundancy: 3
dependsOn: 2,
isDependedOn: 1,
hasRedundancy: 3
}]
}]);
});
......
......@@ -287,9 +287,9 @@ var
for (i = 4; i < data.byteLength; i++) {
result.samples.push({
sampleDependsOn: (data[i] & 0x30) >> 4,
sampleIsDependedOn: (data[i] & 0x0c) >> 2,
sampleHasRedundancy: data[i] & 0x03
dependsOn: (data[i] & 0x30) >> 4,
isDependedOn: (data[i] & 0x0c) >> 2,
hasRedundancy: data[i] & 0x03
});
}
return result;
......
......@@ -874,8 +874,9 @@ validateTrack = function(track, metadata) {
};
validateTrackFragment = function(track, metadata) {
var tfhd, trun, i, sample;
var tfhd, trun, sdtp, i, sample;
equal(track.type, 'traf', 'wrote a track fragment');
equal(track.boxes.length, 4, 'wrote four track fragment children');
tfhd = track.boxes[0];
equal(tfhd.type, 'tfhd', 'wrote a track fragment header');
equal(tfhd.trackId, metadata.trackId, 'wrote the track id');
......@@ -902,6 +903,24 @@ validateTrackFragment = function(track, metadata) {
equal(sample.flags.hasRedundancy, 0, 'sample redundancy is unknown');
equal(sample.flags.degradationPriority, 0, 'sample degradation priority is zero');
}
sdtp = track.boxes[3];
equal(trun.samples.length,
sdtp.samples.length,
'wrote an equal number of trun and sdtp samples');
for (i = 0; i < sdtp.samples.length; i++) {
sample = sdtp.samples[i];
notEqual(sample.dependsOn, 0, 'sample dependency is not unknown');
equal(trun.samples[i].flags.dependsOn,
sample.dependsOn,
'wrote a consistent dependsOn');
equal(trun.samples[i].flags.isDependedOn,
sample.isDependedOn,
'wrote a consistent isDependedOn');
equal(trun.samples[i].flags.hasRedundancy,
sample.hasRedundancy,
'wrote a consistent hasRedundancy');
}
};
test('parses an example mp2t file and generates media segments', function() {
......