UNPKG

shaka-player

Version:
249 lines (227 loc) • 6.98 kB
/*! @license * Shaka Player * Copyright 2016 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.codec.VP9'); /** * VP9 utils. * * @see https://www.webmproject.org/vp9/ * @see https://www.webmproject.org/vp9/mp4/ */ shaka.codec.VP9 = class { /** * Reads what the codec string of a stream needs from a key frame, for the * containers that do not carry it apart from the frames. * * @param {!Uint8Array} frame A VP9 frame; only key frames are usable. * @return {?{profile: number, bitDepth: number, chroma: number, * width: number, height: number}} * @see https://www.webmproject.org/vp9/ (uncompressed_header) */ static parseKeyFrame(frame) { const VP9 = shaka.codec.VP9; if (frame.length < VP9.MIN_KEYFRAME_SIZE_) { return null; } let bit = 0; const read = (count) => { let value = 0; for (let i = 0; i < count; i++) { const byte = frame[bit >> 3]; value = (value << 1) | ((byte >> (7 - (bit & 7))) & 1); bit++; } return value; }; if (read(2) != VP9.FRAME_MARKER_) { return null; } const profileLow = read(1); const profileHigh = read(1); const profile = (profileHigh << 1) + profileLow; if (profile == VP9.PROFILE_WITH_RESERVED_BIT_) { read(1); } const showExistingFrame = read(1); if (showExistingFrame) { return null; } const frameType = read(1); // show_frame and error_resilient_mode. read(2); if (frameType != VP9.KEY_FRAME_) { return null; } if (read(24) != VP9.SYNC_CODE_) { return null; } let bitDepth = 8; if (profile >= 2) { bitDepth = read(1) ? 12 : 10; } const colorSpace = read(3); let subsamplingX = 1; let subsamplingY = 1; if (colorSpace != VP9.COLOR_SPACE_RGB_) { // color_range. read(1); if (profile == 1 || profile == 3) { subsamplingX = read(1); subsamplingY = read(1); // reserved_zero. read(1); } } else if (profile == 1 || profile == 3) { subsamplingX = 0; subsamplingY = 0; } const width = read(16) + 1; const height = read(16) + 1; let chroma = VP9.CHROMA_420_COLOCATED; if (subsamplingX && !subsamplingY) { chroma = VP9.CHROMA_422; } else if (!subsamplingX && !subsamplingY) { chroma = VP9.CHROMA_444; } return {profile, bitDepth, chroma, width, height}; } /** * Builds the codec string of a VP9 stream. * * @param {{profile: number, bitDepth: number, chroma: number}} info * @param {number} width * @param {number} height * @param {?number} frameDuration Seconds per frame, if known. * @return {string} */ static getCodecs(info, width, height, frameDuration) { const VP9 = shaka.codec.VP9; const pad = (value) => String(value).padStart(2, '0'); const level = VP9.getLevel_(width, height, frameDuration); return 'vp09.' + pad(info.profile) + '.' + pad(level) + '.' + pad(info.bitDepth) + '.' + pad(info.chroma); } /** * Builds the payload of the vpcC box (VP Codec Configuration) from a VP9 * codec string. * * @param {string} codecs 'vp09.PP.LL.DD', optionally followed by * '.CC.cp.tc.mc.FF'. * @return {!Uint8Array} * @see https://www.webmproject.org/vp9/mp4/#vp-codec-configuration-box */ static buildVpcC(codecs) { const VP9 = shaka.codec.VP9; // Skip the 'vp09' sample entry name and read the numeric fields. const fields = codecs.split('.').slice(1).map((value) => { return parseInt(value, 10); }); const [profile = 0, level = 0, bitDepth = 8, chroma = VP9.CHROMA_420_COLOCATED, primaries = VP9.UNSPECIFIED_, transfer = VP9.UNSPECIFIED_, matrix = VP9.UNSPECIFIED_, fullRange = 0] = fields; return new Uint8Array([ // A full box: version 1, no flags. 1, 0, 0, 0, profile, level, (bitDepth << 4) | (chroma << 1) | fullRange, primaries, transfer, matrix, // codecInitializationDataSize (2 bytes): VP9 has none. 0, 0, ]); } /** * Picks the lowest VP9 level whose limits hold the picture size and the * sample rate. * * @param {number} width * @param {number} height * @param {?number} frameDuration * @return {number} * @private */ static getLevel_(width, height, frameDuration) { const VP9 = shaka.codec.VP9; const pictureSize = width * height; const frameRate = frameDuration ? 1 / frameDuration : VP9.DEFAULT_FRAME_RATE_; const sampleRate = pictureSize * frameRate; for (const [level, maxSampleRate, maxPictureSize] of VP9.LEVELS_) { if (pictureSize <= maxPictureSize && sampleRate <= maxSampleRate) { return level; } } return VP9.LEVELS_[VP9.LEVELS_.length - 1][0]; } }; /** * Values of the chroma subsampling field of the VP9 codec string. * @const {number} */ shaka.codec.VP9.CHROMA_420_COLOCATED = 1; /** @const {number} */ shaka.codec.VP9.CHROMA_422 = 2; /** @const {number} */ shaka.codec.VP9.CHROMA_444 = 3; /** * The value of the color primaries, transfer and matrix fields when the stream * does not say (H.273 "unspecified"). * @private @const {number} */ shaka.codec.VP9.UNSPECIFIED_ = 2; /** * Frame rate assumed to pick a level when the stream does not say. * @private @const {number} */ shaka.codec.VP9.DEFAULT_FRAME_RATE_ = 30; /** * Fields of the uncompressed header of a VP9 frame: the marker every frame * starts with, the profile whose header has one reserved bit, the value of * frame_type for a key frame, the sync code of key frames and RGB's color * space. * @private @const {number} */ shaka.codec.VP9.FRAME_MARKER_ = 2; /** @private @const {number} */ shaka.codec.VP9.PROFILE_WITH_RESERVED_BIT_ = 3; /** @private @const {number} */ shaka.codec.VP9.KEY_FRAME_ = 0; /** @private @const {number} */ shaka.codec.VP9.SYNC_CODE_ = 0x498342; /** @private @const {number} */ shaka.codec.VP9.COLOR_SPACE_RGB_ = 7; /** * The bytes needed to read the uncompressed header of a key frame up to the * frame size: marker, profile and flags, sync code, color config and size. * @private @const {number} */ shaka.codec.VP9.MIN_KEYFRAME_SIZE_ = 12; /** * VP9 levels: [level, MaxLumaSampleRate, MaxLumaPictureSize], from Annex A of * the VP9 bitstream specification. Levels 4/4.1 and 5/5.1/5.2 differ only in * the bitrate and the sample rate limits. * @private @const {!Array<!Array<number>>} */ shaka.codec.VP9.LEVELS_ = [ [10, 829440, 36864], [11, 2764800, 73728], [20, 4608000, 122880], [21, 9216000, 245760], [30, 20736000, 552960], [31, 36864000, 983040], [40, 83558400, 2228224], [41, 160432128, 2228224], [50, 311951360, 8912896], [51, 588251136, 8912896], [52, 1176502272, 8912896], [60, 1176502272, 35651584], [61, 2353004544, 35651584], [62, 4706009088, 35651584], ];