Skip to content

Commit

Permalink
Fix regression in M2TS probe introduced in #5503
Browse files Browse the repository at this point in the history
Fixes #5857
  • Loading branch information
robwalch committed Oct 1, 2023
1 parent 8de2e17 commit 31e998a
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 43 deletions.
10 changes: 7 additions & 3 deletions src/controller/stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,9 +576,13 @@ export default class StreamController
this.hls.trigger(Events.BUFFER_RESET, undefined);
this.fragmentTracker.removeAllFragments();
this.couldBacktrack = false;
this.startPosition = this.lastCurrentTime = 0;
this.levels = this.fragPlaying = this.backtrackFragment = null;
this.altAudio = this.audioOnly = false;
this.startPosition = this.lastCurrentTime = this.fragLastKbps = 0;
this.levels =
this.fragPlaying =
this.backtrackFragment =
this.levelLastLoaded =
null;
this.altAudio = this.audioOnly = this.startFragRequested = false;
}

private onManifestParsed(
Expand Down
8 changes: 5 additions & 3 deletions src/demux/audio/adts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type FrameHeader = {
};

export function getAudioConfig(
observer,
observer: HlsEventEmitter,
data: Uint8Array,
offset: number,
audioCodec: string,
Expand All @@ -45,11 +45,13 @@ export function getAudioConfig(
adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
const adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
observer.trigger(Events.ERROR, {
const error = new Error(`invalid ADTS sampling index:${adtsSamplingIndex}`);
observer.emit(Events.ERROR, Events.ERROR, {
type: ErrorTypes.MEDIA_ERROR,
details: ErrorDetails.FRAG_PARSING_ERROR,
fatal: true,
reason: `invalid ADTS sampling index:${adtsSamplingIndex}`,
error,
reason: error.message,
});
return;
}
Expand Down
10 changes: 6 additions & 4 deletions src/demux/tsdemuxer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,18 @@ class TSDemuxer implements Demuxer {

static syncOffset(data: Uint8Array): number {
const length = data.length;
let scanwindow =
Math.min(PACKET_LENGTH * 5, data.length - PACKET_LENGTH) + 1;
let scanwindow = Math.min(PACKET_LENGTH * 5, length - PACKET_LENGTH) + 1;
let i = 0;
while (i < scanwindow) {
// a TS init segment should contain at least 2 TS packets: PAT and PMT, each starting with 0x47
let foundPat = false;
let packetStart = -1;
let tsPackets = 0;
for (let j = i; j < length; j += PACKET_LENGTH) {
if (data[j] === 0x47) {
if (
data[j] === 0x47 &&
(length - j === PACKET_LENGTH || data[j + PACKET_LENGTH] === 0x47)
) {
tsPackets++;
if (packetStart === -1) {
packetStart = j;
Expand All @@ -134,7 +136,7 @@ class TSDemuxer implements Demuxer {
return packetStart;
}
} else if (tsPackets) {
// Exit if sync word found, but does not contain contiguous packets (#5501)
// Exit if sync word found, but does not contain contiguous packets
return -1;
} else {
break;
Expand Down
60 changes: 27 additions & 33 deletions tests/unit/demuxer/adts.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import EventEmitter from 'eventemitter3';
import {
getAudioConfig,
isHeaderPattern,
Expand All @@ -14,24 +15,25 @@ import { ErrorTypes } from '../../../src/errors';
import sinon from 'sinon';

describe('getAudioConfig', function () {
it('should trigger a MEDIA_ERROR event if sample index is invalid', function () {
const observer = {
trigger: sinon.spy(),
};
it('should emit a MEDIA_ERROR event if sample index is invalid', function () {
const observer = new EventEmitter();
sinon.spy(observer, 'emit');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
data[2] = 0x34; // sampling_frequency_index = 14, which is a reserved value

expect(getAudioConfig(observer, data, 0, 'mp4a.40.29')).to.not.exist;
expect(observer.trigger).to.have.been.calledOnce;
expect(observer.trigger.args[0][1].type).to.equal(ErrorTypes.MEDIA_ERROR);
expect(observer.emit).to.have.been.calledOnce;
expect(observer.emit.args[0][2].type).to.equal(
ErrorTypes.MEDIA_ERROR,
JSON.stringify(observer.emit.args, null, 2),
);
});

it('should return audio config for firefox if the specified sampling frequency > 24kHz', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'firefox'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'firefox');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand All @@ -47,9 +49,8 @@ describe('getAudioConfig', function () {
});

it('should return audio config with a different extension sampling index for Firefox if sampling freq is low', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'Firefox'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'Firefox');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand All @@ -65,9 +66,8 @@ describe('getAudioConfig', function () {
});

it('should return audio config for Android', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'Android'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'Android');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand All @@ -83,9 +83,8 @@ describe('getAudioConfig', function () {
});

it('should return audio config for Chrome', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'Chrome'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'Chrome');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand All @@ -101,9 +100,8 @@ describe('getAudioConfig', function () {
});

it('should return audio config for Chrome if there is no audio codec', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'Chrome'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'Chrome');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand All @@ -119,9 +117,8 @@ describe('getAudioConfig', function () {
});

it('should return audio config for Chrome if there is no audio codec and freq is high enough', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'Chrome'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'Chrome');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand All @@ -137,9 +134,8 @@ describe('getAudioConfig', function () {
});

it('should return audio config for Chrome if audio codec is "mp4a.40.5"', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'Chrome'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'Chrome');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand All @@ -155,9 +151,8 @@ describe('getAudioConfig', function () {
});

it('should return audio config for Chrome if audio codec is "mp4a.40.2"', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'Chrome'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'Chrome');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand All @@ -174,9 +169,8 @@ describe('getAudioConfig', function () {
});

it('should return audio config for Vivaldi', function () {
const observer = {
trigger: sinon.stub(navigator, 'userAgent').get(() => 'Vivaldi'),
};
const observer = new EventEmitter();
sinon.stub(navigator, 'userAgent').get(() => 'Vivaldi');
const data = new Uint8Array(new ArrayBuffer(4));
data[0] = 0xff;
data[1] = 0xf0; // ID = 0 (MPEG-4), layer = 00, protection_absent = 0
Expand Down

0 comments on commit 31e998a

Please sign in to comment.