mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-02 05:13:50 +02:00
Add language getter to InputTrack
This commit is contained in:
@@ -43,6 +43,8 @@
|
|||||||
const videoTrack = await input.getPrimaryVideoTrack();
|
const videoTrack = await input.getPrimaryVideoTrack();
|
||||||
const sink = new Metamuxer.VideoFrameSink(videoTrack);
|
const sink = new Metamuxer.VideoFrameSink(videoTrack);
|
||||||
|
|
||||||
|
console.log(await videoTrack.getLanguageCode());
|
||||||
|
|
||||||
for await (const thing of sink.framesAtTimestamps([0.2, 1, 2, 423])) {
|
for await (const thing of sink.framesAtTimestamps([0.2, 1, 2, 423])) {
|
||||||
console.log(thing)
|
console.log(thing)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface InputTrackBacking {
|
|||||||
getCodec(): Promise<MediaCodec | null>;
|
getCodec(): Promise<MediaCodec | null>;
|
||||||
getFirstTimestamp(): Promise<number>;
|
getFirstTimestamp(): Promise<number>;
|
||||||
computeDuration(): Promise<number>;
|
computeDuration(): Promise<number>;
|
||||||
|
getLanguageCode(): Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
@@ -39,6 +40,10 @@ export abstract class InputTrack {
|
|||||||
computeDuration() {
|
computeDuration() {
|
||||||
return this._backing.computeDuration();
|
return this._backing.computeDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLanguageCode() {
|
||||||
|
return this._backing.getLanguageCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InputVideoTrackBacking extends InputTrackBacking {
|
export interface InputVideoTrackBacking extends InputTrackBacking {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
colorSpaceIsComplete,
|
colorSpaceIsComplete,
|
||||||
IDENTITY_MATRIX,
|
IDENTITY_MATRIX,
|
||||||
rotationMatrix,
|
rotationMatrix,
|
||||||
|
UNDETERMINED_LANGUAGE,
|
||||||
} from '../misc';
|
} from '../misc';
|
||||||
import {
|
import {
|
||||||
AudioCodec,
|
AudioCodec,
|
||||||
@@ -429,7 +430,7 @@ export const mdhd = (
|
|||||||
const u32OrU64 = needsU64 ? u64 : u32;
|
const u32OrU64 = needsU64 ? u64 : u32;
|
||||||
|
|
||||||
let language = 0;
|
let language = 0;
|
||||||
for (const character of (trackData.track.metadata.languageCode ?? 'und')) {
|
for (const character of (trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE)) {
|
||||||
language <<= 5;
|
language <<= 5;
|
||||||
language += character.charCodeAt(0) - 0x60;
|
language += character.charCodeAt(0) - 0x60;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import {
|
|||||||
last,
|
last,
|
||||||
AsyncMutex,
|
AsyncMutex,
|
||||||
findLastIndex,
|
findLastIndex,
|
||||||
|
UNDETERMINED_LANGUAGE,
|
||||||
} from '../misc';
|
} from '../misc';
|
||||||
import { Reader } from '../reader';
|
import { Reader } from '../reader';
|
||||||
import { EncodedAudioSample, EncodedVideoSample, PLACEHOLDER_DATA, SampleType } from '../sample';
|
import { EncodedAudioSample, EncodedVideoSample, PLACEHOLDER_DATA, SampleType } from '../sample';
|
||||||
@@ -47,6 +48,7 @@ type InternalTrack = {
|
|||||||
durationInMovieTimescale: number;
|
durationInMovieTimescale: number;
|
||||||
durationInMediaTimescale: number;
|
durationInMediaTimescale: number;
|
||||||
rotation: Rotation;
|
rotation: Rotation;
|
||||||
|
languageCode: string;
|
||||||
sampleTableByteOffset: number;
|
sampleTableByteOffset: number;
|
||||||
sampleTable: SampleTable | null;
|
sampleTable: SampleTable | null;
|
||||||
fragmentLookupTable: FragmentLookupTableEntry[] | null;
|
fragmentLookupTable: FragmentLookupTableEntry[] | null;
|
||||||
@@ -557,6 +559,7 @@ export class IsobmffDemuxer extends Demuxer {
|
|||||||
durationInMovieTimescale: -1,
|
durationInMovieTimescale: -1,
|
||||||
durationInMediaTimescale: -1,
|
durationInMediaTimescale: -1,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
|
languageCode: UNDETERMINED_LANGUAGE,
|
||||||
sampleTableByteOffset: -1,
|
sampleTableByteOffset: -1,
|
||||||
sampleTable: null,
|
sampleTable: null,
|
||||||
fragmentLookupTable: null,
|
fragmentLookupTable: null,
|
||||||
@@ -642,6 +645,17 @@ export class IsobmffDemuxer extends Demuxer {
|
|||||||
track.timescale = this.isobmffReader.readU32();
|
track.timescale = this.isobmffReader.readU32();
|
||||||
track.durationInMediaTimescale = this.isobmffReader.readU64();
|
track.durationInMediaTimescale = this.isobmffReader.readU64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let language = this.isobmffReader.readU16();
|
||||||
|
|
||||||
|
if (language > 0) {
|
||||||
|
track.languageCode = '';
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
track.languageCode = String.fromCharCode(0x60 + (language & 0b11111)) + track.languageCode;
|
||||||
|
language >>= 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
}; break;
|
}; break;
|
||||||
|
|
||||||
case 'hdlr': {
|
case 'hdlr': {
|
||||||
@@ -1689,6 +1703,10 @@ abstract class IsobmffTrackBacking<
|
|||||||
return (lastSample?.timestamp ?? 0) + (lastSample?.duration ?? 0);
|
return (lastSample?.timestamp ?? 0) + (lastSample?.duration ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLanguageCode() {
|
||||||
|
return this.internalTrack.languageCode;
|
||||||
|
}
|
||||||
|
|
||||||
async getFirstTimestamp() {
|
async getFirstTimestamp() {
|
||||||
const firstSample = await this.getFirstSample({ metadataOnly: true });
|
const firstSample = await this.getFirstSample({ metadataOnly: true });
|
||||||
return firstSample?.timestamp ?? 0;
|
return firstSample?.timestamp ?? 0;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import {
|
|||||||
MATRIX_COEFFICIENTS_MAP_INVERSE,
|
MATRIX_COEFFICIENTS_MAP_INVERSE,
|
||||||
Rotation,
|
Rotation,
|
||||||
TRANSFER_CHARACTERISTICS_MAP_INVERSE,
|
TRANSFER_CHARACTERISTICS_MAP_INVERSE,
|
||||||
|
UNDETERMINED_LANGUAGE,
|
||||||
} from '../misc';
|
} from '../misc';
|
||||||
import { Reader } from '../reader';
|
import { Reader } from '../reader';
|
||||||
import { EncodedAudioSample, EncodedVideoSample, PLACEHOLDER_DATA, SampleType } from '../sample';
|
import { EncodedAudioSample, EncodedVideoSample, PLACEHOLDER_DATA, SampleType } from '../sample';
|
||||||
@@ -107,6 +108,7 @@ type InternalTrack = {
|
|||||||
inputTrack: InputTrack | null;
|
inputTrack: InputTrack | null;
|
||||||
codecId: string | null;
|
codecId: string | null;
|
||||||
codecPrivate: Uint8Array | null;
|
codecPrivate: Uint8Array | null;
|
||||||
|
languageCode: string;
|
||||||
info:
|
info:
|
||||||
| null
|
| null
|
||||||
| {
|
| {
|
||||||
@@ -583,6 +585,7 @@ export class MatroskaDemuxer extends Demuxer {
|
|||||||
inputTrack: null,
|
inputTrack: null,
|
||||||
codecId: null,
|
codecId: null,
|
||||||
codecPrivate: null,
|
codecPrivate: null,
|
||||||
|
languageCode: UNDETERMINED_LANGUAGE,
|
||||||
info: null,
|
info: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -733,6 +736,12 @@ export class MatroskaDemuxer extends Demuxer {
|
|||||||
this.currentTrack.codecPrivate = reader.readBytes(size);
|
this.currentTrack.codecPrivate = reader.readBytes(size);
|
||||||
}; break;
|
}; break;
|
||||||
|
|
||||||
|
case EBMLId.Language: {
|
||||||
|
if (!this.currentTrack) break;
|
||||||
|
|
||||||
|
this.currentTrack.languageCode = reader.readString(size);
|
||||||
|
}; break;
|
||||||
|
|
||||||
case EBMLId.Video: {
|
case EBMLId.Video: {
|
||||||
if (this.currentTrack?.info?.type !== 'video') break;
|
if (this.currentTrack?.info?.type !== 'video') break;
|
||||||
|
|
||||||
@@ -967,6 +976,10 @@ abstract class MatroskaTrackBacking<
|
|||||||
return (lastSample?.timestamp ?? 0) + (lastSample?.duration ?? 0);
|
return (lastSample?.timestamp ?? 0) + (lastSample?.duration ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLanguageCode() {
|
||||||
|
return this.internalTrack.languageCode;
|
||||||
|
}
|
||||||
|
|
||||||
async getFirstTimestamp() {
|
async getFirstTimestamp() {
|
||||||
const firstSample = await this.getFirstSample({ metadataOnly: true });
|
const firstSample = await this.getFirstSample({ metadataOnly: true });
|
||||||
return firstSample?.timestamp ?? 0;
|
return firstSample?.timestamp ?? 0;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
COLOR_PRIMARIES_MAP,
|
COLOR_PRIMARIES_MAP,
|
||||||
MATRIX_COEFFICIENTS_MAP,
|
MATRIX_COEFFICIENTS_MAP,
|
||||||
TRANSFER_CHARACTERISTICS_MAP,
|
TRANSFER_CHARACTERISTICS_MAP,
|
||||||
|
UNDETERMINED_LANGUAGE,
|
||||||
assert,
|
assert,
|
||||||
colorSpaceIsComplete,
|
colorSpaceIsComplete,
|
||||||
readBits,
|
readBits,
|
||||||
@@ -241,7 +242,7 @@ export class MatroskaMuxer extends Muxer {
|
|||||||
{ id: EBMLId.TrackUID, data: trackData.track.id },
|
{ id: EBMLId.TrackUID, data: trackData.track.id },
|
||||||
{ id: EBMLId.TrackType, data: TRACK_TYPE_MAP[trackData.type] },
|
{ id: EBMLId.TrackType, data: TRACK_TYPE_MAP[trackData.type] },
|
||||||
{ id: EBMLId.FlagLacing, data: 0 },
|
{ id: EBMLId.FlagLacing, data: 0 },
|
||||||
{ id: EBMLId.Language, data: trackData.track.metadata.languageCode ?? 'und' },
|
{ id: EBMLId.Language, data: trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE },
|
||||||
{ id: EBMLId.CodecID, data: codecId },
|
{ id: EBMLId.CodecID, data: codecId },
|
||||||
{ id: EBMLId.CodecDelay, data: 0 },
|
{ id: EBMLId.CodecDelay, data: 0 },
|
||||||
{ id: EBMLId.SeekPreRoll, data: seekPreRollNs },
|
{ id: EBMLId.SeekPreRoll, data: seekPreRollNs },
|
||||||
|
|||||||
@@ -329,3 +329,5 @@ export const mapAsyncGenerator = <T, U>(
|
|||||||
export const clamp = (value: number, min: number, max: number) => {
|
export const clamp = (value: number, min: number, max: number) => {
|
||||||
return Math.max(min, Math.min(max, value));
|
return Math.max(min, Math.min(max, value));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const UNDETERMINED_LANGUAGE = 'und';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Demuxer } from '../demuxer';
|
|||||||
import { Input } from '../input';
|
import { Input } from '../input';
|
||||||
import { InputAudioTrack, InputAudioTrackBacking } from '../input-track';
|
import { InputAudioTrack, InputAudioTrackBacking } from '../input-track';
|
||||||
import { SampleRetrievalOptions } from '../media-sink';
|
import { SampleRetrievalOptions } from '../media-sink';
|
||||||
import { assert } from '../misc';
|
import { assert, UNDETERMINED_LANGUAGE } from '../misc';
|
||||||
import { Reader } from '../reader';
|
import { Reader } from '../reader';
|
||||||
import { EncodedAudioSample, PLACEHOLDER_DATA } from '../sample';
|
import { EncodedAudioSample, PLACEHOLDER_DATA } from '../sample';
|
||||||
import { RiffReader } from './riff-reader';
|
import { RiffReader } from './riff-reader';
|
||||||
@@ -215,6 +215,10 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
return this.demuxer.audioInfo.sampleRate;
|
return this.demuxer.audioInfo.sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLanguageCode() {
|
||||||
|
return UNDETERMINED_LANGUAGE;
|
||||||
|
}
|
||||||
|
|
||||||
async getFirstTimestamp() {
|
async getFirstTimestamp() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user