mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-02 21:33:52 +02:00
Skip HEVC RASL slices following a decoder reset
This commit is contained in:
+9
-1
@@ -17,7 +17,15 @@
|
|||||||
const videoTrack = await input.getPrimaryVideoTrack();
|
const videoTrack = await input.getPrimaryVideoTrack();
|
||||||
const sink = new Mediabunny.VideoSampleSink(videoTrack);
|
const sink = new Mediabunny.VideoSampleSink(videoTrack);
|
||||||
|
|
||||||
console.log(await sink.getSample(await videoTrack.getFirstTimestamp()))
|
console.log(await sink.getSample(2.131875));
|
||||||
|
|
||||||
|
/*
|
||||||
|
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
||||||
|
|
||||||
|
for await (const packet of sink.packets()) {
|
||||||
|
console.log(packet)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
for await (const sample of sink.samples(0.99)) {
|
for await (const sample of sink.samples(0.99)) {
|
||||||
|
|||||||
@@ -96,6 +96,13 @@ const generateThumbnails = async (resource: File | string) => {
|
|||||||
timestampElement.className
|
timestampElement.className
|
||||||
= 'absolute bottom-0 right-0 bg-black/30 text-white px-1 py-0.5 text-[11px] rounded-tl-lg';
|
= 'absolute bottom-0 right-0 bg-black/30 text-white px-1 py-0.5 text-[11px] rounded-tl-lg';
|
||||||
container.append(timestampElement);
|
container.append(timestampElement);
|
||||||
|
} else {
|
||||||
|
// Add something to indicate that the thumbnail is missing
|
||||||
|
const p = document.createElement('p');
|
||||||
|
p.textContent = '?';
|
||||||
|
p.className = 'absolute inset-0 flex items-center justify-center text-3xl opacity-50';
|
||||||
|
|
||||||
|
container.append(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
|||||||
Generated
+6
-6
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.14.2",
|
"version": "1.14.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mediabunny",
|
"name": "mediabunny",
|
||||||
"version": "1.14.2",
|
"version": "1.14.3",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@@ -7749,9 +7749,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mediabunny": {
|
"node_modules/mediabunny": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/mediabunny/-/mediabunny-1.14.2.tgz",
|
||||||
"integrity": "sha512-TjLg8GQGGsnGePcA6i0NItGe9a5G8WaleCGaXpb5V5okwuK5KpNKfcmTZXItnjfPLo7FvfEZI0NFp1lIR8Os7Q==",
|
"integrity": "sha512-JCup3rpsJGIw3I7E7bZSmVEANCr/OwfwkH3g/Wq1TcHEJ7ymLLw+jC3+/Nnn/JLXzFnw8/I6fV3xECLnFedfHg==",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
@@ -12242,7 +12242,7 @@
|
|||||||
},
|
},
|
||||||
"packages/mp3-encoder": {
|
"packages/mp3-encoder": {
|
||||||
"name": "@mediabunny/mp3-encoder",
|
"name": "@mediabunny/mp3-encoder",
|
||||||
"version": "1.14.2",
|
"version": "1.14.3",
|
||||||
"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.14.2",
|
"version": "1.14.3",
|
||||||
"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.14.2",
|
"version": "1.14.3",
|
||||||
"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",
|
||||||
|
|||||||
+67
-50
@@ -26,8 +26,27 @@ import { EncodedPacket, PacketType } from './packet';
|
|||||||
// Rec. ITU-T H.265
|
// Rec. ITU-T H.265
|
||||||
// https://stackoverflow.com/questions/24884827
|
// https://stackoverflow.com/questions/24884827
|
||||||
|
|
||||||
|
export enum AvcNalUnitType {
|
||||||
|
IDR = 5,
|
||||||
|
SPS = 7,
|
||||||
|
PPS = 8,
|
||||||
|
SPS_EXT = 13,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum HevcNalUnitType {
|
||||||
|
RASL_N = 8,
|
||||||
|
RASL_R = 9,
|
||||||
|
BLA_W_LP = 16,
|
||||||
|
RSV_IRAP_VCL23 = 23,
|
||||||
|
VPS_NUT = 32,
|
||||||
|
SPS_NUT = 33,
|
||||||
|
PPS_NUT = 34,
|
||||||
|
PREFIX_SEI_NUT = 39,
|
||||||
|
SUFFIX_SEI_NUT = 40,
|
||||||
|
}
|
||||||
|
|
||||||
/** Finds all NAL units in an AVC packet in Annex B format. */
|
/** Finds all NAL units in an AVC packet in Annex B format. */
|
||||||
const findNalUnitsInAnnexB = (packetData: Uint8Array) => {
|
export const findNalUnitsInAnnexB = (packetData: Uint8Array) => {
|
||||||
const nalUnits: Uint8Array[] = [];
|
const nalUnits: Uint8Array[] = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
@@ -184,6 +203,21 @@ export type AvcDecoderConfigurationRecord = {
|
|||||||
sequenceParameterSetExt: Uint8Array[] | null;
|
sequenceParameterSetExt: Uint8Array[] | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const extractAvcNalUnits = (packetData: Uint8Array, decoderConfig: VideoDecoderConfig) => {
|
||||||
|
if (decoderConfig.description) {
|
||||||
|
// Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config
|
||||||
|
|
||||||
|
const bytes = toUint8Array(decoderConfig.description);
|
||||||
|
const lengthSizeMinusOne = bytes[4]! & 0b11;
|
||||||
|
const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
|
||||||
|
|
||||||
|
return findNalUnitsInLengthPrefixed(packetData, lengthSize);
|
||||||
|
} else {
|
||||||
|
// Stream is in Annex B format
|
||||||
|
return findNalUnitsInAnnexB(packetData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const extractNalUnitTypeForAvc = (data: Uint8Array) => {
|
const extractNalUnitTypeForAvc = (data: Uint8Array) => {
|
||||||
return data[0]! & 0x1F;
|
return data[0]! & 0x1F;
|
||||||
};
|
};
|
||||||
@@ -193,9 +227,9 @@ export const extractAvcDecoderConfigurationRecord = (packetData: Uint8Array) =>
|
|||||||
try {
|
try {
|
||||||
const nalUnits = findNalUnitsInAnnexB(packetData);
|
const nalUnits = findNalUnitsInAnnexB(packetData);
|
||||||
|
|
||||||
const spsUnits = nalUnits.filter(unit => extractNalUnitTypeForAvc(unit) === 7);
|
const spsUnits = nalUnits.filter(unit => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.SPS);
|
||||||
const ppsUnits = nalUnits.filter(unit => extractNalUnitTypeForAvc(unit) === 8);
|
const ppsUnits = nalUnits.filter(unit => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.PPS);
|
||||||
const spsExtUnits = nalUnits.filter(unit => extractNalUnitTypeForAvc(unit) === 13);
|
const spsExtUnits = nalUnits.filter(unit => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.SPS_EXT);
|
||||||
|
|
||||||
if (spsUnits.length === 0) {
|
if (spsUnits.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
@@ -337,12 +371,6 @@ export const serializeAvcDecoderConfigurationRecord = (record: AvcDecoderConfigu
|
|||||||
return new Uint8Array(bytes);
|
return new Uint8Array(bytes);
|
||||||
};
|
};
|
||||||
|
|
||||||
const NALU_TYPE_VPS = 32;
|
|
||||||
const NALU_TYPE_SPS = 33;
|
|
||||||
const NALU_TYPE_PPS = 34;
|
|
||||||
const NALU_TYPE_SEI_PREFIX = 39;
|
|
||||||
const NALU_TYPE_SEI_SUFFIX = 40;
|
|
||||||
|
|
||||||
// Data specified in ISO 14496-15
|
// Data specified in ISO 14496-15
|
||||||
export type HevcDecoderConfigurationRecord = {
|
export type HevcDecoderConfigurationRecord = {
|
||||||
configurationVersion: number;
|
configurationVersion: number;
|
||||||
@@ -369,7 +397,22 @@ export type HevcDecoderConfigurationRecord = {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const extractNalUnitTypeForHevc = (data: Uint8Array) => {
|
export const extractHevcNalUnits = (packetData: Uint8Array, decoderConfig: VideoDecoderConfig) => {
|
||||||
|
if (decoderConfig.description) {
|
||||||
|
// Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config
|
||||||
|
|
||||||
|
const bytes = toUint8Array(decoderConfig.description);
|
||||||
|
const lengthSizeMinusOne = bytes[21]! & 0b11;
|
||||||
|
const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
|
||||||
|
|
||||||
|
return findNalUnitsInLengthPrefixed(packetData, lengthSize);
|
||||||
|
} else {
|
||||||
|
// Stream is in Annex B format
|
||||||
|
return findNalUnitsInAnnexB(packetData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const extractNalUnitTypeForHevc = (data: Uint8Array) => {
|
||||||
return (data[0]! >> 1) & 0x3F;
|
return (data[0]! >> 1) & 0x3F;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -380,12 +423,12 @@ export const extractHevcDecoderConfigurationRecord = (
|
|||||||
try {
|
try {
|
||||||
const nalUnits = findNalUnitsInAnnexB(packetData);
|
const nalUnits = findNalUnitsInAnnexB(packetData);
|
||||||
|
|
||||||
const vpsUnits = nalUnits.filter(unit => extractNalUnitTypeForHevc(unit) === NALU_TYPE_VPS);
|
const vpsUnits = nalUnits.filter(unit => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.VPS_NUT);
|
||||||
const spsUnits = nalUnits.filter(unit => extractNalUnitTypeForHevc(unit) === NALU_TYPE_SPS);
|
const spsUnits = nalUnits.filter(unit => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.SPS_NUT);
|
||||||
const ppsUnits = nalUnits.filter(unit => extractNalUnitTypeForHevc(unit) === NALU_TYPE_PPS);
|
const ppsUnits = nalUnits.filter(unit => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.PPS_NUT);
|
||||||
const seiUnits = nalUnits.filter(
|
const seiUnits = nalUnits.filter(
|
||||||
unit => extractNalUnitTypeForHevc(unit) === NALU_TYPE_SEI_PREFIX
|
unit => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.PREFIX_SEI_NUT
|
||||||
|| extractNalUnitTypeForHevc(unit) === NALU_TYPE_SEI_SUFFIX,
|
|| extractNalUnitTypeForHevc(unit) === HevcNalUnitType.SUFFIX_SEI_NUT,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (spsUnits.length === 0 || ppsUnits.length === 0) return null;
|
if (spsUnits.length === 0 || ppsUnits.length === 0) return null;
|
||||||
@@ -521,7 +564,7 @@ export const extractHevcDecoderConfigurationRecord = (
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
arrayCompleteness: 1,
|
arrayCompleteness: 1,
|
||||||
nalUnitType: NALU_TYPE_VPS,
|
nalUnitType: HevcNalUnitType.VPS_NUT,
|
||||||
nalUnits: vpsUnits,
|
nalUnits: vpsUnits,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -530,7 +573,7 @@ export const extractHevcDecoderConfigurationRecord = (
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
arrayCompleteness: 1,
|
arrayCompleteness: 1,
|
||||||
nalUnitType: NALU_TYPE_SPS,
|
nalUnitType: HevcNalUnitType.SPS_NUT,
|
||||||
nalUnits: spsUnits,
|
nalUnits: spsUnits,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -539,7 +582,7 @@ export const extractHevcDecoderConfigurationRecord = (
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
arrayCompleteness: 1,
|
arrayCompleteness: 1,
|
||||||
nalUnitType: NALU_TYPE_PPS,
|
nalUnitType: HevcNalUnitType.PPS_NUT,
|
||||||
nalUnits: ppsUnits,
|
nalUnits: ppsUnits,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -1440,22 +1483,9 @@ export const determineVideoPacketType = async (
|
|||||||
const decoderConfig = await videoTrack.getDecoderConfig();
|
const decoderConfig = await videoTrack.getDecoderConfig();
|
||||||
assert(decoderConfig);
|
assert(decoderConfig);
|
||||||
|
|
||||||
let nalUnits: Uint8Array[];
|
const nalUnits = extractAvcNalUnits(packet.data, decoderConfig);
|
||||||
|
const isKeyframe = nalUnits.some(x => extractNalUnitTypeForAvc(x) === AvcNalUnitType.IDR);
|
||||||
|
|
||||||
if (decoderConfig.description) {
|
|
||||||
// Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config
|
|
||||||
|
|
||||||
const bytes = toUint8Array(decoderConfig.description);
|
|
||||||
const lengthSizeMinusOne = bytes[4]! & 0b11;
|
|
||||||
const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
|
|
||||||
|
|
||||||
nalUnits = findNalUnitsInLengthPrefixed(packet.data, lengthSize);
|
|
||||||
} else {
|
|
||||||
// Stream is in Annex B format
|
|
||||||
nalUnits = findNalUnitsInAnnexB(packet.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isKeyframe = nalUnits.some(x => extractNalUnitTypeForAvc(x) === 5);
|
|
||||||
return isKeyframe ? 'key' : 'delta';
|
return isKeyframe ? 'key' : 'delta';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1463,25 +1493,12 @@ export const determineVideoPacketType = async (
|
|||||||
const decoderConfig = await videoTrack.getDecoderConfig();
|
const decoderConfig = await videoTrack.getDecoderConfig();
|
||||||
assert(decoderConfig);
|
assert(decoderConfig);
|
||||||
|
|
||||||
let nalUnits: Uint8Array[];
|
const nalUnits = extractHevcNalUnits(packet.data, decoderConfig);
|
||||||
|
|
||||||
if (decoderConfig.description) {
|
|
||||||
// Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config
|
|
||||||
|
|
||||||
const bytes = toUint8Array(decoderConfig.description);
|
|
||||||
const lengthSizeMinusOne = bytes[21]! & 0b11;
|
|
||||||
const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
|
|
||||||
|
|
||||||
nalUnits = findNalUnitsInLengthPrefixed(packet.data, lengthSize);
|
|
||||||
} else {
|
|
||||||
// Stream is in Annex B format
|
|
||||||
nalUnits = findNalUnitsInAnnexB(packet.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isKeyframe = nalUnits.some((x) => {
|
const isKeyframe = nalUnits.some((x) => {
|
||||||
const type = extractNalUnitTypeForHevc(x);
|
const type = extractNalUnitTypeForHevc(x);
|
||||||
return 16 <= type && type <= 23;
|
return HevcNalUnitType.BLA_W_LP <= type && type <= HevcNalUnitType.RSV_IRAP_VCL23;
|
||||||
});
|
});
|
||||||
|
|
||||||
return isKeyframe ? 'key' : 'delta';
|
return isKeyframe ? 'key' : 'delta';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+29
-3
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { parsePcmCodec, PCM_AUDIO_CODECS, PcmAudioCodec, VideoCodec, AudioCodec } from './codec';
|
import { parsePcmCodec, PCM_AUDIO_CODECS, PcmAudioCodec, VideoCodec, AudioCodec } from './codec';
|
||||||
|
import { extractHevcNalUnits, extractNalUnitTypeForHevc, HevcNalUnitType } from './codec-data';
|
||||||
import { CustomVideoDecoder, customVideoDecoders, CustomAudioDecoder, customAudioDecoders } from './custom-coder';
|
import { CustomVideoDecoder, customVideoDecoders, CustomAudioDecoder, customAudioDecoders } from './custom-coder';
|
||||||
import { InputAudioTrack, InputTrack, InputVideoTrack } from './input-track';
|
import { InputAudioTrack, InputTrack, InputVideoTrack } from './input-track';
|
||||||
import {
|
import {
|
||||||
@@ -624,8 +625,8 @@ export abstract class BaseMediaSampleSink<
|
|||||||
const nextPacket = await packetSink.getNextPacket(currentPacket);
|
const nextPacket = await packetSink.getNextPacket(currentPacket);
|
||||||
assert(nextPacket);
|
assert(nextPacket);
|
||||||
|
|
||||||
currentPacket = nextPacket;
|
|
||||||
decoder.decode(nextPacket);
|
decoder.decode(nextPacket);
|
||||||
|
currentPacket = nextPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
maxSequenceNumber = -1;
|
maxSequenceNumber = -1;
|
||||||
@@ -757,12 +758,14 @@ class VideoDecoderWrapper extends DecoderWrapper<VideoSample> {
|
|||||||
|
|
||||||
inputTimestamps: number[] = []; // Timestamps input into the decoder, sorted.
|
inputTimestamps: number[] = []; // Timestamps input into the decoder, sorted.
|
||||||
sampleQueue: VideoSample[] = []; // Safari-specific thing, check usage.
|
sampleQueue: VideoSample[] = []; // Safari-specific thing, check usage.
|
||||||
|
currentPacketIndex = 0;
|
||||||
|
raslSkipped = false; // For HEVC stuff
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
onSample: (sample: VideoSample) => unknown,
|
onSample: (sample: VideoSample) => unknown,
|
||||||
onError: (error: DOMException) => unknown,
|
onError: (error: DOMException) => unknown,
|
||||||
codec: VideoCodec,
|
public codec: VideoCodec,
|
||||||
decoderConfig: VideoDecoderConfig,
|
public decoderConfig: VideoDecoderConfig,
|
||||||
public rotation: Rotation,
|
public rotation: Rotation,
|
||||||
public timeResolution: number,
|
public timeResolution: number,
|
||||||
) {
|
) {
|
||||||
@@ -848,6 +851,26 @@ class VideoDecoderWrapper extends DecoderWrapper<VideoSample> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
decode(packet: EncodedPacket) {
|
decode(packet: EncodedPacket) {
|
||||||
|
if (this.codec === 'hevc' && this.currentPacketIndex > 0 && !this.raslSkipped) {
|
||||||
|
// If we're using HEVC, we need to make sure to skip any RASL slices that follow a non-IDR key frame such as
|
||||||
|
// CRA_NUT. This is because RASL slices cannot be decoded without data before the CRA_NUT. Browsers behave
|
||||||
|
// differently here: Chromium drops the packets, Safari throws a decoder error. Either way, it's not good
|
||||||
|
// and causes bugs upstream. So, let's take the dropping into our own hands.
|
||||||
|
const nalUnits = extractHevcNalUnits(packet.data, this.decoderConfig);
|
||||||
|
const hasRaslPicture = nalUnits.some((x) => {
|
||||||
|
const type = extractNalUnitTypeForHevc(x);
|
||||||
|
return type === HevcNalUnitType.RASL_N || type === HevcNalUnitType.RASL_R;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasRaslPicture) {
|
||||||
|
return; // Drop
|
||||||
|
}
|
||||||
|
|
||||||
|
this.raslSkipped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentPacketIndex++;
|
||||||
|
|
||||||
if (this.customDecoder) {
|
if (this.customDecoder) {
|
||||||
this.customDecoderQueueSize++;
|
this.customDecoderQueueSize++;
|
||||||
void this.customDecoderCallSerializer
|
void this.customDecoderCallSerializer
|
||||||
@@ -879,6 +902,9 @@ class VideoDecoderWrapper extends DecoderWrapper<VideoSample> {
|
|||||||
|
|
||||||
this.sampleQueue.length = 0;
|
this.sampleQueue.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.currentPacketIndex = 0;
|
||||||
|
this.raslSkipped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
|||||||
Reference in New Issue
Block a user