Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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) {
Comment thread
DenizUgur marked this conversation as resolved.
Outdated
parse(stream: MultiBufferStream | BitStream) {
this.max_content_light_level = stream.readUint16();
this.max_pic_average_light_level = stream.readUint16();
}
Expand Down
18 changes: 16 additions & 2 deletions src/boxes/ftyp.ts
Comment thread
y-guyon marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,23 @@ export class ftypBox extends Box {
box_name = 'FileTypeBox' as const;

major_brand: string;
minor_version: number;
minor_version: number | string;
compatible_brands: Array<string>;

parse(stream: MultiBufferStream) {
let toparse = this.size - this.hdr_size;
this.major_brand = stream.readString(4);
this.minor_version = stream.readUint32();
const minor_version_str = String.fromCharCode(
this.minor_version >> 24,
(this.minor_version >> 16) & 255,
(this.minor_version >> 8) & 255,
this.minor_version & 255,
);
if (minor_version_str.match('[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]')) {
// This seems like a four-character code. Display it as such.
this.minor_version = minor_version_str;
}
toparse -= 8;
this.compatible_brands = [];
let i = 0;
Expand All @@ -29,7 +39,11 @@ export class ftypBox extends Box {
this.size = 8 + 4 * this.compatible_brands.length;
this.writeHeader(stream);
stream.writeString(this.major_brand, undefined, 4);
stream.writeUint32(this.minor_version);
if (typeof this.minor_version === 'number') {
stream.writeUint32(this.minor_version);
} else {
stream.writeString(this.minor_version, undefined, 4);
}
for (let i = 0; i < this.compatible_brands.length; i++) {
stream.writeString(this.compatible_brands[i], undefined, 4);
}
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