Skip to content

Commit

Permalink
MP4Remuxer: Refine last sample duration calculation logic to be accurate
Browse files Browse the repository at this point in the history
  • Loading branch information
xqq committed Aug 2, 2017
1 parent 71aa7ed commit 2edad7f
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/core/transmuxing-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ class TransmuxingController {
this._internalAbort();
this._loadSegment(nextSegmentIndex);
} else {
this._remuxer.flushStashedSamples();
this._emitter.emit(TransmuxingEvents.LOADING_COMPLETE);
this._disableStatisticsReporter();
}
Expand Down
4 changes: 2 additions & 2 deletions src/demux/flv-demuxer.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ class FLVDemuxer {
}
} else if (aacData.packetType === 1) { // AAC raw frame data
let dts = this._timestampBase + tagTimestamp;
let aacSample = {unit: aacData.data, dts: dts, pts: dts};
let aacSample = {unit: aacData.data, length: aacData.data.byteLength, dts: dts, pts: dts};
track.samples.push(aacSample);
track.length += aacData.data.length;
} else {
Expand Down Expand Up @@ -587,7 +587,7 @@ class FLVDemuxer {
return;
}
let dts = this._timestampBase + tagTimestamp;
let mp3Sample = {unit: data, dts: dts, pts: dts};
let mp3Sample = {unit: data, length: data.byteLength, dts: dts, pts: dts};
track.samples.push(mp3Sample);
track.length += data.length;
}
Expand Down
101 changes: 93 additions & 8 deletions src/remux/mp4-remuxer.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class MP4Remuxer {
this._videoDtsBase = Infinity;
this._audioNextDts = undefined;
this._videoNextDts = undefined;
this._audioStashedLastSample = null;
this._videoStashedLastSample = null;

this._audioMeta = null;
this._videoMeta = null;
Expand Down Expand Up @@ -121,6 +123,8 @@ class MP4Remuxer {
}

seek(originalDts) {
this._audioStashedLastSample = null;
this._videoStashedLastSample = null;
this._videoSegmentInfoList.clear();
this._audioSegmentInfoList.clear();
}
Expand Down Expand Up @@ -189,6 +193,32 @@ class MP4Remuxer {
this._dtsBaseInited = true;
}

flushStashedSamples() {
let videoSample = this._videoStashedLastSample;
let audioSample = this._audioStashedLastSample;

let videoTrack = {
type: 'video',
id: 1,
sequenceNumber: 0,
samples: [videoSample],
length: videoSample.length
};

let audioTrack = {
type: 'audio',
id: 2,
sequenceNumber: 0,
samples: [audioSample],
length: audioSample.length
};

this._videoStashedLastSample = null;
this._audioStashedLastSample = null;

this.remux(audioTrack, videoTrack);
}

_remuxAudio(audioTrack) {
if (this._audioMeta == null) {
return;
Expand Down Expand Up @@ -224,6 +254,29 @@ class MP4Remuxer {
mdatBytes = 8 + track.length;
}


let lastSample = null;

// Pop the lastSample and waiting for stash
if (samples.length > 1) {
lastSample = samples.pop();
mdatBytes -= lastSample.length;
}

// Insert [stashed lastSample in the previous batch] to the front
if (this._audioStashedLastSample != null) {
let sample = this._audioStashedLastSample;
this._audioStashedLastSample = null;
samples.unshift(sample);
mdatBytes += sample.length;
}

// Stash the lastSample of current batch, waiting for next batch
if (lastSample != null) {
this._audioStashedLastSample = lastSample;
}


let firstSampleOriginalDts = samples[0].dts - this._dtsBase;

// calculate dtsCorrection
Expand Down Expand Up @@ -289,7 +342,10 @@ class MP4Remuxer {
let nextDts = samples[i + 1].dts - this._dtsBase - dtsCorrection;
sampleDuration = nextDts - dts;
} else { // the last sample
if (mp4Samples.length >= 1) { // use second last sample duration
if (lastSample != null) { // use stashed sample's dts to calculate sample duration
let nextDts = lastSample.dts - this._dtsBase - dtsCorrection;
sampleDuration = nextDts - dts;
} else if (mp4Samples.length >= 1) { // use second last sample duration
sampleDuration = mp4Samples[mp4Samples.length - 1].duration;
} else { // the only one sample, use reference sample duration
sampleDuration = Math.floor(refSampleDuration);
Expand Down Expand Up @@ -479,13 +535,31 @@ class MP4Remuxer {
}

let offset = 8;
let mdatbox = null;
let mdatBytes = 8 + videoTrack.length;
let mdatbox = new Uint8Array(mdatBytes);
mdatbox[0] = (mdatBytes >>> 24) & 0xFF;
mdatbox[1] = (mdatBytes >>> 16) & 0xFF;
mdatbox[2] = (mdatBytes >>> 8) & 0xFF;
mdatbox[3] = (mdatBytes) & 0xFF;
mdatbox.set(MP4.types.mdat, 4);


let lastSample = null;

// Pop the lastSample and waiting for stash
if (samples.length > 1) {
lastSample = samples.pop();
mdatBytes -= lastSample.length;
}

// Insert [stashed lastSample in the previous batch] to the front
if (this._videoStashedLastSample != null) {
let sample = this._videoStashedLastSample;
this._videoStashedLastSample = null;
samples.unshift(sample);
mdatBytes += sample.length;
}

// Stash the lastSample of current batch, waiting for next batch
if (lastSample != null) {
this._videoStashedLastSample = lastSample;
}


let firstSampleOriginalDts = samples[0].dts - this._dtsBase;

Expand Down Expand Up @@ -533,7 +607,10 @@ class MP4Remuxer {
let nextDts = samples[i + 1].dts - this._dtsBase - dtsCorrection;
sampleDuration = nextDts - dts;
} else { // the last sample
if (mp4Samples.length >= 1) { // use second last sample duration
if (lastSample != null) { // use stashed sample's dts to calculate sample duration
let nextDts = lastSample.dts - this._dtsBase - dtsCorrection;
sampleDuration = nextDts - dts;
} else if (mp4Samples.length >= 1) { // use second last sample duration
sampleDuration = mp4Samples[mp4Samples.length - 1].duration;
} else { // the only one sample, use reference sample duration
sampleDuration = Math.floor(this._videoMeta.refSampleDuration);
Expand Down Expand Up @@ -565,6 +642,14 @@ class MP4Remuxer {
});
}

// allocate mdatbox
mdatbox = new Uint8Array(mdatBytes);
mdatbox[0] = (mdatBytes >>> 24) & 0xFF;
mdatbox[1] = (mdatBytes >>> 16) & 0xFF;
mdatbox[2] = (mdatBytes >>> 8) & 0xFF;
mdatbox[3] = (mdatBytes) & 0xFF;
mdatbox.set(MP4.types.mdat, 4);

// Write samples into mdatbox
for (let i = 0; i < mp4Samples.length; i++) {
let units = mp4Samples[i].units;
Expand Down

0 comments on commit 2edad7f

Please sign in to comment.