mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-02 05:13:50 +02:00
WIP
This commit is contained in:
+43
-27
@@ -12,7 +12,7 @@ import { Input } from '../input';
|
||||
import { InputAudioTrack, InputAudioTrackBacking } from '../input-track';
|
||||
import { DEFAULT_TRACK_DISPOSITION, MetadataTags } from '../metadata';
|
||||
import { PacketRetrievalOptions } from '../media-sink';
|
||||
import { assert, AsyncMutex, binarySearchExact, binarySearchLessOrEqual, UNDETERMINED_LANGUAGE } from '../misc';
|
||||
import { assert, AsyncMutex, AsyncMutex2, binarySearchExact, binarySearchLessOrEqual, ResultValue, UNDETERMINED_LANGUAGE, Yo } from '../misc';
|
||||
import { EncodedPacket, PLACEHOLDER_DATA } from '../packet';
|
||||
import { FrameHeader, getXingOffset, INFO, XING } from '../../shared/mp3-misc';
|
||||
import {
|
||||
@@ -42,7 +42,8 @@ export class Mp3Demuxer extends Demuxer {
|
||||
|
||||
tracks: InputAudioTrack[] = [];
|
||||
|
||||
readingMutex = new AsyncMutex();
|
||||
// readingMutex = new AsyncMutex();
|
||||
readingMutex = new AsyncMutex2();
|
||||
lastSampleLoaded = false;
|
||||
lastLoadedPos = 0;
|
||||
nextTimestampInSamples = 0;
|
||||
@@ -57,7 +58,9 @@ export class Mp3Demuxer extends Demuxer {
|
||||
return this.metadataPromise ??= (async () => {
|
||||
// Keep loading until we find the first frame header
|
||||
while (!this.firstFrameHeader && !this.lastSampleLoaded) {
|
||||
await this.advanceReader();
|
||||
const result = new ResultValue<void>();
|
||||
const promise = this.advanceReader(result);
|
||||
if (result.pending) await promise;
|
||||
}
|
||||
|
||||
if (!this.firstFrameHeader) {
|
||||
@@ -68,7 +71,7 @@ export class Mp3Demuxer extends Demuxer {
|
||||
})();
|
||||
}
|
||||
|
||||
async advanceReader() {
|
||||
async advanceReader(res: ResultValue<void>): Promise<Yo> {
|
||||
if (this.lastLoadedPos === 0) {
|
||||
// Let's skip all ID3v2 tags at the start of the file
|
||||
while (true) {
|
||||
@@ -77,7 +80,7 @@ export class Mp3Demuxer extends Demuxer {
|
||||
|
||||
if (!slice) {
|
||||
this.lastSampleLoaded = true;
|
||||
return;
|
||||
return res.set();
|
||||
}
|
||||
|
||||
const id3V2Header = readId3V2Header(slice);
|
||||
@@ -89,19 +92,25 @@ export class Mp3Demuxer extends Demuxer {
|
||||
}
|
||||
}
|
||||
|
||||
const result = await readNextFrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize);
|
||||
if (!result) {
|
||||
const result = new ResultValue<{
|
||||
header: FrameHeader;
|
||||
startPos: number;
|
||||
} | null>();
|
||||
const promise = readNextFrameHeader(result, this.reader, this.lastLoadedPos, this.reader.fileSize);
|
||||
if (result.pending) await promise;
|
||||
|
||||
if (!result.value) {
|
||||
this.lastSampleLoaded = true;
|
||||
return;
|
||||
return res.set();
|
||||
}
|
||||
|
||||
const header = result.header;
|
||||
const header = result.value.header;
|
||||
|
||||
this.lastLoadedPos = result.startPos + header.totalSize - 1; // -1 in case the frame is 1 byte too short
|
||||
this.lastLoadedPos = result.value.startPos + header.totalSize - 1; // -1 in case the frame is 1 byte too short
|
||||
|
||||
const xingOffset = getXingOffset(header.mpegVersionId, header.channel);
|
||||
|
||||
let slice = this.reader.requestSlice(result.startPos + xingOffset, 4);
|
||||
let slice = this.reader.requestSlice(result.value.startPos + xingOffset, 4);
|
||||
if (slice instanceof Promise) slice = await slice;
|
||||
if (slice) {
|
||||
const word = readU32Be(slice);
|
||||
@@ -109,7 +118,7 @@ export class Mp3Demuxer extends Demuxer {
|
||||
|
||||
if (isXing) {
|
||||
// There's no actual audio data in this frame, so let's skip it
|
||||
return;
|
||||
return res.set();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,14 +137,14 @@ export class Mp3Demuxer extends Demuxer {
|
||||
const sample: Sample = {
|
||||
timestamp: this.nextTimestampInSamples / this.firstFrameHeader.sampleRate,
|
||||
duration: sampleDuration,
|
||||
dataStart: result.startPos,
|
||||
dataStart: result.value.startPos,
|
||||
dataSize: header.totalSize,
|
||||
};
|
||||
|
||||
this.loadedSamples.push(sample);
|
||||
this.nextTimestampInSamples += header.audioSamplesInFrame;
|
||||
|
||||
return;
|
||||
return res.set();
|
||||
}
|
||||
|
||||
async getMimeType() {
|
||||
@@ -273,14 +282,14 @@ class Mp3AudioTrackBacking implements InputAudioTrackBacking {
|
||||
};
|
||||
}
|
||||
|
||||
async getPacketAtIndex(sampleIndex: number, options: PacketRetrievalOptions) {
|
||||
async getPacketAtIndex(res: ResultValue<EncodedPacket | null>, sampleIndex: number, options: PacketRetrievalOptions): Promise<Yo> {
|
||||
if (sampleIndex === -1) {
|
||||
return null;
|
||||
return res.set(null);
|
||||
}
|
||||
|
||||
const rawSample = this.demuxer.loadedSamples[sampleIndex];
|
||||
if (!rawSample) {
|
||||
return null;
|
||||
return res.set(null);
|
||||
}
|
||||
|
||||
let data: Uint8Array;
|
||||
@@ -291,28 +300,33 @@ class Mp3AudioTrackBacking implements InputAudioTrackBacking {
|
||||
if (slice instanceof Promise) slice = await slice;
|
||||
|
||||
if (!slice) {
|
||||
return null; // Data didn't fit into the rest of the file
|
||||
return res.set(null); // Data didn't fit into the rest of the file
|
||||
}
|
||||
|
||||
data = readBytes(slice, rawSample.dataSize);
|
||||
}
|
||||
|
||||
return new EncodedPacket(
|
||||
return res.set(new EncodedPacket(
|
||||
data,
|
||||
'key',
|
||||
rawSample.timestamp,
|
||||
rawSample.duration,
|
||||
sampleIndex,
|
||||
rawSample.dataSize,
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
getFirstPacket(options: PacketRetrievalOptions) {
|
||||
return this.getPacketAtIndex(0, options);
|
||||
getFirstPacket(res: ResultValue<EncodedPacket | null>, options: PacketRetrievalOptions) {
|
||||
return this.getPacketAtIndex(res, 0, options);
|
||||
}
|
||||
|
||||
async getNextPacket(packet: EncodedPacket, options: PacketRetrievalOptions) {
|
||||
const release = await this.demuxer.readingMutex.acquire();
|
||||
async getNextPacket(res: ResultValue<EncodedPacket | null>, packet: EncodedPacket, options: PacketRetrievalOptions): Promise<Yo> {
|
||||
// using foo = 5;
|
||||
while (this.demuxer.readingMutex.locked) await this.demuxer.readingMutex.promise;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
using _ = this.demuxer.readingMutex.lock();
|
||||
// const release = await this.demuxer.readingMutex.acquire();
|
||||
|
||||
try {
|
||||
const sampleIndex = binarySearchExact(
|
||||
@@ -330,12 +344,14 @@ class Mp3AudioTrackBacking implements InputAudioTrackBacking {
|
||||
nextIndex >= this.demuxer.loadedSamples.length
|
||||
&& !this.demuxer.lastSampleLoaded
|
||||
) {
|
||||
await this.demuxer.advanceReader();
|
||||
const result = new ResultValue<void>();
|
||||
const promise = this.demuxer.advanceReader(result);
|
||||
if (result.pending) await promise;
|
||||
}
|
||||
|
||||
return this.getPacketAtIndex(nextIndex, options);
|
||||
return this.getPacketAtIndex(res, nextIndex, options);
|
||||
} finally {
|
||||
release();
|
||||
// release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-6
@@ -7,12 +7,18 @@
|
||||
*/
|
||||
|
||||
import { FRAME_HEADER_SIZE, FrameHeader, readFrameHeader } from '../../shared/mp3-misc';
|
||||
import { ResultValue, Yo } from '../misc';
|
||||
import { Reader, readU32Be } from '../reader';
|
||||
|
||||
export const readNextFrameHeader = async (reader: Reader, startPos: number, until: number | null): Promise<{
|
||||
header: FrameHeader;
|
||||
startPos: number;
|
||||
} | null> => {
|
||||
export const readNextFrameHeader = async (
|
||||
res: ResultValue<{
|
||||
header: FrameHeader;
|
||||
startPos: number;
|
||||
} | null>,
|
||||
reader: Reader,
|
||||
startPos: number,
|
||||
until: number | null,
|
||||
): Promise<Yo> => {
|
||||
let currentPos = startPos;
|
||||
|
||||
while (until === null || currentPos < until) {
|
||||
@@ -24,11 +30,11 @@ export const readNextFrameHeader = async (reader: Reader, startPos: number, unti
|
||||
|
||||
const result = readFrameHeader(word, reader.fileSize !== null ? reader.fileSize - currentPos : null);
|
||||
if (result.header) {
|
||||
return { header: result.header, startPos: currentPos };
|
||||
return res.set({ header: result.header, startPos: currentPos });
|
||||
}
|
||||
|
||||
currentPos += result.bytesAdvanced;
|
||||
}
|
||||
|
||||
return null;
|
||||
return res.set(null);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user