Fix AVC software decoder sometimes dropping B-frames (fixes #488)

This commit is contained in:
Vanilagy
2026-09-09 16:55:06 +02:00
parent 4b140fe46c
commit f767b6f601
9 changed files with 276 additions and 19 deletions
+64 -2
View File
@@ -1,9 +1,13 @@
import { expect, test } from 'vitest';
import { Input } from '../../src/input.js';
import { UrlSource } from '../../src/source.js';
import { BufferSource, UrlSource } from '../../src/source.js';
import { ALL_FORMATS } from '../../src/input-format.js';
import { assert } from '../../src/misc.js';
import { AudioSampleSink } from '../../src/media-sink.js';
import { AudioSampleSink, VideoSampleSink } from '../../src/media-sink.js';
import { Output } from '../../src/output.js';
import { MpegTsOutputFormat } from '../../src/output-format.js';
import { BufferTarget } from '../../src/target.js';
import { Conversion } from '../../src/conversion.js';
// https://github.com/Vanilagy/mediabunny/issues/370
test('Negative audio timestamps are preserved', async () => {
@@ -24,3 +28,61 @@ test('Negative audio timestamps are preserved', async () => {
break;
}
});
test('No B-frames are skipped when software-decoding AVC', async () => {
using input = new Input({
source: new UrlSource('/missing-reorder-metadata-v1.mp4'),
formats: ALL_FORMATS,
});
const track = await input.getPrimaryVideoTrack();
assert(track);
const sink = new VideoSampleSink(track, {
hardwareAcceleration: 'prefer-software',
});
let count = 0;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for await (using sample of sink.samples()) {
count++;
}
expect(count).toBe(48);
});
test('No B-frames are skipped when software-decoding AVC, Annex B edition', async () => {
using input = new Input({
source: new UrlSource('/missing-reorder-metadata-v1.mp4'),
formats: ALL_FORMATS,
});
// Force Annex B by converting to MPEG-TS
const output = new Output({
format: new MpegTsOutputFormat(),
target: new BufferTarget(),
});
const conversion = await Conversion.init({ input, output, copy: { mode: 'forced' } });
await conversion.execute();
using newInput = new Input({
source: new BufferSource(output.target.buffer!),
formats: ALL_FORMATS,
});
const track = await newInput.getPrimaryVideoTrack();
assert(track);
const sink = new VideoSampleSink(track, {
hardwareAcceleration: 'prefer-software',
});
let count = 0;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for await (using sample of sink.samples()) {
count++;
}
expect(count).toBe(48);
});