Merge main into release for tag v1.29.1

This commit is contained in:
github-actions[bot]
2026-01-20 19:13:22 +00:00
6 changed files with 71 additions and 20 deletions
+6 -6
View File
@@ -1,12 +1,12 @@
{
"name": "mediabunny",
"version": "1.29.0",
"version": "1.29.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mediabunny",
"version": "1.29.0",
"version": "1.29.1",
"license": "MPL-2.0",
"workspaces": [
"packages/*"
@@ -7739,9 +7739,9 @@
}
},
"node_modules/mediabunny": {
"version": "1.28.0",
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.28.0.tgz",
"integrity": "sha512-D63nzvBRIBSUsRgaIfFugWCy2iOV5T/C6nHn2fW0aWqyRuSGzWsVMXzlNi3iCKieoA/WECYJg8oVGtUukpy3XQ==",
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.29.0.tgz",
"integrity": "sha512-18B8w/rhO/ph/AFsIXvzZg8RaSQZ+ZYfJ99MZlTjDmlgCT58jV3azrnWQ/OSquYDi8q0xmn64mnfTEHgww3+zw==",
"license": "MPL-2.0",
"peer": true,
"workspaces": [
@@ -12065,7 +12065,7 @@
},
"packages/mp3-encoder": {
"name": "@mediabunny/mp3-encoder",
"version": "1.29.0",
"version": "1.29.1",
"license": "MPL-2.0",
"devDependencies": {
"@types/emscripten": "^1.40.1"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "mediabunny",
"author": "Vanilagy",
"version": "1.29.0",
"version": "1.29.1",
"description": "Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.",
"type": "module",
"workspaces": [
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@mediabunny/mp3-encoder",
"author": "Vanilagy",
"version": "1.29.0",
"version": "1.29.1",
"description": "MP3 encoder extension for Mediabunny, based on LAME.",
"main": "./dist/bundles/mediabunny-mp3-encoder.mjs",
"module": "./dist/bundles/mediabunny-mp3-encoder.mjs",
+32 -5
View File
@@ -46,6 +46,7 @@ import { DEFAULT_TRACK_DISPOSITION, MetadataTags } from '../metadata';
import {
assert,
AsyncMutex,
binarySearchExact,
binarySearchLessOrEqual,
Bitstream,
COLOR_PRIMARIES_MAP_INVERSE,
@@ -118,6 +119,7 @@ export class MpegTsDemuxer extends Demuxer {
tracks: InputTrack[] = [];
packetOffset = 0;
packetStride = -1;
sectionEndPositions: number[] = [];
constructor(input: Input) {
super(input);
@@ -157,7 +159,11 @@ export class MpegTsDemuxer extends Demuxer {
let hasProgramMap = false;
while (true) {
const section = await this.readSection(currentPos, true);
const section = await this.readSection(
currentPos,
true,
!hasProgramMap, // Expect contiguous sections as long as we don't have the PMT
);
if (!section) {
break;
}
@@ -447,13 +453,13 @@ export class MpegTsDemuxer extends Demuxer {
return buildMpegTsMimeType(codecStrings);
}
async readSection(startPos: number, full: boolean): Promise<Section | null> {
async readSection(startPos: number, full: boolean, contiguous = false): Promise<Section | null> {
let endPos = startPos;
let currentPos = startPos;
const chunks: Uint8Array[] = [];
let chunksByteLength = 0;
let firstPacket: TsPacket | null = null;
let mustAddSectionEnd = true;
while (true) {
const packet = await this.readPacket(currentPos);
@@ -471,7 +477,11 @@ export class MpegTsDemuxer extends Demuxer {
firstPacket = packet;
} else {
if (packet.pid !== firstPacket.pid) {
continue; // Ignore this packet
if (contiguous) {
break; // End of section
} else {
continue; // Ignore this packet
}
}
if (packet.payloadUnitStartIndicator === 1) {
@@ -501,8 +511,21 @@ export class MpegTsDemuxer extends Demuxer {
// 64 is just "a bit of data", enough for the PES packet header
if (!full && chunksByteLength >= 64) {
mustAddSectionEnd = false; // Not the actual section end
break;
}
// Check if we already know this is a section end
const isKnownSectionEnd = binarySearchExact(this.sectionEndPositions, endPos, x => x) !== -1;
if (isKnownSectionEnd) {
mustAddSectionEnd = false;
break;
}
}
if (mustAddSectionEnd) {
const index = binarySearchLessOrEqual(this.sectionEndPositions, endPos, x => x);
this.sectionEndPositions.splice(index + 1, 0, endPos);
}
if (!firstPacket) {
@@ -1303,6 +1326,10 @@ class MpegTsVideoTrackBacking extends MpegTsTrackBacking implements InputVideoTr
const codec = this.elementaryStream.info.codec;
const CHUNK_SIZE = 1024;
if (codec !== 'avc' && codec !== 'hevc') {
throw new Error('Unhandled.');
}
let packetStartPos: number | null = null;
while (true) {
@@ -1522,7 +1549,7 @@ class MpegTsAudioTrackBacking extends MpegTsTrackBacking implements InputAudioTr
context.seekTo(possibleHeaderStartPos + 1);
}
} else {
throw new Error('Unreachable');
throw new Error('Unhandled.');
}
}
+1 -1
View File
@@ -62,7 +62,7 @@ test('ADTS muxer with raw AAC input', async () => {
expect(count).toBe(237);
});
test('ADTS muxer with ADTS input (passthrough)', async () => {
test('ADTS muxer with ADTS input (passthrough)', { timeout: 10_000 }, async () => {
using input = new Input({
source: new FilePathSource(path.join(__dirname, '../public/sample3.aac')),
formats: ALL_FORMATS,
+30 -6
View File
@@ -1,6 +1,6 @@
import { expect, test } from 'vitest';
import { Input } from '../../src/input.js';
import { FilePathSource, ReadableStreamSource, UrlSource } from '../../src/source.js';
import { FilePathSource, ReadableStreamSource, StreamSource, UrlSource } from '../../src/source.js';
import path from 'node:path';
import fs from 'node:fs';
import { Readable } from 'node:stream';
@@ -241,11 +241,11 @@ test('MPEG-TS video seeking', async () => {
expect(allPackets).toHaveLength(298);
for (const packet of allPackets) {
const seekedPacked = await sink.getPacket(packet.timestamp);
assert(seekedPacked);
expect(seekedPacked.timestamp).toBe(packet.timestamp); // The correct timestamp was retrieved for this packet
expect(seekedPacked.duration).toBe(packet.duration); // The correct duration was retrieved for this packet
expect(seekedPacked.sequenceNumber).toBe(packet.sequenceNumber);
const seekedPacket = await sink.getPacket(packet.timestamp);
assert(seekedPacket);
expect(seekedPacket.timestamp).toBe(packet.timestamp); // The correct timestamp was retrieved for this packet
expect(seekedPacket.duration).toBe(packet.duration); // The correct duration was retrieved for this packet
expect(seekedPacket.sequenceNumber).toBe(packet.sequenceNumber);
}
});
@@ -573,3 +573,27 @@ test('MPEG-TS with MP3 audio', async () => {
expect(count).toBeGreaterThan(0);
});
test('MPEG-TS partial reading', async () => {
const fullPath = path.join(__dirname, '../public/193039199_mp4_h264_aac_fhd_7.ts');
const buffer = await fs.promises.readFile(fullPath);
let maxEnd = 0;
using input = new Input({
source: new StreamSource({
getSize: () => {
return buffer.byteLength;
},
read: (start, end) => {
maxEnd = Math.max(maxEnd, end);
return buffer.subarray(start, end);
},
}),
formats: ALL_FORMATS,
});
await input.getTracks();
// Not much of the file has been read since we only requested metadata
expect(maxEnd).toBeLessThanOrEqual(86480);
});