158 lines
5.0 KiB
JavaScript
158 lines
5.0 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.hasFps = exports.hasFpsSuitedForSlowFps = exports.getFps = exports.getFpsFromMp4TrakBox = exports.getTimescaleAndDuration = exports.trakBoxContainsVideo = exports.trakBoxContainsAudio = void 0;
|
|
const traversal_1 = require("./containers/iso-base-media/traversal");
|
|
const traversal_2 = require("./containers/riff/traversal");
|
|
const is_audio_structure_1 = require("./is-audio-structure");
|
|
const calculateFps = ({ sttsBox, timeScale, durationInSamples, }) => {
|
|
let totalSamples = 0;
|
|
for (const sample of sttsBox.sampleDistribution) {
|
|
totalSamples += sample.sampleCount;
|
|
}
|
|
if (totalSamples === 0) {
|
|
return null;
|
|
}
|
|
const durationInSeconds = durationInSamples / timeScale;
|
|
const fps = totalSamples / durationInSeconds;
|
|
return fps;
|
|
};
|
|
const trakBoxContainsAudio = (trakBox) => {
|
|
const stsd = (0, traversal_1.getStsdBox)(trakBox);
|
|
if (!stsd) {
|
|
return false;
|
|
}
|
|
const videoSample = stsd.samples.find((s) => s.type === 'audio');
|
|
if (!videoSample || videoSample.type !== 'audio') {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
exports.trakBoxContainsAudio = trakBoxContainsAudio;
|
|
const trakBoxContainsVideo = (trakBox) => {
|
|
const stsd = (0, traversal_1.getStsdBox)(trakBox);
|
|
if (!stsd) {
|
|
return false;
|
|
}
|
|
const videoSample = stsd.samples.find((s) => s.type === 'video');
|
|
if (!videoSample || videoSample.type !== 'video') {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
exports.trakBoxContainsVideo = trakBoxContainsVideo;
|
|
const getTimescaleAndDuration = (trakBox) => {
|
|
const mdhdBox = (0, traversal_1.getMdhdBox)(trakBox);
|
|
if (mdhdBox) {
|
|
return { timescale: mdhdBox.timescale, duration: mdhdBox.duration };
|
|
}
|
|
return null;
|
|
};
|
|
exports.getTimescaleAndDuration = getTimescaleAndDuration;
|
|
const getFpsFromMp4TrakBox = (trakBox) => {
|
|
const timescaleAndDuration = (0, exports.getTimescaleAndDuration)(trakBox);
|
|
if (!timescaleAndDuration) {
|
|
return null;
|
|
}
|
|
const sttsBox = (0, traversal_1.getSttsBox)(trakBox);
|
|
if (!sttsBox) {
|
|
return null;
|
|
}
|
|
return calculateFps({
|
|
sttsBox,
|
|
timeScale: timescaleAndDuration.timescale,
|
|
durationInSamples: timescaleAndDuration.duration,
|
|
});
|
|
};
|
|
exports.getFpsFromMp4TrakBox = getFpsFromMp4TrakBox;
|
|
const getFpsFromIsoMaseMedia = (state) => {
|
|
var _a, _b;
|
|
const moovBox = (0, traversal_1.getMoovBoxFromState)({
|
|
structureState: state.structure,
|
|
isoState: state.iso,
|
|
mp4HeaderSegment: (_b = (_a = state.m3uPlaylistContext) === null || _a === void 0 ? void 0 : _a.mp4HeaderSegment) !== null && _b !== void 0 ? _b : null,
|
|
mayUsePrecomputed: true,
|
|
});
|
|
if (!moovBox) {
|
|
return null;
|
|
}
|
|
const trackBoxes = (0, traversal_1.getTraks)(moovBox);
|
|
const trackBox = trackBoxes.find(exports.trakBoxContainsVideo);
|
|
if (!trackBox) {
|
|
return null;
|
|
}
|
|
return (0, exports.getFpsFromMp4TrakBox)(trackBox);
|
|
};
|
|
const getFpsFromAvi = (structure) => {
|
|
const strl = (0, traversal_2.getStrlBoxes)(structure);
|
|
for (const s of strl) {
|
|
const strh = (0, traversal_2.getStrhBox)(s.children);
|
|
if (!strh) {
|
|
throw new Error('No strh box');
|
|
}
|
|
if (strh.fccType === 'auds') {
|
|
continue;
|
|
}
|
|
return strh.rate;
|
|
}
|
|
return null;
|
|
};
|
|
const getFps = (state) => {
|
|
const segments = state.structure.getStructure();
|
|
if (segments.type === 'iso-base-media') {
|
|
return getFpsFromIsoMaseMedia(state);
|
|
}
|
|
if (segments.type === 'riff') {
|
|
return getFpsFromAvi(segments);
|
|
}
|
|
// People need to get it from slowFps
|
|
if (segments.type === 'matroska') {
|
|
return null;
|
|
}
|
|
// People need to get it from slowFps
|
|
if (segments.type === 'transport-stream') {
|
|
return null;
|
|
}
|
|
// Same as m3u8
|
|
if (segments.type === 'm3u') {
|
|
return null;
|
|
}
|
|
if (segments.type === 'mp3' ||
|
|
segments.type === 'wav' ||
|
|
segments.type === 'flac' ||
|
|
segments.type === 'aac') {
|
|
return null;
|
|
}
|
|
throw new Error('Cannot get fps, not implemented: ' + segments);
|
|
};
|
|
exports.getFps = getFps;
|
|
const hasFpsSuitedForSlowFps = (state) => {
|
|
try {
|
|
return (0, exports.getFps)(state) !== null;
|
|
}
|
|
catch (_a) {
|
|
return false;
|
|
}
|
|
};
|
|
exports.hasFpsSuitedForSlowFps = hasFpsSuitedForSlowFps;
|
|
const hasFps = (state) => {
|
|
// Matroska and Transport stream has no FPS metadata
|
|
// Not bothering to parse
|
|
// Users should use `slowFps` field
|
|
// same goes for audio
|
|
const structure = state.structure.getStructure();
|
|
if ((0, is_audio_structure_1.isAudioStructure)(structure)) {
|
|
return true;
|
|
}
|
|
if (structure.type === 'matroska') {
|
|
return true;
|
|
}
|
|
if (structure.type === 'transport-stream') {
|
|
return true;
|
|
}
|
|
if (structure.type === 'm3u') {
|
|
return true;
|
|
}
|
|
return (0, exports.hasFpsSuitedForSlowFps)(state);
|
|
};
|
|
exports.hasFps = hasFps;
|