mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 05:43:50 +02:00
Refine av1C box data
This commit is contained in:
@@ -29,7 +29,6 @@
|
||||
output.start();
|
||||
|
||||
for await (const frame of drain.frames(0, 10)) {
|
||||
console.log(frame.timestamp, frame.duration)
|
||||
await mediaSource.digest(frame);
|
||||
frame.close();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ const input = new Metamuxer.Input({
|
||||
source
|
||||
});
|
||||
|
||||
console.log(await input.getMimeType())
|
||||
|
||||
const videoTrack = await input.getPrimaryVideoTrack();
|
||||
const audioTrack = await input.getPrimaryAudioTrack();
|
||||
|
||||
|
||||
+2
-49
@@ -168,7 +168,7 @@ export const buildVideoCodecString = (codec: VideoCodec, width: number, height:
|
||||
|
||||
return `vp09.${profile}.${levelInfo.level.toString().padStart(2, '0')}.${bitDepth}`;
|
||||
} else if (codec === 'av1') {
|
||||
const profile = 0; // Main Profile
|
||||
const profile = 0; // Main Profile, single digit
|
||||
|
||||
const pictureSize = width * height;
|
||||
const levelInfo = AV1_LEVEL_TABLE.find(
|
||||
@@ -273,59 +273,12 @@ export const extractVideoCodecString = (trackInfo: {
|
||||
throw new Error('Missing AV1 codec info - unable to construct codec string.');
|
||||
}
|
||||
|
||||
const profile = av1CodecInfo.seqProfile;
|
||||
const profile = av1CodecInfo.seqProfile; // Single digit
|
||||
const level = av1CodecInfo.seqLevelIdx0.toString().padStart(2, '0');
|
||||
const tier = av1CodecInfo.seqTier0 ? 'H' : 'M';
|
||||
const bitDepth = av1CodecInfo.bitDepth.toString().padStart(2, '0');
|
||||
|
||||
return `av01.${profile}.${level}${tier}.${bitDepth}`;
|
||||
|
||||
/*
|
||||
const chunk = await videoTrack._backing.getFirstChunk({});
|
||||
if (!chunk) {
|
||||
throw new Error('ahh');
|
||||
}
|
||||
|
||||
const buffer = new ArrayBuffer(chunk.byteLength);
|
||||
chunk.copyTo(buffer);
|
||||
|
||||
console.log(new Uint8Array(buffer));
|
||||
|
||||
const view = new DataView(buffer);
|
||||
let pos = 0;
|
||||
const byte = view.getUint8(pos++);
|
||||
|
||||
const obuType = (byte & 0b1111000) >> 3;
|
||||
const obuExtensionFlag = (byte & 0b100) >> 2;
|
||||
const obuHasSizeField = (byte & 0b10) >> 1;
|
||||
|
||||
if (obuExtensionFlag) {
|
||||
pos++;
|
||||
}
|
||||
|
||||
function leb128() {
|
||||
let value = 0;
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const leb128_byte = view.getUint8(pos);
|
||||
value |= (leb128_byte & 0x7f) << (i * 7); // Extract the lower 7 bits and shift them accordingly
|
||||
pos++;
|
||||
|
||||
// Check if the most significant bit (MSB) is 0, signaling the end of the LEB128 sequence
|
||||
if ((leb128_byte & 0x80) === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
if (obuHasSizeField) {
|
||||
console.log(leb128());
|
||||
}
|
||||
|
||||
// Some extra stuff, todo
|
||||
*/
|
||||
}
|
||||
|
||||
throw new TypeError(`Unhandled codec '${codec}'.`);
|
||||
|
||||
@@ -596,7 +596,7 @@ export const vpcC = (trackData: IsobmffVideoTrackData) => {
|
||||
const decoderConfig = trackData.info.decoderConfig;
|
||||
assert(decoderConfig.colorSpace); // This is guaranteed by an earlier validation step
|
||||
|
||||
const parts = decoderConfig.codec.split('.');
|
||||
const parts = decoderConfig.codec.split('.'); // We can derive the required values from the codec string
|
||||
const profile = Number(parts[1]);
|
||||
const level = Number(parts[2]);
|
||||
|
||||
@@ -604,10 +604,15 @@ export const vpcC = (trackData: IsobmffVideoTrackData) => {
|
||||
const chromaSubsampling = 0;
|
||||
const thirdByte = (bitDepth << 4) + (chromaSubsampling << 1) + Number(decoderConfig.colorSpace.fullRange);
|
||||
|
||||
// Set all to undetermined. We could determine them using the codec color space info, but there's no need.
|
||||
const colourPrimaries = 2;
|
||||
const transferCharacteristics = 2;
|
||||
const matrixCoefficients = 2;
|
||||
const colourPrimaries = decoderConfig.colorSpace.primaries
|
||||
? COLOR_PRIMARIES_MAP[decoderConfig.colorSpace.primaries]
|
||||
: 2; // Default to undetermined
|
||||
const transferCharacteristics = decoderConfig.colorSpace.transfer
|
||||
? TRANSFER_CHARACTERISTICS_MAP[decoderConfig.colorSpace.transfer]
|
||||
: 2;
|
||||
const matrixCoefficients = decoderConfig.colorSpace.matrix
|
||||
? MATRIX_COEFFICIENTS_MAP[decoderConfig.colorSpace.matrix]
|
||||
: 2;
|
||||
|
||||
return fullBox('vpcC', 1, 0, [
|
||||
u8(profile), // Profile
|
||||
@@ -621,21 +626,45 @@ export const vpcC = (trackData: IsobmffVideoTrackData) => {
|
||||
};
|
||||
|
||||
/** AV1 Configuration Box: Provides additional information to the decoder. */
|
||||
export const av1C = () => {
|
||||
export const av1C = (trackData: IsobmffVideoTrackData) => {
|
||||
// Reference: https://aomediacodec.github.io/av1-isobmff/
|
||||
|
||||
const decoderConfig = trackData.info.decoderConfig;
|
||||
const parts = decoderConfig.codec.split('.'); // We can derive the required values from the codec string
|
||||
|
||||
const marker = 1;
|
||||
const version = 1;
|
||||
const firstByte = (marker << 7) + version;
|
||||
|
||||
// The box contents are not correct like this, but its length is. Getting the values for the last three bytes
|
||||
// requires peeking into the bitstream of the coded chunks. Might come back later.
|
||||
// TODO
|
||||
const profile = Number(parts[1]);
|
||||
const levelAndTier = parts[2]!;
|
||||
const level = Number(levelAndTier.slice(0, -1));
|
||||
const tier = levelAndTier.slice(-1) === 'H' ? 1 : 0;
|
||||
const bitDepth = Number(parts[3]);
|
||||
const secondByte = (profile << 5) + level;
|
||||
|
||||
// The following values are educated, very likely guesses (typical 4:2:0 chroma subsampling)
|
||||
const twelveBit = 0;
|
||||
const monochrome = 0;
|
||||
const chromaSubsamplingX = 1;
|
||||
const chromaSubsamplingY = 1;
|
||||
const chromaSamplePosition = 1; // CSP_VERTICAL
|
||||
const thirdByte = (tier << 7)
|
||||
+ ((bitDepth === 8 ? 0 : 1) << 6)
|
||||
+ (twelveBit << 5)
|
||||
+ (monochrome << 4)
|
||||
+ (chromaSubsamplingX << 3)
|
||||
+ (chromaSubsamplingY << 2)
|
||||
+ chromaSamplePosition;
|
||||
|
||||
const initialPresentationDelayPresent = 0; // Should be fine
|
||||
const fourthByte = initialPresentationDelayPresent;
|
||||
|
||||
return box('av1C', [
|
||||
firstByte,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
secondByte,
|
||||
thirdByte,
|
||||
fourthByte,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user