avbridge 2.2.1 → 2.5.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 (165) hide show
  1. package/CHANGELOG.md +153 -1
  2. package/NOTICE.md +2 -2
  3. package/README.md +2 -3
  4. package/THIRD_PARTY_LICENSES.md +2 -2
  5. package/dist/avi-2JPBSHGA.js +183 -0
  6. package/dist/avi-2JPBSHGA.js.map +1 -0
  7. package/dist/avi-F6WZJK5T.cjs +185 -0
  8. package/dist/avi-F6WZJK5T.cjs.map +1 -0
  9. package/dist/{avi-GCGM7OJI.js → avi-NJXAXUXK.js} +9 -3
  10. package/dist/avi-NJXAXUXK.js.map +1 -0
  11. package/dist/{avi-6SJLWIWW.cjs → avi-W6L3BTWU.cjs} +10 -4
  12. package/dist/avi-W6L3BTWU.cjs.map +1 -0
  13. package/dist/chunk-2IJ66NTD.cjs +212 -0
  14. package/dist/chunk-2IJ66NTD.cjs.map +1 -0
  15. package/dist/{chunk-ILKDNBSE.js → chunk-2XW2O3YI.cjs} +55 -10
  16. package/dist/chunk-2XW2O3YI.cjs.map +1 -0
  17. package/dist/chunk-5KVLE6YI.js +167 -0
  18. package/dist/chunk-5KVLE6YI.js.map +1 -0
  19. package/dist/chunk-5YAWWKA3.js +18 -0
  20. package/dist/chunk-5YAWWKA3.js.map +1 -0
  21. package/dist/chunk-CPJLFFCC.js +189 -0
  22. package/dist/chunk-CPJLFFCC.js.map +1 -0
  23. package/dist/chunk-CPZ7PXAM.cjs +240 -0
  24. package/dist/chunk-CPZ7PXAM.cjs.map +1 -0
  25. package/dist/{chunk-WD2ZNQA7.js → chunk-DCSOQH2N.js} +7 -4
  26. package/dist/chunk-DCSOQH2N.js.map +1 -0
  27. package/dist/{chunk-HZLQNKFN.cjs → chunk-E76AMWI4.js} +40 -15
  28. package/dist/chunk-E76AMWI4.js.map +1 -0
  29. package/dist/chunk-F3LQJKXK.cjs +20 -0
  30. package/dist/chunk-F3LQJKXK.cjs.map +1 -0
  31. package/dist/chunk-IAYKFGFG.js +200 -0
  32. package/dist/chunk-IAYKFGFG.js.map +1 -0
  33. package/dist/{chunk-DMWARSEF.js → chunk-KY2GPCT7.js} +788 -697
  34. package/dist/chunk-KY2GPCT7.js.map +1 -0
  35. package/dist/chunk-LUFA47FP.js +19 -0
  36. package/dist/chunk-LUFA47FP.js.map +1 -0
  37. package/dist/chunk-NNVOHKXJ.cjs +204 -0
  38. package/dist/chunk-NNVOHKXJ.cjs.map +1 -0
  39. package/dist/chunk-Q2VUO52Z.cjs +374 -0
  40. package/dist/chunk-Q2VUO52Z.cjs.map +1 -0
  41. package/dist/chunk-QDJLQR53.cjs +22 -0
  42. package/dist/chunk-QDJLQR53.cjs.map +1 -0
  43. package/dist/chunk-S4WAZC2T.cjs +173 -0
  44. package/dist/chunk-S4WAZC2T.cjs.map +1 -0
  45. package/dist/chunk-SMH6IOP2.js +368 -0
  46. package/dist/chunk-SMH6IOP2.js.map +1 -0
  47. package/dist/chunk-SR3MPV4D.js +237 -0
  48. package/dist/chunk-SR3MPV4D.js.map +1 -0
  49. package/dist/{chunk-UF2N5L63.cjs → chunk-TBW26OPP.cjs} +800 -710
  50. package/dist/chunk-TBW26OPP.cjs.map +1 -0
  51. package/dist/chunk-X2K3GIWE.js +235 -0
  52. package/dist/chunk-X2K3GIWE.js.map +1 -0
  53. package/dist/{chunk-L4NPOJ36.cjs → chunk-Z33SBWL5.cjs} +7 -4
  54. package/dist/chunk-Z33SBWL5.cjs.map +1 -0
  55. package/dist/chunk-ZCUXHW55.cjs +242 -0
  56. package/dist/chunk-ZCUXHW55.cjs.map +1 -0
  57. package/dist/element-browser.js +1282 -503
  58. package/dist/element-browser.js.map +1 -1
  59. package/dist/element.cjs +59 -5
  60. package/dist/element.cjs.map +1 -1
  61. package/dist/element.d.cts +39 -1
  62. package/dist/element.d.ts +39 -1
  63. package/dist/element.js +58 -4
  64. package/dist/element.js.map +1 -1
  65. package/dist/index.cjs +605 -327
  66. package/dist/index.cjs.map +1 -1
  67. package/dist/index.d.cts +48 -4
  68. package/dist/index.d.ts +48 -4
  69. package/dist/index.js +528 -319
  70. package/dist/index.js.map +1 -1
  71. package/dist/libav-demux-H2GS46GH.cjs +27 -0
  72. package/dist/{libav-http-reader-NQJVY273.js.map → libav-demux-H2GS46GH.cjs.map} +1 -1
  73. package/dist/libav-demux-OWZ4T2YW.js +6 -0
  74. package/dist/{libav-http-reader-FPYDBMYK.cjs.map → libav-demux-OWZ4T2YW.js.map} +1 -1
  75. package/dist/libav-http-reader-AZLE7YFS.cjs +16 -0
  76. package/dist/libav-http-reader-AZLE7YFS.cjs.map +1 -0
  77. package/dist/libav-http-reader-WXG3Z7AI.js +3 -0
  78. package/dist/libav-http-reader-WXG3Z7AI.js.map +1 -0
  79. package/dist/{libav-import-GST2AMPL.cjs → libav-import-2ZVKV2E7.cjs} +2 -2
  80. package/dist/{libav-import-GST2AMPL.cjs.map → libav-import-2ZVKV2E7.cjs.map} +1 -1
  81. package/dist/{libav-import-2JURFHEW.js → libav-import-6MGLCXVQ.js} +2 -2
  82. package/dist/{libav-import-2JURFHEW.js.map → libav-import-6MGLCXVQ.js.map} +1 -1
  83. package/dist/{player-U2NPmFvA.d.cts → player-B6WB74RD.d.cts} +62 -3
  84. package/dist/{player-U2NPmFvA.d.ts → player-B6WB74RD.d.ts} +62 -3
  85. package/dist/player.cjs +5631 -0
  86. package/dist/player.cjs.map +1 -0
  87. package/dist/player.d.cts +699 -0
  88. package/dist/player.d.ts +699 -0
  89. package/dist/player.js +5629 -0
  90. package/dist/player.js.map +1 -0
  91. package/dist/remux-OBSMIENG.cjs +35 -0
  92. package/dist/remux-OBSMIENG.cjs.map +1 -0
  93. package/dist/remux-WBYIZBBX.js +10 -0
  94. package/dist/remux-WBYIZBBX.js.map +1 -0
  95. package/dist/source-4TZ6KMNV.js +4 -0
  96. package/dist/{source-FFZ7TW2B.js.map → source-4TZ6KMNV.js.map} +1 -1
  97. package/dist/source-7YLO6E7X.cjs +29 -0
  98. package/dist/{source-CN43EI7Z.cjs.map → source-7YLO6E7X.cjs.map} +1 -1
  99. package/dist/source-MTX5ELUZ.js +4 -0
  100. package/dist/source-MTX5ELUZ.js.map +1 -0
  101. package/dist/source-VFLXLOCN.cjs +29 -0
  102. package/dist/source-VFLXLOCN.cjs.map +1 -0
  103. package/dist/subtitles-4T74JRGT.js +4 -0
  104. package/dist/subtitles-4T74JRGT.js.map +1 -0
  105. package/dist/subtitles-QUH4LPI4.cjs +29 -0
  106. package/dist/subtitles-QUH4LPI4.cjs.map +1 -0
  107. package/dist/variant-routing-434STYAB.js +3 -0
  108. package/dist/{variant-routing-JOBWXYKD.js.map → variant-routing-434STYAB.js.map} +1 -1
  109. package/dist/variant-routing-HONNAA6R.cjs +12 -0
  110. package/dist/{variant-routing-GOHB2RZN.cjs.map → variant-routing-HONNAA6R.cjs.map} +1 -1
  111. package/package.json +9 -1
  112. package/src/classify/rules.ts +27 -5
  113. package/src/convert/remux.ts +9 -35
  114. package/src/convert/transcode-libav.ts +691 -0
  115. package/src/convert/transcode.ts +53 -12
  116. package/src/element/avbridge-player.ts +861 -0
  117. package/src/element/avbridge-video.ts +54 -0
  118. package/src/element/player-icons.ts +25 -0
  119. package/src/element/player-styles.ts +472 -0
  120. package/src/errors.ts +53 -0
  121. package/src/index.ts +23 -0
  122. package/src/player-element.ts +18 -0
  123. package/src/player.ts +118 -27
  124. package/src/plugins/builtin.ts +2 -2
  125. package/src/probe/avi.ts +4 -0
  126. package/src/probe/index.ts +40 -10
  127. package/src/strategies/fallback/audio-output.ts +31 -0
  128. package/src/strategies/fallback/decoder.ts +179 -175
  129. package/src/strategies/fallback/index.ts +48 -6
  130. package/src/strategies/fallback/libav-import.ts +9 -1
  131. package/src/strategies/fallback/variant-routing.ts +7 -13
  132. package/src/strategies/fallback/video-renderer.ts +231 -32
  133. package/src/strategies/hybrid/decoder.ts +219 -200
  134. package/src/strategies/hybrid/index.ts +48 -7
  135. package/src/strategies/native.ts +6 -3
  136. package/src/strategies/remux/index.ts +14 -2
  137. package/src/strategies/remux/mse.ts +12 -2
  138. package/src/strategies/remux/pipeline.ts +72 -12
  139. package/src/subtitles/index.ts +7 -3
  140. package/src/subtitles/render.ts +8 -0
  141. package/src/types.ts +53 -1
  142. package/src/util/libav-demux.ts +405 -0
  143. package/src/util/libav-http-reader.ts +5 -1
  144. package/src/util/source.ts +28 -8
  145. package/src/util/transport.ts +26 -0
  146. package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.mjs +1 -1
  147. package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.wasm +0 -0
  148. package/dist/avi-6SJLWIWW.cjs.map +0 -1
  149. package/dist/avi-GCGM7OJI.js.map +0 -1
  150. package/dist/chunk-DMWARSEF.js.map +0 -1
  151. package/dist/chunk-HZLQNKFN.cjs.map +0 -1
  152. package/dist/chunk-ILKDNBSE.js.map +0 -1
  153. package/dist/chunk-J5MCMN3S.js +0 -27
  154. package/dist/chunk-J5MCMN3S.js.map +0 -1
  155. package/dist/chunk-L4NPOJ36.cjs.map +0 -1
  156. package/dist/chunk-NZU7W256.cjs +0 -29
  157. package/dist/chunk-NZU7W256.cjs.map +0 -1
  158. package/dist/chunk-UF2N5L63.cjs.map +0 -1
  159. package/dist/chunk-WD2ZNQA7.js.map +0 -1
  160. package/dist/libav-http-reader-FPYDBMYK.cjs +0 -16
  161. package/dist/libav-http-reader-NQJVY273.js +0 -3
  162. package/dist/source-CN43EI7Z.cjs +0 -28
  163. package/dist/source-FFZ7TW2B.js +0 -3
  164. package/dist/variant-routing-GOHB2RZN.cjs +0 -12
  165. package/dist/variant-routing-JOBWXYKD.js +0 -3
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ var chunkQ2VUO52Z_cjs = require('./chunk-Q2VUO52Z.cjs');
4
+ require('./chunk-ZCUXHW55.cjs');
5
+ require('./chunk-2IJ66NTD.cjs');
6
+ require('./chunk-QDJLQR53.cjs');
7
+ require('./chunk-CPZ7PXAM.cjs');
8
+ require('./chunk-Z33SBWL5.cjs');
9
+ require('./chunk-G4APZMCP.cjs');
10
+ require('./chunk-F3LQJKXK.cjs');
11
+
12
+
13
+
14
+ Object.defineProperty(exports, "createOutputFormat", {
15
+ enumerable: true,
16
+ get: function () { return chunkQ2VUO52Z_cjs.createOutputFormat; }
17
+ });
18
+ Object.defineProperty(exports, "generateFilename", {
19
+ enumerable: true,
20
+ get: function () { return chunkQ2VUO52Z_cjs.generateFilename; }
21
+ });
22
+ Object.defineProperty(exports, "mimeForFormat", {
23
+ enumerable: true,
24
+ get: function () { return chunkQ2VUO52Z_cjs.mimeForFormat; }
25
+ });
26
+ Object.defineProperty(exports, "remux", {
27
+ enumerable: true,
28
+ get: function () { return chunkQ2VUO52Z_cjs.remux; }
29
+ });
30
+ Object.defineProperty(exports, "validateRemuxEligibility", {
31
+ enumerable: true,
32
+ get: function () { return chunkQ2VUO52Z_cjs.validateRemuxEligibility; }
33
+ });
34
+ //# sourceMappingURL=remux-OBSMIENG.cjs.map
35
+ //# sourceMappingURL=remux-OBSMIENG.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"remux-OBSMIENG.cjs"}
@@ -0,0 +1,10 @@
1
+ export { createOutputFormat, generateFilename, mimeForFormat, remux, validateRemuxEligibility } from './chunk-SMH6IOP2.js';
2
+ import './chunk-SR3MPV4D.js';
3
+ import './chunk-CPJLFFCC.js';
4
+ import './chunk-LUFA47FP.js';
5
+ import './chunk-X2K3GIWE.js';
6
+ import './chunk-DCSOQH2N.js';
7
+ import './chunk-5DMTJVIU.js';
8
+ import './chunk-5YAWWKA3.js';
9
+ //# sourceMappingURL=remux-WBYIZBBX.js.map
10
+ //# sourceMappingURL=remux-WBYIZBBX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"remux-WBYIZBBX.js"}
@@ -0,0 +1,4 @@
1
+ export { isInMemorySource, normalizeSource, sniffContainer, sniffContainerFromBytes, sniffNormalizedSource } from './chunk-CPJLFFCC.js';
2
+ import './chunk-LUFA47FP.js';
3
+ //# sourceMappingURL=source-4TZ6KMNV.js.map
4
+ //# sourceMappingURL=source-4TZ6KMNV.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"source-FFZ7TW2B.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"source-4TZ6KMNV.js"}
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ var chunk2XW2O3YI_cjs = require('./chunk-2XW2O3YI.cjs');
4
+ require('./chunk-QDJLQR53.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "isInMemorySource", {
9
+ enumerable: true,
10
+ get: function () { return chunk2XW2O3YI_cjs.isInMemorySource; }
11
+ });
12
+ Object.defineProperty(exports, "normalizeSource", {
13
+ enumerable: true,
14
+ get: function () { return chunk2XW2O3YI_cjs.normalizeSource; }
15
+ });
16
+ Object.defineProperty(exports, "sniffContainer", {
17
+ enumerable: true,
18
+ get: function () { return chunk2XW2O3YI_cjs.sniffContainer; }
19
+ });
20
+ Object.defineProperty(exports, "sniffContainerFromBytes", {
21
+ enumerable: true,
22
+ get: function () { return chunk2XW2O3YI_cjs.sniffContainerFromBytes; }
23
+ });
24
+ Object.defineProperty(exports, "sniffNormalizedSource", {
25
+ enumerable: true,
26
+ get: function () { return chunk2XW2O3YI_cjs.sniffNormalizedSource; }
27
+ });
28
+ //# sourceMappingURL=source-7YLO6E7X.cjs.map
29
+ //# sourceMappingURL=source-7YLO6E7X.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"source-CN43EI7Z.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"source-7YLO6E7X.cjs"}
@@ -0,0 +1,4 @@
1
+ export { isInMemorySource, normalizeSource, sniffContainer, sniffContainerFromBytes, sniffNormalizedSource } from './chunk-E76AMWI4.js';
2
+ import './chunk-LUFA47FP.js';
3
+ //# sourceMappingURL=source-MTX5ELUZ.js.map
4
+ //# sourceMappingURL=source-MTX5ELUZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"source-MTX5ELUZ.js"}
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ var chunk2IJ66NTD_cjs = require('./chunk-2IJ66NTD.cjs');
4
+ require('./chunk-QDJLQR53.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "isInMemorySource", {
9
+ enumerable: true,
10
+ get: function () { return chunk2IJ66NTD_cjs.isInMemorySource; }
11
+ });
12
+ Object.defineProperty(exports, "normalizeSource", {
13
+ enumerable: true,
14
+ get: function () { return chunk2IJ66NTD_cjs.normalizeSource; }
15
+ });
16
+ Object.defineProperty(exports, "sniffContainer", {
17
+ enumerable: true,
18
+ get: function () { return chunk2IJ66NTD_cjs.sniffContainer; }
19
+ });
20
+ Object.defineProperty(exports, "sniffContainerFromBytes", {
21
+ enumerable: true,
22
+ get: function () { return chunk2IJ66NTD_cjs.sniffContainerFromBytes; }
23
+ });
24
+ Object.defineProperty(exports, "sniffNormalizedSource", {
25
+ enumerable: true,
26
+ get: function () { return chunk2IJ66NTD_cjs.sniffNormalizedSource; }
27
+ });
28
+ //# sourceMappingURL=source-VFLXLOCN.cjs.map
29
+ //# sourceMappingURL=source-VFLXLOCN.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"source-VFLXLOCN.cjs"}
@@ -0,0 +1,4 @@
1
+ export { SubtitleOverlay, SubtitleResourceBag, attachSubtitleTracks, discoverSidecars, srtToVtt } from './chunk-5KVLE6YI.js';
2
+ import './chunk-LUFA47FP.js';
3
+ //# sourceMappingURL=subtitles-4T74JRGT.js.map
4
+ //# sourceMappingURL=subtitles-4T74JRGT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"subtitles-4T74JRGT.js"}
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ var chunkS4WAZC2T_cjs = require('./chunk-S4WAZC2T.cjs');
4
+ require('./chunk-QDJLQR53.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "SubtitleOverlay", {
9
+ enumerable: true,
10
+ get: function () { return chunkS4WAZC2T_cjs.SubtitleOverlay; }
11
+ });
12
+ Object.defineProperty(exports, "SubtitleResourceBag", {
13
+ enumerable: true,
14
+ get: function () { return chunkS4WAZC2T_cjs.SubtitleResourceBag; }
15
+ });
16
+ Object.defineProperty(exports, "attachSubtitleTracks", {
17
+ enumerable: true,
18
+ get: function () { return chunkS4WAZC2T_cjs.attachSubtitleTracks; }
19
+ });
20
+ Object.defineProperty(exports, "discoverSidecars", {
21
+ enumerable: true,
22
+ get: function () { return chunkS4WAZC2T_cjs.discoverSidecars; }
23
+ });
24
+ Object.defineProperty(exports, "srtToVtt", {
25
+ enumerable: true,
26
+ get: function () { return chunkS4WAZC2T_cjs.srtToVtt; }
27
+ });
28
+ //# sourceMappingURL=subtitles-QUH4LPI4.cjs.map
29
+ //# sourceMappingURL=subtitles-QUH4LPI4.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"subtitles-QUH4LPI4.cjs"}
@@ -0,0 +1,3 @@
1
+ export { pickLibavVariant } from './chunk-5YAWWKA3.js';
2
+ //# sourceMappingURL=variant-routing-434STYAB.js.map
3
+ //# sourceMappingURL=variant-routing-434STYAB.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"variant-routing-JOBWXYKD.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"variant-routing-434STYAB.js"}
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ var chunkF3LQJKXK_cjs = require('./chunk-F3LQJKXK.cjs');
4
+
5
+
6
+
7
+ Object.defineProperty(exports, "pickLibavVariant", {
8
+ enumerable: true,
9
+ get: function () { return chunkF3LQJKXK_cjs.pickLibavVariant; }
10
+ });
11
+ //# sourceMappingURL=variant-routing-HONNAA6R.cjs.map
12
+ //# sourceMappingURL=variant-routing-HONNAA6R.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"variant-routing-GOHB2RZN.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"variant-routing-HONNAA6R.cjs"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "avbridge",
3
- "version": "2.2.1",
3
+ "version": "2.5.0",
4
4
  "description": "Play and convert arbitrary video files in the browser. Native, remux, hybrid, fallback, and transcode — one API.",
5
5
  "license": "MIT",
6
6
  "author": "Keishi Hattori",
@@ -35,6 +35,8 @@
35
35
  "sideEffects": [
36
36
  "./dist/element.js",
37
37
  "./dist/element.cjs",
38
+ "./dist/player.js",
39
+ "./dist/player.cjs",
38
40
  "./dist/element-browser.js"
39
41
  ],
40
42
  "main": "./dist/index.cjs",
@@ -51,6 +53,11 @@
51
53
  "import": "./dist/element.js",
52
54
  "require": "./dist/element.cjs"
53
55
  },
56
+ "./player": {
57
+ "types": "./dist/player.d.ts",
58
+ "import": "./dist/player.js",
59
+ "require": "./dist/player.cjs"
60
+ },
54
61
  "./element-browser": {
55
62
  "types": "./dist/element.d.ts",
56
63
  "import": "./dist/element-browser.js"
@@ -83,6 +90,7 @@
83
90
  "test:playback": "node scripts/playback-test.mjs",
84
91
  "test:convert": "node scripts/convert-test.mjs",
85
92
  "test:element": "node scripts/element-test.mjs",
93
+ "test:player-controls": "node scripts/player-controls-test.mjs",
86
94
  "test:url-streaming": "node scripts/url-streaming-test.mjs",
87
95
  "fixtures": "node scripts/generate-fixtures.mjs",
88
96
  "audit:bundle": "node scripts/bundle-audit.mjs"
@@ -13,8 +13,9 @@ import { mp4MimeFor, mseSupports } from "../util/codec-strings.js";
13
13
  * Codecs we know `<video>` and MSE support across modern desktop + Android.
14
14
  * The decision to remux instead of decode hinges on this list.
15
15
  */
16
- const NATIVE_VIDEO_CODECS = new Set<VideoCodec>(["h264", "h265", "vp8", "vp9", "av1"]);
17
- const NATIVE_AUDIO_CODECS = new Set<AudioCodec>([
16
+ /** Codecs the browser can decode natively (also the set WebCodecs can transcode). */
17
+ export const NATIVE_VIDEO_CODECS = new Set<VideoCodec>(["h264", "h265", "vp8", "vp9", "av1"]);
18
+ export const NATIVE_AUDIO_CODECS = new Set<AudioCodec>([
18
19
  "aac",
19
20
  "mp3",
20
21
  "opus",
@@ -25,14 +26,15 @@ const NATIVE_AUDIO_CODECS = new Set<AudioCodec>([
25
26
  /**
26
27
  * Codecs no major browser plays, period. These force the WASM fallback.
27
28
  */
28
- const FALLBACK_VIDEO_CODECS = new Set<VideoCodec>([
29
+ export const FALLBACK_VIDEO_CODECS = new Set<VideoCodec>([
29
30
  "wmv3", "vc1", "mpeg4",
30
31
  "rv10", "rv20", "rv30", "rv40",
31
32
  "mpeg2", "mpeg1", "theora",
32
33
  ]);
33
- const FALLBACK_AUDIO_CODECS = new Set<AudioCodec>([
34
+ export const FALLBACK_AUDIO_CODECS = new Set<AudioCodec>([
34
35
  "wmav2", "wmapro", "ac3", "eac3",
35
36
  "cook", "ra_144", "ra_288", "sipr", "atrac3",
37
+ "dts", "truehd",
36
38
  ]);
37
39
 
38
40
  /**
@@ -120,7 +122,27 @@ export function classifyContext(ctx: MediaContext): Classification {
120
122
  reason: `video codec "${video.codec}" has no browser decoder; WASM fallback required`,
121
123
  };
122
124
  }
123
- if (audio && FALLBACK_AUDIO_CODECS.has(audio.codec)) {
125
+ // Audio codec needs WASM decode — either it's in the known fallback set
126
+ // or it's unrecognized ("unknown" / not in native set). Unknown codecs
127
+ // definitely can't play natively, so they get the same treatment.
128
+ const audioNeedsFallback = audio && (
129
+ FALLBACK_AUDIO_CODECS.has(audio.codec) ||
130
+ !NATIVE_AUDIO_CODECS.has(audio.codec)
131
+ );
132
+ if (audioNeedsFallback) {
133
+ // If the VIDEO codec is native, prefer hybrid (WebCodecs hardware video
134
+ // decode + libav software audio decode) over full WASM fallback. This is
135
+ // critical for Blu-ray MKVs: H.264 1080p in WASM is unwatchably slow,
136
+ // but WebCodecs decodes it at full speed while libav handles the DTS/AC3
137
+ // audio in software.
138
+ if (NATIVE_VIDEO_CODECS.has(video.codec) && webCodecsAvailable()) {
139
+ return {
140
+ class: "HYBRID_CANDIDATE",
141
+ strategy: "hybrid",
142
+ reason: `video "${video.codec}" is hardware-decodable via WebCodecs; audio "${audio.codec}" decoded in software by libav`,
143
+ fallbackChain: ["fallback"],
144
+ };
145
+ }
124
146
  return {
125
147
  class: "FALLBACK_REQUIRED",
126
148
  strategy: "fallback",
@@ -11,12 +11,14 @@
11
11
  */
12
12
 
13
13
  import { probe } from "../probe/index.js";
14
+ import { isAnnexB, annexBToAvcc } from "../strategies/remux/annexb.js";
14
15
  import {
15
16
  avbridgeVideoToMediabunny,
16
17
  avbridgeAudioToMediabunny,
17
18
  buildMediabunnySourceFromInput,
18
19
  } from "../probe/mediabunny.js";
19
20
  import { normalizeSource } from "../util/source.js";
21
+ import { sanitizePacketTimestamp } from "../util/libav-demux.js";
20
22
  import { prepareLibavInput, type LibavInputHandle } from "../util/libav-http-reader.js";
21
23
  import type {
22
24
  MediaInput,
@@ -304,6 +306,13 @@ async function doLibavRemux(
304
306
  return ts;
305
307
  }, videoTimeBase);
306
308
 
309
+ // libav demuxes AVI/ASF/FLV H.264 as Annex B (start-code framed),
310
+ // but mediabunny's fMP4 muxer expects AVCC (length-prefixed). Convert
311
+ // on the fly. The check is cheap: isAnnexB reads 4 bytes at the head.
312
+ if (videoTrackInfo && (videoTrackInfo.codec === "h264" || videoTrackInfo.codec === "h265") && isAnnexB(pkt.data)) {
313
+ pkt.data = annexBToAvcc(pkt.data);
314
+ }
315
+
307
316
  const mbPacket = libavPacketToMediAbunny(mb, pkt);
308
317
  await videoSource.add(
309
318
  mbPacket,
@@ -377,41 +386,6 @@ async function doLibavRemux(
377
386
  };
378
387
  }
379
388
 
380
- // ── Packet timestamp sanitizer (from hybrid/decoder.ts) ─────────────────────
381
-
382
- function sanitizePacketTimestamp(
383
- pkt: LibavPacket,
384
- nextUs: () => number,
385
- fallbackTimeBase?: [number, number],
386
- ): void {
387
- const lo = pkt.pts ?? 0;
388
- const hi = pkt.ptshi ?? 0;
389
- const isInvalid = (hi === -2147483648 && lo === 0) || !Number.isFinite(lo);
390
- if (isInvalid) {
391
- const us = nextUs();
392
- pkt.pts = us;
393
- pkt.ptshi = 0;
394
- pkt.time_base_num = 1;
395
- pkt.time_base_den = 1_000_000;
396
- return;
397
- }
398
- const tb = fallbackTimeBase ?? [1, 1_000_000];
399
- const pts64 = hi * 0x100000000 + lo;
400
- const us = Math.round((pts64 * 1_000_000 * tb[0]) / tb[1]);
401
- if (Number.isFinite(us) && Math.abs(us) <= Number.MAX_SAFE_INTEGER) {
402
- pkt.pts = us;
403
- pkt.ptshi = us < 0 ? -1 : 0;
404
- pkt.time_base_num = 1;
405
- pkt.time_base_den = 1_000_000;
406
- return;
407
- }
408
- const fallback = nextUs();
409
- pkt.pts = fallback;
410
- pkt.ptshi = 0;
411
- pkt.time_base_num = 1;
412
- pkt.time_base_den = 1_000_000;
413
- }
414
-
415
389
  // ── Helpers ─────────────────────────────────────────────────────────────────
416
390
 
417
391
  /** @internal Exported for use by transcode(). */