mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 22:03:49 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e546c2cc7 | ||
|
|
7e89511ca6 | ||
|
|
e0a4169bf8 | ||
|
|
c9dcebed6f | ||
|
|
ae0266df52 |
+4
-4
@@ -24,7 +24,7 @@
|
||||
chunked: true,
|
||||
chunkSize: 2**20
|
||||
});
|
||||
const outputFormat = new Mediabunny.Mp4OutputFormat({});
|
||||
const outputFormat = new Mediabunny.Mp3OutputFormat({});
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.textContent = 'Cancel';
|
||||
@@ -41,7 +41,7 @@
|
||||
target
|
||||
}),
|
||||
audio: {
|
||||
discard: true,
|
||||
//discard: true,
|
||||
//codec: 'opus',
|
||||
//bitrate: 128000,
|
||||
//numberOfChannels: 1,
|
||||
@@ -94,8 +94,8 @@
|
||||
//height: 100,
|
||||
}),
|
||||
trim: {
|
||||
start: 0,
|
||||
end: 20
|
||||
//start: 0,
|
||||
//end: 20
|
||||
},
|
||||
});
|
||||
console.log(conversion);
|
||||
|
||||
+9
-9
@@ -8,15 +8,6 @@
|
||||
document.body.append(fileInput);
|
||||
|
||||
fileInput.addEventListener('change', async () => {
|
||||
const videoUrl = "https://upload.wikimedia.org/wikipedia/commons/5/53/1941._%D0%9A%D0%BE%D0%BD%D1%91%D0%BA-%D0%B3%D0%BE%D1%80%D0%B1%D1%83%D0%BD%D0%BE%D0%BA.webm"
|
||||
const source = new Mediabunny.UrlSource(videoUrl)
|
||||
const input = new Mediabunny.Input({ formats: Mediabunny.ALL_FORMATS, source });
|
||||
|
||||
const videoTrack = await input.getPrimaryVideoTrack();
|
||||
|
||||
console.log(videoTrack);
|
||||
|
||||
/*
|
||||
const file = fileInput.files[0];
|
||||
const source = new Mediabunny.BlobSource(file);
|
||||
|
||||
@@ -25,6 +16,15 @@
|
||||
source
|
||||
});
|
||||
|
||||
const videoTrack = await input.getPrimaryVideoTrack();
|
||||
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
||||
|
||||
for await (const packet of sink.packets(undefined, undefined, { verifyKeyPackets: false })) {
|
||||
console.log(packet);
|
||||
if (packet.timestamp >= 2.4) break;
|
||||
}
|
||||
|
||||
/*
|
||||
const audioTrack = await input.getPrimaryAudioTrack();
|
||||
const sink = new Mediabunny.EncodedPacketSink(audioTrack);
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ const sampleSource = new VideoSampleSource({
|
||||
});
|
||||
|
||||
await sampleSource.add(videoSample);
|
||||
videoSample.close(); // If it's not needed anymore
|
||||
|
||||
// You may optionally force samples to be encoded as key frames:
|
||||
await sampleSource.add(videoSample, { keyFrame: true });
|
||||
@@ -285,6 +286,7 @@ const sampleSource = new AudioSampleSource({
|
||||
});
|
||||
|
||||
await sampleSource.add(audioSample);
|
||||
audioSample.close(); // If it's not needed anymore
|
||||
```
|
||||
|
||||
### `AudioBufferSource`
|
||||
|
||||
Generated
+6
-6
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "mediabunny",
|
||||
"version": "1.7.1",
|
||||
"version": "1.7.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mediabunny",
|
||||
"version": "1.7.1",
|
||||
"version": "1.7.3",
|
||||
"license": "MPL-2.0",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
@@ -5900,9 +5900,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mediabunny": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.7.0.tgz",
|
||||
"integrity": "sha512-QcTdptOtvjAHb4KQpgWWWHRS0+DgGwTXelTwPWaZwQu85iYy11bzsLS4e29rfH4nLL/eq8K/dBsjj1LuApc2Qw==",
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.7.2.tgz",
|
||||
"integrity": "sha512-M84Ice7IR1OpWmmDoUh691Hjpf+w2UTt+VWUH0WkiF5MdfFZ63OAF2TmOhbAEVZyvQ088xlvmaT01t00Qgy/QA==",
|
||||
"license": "MPL-2.0",
|
||||
"peer": true,
|
||||
"workspaces": [
|
||||
@@ -9017,7 +9017,7 @@
|
||||
},
|
||||
"packages/mp3-encoder": {
|
||||
"name": "@mediabunny/mp3-encoder",
|
||||
"version": "1.7.1",
|
||||
"version": "1.7.3",
|
||||
"license": "MPL-2.0",
|
||||
"devDependencies": {
|
||||
"@types/emscripten": "^1.40.1"
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "mediabunny",
|
||||
"author": "Vanilagy",
|
||||
"version": "1.7.1",
|
||||
"version": "1.7.3",
|
||||
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@mediabunny/mp3-encoder",
|
||||
"author": "Vanilagy",
|
||||
"version": "1.7.1",
|
||||
"version": "1.7.3",
|
||||
"description": "MP3 encoder extension for Mediabunny, based on LAME.",
|
||||
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
|
||||
|
||||
@@ -1459,6 +1459,12 @@ export class IsobmffDemuxer extends Demuxer {
|
||||
const sampleIndex = this.metadataReader.readU32() - 1; // Convert to 0-indexed
|
||||
track.sampleTable.keySampleIndices.push(sampleIndex);
|
||||
}
|
||||
|
||||
if (track.sampleTable.keySampleIndices[0] !== 0) {
|
||||
// Some files don't mark the first sample a key sample, which is basically almost always incorrect.
|
||||
// Here, we correct for that mistake:
|
||||
track.sampleTable.keySampleIndices.unshift(0);
|
||||
}
|
||||
}; break;
|
||||
|
||||
case 'stsc': {
|
||||
|
||||
+7
-1
@@ -1248,9 +1248,15 @@ class AudioDecoderWrapper extends DecoderWrapper<AudioSample> {
|
||||
super(onSample, onError);
|
||||
|
||||
const sampleHandler = (sample: AudioSample) => {
|
||||
const sampleRate = decoderConfig.sampleRate;
|
||||
if (sample.numberOfFrames === 0) {
|
||||
// We skip zero-data (empty) AudioSamples. These are sometimes emitted, for example, by Firefox when it
|
||||
// decodes Vorbis (at the start).
|
||||
sample.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Round the timestamp to the sample rate
|
||||
const sampleRate = decoderConfig.sampleRate;
|
||||
sample.setTimestamp(Math.round(sample.timestamp * sampleRate) / sampleRate);
|
||||
|
||||
onSample(sample);
|
||||
|
||||
+25
-24
@@ -158,7 +158,8 @@ export class EncodedVideoPacketSource extends VideoSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an encoded packet to the output video track.
|
||||
* Adds an encoded packet to the output video track. Packets must be added in *decode order*, while a packet's
|
||||
* timestamp must be its *presentation timestamp*. B-frames are handled automatically.
|
||||
*
|
||||
* @param meta - Additional metadata from the encoder. You should pass this for the first call, including a valid
|
||||
* decoder config.
|
||||
@@ -322,17 +323,17 @@ class VideoEncoderWrapper {
|
||||
|
||||
if (this.customEncoder) {
|
||||
this.customEncoderQueueSize++;
|
||||
const promise = this.customEncoderCallSerializer
|
||||
.call(() => this.customEncoder!.encode(videoSample, finalEncodeOptions))
|
||||
.then(() => {
|
||||
this.customEncoderQueueSize--;
|
||||
|
||||
if (shouldClose) {
|
||||
videoSample.close();
|
||||
}
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
this.encoderError ??= error;
|
||||
// We clone the sample so it cannot be closed on us from the outside before it reaches the encoder
|
||||
const clonedSample = videoSample.clone();
|
||||
|
||||
const promise = this.customEncoderCallSerializer
|
||||
.call(() => this.customEncoder!.encode(clonedSample, finalEncodeOptions))
|
||||
.then(() => this.customEncoderQueueSize--)
|
||||
.catch((error: Error) => this.encoderError ??= error)
|
||||
.finally(() => {
|
||||
clonedSample.close();
|
||||
// `videoSample` gets closed in the finally block at the end of the method
|
||||
});
|
||||
|
||||
if (this.customEncoderQueueSize >= 4) {
|
||||
@@ -439,6 +440,7 @@ class VideoEncoderWrapper {
|
||||
void this.muxer!.addEncodedVideoPacket(this.source._connectedTrack!, packet, meta);
|
||||
},
|
||||
error: (error) => {
|
||||
error.stack = new Error().stack; // Provide a more useful stack trace
|
||||
this.encoderError ??= error;
|
||||
},
|
||||
});
|
||||
@@ -482,7 +484,6 @@ class VideoEncoderWrapper {
|
||||
|
||||
checkForEncoderError() {
|
||||
if (this.encoderError) {
|
||||
this.encoderError.stack = new Error().stack; // Provide a more useful stack trace
|
||||
throw this.encoderError;
|
||||
}
|
||||
}
|
||||
@@ -788,7 +789,7 @@ export class EncodedAudioPacketSource extends AudioSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an encoded packet to the output audio track.
|
||||
* Adds an encoded packet to the output audio track. Packets must be added in *decode order*.
|
||||
*
|
||||
* @param meta - Additional metadata from the encoder. You should pass this for the first call, including a valid
|
||||
* decoder config.
|
||||
@@ -938,17 +939,17 @@ class AudioEncoderWrapper {
|
||||
|
||||
if (this.customEncoder) {
|
||||
this.customEncoderQueueSize++;
|
||||
const promise = this.customEncoderCallSerializer
|
||||
.call(() => this.customEncoder!.encode(audioSample))
|
||||
.then(() => {
|
||||
this.customEncoderQueueSize--;
|
||||
|
||||
if (shouldClose) {
|
||||
audioSample.close();
|
||||
}
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
this.encoderError ??= error;
|
||||
// We clone the sample so it cannot be closed on us from the outside before it reaches the encoder
|
||||
const clonedSample = audioSample.clone();
|
||||
|
||||
const promise = this.customEncoderCallSerializer
|
||||
.call(() => this.customEncoder!.encode(clonedSample))
|
||||
.then(() => this.customEncoderQueueSize--)
|
||||
.catch((error: Error) => this.encoderError ??= error)
|
||||
.finally(() => {
|
||||
clonedSample.close();
|
||||
// `audioSample` gets closed in the finally block at the end of the method
|
||||
});
|
||||
|
||||
if (this.customEncoderQueueSize >= 4) {
|
||||
@@ -1127,6 +1128,7 @@ class AudioEncoderWrapper {
|
||||
void this.muxer!.addEncodedAudioPacket(this.source._connectedTrack!, packet, meta);
|
||||
},
|
||||
error: (error) => {
|
||||
error.stack = new Error().stack; // Provide a more useful stack trace
|
||||
this.encoderError ??= error;
|
||||
},
|
||||
});
|
||||
@@ -1265,7 +1267,6 @@ class AudioEncoderWrapper {
|
||||
|
||||
checkForEncoderError() {
|
||||
if (this.encoderError) {
|
||||
this.encoderError.stack = new Error().stack; // Provide a more useful stack trace
|
||||
throw this.encoderError;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user