consortium
Version:
Remote control and session sharing CLI for AI coding agents
2,761 lines • 88 kB
JavaScript
import { b as u8, u as u32, s as string, h as u16, i as getUint16, j as setUint16, c as u64, d as decodeUtf8, k as getUint32BigEndian, e as extend } from './string-BC-7T2zc.mjs';
import { s as struct, b as buffer, f as field, S as StructDeserializeStream, B as BufferedReadableStream } from './struct-deserialize-DqeMe-dl.mjs';
import { C as Consumable, P as PushReadableStream, b as PromiseResolver, T as TransformStream } from './consumable-GBIKq8FA.mjs';
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 = struct({ type: u8 }, { littleEndian: false });
const ScrcpyInjectKeyCodeControlMessage = /* @__PURE__ */ (() => struct({
type: u8(ScrcpyControlMessageType.InjectKeyCode),
action: u8(),
keyCode: u32(),
repeat: u32,
metaState: u32()
}, { littleEndian: false }))();
const ScrcpyInjectTextControlMessage = struct({ type: u8, text: 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 = struct({ type: u8, mode: u8() }, { littleEndian: false });
const ScrcpyStartAppControlMessage = struct({
type: u8,
name: string(u8)
}, { littleEndian: false });
const ScrcpyUHidInputControlMessage = /* @__PURE__ */ (() => struct({
type: u8(ScrcpyControlMessageType.UHidInput),
id: u16,
data: buffer(u16)
}, { littleEndian: false }))();
const ScrcpyUHidDestroyControlMessage = struct({ type: u8, id: 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.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 = struct({ content: string(u32) }, { littleEndian: false });
class ClipboardStream extends 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 = field(2, "byob", (source, { buffer, index, littleEndian }) => {
source = clamp(source, -1, 1);
source = source === 1 ? 65535 : source * 65536;
setUint16(buffer, index, source, littleEndian);
}, function* (then, reader, { littleEndian }) {
const data = yield* then(reader.readExactly(2));
const value = getUint16(data, 0, littleEndian);
return value === 65535 ? 1 : value / 65536;
});
const MediaStreamRawPacket = struct({ pts: u64, data: buffer(u32) }, { littleEndian: false });
const PtsConfig = 1n << 63n;
async function readString(stream, maxLength) {
const buffer = await stream.readExactly(maxLength);
return decodeUtf8(buffer.subarray(0, buffer.indexOf(0)));
}
async function readU32(stream) {
const buffer = await stream.readExactly(4);
return getUint32BigEndian(buffer, 0);
}
const Defaults$7 = /* @__PURE__ */ (() => ({
...Defaults$8,
encoderName: void 0
}))();
const BackOrScreenOnControlMessage = extend(BackOrScreenOnControlMessage$1, { action: 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 = struct({ sequence: u64 }, { littleEndian: false });
const SetClipboardControlMessage = struct({
type: u8,
sequence: u64,
paste: u8(),
content: 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 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 TransformStream({
transform(chunk, controller) {
controller.enqueue({
type: "data",
data: chunk
});
}
});
}
const deserializeStream = new StructDeserializeStream(MediaStreamRawPacket);
return {
writable: deserializeStream.writable,
readable: deserializeStream.readable.pipeThrough(new 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 = 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__ */ (() => struct({
type: u8(ScrcpyControlMessageType.InjectScroll),
pointerX: u32,
pointerY: u32,
videoWidth: u16,
videoHeight: u16,
scrollX: SignedFloat,
scrollY: SignedFloat,
buttons: 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__ */ (() => struct({
type: u8(ScrcpyControlMessageType.InjectTouch),
action: u8(),
pointerId: u64,
pointerX: u32,
pointerY: u32,
videoWidth: u16,
videoHeight: u16,
pressure: UnsignedFloat,
actionButton: u32,
buttons: u32
}, { littleEndian: false }))();
function serializeInjectTouchControlMessage(message) {
return InjectTouchControlMessage.serialize(message);
}
async function parseAudioStreamMetadata(stream, options) {
const buffered = new BufferedReadableStream(stream);
const buffer = await buffered.readExactly(4);
const codecMetadataValue = 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 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 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
};
}
export { Av1 as A, BackOrScreenOnControlMessage as B, h265ParseSpsMultilayerExtension as C, DefaultServerPath as D, EmptyControlMessage as E, h265ParseSubLayerHrdParameters as F, h265ParseVideoParameterSet as G, H265AspectRatioIndicator as H, InjectScrollControlMessage as I, h265ParseVuiParameters as J, h265SearchConfiguration as K, isScrcpyOptionValue as L, omit as M, NaluSodbBitReader as N, toScrcpyOptionValue as O, ScrcpyAudioCodec as S, ScrcpyControlMessageSerializer as a, ScrcpyControlMessageType as b, ScrcpyControlMessageTypeMap as c, ScrcpyControlMessageWriter as d, ScrcpyDeviceMessageParsers as e, ScrcpyInjectKeyCodeControlMessage as f, ScrcpyInjectTextControlMessage as g, InjectTouchControlMessage as h, ScrcpyOptions2_1 as i, SetClipboardControlMessage as j, ScrcpySetDisplayPowerControlMessage as k, ScrcpyVideoCodecId as l, annexBSplitNalu as m, clamp as n, getSubHeightC as o, getSubWidthC as p, h264ParseConfiguration as q, h264ParseSequenceParameterSet as r, h264SearchConfiguration as s, h265ParseConfiguration as t, h265ParseHrdParameters as u, h265ParseNaluHeader as v, h265ParseScalingListData as w, h265ParseSequenceParameterSet as x, h265ParseShortTermReferencePictureSet as y, h265ParseSps3dExtension as z };