-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented tfdt and trun boxes in the box-moof package.
- Loading branch information
Showing
3 changed files
with
227 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
import {BoxEncoding} from "@isomp4/core"; | ||
import {mfhd} from "./mfhd.js"; | ||
import {tfdt} from "./tfdt.js"; | ||
import {tfhd} from "./tfhd.js"; | ||
import {trun} from "./trun.js"; | ||
|
||
export const traf = new BoxEncoding("traf", tfhd); | ||
export const traf = new BoxEncoding("traf", tfdt, tfhd, trun); | ||
export const moof = new BoxEncoding("moof", mfhd, traf); | ||
|
||
export * from "./mfhd.js"; | ||
export * from "./tfdt.js"; | ||
export * from "./tfhd.js"; | ||
export * from "./trun.js"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import type {Buffer} from "buffer"; | ||
import type {BoxHeader, FullBox} from "@isomp4/core"; | ||
import {FullBoxEncoding, readSafeUInt64BE} from "@isomp4/core"; | ||
|
||
export interface TrackFragmentBaseMediaDecodeTimeBox extends FullBox { | ||
baseMediaDecodeTime: number; | ||
} | ||
|
||
class TrackFragmentBaseMediaDecodeTimeBoxEncoding extends FullBoxEncoding { | ||
|
||
constructor() { | ||
super("tfdt"); | ||
} | ||
|
||
public override encodingLength(obj: TrackFragmentBaseMediaDecodeTimeBox): number { | ||
return super.encodingLength(obj); // TODO implement | ||
} | ||
|
||
public override encodeTo(obj: TrackFragmentBaseMediaDecodeTimeBox, buffer: Buffer): number { | ||
const requiredBytes = super.encodeTo(obj, buffer); | ||
if (requiredBytes > 0) { | ||
return requiredBytes; | ||
} | ||
// let offset = this.encodedBytes; | ||
// // TODO implementing encoding | ||
// this.encodedBytes = offset; | ||
return 0; | ||
} | ||
|
||
public override decode(buffer: Buffer, header?: BoxHeader): TrackFragmentBaseMediaDecodeTimeBox | number { | ||
const superBox = super.decode(buffer, header); | ||
if (typeof superBox === "number") { | ||
return superBox; | ||
} | ||
let baseMediaDecodeTime: number; | ||
let offset: number = this.decodedBytes; | ||
switch (superBox.version) { | ||
case 0: | ||
// 32-bit time | ||
if (buffer.length < offset + 4) { | ||
return offset + 4; | ||
} | ||
baseMediaDecodeTime = buffer.readUInt32BE(offset); | ||
offset += 4; | ||
break; | ||
case 1: | ||
// 64-bit time | ||
if (buffer.length < offset + 8) { | ||
return offset + 8; | ||
} | ||
baseMediaDecodeTime = readSafeUInt64BE(buffer, offset); | ||
offset += 8; | ||
break; | ||
default: | ||
throw new Error("Unsupported version of tfdt box: " + superBox.version); | ||
} | ||
this.decodedBytes = offset; | ||
return { | ||
...superBox, | ||
baseMediaDecodeTime, | ||
}; | ||
} | ||
|
||
} | ||
|
||
export const tfdt = new TrackFragmentBaseMediaDecodeTimeBoxEncoding(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import type {Buffer} from "buffer"; | ||
import type {BoxHeader, FullBox} from "@isomp4/core"; | ||
import {FullBoxEncoding} from "@isomp4/core"; | ||
|
||
interface TrackRunSample { | ||
duration?: number; | ||
size?: number; | ||
flags?: number; | ||
compositionTimeOffset?: number; | ||
} | ||
|
||
export interface TrackRunBox extends FullBox { | ||
// Note: sampleCount is encoded in the samples array | ||
// Optional based on flags | ||
dataOffset?: number; | ||
firstSampleFlags?: number; | ||
samples: TrackRunSample[]; | ||
} | ||
|
||
export namespace TrackRunBox { | ||
|
||
export interface Flags { | ||
dataOffsetPresent: boolean; | ||
firstSampleFlagsPresent: boolean; | ||
sampleDurationPresent: boolean; | ||
sampleSizePresent: boolean; | ||
sampleFlagsPresent: boolean; | ||
sampleCompositionTimeOffsetsPresent: boolean; | ||
} | ||
|
||
export function parseFlags(flags: number): Flags { | ||
return { | ||
dataOffsetPresent: (flags & 0x000001) !== 0, | ||
firstSampleFlagsPresent: (flags & 0x000004) !== 0, | ||
sampleDurationPresent: (flags & 0x000100) !== 0, | ||
sampleSizePresent: (flags & 0x000200) !== 0, | ||
sampleFlagsPresent: (flags & 0x000400) !== 0, | ||
sampleCompositionTimeOffsetsPresent: (flags & 0x000800) !== 0, | ||
}; | ||
} | ||
|
||
} | ||
|
||
class TrackRunBoxEncoding extends FullBoxEncoding { | ||
|
||
constructor() { | ||
super("trun"); | ||
} | ||
|
||
public override encodingLength(obj: TrackRunBox): number { | ||
return super.encodingLength(obj); // TODO implement | ||
} | ||
|
||
public override encodeTo(obj: TrackRunBox, buffer: Buffer): number { | ||
const requiredBytes = super.encodeTo(obj, buffer); | ||
if (requiredBytes > 0) { | ||
return requiredBytes; | ||
} | ||
// let offset = this.encodedBytes; | ||
// // TODO implementing encoding | ||
// this.encodedBytes = offset; | ||
return 0; | ||
} | ||
|
||
public override decode(buffer: Buffer, header?: BoxHeader): TrackRunBox | number { | ||
const superBox = super.decode(buffer, header); | ||
if (typeof superBox === "number") { | ||
return superBox; | ||
} | ||
let offset: number = this.decodedBytes; | ||
if (buffer.length < offset + 4) { | ||
return offset + 4; | ||
} | ||
const sampleCount: number = buffer.readUInt32BE(offset); | ||
offset += 4; | ||
const bflags: TrackRunBox.Flags = TrackRunBox.parseFlags(superBox.flags); | ||
let dataOffset: number | undefined; | ||
if (bflags.dataOffsetPresent) { | ||
if (buffer.length < offset + 4) { | ||
return offset + 4; | ||
} | ||
dataOffset = buffer.readInt32BE(offset); // signed | ||
offset += 4; | ||
} | ||
let firstSampleFlags: number | undefined; | ||
if (bflags.firstSampleFlagsPresent) { | ||
if (bflags.sampleFlagsPresent) { | ||
throw new Error("Malformed input: Sample flags shall not be present!"); | ||
} | ||
if (buffer.length < offset + 4) { | ||
return offset + 4; | ||
} | ||
firstSampleFlags = buffer.readUInt32BE(offset); | ||
offset += 4; | ||
} | ||
const bytesPerSample: number = | ||
(bflags.sampleDurationPresent ? 4 : 0) + | ||
(bflags.sampleSizePresent ? 4 : 0) + | ||
(bflags.sampleFlagsPresent ? 4 : 0) + | ||
(bflags.sampleCompositionTimeOffsetsPresent ? 4 : 0); | ||
const bytesForSamples: number = bytesPerSample * sampleCount; | ||
if (buffer.length < offset + bytesForSamples) { | ||
return offset + bytesForSamples; | ||
} | ||
const samples: TrackRunSample[] = []; | ||
for (let i = 0; i < sampleCount; i++) { | ||
let duration: number | undefined; | ||
let size: number | undefined; | ||
let flags: number | undefined; | ||
let compositionTimeOffset: number | undefined; | ||
if (bflags.sampleDurationPresent) { | ||
duration = buffer.readUInt32BE(offset); | ||
offset += 4; | ||
} | ||
if (bflags.sampleSizePresent) { | ||
size = buffer.readUInt32BE(offset); | ||
offset += 4; | ||
} | ||
if (bflags.sampleFlagsPresent) { | ||
flags = buffer.readUInt32BE(offset); | ||
offset += 4; | ||
} else if (bflags.firstSampleFlagsPresent && i === 0) { | ||
flags = firstSampleFlags; | ||
} | ||
if (bflags.sampleCompositionTimeOffsetsPresent) { | ||
switch (superBox.version) { | ||
case 0: | ||
compositionTimeOffset = buffer.readUInt32BE(offset); // Unsigned | ||
break; | ||
case 1: | ||
compositionTimeOffset = buffer.readInt32BE(offset); // Signed | ||
break; | ||
default: | ||
throw new Error("Unsupported version of trun box: " + superBox.version); | ||
} | ||
offset += 4; | ||
} | ||
samples.push({ | ||
duration, | ||
size, | ||
flags, | ||
compositionTimeOffset, | ||
}); | ||
} | ||
this.decodedBytes = offset; | ||
return { | ||
...superBox, | ||
dataOffset, | ||
firstSampleFlags, | ||
samples, | ||
}; | ||
} | ||
|
||
} | ||
|
||
export const trun = new TrackRunBoxEncoding(); |