@hyperframes/producer 0.4.11 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -98671,7 +98671,7 @@ var DEFAULT_CONFIG = {
98671
98671
  ffmpegStreamingTimeout: 6e5,
98672
98672
  hdr: false,
98673
98673
  hdrAutoDetect: true,
98674
- audioGain: 1.35,
98674
+ audioGain: 1,
98675
98675
  frameDataUriCacheLimit: 256,
98676
98676
  playerReadyTimeout: 45e3,
98677
98677
  renderReadyTimeout: 15e3,
@@ -102783,6 +102783,37 @@ async function convertSdrToHdr(inputPath, outputPath, signal, config2) {
102783
102783
  );
102784
102784
  }
102785
102785
  }
102786
+ async function convertVfrToCfr(inputPath, outputPath, targetFps, startTime, duration, signal, config2) {
102787
+ const timeout2 = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
102788
+ const args = [
102789
+ "-ss",
102790
+ String(startTime),
102791
+ "-i",
102792
+ inputPath,
102793
+ "-t",
102794
+ String(duration),
102795
+ "-fps_mode",
102796
+ "cfr",
102797
+ "-r",
102798
+ String(targetFps),
102799
+ "-c:v",
102800
+ "libx264",
102801
+ "-preset",
102802
+ "fast",
102803
+ "-crf",
102804
+ "18",
102805
+ "-c:a",
102806
+ "copy",
102807
+ "-y",
102808
+ outputPath
102809
+ ];
102810
+ const result = await runFfmpeg(args, { signal, timeout: timeout2 });
102811
+ if (!result.success) {
102812
+ throw new Error(
102813
+ `VFR\u2192CFR conversion failed (exit ${result.exitCode}): ${result.stderr.slice(-300)}`
102814
+ );
102815
+ }
102816
+ }
102786
102817
  async function extractAllVideoFrames(videos, baseDir, options, signal, config2, compiledDir) {
102787
102818
  const startTime = Date.now();
102788
102819
  const extracted = [];
@@ -102840,6 +102871,39 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
102840
102871
  }
102841
102872
  }
102842
102873
  }
102874
+ const vfrNormDir = join8(options.outputDir, "_vfr_normalized");
102875
+ for (let i = 0; i < resolvedVideos.length; i++) {
102876
+ if (signal?.aborted) break;
102877
+ const entry = resolvedVideos[i];
102878
+ if (!entry) continue;
102879
+ const metadata = await extractVideoMetadata(entry.videoPath);
102880
+ if (!metadata.isVFR) continue;
102881
+ let segDuration = entry.video.end - entry.video.start;
102882
+ if (!Number.isFinite(segDuration) || segDuration <= 0) {
102883
+ const sourceRemaining = metadata.durationSeconds - entry.video.mediaStart;
102884
+ segDuration = sourceRemaining > 0 ? sourceRemaining : metadata.durationSeconds;
102885
+ }
102886
+ mkdirSync5(vfrNormDir, { recursive: true });
102887
+ const normalizedPath = join8(vfrNormDir, `${entry.video.id}_cfr.mp4`);
102888
+ try {
102889
+ await convertVfrToCfr(
102890
+ entry.videoPath,
102891
+ normalizedPath,
102892
+ options.fps,
102893
+ entry.video.mediaStart,
102894
+ segDuration,
102895
+ signal,
102896
+ config2
102897
+ );
102898
+ entry.videoPath = normalizedPath;
102899
+ entry.video = { ...entry.video, mediaStart: 0 };
102900
+ } catch (err) {
102901
+ errors.push({
102902
+ videoId: entry.video.id,
102903
+ error: err instanceof Error ? err.message : String(err)
102904
+ });
102905
+ }
102906
+ }
102843
102907
  const results = await Promise.all(
102844
102908
  resolvedVideos.map(async ({ video, videoPath }) => {
102845
102909
  if (signal?.aborted) {
@@ -103515,7 +103579,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
103515
103579
  end: element.end,
103516
103580
  mediaStart: element.mediaStart,
103517
103581
  duration: element.end - element.start,
103518
- volume: element.volume || 1
103582
+ volume: element.volume ?? 1
103519
103583
  });
103520
103584
  } catch (err) {
103521
103585
  errors.push(`Error: ${element.id} \u2014 ${err instanceof Error ? err.message : String(err)}`);
@@ -109038,8 +109102,8 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
109038
109102
  );
109039
109103
  }
109040
109104
  if (metadata.isVFR) {
109041
- console.warn(
109042
- `[Compiler] WARNING: Video "${video.id}" is variable frame rate (VFR). Screen recordings and phone videos are often VFR, which causes stuttering and frame skipping in renders. Re-encode with: ${reencode}`
109105
+ console.info(
109106
+ `[Compiler] Video "${video.id}" is variable frame rate (VFR); the engine will normalize it to CFR before frame extraction. If rendering feels slow on this video, pre-encode once with: ${reencode}`
109043
109107
  );
109044
109108
  }
109045
109109
  }).catch(() => {