mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(cli): normalize the audio passage the clip plays (#5222)
This commit is contained in:
@@ -13,6 +13,39 @@ const track = (integratedLufs: number, truePeakDbfs: number, volume = 1) => ({
|
||||
truePeakDbfs,
|
||||
});
|
||||
|
||||
describe("audioTags playback offsets", () => {
|
||||
it.each([
|
||||
['data-playback-start="4"', 4],
|
||||
['data-playback-start="4" data-media-start="1"', 4],
|
||||
['data-playback-start="0" data-media-start="4"', 0],
|
||||
['data-playback-start="4" data-media-start="invalid"', 4],
|
||||
['data-playback-start="-1" data-media-start="3"', 3],
|
||||
['data-playback-start="1.5s" data-media-start="3"', 3],
|
||||
['data-playback-start="" data-media-start="3"', 3],
|
||||
['data-playback-start="invalid"', 0],
|
||||
['data-media-start="3"', 3],
|
||||
])("measures the selected in-point for %s", (attributes, expected) => {
|
||||
const html = `<audio id="voice" src="voice.wav" data-duration="2" ${attributes}></audio>`;
|
||||
expect(audioTags(html)[0]).toEqual(expect.objectContaining({ mediaStart: expected }));
|
||||
});
|
||||
|
||||
it("measures a video from its playback in-point at its authored speed", () => {
|
||||
const html = `<video id="talk" src="talk.mp4" data-playback-start="4" data-media-start="1" data-duration="2" data-playback-rate="2"></video>`;
|
||||
const [tag] = audioTags(html);
|
||||
expect(tag).toBeDefined();
|
||||
if (!tag) throw new Error("missing video");
|
||||
const args = loudnessMeasureArgs("talk.mp4", tag);
|
||||
expect(args.slice(args.indexOf("-ss"), args.indexOf("-i"))).toEqual(["-ss", "4", "-t", "4"]);
|
||||
});
|
||||
|
||||
it("preserves the selected in-point when writing the matched gain", () => {
|
||||
const html = `<audio id="voice" src="voice.wav" data-playback-start="4" data-media-start="1" data-volume="1"></audio>`;
|
||||
const changed = updateAudioVolume(html, "voice", 0.5);
|
||||
expect(changed).toBe(html.replace('data-volume="1"', 'data-volume="0.5"'));
|
||||
expect(audioTags(changed)[0]).toEqual(expect.objectContaining({ mediaStart: 4, volume: 0.5 }));
|
||||
});
|
||||
});
|
||||
|
||||
describe("audioTags with video", () => {
|
||||
it("includes a video with sound as a normalizable clip", () => {
|
||||
const html = `<video id="a-roll" src="talk.mp4" data-has-audio="true" data-duration="4"></video>`;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { promisify } from "node:util";
|
||||
import { isAudibleVideoElement } from "@hyperframes/core/audible-video";
|
||||
import { formatAudioGain, MAX_AUDIO_GAIN_DB } from "@hyperframes/core/audio-gain";
|
||||
import { findFfBinary } from "@hyperframes/parsers/ff-binaries";
|
||||
import { readMediaOffsetSeconds } from "@hyperframes/parsers/media-duration";
|
||||
import { requestedProjectPath } from "./requestSubPath.js";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
@@ -253,6 +254,14 @@ function requiredAudioIdentity(attributes: Map<string, AttributeSpan>) {
|
||||
return { id, src };
|
||||
}
|
||||
|
||||
function authoredMediaStart(attributes: Map<string, AttributeSpan>, id: string): number {
|
||||
return readMediaOffsetSeconds((name) => {
|
||||
const raw = attributes.get(name)?.value;
|
||||
if (name === "data-media-start") authoredNumber(raw, 0, name, id);
|
||||
return raw;
|
||||
});
|
||||
}
|
||||
|
||||
/** Boolean attributes carry no `=`, so the value map cannot see them. */
|
||||
function hasBareAttribute(html: string, range: TagRange, name: string): boolean {
|
||||
const unquoted = html.slice(range.start, range.end).replace(/"[^"]*"|'[^']*'/g, '""');
|
||||
@@ -298,12 +307,7 @@ function mediaTagFromRange(html: string, range: MediaTagRange): AudioTag | null
|
||||
id,
|
||||
src,
|
||||
volume: authoredNumber(volumeAttribute?.value, 1, "data-volume", id),
|
||||
mediaStart: authoredNumber(
|
||||
attributes.get("data-media-start")?.value,
|
||||
0,
|
||||
"data-media-start",
|
||||
id,
|
||||
),
|
||||
mediaStart: authoredMediaStart(attributes, id),
|
||||
duration: authoredDuration(attributes, id),
|
||||
playbackRate: authoredNumber(
|
||||
attributes.get("data-playback-rate")?.value,
|
||||
|
||||
Reference in New Issue
Block a user