yuv-rx
Version:
Reading videos as Rx Observables of decoded frames
114 lines (113 loc) • 3.74 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Y4MHeader = exports.Y4MFrame = exports.Y4MFrameHeader = void 0;
const frame_1 = require("./frame");
function interlacingFromChar(char) {
switch (char) {
case 't':
return 'TopFieldFirst';
case 'b':
return 'BottomFieldFirst';
case 'm':
return 'Mixed';
case 'p':
default:
return 'Progressive';
}
}
class Y4MFrameHeader {
}
exports.Y4MFrameHeader = Y4MFrameHeader;
class Y4MFrame {
constructor(fn, yuv) {
this.fn = fn;
this.yuv = yuv;
}
}
exports.Y4MFrame = Y4MFrame;
class Y4MHeader {
constructor() {
this.interlacing = 'Progressive';
this.aspectRatio = { numerator: 1, denominator: 1 };
this.colorspace = 'C420mpeg2';
this.timeScale = -1;
}
chromaWidth() {
if (this.colorspace == 'C444' || this.colorspace == 'C422') {
return this.width;
}
else {
return Math.ceil(this.width / 2);
}
}
chromaHeight() {
if (this.colorspace == 'C444') {
return this.height;
}
else {
return Math.ceil(this.height / 2);
}
}
chromaSize() {
return this.chromaWidth() * this.chromaHeight();
}
lumaSize() {
return this.width * this.height;
}
getFrameSize() {
return this.lumaSize() + this.chromaSize() * 2;
}
static fromString(line) {
if ('YUV4MPEG2 ' != line.substring(0, 10)) {
throw new Error('Wrong yuv4mpeg header.');
}
const split = line.substring(10).split(' ');
const header = new Y4MHeader();
for (const s of split) {
const key = s.charAt(0);
const value = s.substring(1);
switch (key) {
case 'W':
header.width = parseInt(value);
break;
case 'H':
header.height = parseInt(value);
break;
case 'F':
header.frameRate = (0, frame_1.parseRational)(value);
header.timeScale = header.frameRate.numerator;
header.videoMediaTimeScale = header.timeScale;
break;
case 'I':
header.interlacing = interlacingFromChar(s.charAt(1));
break;
case 'A':
header.aspectRatio = (0, frame_1.parseRational)(value);
break;
case 'C':
header.colorspace = s;
break;
case 'X':
header.comment = value;
const vmtsMatch = Y4MHeader.videoMediaTimeScaleRegex.exec(line);
if (vmtsMatch != null) {
header.videoMediaTimeScale = parseInt(vmtsMatch.groups.ts);
}
else {
const tsMatch = Y4MHeader.timeScaleRegex.exec(line);
if (tsMatch != null) {
header.timeScale = parseInt(tsMatch.groups.ts);
}
}
break;
}
}
return header;
}
toString() {
return `YUV4MPEG2 W${this.width} H${this.height} F${this.frameRate.numerator}:${this.frameRate.denominator} Ip A${this.aspectRatio.numerator}:${this.aspectRatio.denominator} ${this.colorspace} XYSCSS=420MPEG2`;
}
}
exports.Y4MHeader = Y4MHeader;
Y4MHeader.timeScaleRegex = /TS=(?<ts>\d+)/;
Y4MHeader.videoMediaTimeScaleRegex = /VMTS=(?<ts>\d+)/;