mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 13:53:53 +02:00
Merge main into release for tag v1.14.4
This commit is contained in:
+6
-3
@@ -24,7 +24,7 @@
|
|||||||
chunked: true,
|
chunked: true,
|
||||||
chunkSize: 2**20
|
chunkSize: 2**20
|
||||||
});
|
});
|
||||||
const outputFormat = new Mediabunny.Mp4OutputFormat({});
|
const outputFormat = new Mediabunny.WavOutputFormat({});
|
||||||
|
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
button.textContent = 'Cancel';
|
button.textContent = 'Cancel';
|
||||||
@@ -72,6 +72,9 @@
|
|||||||
}),
|
}),
|
||||||
output,
|
output,
|
||||||
audio: {
|
audio: {
|
||||||
|
codec: 'pcm-s16',
|
||||||
|
//sampleRate: 16000,
|
||||||
|
//numberOfChannels: 1,
|
||||||
//discard: true,
|
//discard: true,
|
||||||
//codec: 'opus',
|
//codec: 'opus',
|
||||||
//bitrate: 128000,
|
//bitrate: 128000,
|
||||||
@@ -106,7 +109,7 @@
|
|||||||
*/
|
*/
|
||||||
video: () => ({
|
video: () => ({
|
||||||
//discard: true,
|
//discard: true,
|
||||||
forceTranscode: true,
|
//forceTranscode: true,
|
||||||
//codec: 'avc',
|
//codec: 'avc',
|
||||||
//fit: 'contain',
|
//fit: 'contain',
|
||||||
//frameRate: 27.123,
|
//frameRate: 27.123,
|
||||||
@@ -129,7 +132,7 @@
|
|||||||
//height: 100,
|
//height: 100,
|
||||||
}),
|
}),
|
||||||
trim: {
|
trim: {
|
||||||
start: 1,
|
start: 0,
|
||||||
end: 10
|
end: 10
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
+5
-3
@@ -14,10 +14,12 @@
|
|||||||
source: new Mediabunny.BlobSource(file),
|
source: new Mediabunny.BlobSource(file),
|
||||||
});
|
});
|
||||||
|
|
||||||
const videoTrack = await input.getPrimaryVideoTrack();
|
const audioTrack = await input.getPrimaryAudioTrack();
|
||||||
const sink = new Mediabunny.VideoSampleSink(videoTrack);
|
const sink = new Mediabunny.EncodedPacketSink(audioTrack);
|
||||||
|
|
||||||
console.log(await sink.getSample(2.131875));
|
for await (const packet of sink.packets()) {
|
||||||
|
console.log(packet);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
||||||
|
|||||||
Generated
+6
-6
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.14.3",
|
"version": "1.14.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.14.3",
|
"version": "1.14.4",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@@ -7749,9 +7749,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mediabunny": {
|
"node_modules/mediabunny": {
|
||||||
"version": "1.14.2",
|
"version": "1.14.3",
|
||||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.14.3.tgz",
|
||||||
"integrity": "sha512-JCup3rpsJGIw3I7E7bZSmVEANCr/OwfwkH3g/Wq1TcHEJ7ymLLw+jC3+/Nnn/JLXzFnw8/I6fV3xECLnFedfHg==",
|
"integrity": "sha512-kCvieRo6X1QDcdWLjn7o2BY/VCDeyU9nNGBVjOIOiWPoTtIekHR+viKAYaZafLEm0poBv+O2PwttL37PaSo/kA==",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
@@ -12242,7 +12242,7 @@
|
|||||||
},
|
},
|
||||||
"packages/mp3-encoder": {
|
"packages/mp3-encoder": {
|
||||||
"name": "@mediabunny/mp3-encoder",
|
"name": "@mediabunny/mp3-encoder",
|
||||||
"version": "1.14.3",
|
"version": "1.14.4",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/emscripten": "^1.40.1"
|
"@types/emscripten": "^1.40.1"
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"author": "Vanilagy",
|
"author": "Vanilagy",
|
||||||
"version": "1.14.3",
|
"version": "1.14.4",
|
||||||
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@mediabunny/mp3-encoder",
|
"name": "@mediabunny/mp3-encoder",
|
||||||
"author": "Vanilagy",
|
"author": "Vanilagy",
|
||||||
"version": "1.14.3",
|
"version": "1.14.4",
|
||||||
"description": "MP3 encoder extension for Mediabunny, based on LAME.",
|
"description": "MP3 encoder extension for Mediabunny, based on LAME.",
|
||||||
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||||
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||||
|
|||||||
+1
-1
@@ -621,7 +621,7 @@ export const parseAacAudioSpecificConfig = (bytes: Uint8Array | null): AacAudioS
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OPUS_INTERNAL_SAMPLE_RATE = 48000;
|
export const OPUS_SAMPLE_RATE = 48_000;
|
||||||
|
|
||||||
const PCM_CODEC_REGEX = /^pcm-([usf])(\d+)+(be)?$/;
|
const PCM_CODEC_REGEX = /^pcm-([usf])(\d+)+(be)?$/;
|
||||||
|
|
||||||
|
|||||||
+17
-17
@@ -1125,8 +1125,6 @@ export class Conversion {
|
|||||||
await this._started;
|
await this._started;
|
||||||
|
|
||||||
const resampler = new AudioResampler({
|
const resampler = new AudioResampler({
|
||||||
sourceNumberOfChannels: track.numberOfChannels,
|
|
||||||
sourceSampleRate: track.sampleRate,
|
|
||||||
targetNumberOfChannels,
|
targetNumberOfChannels,
|
||||||
targetSampleRate,
|
targetSampleRate,
|
||||||
startTime: this._startTimestamp,
|
startTime: this._startTimestamp,
|
||||||
@@ -1246,9 +1244,9 @@ class TrackSynchronizer {
|
|||||||
* OfflineAudioContext.
|
* OfflineAudioContext.
|
||||||
*/
|
*/
|
||||||
export class AudioResampler {
|
export class AudioResampler {
|
||||||
sourceSampleRate: number;
|
sourceSampleRate: number | null = null;
|
||||||
targetSampleRate: number;
|
targetSampleRate: number;
|
||||||
sourceNumberOfChannels: number;
|
sourceNumberOfChannels: number | null = null;
|
||||||
targetNumberOfChannels: number;
|
targetNumberOfChannels: number;
|
||||||
startTime: number;
|
startTime: number;
|
||||||
endTime: number;
|
endTime: number;
|
||||||
@@ -1262,20 +1260,16 @@ export class AudioResampler {
|
|||||||
/** The highest index written to in the current buffer */
|
/** The highest index written to in the current buffer */
|
||||||
maxWrittenFrame: number;
|
maxWrittenFrame: number;
|
||||||
channelMixer!: (sourceData: Float32Array, sourceFrameIndex: number, targetChannelIndex: number) => number;
|
channelMixer!: (sourceData: Float32Array, sourceFrameIndex: number, targetChannelIndex: number) => number;
|
||||||
tempSourceBuffer: Float32Array;
|
tempSourceBuffer!: Float32Array;
|
||||||
|
|
||||||
constructor(options: {
|
constructor(options: {
|
||||||
sourceSampleRate: number;
|
|
||||||
targetSampleRate: number;
|
targetSampleRate: number;
|
||||||
sourceNumberOfChannels: number;
|
|
||||||
targetNumberOfChannels: number;
|
targetNumberOfChannels: number;
|
||||||
startTime: number;
|
startTime: number;
|
||||||
endTime: number;
|
endTime: number;
|
||||||
onSample: (sample: AudioSample) => Promise<void>;
|
onSample: (sample: AudioSample) => Promise<void>;
|
||||||
}) {
|
}) {
|
||||||
this.sourceSampleRate = options.sourceSampleRate;
|
|
||||||
this.targetSampleRate = options.targetSampleRate;
|
this.targetSampleRate = options.targetSampleRate;
|
||||||
this.sourceNumberOfChannels = options.sourceNumberOfChannels;
|
|
||||||
this.targetNumberOfChannels = options.targetNumberOfChannels;
|
this.targetNumberOfChannels = options.targetNumberOfChannels;
|
||||||
this.startTime = options.startTime;
|
this.startTime = options.startTime;
|
||||||
this.endTime = options.endTime;
|
this.endTime = options.endTime;
|
||||||
@@ -1287,17 +1281,14 @@ export class AudioResampler {
|
|||||||
this.outputBuffer = new Float32Array(this.bufferSizeInSamples);
|
this.outputBuffer = new Float32Array(this.bufferSizeInSamples);
|
||||||
this.bufferStartFrame = 0;
|
this.bufferStartFrame = 0;
|
||||||
this.maxWrittenFrame = -1;
|
this.maxWrittenFrame = -1;
|
||||||
|
|
||||||
this.setupChannelMixer();
|
|
||||||
|
|
||||||
// Pre-allocate temporary buffer for source data
|
|
||||||
this.tempSourceBuffer = new Float32Array(this.sourceSampleRate * this.sourceNumberOfChannels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the channel mixer to handle up/downmixing in the case where input and output channel counts don't match.
|
* Sets up the channel mixer to handle up/downmixing in the case where input and output channel counts don't match.
|
||||||
*/
|
*/
|
||||||
setupChannelMixer(): void {
|
doChannelMixerSetup(): void {
|
||||||
|
assert(this.sourceNumberOfChannels !== null);
|
||||||
|
|
||||||
const sourceNum = this.sourceNumberOfChannels;
|
const sourceNum = this.sourceNumberOfChannels;
|
||||||
const targetNum = this.targetNumberOfChannels;
|
const targetNum = this.targetNumberOfChannels;
|
||||||
|
|
||||||
@@ -1415,8 +1406,17 @@ export class AudioResampler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async add(audioSample: AudioSample) {
|
async add(audioSample: AudioSample) {
|
||||||
if (!audioSample || audioSample._closed) {
|
if (this.sourceSampleRate === null) {
|
||||||
return;
|
// This is the first sample, so let's init the missing data. Initting the sample rate from the decoded
|
||||||
|
// sample is more reliable than using the file's metadata, because decoders are free to emit any sample rate
|
||||||
|
// they see fit.
|
||||||
|
this.sourceSampleRate = audioSample.sampleRate;
|
||||||
|
this.sourceNumberOfChannels = audioSample.numberOfChannels;
|
||||||
|
|
||||||
|
// Pre-allocate temporary buffer for source data
|
||||||
|
this.tempSourceBuffer = new Float32Array(this.sourceSampleRate * this.sourceNumberOfChannels);
|
||||||
|
|
||||||
|
this.doChannelMixerSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
const requiredSamples = audioSample.numberOfFrames * audioSample.numberOfChannels;
|
const requiredSamples = audioSample.numberOfFrames * audioSample.numberOfChannels;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
extractAudioCodecString,
|
extractAudioCodecString,
|
||||||
extractVideoCodecString,
|
extractVideoCodecString,
|
||||||
MediaCodec,
|
MediaCodec,
|
||||||
|
OPUS_SAMPLE_RATE,
|
||||||
parseAacAudioSpecificConfig,
|
parseAacAudioSpecificConfig,
|
||||||
parsePcmCodec,
|
parsePcmCodec,
|
||||||
PCM_AUDIO_CODECS,
|
PCM_AUDIO_CODECS,
|
||||||
@@ -1049,6 +1050,10 @@ export class IsobmffDemuxer extends Demuxer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (track.info.codec === 'opus') {
|
||||||
|
sampleRate = OPUS_SAMPLE_RATE; // Always the same
|
||||||
|
}
|
||||||
|
|
||||||
track.info.numberOfChannels = channelCount;
|
track.info.numberOfChannels = channelCount;
|
||||||
track.info.sampleRate = sampleRate;
|
track.info.sampleRate = sampleRate;
|
||||||
|
|
||||||
@@ -1421,7 +1426,7 @@ export class IsobmffDemuxer extends Demuxer {
|
|||||||
|
|
||||||
track.info.codecDescription = description;
|
track.info.codecDescription = description;
|
||||||
track.info.numberOfChannels = outputChannelCount;
|
track.info.numberOfChannels = outputChannelCount;
|
||||||
track.info.sampleRate = inputSampleRate;
|
// Don't copy the input sample rate, irrelevant, and output sample rate is fixed
|
||||||
}; break;
|
}; break;
|
||||||
|
|
||||||
case 'dfLa': { // Used for FLAC audio
|
case 'dfLa': { // Used for FLAC audio
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
extractAudioCodecString,
|
extractAudioCodecString,
|
||||||
extractVideoCodecString,
|
extractVideoCodecString,
|
||||||
MediaCodec,
|
MediaCodec,
|
||||||
|
OPUS_SAMPLE_RATE,
|
||||||
VideoCodec,
|
VideoCodec,
|
||||||
} from '../codec';
|
} from '../codec';
|
||||||
import { Demuxer } from '../demuxer';
|
import { Demuxer } from '../demuxer';
|
||||||
@@ -988,6 +989,7 @@ export class MatroskaDemuxer extends Demuxer {
|
|||||||
} else if (codecIdWithoutSuffix === CODEC_STRING_MAP.opus) {
|
} else if (codecIdWithoutSuffix === CODEC_STRING_MAP.opus) {
|
||||||
this.currentTrack.info.codec = 'opus';
|
this.currentTrack.info.codec = 'opus';
|
||||||
this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate;
|
this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate;
|
||||||
|
this.currentTrack.info.sampleRate = OPUS_SAMPLE_RATE; // Always the same
|
||||||
} else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vorbis) {
|
} else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vorbis) {
|
||||||
this.currentTrack.info.codec = 'vorbis';
|
this.currentTrack.info.codec = 'vorbis';
|
||||||
this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate;
|
this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ import {
|
|||||||
parseSubtitleTimestamp,
|
parseSubtitleTimestamp,
|
||||||
} from '../subtitles';
|
} from '../subtitles';
|
||||||
import {
|
import {
|
||||||
OPUS_INTERNAL_SAMPLE_RATE,
|
OPUS_SAMPLE_RATE,
|
||||||
PCM_AUDIO_CODECS,
|
PCM_AUDIO_CODECS,
|
||||||
PcmAudioCodec,
|
PcmAudioCodec,
|
||||||
SubtitleCodec,
|
SubtitleCodec,
|
||||||
@@ -293,7 +293,7 @@ export class MatroskaMuxer extends Muxer {
|
|||||||
const header = parseOpusIdentificationHeader(bytes);
|
const header = parseOpusIdentificationHeader(bytes);
|
||||||
|
|
||||||
// Use the preSkip value from the header
|
// Use the preSkip value from the header
|
||||||
seekPreRollNs = Math.round(1e9 * (header.preSkip / OPUS_INTERNAL_SAMPLE_RATE));
|
seekPreRollNs = Math.round(1e9 * (header.preSkip / OPUS_SAMPLE_RATE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { OPUS_INTERNAL_SAMPLE_RATE } from '../codec';
|
import { OPUS_SAMPLE_RATE } from '../codec';
|
||||||
import { parseModesFromVorbisSetupPacket, parseOpusIdentificationHeader } from '../codec-data';
|
import { parseModesFromVorbisSetupPacket, parseOpusIdentificationHeader } from '../codec-data';
|
||||||
import { Demuxer } from '../demuxer';
|
import { Demuxer } from '../demuxer';
|
||||||
import { Input } from '../input';
|
import { Input } from '../input';
|
||||||
@@ -249,7 +249,7 @@ export class OggDemuxer extends Demuxer {
|
|||||||
|
|
||||||
const header = parseOpusIdentificationHeader(firstPacket.data);
|
const header = parseOpusIdentificationHeader(firstPacket.data);
|
||||||
bitstream.numberOfChannels = header.outputChannelCount;
|
bitstream.numberOfChannels = header.outputChannelCount;
|
||||||
bitstream.sampleRate = header.inputSampleRate;
|
bitstream.sampleRate = OPUS_SAMPLE_RATE; // Always the same
|
||||||
|
|
||||||
bitstream.codecInfo.opusInfo = {
|
bitstream.codecInfo.opusInfo = {
|
||||||
preSkip: header.preSkip,
|
preSkip: header.preSkip,
|
||||||
@@ -574,7 +574,7 @@ class OggAudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
constructor(public bitstream: LogicalBitstream, public demuxer: OggDemuxer) {
|
constructor(public bitstream: LogicalBitstream, public demuxer: OggDemuxer) {
|
||||||
// Opus always uses a fixed sample rate for its internal calculations, even if the actual rate is different
|
// Opus always uses a fixed sample rate for its internal calculations, even if the actual rate is different
|
||||||
this.internalSampleRate = bitstream.codecInfo.codec === 'opus'
|
this.internalSampleRate = bitstream.codecInfo.codec === 'opus'
|
||||||
? OPUS_INTERNAL_SAMPLE_RATE
|
? OPUS_SAMPLE_RATE
|
||||||
: bitstream.sampleRate;
|
: bitstream.sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { OPUS_INTERNAL_SAMPLE_RATE, validateAudioChunkMetadata } from '../codec';
|
import { OPUS_SAMPLE_RATE, validateAudioChunkMetadata } from '../codec';
|
||||||
import { parseModesFromVorbisSetupPacket, parseOpusIdentificationHeader } from '../codec-data';
|
import { parseModesFromVorbisSetupPacket, parseOpusIdentificationHeader } from '../codec-data';
|
||||||
import {
|
import {
|
||||||
assert,
|
assert,
|
||||||
@@ -119,7 +119,7 @@ export class OggMuxer extends Muxer {
|
|||||||
track,
|
track,
|
||||||
serialNumber,
|
serialNumber,
|
||||||
internalSampleRate: track.source._codec === 'opus'
|
internalSampleRate: track.source._codec === 'opus'
|
||||||
? OPUS_INTERNAL_SAMPLE_RATE
|
? OPUS_SAMPLE_RATE
|
||||||
: meta.decoderConfig.sampleRate,
|
: meta.decoderConfig.sampleRate,
|
||||||
codecInfo: {
|
codecInfo: {
|
||||||
codec: track.source._codec,
|
codec: track.source._codec,
|
||||||
|
|||||||
Reference in New Issue
Block a user