Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/av-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export function adjustAudioDataVolume(ad: AudioData, volume: number) {
sampleRate: ad.sampleRate,
numberOfChannels: ad.numberOfChannels,
timestamp: ad.timestamp,
format: ad.format,
format: ad.format!,
numberOfFrames: ad.numberOfFrames,
data,
});
Expand Down Expand Up @@ -223,8 +223,8 @@ export function autoReadStream<ST extends ReadableStream>(
stream: ST,
cbs: {
onChunk: ST extends ReadableStream<infer DT>
? (chunk: DT) => Promise<void>
: never;
? (chunk: DT) => Promise<void>
: never;
onDone: () => void;
}
) {
Expand Down
74 changes: 31 additions & 43 deletions src/clips/mp4-clip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ export class MP4Clip implements IClip {
video: VideoDecoderConfig | null;
audio: AudioDecoderConfig | null;
} = {
video: null,
audio: null,
};
video: null,
audio: null,
};

#opts: MP4ClipOpts = { audio: true };

Expand Down Expand Up @@ -114,15 +114,15 @@ export class MP4Clip implements IClip {
this.#localFile = isOTFile(source)
? source
: "localFile" in source
? source.localFile // from clone
: tmpfile();
? source.localFile // from clone
: tmpfile();

this.ready = (
source instanceof ReadableStream
? initByStream(source).then((s) => parseMP4Stream(s, this.#opts))
: isOTFile(source)
? source.stream().then((s) => parseMP4Stream(s, this.#opts))
: Promise.resolve(source)
? source.stream().then((s) => parseMP4Stream(s, this.#opts))
: Promise.resolve(source)
).then(async ({ videoSamples, audioSamples, decoderConf }) => {
this.#videoSamples = videoSamples;
this.#decoderConf = decoderConf;
Expand All @@ -132,10 +132,10 @@ export class MP4Clip implements IClip {
decoderConf.video == null
? null
: {
...decoderConf.video,
hardwareAcceleration:
this.#opts.__unsafe_hardwareAcceleration__,
},
...decoderConf.video,
hardwareAcceleration:
this.#opts.__unsafe_hardwareAcceleration__,
},
audio: decoderConf.audio,
},
await this.#localFile.createReader(),
Expand All @@ -147,7 +147,6 @@ export class MP4Clip implements IClip {
this.#audioFrameFinder = audioFrameFinder;

this.#meta = genMeta(decoderConf, videoSamples, audioSamples);
this.#log.info("MP4Clip meta:", this.#meta);
return { ...this.#meta };
});
}
Expand Down Expand Up @@ -406,22 +405,22 @@ function genDecoder(
volume === 0 || decoderConf.audio == null || audioSamples.length === 0
? null
: new AudioFrameFinder(
localFileReader,
audioSamples,
decoderConf.audio,
{
volume,
targetSampleRate: DEFAULT_AUDIO_CONF.sampleRate,
}
),
localFileReader,
audioSamples,
decoderConf.audio,
{
volume,
targetSampleRate: DEFAULT_AUDIO_CONF.sampleRate,
}
),
videoFrameFinder:
decoderConf.video == null || videoSamples.length === 0
? null
: new VideoFrameFinder(
localFileReader,
videoSamples,
decoderConf.video
),
localFileReader,
videoSamples,
decoderConf.video
),
};
}

Expand Down Expand Up @@ -456,16 +455,6 @@ async function parseMP4Stream(
Error("MP4Clip must contain at least one video or audio track")
);
}
Log.info(
"mp4BoxFile moov ready",
{
...data.info,
tracks: null,
videoTracks: null,
audioTracks: null,
},
decoderConf
);
} else if (chunkType === "samples") {
if (data.type === "video") {
if (videoDeltaTS === -1) videoDeltaTS = data.samples[0].dts;
Expand Down Expand Up @@ -494,7 +483,6 @@ async function parseMP4Stream(
firstSample.duration += firstSample.cts;
firstSample.cts = 0;
}
Log.info("mp4 stream parsed");
resolve({
videoSamples,
audioSamples,
Expand Down Expand Up @@ -530,7 +518,7 @@ class VideoFrameFinder {
public localFileReader: LocalFileReader,
public samples: ExtMP4Sample[],
public conf: VideoDecoderConfig
) {}
) { }

#ts = 0;
#curAborter = { abort: false, st: performance.now() };
Expand Down Expand Up @@ -757,9 +745,9 @@ class AudioFrameFinder {
frameCnt: number;
data: [Float32Array, Float32Array][];
} = {
frameCnt: 0,
data: [],
};
frameCnt: 0,
data: [],
};
#parseFrame = async (
deltaTime: number,
dec: ReturnType<typeof createAudioChunksDecoder> | null = null,
Expand Down Expand Up @@ -953,7 +941,7 @@ function emitAudioFrames(
const audio = [new Float32Array(emitCnt), new Float32Array(emitCnt)];
let offset = 0;
let i = 0;
for (; i < pcmData.data.length; ) {
for (; i < pcmData.data.length;) {
const [chan0, chan1] = pcmData.data[i];
if (offset + chan0.length > emitCnt) {
const gapCnt = emitCnt - offset;
Expand Down Expand Up @@ -990,7 +978,7 @@ async function videosamples2Chunks(
return samples.map((s) => {
const offset = s.offset - first.offset;
let sData = data.subarray(offset, offset + s.size);
if (s.is_idr) sData = removeSEIForIDR(sData);
if (s.is_idr) sData = removeSEIForIDR(sData) as Uint8Array<ArrayBuffer>;
return new EncodedVideoChunk({
type: s.is_sync ? "key" : "delta",
timestamp: s.cts,
Expand All @@ -1005,7 +993,7 @@ async function videosamples2Chunks(
let sData = await reader.read(s.size, {
at: s.offset,
});
if (s.is_idr) sData = removeSEIForIDR(new Uint8Array(sData));
if (s.is_idr) sData = removeSEIForIDR(new Uint8Array(sData)) as unknown as ArrayBuffer;
return new EncodedVideoChunk({
type: s.is_sync ? "key" : "delta",
timestamp: s.cts,
Expand Down Expand Up @@ -1071,7 +1059,7 @@ function isIDRFrame(u8Arr: Uint8Array, type: MP4Sample["description"]["type"]) {

const dv = new DataView(u8Arr.buffer);
let i = 0;
for (; i < u8Arr.byteLength - 4; ) {
for (; i < u8Arr.byteLength - 4;) {
if (type === "avc1") {
if ((dv.getUint8(i + 4) & 0x1f) === 5) return true;
} else if (type === "hvc1") {
Expand Down
3 changes: 0 additions & 3 deletions src/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const lvHandler = ["debug", "info", "warn", "error"].reduce(
Object.assign(acc, {
[lvName]: (...args: any[]) => {
if (THRESHOLD <= lvThres) {
console[lvName as LvName](...args);
writer?.write(
`[${lvName}][${getTimeStr()}] ${args
.map((a) => any2Str(a))
Expand Down Expand Up @@ -67,8 +66,6 @@ map.set(Log.error, 3);
async function init() {
try {
writer = await localFile.createWriter();
Log.info(navigator.userAgent);
Log.info("date: " + new Date().toLocaleDateString());
} catch (err) {
if (!(err instanceof Error)) throw err;
if (err.message.includes("createSyncAccessHandle is not a function")) {
Expand Down
13 changes: 6 additions & 7 deletions src/mp4-utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ function encodeAudioTrack(
error: Log.error,
output: (chunk, meta) => {
if (trackId === -1) {
const desc = meta.decoderConfig?.description;
const desc = meta?.decoderConfig?.description;
trackId = mp4File.addTrack({
...audioTrackOpts,
description: desc == null ? undefined : createESDSBox(desc),
Expand Down Expand Up @@ -417,7 +417,7 @@ export function file2stream(

let i = sendedBoxIdx;
try {
for (; i < boxes.length; ) {
for (; i < boxes.length;) {
boxes[i].write(ds);
delete boxes[i];
i += 1;
Expand All @@ -426,8 +426,7 @@ export function file2stream(
const errBox = boxes[i];
if (err instanceof Error && errBox != null) {
throw Error(
`${err.message} | deltaBuf( boxType: ${errBox.type}, boxSize: ${
errBox.size
`${err.message} | deltaBuf( boxType: ${errBox.type}, boxSize: ${errBox.size
}, boxDataLen: ${errBox.data?.length ?? -1})`
);
}
Expand Down Expand Up @@ -656,7 +655,7 @@ async function concatStreamsToMP4BoxFile(
const offsetCTS = type === "video" ? vCTS : aCTS;

samples.forEach((s) => {
outfile.addSample(trackId, s.data, {
outfile.addSample(trackId, s.data as unknown as ArrayBuffer, {
duration: s.duration,
dts: s.dts + offsetDTS,
cts: s.cts + offsetCTS,
Expand Down Expand Up @@ -870,7 +869,7 @@ export function mixinMP4AndAudio(
} else if (chunkType === "samples") {
const { id, type, samples } = data;
if (type === "video") {
samples.forEach((s) => outfile.addSample(id, s.data, s));
samples.forEach((s) => outfile.addSample(id, s.data as unknown as ArrayBuffer, s));

if (!mp4HasAudio) await addInputAudio2Track(samples);
return;
Expand Down Expand Up @@ -903,7 +902,7 @@ export function mixinMP4AndAudio(
const pcmLength = Math.floor(
((lastSamp.cts + lastSamp.duration - firstSamp.cts) /
lastSamp.timescale) *
sampleRate
sampleRate
);
const audioDataBuf = mixinPCM([getInputAudioSlice(pcmLength)]);
if (audioDataBuf.length === 0) return;
Expand Down
6 changes: 3 additions & 3 deletions src/mp4-utils/mp4box-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ export function extractFileConfig(file: MP4File, info: MP4Info) {
const { descKey, type } = vTrack.codec.startsWith("avc1")
? { descKey: "avcDecoderConfigRecord", type: "avc1" }
: vTrack.codec.startsWith("hvc1")
? { descKey: "hevcDecoderConfigRecord", type: "hvc1" }
: { descKey: "", type: "" };
? { descKey: "hevcDecoderConfigRecord", type: "hvc1" }
: { descKey: "", type: "" };
if (descKey !== "") {
rs.videoTrackConf = {
timescale: vTrack.timescale,
Expand All @@ -40,7 +40,7 @@ export function extractFileConfig(file: MP4File, info: MP4Info) {
codec: vTrack.codec,
codedHeight: vTrack.video.height,
codedWidth: vTrack.video.width,
description: videoDesc,
description: videoDesc as AllowSharedBufferSource | undefined,
};
}

Expand Down