@bycrux/editor 0.11.2 → 1.0.1
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/package.json +3 -1
- package/src/ControlsInfoModal.tsx +251 -61
- package/src/__tests__/ControlsInfoModal.test.tsx +43 -0
- package/src/__tests__/adapter.test.ts +59 -1
- package/src/__tests__/schema-assignability.test.ts +93 -0
- package/src/__tests__/schema.test.ts +15 -0
- package/src/__tests__/video-adapter-contract.test.ts +128 -5
- package/src/carousel/AddElementMenu.tsx +10 -4
- package/src/carousel/CarouselEditor.tsx +46 -8
- package/src/carousel/CarouselRenderModal.tsx +15 -10
- package/src/carousel/OverlayPicker.tsx +10 -3
- package/src/carousel/SlidePropertyPanel.tsx +43 -21
- package/src/components/FilmstripScrubber.tsx +277 -0
- package/src/components/__tests__/FilmstripScrubber.test.tsx +216 -0
- package/src/engine/__tests__/audio-clock.test.ts +655 -0
- package/src/engine/__tests__/audio-worklet-source.test.ts +316 -0
- package/src/engine/__tests__/batch-planner.test.ts +298 -0
- package/src/engine/__tests__/decode-worker-source.test.ts +249 -0
- package/src/engine/__tests__/demux-ranged.test.ts +495 -0
- package/src/engine/__tests__/demux-truncated.test.ts +136 -0
- package/src/engine/__tests__/demux.test.ts +305 -0
- package/src/engine/__tests__/eligibility.test.ts +146 -0
- package/src/engine/__tests__/engine-recovery.test.ts +263 -0
- package/src/engine/__tests__/engine.test.ts +326 -0
- package/src/engine/__tests__/frame-server-ranged.test.ts +261 -0
- package/src/engine/__tests__/frame-server.test.ts +326 -0
- package/src/engine/__tests__/media-loader-ranged.test.ts +289 -0
- package/src/engine/__tests__/media-loader.test.ts +100 -0
- package/src/engine/__tests__/scheduler-crop.test.ts +353 -0
- package/src/engine/__tests__/scheduler.test.ts +1310 -0
- package/src/engine/__tests__/scrub-resolve.test.ts +96 -0
- package/src/engine/__tests__/scrub-source.test.ts +195 -0
- package/src/engine/__tests__/source-host.test.ts +455 -0
- package/src/engine/__tests__/time-stretch.test.ts +182 -0
- package/src/engine/audio-clock.ts +1179 -0
- package/src/engine/audio-worklet-source.ts +160 -0
- package/src/engine/batch-planner.ts +308 -0
- package/src/engine/debug-hud.tsx +54 -0
- package/src/engine/decode-worker-source.ts +142 -0
- package/src/engine/demux.ts +900 -0
- package/src/engine/eligibility.ts +140 -0
- package/src/engine/frame-server.ts +644 -0
- package/src/engine/index.ts +950 -0
- package/src/engine/media-loader.ts +380 -0
- package/src/engine/mp4box.d.ts +214 -0
- package/src/engine/scheduler.ts +1324 -0
- package/src/engine/scrub-resolve.ts +66 -0
- package/src/engine/scrub-source.ts +496 -0
- package/src/engine/time-stretch.ts +224 -0
- package/src/index.ts +83 -1
- package/src/preview/OverlayPreview.tsx +2 -24
- package/src/schema.ts +146 -3
- package/src/state/__tests__/use-project-sync.test.tsx +56 -0
- package/src/state/use-project-sync.ts +17 -0
- package/src/test-setup.ts +32 -0
- package/src/text/FontPicker.tsx +85 -51
- package/src/text/TextFormattingToolbar.tsx +6 -1
- package/src/text/__tests__/FontPicker.options.test.ts +43 -0
- package/src/text/__tests__/TextFormattingToolbar.test.tsx +4 -4
- package/src/theme.ts +108 -3
- package/src/types.ts +601 -22
- package/src/ui/Loader.tsx +64 -0
- package/src/ui/NumberField.tsx +254 -0
- package/src/ui/Slider.tsx +128 -0
- package/src/ui/Tooltip.tsx +118 -0
- package/src/ui/__tests__/NumberField.test.tsx +298 -0
- package/src/ui/__tests__/Slider.test.tsx +150 -0
- package/src/ui/__tests__/Tooltip.test.tsx +105 -0
- package/src/ui/__tests__/usePersistentState.test.tsx +112 -0
- package/src/ui/badge.tsx +12 -4
- package/src/ui/index.ts +6 -0
- package/src/ui/input.tsx +1 -1
- package/src/ui/select.tsx +1 -1
- package/src/ui/switch.tsx +12 -2
- package/src/ui/textarea.tsx +1 -1
- package/src/ui/usePersistentState.ts +63 -0
- package/src/video/AudioPolishModal.tsx +983 -0
- package/src/video/CaptionListPanel.test.tsx +944 -0
- package/src/video/CaptionListPanel.tsx +1106 -0
- package/src/video/CaptionRegenModal.tsx +37 -9
- package/src/video/CaptionSpecimen.tsx +160 -0
- package/src/video/CaptionStyleGallery.tsx +466 -0
- package/src/video/CommandPalette.tsx +165 -0
- package/src/video/ImageToneMenu.tsx +137 -0
- package/src/video/OverlayInspector.tsx +977 -0
- package/src/video/RenderModal.tsx +1035 -62
- package/src/video/VersionCompare.tsx +258 -0
- package/src/video/VersionPanel.tsx +117 -42
- package/src/video/VideoEditor.tsx +2229 -243
- package/src/video/__tests__/AudioPolishModal.test.tsx +825 -0
- package/src/video/__tests__/CaptionListPanel.font.test.tsx +397 -0
- package/src/video/__tests__/CaptionListPanel.generate.test.tsx +153 -0
- package/src/video/__tests__/CaptionRegenModal.test.tsx +29 -0
- package/src/video/__tests__/CaptionSpecimen.test.tsx +213 -0
- package/src/video/__tests__/CaptionStyleGallery.test.tsx +362 -0
- package/src/video/__tests__/CommandPalette.test.tsx +119 -0
- package/src/video/__tests__/OverlayInspector.test.tsx +1367 -0
- package/src/video/__tests__/RenderModal.exportControls.test.tsx +319 -0
- package/src/video/__tests__/RenderModal.options.test.tsx +562 -0
- package/src/video/__tests__/RenderModal.progress.test.ts +65 -0
- package/src/video/__tests__/VersionCompare.test.tsx +182 -0
- package/src/video/__tests__/VersionPanel.test.tsx +279 -0
- package/src/video/__tests__/VideoEditor.audioPolish.test.tsx +241 -0
- package/src/video/__tests__/VideoEditor.captionDelete.test.tsx +147 -0
- package/src/video/__tests__/VideoEditor.captionGesture.test.tsx +170 -0
- package/src/video/__tests__/VideoEditor.captionSeam.test.tsx +134 -0
- package/src/video/__tests__/VideoEditor.clipKeyframes.test.tsx +59 -0
- package/src/video/__tests__/VideoEditor.context.test.tsx +44 -0
- package/src/video/__tests__/VideoEditor.editFocus.test.tsx +55 -0
- package/src/video/__tests__/VideoEditor.keymap.test.tsx +725 -0
- package/src/video/__tests__/VideoEditor.layout.test.tsx +338 -0
- package/src/video/__tests__/VideoEditor.propertiesPanel.test.tsx +765 -0
- package/src/video/__tests__/VideoEditor.rippleDeleteCaptions.test.tsx +159 -0
- package/src/video/__tests__/VideoEditor.sourcePreview.test.tsx +122 -0
- package/src/video/__tests__/VideoEditor.test.tsx +403 -50
- package/src/video/__tests__/audioMagnet.test.ts +158 -0
- package/src/video/__tests__/audioPolish.test.ts +1202 -0
- package/src/video/__tests__/captionActiveWord.test.ts +107 -0
- package/src/video/__tests__/captionLanes.test.ts +262 -0
- package/src/video/__tests__/captionPositioning.test.tsx +8 -3
- package/src/video/__tests__/captionWordFloor.test.ts +228 -0
- package/src/video/__tests__/clipboard-ops.test.ts +430 -0
- package/src/video/__tests__/cuts.insert.test.ts +244 -0
- package/src/video/__tests__/cuts.test.ts +1213 -34
- package/src/video/__tests__/export-limits.test.ts +195 -0
- package/src/video/__tests__/hover-scrub.test.ts +163 -0
- package/src/video/__tests__/keyframeOps.canKeyframeProp.test.ts +61 -0
- package/src/video/__tests__/keyframeOps.test.ts +643 -0
- package/src/video/__tests__/keymap.test.tsx +171 -0
- package/src/video/__tests__/render-progress.test.tsx +20 -4
- package/src/video/__tests__/shuttle.test.ts +210 -0
- package/src/video/__tests__/source-preview.test.ts +60 -0
- package/src/video/__tests__/timecode.test.ts +77 -0
- package/src/video/__tests__/use-report-context.test.tsx +101 -0
- package/src/video/audioMagnet.ts +72 -0
- package/src/video/audioPolish.ts +774 -0
- package/src/video/captionActiveWord.ts +74 -0
- package/src/video/captionLanes.ts +202 -0
- package/src/video/captionRepair.ts +9 -5
- package/src/video/captionStyleDefaults.ts +100 -0
- package/src/video/captionWordFloor.ts +83 -0
- package/src/video/clipboard-ops.ts +377 -0
- package/src/video/cuts.ts +713 -37
- package/src/video/export-limits.ts +102 -0
- package/src/video/hover-scrub.ts +102 -0
- package/src/video/imageTone.ts +58 -0
- package/src/video/imageToneExamples.ts +10 -0
- package/src/video/keyframeOps.ts +384 -0
- package/src/video/keymap.ts +146 -0
- package/src/video/panels/ClipPropertiesPanel.tsx +706 -0
- package/src/video/panels/LeftPanelTabs.tsx +187 -0
- package/src/video/panels/OverlayContentPanel.tsx +351 -0
- package/src/video/panels/TabNav.tsx +60 -0
- package/src/video/panels/__tests__/ClipPropertiesPanel.test.tsx +645 -0
- package/src/video/panels/__tests__/LeftPanelTabs.test.tsx +189 -0
- package/src/video/panels/__tests__/OverlayContentPanel.test.tsx +222 -0
- package/src/video/panels/__tests__/TabNav.test.tsx +71 -0
- package/src/video/preview/CaptionPreview.tsx +57 -69
- package/src/video/preview/EngineSurface.tsx +103 -0
- package/src/video/preview/OverlayItemsLayer.tsx +315 -103
- package/src/video/preview/PreviewPlayer.tsx +337 -56
- package/src/video/preview/SocialPreviewMenu.tsx +214 -0
- package/src/video/preview/SocialSafeZoneOverlay.tsx +478 -0
- package/src/video/preview/__tests__/CaptionPreview.fonts.test.tsx +97 -0
- package/src/video/preview/__tests__/EngineSurface.test.tsx +114 -0
- package/src/video/preview/__tests__/OverlayItemsLayer.edit.test.tsx +4 -2
- package/src/video/preview/__tests__/OverlayItemsLayer.keyframes.test.tsx +363 -0
- package/src/video/preview/__tests__/OverlayItemsLayer.selection.test.tsx +329 -0
- package/src/video/preview/__tests__/PreviewPlayer.engine.test.tsx +139 -0
- package/src/video/preview/__tests__/SocialPreviewMenu.test.tsx +121 -0
- package/src/video/preview/__tests__/SocialSafeZoneOverlay.test.tsx +165 -0
- package/src/video/preview/__tests__/captionDragState.test.ts +120 -1
- package/src/video/preview/__tests__/latencyCompensation.test.tsx +451 -0
- package/src/video/preview/__tests__/proxySupport.test.ts +75 -0
- package/src/video/preview/__tests__/transformStyle.test.ts +29 -1
- package/src/video/preview/__tests__/useDragOverlay.perAxis.test.ts +197 -0
- package/src/video/preview/__tests__/useEnginePlayback.test.tsx +530 -0
- package/src/video/preview/__tests__/useVideoPlayback.corpus.test.ts +313 -0
- package/src/video/preview/__tests__/useVideoPlayback.test.ts +38 -5
- package/src/video/preview/__tests__/useVideoPlayback.trackAudio.test.ts +278 -0
- package/src/video/preview/audio-context.ts +111 -0
- package/src/video/preview/captionDragState.ts +91 -1
- package/src/video/preview/proxySupport.ts +86 -0
- package/src/video/preview/transformStyle.ts +22 -12
- package/src/video/preview/useDragOverlay.ts +92 -18
- package/src/video/preview/useEnginePlayback.ts +625 -0
- package/src/video/preview/useVideoPlayback.ts +211 -167
- package/src/video/sdrCurves.ts +56 -0
- package/src/video/shuttle.ts +159 -0
- package/src/video/source-preview.ts +66 -0
- package/src/video/timecode.ts +59 -0
- package/src/video/timeline/EditableSegment.tsx +1 -1
- package/src/video/timeline/Scrubber.tsx +46 -174
- package/src/video/timeline/SpeedControl.tsx +95 -0
- package/src/video/timeline/Timeline.tsx +1061 -328
- package/src/video/timeline/TimelineContext.ts +17 -10
- package/src/video/timeline/TrackGutter.tsx +560 -0
- package/src/video/timeline/TrackSettingsPopover.tsx +228 -0
- package/src/video/timeline/VolumeControl.tsx +113 -0
- package/src/video/timeline/__tests__/Timeline.backgroundClick.test.tsx +110 -0
- package/src/video/timeline/__tests__/Timeline.crossfade.test.tsx +104 -0
- package/src/video/timeline/__tests__/Timeline.fadeCurveMenu.test.tsx +174 -0
- package/src/video/timeline/__tests__/Timeline.keyframeDelete.test.tsx +273 -0
- package/src/video/timeline/__tests__/Timeline.keyframeFollow.test.tsx +215 -0
- package/src/video/timeline/__tests__/Timeline.keyframeMenu.test.tsx +253 -0
- package/src/video/timeline/__tests__/Timeline.keymap.test.tsx +372 -0
- package/src/video/timeline/__tests__/Timeline.subcutRegen.test.tsx +351 -0
- package/src/video/timeline/__tests__/TrackGutter.test.tsx +372 -0
- package/src/video/timeline/__tests__/_canvasSelect.test.tsx +273 -0
- package/src/video/timeline/__tests__/_canvasSelect.ts +414 -0
- package/src/video/timeline/__tests__/dragdrop-math.test.ts +135 -0
- package/src/video/timeline/__tests__/effectiveItemAudio.test.ts +50 -0
- package/src/video/timeline/__tests__/enabledTrackItems.test.ts +164 -0
- package/src/video/timeline/__tests__/moveItemAcrossTracks.test.ts +363 -0
- package/src/video/timeline/__tests__/multiSelectOps.test.ts +447 -0
- package/src/video/timeline/__tests__/placement.test.ts +278 -0
- package/src/video/timeline/__tests__/resizeWindowedItem.test.ts +140 -0
- package/src/video/timeline/__tests__/timeline-model.test.ts +576 -0
- package/src/video/timeline/__tests__/visualItemLabel.test.ts +69 -0
- package/src/video/timeline/canvas/TimelineCanvas.tsx +1447 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.drop.test.tsx +439 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.edgeScroll.test.tsx +346 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.panefill.test.tsx +122 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.pendingDrops.test.tsx +316 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.pointer.test.tsx +606 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.test.tsx +407 -0
- package/src/video/timeline/canvas/__tests__/clip-bands.test.ts +77 -0
- package/src/video/timeline/canvas/__tests__/draw.test.ts +2198 -0
- package/src/video/timeline/canvas/__tests__/fade-curve.test.ts +187 -0
- package/src/video/timeline/canvas/__tests__/filmstrips.test.ts +561 -0
- package/src/video/timeline/canvas/__tests__/hit-test.test.ts +818 -0
- package/src/video/timeline/canvas/__tests__/pending-drop.test.ts +210 -0
- package/src/video/timeline/canvas/__tests__/pointer-machine.test.ts +3358 -0
- package/src/video/timeline/canvas/__tests__/snap.test.ts +257 -0
- package/src/video/timeline/canvas/__tests__/viewport.test.ts +399 -0
- package/src/video/timeline/canvas/__tests__/waveforms.test.ts +946 -0
- package/src/video/timeline/canvas/clip-bands.ts +56 -0
- package/src/video/timeline/canvas/draw.ts +2187 -0
- package/src/video/timeline/canvas/fade-curve.ts +111 -0
- package/src/video/timeline/canvas/filmstrips.ts +418 -0
- package/src/video/timeline/canvas/hit-test.ts +501 -0
- package/src/video/timeline/canvas/keyframe-strip.ts +73 -0
- package/src/video/timeline/canvas/pointer-machine.ts +1828 -0
- package/src/video/timeline/canvas/snap.ts +232 -0
- package/src/video/timeline/canvas/viewport.ts +457 -0
- package/src/video/timeline/canvas/waveforms.ts +664 -0
- package/src/video/timeline/makeCaptionEdit.ts +5 -1
- package/src/video/timeline/multiSelectOps.ts +214 -55
- package/src/video/timeline/placement.ts +282 -0
- package/src/video/timeline/timeline-model.ts +919 -0
- package/src/video/timeline/useItemDragDrop.ts +151 -178
- package/src/video/timeline/useTimelineZoom.ts +25 -60
- package/src/video/timeline/utils.ts +0 -12
- package/src/video/use-report-context.ts +75 -0
- package/src/video/preview/OverlayPropsModal.tsx +0 -292
- package/src/video/preview/__tests__/OverlayPropsModal.test.tsx +0 -32
- package/src/video/timeline/AudioTrackRow.tsx +0 -404
- package/src/video/timeline/AudioWaveformLayer.tsx +0 -117
- package/src/video/timeline/CaptionTrackRow.tsx +0 -235
- package/src/video/timeline/PlayheadLine.tsx +0 -18
- package/src/video/timeline/TranscriptModal.tsx +0 -70
- package/src/video/timeline/TranscriptPanel.tsx +0 -273
- package/src/video/timeline/VisualTrackRow.tsx +0 -300
- package/src/video/timeline/__tests__/CaptionTrackRow.test.tsx +0 -241
- package/src/video/timeline/__tests__/PlayheadLine.test.tsx +0 -60
- package/src/video/timeline/__tests__/TranscriptModal.test.tsx +0 -41
- package/src/video/timeline/__tests__/TranscriptPanel.test.tsx +0 -184
- package/src/video/timeline/__tests__/useItemDragDrop.test.ts +0 -72
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SP4 T1 — the playback engine's own eligibility gate.
|
|
3
|
+
*
|
|
4
|
+
* `../video/preview/proxySupport.ts` already gates the LEGACY `<video>`
|
|
5
|
+
* player: it probes `<video>`/MediaSource decode support for the H.264+Opus
|
|
6
|
+
* proxy MIME and strips `proxySrc` from an item when unsupported. The engine
|
|
7
|
+
* never touches `<video>` — it decodes via WebCodecs directly — so it cannot
|
|
8
|
+
* reuse that probe or its cache; it runs its OWN capability read via the
|
|
9
|
+
* `VideoDecoder`/`AudioDecoder` `isConfigSupported` statics. Same target
|
|
10
|
+
* codecs (avc1 video + opus audio, muxed in the SP3 editing-proxy's MP4),
|
|
11
|
+
* two independent browser API surfaces, evaluated independently. Do NOT
|
|
12
|
+
* import `proxySupport.ts` here, and do not import this module there — see
|
|
13
|
+
* the plan's decision 2.
|
|
14
|
+
*
|
|
15
|
+
* Two halves, deliberately separable so the pure part is trivially unit
|
|
16
|
+
* tested without touching the (jsdom-less, WebCodecs-less) browser probe:
|
|
17
|
+
* - `checkProjectShapeEligibility` — pure, sync: every track-0 video item
|
|
18
|
+
* must carry `proxySrc`, and none may require `nobg_preview_src` (a VP9
|
|
19
|
+
* WebM-with-alpha preview — the engine's demuxer is MP4-only in v1).
|
|
20
|
+
* - `engineCapabilitySupported` — async, session-cached, same
|
|
21
|
+
* cache-and-test-hook shape as `proxySupport.ts`'s
|
|
22
|
+
* `proxyPlaybackSupported`.
|
|
23
|
+
* `evaluateEngineEligibility` composes both: shape first (cheap, sync, no
|
|
24
|
+
* await needed when a project already disqualifies itself on content), then
|
|
25
|
+
* the capability probe — matching decision 2's "(a) AND (b)" gate.
|
|
26
|
+
*
|
|
27
|
+
* Called once per project-load; the call-site semantics (a React effect,
|
|
28
|
+
* re-evaluated only on project identity change, with per-clip Preparing-
|
|
29
|
+
* placeholder fallback rather than a whole-project revert) land in T6. This
|
|
30
|
+
* module is the pure/async logic T6 calls into.
|
|
31
|
+
*/
|
|
32
|
+
import type { EditorProject as Project } from '../schema'
|
|
33
|
+
import { trackItems } from '../video/timeline/timeline-model'
|
|
34
|
+
|
|
35
|
+
export interface EligibilityResult {
|
|
36
|
+
eligible: boolean
|
|
37
|
+
reason?: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The SP3 editing proxy's video codec — matches `proxySupport.ts`'s
|
|
42
|
+
* PROXY_MIME target (same encoder output, independently probed via a
|
|
43
|
+
* different API). avc1.640028 = High profile @ level 4.0: libx264's actual
|
|
44
|
+
* default output (High, not Main; 720p above 30fps needs level 4.0 over
|
|
45
|
+
* 3.1). Keep in sync with `lib/proxy.py`'s encoder params — this describes
|
|
46
|
+
* what libx264 emits, not a target to constrain it to.
|
|
47
|
+
*/
|
|
48
|
+
const ENGINE_VIDEO_CODEC = 'avc1.640028'
|
|
49
|
+
/**
|
|
50
|
+
* Opus decodes at a fixed internal rate of 48kHz regardless of source/encode
|
|
51
|
+
* rate (a codec-level guarantee, not a pipeline convention), so probing at
|
|
52
|
+
* 48kHz/stereo is representative of every proxy — see `lib/proxy.py`'s
|
|
53
|
+
* `libopus` encode, which sets no explicit `-ar`/`-ac` and relies on exactly
|
|
54
|
+
* this. Channel count is not load-bearing for `isConfigSupported`'s verdict;
|
|
55
|
+
* 2 matches the documented pipeline assumption.
|
|
56
|
+
*/
|
|
57
|
+
const ENGINE_AUDIO_CODEC = 'opus'
|
|
58
|
+
const ENGINE_AUDIO_SAMPLE_RATE = 48000
|
|
59
|
+
const ENGINE_AUDIO_CHANNELS = 2
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Pure project-shape check: every track-0 video item is proxied and
|
|
63
|
+
* MP4-safe. Vacuously eligible for a project with no track-0 video items
|
|
64
|
+
* (e.g. a canvas-only background-image project) — the scheduler's
|
|
65
|
+
* wall-clock-fallback clock covers those (T5), no video decode required.
|
|
66
|
+
*/
|
|
67
|
+
export function checkProjectShapeEligibility(project: Project): EligibilityResult {
|
|
68
|
+
const videoClips = (trackItems(project)[0] ?? []).filter((item) => item.type === 'video')
|
|
69
|
+
for (const clip of videoClips) {
|
|
70
|
+
if (clip.nobg_preview_src) {
|
|
71
|
+
return {
|
|
72
|
+
eligible: false,
|
|
73
|
+
reason: `clip "${clip.id}" requires nobg_preview_src (WebM alpha) — the engine's demuxer is MP4-only in v1`,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!clip.proxySrc) {
|
|
77
|
+
return { eligible: false, reason: `clip "${clip.id}" has no proxySrc yet` }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { eligible: true }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let capabilityCache: boolean | null = null
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* WebCodecs capability probe: can this browser decode the SP3 editing
|
|
87
|
+
* proxy's codecs (avc1 video + opus audio)? Cached for the session — same
|
|
88
|
+
* shape as `proxySupport.ts`'s `proxyPlaybackSupported`, an independent
|
|
89
|
+
* cache (see the module doc for why the two probes don't share one).
|
|
90
|
+
* `VideoDecoder`/`AudioDecoder` are absent in jsdom/vitest (there is no
|
|
91
|
+
* WebCodecs polyfill for the test environment) and in real non-WebCodecs
|
|
92
|
+
* browsers alike, so the absence branch is the common real-world failure
|
|
93
|
+
* path, not just a test artifact.
|
|
94
|
+
*/
|
|
95
|
+
export async function engineCapabilitySupported(): Promise<boolean> {
|
|
96
|
+
if (capabilityCache !== null) return capabilityCache
|
|
97
|
+
let ok = false
|
|
98
|
+
try {
|
|
99
|
+
if (typeof VideoDecoder !== 'undefined' && typeof AudioDecoder !== 'undefined') {
|
|
100
|
+
const [video, audio] = await Promise.all([
|
|
101
|
+
VideoDecoder.isConfigSupported({ codec: ENGINE_VIDEO_CODEC }),
|
|
102
|
+
AudioDecoder.isConfigSupported({
|
|
103
|
+
codec: ENGINE_AUDIO_CODEC,
|
|
104
|
+
numberOfChannels: ENGINE_AUDIO_CHANNELS,
|
|
105
|
+
sampleRate: ENGINE_AUDIO_SAMPLE_RATE,
|
|
106
|
+
}),
|
|
107
|
+
])
|
|
108
|
+
ok = !!video.supported && !!audio.supported
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
ok = false
|
|
112
|
+
}
|
|
113
|
+
capabilityCache = ok
|
|
114
|
+
return capabilityCache
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Test hook: force (true/false) or reset (null) the cached probe result. */
|
|
118
|
+
export function __setEngineCapabilityForTests(value: boolean | null): void {
|
|
119
|
+
capabilityCache = value
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The full gate a project must pass for the engine to take it over. Either
|
|
124
|
+
* half failing produces a console-ready `reason` (the caller logs it — see
|
|
125
|
+
* T6). `enabled` on the host's `engine` prop is a separate, prior gate (does
|
|
126
|
+
* the host even want to try) — this function only answers "can this
|
|
127
|
+
* specific project run on the engine right now."
|
|
128
|
+
*/
|
|
129
|
+
export async function evaluateEngineEligibility(project: Project): Promise<EligibilityResult> {
|
|
130
|
+
const shape = checkProjectShapeEligibility(project)
|
|
131
|
+
if (!shape.eligible) return shape
|
|
132
|
+
const capable = await engineCapabilitySupported()
|
|
133
|
+
if (!capable) {
|
|
134
|
+
return {
|
|
135
|
+
eligible: false,
|
|
136
|
+
reason: 'WebCodecs avc1/opus decode is not supported in this browser',
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { eligible: true }
|
|
140
|
+
}
|