consortium
Version:
Remote control and session sharing CLI for AI coding agents
2,804 lines • 89.7 kB
JavaScript
'use strict';
var string = require('./string-CdxeepiN.cjs');
var structDeserialize = require('./struct-deserialize-BJQW83nw.cjs');
var consumable = require('./consumable-jpudCE9S.cjs');
class ScrcpyAudioCodec {
static Opus = /* @__PURE__ */ new ScrcpyAudioCodec("opus", 1869641075, "audio/opus", "opus");
static Aac = /* @__PURE__ */ new ScrcpyAudioCodec("aac", 6381923, "audio/aac", "mp4a.66");
static Flac = /* @__PURE__ */ new ScrcpyAudioCodec("flac", 1718378851, "audio/flac", "flac");
static Raw = /* @__PURE__ */ new ScrcpyAudioCodec("raw", 7496055, "audio/raw", "");
optionValue;
metadataValue;
mimeType;
webCodecId;
constructor(optionValue, metadataValue, mimeType, webCodecId) {
this.optionValue = optionValue;
this.metadataValue = metadataValue;
this.mimeType = mimeType;
this.webCodecId = webCodecId;
}
toOptionValue() {
return this.optionValue;
}
}
const ScrcpyControlMessageType = {
InjectKeyCode: 0,
InjectText: 1,
InjectTouch: 2,
InjectScroll: 3,
BackOrScreenOn: 4,
ExpandNotificationPanel: 5,
ExpandSettingPanel: 6,
CollapseNotificationPanel: 7,
GetClipboard: 8,
SetClipboard: 9,
SetDisplayPower: 10,
RotateDevice: 11,
UHidCreate: 12,
UHidInput: 13,
UHidDestroy: 14,
StartApp: 16,
ResetVideo: 17
};
class ScrcpyDeviceMessageParsers {
#parsers = [];
get parsers() {
return this.#parsers;
}
#add(id, parser) {
if (this.#parsers[id]) {
throw new Error(`Duplicate parser for id ${id}`);
}
this.#parsers[id] = parser;
}
add(parser) {
if (Array.isArray(parser.id)) {
for (const id of parser.id) {
this.#add(id, parser);
}
} else {
this.#add(parser.id, parser);
}
return parser;
}
async parse(id, stream) {
const parser = this.#parsers[id];
if (!parser) {
throw new Error(`Unknown device message id ${id}`);
}
return parser.parse(id, stream);
}
close() {
for (const parser of this.#parsers) {
parser.close();
}
}
error(e) {
for (const parser of this.#parsers) {
parser.error(e);
}
}
}
function isScrcpyOptionValue(value) {
return typeof value === "object" && value !== null && "toOptionValue" in value && typeof value.toOptionValue === "function";
}
function toScrcpyOptionValue(value, empty) {
if (isScrcpyOptionValue(value)) {
value = value.toOptionValue();
}
if (value === void 0) {
return empty;
}
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
throw new TypeError(`Invalid option value: ${JSON.stringify(value)}`);
}
return value.toString();
}
const ScrcpyVideoCodecId = {
H264: 1748121140,
H265: 1748121141,
AV1: 6387249
};
// @__NO_SIDE_EFFECTS__
function getInt16(buffer, offset, littleEndian) {
return littleEndian ? (buffer[offset] | buffer[offset + 1] << 8) << 16 >> 16 : (buffer[offset] << 8 | buffer[offset + 1]) << 16 >> 16;
}
function setInt16(buffer, offset, value, littleEndian) {
if (littleEndian) {
buffer[offset] = value;
buffer[offset + 1] = value >> 8;
} else {
buffer[offset] = value >> 8;
buffer[offset + 1] = value;
}
}
const EmptyControlMessage = structDeserialize.struct({ type: string.u8 }, { littleEndian: false });
const ScrcpyInjectKeyCodeControlMessage = /* @__PURE__ */ (() => structDeserialize.struct({
type: string.u8(ScrcpyControlMessageType.InjectKeyCode),
action: string.u8(),
keyCode: string.u32(),
repeat: string.u32,
metaState: string.u32()
}, { littleEndian: false }))();
const ScrcpyInjectTextControlMessage = structDeserialize.struct({ type: string.u8, text: string.string(string.u32) }, { littleEndian: false });
class ScrcpyControlMessageTypeMap {
#types;
constructor(options) {
this.#types = options.controlMessageTypes;
}
get(type) {
const value = this.#types.indexOf(type);
if (value === -1) {
throw new TypeError("Invalid or unsupported control message type");
}
return value;
}
fillMessageType(message, type) {
message.type = this.get(type);
return message;
}
}
const ScrcpySetDisplayPowerControlMessage = structDeserialize.struct({ type: string.u8, mode: string.u8() }, { littleEndian: false });
const ScrcpyStartAppControlMessage = structDeserialize.struct({
type: string.u8,
name: string.string(string.u8)
}, { littleEndian: false });
const ScrcpyUHidInputControlMessage = /* @__PURE__ */ (() => structDeserialize.struct({
type: string.u8(ScrcpyControlMessageType.UHidInput),
id: string.u16,
data: structDeserialize.buffer(string.u16)
}, { littleEndian: false }))();
const ScrcpyUHidDestroyControlMessage = structDeserialize.struct({ type: string.u8, id: string.u16 }, { littleEndian: false });
class ScrcpyControlMessageSerializer {
#options;
#typeMap;
#scrollController;
constructor(options) {
this.#options = options;
this.#typeMap = new ScrcpyControlMessageTypeMap(options);
this.#scrollController = options.createScrollController();
}
injectKeyCode(message) {
return ScrcpyInjectKeyCodeControlMessage.serialize(this.#typeMap.fillMessageType(message, ScrcpyControlMessageType.InjectKeyCode));
}
injectText(text) {
return ScrcpyInjectTextControlMessage.serialize({
text,
type: this.#typeMap.get(ScrcpyControlMessageType.InjectText)
});
}
/**
* `pressure` is a float value between 0 and 1.
*/
injectTouch(message) {
return this.#options.serializeInjectTouchControlMessage(this.#typeMap.fillMessageType(message, ScrcpyControlMessageType.InjectTouch));
}
/**
* `scrollX` and `scrollY` are float values between 0 and 1.
*/
injectScroll(message) {
return this.#scrollController.serializeScrollMessage(this.#typeMap.fillMessageType(message, ScrcpyControlMessageType.InjectScroll));
}
backOrScreenOn(action) {
return this.#options.serializeBackOrScreenOnControlMessage({
action,
type: this.#typeMap.get(ScrcpyControlMessageType.BackOrScreenOn)
});
}
setDisplayPower(mode) {
return ScrcpySetDisplayPowerControlMessage.serialize({
mode,
type: this.#typeMap.get(ScrcpyControlMessageType.SetDisplayPower)
});
}
expandNotificationPanel() {
return EmptyControlMessage.serialize({
type: this.#typeMap.get(ScrcpyControlMessageType.ExpandNotificationPanel)
});
}
expandSettingPanel() {
return EmptyControlMessage.serialize({
type: this.#typeMap.get(ScrcpyControlMessageType.ExpandSettingPanel)
});
}
collapseNotificationPanel() {
return EmptyControlMessage.serialize({
type: this.#typeMap.get(ScrcpyControlMessageType.CollapseNotificationPanel)
});
}
rotateDevice() {
return EmptyControlMessage.serialize({
type: this.#typeMap.get(ScrcpyControlMessageType.RotateDevice)
});
}
setClipboard(message) {
return this.#options.serializeSetClipboardControlMessage({
...message,
type: this.#typeMap.get(ScrcpyControlMessageType.SetClipboard)
});
}
uHidCreate(message) {
if (!this.#options.serializeUHidCreateControlMessage) {
throw new Error("UHid not supported");
}
return this.#options.serializeUHidCreateControlMessage(this.#typeMap.fillMessageType(message, ScrcpyControlMessageType.UHidCreate));
}
uHidInput(message) {
return ScrcpyUHidInputControlMessage.serialize(this.#typeMap.fillMessageType(message, ScrcpyControlMessageType.UHidInput));
}
uHidDestroy(id) {
return ScrcpyUHidDestroyControlMessage.serialize({
type: this.#typeMap.get(ScrcpyControlMessageType.UHidDestroy),
id
});
}
startApp(name, options) {
if (options?.searchByName) {
name = "?" + name;
}
if (options?.forceStop) {
name = "+" + name;
}
return ScrcpyStartAppControlMessage.serialize({
type: this.#typeMap.get(ScrcpyControlMessageType.StartApp),
name
});
}
resetVideo() {
return EmptyControlMessage.serialize({
type: this.#typeMap.get(ScrcpyControlMessageType.ResetVideo)
});
}
}
class ScrcpyControlMessageWriter {
#writer;
#serializer;
constructor(writer, options) {
this.#writer = writer;
this.#serializer = new ScrcpyControlMessageSerializer(options);
}
write(message) {
return consumable.Consumable.WritableStream.write(this.#writer, message);
}
injectKeyCode(message) {
return this.write(this.#serializer.injectKeyCode(message));
}
injectText(text) {
return this.write(this.#serializer.injectText(text));
}
/**
* `pressure` is a float value between 0 and 1.
*/
injectTouch(message) {
return this.write(this.#serializer.injectTouch(message));
}
/**
* `scrollX` and `scrollY` are float values between 0 and 1.
*/
async injectScroll(message) {
const data = this.#serializer.injectScroll(message);
if (data) {
await this.write(data);
}
}
async backOrScreenOn(action) {
const data = this.#serializer.backOrScreenOn(action);
if (data) {
await this.write(data);
}
}
setScreenPowerMode(mode) {
return this.write(this.#serializer.setDisplayPower(mode));
}
expandNotificationPanel() {
return this.write(this.#serializer.expandNotificationPanel());
}
expandSettingPanel() {
return this.write(this.#serializer.expandSettingPanel());
}
collapseNotificationPanel() {
return this.write(this.#serializer.collapseNotificationPanel());
}
rotateDevice() {
return this.write(this.#serializer.rotateDevice());
}
async setClipboard(message) {
const result = this.#serializer.setClipboard(message);
if (result instanceof Uint8Array) {
await this.write(result);
} else {
await this.write(result[0]);
await result[1];
}
}
uHidCreate(message) {
return this.write(this.#serializer.uHidCreate(message));
}
uHidInput(message) {
return this.write(this.#serializer.uHidInput(message));
}
uHidDestroy(id) {
return this.write(this.#serializer.uHidDestroy(id));
}
startApp(name, options) {
return this.write(this.#serializer.startApp(name, options));
}
resetVideo() {
return this.write(this.#serializer.resetVideo());
}
releaseLock() {
this.#writer.releaseLock();
}
async close() {
await this.#writer.close();
}
}
const BackOrScreenOnControlMessage$1 = EmptyControlMessage;
const ClipboardDeviceMessage = structDeserialize.struct({ content: string.string(string.u32) }, { littleEndian: false });
class ClipboardStream extends consumable.PushReadableStream {
#controller;
id = 0;
constructor() {
let controller;
super((controller_) => {
controller = controller_;
});
this.#controller = controller;
}
async parse(_id, stream) {
const message = await ClipboardDeviceMessage.deserialize(stream);
await this.#controller.enqueue(message.content);
}
close() {
this.#controller.close();
}
error(e) {
this.#controller.error(e);
}
}
const ControlMessageTypes$1 = /* @__PURE__ */ (() => [
/* 0 */
ScrcpyControlMessageType.InjectKeyCode,
/* 1 */
ScrcpyControlMessageType.InjectText,
/* 2 */
ScrcpyControlMessageType.InjectTouch,
/* 3 */
ScrcpyControlMessageType.InjectScroll,
/* 4 */
ScrcpyControlMessageType.BackOrScreenOn,
/* 5 */
ScrcpyControlMessageType.ExpandNotificationPanel,
/* 6 */
ScrcpyControlMessageType.CollapseNotificationPanel,
/* 7 */
ScrcpyControlMessageType.GetClipboard,
/* 8 */
ScrcpyControlMessageType.SetClipboard,
/* 9 */
ScrcpyControlMessageType.SetDisplayPower,
/* 10 */
ScrcpyControlMessageType.RotateDevice
])();
const VideoOrientation$1 = {
Unlocked: -1};
const Defaults$8 = {
logLevel: "debug",
maxSize: 0,
bitRate: 8e6,
maxFps: 0,
lockVideoOrientation: VideoOrientation$1.Unlocked,
tunnelForward: false,
crop: void 0,
sendFrameMeta: true,
control: true,
displayId: 0,
showTouches: false,
stayAwake: false,
codecOptions: void 0
};
function clamp(value, min, max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}
const DefaultServerPath = "/data/local/tmp/scrcpy-server.jar";
// @__NO_SIDE_EFFECTS__
function omit(value, ...keys) {
return Object.fromEntries(Object.entries(value).filter(([key]) => !keys.includes(key)));
}
const UnsignedFloat = structDeserialize.field(2, "byob", (source, { buffer, index, littleEndian }) => {
source = clamp(source, -1, 1);
source = source === 1 ? 65535 : source * 65536;
string.setUint16(buffer, index, source, littleEndian);
}, function* (then, reader, { littleEndian }) {
const data = yield* then(reader.readExactly(2));
const value = string.getUint16(data, 0, littleEndian);
return value === 65535 ? 1 : value / 65536;
});
const MediaStreamRawPacket = structDeserialize.struct({ pts: string.u64, data: structDeserialize.buffer(string.u32) }, { littleEndian: false });
const PtsConfig = 1n << 63n;
async function readString(stream, maxLength) {
const buffer = await stream.readExactly(maxLength);
return string.decodeUtf8(buffer.subarray(0, buffer.indexOf(0)));
}
async function readU32(stream) {
const buffer = await stream.readExactly(4);
return string.getUint32BigEndian(buffer, 0);
}
const Defaults$7 = /* @__PURE__ */ (() => ({
...Defaults$8,
encoderName: void 0
}))();
const BackOrScreenOnControlMessage = string.extend(BackOrScreenOnControlMessage$1, { action: string.u8() });
function serializeBackOrScreenOnControlMessage(message) {
return BackOrScreenOnControlMessage.serialize(message);
}
const ControlMessageTypes = /* @__PURE__ */ (() => {
const result = ControlMessageTypes$1.slice();
result.splice(6, 0, ScrcpyControlMessageType.ExpandSettingPanel);
return result;
})();
const VideoOrientation = {
Unlocked: -1};
const Defaults$6 = /* @__PURE__ */ (() => ({
...Defaults$7,
logLevel: "debug",
lockVideoOrientation: VideoOrientation.Unlocked,
powerOffOnClose: false
}))();
const Defaults$5 = /* @__PURE__ */ (() => ({
...Defaults$6,
clipboardAutosync: true
}))();
function toSnakeCase(input) {
return input.replace(/([A-Z])/g, "_$1").toLowerCase();
}
function serialize(options, defaults) {
const result = [];
for (const [key, value] of Object.entries(options)) {
const serializedValue = toScrcpyOptionValue(value, void 0);
if (serializedValue === void 0) {
continue;
}
const defaultValue = toScrcpyOptionValue(defaults[key], void 0);
if (serializedValue === defaultValue) {
continue;
}
result.push(`${toSnakeCase(key)}=${serializedValue}`);
}
return result;
}
const AckClipboardDeviceMessage = structDeserialize.struct({ sequence: string.u64 }, { littleEndian: false });
const SetClipboardControlMessage = structDeserialize.struct({
type: string.u8,
sequence: string.u64,
paste: string.u8(),
content: string.string(string.u32)
}, { littleEndian: false });
class AckClipboardHandler {
#resolvers = /* @__PURE__ */ new Map();
#closed = false;
id = 1;
async parse(_id, stream) {
const message = await AckClipboardDeviceMessage.deserialize(stream);
const resolver = this.#resolvers.get(message.sequence);
if (resolver) {
resolver.resolve();
this.#resolvers.delete(message.sequence);
}
}
close() {
for (const resolver of this.#resolvers.values()) {
resolver.reject();
}
this.#resolvers.clear();
this.#closed = true;
}
error(e) {
for (const resolver of this.#resolvers.values()) {
resolver.reject(e);
}
this.#resolvers.clear();
this.#closed = true;
}
serializeSetClipboardControlMessage(message) {
if (message.sequence === 0n) {
return SetClipboardControlMessage.serialize(message);
}
if (this.#closed) {
throw new Error();
}
const resolver = new consumable.PromiseResolver();
this.#resolvers.set(message.sequence, resolver);
return [
SetClipboardControlMessage.serialize(message),
resolver.promise
];
}
}
const Defaults$4 = /* @__PURE__ */ (() => ({
...Defaults$5,
downsizeOnError: true,
sendDeviceMeta: true,
sendDummyByte: true
}))();
const Defaults$3 = /* @__PURE__ */ (() => ({
...Defaults$4,
cleanup: true
}))();
const PtsKeyframe = 1n << 62n;
function createMediaStreamTransformer(options) {
if (!options.sendFrameMeta) {
return new consumable.TransformStream({
transform(chunk, controller) {
controller.enqueue({
type: "data",
data: chunk
});
}
});
}
const deserializeStream = new structDeserialize.StructDeserializeStream(MediaStreamRawPacket);
return {
writable: deserializeStream.writable,
readable: deserializeStream.readable.pipeThrough(new consumable.TransformStream({
transform(packet, controller) {
if (packet.pts === PtsConfig) {
controller.enqueue({
type: "configuration",
data: packet.data
});
return;
}
if (packet.pts & PtsKeyframe) {
controller.enqueue({
type: "data",
keyframe: true,
pts: packet.pts & ~PtsKeyframe,
data: packet.data
});
return;
}
controller.enqueue({
type: "data",
keyframe: false,
pts: packet.pts,
data: packet.data
});
}
}))
};
}
const Defaults$2 = /* @__PURE__ */ (() => ({
...Defaults$3,
powerOn: true
}))();
const SignedFloat = structDeserialize.field(2, "byob", (value, { buffer, index, littleEndian }) => {
value = clamp(value, -1, 1);
value = value === 1 ? 32767 : value * 32768;
setInt16(buffer, index, value, littleEndian);
}, function* (then, reader, { littleEndian }) {
const data = yield* then(reader.readExactly(2));
const value = getInt16(data, 0, littleEndian);
return value === 32767 ? 1 : value / 32768;
});
const InjectScrollControlMessage = /* @__PURE__ */ (() => structDeserialize.struct({
type: string.u8(ScrcpyControlMessageType.InjectScroll),
pointerX: string.u32,
pointerY: string.u32,
videoWidth: string.u16,
videoHeight: string.u16,
scrollX: SignedFloat,
scrollY: SignedFloat,
buttons: string.u32
}, { littleEndian: false }))();
class ScrollController {
serializeScrollMessage(message) {
return InjectScrollControlMessage.serialize(message);
}
}
function createScrollController() {
return new ScrollController();
}
const Defaults$1 = /* @__PURE__ */ (() => ({
...omit(Defaults$2, "bitRate", "codecOptions", "encoderName"),
scid: void 0,
videoCodec: "h264",
videoBitRate: 8e6,
videoCodecOptions: void 0,
videoEncoder: void 0,
audio: true,
audioCodec: "opus",
audioBitRate: 128e3,
audioCodecOptions: void 0,
audioEncoder: void 0,
listEncoders: false,
listDisplays: false,
sendCodecMeta: true
}))();
const InjectTouchControlMessage = /* @__PURE__ */ (() => structDeserialize.struct({
type: string.u8(ScrcpyControlMessageType.InjectTouch),
action: string.u8(),
pointerId: string.u64,
pointerX: string.u32,
pointerY: string.u32,
videoWidth: string.u16,
videoHeight: string.u16,
pressure: UnsignedFloat,
actionButton: string.u32,
buttons: string.u32
}, { littleEndian: false }))();
function serializeInjectTouchControlMessage(message) {
return InjectTouchControlMessage.serialize(message);
}
async function parseAudioStreamMetadata(stream, options) {
const buffered = new structDeserialize.BufferedReadableStream(stream);
const buffer = await buffered.readExactly(4);
const codecMetadataValue = string.getUint32BigEndian(buffer, 0);
switch (codecMetadataValue) {
case 0:
return {
type: "disabled"
};
case 1:
return {
type: "errored"
};
}
if (options.sendCodecMeta) {
let codec2;
switch (codecMetadataValue) {
case ScrcpyAudioCodec.Raw.metadataValue:
codec2 = ScrcpyAudioCodec.Raw;
break;
case ScrcpyAudioCodec.Opus.metadataValue:
codec2 = ScrcpyAudioCodec.Opus;
break;
case ScrcpyAudioCodec.Aac.metadataValue:
codec2 = ScrcpyAudioCodec.Aac;
break;
case ScrcpyAudioCodec.Flac.metadataValue:
codec2 = ScrcpyAudioCodec.Flac;
break;
default:
throw new Error(`Unknown audio codec metadata value: ${codecMetadataValue}`);
}
return {
type: "success",
codec: codec2,
stream: buffered.release()
};
}
let codec;
switch (options.audioCodec) {
case "raw":
codec = ScrcpyAudioCodec.Raw;
break;
case "opus":
codec = ScrcpyAudioCodec.Opus;
break;
case "aac":
codec = ScrcpyAudioCodec.Aac;
break;
case "flac":
codec = ScrcpyAudioCodec.Flac;
break;
default:
throw new Error(`Unknown audio codec metadata value: ${codecMetadataValue}`);
}
return {
type: "success",
codec,
stream: new consumable.PushReadableStream(async (controller) => {
await controller.enqueue(buffer);
const stream2 = buffered.release();
const reader = stream2.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
await controller.enqueue(value);
}
})
};
}
function parseDisplay(line) {
const match = line.match(/^\s+--display=(\d+)\s+\(([^)]+)\)$/);
if (match) {
const display = {
id: Number.parseInt(match[1], 10)
};
if (match[2] !== "size unknown") {
display.resolution = match[2];
}
return display;
}
return void 0;
}
const EncoderRegex = /^\s+--(video|audio)-codec=(\S+)\s+--\1-encoder='([^']+)'$/;
function parseEncoder(line) {
const match = line.match(EncoderRegex);
return match ? {
type: match[1],
name: match[3],
codec: match[2]
} : void 0;
}
function toCodecId(codec) {
switch (codec) {
case "h264":
return ScrcpyVideoCodecId.H264;
case "h265":
return ScrcpyVideoCodecId.H265;
case "av1":
return ScrcpyVideoCodecId.AV1;
default:
throw new Error(`Unknown video codec: ${codec}`);
}
}
async function parseAsync(options, stream) {
const buffered = new structDeserialize.BufferedReadableStream(stream);
let deviceName;
if (options.sendDeviceMeta) {
deviceName = await readString(buffered, 64);
}
let codec;
let width;
let height;
if (options.sendCodecMeta) {
codec = await readU32(buffered);
width = await readU32(buffered);
height = await readU32(buffered);
} else {
codec = toCodecId(options.videoCodec);
}
return {
stream: buffered.release(),
metadata: { deviceName, codec, width, height }
};
}
function parseVideoStreamMetadata(options, stream) {
if (!options.sendDeviceMeta && !options.sendCodecMeta) {
return {
stream,
metadata: { codec: toCodecId(options.videoCodec) }
};
}
return parseAsync(options, stream);
}
function setListDisplays(options) {
options.listDisplays = true;
}
function setListEncoders(options) {
options.listEncoders = true;
}
const Defaults = /* @__PURE__ */ (() => ({
...Defaults$1,
video: true,
audioSource: "output"
}))();
class ScrcpyOptions2_1 {
static Defaults = Defaults;
value;
get controlMessageTypes() {
return ControlMessageTypes;
}
#clipboard;
get clipboard() {
return this.#clipboard;
}
#ackClipboardHandler;
#deviceMessageParsers = new ScrcpyDeviceMessageParsers();
get deviceMessageParsers() {
return this.#deviceMessageParsers;
}
constructor(init) {
this.value = { ...Defaults, ...init };
if (this.value.control && this.value.clipboardAutosync) {
this.#clipboard = this.#deviceMessageParsers.add(new ClipboardStream());
this.#ackClipboardHandler = this.#deviceMessageParsers.add(new AckClipboardHandler());
}
}
serialize() {
return serialize(this.value, Defaults);
}
setListDisplays() {
setListDisplays(this.value);
}
parseDisplay(line) {
return parseDisplay(line);
}
setListEncoders() {
setListEncoders(this.value);
}
parseEncoder(line) {
return parseEncoder(line);
}
parseVideoStreamMetadata(stream) {
return parseVideoStreamMetadata(this.value, stream);
}
parseAudioStreamMetadata(stream) {
return parseAudioStreamMetadata(stream, this.value);
}
createMediaStreamTransformer() {
return createMediaStreamTransformer(this.value);
}
serializeInjectTouchControlMessage(message) {
return serializeInjectTouchControlMessage(message);
}
serializeBackOrScreenOnControlMessage(message) {
return serializeBackOrScreenOnControlMessage(message);
}
serializeSetClipboardControlMessage(message) {
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(message);
}
createScrollController() {
return createScrollController();
}
}
class BitReader {
#data;
#byte;
#bytePosition = 0;
#bitPosition = 7;
get byteAligned() {
return this.#bitPosition === 7;
}
get ended() {
return this.#bytePosition >= this.#data.length;
}
constructor(data) {
this.#data = data;
this.#byte = data[0];
}
f1() {
const value = this.#byte >> this.#bitPosition;
this.#bitPosition -= 1;
if (this.#bitPosition < 0) {
this.#bytePosition += 1;
this.#bitPosition = 7;
this.#byte = this.#data[this.#bytePosition];
}
return value & 1;
}
f(n) {
let value = 0;
for (; n > 0; n -= 1) {
value <<= 1;
value |= this.f1();
}
return value;
}
skip(n) {
if (n <= this.#bitPosition + 1) {
this.#bytePosition += 1;
this.#bitPosition = 7;
this.#byte = this.#data[this.#bytePosition];
return;
}
n -= this.#bitPosition + 1;
this.#bytePosition += 1;
const bytes = n / 8 | 0;
if (bytes > 0) {
this.#bytePosition += bytes;
n -= bytes * 8;
}
this.#bitPosition = 7 - n;
this.#byte = this.#data[this.#bytePosition];
}
readBytes(n) {
if (!this.byteAligned) {
throw new Error("Bytes must be byte-aligned");
}
const value = this.#data.subarray(this.#bytePosition, this.#bytePosition + n);
this.#bytePosition += n;
this.#byte = this.#data[this.#bytePosition];
return value;
}
getPosition() {
return [this.#bytePosition, this.#bitPosition];
}
setPosition([bytePosition, bitPosition]) {
this.#bytePosition = bytePosition;
this.#bitPosition = bitPosition;
this.#byte = this.#data[bytePosition];
}
}
const ObuType = {
SequenceHeader: 1,
TemporalDelimiter: 2,
FrameHeader: 3,
TileGroup: 4,
Metadata: 5,
Frame: 6,
RedundantFrameHeader: 7,
TileList: 8,
Padding: 15
};
const ColorPrimaries = {
Bt709: 1,
Unspecified: 2,
Bt470M: 4,
Bt470BG: 5,
Bt601: 6,
Smpte240: 7,
GenericFilm: 8,
Bt2020: 9,
Xyz: 10,
Smpte431: 11,
Smpte432: 12,
Ebu3213: 22
};
const TransferCharacteristics = {
Bt709: 1,
Unspecified: 2,
Bt470M: 4,
Bt470BG: 5,
Bt601: 6,
Smpte240: 7,
Linear: 8,
Log100: 9,
Log100Sqrt10: 10,
Iec61966: 11,
Bt1361: 12,
Srgb: 13,
Bt2020Ten: 14,
Bt2020Twelve: 15,
Smpte2084: 16,
Smpte428: 17,
Hlg: 18
};
const MatrixCoefficients = {
Identity: 0,
Bt709: 1,
Unspecified: 2,
Fcc: 4,
Bt470BG: 5,
Bt601: 6,
Smpte240: 7,
YCgCo: 8,
Bt2020Ncl: 9,
Bt2020Cl: 10,
Smpte2085: 11,
ChromatNcl: 12,
ChromatCl: 13,
ICtCp: 14
};
class Av1 extends BitReader {
static ObuType = ObuType;
static ColorPrimaries = ColorPrimaries;
static TransferCharacteristics = TransferCharacteristics;
static MatrixCoefficients = MatrixCoefficients;
#Leb128Bytes = 0;
uvlc() {
let leadingZeros = 0;
while (!this.f1()) {
leadingZeros += 1;
}
if (leadingZeros >= 32) {
return 2 ** 32 - 1;
}
const value = this.f(leadingZeros);
return value + (1 << leadingZeros >>> 0) - 1;
}
leb128() {
if (!this.byteAligned) {
throw new Error("LEB128 must be byte-aligned");
}
let value = 0n;
this.#Leb128Bytes = 0;
for (let i = 0n; i < 8n; i += 1n) {
const leb128_byte = this.f(8);
value |= BigInt(leb128_byte & 127) << 7n * i;
this.#Leb128Bytes += 1;
if ((leb128_byte & 128) == 0) {
break;
}
}
return value;
}
*annexBBitstream() {
while (!this.ended) {
const temporal_unit_size = this.leb128();
yield* this.temporalUnit(temporal_unit_size);
}
}
*temporalUnit(sz) {
while (sz > 0) {
const frame_unit_size = this.leb128();
sz -= BigInt(this.#Leb128Bytes);
yield* this.frameUnit(frame_unit_size);
sz -= frame_unit_size;
}
}
*frameUnit(sz) {
while (sz > 0) {
const obu_length = this.leb128();
sz -= BigInt(this.#Leb128Bytes);
const obu = this.openBitstreamUnit(obu_length);
if (obu) {
yield obu;
}
sz -= obu_length;
}
}
#OperatingPointIdc = 0;
openBitstreamUnit(sz) {
const obu_header = this.obuHeader();
let obu_size;
if (obu_header.obu_has_size_field) {
obu_size = this.leb128();
} else if (sz !== void 0) {
obu_size = sz - 1n - (obu_header.obu_extension_flag ? 1n : 0n);
} else {
throw new Error("obu_has_size_field must be true");
}
const startPosition = this.getPosition();
if (obu_header.obu_type !== Av1.ObuType.SequenceHeader && obu_header.obu_type !== Av1.ObuType.TemporalDelimiter && this.#OperatingPointIdc !== 0 && obu_header.obu_extension_header) {
const inTemporalLayer = !!(this.#OperatingPointIdc & 1 << obu_header.obu_extension_header.temporal_id);
const inSpatialLayer = !!(this.#OperatingPointIdc & 1 << obu_header.obu_extension_header.spatial_id + 8);
if (!inTemporalLayer || !inSpatialLayer) {
this.skip(Number(obu_size));
return;
}
}
let sequence_header_obu;
switch (obu_header.obu_type) {
case Av1.ObuType.SequenceHeader:
sequence_header_obu = this.sequenceHeaderObu();
break;
}
const currentPosition = this.getPosition();
const payloadBits = (currentPosition[0] - startPosition[0]) * 8 + (startPosition[1] - currentPosition[1]);
if (obu_size > 0) {
this.skip(Number(obu_size) * 8 - payloadBits);
}
return {
obu_header,
obu_size,
sequence_header_obu
};
}
obuHeader() {
const obu_forbidden_bit = !!this.f1();
if (obu_forbidden_bit) {
throw new Error("Invalid data");
}
const obu_type = this.f(4);
const obu_extension_flag = !!this.f1();
const obu_has_size_field = !!this.f1();
this.f1();
let obu_extension_header;
if (obu_extension_flag) {
obu_extension_header = this.obuExtensionHeader();
}
return {
obu_type,
obu_extension_flag,
obu_has_size_field,
obu_extension_header
};
}
obuExtensionHeader() {
const temporal_id = this.f(3);
const spatial_id = this.f(2);
this.skip(3);
return { temporal_id, spatial_id };
}
static SelectScreenContentTools = 2;
static SelectIntegerMv = 2;
sequenceHeaderObu() {
const seq_profile = this.f(3);
const still_picture = !!this.f1();
const reduced_still_picture_header = !!this.f1();
let timing_info_present_flag = false;
let timing_info;
let decoder_model_info_present_flag = false;
let decoder_model_info;
let initial_display_delay_present_flag = false;
let operating_points_cnt_minus_1 = 0;
const operating_point_idc = [];
const seq_level_idx = [];
const seq_tier = [];
const decoder_model_present_for_this_op = [];
const initial_display_delay_present_for_this_op = [];
let operating_parameters_info;
let initial_display_delay_minus_1;
if (reduced_still_picture_header) {
operating_point_idc[0] = 0;
seq_level_idx[0] = this.f(5);
seq_tier[0] = 0;
decoder_model_present_for_this_op[0] = false;
initial_display_delay_present_for_this_op[0] = false;
} else {
timing_info_present_flag = !!this.f1();
if (timing_info_present_flag) {
timing_info = this.timingInfo();
decoder_model_info_present_flag = !!this.f1();
if (decoder_model_info_present_flag) {
decoder_model_info = this.decoderModelInfo();
operating_parameters_info = [];
}
}
initial_display_delay_present_flag = !!this.f1();
if (initial_display_delay_present_flag) {
initial_display_delay_minus_1 = [];
}
operating_points_cnt_minus_1 = this.f(5);
for (let i = 0; i <= operating_points_cnt_minus_1; i += 1) {
operating_point_idc[i] = this.f(12);
seq_level_idx[i] = this.f(5);
if (seq_level_idx[i] > 7) {
seq_tier[i] = this.f1();
} else {
seq_tier[i] = 0;
}
if (decoder_model_info_present_flag) {
decoder_model_present_for_this_op[i] = !!this.f1();
if (decoder_model_present_for_this_op[i]) {
operating_parameters_info[i] = this.operatingParametersInfo(decoder_model_info);
}
} else {
decoder_model_present_for_this_op[i] = false;
}
if (initial_display_delay_present_flag) {
initial_display_delay_present_for_this_op[i] = !!this.f1();
if (initial_display_delay_present_for_this_op[i]) {
initial_display_delay_minus_1[i] = this.f(4);
}
}
}
}
const operatingPoint = this.chooseOperatingPoint();
this.#OperatingPointIdc = operating_point_idc[operatingPoint];
const frame_width_bits_minus_1 = this.f(4);
const frame_height_bits_minus_1 = this.f(4);
const max_frame_width_minus_1 = this.f(frame_width_bits_minus_1 + 1);
const max_frame_height_minus_1 = this.f(frame_height_bits_minus_1 + 1);
let frame_id_numbers_present_flag = false;
let delta_frame_id_length_minus_2;
let additional_frame_id_length_minus_1;
if (!reduced_still_picture_header) {
frame_id_numbers_present_flag = !!this.f1();
if (frame_id_numbers_present_flag) {
delta_frame_id_length_minus_2 = this.f(4);
additional_frame_id_length_minus_1 = this.f(3);
}
}
const use_128x128_superblock = !!this.f1();
const enable_filter_intra = !!this.f1();
const enable_intra_edge_filter = !!this.f1();
let enable_interintra_compound = false;
let enable_masked_compound = false;
let enable_warped_motion = false;
let enable_dual_filter = false;
let enable_order_hint = false;
let enable_jnt_comp = false;
let enable_ref_frame_mvs = false;
let seq_choose_screen_content_tools = false;
let seq_force_screen_content_tools = Av1.SelectScreenContentTools;
let seq_choose_integer_mv = false;
let seq_force_integer_mv = Av1.SelectIntegerMv;
let order_hint_bits_minus_1;
if (!reduced_still_picture_header) {
enable_interintra_compound = !!this.f1();
enable_masked_compound = !!this.f1();
enable_warped_motion = !!this.f1();
enable_dual_filter = !!this.f1();
enable_order_hint = !!this.f1();
if (enable_order_hint) {
enable_jnt_comp = !!this.f1();
enable_ref_frame_mvs = !!this.f1();
}
seq_choose_screen_content_tools = !!this.f1();
if (!seq_choose_screen_content_tools) {
seq_force_screen_content_tools = this.f1();
}
if (seq_force_screen_content_tools > 0) {
seq_choose_integer_mv = !!this.f1();
if (!seq_choose_integer_mv) {
seq_force_integer_mv = this.f1();
}
}
if (enable_order_hint) {
order_hint_bits_minus_1 = this.f(3);
}
}
const enable_superres = !!this.f1();
const enable_cdef = !!this.f1();
const enable_restoration = !!this.f1();
const color_config = this.colorConfig(seq_profile);
const film_grain_params_present = !!this.f1();
return {
seq_profile,
still_picture,
reduced_still_picture_header,
timing_info_present_flag,
timing_info,
decoder_model_info_present_flag,
decoder_model_info,
initial_display_delay_present_flag,
initial_display_delay_minus_1,
operating_points_cnt_minus_1,
operating_point_idc,
seq_level_idx,
seq_tier,
decoder_model_present_for_this_op,
operating_parameters_info,
initial_display_delay_present_for_this_op,
frame_width_bits_minus_1,
frame_height_bits_minus_1,
max_frame_width_minus_1,
max_frame_height_minus_1,
frame_id_numbers_present_flag,
delta_frame_id_length_minus_2,
additional_frame_id_length_minus_1,
use_128x128_superblock,
enable_filter_intra,
enable_intra_edge_filter,
enable_interintra_compound,
enable_masked_compound,
enable_warped_motion,
enable_dual_filter,
enable_order_hint,
enable_jnt_comp,
enable_ref_frame_mvs,
seq_choose_screen_content_tools,
seq_force_screen_content_tools,
seq_choose_integer_mv,
seq_force_integer_mv,
order_hint_bits_minus_1,
enable_superres,
enable_cdef,
enable_restoration,
color_config,
film_grain_params_present
};
}
searchSequenceHeaderObu() {
while (!this.ended) {
const obu = this.openBitstreamUnit();
if (!obu) {
continue;
}
if (obu.sequence_header_obu) {
return obu.sequence_header_obu;
}
}
return void 0;
}
timingInfo() {
const num_units_in_display_tick = this.f(32);
const time_scale = this.f(32);
const equal_picture_interval = !!this.f1();
let num_ticks_per_picture_minus_1;
if (equal_picture_interval) {
num_ticks_per_picture_minus_1 = this.uvlc();
}
return {
num_units_in_display_tick,
time_scale,
equal_picture_interval,
num_ticks_per_picture_minus_1
};
}
decoderModelInfo() {
const buffer_delay_length_minus_1 = this.f(5);
const num_units_in_decoding_tick = this.f(32);
const buffer_removal_time_length_minus_1 = this.f(5);
const frame_presentation_time_length_minus_1 = this.f(5);
return {
buffer_delay_length_minus_1,
num_units_in_decoding_tick,
buffer_removal_time_length_minus_1,
frame_presentation_time_length_minus_1
};
}
operatingParametersInfo(decoderModelInfo) {
const n = decoderModelInfo.buffer_delay_length_minus_1 + 1;
const decoder_buffer_delay = this.f(n);
const encoder_buffer_delay = this.f(n);
const low_delay_mode_flag = !!this.f1();
return {
decoder_buffer_delay,
encoder_buffer_delay,
low_delay_mode_flag
};
}
chooseOperatingPoint() {
return 0;
}
colorConfig(seq_profile) {
const high_bitdepth = !!this.f1();
let twelve_bit = false;
let BitDepth = 8;
if (seq_profile === 2 && high_bitdepth) {
twelve_bit = !!this.f1();
BitDepth = twelve_bit ? 12 : 10;
} else if (seq_profile <= 2) {
BitDepth = high_bitdepth ? 10 : 8;
}
let mono_chrome = false;
if (seq_profile === 1) {
mono_chrome = !!this.f1();
}
const color_description_present_flag = !!this.f1();
let color_primaries = Av1.ColorPrimaries.Unspecified;
let transfer_characteristics = Av1.TransferCharacteristics.Unspecified;
let matrix_coefficients = Av1.MatrixCoefficients.Unspecified;
if (color_description_present_flag) {
color_primaries = this.f(8);
transfer_characteristics = this.f(8);
matrix_coefficients = this.f(8);
}
let color_range = false;
let subsampling_x;
let subsampling_y;
let chroma_sample_position = 0;
let separate_uv_delta_q = false;
if (mono_chrome) {
color_range = !!this.f1();
subsampling_x = true;
subsampling_y = true;
} else {
if (color_primaries === Av1.ColorPrimaries.Bt709 && transfer_characteristics === Av1.TransferCharacteristics.Srgb && matrix_coefficients === Av1.MatrixCoefficients.Identity) {
color_range = true;
subsampling_x = false;
subsampling_y = false;
} else {
color_range = !!this.f1();
switch (seq_profile) {
case 0:
subsampling_x = true;
subsampling_y = true;
break;
case 1:
subsampling_x = false;
subsampling_y = false;
break;
default:
if (BitDepth == 12) {
subsampling_x = !!this.f1();
if (subsampling_x) {
subsampling_y = !!this.f1();
} else {
subsampling_y = false;
}
} else {
subsampling_x = true;
subsampling_y = false;
}
break;
}
if (subsampling_x && subsampling_y) {
chroma_sample_position = this.f(2);
}
}
separate_uv_delta_q = !!this.f1();
}
return {
high_bitdepth,
twelve_bit,
BitDepth,
mono_chrome,
color_description_present_flag,
color_primaries,
transfer_characteristics,
matrix_coefficients,
color_range,
subsampling_x,
subsampling_y,
chroma_sample_position,
separate_uv_delta_q
};
}
}
function* annexBSplitNalu(buffer) {
let start = -1;
let zeroCount = 0;
let inEmulation = false;
for (let i = 0; i < buffer.length; i += 1) {
const byte = buffer[i];
if (inEmulation) {
if (byte > 3) {
throw new Error("Invalid data");
}
inEmulation = false;
continue;
}
if (byte === 0) {
zeroCount += 1;
continue;
}
const prevZeroCount = zeroCount;
zeroCount = 0;
if (start === -1) {
if (prevZeroCount >= 2 && byte === 1) {
start = i + 1;
continue;
}
throw new Error("Invalid data");
}
if (prevZeroCount < 2) {
continue;
}
if (byte === 1) {
yield buffer.subarray(start, i - prevZeroCount);
start = i + 1;
continue;
}
if (prevZeroCount > 2) {
throw new Error("Invalid data");
}
switch (byte) {
case 2:
throw new Error("Invalid data");
case 3:
inEmulation = true;
break;
}
}
if (inEmulation) {
throw new Error("Invalid data");
}
yield buffer.subarray(start, buffer.length);
}
class NaluSodbBitReader {
#nalu;
// logical length is `#byteLength * 8 + (7 - #stopBitIndex)`
#byteLength;
#stopBitIndex;
#zeroCount = 0;
// logical position is `#bytePosition * 8 + (7 - #bitPosition)`
#bytePosition = 0;
#bitPosition = 7;
#byte = 0;
get byteLength() {
return this.#byteLength;
}
get stopBitIndex() {
return this.#stopBitIndex;
}
get bytePosition() {
return this.#bytePosition;
}
get bitPosition() {
return this.#bitPosition;
}
get ended() {
return this.#bytePosition >= this.#byteLength && this.#bitPosition <= this.#stopBitIndex;
}
constructor(nalu) {
this.#nalu = nalu;
for (let i = nalu.length - 1; i >= 0; i -= 1) {
if (this.#nalu[i] === 0) {
continue;
}
const byte = nalu[i];
for (let j = 0; j < 8; j += 1) {
if ((byte >> j & 1) === 1) {
this.#byteLength = i;
this.#stopBitIndex = j;
this.#loadByte();
return;
}
}
}
throw new Error("Stop bit not found");
}
#loadByte() {
this.#byte = this.#nalu[this.#bytePosition];
if (this.#zeroCount === 2 && this.#byte === 3) {
this.#zeroCount = 0;
this.#bytePosition += 1;
this.#loadByte();
return;
}
if (this.#byte === 0) {
this.#zeroCount += 1;
} else {
this.#zeroCount = 0;
}
}
next() {
if (this.ended) {
throw new Error("Bit index out of bounds");
}
const value = this.#byte >> this.#bitPosition & 1;
this.#bitPosition -= 1;
if (this.#bitPosition < 0) {
this.#bytePosition += 1;
this.#bitPosition = 7;
this.#loadByte();
}
return value;
}
read(length) {
if (length > 32) {
throw new Error("Read length too large");
}
let result = 0;
for (let i = 0; i < length; i += 1) {
result = result << 1 | this.next();
}
return result;
}
/**
* Throws an error if the current position is invalid for `skip`.
*
* Usually it will throw if `ended` is `true`,
* except when the bit position is at the stop bit,
* in which case `ended` will be `true`, but it won't throw.
* `skip` can skip all remaining bits, and stop at the end position.
* The next `next` call will throw since there is no more bits to read.
*/
#checkSkipPosition() {
if (this.#bytePosition >= this.#byteLength && this.#bitPosition < this.#stopBitIndex) {
throw new Error("Bit index out of bounds");
}
}
skip(length) {
if (length <= this.#bitPosition + 1) {
this.#bitPosition -= length;
this.#checkSkipPosition();
return;
}
length -= this.#bitPosition + 1;
this.#bytePosition += 1;
this.#bitPosition = 7;
this.#loadByte();
this.#checkSkipPosition();
for (; length >= 8; length -= 8) {
this.#bytePosition += 1;
this.#loadByte();
this.#checkSkipPosition();
}
this.#bitPosition = 7 - length;
this.#checkSkipPosition();
}
decodeExponentialGolombNumber() {
let length = 0;
while (this.next() === 0) {
length += 1;
}
if (length === 0) {
return 0;
}
return (1 << length | this.read(length)) - 1;
}
#save() {
return {
zeroCount: this.#zeroCount,
bytePosition: this.#bytePosition,
bitPosition: this.#bitPosition,
byte: this.#byte
};
}
#restore(state) {
this.#zeroCount = state.zeroCount;
this.#bytePosition = state.bytePosition;
this.#bitPosition = state.bitPosition;
this.#byte = state.byte;
}
peek(length) {
const state = this.#save();
const result = this.read(length);
this.#restore(state);
return result;
}
readBytes(length) {
const result = new Uint8Array(length);
for (let i = 0; i < length; i += 1) {
result[i] = this.read(8);
}
return result;
}
peekBytes(length) {
const state = this.#save();
const result = this.readBytes(length);
this.#restore(state);
return result;
}
}
function h264ParseSequenceParameterSet(nalu) {
const reader = new NaluSodbBitReader(nalu);
if (reader.next() !== 0) {
throw new Error("Invalid data");
}
const nal_ref_idc = reader.read(2);
const nal_unit_type = reader.read(5);
if (nal_unit_type !== 7) {
throw new Error("Invalid data");
}
if (nal_ref_idc === 0) {
throw new Error("Invalid data");
}
const profile_idc = reader.read(8);
const constraint_set = reader.peek(8);
const constraint_set0_flag = !!reader.next();
const constraint_set1_flag = !!reader.next();
const constraint_set2_flag = !!reader.next();
const constraint_set3_flag = !!reader.next();
const constraint_set4_flag = !!reader.next();
const constraint_set5_flag = !!reader.next();
if (reader.read(2) !== 0) {
throw new Error("Invalid data");
}
const level_idc = reader.read(8);
const seq_parameter_set_id = reader.decodeExponentialGolombNumber();
if (profile_idc === 100 || profile_idc === 110 || profile_idc === 122 || profile_idc === 244 || profile_idc === 44 || profile_idc === 83 || profile_idc === 86 || profile_idc === 118 || profile_idc === 128 || profile_idc === 138 || profile_idc === 139 || profile_idc === 134) {
const chroma_format_idc = reader.decodeExponentialGolombNumber();
if (chroma_format_idc === 3) {
reader.next();
}
reader.decodeExponentialGolombNumber();
reader.decodeExponentialGolombNumber();
reader.next();
const seq_scaling_matrix_present_flag = !!reader.next();
if (seq_scaling_matrix_present_flag) {
for (let i = 0; i < (chroma_format_idc !== 3 ? 8 : 12); i += 1) {
!!reader.next();
}
}
}
reader.decodeExponentialGolombNumber();
const pic_order_cnt_type = reader.decodeExponentialGolombNumber();
if (pic_order_cnt_type === 0) {
reader.decodeExponentialGolombNumber();
} else if (pic_order_cnt_type === 1) {
reader.next();
reader.decodeExponentialGolombNumber();
reader.decodeExponentialGolombNumber();
const num_ref_frames_in_pic_order_cnt_cycle = reader.decodeExponentialGolombNumber();
for (let i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i += 1) {
reader.decodeExponentialGolombNumber();
}
}
reader.decodeExponentialGolombNumber();
reader.next();
const pic_width_in_mbs_minus1 = reader.decodeExponentialGolombNumber();
const pic_height_in_map_units_minus1 = reader.decodeExponentialGolombNumber();
const frame_mbs_only_flag = reader.next();
if (!frame_mbs_only_flag) {
reader.next();
}
reader.next();
const frame_cropping_flag = !!reader.next();
let frame_crop_left_offset;
let frame_crop_right_offset;
let frame_crop_top_offset;
let frame_crop_bottom_offset;
if (frame_cropping_flag) {
frame_crop_left_offset = reader.decodeExponentialGolombNumber();
frame_crop_right_offset = reader.decodeExponentialGolombNumber();
frame_crop_top_offset = reader.decodeExponentialGolombNumber();
frame_crop_bottom_offset = reader.decodeExponentialGolombNumber();
} else {
frame_crop_left_offset = 0;
frame_crop_right_offset = 0;
frame_crop_top_offset = 0;
frame_crop_bottom_offset = 0;
}
!!reader.next();
return {
profile_idc,
constraint_set,
constraint_set0_flag,
constraint_set1_flag,
constraint_set2_flag,
constraint_set3_flag,
constraint_set4_flag,
constraint_set5_flag,
level_idc,
seq_parameter_set_id,
pic_width_in_mbs_minus1,
pic_height_in_map_units_minus1,
frame_mbs_only_flag,
frame_cropping_flag,
frame_crop_left_offset,
frame_crop_right_offset,
frame_crop_top_offset,
frame_crop_bottom_offset
};
}
function h264SearchConfiguration(buffer) {
let sequenceParameterSet;
let pictureParameterSet;
for (const nalu of annexBSplitNalu(buffer)) {
const naluType = nalu[0] & 31;
switch (naluType) {
case 7:
sequenceParameterSet = nalu;
if (pictureParameterSet) {
return {
sequenceParameterSet,
pictureParameterSet
};
}
break;
case 8:
pictureParameterSet = nalu;
if (sequenceParameterSet) {
return {
sequenceParameterSet,
pictureParameterSet
};
}
break;
}
}
throw new Error("Invalid data");
}
function h264ParseConfiguration(data) {
const { sequenceParameterSet, pictureParameterSet } = h264SearchConfiguration(data);
const { profile_idc: profileIndex, constraint_set: constraintSet, level_idc: levelIndex, pic_width_in_mbs_minus1, pic_height_in_map_units_minus1, frame_mbs_only_flag, frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset, frame_crop_bottom_offset } = h264ParseSequenceParameterSet(sequenceParameterSet);
const encodedWidth = (pic_width_in_mbs_minus1 + 1) * 16;
const encodedHeight = (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) * 16;
const cropLeft = frame_crop_left_offset * 2;
const cropRight = frame_crop_right_offset * 2;
const cropTop = frame_crop_top_offset * 2;
const cropBottom = frame_crop_bottom_offset * 2;
const croppedWidth = encodedWidth - cropLeft - cropRight;
const croppedHeight = encodedHeight - cropTop - cropBottom;
return {
pictureParameterSet,
sequenceParameterSet,
profileIndex,
constraintSet,
levelIndex,
encodedWidth,
encodedHeight,
cropLeft,
cropRight,
cropTop,
cropBottom,
croppedWidth,
croppedHeight
};
}
function getSubWidthC(chroma_format_idc) {
switch (chroma_format_idc) {
case 0:
case 3:
return 1;
case 1:
case 2:
return 2;
default:
throw new Error("Invalid chroma_format_idc");
}
}
function getSubHeightC(chroma_format_idc) {
switch (chroma_format_idc) {
case 0:
case 2:
case 3:
return 1;
case 1:
return 2;
default:
throw new Error("Invalid chroma_format_idc");
}
}
function h265ParseNaluHeader(nalu) {
const reader = new NaluSodbBitReader(nalu);
if (reader.next() !== 0) {
throw new Error("Invalid NALU header");
}
const nal_unit_type = reader.read(6);
const nuh_layer_id = reader.read(6);
const nuh_temporal_id_plus1 = reader.read(3);
return {
nal_unit_type,
nuh_layer_id,
nuh_temporal_id_plus1
};
}
function h265ParseVideoParameterSet(nalu) {
const reader = new NaluSodbBitReader(nalu);
const vps_video_parameter_set_id = reader.read(4);
const vps_base_layer_internal_flag = !!reader.next();
const vps_base_layer_available_flag = !!reader.next();
const vps_max_layers_minus1 = reader.read(6);
const vps_max_sub_layers_minus1 = reader.read(3);
const vps_temporal_id_nesting_flag = !!reader.next();
reader.skip(16);
const profileTierLevel = h265ParseProfileTierLevel(reader, true, vps_max_sub_layers_minus1);
const vps_sub_layer_ordering_info_present_flag = !!reader.next();
const vps_max_dec_pic_buffering_minus1 = [];
const vps_max_num_reorder_pics = [];
const vps_max_latency_increase_plus1 = [];
for (let i = vps_sub_layer_ordering_info_present_flag ? 0 : vps_max_sub_layers_minus1; i <= vps_max_sub_layers_minus1; i += 1) {
vps_max_dec_pic_buffering_minus1[i] = reader.decodeExponentialGolombNumber();
vps_max_num_reorder_pics[i] = reader.decodeExponentialGolombNumber();
vps_max_latency_increase_plus1[i] = reader.decodeExponentialGolombNumber();
}
const vps_max_layer_id = reader.read(6);
const vps_num_layer_sets_minus1 = reader.decodeExponentialGolombNumber();
const layer_id_included_flag = [];
for (let i = 1; i <= vps_num_layer_sets_minus1; i += 1) {
layer_id_included_flag[i] = [];
for (let j = 0; j <= vps_max_layer_id; j += 1) {
layer_id_included_flag[i][j] = !!reader.next();
}
}
const vps_timing_info_present_flag = !!reader.next();
let vps_num_units_in_tick;
let vps_time_scale;
let vps_poc_proportional_to_timing_flag;
let vps_num_ticks_poc_diff_one_minus1;
let vps_num_hrd_parameters;
let hrd_layer_set_idx;
let cprms_present_flag;
let hrdParameters;
if (vps_timing_info_present_flag) {
vps_num_units_in_tick = reader.read(32);
vps_time_scale = reader.read(32);
vps_poc_proportional_to_timing_flag = !!reader.next();
if (vps_poc_proportional_to_timing_flag) {
vps_num_ticks_poc_diff_one_minus1 = reader.decodeExponentialGolombNumber();
}
vps_num_hrd_parameters = reader.decodeExponentialGolombNumber();
hrd_layer_set_idx = [];
cprms_present_flag = [true];
hrdParameters = [];
for (let i = 0; i < vps_num_hrd_parameters; i += 1) {
hrd_layer_set_idx[i] = reader.decodeExponentialGolombNumber();
if (i > 0) {
cprms_present_flag[i] = !!reader.next();
}
hrdParameters[i] = h265ParseHrdParameters(reader, cprms_present_flag[i], vps_max_sub_layers_minus1);
}
}
const vps_extension_flag = !!reader.next();
return {
vps_video_parameter_set_id,
vps_base_layer_internal_flag,
vps_base_layer_available_flag,
vps_max_layers_minus1,
vps_max_sub_layers_minus1,
vps_temporal_id_nesting_flag,
profileTierLevel,
vps_sub_layer_ordering_info_present_flag,
vps_max_dec_pic_buffering_minus1,
vps_max_num_reorder_pics,
vps_max_latency_increase_plus1,
vps_max_layer_id,
vps_num_layer_sets_minus1,
layer_id_included_flag,
vps_timing_info_present_flag,
vps_num_units_in_tick,
vps_time_scale,
vps_poc_proportional_to_timing_flag,
vps_num_ticks_poc_diff_one_minus1,
vps_num_hrd_parameters,
hrd_layer_set_idx,
cprms_present_flag,
hrdParameters,
vps_extension_flag
};
}
function h265ParseSequenceParameterSet(nalu) {
const reader = new NaluSodbBitReader(nalu);
const sps_video_parameter_set_id = reader.read(4);
const sps_max_sub_layers_minus1 = reader.read(3);
const sps_temporal_id_nesting_flag = !!reader.next();
const profileTierLevel = h265ParseProfileTierLevel(reader, true, sps_max_sub_layers_minus1);
const sps_seq_parameter_set_id = reader.decodeExponentialGolombNumber();
const chroma_format_idc = reader.decodeExponentialGolombNumber();
let separate_colour_plane_flag;
if (chroma_format_idc === 3) {
separate_colour_plane_flag = !!reader.next();
}
const pic_width_in_luma_samples = reader.decodeExponentialGolombNumber();
const pic_height_in_luma_samples = reader.decodeExponentialGolombNumber();
const conformance_window_flag = !!reader.next();
let conf_win_left_offset;
let conf_win_right_offset;
let conf_win_top_offset;
let conf_win_bottom_offset;
if (conformance_window_flag) {
conf_win_left_offset = reader.decodeExponentialGolombNumber();
conf_win_right_offset = reader.decodeExponentialGolombNumber();
conf_win_top_offset = reader.decodeExponentialGolombNumber();
conf_win_bottom_offset = reader.decodeExponentialGolombNumber();
}
const bit_depth_luma_minus8 = reader.decodeExponentialGolombNumber();
const bit_depth_chroma_minus8 = reader.decodeExponentialGolombNumber();
const log2_max_pic_order_cnt_lsb_minus4 = reader.decodeExponentialGolombNumber();
const sps_max_dec_pic_buffering_minus1 = [];
const sps_max_num_reorder_pics = [];
const sps_max_latency_increase_plus1 = [];
const sps_sub_layer_ordering_info_present_flag = !!reader.next();
for (let i = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; i <= sps_max_sub_layers_minus1; i += 1) {
sps_max_dec_pic_buffering_minus1[i] = reader.decodeExponentialGolombNumber();
sps_max_num_reorder_pics[i] = reader.decodeExponentialGolombNumber();
sps_max_latency_increase_plus1[i] = reader.decodeExponentialGolombNumber();
}
const log2_min_luma_coding_block_size_minus3 = reader.decodeExponentialGolombNumber();
const log2_diff_max_min_luma_coding_block_size = reader.decodeExponentialGolombNumber();
const log2_min_luma_transform_block_size_minus2 = reader.decodeExponentialGolombNumber();
const log2_diff_max_min_luma_transform_block_size = reader.decodeExponentialGolombNumber();
const max_transform_hierarchy_depth_inter = reader.decodeExponentialGolombNumber();
const max_transform_hierarchy_depth_intra = reader.decodeExponentialGolombNumber();
const scaling_list_enabled_flag = !!reader.next();
let sps_scaling_list_data_present_flag;
let scalingListData;
if (scaling_list_enabled_flag) {
sps_scaling_list_data_present_flag = !!reader.next();
if (sps_scaling_list_data_present_flag) {
scalingListData = h265ParseScalingListData(reader);
}
}
const amp_enabled_flag = !!reader.next();
const sample_adaptive_offset_enabled_flag = !!reader.next();
const pcm_enabled_flag = !!reader.next();
let pcm_sample_bit_depth_luma_minus1;
let pcm_sample_bit_depth_chroma_minus1;
let log2_min_pcm_luma_coding_block_size_minus3;
let log2_diff_max_min_pcm_luma_coding_block_size;
let pcm_loop_filter_disabled_flag;
if (pcm_enabled_flag) {
pcm_sample_bit_depth_luma_minus1 = reader.read(4);
pcm_sample_bit_depth_chroma_minus1 = reader.read(4);
log2_min_pcm_luma_coding_block_size_minus3 = reader.decodeExponentialGolombNumber();
log2_diff_max_min_pcm_luma_coding_block_size = reader.decodeExponentialGolombNumber();
pcm_loop_filter_disabled_flag = !!reader.next();
}
const num_short_term_ref_pic_sets = reader.decodeExponentialGolombNumber();
const shortTermRefPicSets = [];
for (let i = 0; i < num_short_term_ref_pic_sets; i += 1) {
shortTermRefPicSets[i] = h265ParseShortTermReferencePictureSet(reader, i, num_short_term_ref_pic_sets, shortTermRefPicSets);
}
const long_term_ref_pics_present_flag = !!reader.next();
let num_long_term_ref_pics_sps;
let lt_ref_pic_poc_lsb_sps;
let used_by_curr_pic_lt_sps_flag;
if (long_term_ref_pics_present_flag) {
num_long_term_ref_pics_sps = reader.decodeExponentialGolombNumber();
lt_ref_pic_poc_lsb_sps = [];
used_by_curr_pic_lt_sps_flag = [];
for (let i = 0; i < num_long_term_ref_pics_sps; i += 1) {
lt_ref_pic_poc_lsb_sps[i] = reader.read(log2_max_pic_order_cnt_lsb_minus4 + 4);
used_by_curr_pic_lt_sps_flag[i] = !!reader.next();
}
}
const sps_temporal_mvp_enabled_flag = !!reader.next();
const strong_intra_smoothing_enabled_flag = !!reader.next();
const vui_parameters_present_flag = !!reader.next();
let vuiParameters;
if (vui_parameters_present_flag) {
vuiParameters = h265ParseVuiParameters(reader, sps_max_sub_layers_minus1);
}
const sps_extension_present_flag = !!reader.next();
let sps_range_extension_flag;
let sps_multilayer_extension_flag;
let sps_3d_extension_flag;
let sps_scc_extension_flag;
let sps_extension_4bits;
if (sps_extension_present_flag) {
sps_range_extension_flag = !!reader.next();
sps_multilayer_extension_flag = !!reader.next();
sps_3d_extension_flag = !!reader.next();
sps_scc_extension_flag = !!reader.next();
sps_extension_4bits = reader.read(4);
}
if (sps_range_extension_flag) {
throw new Error("Not implemented");
}
let spsMultilayerExtension;
if (sps_multilayer_extension_flag) {
spsMultilayerExtension = h265ParseSpsMultilayerExtension(reader);
}
let sps3dExtension;
if (sps_3d_extension_flag) {
sps3dExtension = h265ParseSps3dExtension(reader);
}
if (sps_scc_extension_flag) {
throw new Error("Not implemented");
}
let sps_extension_data_flag;
if (sps_extension_4bits) {
sps_extension_data_flag = [];
let i = 0;
while (!reader.ended) {
sps_extension_data_flag[i] = !!reader.next();
i += 1;
}
}
return {
sps_video_parameter_set_id,
sps_max_sub_layers_minus1,
sps_temporal_id_nesting_flag,
profileTierLevel,
sps_seq_parameter_set_id,
chroma_format_idc,
separate_colour_plane_flag,
pic_width_in_luma_samples,
pic_height_in_luma_samples,
conformance_window_flag,
conf_win_left_offset,
conf_win_right_offset,
conf_win_top_offset,
conf_win_bottom_offset,
bit_depth_luma_minus8,
bit_depth_chroma_minus8,
log2_max_pic_order_cnt_lsb_minus4,
sps_sub_layer_ordering_info_present_flag,
sps_max_dec_pic_buffering_minus1,
sps_max_num_reorder_pics,
sps_max_latency_increase_plus1,
log2_min_luma_coding_block_size_minus3,
log2_diff_max_min_luma_coding_block_size,
log2_min_luma_transform_block_size_minus2,
log2_diff_max_min_luma_transform_block_size,
max_transform_hierarchy_depth_inter,
max_transform_hierarchy_depth_intra,
scaling_list_enabled_flag,
sps_scaling_list_data_present_flag,
scalingListData,
amp_enabled_flag,
sample_adaptive_offset_enabled_flag,
pcm_enabled_flag,
pcm_sample_bit_depth_luma_minus1,
pcm_sample_bit_depth_chroma_minus1,
log2_min_pcm_luma_coding_block_size_minus3,
log2_diff_max_min_pcm_luma_coding_block_size,
pcm_loop_filter_disabled_flag,
num_short_term_ref_pic_sets,
shortTermRefPicSets,
long_term_ref_pics_present_flag,
num_long_term_ref_pics_sps,
lt_ref_pic_poc_lsb_sps,
used_by_curr_pic_lt_sps_flag,
sps_temporal_mvp_enabled_flag,
strong_intra_smoothing_enabled_flag,
vui_parameters_present_flag,
vuiParameters,
sps_extension_present_flag,
sps_range_extension_flag,
sps_multilayer_extension_flag,
sps_3d_extension_flag,
sps_scc_extension_flag,
sps_extension_4bits,
spsMultilayerExtension,
sps3dExtension,
sps_extension_data_flag
};
}
function h265ParseProfileTier(reader) {
const profile_space = reader.read(2);
const tier_flag = !!reader.next();
const profile_idc = reader.read(5);
const profileCompatibilitySet = reader.peekBytes(4);
const profile_compatibility_flag = [];
for (let j = 0; j < 32; j += 1) {
profile_compatibility_flag[j] = !!reader.next();
}
const constraintSet = reader.peekBytes(6);
const progressive_source_flag = !!reader.next();
const interlaced_source_flag = !!reader.next();
const non_packed_constraint_flag = !!reader.next();
const frame_only_constraint_flag = !!reader.next();
let max_12bit_constraint_flag;
let max_10bit_constraint_flag;
let max_8bit_constraint_flag;
let max_422chroma_constraint_flag;
let max_420chroma_constraint_flag;
let max_monochrome_constraint_flag;
let intra_constraint_flag;
let one_picture_only_constraint_flag;
let lower_bit_rate_constraint_flag;
let max_14bit_constraint_flag;
if (profile_idc === 4 || profile_compatibility_flag[4] || profile_idc === 5 || profile_compatibility_flag[5] || profile_idc === 6 || profile_compatibility_flag[6] || profile_idc === 7 || profile_compatibility_flag[7] || profile_idc === 8 || profile_compatibility_flag[8] || profile_idc === 9 || profile_compatibility_flag[9] || profile_idc === 10 || profile_compatibility_flag[10] || profile_idc === 11 || profile_compatibility_flag[11]) {
max_12bit_constraint_flag = !!reader.next();
max_10bit_constraint_flag = !!reader.next();
max_8bit_constraint_flag = !!reader.next();
max_422chroma_constraint_flag = !!reader.next();
max_420chroma_constraint_flag = !!reader.next();
max_monochrome_constraint_flag = !!reader.next();
intra_constraint_flag = !!reader.next();
one_picture_only_constraint_flag = !!reader.next();
lower_bit_rate_constraint_flag = !!reader.next();
if (profile_idc === 5 || profile_compatibility_flag[5] || profile_idc === 9 || profile_compatibility_flag[9] || profile_idc === 10 || profile_compatibility_flag[10] || profile_idc === 11 || profile_compatibility_flag[11]) {
max_14bit_constraint_flag = !!reader.next();
reader.skip(33);
} else {
reader.skip(34);
}
} else if (profile_idc === 2 || profile_compatibility_flag[2]) {
reader.skip(7);
one_picture_only_constraint_flag = !!reader.next();
reader.skip(35);
} else {
reader.skip(43);
}
let inbld_flag;
if (profile_idc === 1 || profile_compatibility_flag[1] || profile_idc === 2 || profile_compatibility_flag[2] || profile_idc === 3 || profile_compatibility_flag[3] || profile_idc === 4 || profile_compatibility_flag[4] || profile_idc === 5 || profile_compatibility_flag[5] || profile_idc === 9 || profile_compatibility_flag[9] || profile_idc === 11 || profile_compatibility_flag[11]) {
inbld_flag = !!reader.next();
} else {
reader.skip(1);
}
return {
profile_space,
tier_flag,
profile_idc,
profileCompatibilitySet,
profile_compatibility_flag,
constraintSet,
progressive_source_flag,
interlaced_source_flag,
non_packed_constraint_flag,
frame_only_constraint_flag,
max_12bit_constraint_flag,
max_10bit_constraint_flag,
max_8bit_constraint_flag,
max_422chroma_constraint_flag,
max_420chroma_constraint_flag,
max_monochrome_constraint_flag,
intra_constraint_flag,
one_picture_only_constraint_flag,
lower_bit_rate_constraint_flag,
max_14bit_constraint_flag,
inbld_flag
};
}
function h265ParseProfileTierLevel(reader, profilePresentFlag, maxNumSubLayersMinus1) {
let generalProfileTier;
{
generalProfileTier = h265ParseProfileTier(reader);
}
const general_level_idc = reader.read(8);
const sub_layer_profile_present_flag = [];
const sub_layer_level_present_flag = [];
for (let i = 0; i < maxNumSubLayersMinus1; i += 1) {
sub_layer_profile_present_flag[i] = !!reader.next();
sub_layer_level_present_flag[i] = !!reader.next();
}
if (maxNumSubLayersMinus1 > 0) {
for (let i = maxNumSubLayersMinus1; i < 8; i += 1) {
reader.read(2);
}
}
const subLayerProfileTier = [];
const sub_layer_level_idc = [];
for (let i = 0; i < maxNumSubLayersMinus1; i += 1) {
if (sub_layer_profile_present_flag[i]) {
subLayerProfileTier[i] = h265ParseProfileTier(reader);
}
if (sub_layer_level_present_flag[i]) {
sub_layer_level_idc[i] = reader.read(8);
}
}
return {
generalProfileTier,
general_level_idc,
sub_layer_profile_present_flag,
sub_layer_level_present_flag,
subLayerProfileTier,
sub_layer_level_idc
};
}
function h265ParseScalingListData(reader) {
const scaling_list = [];
for (let sizeId = 0; sizeId < 4; sizeId += 1) {
scaling_list[sizeId] = [];
for (let matrixId = 0; matrixId < 6; matrixId += sizeId === 3 ? 3 : 1) {
const scaling_list_pred_mode_flag = !!reader.next();
if (!scaling_list_pred_mode_flag) {
reader.decodeExponentialGolombNumber();
} else {
let nextCoef = 8;
const coefNum = Math.min(64, 1 << 4 + (sizeId << 1));
if (sizeId > 1) {
const scaling_list_dc_coef_minus8 = reader.decodeExponentialGolombNumber();
nextCoef = scaling_list_dc_coef_minus8 + 8;
}
scaling_list[sizeId][matrixId] = [];
for (let i = 0; i < coefNum; i += 1) {
const scaling_list_delta_coef = reader.decodeExponentialGolombNumber();
nextCoef = (nextCoef + scaling_list_delta_coef + 256) % 256;
scaling_list[sizeId][matrixId][i] = nextCoef;
}
}
}
}
return scaling_list;
}
function h265ParseShortTermReferencePictureSet(reader, stRpsIdx, num_short_term_ref_pic_sets, sets) {
let inter_ref_pic_set_prediction_flag = false;
if (stRpsIdx !== 0) {
inter_ref_pic_set_prediction_flag = !!reader.next();
}
let delta_idx_minus1 = 0;
let delta_rps_sign = false;
let abs_delta_rps_minus1 = 0;
const used_by_curr_pic_flag = [];
const use_delta_flag = [];
let num_negative_pics = 0;
let num_positive_pics = 0;
const delta_poc_s0_minus1 = [];
const used_by_curr_pic_s0_flag = [];
const delta_poc_s1_minus1 = [];
const used_by_curr_pic_s1_flag = [];
if (inter_ref_pic_set_prediction_flag) {
if (stRpsIdx === num_short_term_ref_pic_sets) {
delta_idx_minus1 = reader.decodeExponentialGolombNumber();
}
delta_rps_sign = !!reader.next();
abs_delta_rps_minus1 = reader.decodeExponentialGolombNumber();
const RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1);
const RefRps = sets[RefRpsIdx];
const NumDeltaPocs_RefRpsIdx = RefRps.num_negative_pics + RefRps.num_positive_pics;
for (let j = 0; j <= NumDeltaPocs_RefRpsIdx; j += 1) {
used_by_curr_pic_flag[j] = !!reader.next();
if (!used_by_curr_pic_flag[j]) {
use_delta_flag[j] = !!reader.next();
} else {
use_delta_flag[j] = true;
}
}
const DeltaRps = (1 - 2 * Number(delta_rps_sign)) * (abs_delta_rps_minus1 + 1);
const RefPocS0 = [];
const RefPocS1 = [];
const pocS0 = [];
const pocS1 = [];
let dPoc = 0;
for (let i2 = 0; i2 < RefRps.num_negative_pics; i2 += 1) {
dPoc -= RefRps.delta_poc_s0_minus1[i2] + 1;
RefPocS0[i2] = dPoc;
}
dPoc = 0;
for (let i2 = 0; i2 < RefRps.num_positive_pics; i2 += 1) {
dPoc += RefRps.delta_poc_s1_minus1[i2] + 1;
RefPocS1[i2] = dPoc;
}
let i = 0;
if (RefRps.num_positive_pics > 0) {
for (let j = RefRps.num_positive_pics - 1; j >= 0; j -= 1) {
dPoc = RefPocS1[j] + DeltaRps;
if (dPoc < 0 && use_delta_flag[RefRps.num_negative_pics + j]) {
pocS0[i] = dPoc;
used_by_curr_pic_s0_flag[i] = used_by_curr_pic_flag[RefRps.num_negative_pics + j];
i += 1;
}
}
}
if (DeltaRps < 0 && use_delta_flag[NumDeltaPocs_RefRpsIdx]) {
pocS0[i] = DeltaRps;
used_by_curr_pic_s0_flag[i] = used_by_curr_pic_flag[NumDeltaPocs_RefRpsIdx];
i += 1;
}
for (let j = 0; j < RefRps.num_negative_pics; j += 1) {
dPoc = RefPocS0[j] + DeltaRps;
if (dPoc < 0 && use_delta_flag[j]) {
pocS0[i] = dPoc;
used_by_curr_pic_s0_flag[i] = used_by_curr_pic_flag[j];
i += 1;
}
}
num_negative_pics = i;
let prev = 0;
for (i = 0; i < num_negative_pics; i += 1) {
const current = pocS0[i];
delta_poc_s0_minus1[i] = -(current - prev - 1);
prev = current;
}
i = 0;
if (RefRps.num_negative_pics > 0) {
for (let j = RefRps.num_negative_pics - 1; j >= 0; j -= 1) {
dPoc = RefPocS0[j] + DeltaRps;
if (dPoc > 0 && use_delta_flag[j]) {
pocS1[i] = dPoc;
used_by_curr_pic_s1_flag[i] = used_by_curr_pic_flag[j];
i += 1;
}
}
}
if (DeltaRps > 0 && use_delta_flag[NumDeltaPocs_RefRpsIdx]) {
pocS1[i] = DeltaRps;
used_by_curr_pic_s1_flag[i] = used_by_curr_pic_flag[NumDeltaPocs_RefRpsIdx];
i += 1;
}
for (let j = 0; j < RefRps.num_positive_pics; j += 1) {
dPoc = RefPocS1[j] + DeltaRps;
if (dPoc > 0 && use_delta_flag[RefRps.num_negative_pics + j]) {
pocS1[i] = dPoc;
used_by_curr_pic_s1_flag[i] = used_by_curr_pic_flag[RefRps.num_negative_pics + j];
i += 1;
}
}
num_positive_pics = i;
prev = 0;
for (i = 0; i < num_positive_pics; i += 1) {
const current = pocS1[i];
delta_poc_s1_minus1[i] = current - prev - 1;
prev = current;
}
} else {
num_negative_pics = reader.decodeExponentialGolombNumber();
num_positive_pics = reader.decodeExponentialGolombNumber();
for (let i = 0; i < num_negative_pics; i += 1) {
delta_poc_s0_minus1[i] = reader.decodeExponentialGolombNumber();
used_by_curr_pic_s0_flag[i] = !!reader.next();
}
for (let i = 0; i < num_positive_pics; i += 1) {
delta_poc_s1_minus1[i] = reader.decodeExponentialGolombNumber();
used_by_curr_pic_s1_flag[i] = !!reader.next();
}
}
return {
stRpsIdx,
num_short_term_ref_pic_sets,
inter_ref_pic_set_prediction_flag,
delta_idx_minus1,
delta_rps_sign,
abs_delta_rps_minus1,
used_by_curr_pic_flag,
use_delta_flag,
num_negative_pics,
num_positive_pics,
delta_poc_s0_minus1,
used_by_curr_pic_s0_flag,
delta_poc_s1_minus1,
used_by_curr_pic_s1_flag
};
}
const H265AspectRatioIndicator = {
Extended: 255
};
function h265ParseVuiParameters(reader, sps_max_sub_layers_minus1) {
const aspect_ratio_info_present_flag = !!reader.next();
let aspect_ratio_idc;
let sar_width;
let sar_height;
if (aspect_ratio_info_present_flag) {
aspect_ratio_idc = reader.read(8);
if (aspect_ratio_idc === H265AspectRatioIndicator.Extended) {
sar_width = reader.read(16);
sar_height = reader.read(16);
}
}
const overscan_info_present_flag = !!reader.next();
let overscan_appropriate_flag;
if (overscan_info_present_flag) {
overscan_appropriate_flag = !!reader.next();
}
const video_signal_type_present_flag = !!reader.next();
let video_format;
let video_full_range_flag;
let colour_description_present_flag;
let colour_primaries;
let transfer_characteristics;
let matrix_coeffs;
if (video_signal_type_present_flag) {
video_format = reader.read(3);
video_full_range_flag = !!reader.next();
colour_description_present_flag = !!reader.next();
if (colour_description_present_flag) {
colour_primaries = reader.read(8);
transfer_characteristics = reader.read(8);
matrix_coeffs = reader.read(8);
}
}
const chroma_loc_info_present_flag = !!reader.next();
let chroma_sample_loc_type_top_field;
let chroma_sample_loc_type_bottom_field;
if (chroma_loc_info_present_flag) {
chroma_sample_loc_type_top_field = reader.decodeExponentialGolombNumber();
chroma_sample_loc_type_bottom_field = reader.decodeExponentialGolombNumber();
}
const neutral_chroma_indication_flag = !!reader.next();
const field_seq_flag = !!reader.next();
const frame_field_info_present_flag = !!reader.next();
const default_display_window_flag = !!reader.next();
let def_disp_win_left_offset;
let def_disp_win_right_offset;
let def_disp_win_top_offset;
let def_disp_win_bottom_offset;
if (default_display_window_flag) {
def_disp_win_left_offset = reader.decodeExponentialGolombNumber();
def_disp_win_right_offset = reader.decodeExponentialGolombNumber();
def_disp_win_top_offset = reader.decodeExponentialGolombNumber();
def_disp_win_bottom_offset = reader.decodeExponentialGolombNumber();
}
const vui_timing_info_present_flag = !!reader.next();
let vui_num_units_in_tick;
let vui_time_scale;
let vui_poc_proportional_to_timing_flag;
let vui_num_ticks_poc_diff_one_minus1;
let vui_hrd_parameters_present_flag;
let vui_hrd_parameters;
if (vui_timing_info_present_flag) {
vui_num_units_in_tick = reader.read(32);
vui_time_scale = reader.read(32);
vui_poc_proportional_to_timing_flag = !!reader.next();
if (vui_poc_proportional_to_timing_flag) {
vui_num_ticks_poc_diff_one_minus1 = reader.decodeExponentialGolombNumber();
}
vui_hrd_parameters_present_flag = !!reader.next();
if (vui_hrd_parameters_present_flag) {
vui_hrd_parameters = h265ParseHrdParameters(reader, true, sps_max_sub_layers_minus1);
}
}
const bitstream_restriction_flag = !!reader.next();
let tiles_fixed_structure_flag;
let motion_vectors_over_pic_boundaries_flag;
let restricted_ref_pic_lists_flag;
let min_spatial_segmentation_idc;
let max_bytes_per_pic_denom;
let max_bits_per_min_cu_denom;
let log2_max_mv_length_horizontal;
let log2_max_mv_length_vertical;
if (bitstream_restriction_flag) {
tiles_fixed_structure_flag = !!reader.next();
motion_vectors_over_pic_boundaries_flag = !!reader.next();
restricted_ref_pic_lists_flag = !!reader.next();
min_spatial_segmentation_idc = reader.decodeExponentialGolombNumber();
max_bytes_per_pic_denom = reader.decodeExponentialGolombNumber();
max_bits_per_min_cu_denom = reader.decodeExponentialGolombNumber();
log2_max_mv_length_horizontal = reader.decodeExponentialGolombNumber();
log2_max_mv_length_vertical = reader.decodeExponentialGolombNumber();
}
return {
aspect_ratio_info_present_flag,
aspect_ratio_idc,
sar_width,
sar_height,
overscan_info_present_flag,
overscan_appropriate_flag,
video_signal_type_present_flag,
video_format,
video_full_range_flag,
colour_description_present_flag,
colour_primaries,
transfer_characteristics,
matrix_coeffs,
chroma_loc_info_present_flag,
chroma_sample_loc_type_top_field,
chroma_sample_loc_type_bottom_field,
neutral_chroma_indication_flag,
field_seq_flag,
frame_field_info_present_flag,
default_display_window_flag,
def_disp_win_left_offset,
def_disp_win_right_offset,
def_disp_win_top_offset,
def_disp_win_bottom_offset,
vui_timing_info_present_flag,
vui_num_units_in_tick,
vui_time_scale,
vui_poc_proportional_to_timing_flag,
vui_num_ticks_poc_diff_one_minus1,
vui_hrd_parameters_present_flag,
vui_hrd_parameters,
bitstream_restriction_flag,
tiles_fixed_structure_flag,
motion_vectors_over_pic_boundaries_flag,
restricted_ref_pic_lists_flag,
min_spatial_segmentation_idc,
max_bytes_per_pic_denom,
max_bits_per_min_cu_denom,
log2_max_mv_length_horizontal,
log2_max_mv_length_vertical
};
}
function h265ParseHrdParameters(reader, commonInfPresentFlag, maxNumSubLayersMinus1) {
let nal_hrd_parameters_present_flag;
let vcl_hrd_parameters_present_flag;
let sub_pic_hrd_params_present_flag;
let tick_divisor_minus2;
let du_cpb_removal_delay_increment_length_minus1;
let sub_pic_cpb_params_in_pic_timing_sei_flag;
let dpb_output_delay_du_length_minus1;
let bit_rate_scale;
let cpb_size_scale;
let cpb_size_du_scale;
let initial_cpb_removal_delay_length_minus1;
let au_cpb_removal_delay_length_minus1;
let dpb_output_delay_length_minus1;
if (commonInfPresentFlag) {
nal_hrd_parameters_present_flag = !!reader.next();
vcl_hrd_parameters_present_flag = !!reader.next();
if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
sub_pic_hrd_params_present_flag = !!reader.next();
if (sub_pic_hrd_params_present_flag) {
tick_divisor_minus2 = reader.read(8);
du_cpb_removal_delay_increment_length_minus1 = reader.read(5);
sub_pic_cpb_params_in_pic_timing_sei_flag = !!reader.next();
dpb_output_delay_du_length_minus1 = reader.read(5);
}
bit_rate_scale = reader.read(4);
cpb_size_scale = reader.read(4);
if (sub_pic_hrd_params_present_flag) {
cpb_size_du_scale = reader.read(4);
}
initial_cpb_removal_delay_length_minus1 = reader.read(5);
au_cpb_removal_delay_length_minus1 = reader.read(5);
dpb_output_delay_length_minus1 = reader.read(5);
}
}
const fixed_pic_rate_general_flag = [];
const fixed_pic_rate_within_cvs_flag = [];
const elemental_duration_in_tc_minus1 = [];
const low_delay_hrd_flag = [];
const cpb_cnt_minus1 = [];
const nalHrdParameters = [];
const vclHrdParameters = [];
for (let i = 0; i <= maxNumSubLayersMinus1; i += 1) {
fixed_pic_rate_general_flag[i] = !!reader.next();
if (!fixed_pic_rate_general_flag[i]) {
fixed_pic_rate_within_cvs_flag[i] = !!reader.next();
}
if (fixed_pic_rate_within_cvs_flag[i]) {
elemental_duration_in_tc_minus1[i] = reader.decodeExponentialGolombNumber();
} else {
low_delay_hrd_flag[i] = !!reader.next();
}
if (!low_delay_hrd_flag[i]) {
cpb_cnt_minus1[i] = reader.decodeExponentialGolombNumber();
}
if (nal_hrd_parameters_present_flag) {
nalHrdParameters[i] = h265ParseSubLayerHrdParameters(reader, i, getCpbCnt(cpb_cnt_minus1[i]));
}
if (vcl_hrd_parameters_present_flag) {
vclHrdParameters[i] = h265ParseSubLayerHrdParameters(reader, i, getCpbCnt(cpb_cnt_minus1[i]));
}
}
return {
nal_hrd_parameters_present_flag,
vcl_hrd_parameters_present_flag,
sub_pic_hrd_params_present_flag,
tick_divisor_minus2,
du_cpb_removal_delay_increment_length_minus1,
sub_pic_cpb_params_in_pic_timing_sei_flag,
dpb_output_delay_du_length_minus1,
bit_rate_scale,
cpb_size_scale,
cpb_size_du_scale,
initial_cpb_removal_delay_length_minus1,
au_cpb_removal_delay_length_minus1,
dpb_output_delay_length_minus1,
fixed_pic_rate_general_flag,
fixed_pic_rate_within_cvs_flag,
elemental_duration_in_tc_minus1,
low_delay_hrd_flag,
cpb_cnt_minus1,
nalHrdParameters,
vclHrdParameters
};
}
function h265ParseSubLayerHrdParameters(reader, subLayerId, CpbCnt) {
const bit_rate_value_minus1 = [];
const cpb_size_value_minus1 = [];
const cpb_size_du_value_minus1 = [];
const bit_rate_du_value_minus1 = [];
const cbr_flag = [];
for (let i = 0; i < CpbCnt; i += 1) {
bit_rate_value_minus1[i] = reader.decodeExponentialGolombNumber();
cpb_size_value_minus1[i] = reader.decodeExponentialGolombNumber();
if (subLayerId > 0) {
cbr_flag[i] = !!reader.next();
}
}
return {
bit_rate_value_minus1,
cpb_size_value_minus1,
cpb_size_du_value_minus1,
bit_rate_du_value_minus1,
cbr_flag
};
}
function getCpbCnt(cpb_cnt_minus_1) {
return cpb_cnt_minus_1 + 1;
}
function h265SearchConfiguration(buffer) {
let videoParameterSet;
let sequenceParameterSet;
let pictureParameterSet;
let count = 0;
for (const nalu of annexBSplitNalu(buffer)) {
const header = h265ParseNaluHeader(nalu);
const raw = {
...header,
data: nalu,
rbsp: nalu.subarray(2)
};
switch (header.nal_unit_type) {
case 32:
videoParameterSet = raw;
break;
case 33:
sequenceParameterSet = raw;
break;
case 34:
pictureParameterSet = raw;
break;
default:
continue;
}
count += 1;
if (count === 3) {
return {
videoParameterSet,
sequenceParameterSet,
pictureParameterSet
};
}
}
throw new Error("Invalid data");
}
function h265ParseSpsMultilayerExtension(reader) {
const inter_view_mv_vert_constraint_flag = !!reader.next();
return {
inter_view_mv_vert_constraint_flag
};
}
function h265ParseSps3dExtension(reader) {
const iv_di_mc_enabled_flag = [];
const iv_mv_scal_enabled_flag = [];
iv_di_mc_enabled_flag[0] = !!reader.next();
iv_mv_scal_enabled_flag[0] = !!reader.next();
const log2_ivmc_sub_pb_size_minus3 = reader.decodeExponentialGolombNumber();
const iv_res_pred_enabled_flag = !!reader.next();
const depth_ref_enabled_flag = !!reader.next();
const vsp_mc_enabled_flag = !!reader.next();
const dbbp_enabled_flag = !!reader.next();
iv_di_mc_enabled_flag[1] = !!reader.next();
iv_mv_scal_enabled_flag[1] = !!reader.next();
const tex_mc_enabled_flag = !!reader.next();
const log2_texmc_sub_pb_size_minus3 = reader.decodeExponentialGolombNumber();
const intra_contour_enabled_flag = !!reader.next();
const intra_dc_only_wedge_enabled_flag = !!reader.next();
const cqt_cu_part_pred_enabled_flag = !!reader.next();
const inter_dc_only_enabled_flag = !!reader.next();
const skip_intra_enabled_flag = !!reader.next();
return {
iv_di_mc_enabled_flag,
iv_mv_scal_enabled_flag,
log2_ivmc_sub_pb_size_minus3,
iv_res_pred_enabled_flag,
depth_ref_enabled_flag,
vsp_mc_enabled_flag,
dbbp_enabled_flag,
tex_mc_enabled_flag,
log2_texmc_sub_pb_size_minus3,
intra_contour_enabled_flag,
intra_dc_only_wedge_enabled_flag,
cqt_cu_part_pred_enabled_flag,
inter_dc_only_enabled_flag,
skip_intra_enabled_flag
};
}
function h265ParseConfiguration(data) {
const { videoParameterSet, sequenceParameterSet, pictureParameterSet } = h265SearchConfiguration(data);
const { profileTierLevel: { generalProfileTier: { profile_space: generalProfileSpace, tier_flag: generalTierFlag, profile_idc: generalProfileIndex, profileCompatibilitySet: generalProfileCompatibilitySet, constraintSet: generalConstraintSet }, general_level_idc: generalLevelIndex } } = h265ParseVideoParameterSet(videoParameterSet.rbsp);
const { chroma_format_idc, pic_width_in_luma_samples: encodedWidth, pic_height_in_luma_samples: encodedHeight, conf_win_left_offset: cropLeft = 0, conf_win_right_offset: cropRight = 0, conf_win_top_offset: cropTop = 0, conf_win_bottom_offset: cropBottom = 0 } = h265ParseSequenceParameterSet(sequenceParameterSet.rbsp);
const SubWidthC = getSubWidthC(chroma_format_idc);
const SubHeightC = getSubHeightC(chroma_format_idc);
const croppedWidth = encodedWidth - SubWidthC * (cropLeft + cropRight);
const croppedHeight = encodedHeight - SubHeightC * (cropTop + cropBottom);
return {
videoParameterSet,
sequenceParameterSet,
pictureParameterSet,
generalProfileSpace,
generalProfileIndex,
generalProfileCompatibilitySet,
generalTierFlag,
generalLevelIndex,
generalConstraintSet,
encodedWidth,
encodedHeight,
cropLeft,
cropRight,
cropTop,
cropBottom,
croppedWidth,
croppedHeight
};
}
exports.Av1 = Av1;
exports.BackOrScreenOnControlMessage = BackOrScreenOnControlMessage;
exports.DefaultServerPath = DefaultServerPath;
exports.EmptyControlMessage = EmptyControlMessage;
exports.H265AspectRatioIndicator = H265AspectRatioIndicator;
exports.InjectScrollControlMessage = InjectScrollControlMessage;
exports.InjectTouchControlMessage = InjectTouchControlMessage;
exports.NaluSodbBitReader = NaluSodbBitReader;
exports.ScrcpyAudioCodec = ScrcpyAudioCodec;
exports.ScrcpyControlMessageSerializer = ScrcpyControlMessageSerializer;
exports.ScrcpyControlMessageType = ScrcpyControlMessageType;
exports.ScrcpyControlMessageTypeMap = ScrcpyControlMessageTypeMap;
exports.ScrcpyControlMessageWriter = ScrcpyControlMessageWriter;
exports.ScrcpyDeviceMessageParsers = ScrcpyDeviceMessageParsers;
exports.ScrcpyInjectKeyCodeControlMessage = ScrcpyInjectKeyCodeControlMessage;
exports.ScrcpyInjectTextControlMessage = ScrcpyInjectTextControlMessage;
exports.ScrcpyOptions2_1 = ScrcpyOptions2_1;
exports.ScrcpySetDisplayPowerControlMessage = ScrcpySetDisplayPowerControlMessage;
exports.ScrcpyVideoCodecId = ScrcpyVideoCodecId;
exports.SetClipboardControlMessage = SetClipboardControlMessage;
exports.annexBSplitNalu = annexBSplitNalu;
exports.clamp = clamp;
exports.getSubHeightC = getSubHeightC;
exports.getSubWidthC = getSubWidthC;
exports.h264ParseConfiguration = h264ParseConfiguration;
exports.h264ParseSequenceParameterSet = h264ParseSequenceParameterSet;
exports.h264SearchConfiguration = h264SearchConfiguration;
exports.h265ParseConfiguration = h265ParseConfiguration;
exports.h265ParseHrdParameters = h265ParseHrdParameters;
exports.h265ParseNaluHeader = h265ParseNaluHeader;
exports.h265ParseScalingListData = h265ParseScalingListData;
exports.h265ParseSequenceParameterSet = h265ParseSequenceParameterSet;
exports.h265ParseShortTermReferencePictureSet = h265ParseShortTermReferencePictureSet;
exports.h265ParseSps3dExtension = h265ParseSps3dExtension;
exports.h265ParseSpsMultilayerExtension = h265ParseSpsMultilayerExtension;
exports.h265ParseSubLayerHrdParameters = h265ParseSubLayerHrdParameters;
exports.h265ParseVideoParameterSet = h265ParseVideoParameterSet;
exports.h265ParseVuiParameters = h265ParseVuiParameters;
exports.h265SearchConfiguration = h265SearchConfiguration;
exports.isScrcpyOptionValue = isScrcpyOptionValue;
exports.omit = omit;
exports.toScrcpyOptionValue = toScrcpyOptionValue;