diff --git a/dev/convert.html b/dev/convert.html
index f85cc61..c94dbb9 100644
--- a/dev/convert.html
+++ b/dev/convert.html
@@ -96,7 +96,8 @@
input,
output,
audio: {
- discard: true,
+ codec: 'aac',
+ forceTranscode: true,
//forceTranscode: true,
//sampleFormat: 's16',
},
@@ -125,7 +126,7 @@
},
*/
video: {
- //discard: true,
+ discard: true,
},
tags: {} ?? {
title: 'Bigggy',
@@ -145,7 +146,9 @@
}
},
trim: {
- end: 10,
+ start: 300.14984567374756 - 100,
+ end: 310.1548298151939 - 100,
+ //end: 10,
//start: startTime,
//end: startTime + 2,
},
diff --git a/package-lock.json b/package-lock.json
index e603e1f..96a69b9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mediabunny",
- "version": "1.44.1",
+ "version": "1.44.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mediabunny",
- "version": "1.44.1",
+ "version": "1.44.2",
"license": "MPL-2.0",
"workspaces": [
"packages/*"
diff --git a/package.json b/package.json
index 8bf224e..bf48225 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "mediabunny",
"author": "Vanilagy",
- "version": "1.44.1",
+ "version": "1.44.2",
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
"type": "module",
"workspaces": [
diff --git a/packages/aac-encoder/package.json b/packages/aac-encoder/package.json
index 12dfbad..9a770f4 100644
--- a/packages/aac-encoder/package.json
+++ b/packages/aac-encoder/package.json
@@ -1,7 +1,7 @@
{
"name": "@mediabunny/aac-encoder",
"author": "Vanilagy",
- "version": "1.44.1",
+ "version": "1.44.2",
"description": "AAC encoder extension for Mediabunny, based on FFmpeg.",
"main": "./dist/bundles/mediabunny-aac-encoder.mjs",
"module": "./dist/bundles/mediabunny-aac-encoder.mjs",
diff --git a/packages/ac3/package.json b/packages/ac3/package.json
index 90c43bb..973d354 100644
--- a/packages/ac3/package.json
+++ b/packages/ac3/package.json
@@ -1,7 +1,7 @@
{
"name": "@mediabunny/ac3",
"author": "Vanilagy",
- "version": "1.44.1",
+ "version": "1.44.2",
"description": "AC-3 and E-AC-3 (Dolby Digital) decoder and encoder extension for Mediabunny, based on FFmpeg.",
"main": "./dist/bundles/mediabunny-ac3.mjs",
"module": "./dist/bundles/mediabunny-ac3.mjs",
diff --git a/packages/flac-encoder/package.json b/packages/flac-encoder/package.json
index 18a2664..a0d7950 100644
--- a/packages/flac-encoder/package.json
+++ b/packages/flac-encoder/package.json
@@ -1,7 +1,7 @@
{
"name": "@mediabunny/flac-encoder",
"author": "Vanilagy",
- "version": "1.44.1",
+ "version": "1.44.2",
"description": "FLAC encoder extension for Mediabunny, based on libFLAC.",
"main": "./dist/bundles/mediabunny-flac-encoder.mjs",
"module": "./dist/bundles/mediabunny-flac-encoder.mjs",
diff --git a/packages/mp3-encoder/package.json b/packages/mp3-encoder/package.json
index 0c2d43d..97b4dc1 100644
--- a/packages/mp3-encoder/package.json
+++ b/packages/mp3-encoder/package.json
@@ -1,7 +1,7 @@
{
"name": "@mediabunny/mp3-encoder",
"author": "Vanilagy",
- "version": "1.44.1",
+ "version": "1.44.2",
"description": "MP3 encoder extension for Mediabunny, based on LAME.",
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
diff --git a/src/conversion.ts b/src/conversion.ts
index 8c3182b..584ec71 100644
--- a/src/conversion.ts
+++ b/src/conversion.ts
@@ -1889,6 +1889,7 @@ export class Conversion {
startTime: this._startTimestamp,
endTime: this._endTimestamp,
onSample: async (sample) => {
+ assert(sample.timestamp >= this._startTimestamp);
sample.setTimestamp(sample.timestamp - this._startTimestamp);
await this._registerAudioSample(trackOptions, outputTrackId, source, sample);
diff --git a/src/resample.ts b/src/resample.ts
index 727492d..4686a9d 100644
--- a/src/resample.ts
+++ b/src/resample.ts
@@ -20,7 +20,6 @@ export class AudioResampler {
targetSampleRate: number;
sourceNumberOfChannels: number | null = null;
targetNumberOfChannels: number;
- startTime: number;
endTime: number;
onSample: (sample: AudioSample) => Promise;
@@ -33,6 +32,7 @@ export class AudioResampler {
maxWrittenFrame: number | null = null;
channelMixer!: (sourceData: Float32Array, sourceFrameIndex: number, targetChannelIndex: number) => number;
tempSourceBuffer!: Float32Array;
+ timestampOffset: number;
constructor(options: {
targetSampleRate: number;
@@ -43,7 +43,6 @@ export class AudioResampler {
}) {
this.targetSampleRate = options.targetSampleRate;
this.targetNumberOfChannels = options.targetNumberOfChannels;
- this.startTime = options.startTime;
this.endTime = options.endTime;
this.onSample = options.onSample;
@@ -51,7 +50,11 @@ export class AudioResampler {
this.bufferSizeInSamples = this.bufferSizeInFrames * this.targetNumberOfChannels;
this.outputBuffer = new Float32Array(this.bufferSizeInSamples);
- this.bufferStartFrame = Math.floor(this.startTime * this.targetSampleRate);
+
+ this.bufferStartFrame = Math.floor(options.startTime * this.targetSampleRate);
+ // Set to ensure that if the buffer start frame lands on a fractional sample, that the first timestamp still
+ // comes out as exactly startTime
+ this.timestampOffset = options.startTime - this.bufferStartFrame / this.targetSampleRate;
}
/**
@@ -273,7 +276,7 @@ export class AudioResampler {
format: 'f32',
sampleRate: this.targetSampleRate,
numberOfChannels: this.targetNumberOfChannels,
- timestamp: timestampSeconds,
+ timestamp: timestampSeconds + this.timestampOffset,
data: outputData,
});
diff --git a/test/browser/conversion.test.ts b/test/browser/conversion.test.ts
index 561fe4f..ceab56c 100644
--- a/test/browser/conversion.test.ts
+++ b/test/browser/conversion.test.ts
@@ -1,6 +1,12 @@
import { ALL_FORMATS } from '../../src/input-format.js';
import { Input } from '../../src/input.js';
-import { AdtsOutputFormat, HlsOutputFormat, Mp4OutputFormat, MpegTsOutputFormat } from '../../src/output-format.js';
+import {
+ AdtsOutputFormat,
+ HlsOutputFormat,
+ Mp4OutputFormat,
+ MpegTsOutputFormat,
+ WavOutputFormat,
+} from '../../src/output-format.js';
import { Output, OutputTrackGroup } from '../../src/output.js';
import { BufferSource, CustomPathedSource, UrlSource } from '../../src/source.js';
import { expect, test } from 'vitest';
@@ -369,3 +375,30 @@ test('HLS track assignability can be overridden', async () => {
expect(newMasterPlayist).not.toBe(masterPlayist);
expect(newMasterPlayist.match(/\.m3u8/g)?.length).toBe(1);
});
+
+test('Fractional audio sample boundary', async () => {
+ using input = new Input({
+ source: new UrlSource('/trim-buck-bunny-ffmpeg.ts'),
+ formats: ALL_FORMATS,
+ });
+
+ const output = new Output({
+ format: new WavOutputFormat(),
+ target: new BufferTarget(),
+ });
+
+ const conversion = await Conversion.init({
+ input,
+ output,
+ video: {
+ discard: true,
+ },
+ audio: {
+ forceTranscode: true,
+ },
+ trim: {
+ start: 0.4 / 48000,
+ },
+ });
+ await conversion.execute();
+});