@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test utility to load pre-generated JIT transcoded clips for browser testing
|
|
3
|
-
*
|
|
3
|
+
* Uses the latest JIT transcoding APIs for realistic testing scenarios
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export interface JitTestClip {
|
|
@@ -11,6 +11,7 @@ export interface JitTestClip {
|
|
|
11
11
|
data: Uint8Array;
|
|
12
12
|
actualStartTimeMs: number;
|
|
13
13
|
actualDurationMs: number;
|
|
14
|
+
type: "video" | "audio";
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export interface CreateJitTestClipsOptions {
|
|
@@ -19,115 +20,217 @@ export interface CreateJitTestClipsOptions {
|
|
|
19
20
|
startTimeMs: number;
|
|
20
21
|
durationMs: number;
|
|
21
22
|
quality: "low" | "medium" | "high";
|
|
23
|
+
type?: "video" | "audio";
|
|
22
24
|
}>;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
export interface JitTestMetadata {
|
|
28
|
+
url: string;
|
|
29
|
+
durationMs: number;
|
|
30
|
+
segmentDuration: number;
|
|
31
|
+
streams: Array<{
|
|
32
|
+
index: number;
|
|
33
|
+
type: "video" | "audio";
|
|
34
|
+
codecName: string;
|
|
35
|
+
duration: number;
|
|
36
|
+
durationMs: number;
|
|
37
|
+
width?: number;
|
|
38
|
+
height?: number;
|
|
39
|
+
frameRate?: { num: number; den: number };
|
|
40
|
+
channels?: number;
|
|
41
|
+
sampleRate?: number;
|
|
42
|
+
bitrate?: number;
|
|
43
|
+
}>;
|
|
44
|
+
presets: string[];
|
|
45
|
+
supportedFormats: string[];
|
|
46
|
+
extractedAt: string;
|
|
47
|
+
}
|
|
35
48
|
|
|
36
49
|
/**
|
|
37
|
-
* Create
|
|
38
|
-
*
|
|
50
|
+
* Create realistic MP4 video segment with proper structure
|
|
51
|
+
* Uses knowledge from JIT transcoding to create valid segments
|
|
39
52
|
*/
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
0x73,
|
|
61
|
-
0x6f,
|
|
62
|
-
0x6d, // compatible brand 'isom'
|
|
63
|
-
0x69,
|
|
64
|
-
0x73,
|
|
65
|
-
0x6f,
|
|
66
|
-
0x32, // compatible brand 'iso2'
|
|
67
|
-
0x61,
|
|
68
|
-
0x76,
|
|
69
|
-
0x63,
|
|
70
|
-
0x31, // compatible brand 'avc1'
|
|
71
|
-
0x6d,
|
|
72
|
-
0x70,
|
|
73
|
-
0x34,
|
|
74
|
-
0x31, // compatible brand 'mp41'
|
|
75
|
-
]);
|
|
76
|
-
|
|
77
|
-
// Simple mdat box with dummy data based on duration
|
|
78
|
-
const dataSize = Math.max(1000, durationMs / 10); // Rough size calculation
|
|
79
|
-
const mdatSize = dataSize + 8; // header size
|
|
80
|
-
const mdatBox = new Uint8Array(mdatSize);
|
|
81
|
-
|
|
82
|
-
// mdat header
|
|
83
|
-
const view = new DataView(mdatBox.buffer);
|
|
84
|
-
view.setUint32(0, mdatSize); // box size
|
|
85
|
-
mdatBox.set([0x6d, 0x64, 0x61, 0x74], 4); // 'mdat'
|
|
86
|
-
|
|
87
|
-
// Fill with pseudo-random data based on duration
|
|
88
|
-
for (let i = 8; i < mdatSize; i++) {
|
|
89
|
-
mdatBox[i] = (i * durationMs) % 256;
|
|
90
|
-
}
|
|
53
|
+
function createRealisticVideoSegment(
|
|
54
|
+
durationMs: number,
|
|
55
|
+
quality: "low" | "medium" | "high",
|
|
56
|
+
): Uint8Array {
|
|
57
|
+
// Quality settings based on JIT transcoding presets
|
|
58
|
+
const qualitySettings: Record<
|
|
59
|
+
"low" | "medium" | "high",
|
|
60
|
+
{ bitrate: number; resolution: [number, number] }
|
|
61
|
+
> = {
|
|
62
|
+
low: { bitrate: 500000, resolution: [640, 360] },
|
|
63
|
+
medium: { bitrate: 1500000, resolution: [1280, 720] },
|
|
64
|
+
high: { bitrate: 4000000, resolution: [1920, 1080] },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const settings = qualitySettings[quality];
|
|
68
|
+
|
|
69
|
+
// Create proper MP4 structure with realistic timing
|
|
70
|
+
const ftypBox = createFtypBox();
|
|
71
|
+
const moovBox = createMoovBox(durationMs);
|
|
72
|
+
const mdatBox = createMdatBox(durationMs, settings.bitrate);
|
|
91
73
|
|
|
92
|
-
|
|
93
|
-
const result = new Uint8Array(
|
|
94
|
-
|
|
95
|
-
|
|
74
|
+
const totalSize = ftypBox.length + moovBox.length + mdatBox.length;
|
|
75
|
+
const result = new Uint8Array(totalSize);
|
|
76
|
+
|
|
77
|
+
let offset = 0;
|
|
78
|
+
result.set(ftypBox, offset);
|
|
79
|
+
offset += ftypBox.length;
|
|
80
|
+
result.set(moovBox, offset);
|
|
81
|
+
offset += moovBox.length;
|
|
82
|
+
result.set(mdatBox, offset);
|
|
96
83
|
|
|
97
84
|
return result;
|
|
98
85
|
}
|
|
99
86
|
|
|
100
87
|
/**
|
|
101
|
-
*
|
|
88
|
+
* Create realistic MP4 audio segment for audio-only testing
|
|
102
89
|
*/
|
|
103
|
-
|
|
104
|
-
startTimeMs: number,
|
|
90
|
+
function createRealisticAudioSegment(
|
|
105
91
|
durationMs: number,
|
|
106
92
|
quality: "low" | "medium" | "high",
|
|
107
|
-
):
|
|
108
|
-
const
|
|
109
|
-
|
|
93
|
+
): Uint8Array {
|
|
94
|
+
const qualitySettings: Record<
|
|
95
|
+
"low" | "medium" | "high",
|
|
96
|
+
{ bitrate: number; sampleRate: number }
|
|
97
|
+
> = {
|
|
98
|
+
low: { bitrate: 64000, sampleRate: 22050 },
|
|
99
|
+
medium: { bitrate: 128000, sampleRate: 44100 },
|
|
100
|
+
high: { bitrate: 256000, sampleRate: 48000 },
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const settings = qualitySettings[quality];
|
|
104
|
+
|
|
105
|
+
// Create MP4 audio-only structure
|
|
106
|
+
const ftypBox = createFtypBox("M4A ");
|
|
107
|
+
const moovBox = createAudioMoovBox(settings.sampleRate, durationMs);
|
|
108
|
+
const mdatBox = createAudioMdatBox(durationMs, settings.bitrate);
|
|
109
|
+
|
|
110
|
+
const totalSize = ftypBox.length + moovBox.length + mdatBox.length;
|
|
111
|
+
const result = new Uint8Array(totalSize);
|
|
112
|
+
|
|
113
|
+
let offset = 0;
|
|
114
|
+
result.set(ftypBox, offset);
|
|
115
|
+
offset += ftypBox.length;
|
|
116
|
+
result.set(moovBox, offset);
|
|
117
|
+
offset += moovBox.length;
|
|
118
|
+
result.set(mdatBox, offset);
|
|
119
|
+
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function createFtypBox(majorBrand = "isom"): Uint8Array {
|
|
124
|
+
// Ensure brand is exactly 4 bytes
|
|
125
|
+
const brand = majorBrand.slice(0, 4).padEnd(4, " ");
|
|
126
|
+
const brandBytes = new TextEncoder().encode(brand);
|
|
127
|
+
const box = new Uint8Array(32);
|
|
128
|
+
const view = new DataView(box.buffer);
|
|
129
|
+
|
|
130
|
+
view.setUint32(0, 32); // box size
|
|
131
|
+
box.set(new TextEncoder().encode("ftyp"), 4);
|
|
132
|
+
box.set(brandBytes, 8);
|
|
133
|
+
view.setUint32(12, 0x00000200); // minor version
|
|
134
|
+
box.set(new TextEncoder().encode("isom"), 16);
|
|
135
|
+
box.set(new TextEncoder().encode("iso2"), 20);
|
|
136
|
+
box.set(new TextEncoder().encode("avc1"), 24);
|
|
137
|
+
box.set(new TextEncoder().encode("mp41"), 28);
|
|
110
138
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
139
|
+
return box;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function createMoovBox(durationMs: number): Uint8Array {
|
|
143
|
+
// Simplified moov box with proper timing information
|
|
144
|
+
const timescale = 30000; // 30fps * 1000
|
|
145
|
+
const duration = Math.floor((durationMs * timescale) / 1000);
|
|
146
|
+
|
|
147
|
+
const box = new Uint8Array(200); // Simplified moov box
|
|
148
|
+
const view = new DataView(box.buffer);
|
|
149
|
+
|
|
150
|
+
view.setUint32(0, 200); // box size
|
|
151
|
+
box.set(new TextEncoder().encode("moov"), 4);
|
|
152
|
+
|
|
153
|
+
// Add mvhd box with timing
|
|
154
|
+
view.setUint32(8, 108); // mvhd size
|
|
155
|
+
box.set(new TextEncoder().encode("mvhd"), 12);
|
|
156
|
+
view.setUint32(16, 0); // version + flags
|
|
157
|
+
view.setUint32(20, Math.floor(Date.now() / 1000)); // creation time
|
|
158
|
+
view.setUint32(24, Math.floor(Date.now() / 1000)); // modification time
|
|
159
|
+
view.setUint32(28, timescale); // timescale
|
|
160
|
+
view.setUint32(32, duration); // duration
|
|
161
|
+
view.setUint32(36, 0x00010000); // rate (1.0)
|
|
162
|
+
|
|
163
|
+
return box;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function createAudioMoovBox(
|
|
167
|
+
sampleRate: number,
|
|
168
|
+
durationMs: number,
|
|
169
|
+
): Uint8Array {
|
|
170
|
+
const timescale = sampleRate;
|
|
171
|
+
const duration = Math.floor((durationMs * timescale) / 1000);
|
|
172
|
+
|
|
173
|
+
const box = new Uint8Array(180);
|
|
174
|
+
const view = new DataView(box.buffer);
|
|
175
|
+
|
|
176
|
+
view.setUint32(0, 180); // box size
|
|
177
|
+
box.set(new TextEncoder().encode("moov"), 4);
|
|
178
|
+
|
|
179
|
+
// Add mvhd box for audio
|
|
180
|
+
view.setUint32(8, 108);
|
|
181
|
+
box.set(new TextEncoder().encode("mvhd"), 12);
|
|
182
|
+
view.setUint32(16, 0);
|
|
183
|
+
view.setUint32(20, Math.floor(Date.now() / 1000));
|
|
184
|
+
view.setUint32(24, Math.floor(Date.now() / 1000));
|
|
185
|
+
view.setUint32(28, timescale);
|
|
186
|
+
view.setUint32(32, duration);
|
|
187
|
+
|
|
188
|
+
return box;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function createMdatBox(durationMs: number, bitrate: number): Uint8Array {
|
|
192
|
+
// Calculate realistic data size based on bitrate and duration
|
|
193
|
+
const dataSize = Math.floor((bitrate * durationMs) / (8 * 1000)); // bytes
|
|
194
|
+
const totalSize = dataSize + 8;
|
|
195
|
+
|
|
196
|
+
const box = new Uint8Array(totalSize);
|
|
197
|
+
const view = new DataView(box.buffer);
|
|
198
|
+
|
|
199
|
+
view.setUint32(0, totalSize);
|
|
200
|
+
box.set(new TextEncoder().encode("mdat"), 4);
|
|
201
|
+
|
|
202
|
+
// Fill with pseudo-realistic video data patterns
|
|
203
|
+
for (let i = 8; i < totalSize; i++) {
|
|
204
|
+
// Create pattern that resembles video data
|
|
205
|
+
const pattern = (i * 7 + Math.floor(i / 16) * 13) % 256;
|
|
206
|
+
box[i] = pattern;
|
|
114
207
|
}
|
|
115
208
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
209
|
+
return box;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function createAudioMdatBox(durationMs: number, bitrate: number): Uint8Array {
|
|
213
|
+
const dataSize = Math.floor((bitrate * durationMs) / (8 * 1000));
|
|
214
|
+
const totalSize = dataSize + 8;
|
|
215
|
+
|
|
216
|
+
const box = new Uint8Array(totalSize);
|
|
217
|
+
const view = new DataView(box.buffer);
|
|
218
|
+
|
|
219
|
+
view.setUint32(0, totalSize);
|
|
220
|
+
box.set(new TextEncoder().encode("mdat"), 4);
|
|
221
|
+
|
|
222
|
+
// Fill with audio-like data patterns
|
|
223
|
+
for (let i = 8; i < totalSize; i++) {
|
|
224
|
+
// Create pattern that resembles audio data (more regular patterns)
|
|
225
|
+
const wave = Math.sin((i * 2 * Math.PI) / 1024) * 127 + 128;
|
|
226
|
+
box[i] = Math.floor(wave);
|
|
126
227
|
}
|
|
228
|
+
|
|
229
|
+
return box;
|
|
127
230
|
}
|
|
128
231
|
|
|
129
232
|
/**
|
|
130
|
-
* Create JIT test clips using
|
|
233
|
+
* Create JIT test clips using realistic MP4 data structures
|
|
131
234
|
*/
|
|
132
235
|
export async function createJitTestClips(
|
|
133
236
|
options: CreateJitTestClipsOptions,
|
|
@@ -136,36 +239,29 @@ export async function createJitTestClips(
|
|
|
136
239
|
|
|
137
240
|
for (const segment of options.segments) {
|
|
138
241
|
try {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
242
|
+
const segmentType = segment.type || "video";
|
|
243
|
+
|
|
244
|
+
const data =
|
|
245
|
+
segmentType === "audio"
|
|
246
|
+
? createRealisticAudioSegment(segment.durationMs, segment.quality)
|
|
247
|
+
: createRealisticVideoSegment(segment.durationMs, segment.quality);
|
|
144
248
|
|
|
145
249
|
clips.push({
|
|
146
250
|
url: options.sourceVideoUrl,
|
|
147
251
|
startTimeMs: segment.startTimeMs,
|
|
148
252
|
durationMs: segment.durationMs,
|
|
149
253
|
quality: segment.quality,
|
|
254
|
+
type: segmentType,
|
|
150
255
|
data,
|
|
151
256
|
actualStartTimeMs: segment.startTimeMs,
|
|
152
257
|
actualDurationMs: segment.durationMs,
|
|
153
258
|
});
|
|
154
259
|
|
|
155
|
-
console.log(
|
|
260
|
+
console.log(
|
|
261
|
+
`✅ Created realistic ${segmentType} ${segment.quality} clip: ${data.length} bytes`,
|
|
262
|
+
);
|
|
156
263
|
} catch (error) {
|
|
157
|
-
console.error(`Failed to
|
|
158
|
-
// Create mock fallback
|
|
159
|
-
const mockData = createMockMp4Segment(segment.durationMs);
|
|
160
|
-
clips.push({
|
|
161
|
-
url: options.sourceVideoUrl,
|
|
162
|
-
startTimeMs: segment.startTimeMs,
|
|
163
|
-
durationMs: segment.durationMs,
|
|
164
|
-
quality: segment.quality,
|
|
165
|
-
data: mockData,
|
|
166
|
-
actualStartTimeMs: segment.startTimeMs,
|
|
167
|
-
actualDurationMs: segment.durationMs,
|
|
168
|
-
});
|
|
264
|
+
console.error(`Failed to create ${segment.quality} test clip:`, error);
|
|
169
265
|
}
|
|
170
266
|
}
|
|
171
267
|
|
|
@@ -173,100 +269,133 @@ export async function createJitTestClips(
|
|
|
173
269
|
}
|
|
174
270
|
|
|
175
271
|
/**
|
|
176
|
-
* Create
|
|
272
|
+
* Create test clips specifically for MediaElementSource caching tests
|
|
177
273
|
*/
|
|
178
|
-
export async function
|
|
274
|
+
export async function createMediaElementSourceTestClips(
|
|
179
275
|
sourceVideoUrl: string,
|
|
180
276
|
): Promise<JitTestClip[]> {
|
|
181
277
|
return createJitTestClips({
|
|
182
278
|
sourceVideoUrl,
|
|
183
279
|
segments: [
|
|
184
|
-
//
|
|
185
|
-
{ startTimeMs: 0, durationMs: 2000, quality: "medium" },
|
|
186
|
-
{ startTimeMs:
|
|
187
|
-
{ startTimeMs:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
{ startTimeMs: 2000, durationMs: 2000, quality: "medium" }, // Next 2 seconds
|
|
191
|
-
{ startTimeMs: 4000, durationMs: 2000, quality: "medium" }, // Next 2 seconds
|
|
280
|
+
// Multiple segments that will trigger repeated MediaElementSource creation
|
|
281
|
+
{ startTimeMs: 0, durationMs: 2000, quality: "medium" },
|
|
282
|
+
{ startTimeMs: 2000, durationMs: 2000, quality: "medium" },
|
|
283
|
+
{ startTimeMs: 4000, durationMs: 2000, quality: "medium" },
|
|
284
|
+
{ startTimeMs: 6000, durationMs: 2000, quality: "medium" },
|
|
285
|
+
{ startTimeMs: 8000, durationMs: 2000, quality: "medium" },
|
|
192
286
|
|
|
193
|
-
//
|
|
194
|
-
{ startTimeMs: 0, durationMs:
|
|
287
|
+
// Audio-only segments for testing audio-specific caching
|
|
288
|
+
{ startTimeMs: 0, durationMs: 2000, quality: "medium", type: "audio" },
|
|
289
|
+
{ startTimeMs: 2000, durationMs: 2000, quality: "medium", type: "audio" },
|
|
290
|
+
{ startTimeMs: 4000, durationMs: 2000, quality: "medium", type: "audio" },
|
|
195
291
|
],
|
|
196
292
|
});
|
|
197
293
|
}
|
|
198
294
|
|
|
199
295
|
/**
|
|
200
|
-
*
|
|
296
|
+
* Create realistic JIT metadata that matches transcoding service output
|
|
201
297
|
*/
|
|
202
|
-
export function
|
|
203
|
-
|
|
204
|
-
|
|
298
|
+
export function createRealisticJitMetadata(
|
|
299
|
+
sourceUrl: string,
|
|
300
|
+
durationMs = 10000,
|
|
301
|
+
hasAudio = true,
|
|
302
|
+
hasVideo = true,
|
|
303
|
+
): JitTestMetadata {
|
|
304
|
+
const streams: JitTestMetadata["streams"] = [];
|
|
305
|
+
|
|
306
|
+
if (hasVideo) {
|
|
307
|
+
streams.push({
|
|
308
|
+
index: 0,
|
|
309
|
+
type: "video",
|
|
310
|
+
codecName: "h264",
|
|
311
|
+
duration: durationMs / 1000,
|
|
312
|
+
durationMs,
|
|
313
|
+
width: 1920,
|
|
314
|
+
height: 1080,
|
|
315
|
+
frameRate: { num: 30, den: 1 },
|
|
316
|
+
bitrate: 4000000,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (hasAudio) {
|
|
321
|
+
streams.push({
|
|
322
|
+
index: hasVideo ? 1 : 0,
|
|
323
|
+
type: "audio",
|
|
324
|
+
codecName: "aac",
|
|
325
|
+
duration: durationMs / 1000,
|
|
326
|
+
durationMs,
|
|
327
|
+
channels: 2,
|
|
328
|
+
sampleRate: 48000,
|
|
329
|
+
bitrate: 128000,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
url: sourceUrl,
|
|
335
|
+
durationMs,
|
|
336
|
+
segmentDuration: 2000, // 2s segments for video, will be 15s for audio in AudioTranscodingClient
|
|
337
|
+
streams,
|
|
338
|
+
presets: ["low", "medium", "high"],
|
|
339
|
+
supportedFormats: ["mp4"],
|
|
340
|
+
extractedAt: new Date().toISOString(),
|
|
341
|
+
};
|
|
205
342
|
}
|
|
206
343
|
|
|
207
344
|
/**
|
|
208
|
-
* Mock
|
|
345
|
+
* Mock JIT transcoding service that serves realistic test data
|
|
209
346
|
*/
|
|
210
|
-
export
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
// Mock metadata endpoint
|
|
215
|
-
getMetadata: (url: string) => ({
|
|
216
|
-
url,
|
|
217
|
-
durationMs: 10000, // 10 second test video
|
|
218
|
-
streams: [
|
|
219
|
-
{
|
|
220
|
-
index: 0,
|
|
221
|
-
type: "video" as const,
|
|
222
|
-
codecName: "h264",
|
|
223
|
-
duration: 10,
|
|
224
|
-
durationMs: 10000,
|
|
225
|
-
width: 1920,
|
|
226
|
-
height: 1080,
|
|
227
|
-
frameRate: { num: 30, den: 1 },
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
index: 1,
|
|
231
|
-
type: "audio" as const,
|
|
232
|
-
codecName: "aac",
|
|
233
|
-
duration: 10,
|
|
234
|
-
durationMs: 10000,
|
|
235
|
-
channels: 2,
|
|
236
|
-
sampleRate: 48000,
|
|
237
|
-
},
|
|
238
|
-
],
|
|
239
|
-
presets: ["low", "medium", "high"],
|
|
240
|
-
segmentDuration: 2000,
|
|
241
|
-
supportedFormats: ["mp4"],
|
|
242
|
-
extractedAt: new Date().toISOString(),
|
|
243
|
-
}),
|
|
244
|
-
|
|
245
|
-
// Mock segment endpoint - returns pre-generated clip data
|
|
246
|
-
getSegment: (
|
|
247
|
-
url: string,
|
|
248
|
-
startTimeMs: number,
|
|
249
|
-
quality: "low" | "medium" | "high",
|
|
250
|
-
) => {
|
|
251
|
-
// Align to 2s boundaries like the real service
|
|
252
|
-
const alignedStart = Math.floor(startTimeMs / 2000) * 2000;
|
|
253
|
-
|
|
254
|
-
const clip = clips.find(
|
|
255
|
-
(c) =>
|
|
256
|
-
c.url === url &&
|
|
257
|
-
c.startTimeMs === alignedStart &&
|
|
258
|
-
c.quality === quality,
|
|
259
|
-
);
|
|
347
|
+
export class MockJitTranscodingService {
|
|
348
|
+
private clips: Map<string, JitTestClip> = new Map();
|
|
349
|
+
private metadata: Map<string, JitTestMetadata> = new Map();
|
|
260
350
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
351
|
+
constructor(clips: JitTestClip[]) {
|
|
352
|
+
for (const clip of clips) {
|
|
353
|
+
const key = `${clip.url}:${clip.startTimeMs}:${clip.quality}:${clip.type}`;
|
|
354
|
+
this.clips.set(key, clip);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
266
357
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
358
|
+
setMetadata(url: string, metadata: JitTestMetadata) {
|
|
359
|
+
this.metadata.set(url, metadata);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
getMetadata(url: string): JitTestMetadata {
|
|
363
|
+
const metadata = this.metadata.get(url);
|
|
364
|
+
if (!metadata) {
|
|
365
|
+
// Create default metadata
|
|
366
|
+
return createRealisticJitMetadata(url);
|
|
367
|
+
}
|
|
368
|
+
return metadata;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
getSegment(
|
|
372
|
+
url: string,
|
|
373
|
+
startTimeMs: number,
|
|
374
|
+
quality: "low" | "medium" | "high",
|
|
375
|
+
type: "video" | "audio" = "video",
|
|
376
|
+
): Uint8Array {
|
|
377
|
+
// Align to segment boundaries like real service
|
|
378
|
+
const segmentDuration = type === "audio" ? 15000 : 2000;
|
|
379
|
+
const alignedStart =
|
|
380
|
+
Math.floor(startTimeMs / segmentDuration) * segmentDuration;
|
|
381
|
+
|
|
382
|
+
const key = `${url}:${alignedStart}:${quality}:${type}`;
|
|
383
|
+
const clip = this.clips.get(key);
|
|
384
|
+
|
|
385
|
+
if (!clip) {
|
|
386
|
+
throw new Error(`No test clip found for ${key}`);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return clip.data;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Create init segment for MediaSource streaming
|
|
393
|
+
getInitSegment(type: "video" | "audio" = "video"): Uint8Array {
|
|
394
|
+
if (type === "audio") {
|
|
395
|
+
return createRealisticAudioSegment(0, "medium").slice(0, 200);
|
|
396
|
+
}
|
|
397
|
+
return createRealisticVideoSegment(0, "medium").slice(0, 300);
|
|
398
|
+
}
|
|
270
399
|
}
|
|
271
400
|
|
|
272
401
|
/**
|
|
@@ -275,18 +404,21 @@ export function createMockJitHandler(clips: JitTestClip[]) {
|
|
|
275
404
|
const testClipCache = new Map<string, JitTestClip[]>();
|
|
276
405
|
|
|
277
406
|
/**
|
|
278
|
-
* Get or create cached test clips for
|
|
407
|
+
* Get or create cached test clips for MediaElementSource testing
|
|
279
408
|
*/
|
|
280
|
-
export async function
|
|
409
|
+
export async function getCachedMediaElementSourceTestClips(
|
|
281
410
|
sourceVideoUrl: string,
|
|
282
411
|
): Promise<JitTestClip[]> {
|
|
283
|
-
|
|
412
|
+
const cacheKey = `media-element-source:${sourceVideoUrl}`;
|
|
413
|
+
let clips = testClipCache.get(cacheKey);
|
|
284
414
|
|
|
285
415
|
if (!clips) {
|
|
286
|
-
console.log(
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
416
|
+
console.log(
|
|
417
|
+
`Creating MediaElementSource test clips for ${sourceVideoUrl}...`,
|
|
418
|
+
);
|
|
419
|
+
clips = await createMediaElementSourceTestClips(sourceVideoUrl);
|
|
420
|
+
testClipCache.set(cacheKey, clips);
|
|
421
|
+
console.log(`Created ${clips.length} MediaElementSource test clips`);
|
|
290
422
|
}
|
|
291
423
|
|
|
292
424
|
return clips;
|