Skip to content

Commit

Permalink
Fix issue in Layer3.js where last frame is dropped
Browse files Browse the repository at this point in the history
Merge of open pull request in parent project audiocogs/mp3.js#19
  • Loading branch information
Thalhammer committed Sep 24, 2019
1 parent f900eed commit c242d3e
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 47 deletions.
14 changes: 6 additions & 8 deletions src/demuxer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,28 @@ export class MP3Demuxer extends AV.Demuxer {
private sentInfo: boolean;

static probe(stream: AV.Stream) {
var off = stream.offset;
let off = stream.offset;

// skip id3 metadata if it exists
var id3header = MP3Demuxer.getID3v2Header(stream);
let id3header = MP3Demuxer.getID3v2Header(stream);
if (id3header)
stream.advance(10 + id3header.length);

// attempt to read the header of the first audio frame
var s = new MP3Stream(new AV.Bitstream(stream));
var header = null;
let s = new MP3Stream(new AV.Bitstream(stream));
let header = null;

try {
header = MP3FrameHeader.decode(s);
} catch (e) {
console.log(e);
};
} catch (e) {};

// go back to the beginning, for other probes
stream.seek(off);

return !!header;
}

static getID3v2Header(stream) :{
static getID3v2Header(stream) : {
version: string;
major: number;
minor: number;
Expand Down
69 changes: 40 additions & 29 deletions src/layer3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,23 @@ export class Layer3 {

// find main_data of next frame
var peek = stream.copy();
peek.seek(stream.next_frame * 8);

var nextHeader = peek.read(16);
if ((nextHeader & 0xffe6) === 0xffe2) { // syncword | layer
if ((nextHeader & 1) === 0) // protection bit
peek.advance(16); // crc check

peek.advance(16); // skip the rest of the header
next_md_begin = peek.read((nextHeader & 8) ? 9 : 8);
var nextHeader = null;
try {
peek.seek(stream.next_frame * 8);
nextHeader = peek.read(16);
if ((nextHeader & 0xffe6) === 0xffe2) { // syncword | layer
if ((nextHeader & 1) === 0) // protection bit
peek.advance(16); // crc check

peek.advance(16); // skip the rest of the header
next_md_begin = peek.read((nextHeader & 8) ? 9 : 8);
}
} catch (err) {
if (err instanceof AV.UnderflowError) {
next_md_begin = 0;
nextHeader = null;
} else throw err;
}

// find main_data of this frame
var frame_space = stream.next_frame - stream.nextByte();

Expand Down Expand Up @@ -141,26 +147,31 @@ export class Layer3 {
// decode main_data
this.decodeMainData(ptr, frame, si, nch);

// preload main_data buffer with up to 511 bytes for next frame(s)
if (frame_free >= next_md_begin) {
this.memcpy(stream.main_data, 0, stream.stream.stream, stream.next_frame - next_md_begin, next_md_begin);
stream.md_len = next_md_begin;
} else {
if (md_len < si.main_data_begin) {
var extra = si.main_data_begin - md_len;
if (extra + frame_free > next_md_begin)
extra = next_md_begin - frame_free;

if (extra < stream.md_len) {
this.memcpy(stream.main_data, 0, stream.main_data, stream.md_len - extra, extra);
stream.md_len = extra;
}
if (next_md_begin > 0) {
// preload main_data buffer with up to 511 bytes for next frame(s)
if (frame_free >= next_md_begin) {
this.memcpy(stream.main_data, 0, stream.stream.stream, stream.next_frame - next_md_begin, next_md_begin);
stream.md_len = next_md_begin;
} else {
stream.md_len = 0;
}
if (md_len < si.main_data_begin) {
var extra = si.main_data_begin - md_len;
if (extra + frame_free > next_md_begin)
extra = next_md_begin - frame_free;

if (extra < stream.md_len) {
this.memcpy(stream.main_data, 0, stream.main_data, stream.md_len - extra, extra);
stream.md_len = extra;
}
} else {
stream.md_len = 0;
}

this.memcpy(stream.main_data, stream.md_len, stream.stream.stream, stream.next_frame - frame_free, frame_free);
stream.md_len += frame_free;
this.memcpy(stream.main_data, stream.md_len, stream.stream.stream, stream.next_frame - frame_free, frame_free);
stream.md_len += frame_free;
}
} else {
stream.md_len = 0;
stream.main_data.fill(0);
}
}

Expand Down Expand Up @@ -1017,7 +1028,7 @@ export class Layer3 {
if (!(modes[sfbi] & tables.I_STEREO))
continue;

let is_pos = right_ch.scalefac[sfbi];
let is_pos = right_ch.scalefac[sfbi];

if (is_pos >= 7) { // illegal intensity position
modes[sfbi] &= ~tables.I_STEREO;
Expand Down
35 changes: 25 additions & 10 deletions src/stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import {MP3FrameHeader} from './header';

export class MP3Stream {
private stream: AV.Bitstream; // actual bitstream
private sync; // stream sync found
private freerate; // free bitrate (fixed)
private this_frame; // start of current frame
private next_frame; // start of next frame
private sync: boolean; // stream sync found
private freerate: number; // free bitrate (fixed)
private this_frame: number; // start of current frame
private next_frame: number; // start of next frame

private main_data; // actual audio data
private md_len; // length of main data
private main_data: Uint8Array; // actual audio data
private md_len: number; // length of main data


constructor(stream: AV.Bitstream) {
Expand Down Expand Up @@ -39,12 +39,27 @@ export class MP3Stream {
getU8(offset) {
var stream = this.stream.stream;
return stream.peekUInt8(offset - stream.offset);
};
}

getU16(offset) {
var stream = this.stream.stream;
return stream.peekUInt16(offset - stream.offset);
}

getU24(offset) {
var stream = this.stream.stream;
return stream.peekUInt24(offset - stream.offset);
}

getU32(offset) {
var stream = this.stream.stream;
return stream.peekUInt32(offset - stream.offset);
}

nextByte() {
var stream = this.stream;
return stream.bitPosition === 0 ? stream.stream.offset : stream.stream.offset + 1;
};
}

doSync() {
var stream = this.stream.stream;
Expand All @@ -58,11 +73,11 @@ export class MP3Stream {
return false;

return true;
};
}

reset(byteOffset) {
this.stream.seek(byteOffset * 8);
this.next_frame = byteOffset;
this.sync = true;
};
}
}

0 comments on commit c242d3e

Please sign in to comment.