Support AVC3 in ISOBMFF (fixes #216)

This commit is contained in:
Vanilagy
2025-11-11 16:55:54 +01:00
parent 71dd2c565b
commit 5b45c51d40
3 changed files with 10 additions and 3 deletions
+5 -2
View File
@@ -337,6 +337,7 @@ export const extractVideoCodecString = (trackInfo: {
codec: VideoCodec | null; codec: VideoCodec | null;
codecDescription: Uint8Array | null; codecDescription: Uint8Array | null;
colorSpace: VideoColorSpaceInit | null; colorSpace: VideoColorSpaceInit | null;
avcType: 1 | 3 | null;
avcCodecInfo: AvcDecoderConfigurationRecord | null; avcCodecInfo: AvcDecoderConfigurationRecord | null;
hevcCodecInfo: HevcDecoderConfigurationRecord | null; hevcCodecInfo: HevcDecoderConfigurationRecord | null;
vp9CodecInfo: Vp9CodecInfo | null; vp9CodecInfo: Vp9CodecInfo | null;
@@ -345,6 +346,8 @@ export const extractVideoCodecString = (trackInfo: {
const { codec, codecDescription, colorSpace, avcCodecInfo, hevcCodecInfo, vp9CodecInfo, av1CodecInfo } = trackInfo; const { codec, codecDescription, colorSpace, avcCodecInfo, hevcCodecInfo, vp9CodecInfo, av1CodecInfo } = trackInfo;
if (codec === 'avc') { if (codec === 'avc') {
assert(trackInfo.avcType !== null);
if (avcCodecInfo) { if (avcCodecInfo) {
const bytes = new Uint8Array([ const bytes = new Uint8Array([
avcCodecInfo.avcProfileIndication, avcCodecInfo.avcProfileIndication,
@@ -352,14 +355,14 @@ export const extractVideoCodecString = (trackInfo: {
avcCodecInfo.avcLevelIndication, avcCodecInfo.avcLevelIndication,
]); ]);
return `avc1.${bytesToHexString(bytes)}`; return `avc${trackInfo.avcType}.${bytesToHexString(bytes)}`;
} }
if (!codecDescription || codecDescription.byteLength < 4) { if (!codecDescription || codecDescription.byteLength < 4) {
throw new TypeError('AVC decoder description is not provided or is not at least 4 bytes long.'); throw new TypeError('AVC decoder description is not provided or is not at least 4 bytes long.');
} }
return `avc1.${bytesToHexString(codecDescription.subarray(1, 4))}`; return `avc${trackInfo.avcType}.${bytesToHexString(codecDescription.subarray(1, 4))}`;
} else if (codec === 'hevc') { } else if (codec === 'hevc') {
let generalProfileSpace: number; let generalProfileSpace: number;
let generalProfileIdc: number; let generalProfileIdc: number;
+4 -1
View File
@@ -126,6 +126,7 @@ type InternalTrack = {
codec: VideoCodec | null; codec: VideoCodec | null;
codecDescription: Uint8Array | null; codecDescription: Uint8Array | null;
colorSpace: VideoColorSpaceInit | null; colorSpace: VideoColorSpaceInit | null;
avcType: 1 | 3 | null;
avcCodecInfo: AvcDecoderConfigurationRecord | null; avcCodecInfo: AvcDecoderConfigurationRecord | null;
hevcCodecInfo: HevcDecoderConfigurationRecord | null; hevcCodecInfo: HevcDecoderConfigurationRecord | null;
vp9CodecInfo: Vp9CodecInfo | null; vp9CodecInfo: Vp9CodecInfo | null;
@@ -836,6 +837,7 @@ export class IsobmffDemuxer extends Demuxer {
codec: null, codec: null,
codecDescription: null, codecDescription: null,
colorSpace: null, colorSpace: null,
avcType: null,
avcCodecInfo: null, avcCodecInfo: null,
hevcCodecInfo: null, hevcCodecInfo: null,
vp9CodecInfo: null, vp9CodecInfo: null,
@@ -890,8 +892,9 @@ export class IsobmffDemuxer extends Demuxer {
const lowercaseBoxName = sampleBoxInfo.name.toLowerCase(); const lowercaseBoxName = sampleBoxInfo.name.toLowerCase();
if (track.info.type === 'video') { if (track.info.type === 'video') {
if (lowercaseBoxName === 'avc1') { if (lowercaseBoxName === 'avc1' || lowercaseBoxName === 'avc3') {
track.info.codec = 'avc'; track.info.codec = 'avc';
track.info.avcType = lowercaseBoxName === 'avc1' ? 1 : 3;
} else if (lowercaseBoxName === 'hvc1' || lowercaseBoxName === 'hev1') { } else if (lowercaseBoxName === 'hvc1' || lowercaseBoxName === 'hev1') {
track.info.codec = 'hevc'; track.info.codec = 'hevc';
} else if (lowercaseBoxName === 'vp08') { } else if (lowercaseBoxName === 'vp08') {
+1
View File
@@ -2319,6 +2319,7 @@ class MatroskaVideoTrackBacking extends MatroskaTrackBacking implements InputVid
codec: this.internalTrack.info.codec, codec: this.internalTrack.info.codec,
codecDescription: this.internalTrack.info.codecDescription, codecDescription: this.internalTrack.info.codecDescription,
colorSpace: this.internalTrack.info.colorSpace, colorSpace: this.internalTrack.info.colorSpace,
avcType: 1, // We don't know better (or do we?) so just assume 'avc1'
avcCodecInfo: this.internalTrack.info.codec === 'avc' && firstPacket avcCodecInfo: this.internalTrack.info.codec === 'avc' && firstPacket
? extractAvcDecoderConfigurationRecord(firstPacket.data) ? extractAvcDecoderConfigurationRecord(firstPacket.data)
: null, : null,