@pictor-sdk/video-android 0.1.5 → 0.2.0

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.mjs CHANGED
@@ -748,7 +748,8 @@ function composedState(snapshot) {
748
748
  */
749
749
  width: 0,
750
750
  height: 0,
751
- error: snapshot.error ?? null
751
+ error: snapshot.error ?? null,
752
+ readinessFailure: snapshot.readinessFailure ?? null
752
753
  };
753
754
  }
754
755
  function useCompositionPlayback(options) {
@@ -1711,11 +1712,26 @@ var VideoExportRejected = class extends Error {
1711
1712
  }
1712
1713
  };
1713
1714
  var DEFAULT_FPS = 30;
1714
- function describeUnsupported(project, spec) {
1715
+ function animatedSchedulesFor(project) {
1716
+ const schedules = {};
1717
+ for (const overlay of project.overlays) {
1718
+ if (overlay.type !== "sticker") continue;
1719
+ const data = overlay.data;
1720
+ if (data && data.animation) schedules[overlay.id] = data.animation;
1721
+ }
1722
+ return schedules;
1723
+ }
1724
+ function describeUnsupported(project, spec, options) {
1715
1725
  const reasons = [];
1716
1726
  for (const clip of project.clips) {
1717
1727
  if (clip.kind === "photo") {
1718
- reasons.push(`clip '${clip.id}' is a photo, which this exporter does not encode yet`);
1728
+ if (!options.renderPhotoBase) {
1729
+ reasons.push(`clip '${clip.id}' is a photo, and no photo renderer was supplied`);
1730
+ } else if (project.clips.length !== 1) {
1731
+ reasons.push(
1732
+ `clip '${clip.id}' is a photo in a project of ${project.clips.length} clips; only a single-photo story is supported`
1733
+ );
1734
+ }
1719
1735
  continue;
1720
1736
  }
1721
1737
  }
@@ -1747,11 +1763,107 @@ function createMedia3VideoExporter(options) {
1747
1763
  if (issues.length > 0) {
1748
1764
  throw new VideoExportRejected(issues.map((issue) => issue.message));
1749
1765
  }
1750
- const unsupported = describeUnsupported(project, spec);
1766
+ const unsupported = describeUnsupported(project, spec, options);
1751
1767
  if (unsupported.length > 0) throw new VideoExportRejected(unsupported);
1752
1768
  const decision = resolveDestination(spec.destination);
1753
1769
  if (decision.destination === null) throw new VideoExportRejected(decision.reasons);
1754
1770
  const destination = decision.destination;
1771
+ const photoOnly = project.clips.length === 1 && project.clips[0].kind === "photo";
1772
+ if (photoOnly) {
1773
+ const clip = project.clips[0];
1774
+ if (!options.renderPhotoBase) {
1775
+ throw new VideoExportRejected([`clip '${clip.id}' is a photo, and no photo renderer was supplied`]);
1776
+ }
1777
+ const pngPath = await options.renderPhotoBase(clip.source, clip.id);
1778
+ job.checkpoint("resolving");
1779
+ const photoProgram = compileVideoSceneProgram(project, {
1780
+ animatedSchedules: animatedSchedulesFor(project)
1781
+ });
1782
+ if (photoProgram.segments.length === 0) {
1783
+ throw new VideoExportRejected(["the compiled program has no segments"]);
1784
+ }
1785
+ const named2 = /* @__PURE__ */ new Set();
1786
+ for (const segment of photoProgram.segments) {
1787
+ for (const command of segment.commands) {
1788
+ if (command.op === "overlay") named2.add(command.overlayId);
1789
+ }
1790
+ }
1791
+ const overlayPlan2 = options.prepareOverlays ? options.prepareOverlays(photoProgram, project.size, 1) : {
1792
+ resources: [],
1793
+ pending: [],
1794
+ invalid: [...named2].map((overlayId) => ({
1795
+ overlayId,
1796
+ kind: "unknown",
1797
+ reason: "no prepareOverlays was supplied, so this overlay has no portable form"
1798
+ }))
1799
+ };
1800
+ const stagedNow2 = overlayPlan2.resources.map((resource) => resource.file);
1801
+ if (overlayPlan2.pending.length > 0) {
1802
+ options.releaseResources?.(stagedNow2);
1803
+ throw new VideoExportRejected(
1804
+ overlayPlan2.pending.map(
1805
+ (id) => `overlay '${id}' is still preparing; export would omit it`
1806
+ )
1807
+ );
1808
+ }
1809
+ if (overlayPlan2.invalid.length > 0) {
1810
+ options.releaseResources?.(stagedNow2);
1811
+ throw new VideoExportRejected(
1812
+ overlayPlan2.invalid.map(
1813
+ (bad) => `overlay '${bad.overlayId}' (${bad.kind}): ${bad.reason}`
1814
+ )
1815
+ );
1816
+ }
1817
+ job.checkpoint("overlays");
1818
+ let outcome2;
1819
+ try {
1820
+ outcome2 = JSON.parse(
1821
+ await nativeModule().exportRunPhotoProjectAsync(
1822
+ job.id,
1823
+ pngPath,
1824
+ JSON.stringify({
1825
+ version: VIDEO_SCENE_PROGRAM_VERSION,
1826
+ projectSize: { width: project.size.width, height: project.size.height },
1827
+ durationUs: photoProgram.durationUs,
1828
+ segments: photoProgram.segments
1829
+ }),
1830
+ JSON.stringify(overlayPlan2.resources),
1831
+ projectDuration3(project),
1832
+ 180,
1833
+ destination.kind === "file" ? JSON.stringify({
1834
+ kind: "file",
1835
+ path: destination.path,
1836
+ overwrite: destination.overwrite
1837
+ }) : ""
1838
+ )
1839
+ );
1840
+ } finally {
1841
+ options.releaseResources?.(stagedNow2);
1842
+ }
1843
+ if (!outcome2.ok) {
1844
+ const error = outcome2.error || "the export failed";
1845
+ if (isRefusal(error)) throw new VideoExportRejected([error]);
1846
+ throw new VideoExportFailed(job.id, "encoding", error);
1847
+ }
1848
+ const probe2 = JSON.parse(nativeModule().exportProbeOutput(outcome2.uri));
1849
+ if (!probe2.readable) {
1850
+ throw new VideoExportFailed(
1851
+ job.id,
1852
+ "publishing",
1853
+ `${describeTarget(outcome2.uri)} could not be read back: ${probe2.error ?? "no video track"}`
1854
+ );
1855
+ }
1856
+ if (destination.kind === "file") return { kind: "file", uri: outcome2.uri };
1857
+ const temporaryUri2 = outcome2.uri;
1858
+ return {
1859
+ kind: "temporary",
1860
+ uri: temporaryUri2,
1861
+ release: async () => {
1862
+ await Promise.resolve();
1863
+ nativeModule().exportReleaseTemporaryOutput(temporaryUri2);
1864
+ }
1865
+ };
1866
+ }
1755
1867
  const playable = project.clips.filter((clip) => isPlayableWindow(clip));
1756
1868
  if (playable.length === 0) throw new VideoExportRejected(["the project has no playable clips"]);
1757
1869
  if (!(projectDuration3(project) > 0)) {
@@ -1778,7 +1890,9 @@ function createMedia3VideoExporter(options) {
1778
1890
  targetFps: fps
1779
1891
  }));
1780
1892
  const plan = planClipShards(requests, fps);
1781
- const program = compileVideoSceneProgram(project);
1893
+ const program = compileVideoSceneProgram(project, {
1894
+ animatedSchedules: animatedSchedulesFor(project)
1895
+ });
1782
1896
  if (program.segments.length === 0) {
1783
1897
  throw new VideoExportRejected(["the compiled program has no segments"]);
1784
1898
  }