mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 10:53:50 +02:00
Merge main into release for tag v1.8.0
This commit is contained in:
Generated
+6
-6
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "mediabunny",
|
||||
"version": "1.7.6",
|
||||
"version": "1.8.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mediabunny",
|
||||
"version": "1.7.6",
|
||||
"version": "1.8.0",
|
||||
"license": "MPL-2.0",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
@@ -5900,9 +5900,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mediabunny": {
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.7.5.tgz",
|
||||
"integrity": "sha512-H7dH2KCOzP/QDHaaNmgo52pDOAuHfC0aa9w9XKPOzcY6x923vGE2CTOqO9W/WEmf8DCRKReGwupSlWuq9NMLYg==",
|
||||
"version": "1.7.6",
|
||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.7.6.tgz",
|
||||
"integrity": "sha512-PtWscl5vdsBYwtNSO0J21lAGUiweudmTmHabz4NWuQ+mAUvtG1ocupyYpT18IflteVtdtNMqxKKPPbvlcHuk0w==",
|
||||
"license": "MPL-2.0",
|
||||
"peer": true,
|
||||
"workspaces": [
|
||||
@@ -9017,7 +9017,7 @@
|
||||
},
|
||||
"packages/mp3-encoder": {
|
||||
"name": "@mediabunny/mp3-encoder",
|
||||
"version": "1.7.6",
|
||||
"version": "1.8.0",
|
||||
"license": "MPL-2.0",
|
||||
"devDependencies": {
|
||||
"@types/emscripten": "^1.40.1"
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "mediabunny",
|
||||
"author": "Vanilagy",
|
||||
"version": "1.7.6",
|
||||
"version": "1.8.0",
|
||||
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
|
||||
@@ -108,7 +108,7 @@ For simplicity, all built WASM artifacts are included in the repo, since these r
|
||||
|
||||
### Prerequisites
|
||||
|
||||
[Install Emscripten](https://emscripten.org/docs/getting_started/downloads.html). The recommended way is using the emsdk, which involves cloning a repo and running a few commands.
|
||||
[Install Emscripten](https://emscripten.org/docs/getting_started/downloads.html). The recommended way is using the emsdk, which involves cloning a repo and running a few commands. The following commands assume Emscripten is sourced in.
|
||||
|
||||
### Compiling LAME:
|
||||
|
||||
@@ -139,6 +139,7 @@ emcc src/lame-bridge.c build/libmp3lame.a \
|
||||
-s MODULARIZE=1 \
|
||||
-s EXPORT_ES6=1 \
|
||||
-s SINGLE_FILE=1 \
|
||||
-s ALLOW_MEMORY_GROWTH=1 \
|
||||
-s ENVIRONMENT=web,worker \
|
||||
-s EXPORTED_RUNTIME_METHODS=cwrap,HEAPU8 \
|
||||
-s EXPORTED_FUNCTIONS=_malloc,_free \
|
||||
|
||||
Generated
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@mediabunny/mp3-encoder",
|
||||
"author": "Vanilagy",
|
||||
"version": "1.7.6",
|
||||
"version": "1.8.0",
|
||||
"description": "MP3 encoder extension for Mediabunny, based on LAME.",
|
||||
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import { CustomAudioEncoder, AudioCodec, AudioSample, EncodedPacket, registerEncoder } from 'mediabunny';
|
||||
import { FRAME_HEADER_SIZE, readFrameHeader } from '../../../shared/mp3-misc';
|
||||
import { FRAME_HEADER_SIZE, readFrameHeader, SAMPLING_RATES } from '../../../shared/mp3-misc';
|
||||
import type { WorkerCommand, WorkerResponse, WorkerResponseData } from './shared';
|
||||
// @ts-expect-error An esbuild plugin handles this, TypeScript doesn't need to understand
|
||||
import createWorker from './encode.worker';
|
||||
@@ -28,7 +28,7 @@ class Mp3Encoder extends CustomAudioEncoder {
|
||||
static override supports(codec: AudioCodec, config: AudioDecoderConfig): boolean {
|
||||
return codec === 'mp3'
|
||||
&& (config.numberOfChannels === 1 || config.numberOfChannels === 2)
|
||||
&& (config.sampleRate === 32000 || config.sampleRate === 44100 || config.sampleRate === 48000);
|
||||
&& Object.values(SAMPLING_RATES).some(x => x.includes(config.sampleRate));
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
||||
+8
-7
@@ -1334,16 +1334,17 @@ export class AudioBufferSource extends AudioSource {
|
||||
* @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise
|
||||
* to respect writer and encoder backpressure.
|
||||
*/
|
||||
add(audioBuffer: AudioBuffer) {
|
||||
async add(audioBuffer: AudioBuffer) {
|
||||
if (!(audioBuffer instanceof AudioBuffer)) {
|
||||
throw new TypeError('audioBuffer must be an AudioBuffer.');
|
||||
}
|
||||
|
||||
const audioSamples = AudioSample.fromAudioBuffer(audioBuffer, this._accumulatedTime);
|
||||
const promises = audioSamples.map(sample => this._encoder.add(sample, true));
|
||||
|
||||
const iterator = AudioSample._fromAudioBuffer(audioBuffer, this._accumulatedTime);
|
||||
this._accumulatedTime += audioBuffer.duration;
|
||||
return Promise.all(promises);
|
||||
|
||||
for (const audioSample of iterator) {
|
||||
await this._encoder.add(audioSample, true);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -1466,10 +1467,10 @@ export class MediaStreamAudioTrackSource extends AudioSource {
|
||||
let totalDuration = 0;
|
||||
|
||||
this._scriptProcessorNode.onaudioprocess = (event) => {
|
||||
const audioSamples = AudioSample.fromAudioBuffer(event.inputBuffer, totalDuration);
|
||||
const iterator = AudioSample._fromAudioBuffer(event.inputBuffer, totalDuration);
|
||||
totalDuration += event.inputBuffer.duration;
|
||||
|
||||
for (const audioSample of audioSamples) {
|
||||
for (const audioSample of iterator) {
|
||||
if (!audioReceived) {
|
||||
audioReceived = true;
|
||||
|
||||
|
||||
+46
-3
@@ -1067,6 +1067,49 @@ export class AudioSample {
|
||||
(this.timestamp as number) = newTimestamp;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
static* _fromAudioBuffer(audioBuffer: AudioBuffer, timestamp: number) {
|
||||
if (!(audioBuffer instanceof AudioBuffer)) {
|
||||
throw new TypeError('audioBuffer must be an AudioBuffer.');
|
||||
}
|
||||
|
||||
const MAX_FLOAT_COUNT = 48000 * 5; // 5 seconds of mono 48 kHz audio per sample
|
||||
|
||||
const numberOfChannels = audioBuffer.numberOfChannels;
|
||||
const sampleRate = audioBuffer.sampleRate;
|
||||
const totalFrames = audioBuffer.length;
|
||||
const maxFramesPerChunk = Math.floor(MAX_FLOAT_COUNT / numberOfChannels);
|
||||
|
||||
let currentRelativeFrame = 0;
|
||||
let remainingFrames = totalFrames;
|
||||
|
||||
// Create AudioSamples in a chunked fashion so we don't create huge Float32Arrays
|
||||
while (remainingFrames > 0) {
|
||||
const framesToCopy = Math.min(maxFramesPerChunk, remainingFrames);
|
||||
const chunkData = new Float32Array(numberOfChannels * framesToCopy);
|
||||
|
||||
for (let channel = 0; channel < numberOfChannels; channel++) {
|
||||
audioBuffer.copyFromChannel(
|
||||
chunkData.subarray(channel * framesToCopy, (channel + 1) * framesToCopy),
|
||||
channel,
|
||||
currentRelativeFrame,
|
||||
);
|
||||
}
|
||||
|
||||
yield new AudioSample({
|
||||
format: 'f32-planar',
|
||||
sampleRate,
|
||||
numberOfFrames: framesToCopy,
|
||||
numberOfChannels,
|
||||
timestamp: timestamp + currentRelativeFrame / sampleRate,
|
||||
data: chunkData,
|
||||
});
|
||||
|
||||
currentRelativeFrame += framesToCopy;
|
||||
remainingFrames -= framesToCopy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates AudioSamples from an AudioBuffer, starting at the given timestamp in seconds. Typically creates exactly
|
||||
* one sample, but may create multiple if the AudioBuffer is exceedingly large.
|
||||
@@ -1076,7 +1119,7 @@ export class AudioSample {
|
||||
throw new TypeError('audioBuffer must be an AudioBuffer.');
|
||||
}
|
||||
|
||||
const MAX_FLOAT_COUNT = 64 * 1024 * 1024;
|
||||
const MAX_FLOAT_COUNT = 48000 * 5; // 5 seconds of mono 48 kHz audio per sample
|
||||
|
||||
const numberOfChannels = audioBuffer.numberOfChannels;
|
||||
const sampleRate = audioBuffer.sampleRate;
|
||||
@@ -1088,14 +1131,14 @@ export class AudioSample {
|
||||
|
||||
const result: AudioSample[] = [];
|
||||
|
||||
// Create AudioData in a chunked fashion so we don't create huge Float32Arrays
|
||||
// Create AudioSamples in a chunked fashion so we don't create huge Float32Arrays
|
||||
while (remainingFrames > 0) {
|
||||
const framesToCopy = Math.min(maxFramesPerChunk, remainingFrames);
|
||||
const chunkData = new Float32Array(numberOfChannels * framesToCopy);
|
||||
|
||||
for (let channel = 0; channel < numberOfChannels; channel++) {
|
||||
audioBuffer.copyFromChannel(
|
||||
chunkData.subarray(channel * framesToCopy, channel * framesToCopy + framesToCopy),
|
||||
chunkData.subarray(channel * framesToCopy, (channel + 1) * framesToCopy),
|
||||
channel,
|
||||
currentRelativeFrame,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user