@editframe/elements 0.17.6-beta.0 → 0.18.7-beta.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/EF_FRAMEGEN.js +1 -1
- package/dist/elements/EFAudio.d.ts +21 -2
- package/dist/elements/EFAudio.js +41 -11
- package/dist/elements/EFImage.d.ts +1 -0
- package/dist/elements/EFImage.js +11 -3
- package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
- package/dist/elements/EFMedia/AssetMediaEngine.browsertest.d.ts +0 -0
- package/dist/elements/EFMedia/AssetMediaEngine.d.ts +45 -0
- package/dist/elements/EFMedia/AssetMediaEngine.js +135 -0
- package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
- package/dist/elements/EFMedia/BaseMediaEngine.js +115 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.js +179 -0
- package/dist/elements/EFMedia/JitMediaEngine.browsertest.d.ts +0 -0
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +31 -0
- package/dist/elements/EFMedia/JitMediaEngine.js +81 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +48 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +141 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +30 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.d.ts +0 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +32 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +28 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +17 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +107 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
- package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
- package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
- package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
- package/dist/elements/EFMedia/shared/PrecisionUtils.d.ts +28 -0
- package/dist/elements/EFMedia/shared/PrecisionUtils.js +29 -0
- package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +34 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +28 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +17 -0
- package/dist/elements/EFMedia.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia.d.ts +63 -111
- package/dist/elements/EFMedia.js +117 -1113
- package/dist/elements/EFTemporal.d.ts +1 -1
- package/dist/elements/EFTemporal.js +1 -1
- package/dist/elements/EFTimegroup.d.ts +11 -0
- package/dist/elements/EFTimegroup.js +83 -13
- package/dist/elements/EFVideo.d.ts +54 -32
- package/dist/elements/EFVideo.js +100 -207
- package/dist/elements/EFWaveform.js +2 -2
- package/dist/elements/SampleBuffer.d.ts +14 -0
- package/dist/elements/SampleBuffer.js +52 -0
- package/dist/getRenderInfo.js +2 -1
- package/dist/gui/ContextMixin.js +3 -2
- package/dist/gui/EFFilmstrip.d.ts +3 -3
- package/dist/gui/EFFilmstrip.js +1 -1
- package/dist/gui/EFFitScale.d.ts +2 -2
- package/dist/gui/TWMixin.js +1 -1
- package/dist/style.css +1 -1
- package/dist/transcoding/cache/CacheManager.d.ts +73 -0
- package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
- package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
- package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
- package/dist/transcoding/types/index.d.ts +242 -0
- package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
- package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
- package/dist/transcoding/utils/UrlGenerator.js +45 -0
- package/dist/transcoding/utils/constants.d.ts +27 -0
- package/dist/utils/LRUCache.d.ts +34 -0
- package/dist/utils/LRUCache.js +115 -0
- package/package.json +3 -3
- package/src/elements/EFAudio.browsertest.ts +189 -49
- package/src/elements/EFAudio.ts +59 -13
- package/src/elements/EFImage.browsertest.ts +42 -0
- package/src/elements/EFImage.ts +23 -3
- package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
- package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
- package/src/elements/EFMedia/AssetMediaEngine.browsertest.ts +100 -0
- package/src/elements/EFMedia/AssetMediaEngine.ts +255 -0
- package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
- package/src/elements/EFMedia/BaseMediaEngine.ts +219 -0
- package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +481 -0
- package/src/elements/EFMedia/BufferedSeekingInput.ts +324 -0
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
- package/src/elements/EFMedia/JitMediaEngine.ts +166 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +250 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +43 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +199 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +64 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +45 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +24 -0
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +183 -0
- package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
- package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
- package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
- package/src/elements/EFMedia/shared/PrecisionUtils.ts +46 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +68 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +43 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +24 -0
- package/src/elements/EFMedia.browsertest.ts +706 -273
- package/src/elements/EFMedia.ts +136 -1769
- package/src/elements/EFTemporal.ts +3 -4
- package/src/elements/EFTimegroup.browsertest.ts +6 -3
- package/src/elements/EFTimegroup.ts +147 -21
- package/src/elements/EFVideo.browsertest.ts +980 -169
- package/src/elements/EFVideo.ts +113 -458
- package/src/elements/EFWaveform.ts +1 -1
- package/src/elements/MediaController.ts +2 -12
- package/src/elements/SampleBuffer.ts +95 -0
- package/src/gui/ContextMixin.ts +3 -6
- package/src/transcoding/cache/CacheManager.ts +208 -0
- package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
- package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
- package/src/transcoding/types/index.ts +269 -0
- package/src/transcoding/utils/MediaUtils.ts +63 -0
- package/src/transcoding/utils/UrlGenerator.ts +68 -0
- package/src/transcoding/utils/constants.ts +36 -0
- package/src/utils/LRUCache.ts +153 -0
- package/test/EFVideo.framegen.browsertest.ts +39 -30
- package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_1_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__9ed2d25c675aa6bb6ff5b3ae23887c71/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_1_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__9ed2d25c675aa6bb6ff5b3ae23887c71/metadata.json +22 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__d5a3309a2bf756dd6e304807eb402f56/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__d5a3309a2bf756dd6e304807eb402f56/metadata.json +22 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__773254bb671e3466fca8677139fb239e/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__773254bb671e3466fca8677139fb239e/metadata.json +22 -0
- package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
- package/test/createJitTestClips.ts +320 -188
- package/test/recordReplayProxyPlugin.js +352 -0
- package/test/useAssetMSW.ts +1 -1
- package/test/useMSW.ts +35 -22
- package/types.json +1 -1
- package/dist/JitTranscodingClient.d.ts +0 -167
- package/dist/JitTranscodingClient.js +0 -373
- package/dist/ScrubTrackManager.d.ts +0 -96
- package/dist/ScrubTrackManager.js +0 -216
- package/dist/elements/printTaskStatus.js +0 -11
- package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
- package/test/EFVideo.frame-tasks.browsertest.ts +0 -524
- /package/dist/{DecoderResetFrequency.test.d.ts → elements/EFMedia/AssetIdMediaEngine.test.d.ts} +0 -0
- /package/dist/{DecoderResetRecovery.test.d.ts → elements/EFMedia/BaseMediaEngine.test.d.ts} +0 -0
- /package/dist/{JitTranscodingClient.browsertest.d.ts → elements/EFMedia/BufferedSeekingInput.browsertest.d.ts} +0 -0
- /package/dist/{JitTranscodingClient.test.d.ts → elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts} +0 -0
- /package/dist/{ScrubTrackIntegration.test.d.ts → elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts} +0 -0
- /package/dist/{SegmentSwitchLoading.test.d.ts → elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts} +0 -0
package/dist/EF_FRAMEGEN.js
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import { Task } from '@lit/task';
|
|
2
2
|
import { EFMedia } from './EFMedia.js';
|
|
3
|
-
|
|
3
|
+
declare const EFAudio_base: typeof EFMedia;
|
|
4
|
+
export declare class EFAudio extends EFAudio_base {
|
|
5
|
+
static get observedAttributes(): string[];
|
|
6
|
+
attributeChangedCallback(name: string, old: string | null, value: string | null): void;
|
|
4
7
|
audioElementRef: import('lit-html/directives/ref.js').Ref<HTMLAudioElement>;
|
|
5
8
|
render(): import('lit-html').TemplateResult<1>;
|
|
6
|
-
get audioElement(): HTMLAudioElement | undefined;
|
|
7
9
|
frameTask: Task<readonly [import('@lit/task').TaskStatus, import('@lit/task').TaskStatus, import('@lit/task').TaskStatus, import('@lit/task').TaskStatus], void>;
|
|
10
|
+
/**
|
|
11
|
+
* Legacy getter for fragment index task (maps to audioSegmentIdTask)
|
|
12
|
+
*/
|
|
13
|
+
get fragmentIndexTask(): Task<readonly [import('../transcoding/types/index.js').MediaEngine | undefined, number], number | undefined>;
|
|
14
|
+
/**
|
|
15
|
+
* Legacy getter for media segments task (maps to audioSegmentFetchTask)
|
|
16
|
+
*/
|
|
17
|
+
get mediaSegmentsTask(): Task<readonly [import('../transcoding/types/index.js').MediaEngine | undefined, number | undefined], ArrayBuffer>;
|
|
18
|
+
/**
|
|
19
|
+
* Legacy getter for seek task (maps to audioSeekTask)
|
|
20
|
+
*/
|
|
21
|
+
get seekTask(): Task<readonly [number, import('./EFMedia/BufferedSeekingInput.js').BufferedSeekingInput | undefined], import('mediabunny').VideoSample | undefined>;
|
|
22
|
+
/**
|
|
23
|
+
* Legacy getter for audio asset task (maps to audioBufferTask)
|
|
24
|
+
*/
|
|
25
|
+
get videoAssetTask(): Task<readonly [number], import('./EFMedia/audioTasks/makeAudioBufferTask.js').AudioBufferState>;
|
|
8
26
|
}
|
|
9
27
|
declare global {
|
|
10
28
|
interface HTMLElementTagNameMap {
|
|
11
29
|
"ef-audio": EFAudio;
|
|
12
30
|
}
|
|
13
31
|
}
|
|
32
|
+
export {};
|
package/dist/elements/EFAudio.js
CHANGED
|
@@ -1,34 +1,64 @@
|
|
|
1
1
|
import { EFMedia } from "./EFMedia.js";
|
|
2
|
+
import { TWMixin } from "../gui/TWMixin2.js";
|
|
2
3
|
import { Task } from "@lit/task";
|
|
3
4
|
import { html } from "lit";
|
|
4
5
|
import { customElement } from "lit/decorators.js";
|
|
5
6
|
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
6
7
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
7
|
-
let EFAudio = class EFAudio$1 extends EFMedia {
|
|
8
|
+
let EFAudio = class EFAudio$1 extends TWMixin(EFMedia) {
|
|
8
9
|
constructor(..._args) {
|
|
9
10
|
super(..._args);
|
|
10
11
|
this.audioElementRef = createRef();
|
|
11
12
|
this.frameTask = new Task(this, {
|
|
12
13
|
args: () => [
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
14
|
+
this.audioBufferTask.status,
|
|
15
|
+
this.audioSeekTask.status,
|
|
16
|
+
this.audioSegmentFetchTask.status,
|
|
17
|
+
this.mediaEngineTask.status
|
|
17
18
|
],
|
|
18
19
|
task: async () => {
|
|
19
|
-
await this.
|
|
20
|
-
await this.
|
|
21
|
-
await this.
|
|
22
|
-
await this.
|
|
20
|
+
await this.mediaEngineTask.taskComplete;
|
|
21
|
+
await this.audioSegmentFetchTask.taskComplete;
|
|
22
|
+
await this.audioSeekTask.taskComplete;
|
|
23
|
+
await this.audioBufferTask.taskComplete;
|
|
23
24
|
this.rootTimegroup?.requestUpdate();
|
|
24
25
|
}
|
|
25
26
|
});
|
|
26
27
|
}
|
|
28
|
+
static get observedAttributes() {
|
|
29
|
+
const parentAttributes = super.observedAttributes || [];
|
|
30
|
+
return [...parentAttributes];
|
|
31
|
+
}
|
|
32
|
+
attributeChangedCallback(name, old, value) {
|
|
33
|
+
super.attributeChangedCallback(name, old, value);
|
|
34
|
+
if (name === "asset-id") this.assetId = value;
|
|
35
|
+
}
|
|
27
36
|
render() {
|
|
28
37
|
return html`<audio ${ref(this.audioElementRef)}></audio>`;
|
|
29
38
|
}
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Legacy getter for fragment index task (maps to audioSegmentIdTask)
|
|
41
|
+
*/
|
|
42
|
+
get fragmentIndexTask() {
|
|
43
|
+
return this.audioSegmentIdTask;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Legacy getter for media segments task (maps to audioSegmentFetchTask)
|
|
47
|
+
*/
|
|
48
|
+
get mediaSegmentsTask() {
|
|
49
|
+
return this.audioSegmentFetchTask;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Legacy getter for seek task (maps to audioSeekTask)
|
|
53
|
+
*/
|
|
54
|
+
get seekTask() {
|
|
55
|
+
return this.audioSeekTask;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Legacy getter for audio asset task (maps to audioBufferTask)
|
|
59
|
+
*/
|
|
60
|
+
get videoAssetTask() {
|
|
61
|
+
return this.audioBufferTask;
|
|
32
62
|
}
|
|
33
63
|
};
|
|
34
64
|
EFAudio = _decorate([customElement("ef-audio")], EFAudio);
|
|
@@ -9,6 +9,7 @@ export declare class EFImage extends EFImage_base {
|
|
|
9
9
|
set assetId(value: string | null);
|
|
10
10
|
get assetId(): string | null;
|
|
11
11
|
render(): import('lit-html').TemplateResult<1>;
|
|
12
|
+
private isDirectUrl;
|
|
12
13
|
assetPath(): string;
|
|
13
14
|
get hasOwnDuration(): boolean;
|
|
14
15
|
fetchImage: Task<readonly [string, typeof fetch], void>;
|
package/dist/elements/EFImage.js
CHANGED
|
@@ -16,11 +16,13 @@ let EFImage = class EFImage$1 extends EFTemporal(EFSourceMixin(FetchMixin(LitEle
|
|
|
16
16
|
autoRun: EF_INTERACTIVE,
|
|
17
17
|
args: () => [this.assetPath(), this.fetch],
|
|
18
18
|
task: async ([assetPath, fetch], { signal }) => {
|
|
19
|
+
if (this.isDirectUrl(assetPath)) return;
|
|
19
20
|
const response = await fetch(assetPath, { signal });
|
|
20
21
|
const image = new Image();
|
|
21
22
|
image.src = URL.createObjectURL(await response.blob());
|
|
22
|
-
await new Promise((resolve) => {
|
|
23
|
+
await new Promise((resolve, reject) => {
|
|
23
24
|
image.onload = resolve;
|
|
25
|
+
image.onerror = reject;
|
|
24
26
|
});
|
|
25
27
|
if (!this.canvasRef.value) throw new Error("Canvas not ready");
|
|
26
28
|
const ctx = this.canvasRef.value.getContext("2d");
|
|
@@ -46,7 +48,7 @@ let EFImage = class EFImage$1 extends EFTemporal(EFSourceMixin(FetchMixin(LitEle
|
|
|
46
48
|
align-items: center;
|
|
47
49
|
justify-content: center;
|
|
48
50
|
}
|
|
49
|
-
canvas {
|
|
51
|
+
canvas, img {
|
|
50
52
|
all: inherit;
|
|
51
53
|
}
|
|
52
54
|
`];
|
|
@@ -59,10 +61,16 @@ let EFImage = class EFImage$1 extends EFTemporal(EFSourceMixin(FetchMixin(LitEle
|
|
|
59
61
|
return this.#assetId ?? this.getAttribute("asset-id");
|
|
60
62
|
}
|
|
61
63
|
render() {
|
|
62
|
-
|
|
64
|
+
const assetPath = this.assetPath();
|
|
65
|
+
const isDirectUrl = this.isDirectUrl(assetPath);
|
|
66
|
+
return isDirectUrl ? html`<img ${ref(this.imageRef)} src=${assetPath} />` : html`<canvas ${ref(this.canvasRef)}></canvas>`;
|
|
67
|
+
}
|
|
68
|
+
isDirectUrl(src) {
|
|
69
|
+
return src.startsWith("http://") || src.startsWith("https://");
|
|
63
70
|
}
|
|
64
71
|
assetPath() {
|
|
65
72
|
if (this.assetId) return `${this.apiHost}/api/v1/image_files/${this.assetId}`;
|
|
73
|
+
if (this.isDirectUrl(this.src)) return this.src;
|
|
66
74
|
return `/@ef-image/${this.src}`;
|
|
67
75
|
}
|
|
68
76
|
get hasOwnDuration() {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TrackFragmentIndex } from '../../../../assets/src/index.ts';
|
|
2
|
+
import { InitSegmentPaths, MediaEngine } from '../../transcoding/types';
|
|
3
|
+
import { UrlGenerator } from '../../transcoding/utils/UrlGenerator';
|
|
4
|
+
import { EFMedia } from '../EFMedia';
|
|
5
|
+
import { AssetMediaEngine } from './AssetMediaEngine';
|
|
6
|
+
export declare class AssetIdMediaEngine extends AssetMediaEngine implements MediaEngine {
|
|
7
|
+
assetId: string;
|
|
8
|
+
private apiHost;
|
|
9
|
+
static fetchByAssetId(host: EFMedia, _urlGenerator: UrlGenerator, assetId: string, apiHost: string): Promise<AssetIdMediaEngine>;
|
|
10
|
+
constructor(host: EFMedia, assetId: string, data: Record<number, TrackFragmentIndex>, apiHost: string);
|
|
11
|
+
get initSegmentPaths(): InitSegmentPaths;
|
|
12
|
+
get templates(): {
|
|
13
|
+
initSegment: string;
|
|
14
|
+
mediaSegment: string;
|
|
15
|
+
};
|
|
16
|
+
buildInitSegmentUrl(trackId: number): string;
|
|
17
|
+
buildMediaSegmentUrl(trackId: number, _segmentId: number): string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AssetMediaEngine } from "./AssetMediaEngine.js";
|
|
2
|
+
var AssetIdMediaEngine = class AssetIdMediaEngine extends AssetMediaEngine {
|
|
3
|
+
static async fetchByAssetId(host, _urlGenerator, assetId, apiHost) {
|
|
4
|
+
const url = `${apiHost}/api/v1/isobmff_files/${assetId}/index`;
|
|
5
|
+
const response = await host.fetch(url);
|
|
6
|
+
const data = await response.json();
|
|
7
|
+
return new AssetIdMediaEngine(host, assetId, data, apiHost);
|
|
8
|
+
}
|
|
9
|
+
constructor(host, assetId, data, apiHost) {
|
|
10
|
+
super(host, assetId, data);
|
|
11
|
+
this.assetId = assetId;
|
|
12
|
+
this.apiHost = apiHost;
|
|
13
|
+
}
|
|
14
|
+
get initSegmentPaths() {
|
|
15
|
+
const paths = {};
|
|
16
|
+
if (this.audioTrackIndex !== void 0) paths.audio = {
|
|
17
|
+
path: `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${this.audioTrackIndex.track}`,
|
|
18
|
+
pos: this.audioTrackIndex.initSegment.offset,
|
|
19
|
+
size: this.audioTrackIndex.initSegment.size
|
|
20
|
+
};
|
|
21
|
+
if (this.videoTrackIndex !== void 0) paths.video = {
|
|
22
|
+
path: `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${this.videoTrackIndex.track}`,
|
|
23
|
+
pos: this.videoTrackIndex.initSegment.offset,
|
|
24
|
+
size: this.videoTrackIndex.initSegment.size
|
|
25
|
+
};
|
|
26
|
+
return paths;
|
|
27
|
+
}
|
|
28
|
+
get templates() {
|
|
29
|
+
return {
|
|
30
|
+
initSegment: `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/{trackId}`,
|
|
31
|
+
mediaSegment: `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/{trackId}`
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
buildInitSegmentUrl(trackId) {
|
|
35
|
+
return `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${trackId}`;
|
|
36
|
+
}
|
|
37
|
+
buildMediaSegmentUrl(trackId, _segmentId) {
|
|
38
|
+
return `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${trackId}`;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export { AssetIdMediaEngine };
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { TrackFragmentIndex } from '../../../../assets/src/index.ts';
|
|
2
|
+
import { AudioRendition, InitSegmentPaths, MediaEngine, SegmentTimeRange } from '../../transcoding/types';
|
|
3
|
+
import { UrlGenerator } from '../../transcoding/utils/UrlGenerator';
|
|
4
|
+
import { EFMedia } from '../EFMedia';
|
|
5
|
+
import { BaseMediaEngine } from './BaseMediaEngine';
|
|
6
|
+
import { MediaRendition } from './shared/MediaTaskUtils';
|
|
7
|
+
export declare class AssetMediaEngine extends BaseMediaEngine implements MediaEngine {
|
|
8
|
+
host: EFMedia;
|
|
9
|
+
src: string;
|
|
10
|
+
protected data: Record<number, TrackFragmentIndex>;
|
|
11
|
+
static fetch(host: EFMedia, urlGenerator: UrlGenerator, src: string): Promise<AssetMediaEngine>;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
constructor(host: EFMedia, src: string, data: Record<number, TrackFragmentIndex>);
|
|
14
|
+
get audioTrackIndex(): import('../../../../assets/src/index.ts').AudioTrackFragmentIndex | undefined;
|
|
15
|
+
get videoTrackIndex(): import('../../../../assets/src/index.ts').VideoTrackFragmentIndex | undefined;
|
|
16
|
+
get videoRendition(): {
|
|
17
|
+
trackId: number | undefined;
|
|
18
|
+
src: string;
|
|
19
|
+
startTimeOffsetMs: number | undefined;
|
|
20
|
+
};
|
|
21
|
+
get audioRendition(): {
|
|
22
|
+
trackId: number | undefined;
|
|
23
|
+
src: string;
|
|
24
|
+
};
|
|
25
|
+
get initSegmentPaths(): InitSegmentPaths;
|
|
26
|
+
get templates(): {
|
|
27
|
+
initSegment: string;
|
|
28
|
+
mediaSegment: string;
|
|
29
|
+
};
|
|
30
|
+
buildInitSegmentUrl(trackId: number): string;
|
|
31
|
+
buildMediaSegmentUrl(trackId: number, segmentId: number): string;
|
|
32
|
+
fetchInitSegment(rendition: {
|
|
33
|
+
trackId: number | undefined;
|
|
34
|
+
src: string;
|
|
35
|
+
}, signal: AbortSignal): Promise<ArrayBuffer>;
|
|
36
|
+
fetchMediaSegmentImpl(segmentId: number, rendition: {
|
|
37
|
+
trackId: number | undefined;
|
|
38
|
+
src: string;
|
|
39
|
+
}, signal?: AbortSignal): Promise<ArrayBuffer>;
|
|
40
|
+
/**
|
|
41
|
+
* Calculate audio segments for variable-duration segments using track fragment index
|
|
42
|
+
*/
|
|
43
|
+
calculateAudioSegmentRange(fromMs: number, toMs: number, rendition: AudioRendition, _durationMs: number): SegmentTimeRange[];
|
|
44
|
+
computeSegmentId(desiredSeekTimeMs: number, rendition: MediaRendition): number;
|
|
45
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { BaseMediaEngine } from "./BaseMediaEngine.js";
|
|
2
|
+
import { convertToScaledTime, roundToMilliseconds } from "./shared/PrecisionUtils.js";
|
|
3
|
+
var AssetMediaEngine = class AssetMediaEngine extends BaseMediaEngine {
|
|
4
|
+
static async fetch(host, urlGenerator, src) {
|
|
5
|
+
const url = urlGenerator.generateTrackFragmentIndexUrl(src);
|
|
6
|
+
const response = await host.fetch(url);
|
|
7
|
+
const data = await response.json();
|
|
8
|
+
if (src.startsWith("/")) src = src.slice(1);
|
|
9
|
+
return new AssetMediaEngine(host, src, data);
|
|
10
|
+
}
|
|
11
|
+
constructor(host, src, data) {
|
|
12
|
+
super();
|
|
13
|
+
this.host = host;
|
|
14
|
+
this.src = src;
|
|
15
|
+
this.data = data;
|
|
16
|
+
const longestFragment = Object.values(data).reduce((max, fragment) => Math.max(max, fragment.duration / fragment.timescale), 0);
|
|
17
|
+
this.durationMs = longestFragment * 1e3;
|
|
18
|
+
}
|
|
19
|
+
get audioTrackIndex() {
|
|
20
|
+
return Object.values(this.data).find((track) => track.type === "audio");
|
|
21
|
+
}
|
|
22
|
+
get videoTrackIndex() {
|
|
23
|
+
return Object.values(this.data).find((track) => track.type === "video");
|
|
24
|
+
}
|
|
25
|
+
get videoRendition() {
|
|
26
|
+
return {
|
|
27
|
+
trackId: this.videoTrackIndex?.track,
|
|
28
|
+
src: this.src,
|
|
29
|
+
startTimeOffsetMs: this.videoTrackIndex?.startTimeOffsetMs
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
get audioRendition() {
|
|
33
|
+
return {
|
|
34
|
+
trackId: this.audioTrackIndex?.track,
|
|
35
|
+
src: this.src
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
get initSegmentPaths() {
|
|
39
|
+
const paths = {};
|
|
40
|
+
if (this.audioTrackIndex !== void 0) paths.audio = {
|
|
41
|
+
path: `@ef-track/${this.audioTrackIndex.track}.m4s`,
|
|
42
|
+
pos: this.audioTrackIndex.initSegment.offset,
|
|
43
|
+
size: this.audioTrackIndex.initSegment.size
|
|
44
|
+
};
|
|
45
|
+
if (this.videoTrackIndex !== void 0) paths.video = {
|
|
46
|
+
path: `/@ef-track/${this.videoTrackIndex.track}.m4s`,
|
|
47
|
+
pos: this.videoTrackIndex.initSegment.offset,
|
|
48
|
+
size: this.videoTrackIndex.initSegment.size
|
|
49
|
+
};
|
|
50
|
+
return paths;
|
|
51
|
+
}
|
|
52
|
+
get templates() {
|
|
53
|
+
return {
|
|
54
|
+
initSegment: "/@ef-track/{src}?trackId={trackId}",
|
|
55
|
+
mediaSegment: "/@ef-track/{src}?trackId={trackId}"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
buildInitSegmentUrl(trackId) {
|
|
59
|
+
return `/@ef-track/${this.src}?trackId=${trackId}`;
|
|
60
|
+
}
|
|
61
|
+
buildMediaSegmentUrl(trackId, segmentId) {
|
|
62
|
+
return `/@ef-track/${this.src}?trackId=${trackId}&segmentId=${segmentId}`;
|
|
63
|
+
}
|
|
64
|
+
async fetchInitSegment(rendition, signal) {
|
|
65
|
+
if (!rendition.trackId) throw new Error("Track ID is required for asset metadata");
|
|
66
|
+
const url = this.buildInitSegmentUrl(rendition.trackId);
|
|
67
|
+
const initSegment = this.data[rendition.trackId]?.initSegment;
|
|
68
|
+
if (!initSegment) throw new Error("Init segment not found");
|
|
69
|
+
const headers = { Range: `bytes=${initSegment.offset}-${initSegment.offset + initSegment.size - 1}` };
|
|
70
|
+
return this.fetchMediaCacheWithHeaders(url, headers, signal);
|
|
71
|
+
}
|
|
72
|
+
async fetchMediaSegmentImpl(segmentId, rendition, signal) {
|
|
73
|
+
if (!rendition.trackId) throw new Error("Track ID is required for asset metadata");
|
|
74
|
+
if (segmentId === void 0) throw new Error("Segment ID is not available");
|
|
75
|
+
const url = this.buildMediaSegmentUrl(rendition.trackId, segmentId);
|
|
76
|
+
const mediaSegment = this.data[rendition.trackId]?.segments[segmentId];
|
|
77
|
+
if (!mediaSegment) throw new Error("Media segment not found");
|
|
78
|
+
const headers = { Range: `bytes=${mediaSegment.offset}-${mediaSegment.offset + mediaSegment.size - 1}` };
|
|
79
|
+
return this.fetchMediaCacheWithHeaders(url, headers, signal);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Calculate audio segments for variable-duration segments using track fragment index
|
|
83
|
+
*/
|
|
84
|
+
calculateAudioSegmentRange(fromMs, toMs, rendition, _durationMs) {
|
|
85
|
+
if (fromMs >= toMs || !rendition.trackId) return [];
|
|
86
|
+
const track = this.data[rendition.trackId];
|
|
87
|
+
if (!track) return [];
|
|
88
|
+
const { timescale, segments } = track;
|
|
89
|
+
const segmentRanges = [];
|
|
90
|
+
for (let i = 0; i < segments.length; i++) {
|
|
91
|
+
const segment = segments[i];
|
|
92
|
+
const segmentStartTime = segment.cts;
|
|
93
|
+
const segmentEndTime = segment.cts + segment.duration;
|
|
94
|
+
const segmentStartMs = segmentStartTime / timescale * 1e3;
|
|
95
|
+
const segmentEndMs = segmentEndTime / timescale * 1e3;
|
|
96
|
+
if (segmentStartMs < toMs && segmentEndMs > fromMs) segmentRanges.push({
|
|
97
|
+
segmentId: i,
|
|
98
|
+
startMs: segmentStartMs,
|
|
99
|
+
endMs: segmentEndMs
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return segmentRanges;
|
|
103
|
+
}
|
|
104
|
+
computeSegmentId(desiredSeekTimeMs, rendition) {
|
|
105
|
+
if (!rendition.trackId) throw new Error("Track ID is required for asset metadata");
|
|
106
|
+
const track = this.data[rendition.trackId];
|
|
107
|
+
if (!track) throw new Error("Track not found");
|
|
108
|
+
const { timescale, segments } = track;
|
|
109
|
+
const startTimeOffsetMs = "startTimeOffsetMs" in rendition && rendition.startTimeOffsetMs || 0;
|
|
110
|
+
const mediaTimeMs = roundToMilliseconds(desiredSeekTimeMs + startTimeOffsetMs);
|
|
111
|
+
const scaledSeekTime = convertToScaledTime(mediaTimeMs, timescale);
|
|
112
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
113
|
+
const segment = segments[i];
|
|
114
|
+
const segmentEndTime = segment.cts + segment.duration;
|
|
115
|
+
if (segment.cts <= scaledSeekTime && scaledSeekTime < segmentEndTime) return i;
|
|
116
|
+
}
|
|
117
|
+
let nearestSegmentIndex = 0;
|
|
118
|
+
let nearestDistance = Number.MAX_SAFE_INTEGER;
|
|
119
|
+
for (let i = 0; i < segments.length; i++) {
|
|
120
|
+
const segment = segments[i];
|
|
121
|
+
const segmentStartTime = segment.cts;
|
|
122
|
+
const segmentEndTime = segment.cts + segment.duration;
|
|
123
|
+
let distance;
|
|
124
|
+
if (scaledSeekTime < segmentStartTime) distance = segmentStartTime - scaledSeekTime;
|
|
125
|
+
else if (scaledSeekTime >= segmentEndTime) distance = scaledSeekTime - segmentEndTime;
|
|
126
|
+
else return i;
|
|
127
|
+
if (distance < nearestDistance) {
|
|
128
|
+
nearestDistance = distance;
|
|
129
|
+
nearestSegmentIndex = i;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return nearestSegmentIndex;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
export { AssetMediaEngine };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AudioRendition, SegmentTimeRange, VideoRendition } from '../../transcoding/types';
|
|
2
|
+
import { EFMedia } from '../EFMedia.js';
|
|
3
|
+
export declare abstract class BaseMediaEngine {
|
|
4
|
+
private requestDeduplicator;
|
|
5
|
+
abstract get videoRendition(): VideoRendition | undefined;
|
|
6
|
+
abstract get audioRendition(): AudioRendition | undefined;
|
|
7
|
+
abstract get host(): EFMedia;
|
|
8
|
+
getVideoRendition(): VideoRendition;
|
|
9
|
+
getAudioRendition(): AudioRendition;
|
|
10
|
+
/**
|
|
11
|
+
* Generate cache key for segment requests
|
|
12
|
+
*/
|
|
13
|
+
private getSegmentCacheKey;
|
|
14
|
+
/**
|
|
15
|
+
* Abstract method for actual segment fetching - implemented by subclasses
|
|
16
|
+
*/
|
|
17
|
+
abstract fetchMediaSegmentImpl(segmentId: number, rendition: {
|
|
18
|
+
trackId: number | undefined;
|
|
19
|
+
src: string;
|
|
20
|
+
}): Promise<ArrayBuffer>;
|
|
21
|
+
/**
|
|
22
|
+
* Fetch media segment with built-in deduplication
|
|
23
|
+
* Eliminates the need for separate coordinators - cleaner architecture
|
|
24
|
+
*/
|
|
25
|
+
fetchMediaSegment(segmentId: number, rendition: {
|
|
26
|
+
trackId: number | undefined;
|
|
27
|
+
src: string;
|
|
28
|
+
}, _signal?: AbortSignal): Promise<ArrayBuffer>;
|
|
29
|
+
/**
|
|
30
|
+
* Check if a segment is currently being fetched
|
|
31
|
+
*/
|
|
32
|
+
isSegmentBeingFetched(segmentId: number, rendition: {
|
|
33
|
+
src: string;
|
|
34
|
+
trackId: number | undefined;
|
|
35
|
+
}): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Get count of active segment requests (for debugging/monitoring)
|
|
38
|
+
*/
|
|
39
|
+
getActiveSegmentRequestCount(): number;
|
|
40
|
+
/**
|
|
41
|
+
* Cancel all active segment requests (for cleanup)
|
|
42
|
+
*/
|
|
43
|
+
cancelAllSegmentRequests(): void;
|
|
44
|
+
fetchMediaCache(mediaUrl: string): Promise<ArrayBuffer>;
|
|
45
|
+
/**
|
|
46
|
+
* Enhanced caching method that supports custom headers (e.g., Range requests)
|
|
47
|
+
* Cache key includes both URL and headers for proper cache isolation
|
|
48
|
+
*/
|
|
49
|
+
fetchMediaCacheWithHeaders(mediaUrl: string, headers?: Record<string, string>, signal?: AbortSignal): Promise<ArrayBuffer>;
|
|
50
|
+
/**
|
|
51
|
+
* Calculate audio segments needed for a time range
|
|
52
|
+
* Each media engine implements this based on their segment structure
|
|
53
|
+
*/
|
|
54
|
+
calculateAudioSegmentRange(fromMs: number, toMs: number, rendition: AudioRendition, durationMs: number): SegmentTimeRange[];
|
|
55
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { RequestDeduplicator } from "../../transcoding/cache/RequestDeduplicator.js";
|
|
2
|
+
import { SizeAwareLRUCache } from "../../utils/LRUCache.js";
|
|
3
|
+
const mediaCache = new SizeAwareLRUCache(100 * 1024 * 1024);
|
|
4
|
+
var BaseMediaEngine = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.requestDeduplicator = new RequestDeduplicator();
|
|
7
|
+
}
|
|
8
|
+
getVideoRendition() {
|
|
9
|
+
if (!this.videoRendition) throw new Error("No video rendition available");
|
|
10
|
+
return this.videoRendition;
|
|
11
|
+
}
|
|
12
|
+
getAudioRendition() {
|
|
13
|
+
if (!this.audioRendition) throw new Error("No audio rendition available");
|
|
14
|
+
return this.audioRendition;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate cache key for segment requests
|
|
18
|
+
*/
|
|
19
|
+
getSegmentCacheKey(segmentId, rendition) {
|
|
20
|
+
return `${rendition.src}-${rendition.id}-${segmentId}-${rendition.trackId}`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Fetch media segment with built-in deduplication
|
|
24
|
+
* Eliminates the need for separate coordinators - cleaner architecture
|
|
25
|
+
*/
|
|
26
|
+
async fetchMediaSegment(segmentId, rendition, _signal) {
|
|
27
|
+
const cacheKey = this.getSegmentCacheKey(segmentId, rendition);
|
|
28
|
+
return this.requestDeduplicator.executeRequest(cacheKey, async () => {
|
|
29
|
+
return this.fetchMediaSegmentImpl(segmentId, rendition);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if a segment is currently being fetched
|
|
34
|
+
*/
|
|
35
|
+
isSegmentBeingFetched(segmentId, rendition) {
|
|
36
|
+
const cacheKey = this.getSegmentCacheKey(segmentId, rendition);
|
|
37
|
+
return this.requestDeduplicator.isPending(cacheKey);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get count of active segment requests (for debugging/monitoring)
|
|
41
|
+
*/
|
|
42
|
+
getActiveSegmentRequestCount() {
|
|
43
|
+
return this.requestDeduplicator.getPendingCount();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Cancel all active segment requests (for cleanup)
|
|
47
|
+
*/
|
|
48
|
+
cancelAllSegmentRequests() {
|
|
49
|
+
this.requestDeduplicator.clear();
|
|
50
|
+
}
|
|
51
|
+
async fetchMediaCache(mediaUrl) {
|
|
52
|
+
const cached = mediaCache.get(mediaUrl);
|
|
53
|
+
if (cached) return cached;
|
|
54
|
+
const promise = this.host.fetch(mediaUrl).then((response) => response.arrayBuffer());
|
|
55
|
+
mediaCache.set(mediaUrl, promise);
|
|
56
|
+
return promise;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Enhanced caching method that supports custom headers (e.g., Range requests)
|
|
60
|
+
* Cache key includes both URL and headers for proper cache isolation
|
|
61
|
+
*/
|
|
62
|
+
async fetchMediaCacheWithHeaders(mediaUrl, headers, signal) {
|
|
63
|
+
const cacheKey = headers ? `${mediaUrl}:${JSON.stringify(headers)}` : mediaUrl;
|
|
64
|
+
const cached = mediaCache.get(cacheKey);
|
|
65
|
+
if (cached) return cached;
|
|
66
|
+
const promise = this.host.fetch(mediaUrl, {
|
|
67
|
+
headers,
|
|
68
|
+
signal
|
|
69
|
+
}).then((response) => response.arrayBuffer());
|
|
70
|
+
mediaCache.set(cacheKey, promise);
|
|
71
|
+
return promise;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Calculate audio segments needed for a time range
|
|
75
|
+
* Each media engine implements this based on their segment structure
|
|
76
|
+
*/
|
|
77
|
+
calculateAudioSegmentRange(fromMs, toMs, rendition, durationMs) {
|
|
78
|
+
if (fromMs >= toMs) return [];
|
|
79
|
+
const segments = [];
|
|
80
|
+
if (rendition.segmentDurationsMs && rendition.segmentDurationsMs.length > 0) {
|
|
81
|
+
let cumulativeTime = 0;
|
|
82
|
+
for (let i = 0; i < rendition.segmentDurationsMs.length; i++) {
|
|
83
|
+
const segmentDuration = rendition.segmentDurationsMs[i];
|
|
84
|
+
if (segmentDuration === void 0) continue;
|
|
85
|
+
const segmentStartMs = cumulativeTime;
|
|
86
|
+
const segmentEndMs = Math.min(cumulativeTime + segmentDuration, durationMs);
|
|
87
|
+
if (segmentStartMs >= durationMs) break;
|
|
88
|
+
if (segmentStartMs < toMs && segmentEndMs > fromMs) segments.push({
|
|
89
|
+
segmentId: i + 1,
|
|
90
|
+
startMs: segmentStartMs,
|
|
91
|
+
endMs: segmentEndMs
|
|
92
|
+
});
|
|
93
|
+
cumulativeTime += segmentDuration;
|
|
94
|
+
if (cumulativeTime >= durationMs) break;
|
|
95
|
+
}
|
|
96
|
+
return segments;
|
|
97
|
+
}
|
|
98
|
+
const segmentDurationMs = rendition.segmentDurationMs || 1e3;
|
|
99
|
+
const startSegmentIndex = Math.floor(fromMs / segmentDurationMs);
|
|
100
|
+
const endSegmentIndex = Math.floor(toMs / segmentDurationMs);
|
|
101
|
+
for (let i = startSegmentIndex; i <= endSegmentIndex; i++) {
|
|
102
|
+
const segmentId = i + 1;
|
|
103
|
+
const segmentStartMs = i * segmentDurationMs;
|
|
104
|
+
const segmentEndMs = Math.min((i + 1) * segmentDurationMs, durationMs);
|
|
105
|
+
if (segmentStartMs >= durationMs) break;
|
|
106
|
+
if (segmentStartMs < toMs && segmentEndMs > fromMs) segments.push({
|
|
107
|
+
segmentId,
|
|
108
|
+
startMs: segmentStartMs,
|
|
109
|
+
endMs: segmentEndMs
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return segments;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
export { BaseMediaEngine };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { MediaSample } from '../SampleBuffer';
|
|
2
|
+
interface BufferedSeekingInputOptions {
|
|
3
|
+
videoBufferSize?: number;
|
|
4
|
+
audioBufferSize?: number;
|
|
5
|
+
/**
|
|
6
|
+
* Timeline offset in milliseconds to map user timeline to media timeline.
|
|
7
|
+
* Applied during seeking to handle media that doesn't start at 0ms.
|
|
8
|
+
*/
|
|
9
|
+
startTimeOffsetMs?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class NoSample extends RangeError {
|
|
12
|
+
}
|
|
13
|
+
export declare class BufferedSeekingInput {
|
|
14
|
+
private input;
|
|
15
|
+
private trackIterators;
|
|
16
|
+
private trackBuffers;
|
|
17
|
+
private options;
|
|
18
|
+
private trackIteratorCreationPromises;
|
|
19
|
+
private trackSeekPromises;
|
|
20
|
+
/**
|
|
21
|
+
* Timeline offset in milliseconds to map user timeline to media timeline.
|
|
22
|
+
* Applied during seeking to handle media that doesn't start at 0ms.
|
|
23
|
+
*/
|
|
24
|
+
private readonly startTimeOffsetMs;
|
|
25
|
+
constructor(arrayBuffer: ArrayBuffer, options?: BufferedSeekingInputOptions);
|
|
26
|
+
getBufferSize(trackId: number): number;
|
|
27
|
+
getBufferContents(trackId: number): readonly MediaSample[];
|
|
28
|
+
getBufferTimestamps(trackId: number): number[];
|
|
29
|
+
clearBuffer(trackId: number): void;
|
|
30
|
+
computeDuration(): Promise<number>;
|
|
31
|
+
getTrack(trackId: number): Promise<import('mediabunny').InputTrack>;
|
|
32
|
+
getAudioTrack(trackId: number): Promise<import('mediabunny').InputAudioTrack>;
|
|
33
|
+
getVideoTrack(trackId: number): Promise<import('mediabunny').InputVideoTrack>;
|
|
34
|
+
getFirstVideoTrack(): Promise<import('mediabunny').InputVideoTrack | undefined>;
|
|
35
|
+
getFirstAudioTrack(): Promise<import('mediabunny').InputAudioTrack | undefined>;
|
|
36
|
+
getTrackIterator(trackId: number): Promise<AsyncIterator<MediaSample, any, undefined>>;
|
|
37
|
+
private createIteratorSafe;
|
|
38
|
+
createTrackBuffer(trackId: number): Promise<void>;
|
|
39
|
+
seek(trackId: number, timeMs: number): Promise<MediaSample | undefined>;
|
|
40
|
+
private resetIterator;
|
|
41
|
+
private seekSafe;
|
|
42
|
+
}
|
|
43
|
+
export {};
|