@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.
Files changed (211) hide show
  1. package/dist/EF_FRAMEGEN.js +1 -1
  2. package/dist/elements/EFAudio.d.ts +21 -2
  3. package/dist/elements/EFAudio.js +41 -11
  4. package/dist/elements/EFImage.d.ts +1 -0
  5. package/dist/elements/EFImage.js +11 -3
  6. package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
  7. package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
  8. package/dist/elements/EFMedia/AssetMediaEngine.browsertest.d.ts +0 -0
  9. package/dist/elements/EFMedia/AssetMediaEngine.d.ts +45 -0
  10. package/dist/elements/EFMedia/AssetMediaEngine.js +135 -0
  11. package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
  12. package/dist/elements/EFMedia/BaseMediaEngine.js +115 -0
  13. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
  14. package/dist/elements/EFMedia/BufferedSeekingInput.js +179 -0
  15. package/dist/elements/EFMedia/JitMediaEngine.browsertest.d.ts +0 -0
  16. package/dist/elements/EFMedia/JitMediaEngine.d.ts +31 -0
  17. package/dist/elements/EFMedia/JitMediaEngine.js +81 -0
  18. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.d.ts +9 -0
  19. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +16 -0
  20. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +48 -0
  21. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +3 -0
  22. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +141 -0
  23. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.d.ts +9 -0
  24. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +4 -0
  25. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +16 -0
  26. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.d.ts +9 -0
  27. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.d.ts +3 -0
  28. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +30 -0
  29. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.d.ts +0 -0
  30. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
  31. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +32 -0
  32. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
  33. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +28 -0
  34. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
  35. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +17 -0
  36. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
  37. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +107 -0
  38. package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
  39. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
  40. package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
  41. package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
  42. package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
  43. package/dist/elements/EFMedia/shared/PrecisionUtils.d.ts +28 -0
  44. package/dist/elements/EFMedia/shared/PrecisionUtils.js +29 -0
  45. package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
  46. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
  47. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
  48. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
  49. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
  50. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
  51. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
  52. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
  53. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
  54. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
  55. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
  56. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
  57. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
  58. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +34 -0
  59. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
  60. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
  61. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +28 -0
  62. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
  63. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
  64. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +17 -0
  65. package/dist/elements/EFMedia.browsertest.d.ts +1 -0
  66. package/dist/elements/EFMedia.d.ts +63 -111
  67. package/dist/elements/EFMedia.js +117 -1113
  68. package/dist/elements/EFTemporal.d.ts +1 -1
  69. package/dist/elements/EFTemporal.js +1 -1
  70. package/dist/elements/EFTimegroup.d.ts +11 -0
  71. package/dist/elements/EFTimegroup.js +83 -13
  72. package/dist/elements/EFVideo.d.ts +54 -32
  73. package/dist/elements/EFVideo.js +100 -207
  74. package/dist/elements/EFWaveform.js +2 -2
  75. package/dist/elements/SampleBuffer.d.ts +14 -0
  76. package/dist/elements/SampleBuffer.js +52 -0
  77. package/dist/getRenderInfo.js +2 -1
  78. package/dist/gui/ContextMixin.js +3 -2
  79. package/dist/gui/EFFilmstrip.d.ts +3 -3
  80. package/dist/gui/EFFilmstrip.js +1 -1
  81. package/dist/gui/EFFitScale.d.ts +2 -2
  82. package/dist/gui/TWMixin.js +1 -1
  83. package/dist/style.css +1 -1
  84. package/dist/transcoding/cache/CacheManager.d.ts +73 -0
  85. package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
  86. package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
  87. package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
  88. package/dist/transcoding/types/index.d.ts +242 -0
  89. package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
  90. package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
  91. package/dist/transcoding/utils/UrlGenerator.js +45 -0
  92. package/dist/transcoding/utils/constants.d.ts +27 -0
  93. package/dist/utils/LRUCache.d.ts +34 -0
  94. package/dist/utils/LRUCache.js +115 -0
  95. package/package.json +3 -3
  96. package/src/elements/EFAudio.browsertest.ts +189 -49
  97. package/src/elements/EFAudio.ts +59 -13
  98. package/src/elements/EFImage.browsertest.ts +42 -0
  99. package/src/elements/EFImage.ts +23 -3
  100. package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
  101. package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
  102. package/src/elements/EFMedia/AssetMediaEngine.browsertest.ts +100 -0
  103. package/src/elements/EFMedia/AssetMediaEngine.ts +255 -0
  104. package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
  105. package/src/elements/EFMedia/BaseMediaEngine.ts +219 -0
  106. package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +481 -0
  107. package/src/elements/EFMedia/BufferedSeekingInput.ts +324 -0
  108. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
  109. package/src/elements/EFMedia/JitMediaEngine.ts +166 -0
  110. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
  111. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
  112. package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +250 -0
  113. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
  114. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
  115. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
  116. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +43 -0
  117. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +199 -0
  118. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +64 -0
  119. package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +45 -0
  120. package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +24 -0
  121. package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +183 -0
  122. package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
  123. package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
  124. package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
  125. package/src/elements/EFMedia/shared/PrecisionUtils.ts +46 -0
  126. package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
  127. package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
  128. package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
  129. package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
  130. package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
  131. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
  132. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
  133. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
  134. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
  135. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
  136. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
  137. package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +68 -0
  138. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
  139. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +43 -0
  140. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
  141. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +24 -0
  142. package/src/elements/EFMedia.browsertest.ts +706 -273
  143. package/src/elements/EFMedia.ts +136 -1769
  144. package/src/elements/EFTemporal.ts +3 -4
  145. package/src/elements/EFTimegroup.browsertest.ts +6 -3
  146. package/src/elements/EFTimegroup.ts +147 -21
  147. package/src/elements/EFVideo.browsertest.ts +980 -169
  148. package/src/elements/EFVideo.ts +113 -458
  149. package/src/elements/EFWaveform.ts +1 -1
  150. package/src/elements/MediaController.ts +2 -12
  151. package/src/elements/SampleBuffer.ts +95 -0
  152. package/src/gui/ContextMixin.ts +3 -6
  153. package/src/transcoding/cache/CacheManager.ts +208 -0
  154. package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
  155. package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
  156. package/src/transcoding/types/index.ts +269 -0
  157. package/src/transcoding/utils/MediaUtils.ts +63 -0
  158. package/src/transcoding/utils/UrlGenerator.ts +68 -0
  159. package/src/transcoding/utils/constants.ts +36 -0
  160. package/src/utils/LRUCache.ts +153 -0
  161. package/test/EFVideo.framegen.browsertest.ts +39 -30
  162. 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
  163. 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
  164. 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
  165. 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
  166. 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
  167. 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
  168. 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
  169. 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
  170. 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
  171. 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
  172. 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
  173. 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
  174. 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
  175. 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
  176. 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
  177. 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
  178. 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
  179. 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
  180. 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
  181. 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
  182. 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
  183. 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
  184. 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
  185. 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
  186. 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
  187. 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
  188. 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
  189. 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
  190. 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
  191. 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
  192. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
  193. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
  194. package/test/createJitTestClips.ts +320 -188
  195. package/test/recordReplayProxyPlugin.js +352 -0
  196. package/test/useAssetMSW.ts +1 -1
  197. package/test/useMSW.ts +35 -22
  198. package/types.json +1 -1
  199. package/dist/JitTranscodingClient.d.ts +0 -167
  200. package/dist/JitTranscodingClient.js +0 -373
  201. package/dist/ScrubTrackManager.d.ts +0 -96
  202. package/dist/ScrubTrackManager.js +0 -216
  203. package/dist/elements/printTaskStatus.js +0 -11
  204. package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
  205. package/test/EFVideo.frame-tasks.browsertest.ts +0 -524
  206. /package/dist/{DecoderResetFrequency.test.d.ts → elements/EFMedia/AssetIdMediaEngine.test.d.ts} +0 -0
  207. /package/dist/{DecoderResetRecovery.test.d.ts → elements/EFMedia/BaseMediaEngine.test.d.ts} +0 -0
  208. /package/dist/{JitTranscodingClient.browsertest.d.ts → elements/EFMedia/BufferedSeekingInput.browsertest.d.ts} +0 -0
  209. /package/dist/{JitTranscodingClient.test.d.ts → elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts} +0 -0
  210. /package/dist/{ScrubTrackIntegration.test.d.ts → elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts} +0 -0
  211. /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
- * Reads segments created by scripts/generate-jit-test-clips.ts
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
- // Map segments to their pre-generated filenames
26
- const SEGMENT_FILENAMES: Record<string, string> = {
27
- "0:2000:low": "segment-0ms-2s-low.mp4",
28
- "0:2000:medium": "segment-0ms-2s-medium.mp4",
29
- "0:2000:high": "segment-0ms-2s-high.mp4",
30
- "2000:2000:medium": "segment-2000ms-2s-medium.mp4",
31
- "4000:2000:medium": "segment-4000ms-2s-medium.mp4",
32
- "0:4000:medium": "segment-0ms-4s-medium.mp4",
33
- "6000:1000:low": "segment-6000ms-1s-low.mp4",
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 a minimal MP4 file for testing when pre-generated files aren't available
38
- * This creates a very basic MP4 structure that can be used for testing
50
+ * Create realistic MP4 video segment with proper structure
51
+ * Uses knowledge from JIT transcoding to create valid segments
39
52
  */
40
- function createMockMp4Segment(durationMs = 2000): Uint8Array {
41
- // Minimal MP4 structure: ftyp box + mdat box with dummy data
42
- const ftypBox = new Uint8Array([
43
- 0x00,
44
- 0x00,
45
- 0x00,
46
- 0x20, // box size (32 bytes)
47
- 0x66,
48
- 0x74,
49
- 0x79,
50
- 0x70, // 'ftyp'
51
- 0x69,
52
- 0x73,
53
- 0x6f,
54
- 0x6d, // major brand 'isom'
55
- 0x00,
56
- 0x00,
57
- 0x02,
58
- 0x00, // minor version
59
- 0x69,
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
- // Combine boxes
93
- const result = new Uint8Array(ftypBox.length + mdatBox.length);
94
- result.set(ftypBox, 0);
95
- result.set(mdatBox, ftypBox.length);
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
- * Load a pre-generated segment from disk
88
+ * Create realistic MP4 audio segment for audio-only testing
102
89
  */
103
- async function loadPreGeneratedSegment(
104
- startTimeMs: number,
90
+ function createRealisticAudioSegment(
105
91
  durationMs: number,
106
92
  quality: "low" | "medium" | "high",
107
- ): Promise<Uint8Array> {
108
- const segmentKey = `${startTimeMs}:${durationMs}:${quality}`;
109
- const filename = SEGMENT_FILENAMES[segmentKey];
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
- if (!filename) {
112
- console.warn(`No pre-generated segment for ${segmentKey}, using mock data`);
113
- return createMockMp4Segment(durationMs);
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
- try {
117
- // In browser environment, we'll need to fetch from a served location
118
- // For now, use mock data as fallback
119
- console.warn(
120
- `Cannot load ${filename} in browser environment, using mock data`,
121
- );
122
- return createMockMp4Segment(durationMs);
123
- } catch (error) {
124
- console.warn(`Failed to load ${filename}, using mock data:`, error);
125
- return createMockMp4Segment(durationMs);
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 pre-generated segments when available
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 data = await loadPreGeneratedSegment(
140
- segment.startTimeMs,
141
- segment.durationMs,
142
- segment.quality,
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(`✅ Loaded ${segment.quality} clip: ${data.length} bytes`);
260
+ console.log(
261
+ `✅ Created realistic ${segmentType} ${segment.quality} clip: ${data.length} bytes`,
262
+ );
156
263
  } catch (error) {
157
- console.error(`Failed to load ${segment.quality} test clip:`, error);
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 a standard set of test clips for browser testing
272
+ * Create test clips specifically for MediaElementSource caching tests
177
273
  */
178
- export async function createStandardJitTestClips(
274
+ export async function createMediaElementSourceTestClips(
179
275
  sourceVideoUrl: string,
180
276
  ): Promise<JitTestClip[]> {
181
277
  return createJitTestClips({
182
278
  sourceVideoUrl,
183
279
  segments: [
184
- // Short clips for quick testing - these match our pre-generated segments
185
- { startTimeMs: 0, durationMs: 2000, quality: "medium" }, // First 2 seconds
186
- { startTimeMs: 0, durationMs: 2000, quality: "low" }, // Same segment, different quality
187
- { startTimeMs: 0, durationMs: 2000, quality: "high" }, // Same segment, high quality
188
-
189
- // Sequential segments for testing playback
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
- // Edge cases
194
- { startTimeMs: 0, durationMs: 4000, quality: "medium" }, // Longer segment
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
- * Convert JitTestClip to blob URL for use in browser tests
296
+ * Create realistic JIT metadata that matches transcoding service output
201
297
  */
202
- export function createBlobUrlFromJitClip(clip: JitTestClip): string {
203
- const blob = new Blob([clip.data], { type: "video/mp4" });
204
- return URL.createObjectURL(blob);
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 MSW handler that serves pre-generated JIT test clips
345
+ * Mock JIT transcoding service that serves realistic test data
209
346
  */
210
- export function createMockJitHandler(clips: JitTestClip[]) {
211
- return {
212
- clips,
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
- if (!clip) {
262
- throw new Error(
263
- `No test clip found for ${url} at ${alignedStart}ms (${quality})`,
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
- return clip.data;
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 a source URL
407
+ * Get or create cached test clips for MediaElementSource testing
279
408
  */
280
- export async function getCachedJitTestClips(
409
+ export async function getCachedMediaElementSourceTestClips(
281
410
  sourceVideoUrl: string,
282
411
  ): Promise<JitTestClip[]> {
283
- let clips = testClipCache.get(sourceVideoUrl);
412
+ const cacheKey = `media-element-source:${sourceVideoUrl}`;
413
+ let clips = testClipCache.get(cacheKey);
284
414
 
285
415
  if (!clips) {
286
- console.log(`Loading JIT test clips for ${sourceVideoUrl}...`);
287
- clips = await createStandardJitTestClips(sourceVideoUrl);
288
- testClipCache.set(sourceVideoUrl, clips);
289
- console.log(`Loaded ${clips.length} test clips`);
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;