Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions entries/all-boxes.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
export * from '#/boxes/a1lx';
export * from '#/boxes/a1op';
export * from '#/boxes/amve';
export * from '#/boxes/auxC';
export * from '#/boxes/av1C';
export * from '#/boxes/avcC';
export * from '#/boxes/btrt';
export * from '#/boxes/cclv';
export * from '#/boxes/ccst';
export * from '#/boxes/cdef';
export * from '#/boxes/clap';
Expand Down Expand Up @@ -59,8 +61,10 @@ export * from '#/boxes/mehd';
export * from '#/boxes/meta';
export * from '#/boxes/mfhd';
export * from '#/boxes/mfro';
export * from '#/boxes/mini';
export * from '#/boxes/mskC';
export * from '#/boxes/mvhd';
export * from '#/boxes/ndwt';
export * from '#/boxes/npck';
export * from '#/boxes/nump';
export * from '#/boxes/padb';
Expand All @@ -83,6 +87,7 @@ export * from '#/boxes/qt/keys';
export * from '#/boxes/qt/prof';
export * from '#/boxes/qt/tapt';
export * from '#/boxes/qt/wave';
export * from '#/boxes/reve';
export * from '#/boxes/rtp';
export * from '#/boxes/saio';
export * from '#/boxes/saiz';
Expand Down
105 changes: 105 additions & 0 deletions src/bitstream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import type { MultiBufferStream } from '#/buffer';

/**
* BitStream is a class that acts as a MultiBufferStream wrapper for parsing individual bits
*/
export class BitStream {
// The last byte read from the stream.
last_byte: number;
// If not zero, number of most significant bits already read in last_byte.
num_bits_read_in_last_byte: number;

constructor(readonly stream: MultiBufferStream) {
this.last_byte = 0;
this.num_bits_read_in_last_byte = 0;
}

/**
* Reads bits with or without byte alignment and potentially across multiple bytes.
* The bits are read in the earliest byte first, and most significant bits in a byte first.
* @param num_bits Number of bits to read.
* @return An unsigned integer whose binary representation is the big-endian read bits.
*/
read(num_bits: number) {
if (num_bits > 32) {
throw new Error('BitStream.read: Unsupported number of bits.');
}
let remaining_num_bits = num_bits;
let value = 0;
while (remaining_num_bits !== 0) {
if (this.num_bits_read_in_last_byte === 0) {
this.last_byte = this.stream.readUint8();
}
// Number of bits among remaining_num_bits that can be read in the last_byte.
const num_read_bits = Math.min(8 - this.num_bits_read_in_last_byte, remaining_num_bits);
// Read the most significant bits first.
const read_bits =
(this.last_byte >> (8 - this.num_bits_read_in_last_byte - num_read_bits)) &
((1 << num_read_bits) - 1);
value = (value << num_read_bits) | read_bits;
this.num_bits_read_in_last_byte = (this.num_bits_read_in_last_byte + num_read_bits) % 8;
remaining_num_bits -= num_read_bits;
}
return value;
}

/**
* Reads one bit.
* @return The read bit.
*/
bool() {
return this.read(1) === 1;
}

/**
* Reads a potentially unaligned four-character code.
* @return The read big-endian 4CC.
*/
four_cc() {
return String.fromCharCode(this.read(8), this.read(8), this.read(8), this.read(8));
}

/**
* Reads up to seven bits until byte alignment. The read bits must be zeros.
*/
pad_with_zeros() {
if (
this.num_bits_read_in_last_byte !== 0 &&
this.read(8 - this.num_bits_read_in_last_byte) !== 0
) {
throw new Error('BitStream.padding: Bits were not all set to zero.');
}
}

/**
* Reads a potentially unaligned 8-bit unsigned int from the underlying MultiBufferStream.
* @return The read big-endian number.
*/
readUint8() {
return this.read(8);
}

/**
* Reads a potentially unaligned 16-bit unsigned int from the underlying MultiBufferStream.
* @return The read big-endian number.
*/
readUint16() {
return this.read(16);
}

/**
* Reads a potentially unaligned 32-bit unsigned int from the underlying MultiBufferStream.
* @return The read big-endian number.
*/
readUint32() {
return this.read(32);
}

/**
* Reads a potentially unaligned 32-bit signed int from the underlying MultiBufferStream.
* @return The read big-endian number.
*/
readInt32() {
return this.read(1) ? this.read(31) - Math.pow(2, 31) : this.read(31);
}
}
18 changes: 18 additions & 0 deletions src/boxes/amve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Box } from '#/box';
import type { MultiBufferStream } from '#/buffer';
import type { BitStream } from '#/bitstream';

export class amveBox extends Box {
static override readonly fourcc = 'amve' as const;
box_name = 'AmbientViewingEnvironmentBox' as const;

ambient_illuminance: number;
ambient_light_x: number;
ambient_light_y: number;

parse(stream: MultiBufferStream | BitStream) {
this.ambient_illuminance = stream.readUint32();
this.ambient_light_x = stream.readUint16();
this.ambient_light_y = stream.readUint16();
}
}
40 changes: 40 additions & 0 deletions src/boxes/cclv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Box } from '#/box';
import type { MultiBufferStream } from '#/buffer';
import type { BitStream } from '#/bitstream';

export class cclvBox extends Box {
static override readonly fourcc = 'cclv' as const;
box_name = 'ContentColourVolumeBox' as const;

ccv_primaries_x: Array<number>;
ccv_primaries_y: Array<number>;
ccv_min_luminance_value: number;
ccv_max_luminance_value: number;
ccv_avg_luminance_value: number;

parse(stream: MultiBufferStream | BitStream) {
const flags = stream.readUint8();
const ccv_primaries_present_flag = flags & 0x10;
const ccv_min_luminance_value_present_flag = flags & 0x08;
const ccv_max_luminance_value_present_flag = flags & 0x04;
const ccv_avg_luminance_value_present_flag = flags & 0x02;

if (ccv_primaries_present_flag) {
this.ccv_primaries_x = new Array<number>(3);
this.ccv_primaries_y = new Array<number>(3);
for (let c = 0; c < 3; c++) {
this.ccv_primaries_x[c] = stream.readInt32();
this.ccv_primaries_y[c] = stream.readInt32();
}
}
if (ccv_min_luminance_value_present_flag) {
this.ccv_min_luminance_value = stream.readUint32();
}
if (ccv_max_luminance_value_present_flag) {
this.ccv_max_luminance_value = stream.readUint32();
}
if (ccv_avg_luminance_value_present_flag) {
this.ccv_avg_luminance_value = stream.readUint32();
}
}
}
3 changes: 2 additions & 1 deletion src/boxes/clli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box } from '#/box';
import type { MultiBufferStream } from '#/buffer';
import type { BitStream } from '#/bitstream';

export class clliBox extends Box {
static override readonly fourcc = 'clli' as const;
Expand All @@ -8,7 +9,7 @@ export class clliBox extends Box {
max_content_light_level: number;
max_pic_average_light_level: number;

parse(stream: MultiBufferStream) {
parse(stream: MultiBufferStream | BitStream) {
this.max_content_light_level = stream.readUint16();
this.max_pic_average_light_level = stream.readUint16();
}
Expand Down
3 changes: 2 additions & 1 deletion src/boxes/mdcv.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Box } from '#/box';
import type { MultiBufferStream } from '#/buffer';
import { ColorPoint } from './displays/colorPoint';
import type { BitStream } from '#/bitstream';

export class mdcvBox extends Box {
static override readonly fourcc = 'mdcv' as const;
Expand All @@ -11,7 +12,7 @@ export class mdcvBox extends Box {
max_display_mastering_luminance: number;
min_display_mastering_luminance: number;

parse(stream: MultiBufferStream) {
parse(stream: MultiBufferStream | BitStream) {
this.display_primaries = [];
this.display_primaries[0] = new ColorPoint(stream.readUint16(), stream.readUint16());
this.display_primaries[1] = new ColorPoint(stream.readUint16(), stream.readUint16());
Expand Down
Loading