mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-10 09:13:47 +02:00
Fix MPEG-TS demuxer reading entire file in the metadata phase, optimize it a bit, bump patch
This commit is contained in:
Generated
+6
-6
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.29.0",
|
"version": "1.29.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.29.0",
|
"version": "1.29.1",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@@ -7739,9 +7739,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mediabunny": {
|
"node_modules/mediabunny": {
|
||||||
"version": "1.28.0",
|
"version": "1.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.29.0.tgz",
|
||||||
"integrity": "sha512-D63nzvBRIBSUsRgaIfFugWCy2iOV5T/C6nHn2fW0aWqyRuSGzWsVMXzlNi3iCKieoA/WECYJg8oVGtUukpy3XQ==",
|
"integrity": "sha512-18B8w/rhO/ph/AFsIXvzZg8RaSQZ+ZYfJ99MZlTjDmlgCT58jV3azrnWQ/OSquYDi8q0xmn64mnfTEHgww3+zw==",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
@@ -12065,7 +12065,7 @@
|
|||||||
},
|
},
|
||||||
"packages/mp3-encoder": {
|
"packages/mp3-encoder": {
|
||||||
"name": "@mediabunny/mp3-encoder",
|
"name": "@mediabunny/mp3-encoder",
|
||||||
"version": "1.29.0",
|
"version": "1.29.1",
|
||||||
"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.29.0",
|
"version": "1.29.1",
|
||||||
"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.29.0",
|
"version": "1.29.1",
|
||||||
"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",
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import { DEFAULT_TRACK_DISPOSITION, MetadataTags } from '../metadata';
|
|||||||
import {
|
import {
|
||||||
assert,
|
assert,
|
||||||
AsyncMutex,
|
AsyncMutex,
|
||||||
|
binarySearchExact,
|
||||||
binarySearchLessOrEqual,
|
binarySearchLessOrEqual,
|
||||||
Bitstream,
|
Bitstream,
|
||||||
COLOR_PRIMARIES_MAP_INVERSE,
|
COLOR_PRIMARIES_MAP_INVERSE,
|
||||||
@@ -118,6 +119,7 @@ export class MpegTsDemuxer extends Demuxer {
|
|||||||
tracks: InputTrack[] = [];
|
tracks: InputTrack[] = [];
|
||||||
packetOffset = 0;
|
packetOffset = 0;
|
||||||
packetStride = -1;
|
packetStride = -1;
|
||||||
|
sectionEndPositions: number[] = [];
|
||||||
|
|
||||||
constructor(input: Input) {
|
constructor(input: Input) {
|
||||||
super(input);
|
super(input);
|
||||||
@@ -157,7 +159,11 @@ export class MpegTsDemuxer extends Demuxer {
|
|||||||
let hasProgramMap = false;
|
let hasProgramMap = false;
|
||||||
|
|
||||||
while (true) {
|
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) {
|
if (!section) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -447,13 +453,13 @@ export class MpegTsDemuxer extends Demuxer {
|
|||||||
return buildMpegTsMimeType(codecStrings);
|
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 endPos = startPos;
|
||||||
let currentPos = startPos;
|
let currentPos = startPos;
|
||||||
const chunks: Uint8Array[] = [];
|
const chunks: Uint8Array[] = [];
|
||||||
let chunksByteLength = 0;
|
let chunksByteLength = 0;
|
||||||
|
|
||||||
let firstPacket: TsPacket | null = null;
|
let firstPacket: TsPacket | null = null;
|
||||||
|
let mustAddSectionEnd = true;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const packet = await this.readPacket(currentPos);
|
const packet = await this.readPacket(currentPos);
|
||||||
@@ -471,7 +477,11 @@ export class MpegTsDemuxer extends Demuxer {
|
|||||||
firstPacket = packet;
|
firstPacket = packet;
|
||||||
} else {
|
} else {
|
||||||
if (packet.pid !== firstPacket.pid) {
|
if (packet.pid !== firstPacket.pid) {
|
||||||
continue; // Ignore this packet
|
if (contiguous) {
|
||||||
|
break; // End of section
|
||||||
|
} else {
|
||||||
|
continue; // Ignore this packet
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet.payloadUnitStartIndicator === 1) {
|
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
|
// 64 is just "a bit of data", enough for the PES packet header
|
||||||
if (!full && chunksByteLength >= 64) {
|
if (!full && chunksByteLength >= 64) {
|
||||||
|
mustAddSectionEnd = false; // Not the actual section end
|
||||||
break;
|
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) {
|
if (!firstPacket) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { expect, test } from 'vitest';
|
import { expect, test } from 'vitest';
|
||||||
import { Input } from '../../src/input.js';
|
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 path from 'node:path';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { Readable } from 'node:stream';
|
import { Readable } from 'node:stream';
|
||||||
@@ -241,11 +241,11 @@ test('MPEG-TS video seeking', async () => {
|
|||||||
expect(allPackets).toHaveLength(298);
|
expect(allPackets).toHaveLength(298);
|
||||||
|
|
||||||
for (const packet of allPackets) {
|
for (const packet of allPackets) {
|
||||||
const seekedPacked = await sink.getPacket(packet.timestamp);
|
const seekedPacket = await sink.getPacket(packet.timestamp);
|
||||||
assert(seekedPacked);
|
assert(seekedPacket);
|
||||||
expect(seekedPacked.timestamp).toBe(packet.timestamp); // The correct timestamp was retrieved for this packet
|
expect(seekedPacket.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(seekedPacket.duration).toBe(packet.duration); // The correct duration was retrieved for this packet
|
||||||
expect(seekedPacked.sequenceNumber).toBe(packet.sequenceNumber);
|
expect(seekedPacket.sequenceNumber).toBe(packet.sequenceNumber);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -573,3 +573,27 @@ test('MPEG-TS with MP3 audio', async () => {
|
|||||||
|
|
||||||
expect(count).toBeGreaterThan(0);
|
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);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user