webcodecs-worker.js 133 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524
  1. "use strict";
  2. var EncoderWorkerGlobal = (() => {
  3. var __create = Object.create;
  4. var __defProp = Object.defineProperty;
  5. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  6. var __getOwnPropNames = Object.getOwnPropertyNames;
  7. var __getProtoOf = Object.getPrototypeOf;
  8. var __hasOwnProp = Object.prototype.hasOwnProperty;
  9. var __commonJS = (cb, mod) => function __require() {
  10. return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
  11. };
  12. var __copyProps = (to, from, except, desc) => {
  13. if (from && typeof from === "object" || typeof from === "function") {
  14. for (let key of __getOwnPropNames(from))
  15. if (!__hasOwnProp.call(to, key) && key !== except)
  16. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  17. }
  18. return to;
  19. };
  20. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  21. // If the importer is in node compatibility mode or this is not an ESM
  22. // file that has been converted to a CommonJS file using a Babel-
  23. // compatible transform (i.e. "__esModule" has not been set), then set
  24. // "default" to the CommonJS "module.exports" for node compatibility.
  25. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  26. mod
  27. ));
  28. // node_modules/webm-muxer/build/webm-muxer.js
  29. var require_webm_muxer = __commonJS({
  30. "node_modules/webm-muxer/build/webm-muxer.js"(exports, module) {
  31. "use strict";
  32. var WebMMuxer2 = (() => {
  33. var __defProp3 = Object.defineProperty;
  34. var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
  35. var __getOwnPropNames2 = Object.getOwnPropertyNames;
  36. var __hasOwnProp3 = Object.prototype.hasOwnProperty;
  37. var __pow2 = Math.pow;
  38. var __export = (target, all) => {
  39. for (var name in all)
  40. __defProp3(target, name, { get: all[name], enumerable: true });
  41. };
  42. var __copyProps2 = (to, from, except, desc) => {
  43. if (from && typeof from === "object" || typeof from === "function") {
  44. for (let key of __getOwnPropNames2(from))
  45. if (!__hasOwnProp3.call(to, key) && key !== except)
  46. __defProp3(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
  47. }
  48. return to;
  49. };
  50. var __toCommonJS = (mod) => __copyProps2(__defProp3({}, "__esModule", { value: true }), mod);
  51. var __accessCheck2 = (obj, member, msg) => {
  52. if (!member.has(obj))
  53. throw TypeError("Cannot " + msg);
  54. };
  55. var __privateGet2 = (obj, member, getter) => {
  56. __accessCheck2(obj, member, "read from private field");
  57. return getter ? getter.call(obj) : member.get(obj);
  58. };
  59. var __privateAdd2 = (obj, member, value) => {
  60. if (member.has(obj))
  61. throw TypeError("Cannot add the same private member more than once");
  62. member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
  63. };
  64. var __privateSet2 = (obj, member, value, setter) => {
  65. __accessCheck2(obj, member, "write to private field");
  66. setter ? setter.call(obj, value) : member.set(obj, value);
  67. return value;
  68. };
  69. var __privateMethod2 = (obj, member, method) => {
  70. __accessCheck2(obj, member, "access private method");
  71. return method;
  72. };
  73. var main_exports = {};
  74. __export(main_exports, {
  75. default: () => main_default
  76. });
  77. var EBMLFloat32 = class {
  78. constructor(value) {
  79. this.value = value;
  80. }
  81. };
  82. var EBMLFloat64 = class {
  83. constructor(value) {
  84. this.value = value;
  85. }
  86. };
  87. var WriteTarget = class {
  88. constructor() {
  89. this.pos = 0;
  90. this.helper = new Uint8Array(8);
  91. this.helperView = new DataView(this.helper.buffer);
  92. this.offsets = /* @__PURE__ */ new WeakMap();
  93. this.dataOffsets = /* @__PURE__ */ new WeakMap();
  94. }
  95. writeFloat32(value) {
  96. this.helperView.setFloat32(0, value, false);
  97. this.write(this.helper.subarray(0, 4));
  98. }
  99. writeFloat64(value) {
  100. this.helperView.setFloat64(0, value, false);
  101. this.write(this.helper);
  102. }
  103. writeUnsignedInt(value, width = measureUnsignedInt(value)) {
  104. let pos = 0;
  105. switch (width) {
  106. case 6:
  107. this.helperView.setUint8(pos++, value / __pow2(2, 40) | 0);
  108. case 5:
  109. this.helperView.setUint8(pos++, value / __pow2(2, 32) | 0);
  110. case 4:
  111. this.helperView.setUint8(pos++, value >> 24);
  112. case 3:
  113. this.helperView.setUint8(pos++, value >> 16);
  114. case 2:
  115. this.helperView.setUint8(pos++, value >> 8);
  116. case 1:
  117. this.helperView.setUint8(pos++, value);
  118. break;
  119. default:
  120. throw new Error("Bad UINT size " + width);
  121. }
  122. this.write(this.helper.subarray(0, pos));
  123. }
  124. writeEBMLVarInt(value, width = measureEBMLVarInt(value)) {
  125. let pos = 0;
  126. switch (width) {
  127. case 1:
  128. this.helperView.setUint8(pos++, 1 << 7 | value);
  129. break;
  130. case 2:
  131. this.helperView.setUint8(pos++, 1 << 6 | value >> 8);
  132. this.helperView.setUint8(pos++, value);
  133. break;
  134. case 3:
  135. this.helperView.setUint8(pos++, 1 << 5 | value >> 16);
  136. this.helperView.setUint8(pos++, value >> 8);
  137. this.helperView.setUint8(pos++, value);
  138. break;
  139. case 4:
  140. this.helperView.setUint8(pos++, 1 << 4 | value >> 24);
  141. this.helperView.setUint8(pos++, value >> 16);
  142. this.helperView.setUint8(pos++, value >> 8);
  143. this.helperView.setUint8(pos++, value);
  144. break;
  145. case 5:
  146. this.helperView.setUint8(pos++, 1 << 3 | value / __pow2(2, 32) & 7);
  147. this.helperView.setUint8(pos++, value >> 24);
  148. this.helperView.setUint8(pos++, value >> 16);
  149. this.helperView.setUint8(pos++, value >> 8);
  150. this.helperView.setUint8(pos++, value);
  151. break;
  152. case 6:
  153. this.helperView.setUint8(pos++, 1 << 2 | value / __pow2(2, 40) & 3);
  154. this.helperView.setUint8(pos++, value / __pow2(2, 32) | 0);
  155. this.helperView.setUint8(pos++, value >> 24);
  156. this.helperView.setUint8(pos++, value >> 16);
  157. this.helperView.setUint8(pos++, value >> 8);
  158. this.helperView.setUint8(pos++, value);
  159. break;
  160. default:
  161. throw new Error("Bad EBML VINT size " + width);
  162. }
  163. this.write(this.helper.subarray(0, pos));
  164. }
  165. writeString(str) {
  166. this.write(new Uint8Array(str.split("").map((x) => x.charCodeAt(0))));
  167. }
  168. writeEBML(data) {
  169. var _a, _b;
  170. if (data instanceof Uint8Array) {
  171. this.write(data);
  172. } else if (Array.isArray(data)) {
  173. for (let elem of data) {
  174. this.writeEBML(elem);
  175. }
  176. } else {
  177. this.offsets.set(data, this.pos);
  178. this.writeUnsignedInt(data.id);
  179. if (Array.isArray(data.data)) {
  180. let sizePos = this.pos;
  181. let sizeSize = (_a = data.size) != null ? _a : 4;
  182. this.seek(this.pos + sizeSize);
  183. let startPos = this.pos;
  184. this.dataOffsets.set(data, startPos);
  185. this.writeEBML(data.data);
  186. let size = this.pos - startPos;
  187. let endPos = this.pos;
  188. this.seek(sizePos);
  189. this.writeEBMLVarInt(size, sizeSize);
  190. this.seek(endPos);
  191. } else if (typeof data.data === "number") {
  192. let size = (_b = data.size) != null ? _b : measureUnsignedInt(data.data);
  193. this.writeEBMLVarInt(size);
  194. this.writeUnsignedInt(data.data, size);
  195. } else if (typeof data.data === "string") {
  196. this.writeEBMLVarInt(data.data.length);
  197. this.writeString(data.data);
  198. } else if (data.data instanceof Uint8Array) {
  199. this.writeEBMLVarInt(data.data.byteLength, data.size);
  200. this.write(data.data);
  201. } else if (data.data instanceof EBMLFloat32) {
  202. this.writeEBMLVarInt(4);
  203. this.writeFloat32(data.data.value);
  204. } else if (data.data instanceof EBMLFloat64) {
  205. this.writeEBMLVarInt(8);
  206. this.writeFloat64(data.data.value);
  207. }
  208. }
  209. }
  210. };
  211. var measureUnsignedInt = (value) => {
  212. if (value < 1 << 8) {
  213. return 1;
  214. } else if (value < 1 << 16) {
  215. return 2;
  216. } else if (value < 1 << 24) {
  217. return 3;
  218. } else if (value < __pow2(2, 32)) {
  219. return 4;
  220. } else if (value < __pow2(2, 40)) {
  221. return 5;
  222. } else {
  223. return 6;
  224. }
  225. };
  226. var measureEBMLVarInt = (value) => {
  227. if (value < (1 << 7) - 1) {
  228. return 1;
  229. } else if (value < (1 << 14) - 1) {
  230. return 2;
  231. } else if (value < (1 << 21) - 1) {
  232. return 3;
  233. } else if (value < (1 << 28) - 1) {
  234. return 4;
  235. } else if (value < __pow2(2, 35) - 1) {
  236. return 5;
  237. } else if (value < __pow2(2, 42) - 1) {
  238. return 6;
  239. } else {
  240. throw new Error("EBML VINT size not supported " + value);
  241. }
  242. };
  243. var ArrayBufferWriteTarget = class extends WriteTarget {
  244. constructor() {
  245. super();
  246. this.buffer = new ArrayBuffer(__pow2(2, 16));
  247. this.bytes = new Uint8Array(this.buffer);
  248. }
  249. ensureSize(size) {
  250. let newLength = this.buffer.byteLength;
  251. while (newLength < size)
  252. newLength *= 2;
  253. if (newLength === this.buffer.byteLength)
  254. return;
  255. let newBuffer = new ArrayBuffer(newLength);
  256. let newBytes = new Uint8Array(newBuffer);
  257. newBytes.set(this.bytes, 0);
  258. this.buffer = newBuffer;
  259. this.bytes = newBytes;
  260. }
  261. write(data) {
  262. this.ensureSize(this.pos + data.byteLength);
  263. this.bytes.set(data, this.pos);
  264. this.pos += data.byteLength;
  265. }
  266. seek(newPos) {
  267. this.pos = newPos;
  268. }
  269. finalize() {
  270. this.ensureSize(this.pos);
  271. return this.buffer.slice(0, this.pos);
  272. }
  273. };
  274. var FILE_CHUNK_SIZE = __pow2(2, 24);
  275. var MAX_CHUNKS_AT_ONCE2 = 2;
  276. var FileSystemWritableFileStreamWriteTarget = class extends WriteTarget {
  277. constructor(stream) {
  278. super();
  279. this.chunks = [];
  280. this.stream = stream;
  281. }
  282. write(data) {
  283. this.writeDataIntoChunks(data, this.pos);
  284. this.flushChunks();
  285. this.pos += data.byteLength;
  286. }
  287. writeDataIntoChunks(data, position) {
  288. let chunkIndex = this.chunks.findIndex((x) => x.start <= position && position < x.start + FILE_CHUNK_SIZE);
  289. if (chunkIndex === -1)
  290. chunkIndex = this.createChunk(position);
  291. let chunk = this.chunks[chunkIndex];
  292. let relativePosition = position - chunk.start;
  293. let toWrite = data.subarray(0, Math.min(FILE_CHUNK_SIZE - relativePosition, data.byteLength));
  294. chunk.data.set(toWrite, relativePosition);
  295. let section = {
  296. start: relativePosition,
  297. end: relativePosition + toWrite.byteLength
  298. };
  299. insertSectionIntoFileChunk(chunk, section);
  300. if (chunk.written[0].start === 0 && chunk.written[0].end === FILE_CHUNK_SIZE) {
  301. chunk.shouldFlush = true;
  302. }
  303. if (this.chunks.length > MAX_CHUNKS_AT_ONCE2) {
  304. for (let i = 0; i < this.chunks.length - 1; i++) {
  305. this.chunks[i].shouldFlush = true;
  306. }
  307. this.flushChunks();
  308. }
  309. if (toWrite.byteLength < data.byteLength) {
  310. this.writeDataIntoChunks(data.subarray(toWrite.byteLength), position + toWrite.byteLength);
  311. }
  312. }
  313. createChunk(includesPosition) {
  314. let start = Math.floor(includesPosition / FILE_CHUNK_SIZE) * FILE_CHUNK_SIZE;
  315. let chunk = {
  316. start,
  317. data: new Uint8Array(FILE_CHUNK_SIZE),
  318. written: [],
  319. shouldFlush: false
  320. };
  321. this.chunks.push(chunk);
  322. this.chunks.sort((a, b) => a.start - b.start);
  323. return this.chunks.indexOf(chunk);
  324. }
  325. flushChunks(force = false) {
  326. for (let i = 0; i < this.chunks.length; i++) {
  327. let chunk = this.chunks[i];
  328. if (!chunk.shouldFlush && !force)
  329. continue;
  330. for (let section of chunk.written) {
  331. this.stream.write({
  332. type: "write",
  333. data: chunk.data.subarray(section.start, section.end),
  334. position: chunk.start + section.start
  335. });
  336. }
  337. this.chunks.splice(i--, 1);
  338. }
  339. }
  340. seek(newPos) {
  341. this.pos = newPos;
  342. }
  343. finalize() {
  344. this.flushChunks(true);
  345. }
  346. };
  347. var insertSectionIntoFileChunk = (chunk, section) => {
  348. let low = 0;
  349. let high = chunk.written.length - 1;
  350. let index = -1;
  351. while (low <= high) {
  352. let mid = Math.floor(low + (high - low + 1) / 2);
  353. if (chunk.written[mid].start <= section.start) {
  354. low = mid + 1;
  355. index = mid;
  356. } else {
  357. high = mid - 1;
  358. }
  359. }
  360. chunk.written.splice(index + 1, 0, section);
  361. if (index === -1 || chunk.written[index].end < section.start)
  362. index++;
  363. while (index < chunk.written.length - 1 && chunk.written[index].end >= chunk.written[index + 1].start) {
  364. chunk.written[index].end = Math.max(chunk.written[index].end, chunk.written[index + 1].end);
  365. chunk.written.splice(index + 1, 1);
  366. }
  367. };
  368. var VIDEO_TRACK_NUMBER = 1;
  369. var AUDIO_TRACK_NUMBER = 2;
  370. var VIDEO_TRACK_TYPE = 1;
  371. var AUDIO_TRACK_TYPE = 2;
  372. var MAX_CHUNK_LENGTH_MS = __pow2(2, 15);
  373. var CODEC_PRIVATE_MAX_SIZE = __pow2(2, 12);
  374. var APP_NAME = "https://github.com/Vanilagy/webm-muxer";
  375. var SEGMENT_SIZE_BYTES = 6;
  376. var CLUSTER_SIZE_BYTES = 5;
  377. var _target4, _options2, _segment, _segmentInfo, _seekHead, _tracksElement, _segmentDuration, _colourElement, _videoCodecPrivate, _audioCodecPrivate, _cues, _currentCluster, _currentClusterTimestamp, _duration, _videoChunkQueue, _audioChunkQueue, _lastVideoTimestamp, _lastAudioTimestamp, _colorSpace, _finalized2, _validateOptions2, validateOptions_fn2, _createFileHeader, createFileHeader_fn, _writeEBMLHeader, writeEBMLHeader_fn, _createSeekHead, createSeekHead_fn, _createSegmentInfo, createSegmentInfo_fn, _createTracks, createTracks_fn, _createSegment, createSegment_fn, _createCues, createCues_fn, _segmentDataOffset, segmentDataOffset_get, _writeVideoDecoderConfig, writeVideoDecoderConfig_fn, _fixVP9ColorSpace, fixVP9ColorSpace_fn, _createInternalChunk, createInternalChunk_fn, _writeSimpleBlock, writeSimpleBlock_fn, _writeCodecPrivate, writeCodecPrivate_fn, _createNewCluster, createNewCluster_fn, _finalizeCurrentCluster, finalizeCurrentCluster_fn, _ensureNotFinalized2, ensureNotFinalized_fn2;
  378. var WebMMuxer3 = class {
  379. constructor(options) {
  380. __privateAdd2(this, _validateOptions2);
  381. __privateAdd2(this, _createFileHeader);
  382. __privateAdd2(this, _writeEBMLHeader);
  383. __privateAdd2(this, _createSeekHead);
  384. __privateAdd2(this, _createSegmentInfo);
  385. __privateAdd2(this, _createTracks);
  386. __privateAdd2(this, _createSegment);
  387. __privateAdd2(this, _createCues);
  388. __privateAdd2(this, _segmentDataOffset);
  389. __privateAdd2(this, _writeVideoDecoderConfig);
  390. __privateAdd2(this, _fixVP9ColorSpace);
  391. __privateAdd2(this, _createInternalChunk);
  392. __privateAdd2(this, _writeSimpleBlock);
  393. __privateAdd2(this, _writeCodecPrivate);
  394. __privateAdd2(this, _createNewCluster);
  395. __privateAdd2(this, _finalizeCurrentCluster);
  396. __privateAdd2(this, _ensureNotFinalized2);
  397. __privateAdd2(this, _target4, void 0);
  398. __privateAdd2(this, _options2, void 0);
  399. __privateAdd2(this, _segment, void 0);
  400. __privateAdd2(this, _segmentInfo, void 0);
  401. __privateAdd2(this, _seekHead, void 0);
  402. __privateAdd2(this, _tracksElement, void 0);
  403. __privateAdd2(this, _segmentDuration, void 0);
  404. __privateAdd2(this, _colourElement, void 0);
  405. __privateAdd2(this, _videoCodecPrivate, void 0);
  406. __privateAdd2(this, _audioCodecPrivate, void 0);
  407. __privateAdd2(this, _cues, void 0);
  408. __privateAdd2(this, _currentCluster, void 0);
  409. __privateAdd2(this, _currentClusterTimestamp, void 0);
  410. __privateAdd2(this, _duration, 0);
  411. __privateAdd2(this, _videoChunkQueue, []);
  412. __privateAdd2(this, _audioChunkQueue, []);
  413. __privateAdd2(this, _lastVideoTimestamp, 0);
  414. __privateAdd2(this, _lastAudioTimestamp, 0);
  415. __privateAdd2(this, _colorSpace, void 0);
  416. __privateAdd2(this, _finalized2, false);
  417. __privateMethod2(this, _validateOptions2, validateOptions_fn2).call(this, options);
  418. __privateSet2(this, _options2, options);
  419. if (options.target === "buffer") {
  420. __privateSet2(this, _target4, new ArrayBufferWriteTarget());
  421. } else {
  422. __privateSet2(this, _target4, new FileSystemWritableFileStreamWriteTarget(options.target));
  423. }
  424. __privateMethod2(this, _createFileHeader, createFileHeader_fn).call(this);
  425. }
  426. addVideoChunk(chunk, meta, timestamp) {
  427. let data = new Uint8Array(chunk.byteLength);
  428. chunk.copyTo(data);
  429. this.addVideoChunkRaw(data, chunk.type, timestamp != null ? timestamp : chunk.timestamp, meta);
  430. }
  431. addVideoChunkRaw(data, type, timestamp, meta) {
  432. __privateMethod2(this, _ensureNotFinalized2, ensureNotFinalized_fn2).call(this);
  433. if (!__privateGet2(this, _options2).video)
  434. throw new Error("No video track declared.");
  435. if (meta)
  436. __privateMethod2(this, _writeVideoDecoderConfig, writeVideoDecoderConfig_fn).call(this, meta);
  437. let internalChunk = __privateMethod2(this, _createInternalChunk, createInternalChunk_fn).call(this, data, type, timestamp, VIDEO_TRACK_NUMBER);
  438. if (__privateGet2(this, _options2).video.codec === "V_VP9")
  439. __privateMethod2(this, _fixVP9ColorSpace, fixVP9ColorSpace_fn).call(this, internalChunk);
  440. __privateSet2(this, _lastVideoTimestamp, internalChunk.timestamp);
  441. while (__privateGet2(this, _audioChunkQueue).length > 0 && __privateGet2(this, _audioChunkQueue)[0].timestamp <= internalChunk.timestamp) {
  442. let audioChunk = __privateGet2(this, _audioChunkQueue).shift();
  443. __privateMethod2(this, _writeSimpleBlock, writeSimpleBlock_fn).call(this, audioChunk);
  444. }
  445. if (!__privateGet2(this, _options2).audio || internalChunk.timestamp <= __privateGet2(this, _lastAudioTimestamp)) {
  446. __privateMethod2(this, _writeSimpleBlock, writeSimpleBlock_fn).call(this, internalChunk);
  447. } else {
  448. __privateGet2(this, _videoChunkQueue).push(internalChunk);
  449. }
  450. }
  451. addAudioChunk(chunk, meta, timestamp) {
  452. let data = new Uint8Array(chunk.byteLength);
  453. chunk.copyTo(data);
  454. this.addAudioChunkRaw(data, chunk.type, timestamp != null ? timestamp : chunk.timestamp, meta);
  455. }
  456. addAudioChunkRaw(data, type, timestamp, meta) {
  457. __privateMethod2(this, _ensureNotFinalized2, ensureNotFinalized_fn2).call(this);
  458. if (!__privateGet2(this, _options2).audio)
  459. throw new Error("No audio track declared.");
  460. let internalChunk = __privateMethod2(this, _createInternalChunk, createInternalChunk_fn).call(this, data, type, timestamp, AUDIO_TRACK_NUMBER);
  461. __privateSet2(this, _lastAudioTimestamp, internalChunk.timestamp);
  462. while (__privateGet2(this, _videoChunkQueue).length > 0 && __privateGet2(this, _videoChunkQueue)[0].timestamp <= internalChunk.timestamp) {
  463. let videoChunk = __privateGet2(this, _videoChunkQueue).shift();
  464. __privateMethod2(this, _writeSimpleBlock, writeSimpleBlock_fn).call(this, videoChunk);
  465. }
  466. if (!__privateGet2(this, _options2).video || internalChunk.timestamp <= __privateGet2(this, _lastVideoTimestamp)) {
  467. __privateMethod2(this, _writeSimpleBlock, writeSimpleBlock_fn).call(this, internalChunk);
  468. } else {
  469. __privateGet2(this, _audioChunkQueue).push(internalChunk);
  470. }
  471. if (meta == null ? void 0 : meta.decoderConfig) {
  472. __privateMethod2(this, _writeCodecPrivate, writeCodecPrivate_fn).call(this, __privateGet2(this, _audioCodecPrivate), meta.decoderConfig.description);
  473. }
  474. }
  475. finalize() {
  476. while (__privateGet2(this, _videoChunkQueue).length > 0)
  477. __privateMethod2(this, _writeSimpleBlock, writeSimpleBlock_fn).call(this, __privateGet2(this, _videoChunkQueue).shift());
  478. while (__privateGet2(this, _audioChunkQueue).length > 0)
  479. __privateMethod2(this, _writeSimpleBlock, writeSimpleBlock_fn).call(this, __privateGet2(this, _audioChunkQueue).shift());
  480. __privateMethod2(this, _finalizeCurrentCluster, finalizeCurrentCluster_fn).call(this);
  481. __privateGet2(this, _target4).writeEBML(__privateGet2(this, _cues));
  482. let endPos = __privateGet2(this, _target4).pos;
  483. let segmentSize = __privateGet2(this, _target4).pos - __privateGet2(this, _segmentDataOffset, segmentDataOffset_get);
  484. __privateGet2(this, _target4).seek(__privateGet2(this, _target4).offsets.get(__privateGet2(this, _segment)) + 4);
  485. __privateGet2(this, _target4).writeEBMLVarInt(segmentSize, SEGMENT_SIZE_BYTES);
  486. __privateGet2(this, _segmentDuration).data = new EBMLFloat64(__privateGet2(this, _duration));
  487. __privateGet2(this, _target4).seek(__privateGet2(this, _target4).offsets.get(__privateGet2(this, _segmentDuration)));
  488. __privateGet2(this, _target4).writeEBML(__privateGet2(this, _segmentDuration));
  489. __privateGet2(this, _seekHead).data[0].data[1].data = __privateGet2(this, _target4).offsets.get(__privateGet2(this, _cues)) - __privateGet2(this, _segmentDataOffset, segmentDataOffset_get);
  490. __privateGet2(this, _seekHead).data[1].data[1].data = __privateGet2(this, _target4).offsets.get(__privateGet2(this, _segmentInfo)) - __privateGet2(this, _segmentDataOffset, segmentDataOffset_get);
  491. __privateGet2(this, _seekHead).data[2].data[1].data = __privateGet2(this, _target4).offsets.get(__privateGet2(this, _tracksElement)) - __privateGet2(this, _segmentDataOffset, segmentDataOffset_get);
  492. __privateGet2(this, _target4).seek(__privateGet2(this, _target4).offsets.get(__privateGet2(this, _seekHead)));
  493. __privateGet2(this, _target4).writeEBML(__privateGet2(this, _seekHead));
  494. __privateGet2(this, _target4).seek(endPos);
  495. __privateSet2(this, _finalized2, true);
  496. if (__privateGet2(this, _target4) instanceof ArrayBufferWriteTarget) {
  497. return __privateGet2(this, _target4).finalize();
  498. } else if (__privateGet2(this, _target4) instanceof FileSystemWritableFileStreamWriteTarget) {
  499. __privateGet2(this, _target4).finalize();
  500. }
  501. return null;
  502. }
  503. };
  504. _target4 = /* @__PURE__ */ new WeakMap();
  505. _options2 = /* @__PURE__ */ new WeakMap();
  506. _segment = /* @__PURE__ */ new WeakMap();
  507. _segmentInfo = /* @__PURE__ */ new WeakMap();
  508. _seekHead = /* @__PURE__ */ new WeakMap();
  509. _tracksElement = /* @__PURE__ */ new WeakMap();
  510. _segmentDuration = /* @__PURE__ */ new WeakMap();
  511. _colourElement = /* @__PURE__ */ new WeakMap();
  512. _videoCodecPrivate = /* @__PURE__ */ new WeakMap();
  513. _audioCodecPrivate = /* @__PURE__ */ new WeakMap();
  514. _cues = /* @__PURE__ */ new WeakMap();
  515. _currentCluster = /* @__PURE__ */ new WeakMap();
  516. _currentClusterTimestamp = /* @__PURE__ */ new WeakMap();
  517. _duration = /* @__PURE__ */ new WeakMap();
  518. _videoChunkQueue = /* @__PURE__ */ new WeakMap();
  519. _audioChunkQueue = /* @__PURE__ */ new WeakMap();
  520. _lastVideoTimestamp = /* @__PURE__ */ new WeakMap();
  521. _lastAudioTimestamp = /* @__PURE__ */ new WeakMap();
  522. _colorSpace = /* @__PURE__ */ new WeakMap();
  523. _finalized2 = /* @__PURE__ */ new WeakMap();
  524. _validateOptions2 = /* @__PURE__ */ new WeakSet();
  525. validateOptions_fn2 = function(options) {
  526. if (options.type && options.type !== "webm" && options.type !== "matroska") {
  527. throw new Error(`Invalid type: ${options.type}`);
  528. }
  529. };
  530. _createFileHeader = /* @__PURE__ */ new WeakSet();
  531. createFileHeader_fn = function() {
  532. __privateMethod2(this, _writeEBMLHeader, writeEBMLHeader_fn).call(this);
  533. __privateMethod2(this, _createSeekHead, createSeekHead_fn).call(this);
  534. __privateMethod2(this, _createSegmentInfo, createSegmentInfo_fn).call(this);
  535. __privateMethod2(this, _createTracks, createTracks_fn).call(this);
  536. __privateMethod2(this, _createSegment, createSegment_fn).call(this);
  537. __privateMethod2(this, _createCues, createCues_fn).call(this);
  538. };
  539. _writeEBMLHeader = /* @__PURE__ */ new WeakSet();
  540. writeEBMLHeader_fn = function() {
  541. var _a;
  542. let ebmlHeader = { id: 440786851, data: [
  543. { id: 17030, data: 1 },
  544. { id: 17143, data: 1 },
  545. { id: 17138, data: 4 },
  546. { id: 17139, data: 8 },
  547. { id: 17026, data: (_a = __privateGet2(this, _options2).type) != null ? _a : "webm" },
  548. { id: 17031, data: 2 },
  549. { id: 17029, data: 2 }
  550. ] };
  551. __privateGet2(this, _target4).writeEBML(ebmlHeader);
  552. };
  553. _createSeekHead = /* @__PURE__ */ new WeakSet();
  554. createSeekHead_fn = function() {
  555. const kaxCues = new Uint8Array([28, 83, 187, 107]);
  556. const kaxInfo = new Uint8Array([21, 73, 169, 102]);
  557. const kaxTracks = new Uint8Array([22, 84, 174, 107]);
  558. let seekHead = { id: 290298740, data: [
  559. { id: 19899, data: [
  560. { id: 21419, data: kaxCues },
  561. { id: 21420, size: 5, data: 0 }
  562. ] },
  563. { id: 19899, data: [
  564. { id: 21419, data: kaxInfo },
  565. { id: 21420, size: 5, data: 0 }
  566. ] },
  567. { id: 19899, data: [
  568. { id: 21419, data: kaxTracks },
  569. { id: 21420, size: 5, data: 0 }
  570. ] }
  571. ] };
  572. __privateSet2(this, _seekHead, seekHead);
  573. };
  574. _createSegmentInfo = /* @__PURE__ */ new WeakSet();
  575. createSegmentInfo_fn = function() {
  576. let segmentDuration = { id: 17545, data: new EBMLFloat64(0) };
  577. __privateSet2(this, _segmentDuration, segmentDuration);
  578. let segmentInfo = { id: 357149030, data: [
  579. { id: 2807729, data: 1e6 },
  580. { id: 19840, data: APP_NAME },
  581. { id: 22337, data: APP_NAME },
  582. segmentDuration
  583. ] };
  584. __privateSet2(this, _segmentInfo, segmentInfo);
  585. };
  586. _createTracks = /* @__PURE__ */ new WeakSet();
  587. createTracks_fn = function() {
  588. let tracksElement = { id: 374648427, data: [] };
  589. __privateSet2(this, _tracksElement, tracksElement);
  590. if (__privateGet2(this, _options2).video) {
  591. __privateSet2(this, _videoCodecPrivate, { id: 236, size: 4, data: new Uint8Array(CODEC_PRIVATE_MAX_SIZE) });
  592. let colourElement = { id: 21936, data: [
  593. { id: 21937, data: 2 },
  594. { id: 21946, data: 2 },
  595. { id: 21947, data: 2 },
  596. { id: 21945, data: 0 }
  597. ] };
  598. __privateSet2(this, _colourElement, colourElement);
  599. tracksElement.data.push({ id: 174, data: [
  600. { id: 215, data: VIDEO_TRACK_NUMBER },
  601. { id: 29637, data: VIDEO_TRACK_NUMBER },
  602. { id: 131, data: VIDEO_TRACK_TYPE },
  603. { id: 134, data: __privateGet2(this, _options2).video.codec },
  604. __privateGet2(this, _videoCodecPrivate),
  605. __privateGet2(this, _options2).video.frameRate ? { id: 2352003, data: 1e9 / __privateGet2(this, _options2).video.frameRate } : null,
  606. { id: 224, data: [
  607. { id: 176, data: __privateGet2(this, _options2).video.width },
  608. { id: 186, data: __privateGet2(this, _options2).video.height },
  609. colourElement
  610. ] }
  611. ].filter(Boolean) });
  612. }
  613. if (__privateGet2(this, _options2).audio) {
  614. __privateSet2(this, _audioCodecPrivate, { id: 236, size: 4, data: new Uint8Array(CODEC_PRIVATE_MAX_SIZE) });
  615. tracksElement.data.push({ id: 174, data: [
  616. { id: 215, data: AUDIO_TRACK_NUMBER },
  617. { id: 29637, data: AUDIO_TRACK_NUMBER },
  618. { id: 131, data: AUDIO_TRACK_TYPE },
  619. { id: 134, data: __privateGet2(this, _options2).audio.codec },
  620. __privateGet2(this, _audioCodecPrivate),
  621. { id: 225, data: [
  622. { id: 181, data: new EBMLFloat32(__privateGet2(this, _options2).audio.sampleRate) },
  623. { id: 159, data: __privateGet2(this, _options2).audio.numberOfChannels },
  624. __privateGet2(this, _options2).audio.bitDepth ? { id: 25188, data: __privateGet2(this, _options2).audio.bitDepth } : null
  625. ].filter(Boolean) }
  626. ] });
  627. }
  628. };
  629. _createSegment = /* @__PURE__ */ new WeakSet();
  630. createSegment_fn = function() {
  631. let segment = { id: 408125543, size: SEGMENT_SIZE_BYTES, data: [
  632. __privateGet2(this, _seekHead),
  633. __privateGet2(this, _segmentInfo),
  634. __privateGet2(this, _tracksElement)
  635. ] };
  636. __privateSet2(this, _segment, segment);
  637. __privateGet2(this, _target4).writeEBML(segment);
  638. };
  639. _createCues = /* @__PURE__ */ new WeakSet();
  640. createCues_fn = function() {
  641. __privateSet2(this, _cues, { id: 475249515, data: [] });
  642. };
  643. _segmentDataOffset = /* @__PURE__ */ new WeakSet();
  644. segmentDataOffset_get = function() {
  645. return __privateGet2(this, _target4).dataOffsets.get(__privateGet2(this, _segment));
  646. };
  647. _writeVideoDecoderConfig = /* @__PURE__ */ new WeakSet();
  648. writeVideoDecoderConfig_fn = function(meta) {
  649. if (meta.decoderConfig) {
  650. if (meta.decoderConfig.colorSpace) {
  651. let colorSpace = meta.decoderConfig.colorSpace;
  652. __privateSet2(this, _colorSpace, colorSpace);
  653. __privateGet2(this, _colourElement).data = [
  654. { id: 21937, data: {
  655. "rgb": 1,
  656. "bt709": 1,
  657. "bt470bg": 5,
  658. "smpte170m": 6
  659. }[colorSpace.matrix] },
  660. { id: 21946, data: {
  661. "bt709": 1,
  662. "smpte170m": 6,
  663. "iec61966-2-1": 13
  664. }[colorSpace.transfer] },
  665. { id: 21947, data: {
  666. "bt709": 1,
  667. "bt470bg": 5,
  668. "smpte170m": 6
  669. }[colorSpace.primaries] },
  670. { id: 21945, data: [1, 2][Number(colorSpace.fullRange)] }
  671. ];
  672. let endPos = __privateGet2(this, _target4).pos;
  673. __privateGet2(this, _target4).seek(__privateGet2(this, _target4).offsets.get(__privateGet2(this, _colourElement)));
  674. __privateGet2(this, _target4).writeEBML(__privateGet2(this, _colourElement));
  675. __privateGet2(this, _target4).seek(endPos);
  676. }
  677. if (meta.decoderConfig.description) {
  678. __privateMethod2(this, _writeCodecPrivate, writeCodecPrivate_fn).call(this, __privateGet2(this, _videoCodecPrivate), meta.decoderConfig.description);
  679. }
  680. }
  681. };
  682. _fixVP9ColorSpace = /* @__PURE__ */ new WeakSet();
  683. fixVP9ColorSpace_fn = function(chunk) {
  684. if (chunk.type !== "key")
  685. return;
  686. if (!__privateGet2(this, _colorSpace))
  687. return;
  688. let i = 0;
  689. if (readBits(chunk.data, 0, 2) !== 2)
  690. return;
  691. i += 2;
  692. let profile = (readBits(chunk.data, i + 1, i + 2) << 1) + readBits(chunk.data, i + 0, i + 1);
  693. i += 2;
  694. if (profile === 3)
  695. i++;
  696. let showExistingFrame = readBits(chunk.data, i + 0, i + 1);
  697. i++;
  698. if (showExistingFrame)
  699. return;
  700. let frameType = readBits(chunk.data, i + 0, i + 1);
  701. i++;
  702. if (frameType !== 0)
  703. return;
  704. i += 2;
  705. let syncCode = readBits(chunk.data, i + 0, i + 24);
  706. i += 24;
  707. if (syncCode !== 4817730)
  708. return;
  709. if (profile >= 2)
  710. i++;
  711. let colorSpaceID = {
  712. "rgb": 7,
  713. "bt709": 2,
  714. "bt470bg": 1,
  715. "smpte170m": 3
  716. }[__privateGet2(this, _colorSpace).matrix];
  717. writeBits(chunk.data, i + 0, i + 3, colorSpaceID);
  718. };
  719. _createInternalChunk = /* @__PURE__ */ new WeakSet();
  720. createInternalChunk_fn = function(data, type, timestamp, trackNumber) {
  721. let internalChunk = {
  722. data,
  723. type,
  724. timestamp,
  725. trackNumber
  726. };
  727. return internalChunk;
  728. };
  729. _writeSimpleBlock = /* @__PURE__ */ new WeakSet();
  730. writeSimpleBlock_fn = function(chunk) {
  731. let msTime = Math.floor(chunk.timestamp / 1e3);
  732. let clusterIsTooLong = chunk.type !== "key" && msTime - __privateGet2(this, _currentClusterTimestamp) >= MAX_CHUNK_LENGTH_MS;
  733. if (clusterIsTooLong) {
  734. throw new Error(
  735. `Current Matroska cluster exceeded its maximum allowed length of ${MAX_CHUNK_LENGTH_MS} milliseconds. In order to produce a correct WebM file, you must pass in a video key frame at least every ${MAX_CHUNK_LENGTH_MS} milliseconds.`
  736. );
  737. }
  738. let shouldCreateNewClusterFromKeyFrame = (chunk.trackNumber === VIDEO_TRACK_NUMBER || !__privateGet2(this, _options2).video) && chunk.type === "key" && msTime - __privateGet2(this, _currentClusterTimestamp) >= 1e3;
  739. if (!__privateGet2(this, _currentCluster) || shouldCreateNewClusterFromKeyFrame) {
  740. __privateMethod2(this, _createNewCluster, createNewCluster_fn).call(this, msTime);
  741. }
  742. let prelude = new Uint8Array(4);
  743. let view2 = new DataView(prelude.buffer);
  744. view2.setUint8(0, 128 | chunk.trackNumber);
  745. view2.setUint16(1, msTime - __privateGet2(this, _currentClusterTimestamp), false);
  746. view2.setUint8(3, Number(chunk.type === "key") << 7);
  747. let simpleBlock = { id: 163, data: [
  748. prelude,
  749. chunk.data
  750. ] };
  751. __privateGet2(this, _target4).writeEBML(simpleBlock);
  752. __privateSet2(this, _duration, Math.max(__privateGet2(this, _duration), msTime));
  753. };
  754. _writeCodecPrivate = /* @__PURE__ */ new WeakSet();
  755. writeCodecPrivate_fn = function(element, data) {
  756. let endPos = __privateGet2(this, _target4).pos;
  757. __privateGet2(this, _target4).seek(__privateGet2(this, _target4).offsets.get(element));
  758. element = [
  759. { id: 25506, size: 4, data: new Uint8Array(data) },
  760. { id: 236, size: 4, data: new Uint8Array(CODEC_PRIVATE_MAX_SIZE - 2 - 4 - data.byteLength) }
  761. ];
  762. __privateGet2(this, _target4).writeEBML(element);
  763. __privateGet2(this, _target4).seek(endPos);
  764. };
  765. _createNewCluster = /* @__PURE__ */ new WeakSet();
  766. createNewCluster_fn = function(timestamp) {
  767. if (__privateGet2(this, _currentCluster)) {
  768. __privateMethod2(this, _finalizeCurrentCluster, finalizeCurrentCluster_fn).call(this);
  769. }
  770. __privateSet2(this, _currentCluster, { id: 524531317, size: CLUSTER_SIZE_BYTES, data: [
  771. { id: 231, data: timestamp }
  772. ] });
  773. __privateGet2(this, _target4).writeEBML(__privateGet2(this, _currentCluster));
  774. __privateSet2(this, _currentClusterTimestamp, timestamp);
  775. let clusterOffsetFromSegment = __privateGet2(this, _target4).offsets.get(__privateGet2(this, _currentCluster)) - __privateGet2(this, _segmentDataOffset, segmentDataOffset_get);
  776. __privateGet2(this, _cues).data.push({ id: 187, data: [
  777. { id: 179, data: timestamp },
  778. { id: 183, data: [
  779. { id: 247, data: VIDEO_TRACK_NUMBER },
  780. { id: 241, data: clusterOffsetFromSegment }
  781. ] }
  782. ] });
  783. };
  784. _finalizeCurrentCluster = /* @__PURE__ */ new WeakSet();
  785. finalizeCurrentCluster_fn = function() {
  786. let clusterSize = __privateGet2(this, _target4).pos - __privateGet2(this, _target4).dataOffsets.get(__privateGet2(this, _currentCluster));
  787. let endPos = __privateGet2(this, _target4).pos;
  788. __privateGet2(this, _target4).seek(__privateGet2(this, _target4).offsets.get(__privateGet2(this, _currentCluster)) + 4);
  789. __privateGet2(this, _target4).writeEBMLVarInt(clusterSize, CLUSTER_SIZE_BYTES);
  790. __privateGet2(this, _target4).seek(endPos);
  791. };
  792. _ensureNotFinalized2 = /* @__PURE__ */ new WeakSet();
  793. ensureNotFinalized_fn2 = function() {
  794. if (__privateGet2(this, _finalized2)) {
  795. throw new Error("Cannot add new video or audio chunks after the file has been finalized.");
  796. }
  797. };
  798. var main_default = WebMMuxer3;
  799. var readBits = (bytes2, start, end) => {
  800. let result = 0;
  801. for (let i = start; i < end; i++) {
  802. let byteIndex = Math.floor(i / 8);
  803. let byte = bytes2[byteIndex];
  804. let bitIndex = 7 - (i & 7);
  805. let bit = (byte & 1 << bitIndex) >> bitIndex;
  806. result <<= 1;
  807. result |= bit;
  808. }
  809. return result;
  810. };
  811. var writeBits = (bytes2, start, end, value) => {
  812. for (let i = start; i < end; i++) {
  813. let byteIndex = Math.floor(i / 8);
  814. let byte = bytes2[byteIndex];
  815. let bitIndex = 7 - (i & 7);
  816. byte &= ~(1 << bitIndex);
  817. byte |= (value & 1 << end - i - 1) >> end - i - 1 << bitIndex;
  818. bytes2[byteIndex] = byte;
  819. }
  820. };
  821. return __toCommonJS(main_exports);
  822. })();
  823. WebMMuxer2 = WebMMuxer2.default;
  824. if (typeof module === "object" && typeof module.exports === "object") module.exports = WebMMuxer2;
  825. }
  826. });
  827. // node_modules/mp4-muxer/build/mp4-muxer.mjs
  828. var __defProp2 = Object.defineProperty;
  829. var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  830. var __hasOwnProp2 = Object.prototype.hasOwnProperty;
  831. var __propIsEnum = Object.prototype.propertyIsEnumerable;
  832. var __pow = Math.pow;
  833. var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  834. var __spreadValues = (a, b) => {
  835. for (var prop in b || (b = {}))
  836. if (__hasOwnProp2.call(b, prop))
  837. __defNormalProp(a, prop, b[prop]);
  838. if (__getOwnPropSymbols)
  839. for (var prop of __getOwnPropSymbols(b)) {
  840. if (__propIsEnum.call(b, prop))
  841. __defNormalProp(a, prop, b[prop]);
  842. }
  843. return a;
  844. };
  845. var __accessCheck = (obj, member, msg) => {
  846. if (!member.has(obj))
  847. throw TypeError("Cannot " + msg);
  848. };
  849. var __privateGet = (obj, member, getter) => {
  850. __accessCheck(obj, member, "read from private field");
  851. return getter ? getter.call(obj) : member.get(obj);
  852. };
  853. var __privateAdd = (obj, member, value) => {
  854. if (member.has(obj))
  855. throw TypeError("Cannot add the same private member more than once");
  856. member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
  857. };
  858. var __privateSet = (obj, member, value, setter) => {
  859. __accessCheck(obj, member, "write to private field");
  860. setter ? setter.call(obj, value) : member.set(obj, value);
  861. return value;
  862. };
  863. var __privateMethod = (obj, member, method) => {
  864. __accessCheck(obj, member, "access private method");
  865. return method;
  866. };
  867. var bytes = new Uint8Array(8);
  868. var view = new DataView(bytes.buffer);
  869. var u8 = (value) => {
  870. return [(value % 256 + 256) % 256];
  871. };
  872. var u16 = (value) => {
  873. view.setUint16(0, value, false);
  874. return [bytes[0], bytes[1]];
  875. };
  876. var i16 = (value) => {
  877. view.setInt16(0, value, false);
  878. return [bytes[0], bytes[1]];
  879. };
  880. var u24 = (value) => {
  881. view.setUint32(0, value, false);
  882. return [bytes[1], bytes[2], bytes[3]];
  883. };
  884. var u32 = (value) => {
  885. view.setUint32(0, value, false);
  886. return [bytes[0], bytes[1], bytes[2], bytes[3]];
  887. };
  888. var u64 = (value) => {
  889. view.setUint32(0, Math.floor(value / __pow(2, 32)), false);
  890. view.setUint32(4, value, false);
  891. return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]];
  892. };
  893. var fixed_8_8 = (value) => {
  894. view.setInt16(0, __pow(2, 8) * value, false);
  895. return [bytes[0], bytes[1]];
  896. };
  897. var fixed_16_16 = (value) => {
  898. view.setInt32(0, __pow(2, 16) * value, false);
  899. return [bytes[0], bytes[1], bytes[2], bytes[3]];
  900. };
  901. var fixed_2_30 = (value) => {
  902. view.setInt32(0, __pow(2, 30) * value, false);
  903. return [bytes[0], bytes[1], bytes[2], bytes[3]];
  904. };
  905. var ascii = (text, nullTerminated = false) => {
  906. let bytes2 = Array(text.length).fill(null).map((_, i) => text.charCodeAt(i));
  907. if (nullTerminated)
  908. bytes2.push(0);
  909. return bytes2;
  910. };
  911. var last = (arr) => {
  912. return arr && arr[arr.length - 1];
  913. };
  914. var intoTimescale = (timeInSeconds, timescale, round = true) => {
  915. let value = timeInSeconds * timescale;
  916. return round ? Math.round(value) : value;
  917. };
  918. var rotationMatrix = (rotationInDegrees) => {
  919. let theta = rotationInDegrees * (Math.PI / 180);
  920. let cosTheta = Math.cos(theta);
  921. let sinTheta = Math.sin(theta);
  922. return [
  923. cosTheta,
  924. sinTheta,
  925. 0,
  926. -sinTheta,
  927. cosTheta,
  928. 0,
  929. 0,
  930. 0,
  931. 1
  932. ];
  933. };
  934. var IDENTITY_MATRIX = rotationMatrix(0);
  935. var matrixToBytes = (matrix) => {
  936. return [
  937. fixed_16_16(matrix[0]),
  938. fixed_16_16(matrix[1]),
  939. fixed_2_30(matrix[2]),
  940. fixed_16_16(matrix[3]),
  941. fixed_16_16(matrix[4]),
  942. fixed_2_30(matrix[5]),
  943. fixed_16_16(matrix[6]),
  944. fixed_16_16(matrix[7]),
  945. fixed_2_30(matrix[8])
  946. ];
  947. };
  948. var box = (type, contents, children) => ({
  949. type,
  950. contents: contents && new Uint8Array(contents.flat(10)),
  951. children
  952. });
  953. var fullBox = (type, version, flags, contents, children) => box(
  954. type,
  955. [u8(version), u24(flags), contents != null ? contents : []],
  956. children
  957. );
  958. var ftyp = (holdsHevc) => {
  959. if (holdsHevc)
  960. return box("ftyp", [
  961. ascii("isom"),
  962. // Major brand
  963. u32(0),
  964. // Minor version
  965. ascii("iso4"),
  966. // Compatible brand 1
  967. ascii("hvc1")
  968. // Compatible brand 2
  969. ]);
  970. return box("ftyp", [
  971. ascii("isom"),
  972. // Major brand
  973. u32(0),
  974. // Minor version
  975. ascii("isom"),
  976. // Compatible brand 1
  977. ascii("avc1"),
  978. // Compatible brand 2
  979. ascii("mp41")
  980. // Compatible brand 3
  981. ]);
  982. };
  983. var mdat = () => ({ type: "mdat", largeSize: true });
  984. var moov = (tracks, creationTime) => box("moov", null, [
  985. mvhd(creationTime, tracks),
  986. ...tracks.map((x) => trak(x, creationTime))
  987. ]);
  988. var mvhd = (creationTime, tracks) => {
  989. let duration = intoTimescale(Math.max(
  990. 0,
  991. ...tracks.filter((x) => x.samples.length > 0).map((x) => last(x.samples).timestamp + last(x.samples).duration)
  992. ), GLOBAL_TIMESCALE);
  993. let nextTrackId = Math.max(...tracks.map((x) => x.id)) + 1;
  994. return fullBox("mvhd", 0, 0, [
  995. u32(creationTime),
  996. // Creation time
  997. u32(creationTime),
  998. // Modification time
  999. u32(GLOBAL_TIMESCALE),
  1000. // Timescale
  1001. u32(duration),
  1002. // Duration
  1003. fixed_16_16(1),
  1004. // Preferred rate
  1005. fixed_8_8(1),
  1006. // Preferred volume
  1007. Array(10).fill(0),
  1008. // Reserved
  1009. matrixToBytes(IDENTITY_MATRIX),
  1010. // Matrix
  1011. Array(24).fill(0),
  1012. // Pre-defined
  1013. u32(nextTrackId)
  1014. // Next track ID
  1015. ]);
  1016. };
  1017. var trak = (track, creationTime) => box("trak", null, [
  1018. tkhd(track, creationTime),
  1019. mdia(track, creationTime)
  1020. ]);
  1021. var tkhd = (track, creationTime) => {
  1022. let lastSample = last(track.samples);
  1023. let durationInGlobalTimescale = intoTimescale(
  1024. lastSample ? lastSample.timestamp + lastSample.duration : 0,
  1025. GLOBAL_TIMESCALE
  1026. );
  1027. return fullBox("tkhd", 0, 3, [
  1028. u32(creationTime),
  1029. // Creation time
  1030. u32(creationTime),
  1031. // Modification time
  1032. u32(track.id),
  1033. // Track ID
  1034. u32(0),
  1035. // Reserved
  1036. u32(durationInGlobalTimescale),
  1037. // Duration
  1038. Array(8).fill(0),
  1039. // Reserved
  1040. u16(0),
  1041. // Layer
  1042. u16(0),
  1043. // Alternate group
  1044. fixed_8_8(track.info.type === "audio" ? 1 : 0),
  1045. // Volume
  1046. u16(0),
  1047. // Reserved
  1048. matrixToBytes(rotationMatrix(track.info.type === "video" ? track.info.rotation : 0)),
  1049. // Matrix
  1050. fixed_16_16(track.info.type === "video" ? track.info.width : 0),
  1051. // Track width
  1052. fixed_16_16(track.info.type === "video" ? track.info.height : 0)
  1053. // Track height
  1054. ]);
  1055. };
  1056. var mdia = (track, creationTime) => box("mdia", null, [
  1057. mdhd(track, creationTime),
  1058. hdlr(track.info.type === "video" ? "vide" : "soun"),
  1059. minf(track)
  1060. ]);
  1061. var mdhd = (track, creationTime) => {
  1062. let lastSample = last(track.samples);
  1063. let localDuration = intoTimescale(
  1064. lastSample ? lastSample.timestamp + lastSample.duration : 0,
  1065. track.timescale
  1066. );
  1067. return fullBox("mdhd", 0, 0, [
  1068. u32(creationTime),
  1069. // Creation time
  1070. u32(creationTime),
  1071. // Modification time
  1072. u32(track.timescale),
  1073. // Timescale
  1074. u32(localDuration),
  1075. // Duration
  1076. u16(21956),
  1077. // Language ("und", undetermined)
  1078. u16(0)
  1079. // Quality
  1080. ]);
  1081. };
  1082. var hdlr = (componentSubtype) => fullBox("hdlr", 0, 0, [
  1083. ascii("mhlr"),
  1084. // Component type
  1085. ascii(componentSubtype),
  1086. // Component subtype
  1087. u32(0),
  1088. // Component manufacturer
  1089. u32(0),
  1090. // Component flags
  1091. u32(0),
  1092. // Component flags mask
  1093. ascii("mp4-muxer-hdlr")
  1094. // Component name
  1095. ]);
  1096. var minf = (track) => box("minf", null, [
  1097. track.info.type === "video" ? vmhd() : smhd(),
  1098. dinf(),
  1099. stbl(track)
  1100. ]);
  1101. var vmhd = () => fullBox("vmhd", 0, 1, [
  1102. u16(0),
  1103. // Graphics mode
  1104. u16(0),
  1105. // Opcolor R
  1106. u16(0),
  1107. // Opcolor G
  1108. u16(0)
  1109. // Opcolor B
  1110. ]);
  1111. var smhd = () => fullBox("smhd", 0, 0, [
  1112. u16(0),
  1113. // Balance
  1114. u16(0)
  1115. // Reserved
  1116. ]);
  1117. var dinf = () => box("dinf", null, [
  1118. dref()
  1119. ]);
  1120. var dref = () => fullBox("dref", 0, 0, [
  1121. u32(1)
  1122. // Entry count
  1123. ], [
  1124. url()
  1125. ]);
  1126. var url = () => fullBox("url ", 0, 1);
  1127. var stbl = (track) => box("stbl", null, [
  1128. stsd(track),
  1129. stts(track),
  1130. stss(track),
  1131. stsc(track),
  1132. stsz(track),
  1133. stco(track)
  1134. ]);
  1135. var stsd = (track) => fullBox("stsd", 0, 0, [
  1136. u32(1)
  1137. // Entry count
  1138. ], [
  1139. track.info.type === "video" ? videoSampleDescription(
  1140. VIDEO_CODEC_TO_BOX_NAME[track.info.codec],
  1141. track
  1142. ) : soundSampleDescription(
  1143. AUDIO_CODEC_TO_BOX_NAME[track.info.codec],
  1144. track
  1145. )
  1146. ]);
  1147. var videoSampleDescription = (compressionType, track) => box(compressionType, [
  1148. Array(6).fill(0),
  1149. // Reserved
  1150. u16(1),
  1151. // Data reference index
  1152. u16(0),
  1153. // Pre-defined
  1154. u16(0),
  1155. // Reserved
  1156. Array(12).fill(0),
  1157. // Pre-defined
  1158. u16(track.info.width),
  1159. // Width
  1160. u16(track.info.height),
  1161. // Height
  1162. u32(4718592),
  1163. // Horizontal resolution
  1164. u32(4718592),
  1165. // Vertical resolution
  1166. u32(0),
  1167. // Reserved
  1168. u16(1),
  1169. // Frame count
  1170. Array(32).fill(0),
  1171. // Compressor name
  1172. u16(24),
  1173. // Depth
  1174. i16(65535)
  1175. // Pre-defined
  1176. ], [
  1177. VIDEO_CODEC_TO_CONFIGURATION_BOX[track.info.codec](track)
  1178. ]);
  1179. var avcC = (track) => track.codecPrivate && box("avcC", [...track.codecPrivate]);
  1180. var hvcC = (track) => track.codecPrivate && box("hvcC", [...track.codecPrivate]);
  1181. var vpcC = (track) => track.codecPrivate && box("vpcC", [...track.codecPrivate]);
  1182. var av1C = (track) => track.codecPrivate && box("av1C", [...track.codecPrivate]);
  1183. var soundSampleDescription = (compressionType, track) => box(compressionType, [
  1184. Array(6).fill(0),
  1185. // Reserved
  1186. u16(1),
  1187. // Data reference index
  1188. u16(0),
  1189. // Version
  1190. u16(0),
  1191. // Revision level
  1192. u32(0),
  1193. // Vendor
  1194. u16(track.info.numberOfChannels),
  1195. // Number of channels
  1196. u16(16),
  1197. // Sample size (bits)
  1198. u16(0),
  1199. // Compression ID
  1200. u16(0),
  1201. // Packet size
  1202. fixed_16_16(track.info.sampleRate)
  1203. // Sample rate
  1204. ], [
  1205. AUDIO_CODEC_TO_CONFIGURATION_BOX[track.info.codec](track)
  1206. ]);
  1207. var esds = (track) => fullBox("esds", 0, 0, [
  1208. // https://stackoverflow.com/a/54803118
  1209. u32(58753152),
  1210. // TAG(3) = Object Descriptor ([2])
  1211. u8(32 + track.codecPrivate.byteLength),
  1212. // length of this OD (which includes the next 2 tags)
  1213. u16(1),
  1214. // ES_ID = 1
  1215. u8(0),
  1216. // flags etc = 0
  1217. u32(75530368),
  1218. // TAG(4) = ES Descriptor ([2]) embedded in above OD
  1219. u8(18 + track.codecPrivate.byteLength),
  1220. // length of this ESD
  1221. u8(64),
  1222. // MPEG-4 Audio
  1223. u8(21),
  1224. // stream type(6bits)=5 audio, flags(2bits)=1
  1225. u24(0),
  1226. // 24bit buffer size
  1227. u32(130071),
  1228. // max bitrate
  1229. u32(130071),
  1230. // avg bitrate
  1231. u32(92307584),
  1232. // TAG(5) = ASC ([2],[3]) embedded in above OD
  1233. u8(track.codecPrivate.byteLength),
  1234. // length
  1235. ...track.codecPrivate,
  1236. u32(109084800),
  1237. // TAG(6)
  1238. u8(1),
  1239. // length
  1240. u8(2)
  1241. // data
  1242. ]);
  1243. var dOps = (track) => box("dOps", [
  1244. u8(0),
  1245. // Version
  1246. u8(track.info.numberOfChannels),
  1247. // OutputChannelCount
  1248. u16(3840),
  1249. // PreSkip, should be at least 80 milliseconds worth of playback, measured in 48000 Hz samples
  1250. u32(track.info.sampleRate),
  1251. // InputSampleRate
  1252. fixed_8_8(0),
  1253. // OutputGain
  1254. u8(0)
  1255. // ChannelMappingFamily
  1256. ]);
  1257. var stts = (track) => {
  1258. return fullBox("stts", 0, 0, [
  1259. u32(track.timeToSampleTable.length),
  1260. // Number of entries
  1261. track.timeToSampleTable.map((x) => [
  1262. // Time-to-sample table
  1263. u32(x.sampleCount),
  1264. // Sample count
  1265. u32(x.sampleDelta)
  1266. // Sample duration
  1267. ])
  1268. ]);
  1269. };
  1270. var stss = (track) => {
  1271. if (track.samples.every((x) => x.type === "key"))
  1272. return null;
  1273. let keySamples = [...track.samples.entries()].filter(([, sample]) => sample.type === "key");
  1274. return fullBox("stss", 0, 0, [
  1275. u32(keySamples.length),
  1276. // Number of entries
  1277. keySamples.map(([index]) => u32(index + 1))
  1278. // Sync sample table
  1279. ]);
  1280. };
  1281. var stsc = (track) => {
  1282. return fullBox("stsc", 0, 0, [
  1283. u32(track.compactlyCodedChunkTable.length),
  1284. // Number of entries
  1285. track.compactlyCodedChunkTable.map((x) => [
  1286. // Sample-to-chunk table
  1287. u32(x.firstChunk),
  1288. // First chunk
  1289. u32(x.samplesPerChunk),
  1290. // Samples per chunk
  1291. u32(1)
  1292. // Sample description index
  1293. ])
  1294. ]);
  1295. };
  1296. var stsz = (track) => fullBox("stsz", 0, 0, [
  1297. u32(0),
  1298. // Sample size (0 means non-constant size)
  1299. u32(track.samples.length),
  1300. // Number of entries
  1301. track.samples.map((x) => u32(x.size))
  1302. // Sample size table
  1303. ]);
  1304. var stco = (track) => {
  1305. if (track.writtenChunks.length > 0 && last(track.writtenChunks).offset >= __pow(2, 32)) {
  1306. return fullBox("co64", 0, 0, [
  1307. u32(track.writtenChunks.length),
  1308. // Number of entries
  1309. track.writtenChunks.map((x) => u64(x.offset))
  1310. // Chunk offset table
  1311. ]);
  1312. }
  1313. return fullBox("stco", 0, 0, [
  1314. u32(track.writtenChunks.length),
  1315. // Number of entries
  1316. track.writtenChunks.map((x) => u32(x.offset))
  1317. // Chunk offset table
  1318. ]);
  1319. };
  1320. var VIDEO_CODEC_TO_BOX_NAME = {
  1321. "avc": "avc1",
  1322. "hevc": "hvc1",
  1323. "vp9": "vp09",
  1324. "av1": "av01"
  1325. };
  1326. var VIDEO_CODEC_TO_CONFIGURATION_BOX = {
  1327. "avc": avcC,
  1328. "hevc": hvcC,
  1329. "vp9": vpcC,
  1330. "av1": av1C
  1331. };
  1332. var AUDIO_CODEC_TO_BOX_NAME = {
  1333. "aac": "mp4a",
  1334. "opus": "opus"
  1335. };
  1336. var AUDIO_CODEC_TO_CONFIGURATION_BOX = {
  1337. "aac": esds,
  1338. "opus": dOps
  1339. };
  1340. var ArrayBufferTarget = class {
  1341. constructor() {
  1342. this.buffer = null;
  1343. }
  1344. };
  1345. var StreamTarget = class {
  1346. constructor(onData, onDone, options) {
  1347. this.onData = onData;
  1348. this.onDone = onDone;
  1349. this.options = options;
  1350. }
  1351. };
  1352. var FileSystemWritableFileStreamTarget = class {
  1353. constructor(stream, options) {
  1354. this.stream = stream;
  1355. this.options = options;
  1356. }
  1357. };
  1358. var _helper;
  1359. var _helperView;
  1360. var Writer = class {
  1361. constructor() {
  1362. this.pos = 0;
  1363. __privateAdd(this, _helper, new Uint8Array(8));
  1364. __privateAdd(this, _helperView, new DataView(__privateGet(this, _helper).buffer));
  1365. this.offsets = /* @__PURE__ */ new WeakMap();
  1366. }
  1367. /** Sets the current position for future writes to a new one. */
  1368. seek(newPos) {
  1369. this.pos = newPos;
  1370. }
  1371. writeU32(value) {
  1372. __privateGet(this, _helperView).setUint32(0, value, false);
  1373. this.write(__privateGet(this, _helper).subarray(0, 4));
  1374. }
  1375. writeU64(value) {
  1376. __privateGet(this, _helperView).setUint32(0, Math.floor(value / __pow(2, 32)), false);
  1377. __privateGet(this, _helperView).setUint32(4, value, false);
  1378. this.write(__privateGet(this, _helper).subarray(0, 8));
  1379. }
  1380. writeAscii(text) {
  1381. for (let i = 0; i < text.length; i++) {
  1382. __privateGet(this, _helperView).setUint8(i % 8, text.charCodeAt(i));
  1383. if (i % 8 === 7)
  1384. this.write(__privateGet(this, _helper));
  1385. }
  1386. if (text.length % 8 !== 0) {
  1387. this.write(__privateGet(this, _helper).subarray(0, text.length % 8));
  1388. }
  1389. }
  1390. writeBox(box2) {
  1391. var _a, _b;
  1392. this.offsets.set(box2, this.pos);
  1393. if (box2.contents && !box2.children) {
  1394. this.writeBoxHeader(box2, (_a = box2.size) != null ? _a : box2.contents.byteLength + 8);
  1395. this.write(box2.contents);
  1396. } else {
  1397. let startPos = this.pos;
  1398. this.writeBoxHeader(box2, 0);
  1399. if (box2.contents)
  1400. this.write(box2.contents);
  1401. if (box2.children) {
  1402. for (let child of box2.children)
  1403. if (child)
  1404. this.writeBox(child);
  1405. }
  1406. let endPos = this.pos;
  1407. let size = (_b = box2.size) != null ? _b : endPos - startPos;
  1408. this.seek(startPos);
  1409. this.writeBoxHeader(box2, size);
  1410. this.seek(endPos);
  1411. }
  1412. }
  1413. writeBoxHeader(box2, size) {
  1414. this.writeU32(box2.largeSize ? 1 : size);
  1415. this.writeAscii(box2.type);
  1416. if (box2.largeSize)
  1417. this.writeU64(size);
  1418. }
  1419. patchBox(box2) {
  1420. let endPos = this.pos;
  1421. this.seek(this.offsets.get(box2));
  1422. this.writeBox(box2);
  1423. this.seek(endPos);
  1424. }
  1425. };
  1426. _helper = /* @__PURE__ */ new WeakMap();
  1427. _helperView = /* @__PURE__ */ new WeakMap();
  1428. var _target;
  1429. var _buffer;
  1430. var _bytes;
  1431. var _ensureSize;
  1432. var ensureSize_fn;
  1433. var ArrayBufferTargetWriter = class extends Writer {
  1434. constructor(target) {
  1435. super();
  1436. __privateAdd(this, _ensureSize);
  1437. __privateAdd(this, _target, void 0);
  1438. __privateAdd(this, _buffer, new ArrayBuffer(__pow(2, 16)));
  1439. __privateAdd(this, _bytes, new Uint8Array(__privateGet(this, _buffer)));
  1440. __privateSet(this, _target, target);
  1441. }
  1442. write(data) {
  1443. __privateMethod(this, _ensureSize, ensureSize_fn).call(this, this.pos + data.byteLength);
  1444. __privateGet(this, _bytes).set(data, this.pos);
  1445. this.pos += data.byteLength;
  1446. }
  1447. finalize() {
  1448. __privateMethod(this, _ensureSize, ensureSize_fn).call(this, this.pos);
  1449. __privateGet(this, _target).buffer = __privateGet(this, _buffer).slice(0, this.pos);
  1450. }
  1451. };
  1452. _target = /* @__PURE__ */ new WeakMap();
  1453. _buffer = /* @__PURE__ */ new WeakMap();
  1454. _bytes = /* @__PURE__ */ new WeakMap();
  1455. _ensureSize = /* @__PURE__ */ new WeakSet();
  1456. ensureSize_fn = function(size) {
  1457. let newLength = __privateGet(this, _buffer).byteLength;
  1458. while (newLength < size)
  1459. newLength *= 2;
  1460. if (newLength === __privateGet(this, _buffer).byteLength)
  1461. return;
  1462. let newBuffer = new ArrayBuffer(newLength);
  1463. let newBytes = new Uint8Array(newBuffer);
  1464. newBytes.set(__privateGet(this, _bytes), 0);
  1465. __privateSet(this, _buffer, newBuffer);
  1466. __privateSet(this, _bytes, newBytes);
  1467. };
  1468. var _target2;
  1469. var _sections;
  1470. var StreamTargetWriter = class extends Writer {
  1471. constructor(target) {
  1472. super();
  1473. __privateAdd(this, _target2, void 0);
  1474. __privateAdd(this, _sections, []);
  1475. __privateSet(this, _target2, target);
  1476. }
  1477. write(data) {
  1478. __privateGet(this, _sections).push({
  1479. data: data.slice(),
  1480. start: this.pos
  1481. });
  1482. this.pos += data.byteLength;
  1483. }
  1484. flush() {
  1485. if (__privateGet(this, _sections).length === 0)
  1486. return;
  1487. let chunks = [];
  1488. let sorted = [...__privateGet(this, _sections)].sort((a, b) => a.start - b.start);
  1489. chunks.push({
  1490. start: sorted[0].start,
  1491. size: sorted[0].data.byteLength
  1492. });
  1493. for (let i = 1; i < sorted.length; i++) {
  1494. let lastChunk = chunks[chunks.length - 1];
  1495. let section = sorted[i];
  1496. if (section.start <= lastChunk.start + lastChunk.size) {
  1497. lastChunk.size = Math.max(lastChunk.size, section.start + section.data.byteLength - lastChunk.start);
  1498. } else {
  1499. chunks.push({
  1500. start: section.start,
  1501. size: section.data.byteLength
  1502. });
  1503. }
  1504. }
  1505. for (let chunk of chunks) {
  1506. chunk.data = new Uint8Array(chunk.size);
  1507. for (let section of __privateGet(this, _sections)) {
  1508. if (chunk.start <= section.start && section.start < chunk.start + chunk.size) {
  1509. chunk.data.set(section.data, section.start - chunk.start);
  1510. }
  1511. }
  1512. __privateGet(this, _target2).onData(chunk.data, chunk.start);
  1513. }
  1514. __privateGet(this, _sections).length = 0;
  1515. }
  1516. finalize() {
  1517. var _a, _b;
  1518. (_b = (_a = __privateGet(this, _target2)).onDone) == null ? void 0 : _b.call(_a);
  1519. }
  1520. };
  1521. _target2 = /* @__PURE__ */ new WeakMap();
  1522. _sections = /* @__PURE__ */ new WeakMap();
  1523. var DEFAULT_CHUNK_SIZE = __pow(2, 24);
  1524. var MAX_CHUNKS_AT_ONCE = 2;
  1525. var _target3;
  1526. var _chunkSize;
  1527. var _chunks;
  1528. var _writeDataIntoChunks;
  1529. var writeDataIntoChunks_fn;
  1530. var _insertSectionIntoChunk;
  1531. var insertSectionIntoChunk_fn;
  1532. var _createChunk;
  1533. var createChunk_fn;
  1534. var _flushChunks;
  1535. var flushChunks_fn;
  1536. var ChunkedStreamTargetWriter = class extends Writer {
  1537. constructor(target) {
  1538. var _a, _b;
  1539. super();
  1540. __privateAdd(this, _writeDataIntoChunks);
  1541. __privateAdd(this, _insertSectionIntoChunk);
  1542. __privateAdd(this, _createChunk);
  1543. __privateAdd(this, _flushChunks);
  1544. __privateAdd(this, _target3, void 0);
  1545. __privateAdd(this, _chunkSize, void 0);
  1546. __privateAdd(this, _chunks, []);
  1547. __privateSet(this, _target3, target);
  1548. __privateSet(this, _chunkSize, (_b = (_a = target.options) == null ? void 0 : _a.chunkSize) != null ? _b : DEFAULT_CHUNK_SIZE);
  1549. if (!Number.isInteger(__privateGet(this, _chunkSize)) || __privateGet(this, _chunkSize) < __pow(2, 10)) {
  1550. throw new Error("Invalid StreamTarget options: chunkSize must be an integer not smaller than 1024.");
  1551. }
  1552. }
  1553. write(data) {
  1554. __privateMethod(this, _writeDataIntoChunks, writeDataIntoChunks_fn).call(this, data, this.pos);
  1555. __privateMethod(this, _flushChunks, flushChunks_fn).call(this);
  1556. this.pos += data.byteLength;
  1557. }
  1558. finalize() {
  1559. var _a, _b;
  1560. __privateMethod(this, _flushChunks, flushChunks_fn).call(this, true);
  1561. (_b = (_a = __privateGet(this, _target3)).onDone) == null ? void 0 : _b.call(_a);
  1562. }
  1563. };
  1564. _target3 = /* @__PURE__ */ new WeakMap();
  1565. _chunkSize = /* @__PURE__ */ new WeakMap();
  1566. _chunks = /* @__PURE__ */ new WeakMap();
  1567. _writeDataIntoChunks = /* @__PURE__ */ new WeakSet();
  1568. writeDataIntoChunks_fn = function(data, position) {
  1569. let chunkIndex = __privateGet(this, _chunks).findIndex((x) => x.start <= position && position < x.start + __privateGet(this, _chunkSize));
  1570. if (chunkIndex === -1)
  1571. chunkIndex = __privateMethod(this, _createChunk, createChunk_fn).call(this, position);
  1572. let chunk = __privateGet(this, _chunks)[chunkIndex];
  1573. let relativePosition = position - chunk.start;
  1574. let toWrite = data.subarray(0, Math.min(__privateGet(this, _chunkSize) - relativePosition, data.byteLength));
  1575. chunk.data.set(toWrite, relativePosition);
  1576. let section = {
  1577. start: relativePosition,
  1578. end: relativePosition + toWrite.byteLength
  1579. };
  1580. __privateMethod(this, _insertSectionIntoChunk, insertSectionIntoChunk_fn).call(this, chunk, section);
  1581. if (chunk.written[0].start === 0 && chunk.written[0].end === __privateGet(this, _chunkSize)) {
  1582. chunk.shouldFlush = true;
  1583. }
  1584. if (__privateGet(this, _chunks).length > MAX_CHUNKS_AT_ONCE) {
  1585. for (let i = 0; i < __privateGet(this, _chunks).length - 1; i++) {
  1586. __privateGet(this, _chunks)[i].shouldFlush = true;
  1587. }
  1588. __privateMethod(this, _flushChunks, flushChunks_fn).call(this);
  1589. }
  1590. if (toWrite.byteLength < data.byteLength) {
  1591. __privateMethod(this, _writeDataIntoChunks, writeDataIntoChunks_fn).call(this, data.subarray(toWrite.byteLength), position + toWrite.byteLength);
  1592. }
  1593. };
  1594. _insertSectionIntoChunk = /* @__PURE__ */ new WeakSet();
  1595. insertSectionIntoChunk_fn = function(chunk, section) {
  1596. let low = 0;
  1597. let high = chunk.written.length - 1;
  1598. let index = -1;
  1599. while (low <= high) {
  1600. let mid = Math.floor(low + (high - low + 1) / 2);
  1601. if (chunk.written[mid].start <= section.start) {
  1602. low = mid + 1;
  1603. index = mid;
  1604. } else {
  1605. high = mid - 1;
  1606. }
  1607. }
  1608. chunk.written.splice(index + 1, 0, section);
  1609. if (index === -1 || chunk.written[index].end < section.start)
  1610. index++;
  1611. while (index < chunk.written.length - 1 && chunk.written[index].end >= chunk.written[index + 1].start) {
  1612. chunk.written[index].end = Math.max(chunk.written[index].end, chunk.written[index + 1].end);
  1613. chunk.written.splice(index + 1, 1);
  1614. }
  1615. };
  1616. _createChunk = /* @__PURE__ */ new WeakSet();
  1617. createChunk_fn = function(includesPosition) {
  1618. let start = Math.floor(includesPosition / __privateGet(this, _chunkSize)) * __privateGet(this, _chunkSize);
  1619. let chunk = {
  1620. start,
  1621. data: new Uint8Array(__privateGet(this, _chunkSize)),
  1622. written: [],
  1623. shouldFlush: false
  1624. };
  1625. __privateGet(this, _chunks).push(chunk);
  1626. __privateGet(this, _chunks).sort((a, b) => a.start - b.start);
  1627. return __privateGet(this, _chunks).indexOf(chunk);
  1628. };
  1629. _flushChunks = /* @__PURE__ */ new WeakSet();
  1630. flushChunks_fn = function(force = false) {
  1631. for (let i = 0; i < __privateGet(this, _chunks).length; i++) {
  1632. let chunk = __privateGet(this, _chunks)[i];
  1633. if (!chunk.shouldFlush && !force)
  1634. continue;
  1635. for (let section of chunk.written) {
  1636. __privateGet(this, _target3).onData(
  1637. chunk.data.subarray(section.start, section.end),
  1638. chunk.start + section.start
  1639. );
  1640. }
  1641. __privateGet(this, _chunks).splice(i--, 1);
  1642. }
  1643. };
  1644. var FileSystemWritableFileStreamTargetWriter = class extends ChunkedStreamTargetWriter {
  1645. constructor(target) {
  1646. var _a;
  1647. super(new StreamTarget(
  1648. (data, position) => target.stream.write({
  1649. type: "write",
  1650. data,
  1651. position
  1652. }),
  1653. void 0,
  1654. { chunkSize: (_a = target.options) == null ? void 0 : _a.chunkSize }
  1655. ));
  1656. }
  1657. };
  1658. var GLOBAL_TIMESCALE = 1e3;
  1659. var SUPPORTED_VIDEO_CODECS2 = ["avc", "hevc", "vp9", "av1"];
  1660. var SUPPORTED_AUDIO_CODECS2 = ["aac", "opus"];
  1661. var TIMESTAMP_OFFSET = 2082844800;
  1662. var MAX_CHUNK_DURATION = 0.5;
  1663. var FIRST_TIMESTAMP_BEHAVIORS = ["strict", "offset"];
  1664. var _options;
  1665. var _writer;
  1666. var _mdat;
  1667. var _videoTrack;
  1668. var _audioTrack;
  1669. var _creationTime;
  1670. var _finalized;
  1671. var _validateOptions;
  1672. var validateOptions_fn;
  1673. var _writeHeader;
  1674. var writeHeader_fn;
  1675. var _prepareTracks;
  1676. var prepareTracks_fn;
  1677. var _generateMpeg4AudioSpecificConfig;
  1678. var generateMpeg4AudioSpecificConfig_fn;
  1679. var _addSampleToTrack;
  1680. var addSampleToTrack_fn;
  1681. var _validateTimestamp;
  1682. var validateTimestamp_fn;
  1683. var _writeCurrentChunk;
  1684. var writeCurrentChunk_fn;
  1685. var _maybeFlushStreamingTargetWriter;
  1686. var maybeFlushStreamingTargetWriter_fn;
  1687. var _ensureNotFinalized;
  1688. var ensureNotFinalized_fn;
  1689. var Muxer = class {
  1690. constructor(options) {
  1691. __privateAdd(this, _validateOptions);
  1692. __privateAdd(this, _writeHeader);
  1693. __privateAdd(this, _prepareTracks);
  1694. __privateAdd(this, _generateMpeg4AudioSpecificConfig);
  1695. __privateAdd(this, _addSampleToTrack);
  1696. __privateAdd(this, _validateTimestamp);
  1697. __privateAdd(this, _writeCurrentChunk);
  1698. __privateAdd(this, _maybeFlushStreamingTargetWriter);
  1699. __privateAdd(this, _ensureNotFinalized);
  1700. __privateAdd(this, _options, void 0);
  1701. __privateAdd(this, _writer, void 0);
  1702. __privateAdd(this, _mdat, void 0);
  1703. __privateAdd(this, _videoTrack, null);
  1704. __privateAdd(this, _audioTrack, null);
  1705. __privateAdd(this, _creationTime, Math.floor(Date.now() / 1e3) + TIMESTAMP_OFFSET);
  1706. __privateAdd(this, _finalized, false);
  1707. var _a;
  1708. __privateMethod(this, _validateOptions, validateOptions_fn).call(this, options);
  1709. this.target = options.target;
  1710. __privateSet(this, _options, __spreadValues({
  1711. firstTimestampBehavior: "strict"
  1712. }, options));
  1713. if (options.target instanceof ArrayBufferTarget) {
  1714. __privateSet(this, _writer, new ArrayBufferTargetWriter(options.target));
  1715. } else if (options.target instanceof StreamTarget) {
  1716. __privateSet(this, _writer, ((_a = options.target.options) == null ? void 0 : _a.chunked) ? new ChunkedStreamTargetWriter(options.target) : new StreamTargetWriter(options.target));
  1717. } else if (options.target instanceof FileSystemWritableFileStreamTarget) {
  1718. __privateSet(this, _writer, new FileSystemWritableFileStreamTargetWriter(options.target));
  1719. } else {
  1720. throw new Error(`Invalid target: ${options.target}`);
  1721. }
  1722. __privateMethod(this, _writeHeader, writeHeader_fn).call(this);
  1723. __privateMethod(this, _prepareTracks, prepareTracks_fn).call(this);
  1724. }
  1725. addVideoChunk(sample, meta, timestamp) {
  1726. let data = new Uint8Array(sample.byteLength);
  1727. sample.copyTo(data);
  1728. this.addVideoChunkRaw(data, sample.type, timestamp != null ? timestamp : sample.timestamp, sample.duration, meta);
  1729. }
  1730. addVideoChunkRaw(data, type, timestamp, duration, meta) {
  1731. __privateMethod(this, _ensureNotFinalized, ensureNotFinalized_fn).call(this);
  1732. if (!__privateGet(this, _options).video)
  1733. throw new Error("No video track declared.");
  1734. __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _videoTrack), data, type, timestamp, duration, meta);
  1735. }
  1736. addAudioChunk(sample, meta, timestamp) {
  1737. let data = new Uint8Array(sample.byteLength);
  1738. sample.copyTo(data);
  1739. this.addAudioChunkRaw(data, sample.type, timestamp != null ? timestamp : sample.timestamp, sample.duration, meta);
  1740. }
  1741. addAudioChunkRaw(data, type, timestamp, duration, meta) {
  1742. __privateMethod(this, _ensureNotFinalized, ensureNotFinalized_fn).call(this);
  1743. if (!__privateGet(this, _options).audio)
  1744. throw new Error("No audio track declared.");
  1745. __privateMethod(this, _addSampleToTrack, addSampleToTrack_fn).call(this, __privateGet(this, _audioTrack), data, type, timestamp, duration, meta);
  1746. }
  1747. /** Finalizes the file, making it ready for use. Must be called after all video and audio chunks have been added. */
  1748. finalize() {
  1749. if (__privateGet(this, _videoTrack))
  1750. __privateMethod(this, _writeCurrentChunk, writeCurrentChunk_fn).call(this, __privateGet(this, _videoTrack));
  1751. if (__privateGet(this, _audioTrack))
  1752. __privateMethod(this, _writeCurrentChunk, writeCurrentChunk_fn).call(this, __privateGet(this, _audioTrack));
  1753. let mdatPos = __privateGet(this, _writer).offsets.get(__privateGet(this, _mdat));
  1754. let mdatSize = __privateGet(this, _writer).pos - mdatPos;
  1755. __privateGet(this, _mdat).size = mdatSize;
  1756. __privateGet(this, _writer).patchBox(__privateGet(this, _mdat));
  1757. let movieBox = moov([__privateGet(this, _videoTrack), __privateGet(this, _audioTrack)].filter(Boolean), __privateGet(this, _creationTime));
  1758. __privateGet(this, _writer).writeBox(movieBox);
  1759. __privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);
  1760. __privateGet(this, _writer).finalize();
  1761. __privateSet(this, _finalized, true);
  1762. }
  1763. };
  1764. _options = /* @__PURE__ */ new WeakMap();
  1765. _writer = /* @__PURE__ */ new WeakMap();
  1766. _mdat = /* @__PURE__ */ new WeakMap();
  1767. _videoTrack = /* @__PURE__ */ new WeakMap();
  1768. _audioTrack = /* @__PURE__ */ new WeakMap();
  1769. _creationTime = /* @__PURE__ */ new WeakMap();
  1770. _finalized = /* @__PURE__ */ new WeakMap();
  1771. _validateOptions = /* @__PURE__ */ new WeakSet();
  1772. validateOptions_fn = function(options) {
  1773. if (options.video) {
  1774. if (!SUPPORTED_VIDEO_CODECS2.includes(options.video.codec)) {
  1775. throw new Error(`Unsupported video codec: ${options.video.codec}`);
  1776. }
  1777. if (options.video.rotation !== void 0 && ![0, 90, 180, 270].includes(options.video.rotation)) {
  1778. throw new Error(`Invalid video rotation: ${options.video.rotation}. Has to be 0, 90, 180 or 270.`);
  1779. }
  1780. }
  1781. if (options.audio && !SUPPORTED_AUDIO_CODECS2.includes(options.audio.codec)) {
  1782. throw new Error(`Unsupported audio codec: ${options.audio.codec}`);
  1783. }
  1784. if (options.firstTimestampBehavior && !FIRST_TIMESTAMP_BEHAVIORS.includes(options.firstTimestampBehavior)) {
  1785. throw new Error(`Invalid first timestamp behavior: ${options.firstTimestampBehavior}`);
  1786. }
  1787. };
  1788. _writeHeader = /* @__PURE__ */ new WeakSet();
  1789. writeHeader_fn = function() {
  1790. var _a;
  1791. let holdsHevc = ((_a = __privateGet(this, _options).video) == null ? void 0 : _a.codec) === "hevc";
  1792. __privateGet(this, _writer).writeBox(ftyp(holdsHevc));
  1793. __privateSet(this, _mdat, mdat());
  1794. __privateGet(this, _writer).writeBox(__privateGet(this, _mdat));
  1795. __privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);
  1796. };
  1797. _prepareTracks = /* @__PURE__ */ new WeakSet();
  1798. prepareTracks_fn = function() {
  1799. var _a;
  1800. if (__privateGet(this, _options).video) {
  1801. __privateSet(this, _videoTrack, {
  1802. id: 1,
  1803. info: {
  1804. type: "video",
  1805. codec: __privateGet(this, _options).video.codec,
  1806. width: __privateGet(this, _options).video.width,
  1807. height: __privateGet(this, _options).video.height,
  1808. rotation: (_a = __privateGet(this, _options).video.rotation) != null ? _a : 0
  1809. },
  1810. timescale: 720,
  1811. // = lcm(24, 30, 60, 120, 144, 240, 360), so should fit with many framerates
  1812. codecPrivate: new Uint8Array(0),
  1813. samples: [],
  1814. writtenChunks: [],
  1815. currentChunk: null,
  1816. firstTimestamp: void 0,
  1817. lastTimestamp: -1,
  1818. timeToSampleTable: [],
  1819. lastTimescaleUnits: null,
  1820. compactlyCodedChunkTable: []
  1821. });
  1822. }
  1823. if (__privateGet(this, _options).audio) {
  1824. let guessedCodecPrivate = __privateMethod(this, _generateMpeg4AudioSpecificConfig, generateMpeg4AudioSpecificConfig_fn).call(
  1825. this,
  1826. 2,
  1827. // Object type for AAC-LC, since it's the most common
  1828. __privateGet(this, _options).audio.sampleRate,
  1829. __privateGet(this, _options).audio.numberOfChannels
  1830. );
  1831. __privateSet(this, _audioTrack, {
  1832. id: __privateGet(this, _options).video ? 2 : 1,
  1833. info: {
  1834. type: "audio",
  1835. codec: __privateGet(this, _options).audio.codec,
  1836. numberOfChannels: __privateGet(this, _options).audio.numberOfChannels,
  1837. sampleRate: __privateGet(this, _options).audio.sampleRate
  1838. },
  1839. timescale: __privateGet(this, _options).audio.sampleRate,
  1840. codecPrivate: guessedCodecPrivate,
  1841. samples: [],
  1842. writtenChunks: [],
  1843. currentChunk: null,
  1844. firstTimestamp: void 0,
  1845. lastTimestamp: -1,
  1846. timeToSampleTable: [],
  1847. lastTimescaleUnits: null,
  1848. compactlyCodedChunkTable: []
  1849. });
  1850. }
  1851. };
  1852. _generateMpeg4AudioSpecificConfig = /* @__PURE__ */ new WeakSet();
  1853. generateMpeg4AudioSpecificConfig_fn = function(objectType, sampleRate, numberOfChannels) {
  1854. let frequencyIndices = [96e3, 88200, 64e3, 48e3, 44100, 32e3, 24e3, 22050, 16e3, 12e3, 11025, 8e3, 7350];
  1855. let frequencyIndex = frequencyIndices.indexOf(sampleRate);
  1856. let channelConfig = numberOfChannels;
  1857. let configBits = "";
  1858. configBits += objectType.toString(2).padStart(5, "0");
  1859. configBits += frequencyIndex.toString(2).padStart(4, "0");
  1860. if (frequencyIndex === 15)
  1861. configBits += sampleRate.toString(2).padStart(24, "0");
  1862. configBits += channelConfig.toString(2).padStart(4, "0");
  1863. let paddingLength = Math.ceil(configBits.length / 8) * 8;
  1864. configBits = configBits.padEnd(paddingLength, "0");
  1865. let configBytes = new Uint8Array(configBits.length / 8);
  1866. for (let i = 0; i < configBits.length; i += 8) {
  1867. configBytes[i / 8] = parseInt(configBits.slice(i, i + 8), 2);
  1868. }
  1869. return configBytes;
  1870. };
  1871. _addSampleToTrack = /* @__PURE__ */ new WeakSet();
  1872. addSampleToTrack_fn = function(track, data, type, timestamp, duration, meta) {
  1873. var _a;
  1874. let timestampInSeconds = timestamp / 1e6;
  1875. let durationInSeconds = duration / 1e6;
  1876. if (track.firstTimestamp === void 0)
  1877. track.firstTimestamp = timestampInSeconds;
  1878. timestampInSeconds = __privateMethod(this, _validateTimestamp, validateTimestamp_fn).call(this, timestampInSeconds, track);
  1879. track.lastTimestamp = timestampInSeconds;
  1880. if (!track.currentChunk || timestampInSeconds - track.currentChunk.startTimestamp >= MAX_CHUNK_DURATION) {
  1881. if (track.currentChunk)
  1882. __privateMethod(this, _writeCurrentChunk, writeCurrentChunk_fn).call(this, track);
  1883. track.currentChunk = {
  1884. startTimestamp: timestampInSeconds,
  1885. sampleData: [],
  1886. sampleCount: 0
  1887. };
  1888. }
  1889. track.currentChunk.sampleData.push(data);
  1890. track.currentChunk.sampleCount++;
  1891. if ((_a = meta == null ? void 0 : meta.decoderConfig) == null ? void 0 : _a.description) {
  1892. track.codecPrivate = new Uint8Array(meta.decoderConfig.description);
  1893. }
  1894. track.samples.push({
  1895. timestamp: timestampInSeconds,
  1896. duration: durationInSeconds,
  1897. size: data.byteLength,
  1898. type
  1899. });
  1900. if (track.lastTimescaleUnits !== null) {
  1901. let timescaleUnits = intoTimescale(timestampInSeconds, track.timescale, false);
  1902. let delta = Math.round(timescaleUnits - track.lastTimescaleUnits);
  1903. track.lastTimescaleUnits += delta;
  1904. let lastTableEntry = last(track.timeToSampleTable);
  1905. if (lastTableEntry.sampleCount === 1) {
  1906. lastTableEntry.sampleDelta = delta;
  1907. lastTableEntry.sampleCount++;
  1908. } else if (lastTableEntry.sampleDelta === delta) {
  1909. lastTableEntry.sampleCount++;
  1910. } else {
  1911. lastTableEntry.sampleCount--;
  1912. track.timeToSampleTable.push({
  1913. sampleCount: 2,
  1914. sampleDelta: delta
  1915. });
  1916. }
  1917. } else {
  1918. track.lastTimescaleUnits = 0;
  1919. track.timeToSampleTable.push({
  1920. sampleCount: 1,
  1921. sampleDelta: intoTimescale(durationInSeconds, track.timescale)
  1922. });
  1923. }
  1924. };
  1925. _validateTimestamp = /* @__PURE__ */ new WeakSet();
  1926. validateTimestamp_fn = function(timestamp, track) {
  1927. if (__privateGet(this, _options).firstTimestampBehavior === "strict" && track.lastTimestamp === -1 && timestamp !== 0) {
  1928. throw new Error(
  1929. `The first chunk for your media track must have a timestamp of 0 (received ${timestamp}). Non-zero first timestamps are often caused by directly piping frames or audio data from a MediaStreamTrack into the encoder. Their timestamps are typically relative to the age of the document, which is probably what you want.
  1930. If you want to offset all timestamps of a track such that the first one is zero, set firstTimestampBehavior: 'offset' in the options.
  1931. `
  1932. );
  1933. } else if (__privateGet(this, _options).firstTimestampBehavior === "offset") {
  1934. timestamp -= track.firstTimestamp;
  1935. }
  1936. if (timestamp < track.lastTimestamp) {
  1937. throw new Error(
  1938. `Timestamps must be monotonically increasing (went from ${track.lastTimestamp * 1e6} to ${timestamp * 1e6}).`
  1939. );
  1940. }
  1941. return timestamp;
  1942. };
  1943. _writeCurrentChunk = /* @__PURE__ */ new WeakSet();
  1944. writeCurrentChunk_fn = function(track) {
  1945. if (!track.currentChunk)
  1946. return;
  1947. track.currentChunk.offset = __privateGet(this, _writer).pos;
  1948. for (let bytes2 of track.currentChunk.sampleData)
  1949. __privateGet(this, _writer).write(bytes2);
  1950. track.currentChunk.sampleData = null;
  1951. if (track.compactlyCodedChunkTable.length === 0 || last(track.compactlyCodedChunkTable).samplesPerChunk !== track.currentChunk.sampleCount) {
  1952. track.compactlyCodedChunkTable.push({
  1953. firstChunk: track.writtenChunks.length + 1,
  1954. // 1-indexed
  1955. samplesPerChunk: track.currentChunk.sampleCount
  1956. });
  1957. }
  1958. track.writtenChunks.push(track.currentChunk);
  1959. __privateMethod(this, _maybeFlushStreamingTargetWriter, maybeFlushStreamingTargetWriter_fn).call(this);
  1960. };
  1961. _maybeFlushStreamingTargetWriter = /* @__PURE__ */ new WeakSet();
  1962. maybeFlushStreamingTargetWriter_fn = function() {
  1963. if (__privateGet(this, _writer) instanceof StreamTargetWriter) {
  1964. __privateGet(this, _writer).flush();
  1965. }
  1966. };
  1967. _ensureNotFinalized = /* @__PURE__ */ new WeakSet();
  1968. ensureNotFinalized_fn = function() {
  1969. if (__privateGet(this, _finalized)) {
  1970. throw new Error("Cannot add new video or audio chunks after the file has been finalized.");
  1971. }
  1972. };
  1973. // src/muxers/mp4muxer.ts
  1974. var Mp4MuxerWrapper = class {
  1975. constructor(config, postMessageCallback, options) {
  1976. this.videoConfigured = false;
  1977. this.audioConfigured = false;
  1978. this.firstAudioTimestamp = null;
  1979. this.firstVideoTimestamp = null;
  1980. this.firstTimestamp = null;
  1981. this.config = config;
  1982. this.postMessageToMain = postMessageCallback;
  1983. let disableAudio = options?.disableAudio ?? false;
  1984. const videoDisabled = config.width <= 0 || config.height <= 0 || config.videoBitrate <= 0;
  1985. const audioCodecOption = config.codec?.audio ?? "aac";
  1986. const supportedAudioCodecsForMp4 = /* @__PURE__ */ new Set(["aac", "mp3"]);
  1987. if (!supportedAudioCodecsForMp4.has(audioCodecOption)) {
  1988. console.warn(
  1989. `MP4 muxer: Audio codec ${audioCodecOption} is not supported. Disabling audio track.`
  1990. );
  1991. disableAudio = true;
  1992. }
  1993. const muxerAudioCodec = audioCodecOption;
  1994. const commonMuxerOptions = {};
  1995. if (!videoDisabled) {
  1996. const videoCodecOption = config.codec?.video ?? "avc";
  1997. let muxerVideoCodec;
  1998. switch (videoCodecOption) {
  1999. case "hevc":
  2000. muxerVideoCodec = "hevc";
  2001. break;
  2002. case "vp9":
  2003. muxerVideoCodec = "vp9";
  2004. break;
  2005. case "av1":
  2006. muxerVideoCodec = "av1";
  2007. break;
  2008. case "avc":
  2009. default:
  2010. muxerVideoCodec = "avc";
  2011. break;
  2012. }
  2013. commonMuxerOptions.video = {
  2014. codec: muxerVideoCodec,
  2015. width: config.width,
  2016. height: config.height
  2017. // framerate is not directly a muxer option here, but good to have in config
  2018. };
  2019. }
  2020. if (!disableAudio) {
  2021. commonMuxerOptions.audio = {
  2022. codec: muxerAudioCodec,
  2023. sampleRate: config.sampleRate,
  2024. numberOfChannels: config.channels
  2025. };
  2026. }
  2027. if (config.latencyMode === "realtime") {
  2028. this.target = new StreamTarget({
  2029. onData: (chunk, position) => {
  2030. const chunkCopy = new Uint8Array(chunk.slice(0));
  2031. const isHeader = position === 0;
  2032. const message = {
  2033. type: "dataChunk",
  2034. chunk: chunkCopy,
  2035. offset: position,
  2036. // Use position as offset
  2037. isHeader,
  2038. container: "mp4"
  2039. };
  2040. this.postMessageToMain(message, [chunkCopy.buffer]);
  2041. }
  2042. });
  2043. this.muxer = new Muxer({
  2044. target: this.target,
  2045. ...commonMuxerOptions,
  2046. fastStart: "fragmented"
  2047. });
  2048. } else {
  2049. this.target = new ArrayBufferTarget();
  2050. this.muxer = new Muxer({
  2051. target: this.target,
  2052. ...commonMuxerOptions,
  2053. fastStart: "in-memory"
  2054. // or false, depending on desired behavior for non-realtime
  2055. });
  2056. }
  2057. this.videoConfigured = !videoDisabled;
  2058. this.audioConfigured = !disableAudio;
  2059. }
  2060. addVideoChunk(chunk, meta) {
  2061. if (!this.videoConfigured) {
  2062. this.postMessageToMain({
  2063. type: "error",
  2064. errorDetail: {
  2065. message: "MP4: Video track not configured.",
  2066. type: "configuration-error" /* ConfigurationError */
  2067. }
  2068. });
  2069. return;
  2070. }
  2071. try {
  2072. let adjustedChunk = chunk;
  2073. const adjustedMeta = meta;
  2074. if (this.config.firstTimestampBehavior === "offset" && typeof chunk.timestamp === "number") {
  2075. if (this.firstVideoTimestamp === null) {
  2076. this.firstVideoTimestamp = chunk.timestamp;
  2077. if (this.firstTimestamp === null) {
  2078. this.firstTimestamp = chunk.timestamp;
  2079. } else {
  2080. this.firstTimestamp = Math.min(
  2081. this.firstTimestamp,
  2082. chunk.timestamp
  2083. );
  2084. }
  2085. }
  2086. const newTimestamp = Math.max(
  2087. 0,
  2088. chunk.timestamp - (this.firstTimestamp || 0)
  2089. );
  2090. const data = new Uint8Array(chunk.byteLength);
  2091. chunk.copyTo(data.buffer);
  2092. chunk.close?.();
  2093. adjustedChunk = new EncodedVideoChunk({
  2094. type: chunk.type,
  2095. timestamp: newTimestamp,
  2096. duration: chunk.duration ?? void 0,
  2097. data: data.buffer
  2098. });
  2099. } else if (typeof chunk.timestamp !== "number" && this.config.firstTimestampBehavior === "offset") {
  2100. }
  2101. this.muxer.addVideoChunk(adjustedChunk, adjustedMeta);
  2102. } catch (e) {
  2103. this.postMessageToMain({
  2104. type: "error",
  2105. errorDetail: {
  2106. message: `MP4: Error adding video chunk: ${e.message}`,
  2107. type: "muxing-failed" /* MuxingFailed */,
  2108. stack: e.stack
  2109. }
  2110. });
  2111. }
  2112. }
  2113. addAudioChunk(chunk, meta) {
  2114. if (!this.audioConfigured) {
  2115. return;
  2116. }
  2117. try {
  2118. let adjustedChunk = chunk;
  2119. const adjustedMeta = meta;
  2120. if (this.config.firstTimestampBehavior === "offset" && typeof chunk.timestamp === "number") {
  2121. if (this.firstAudioTimestamp === null) {
  2122. this.firstAudioTimestamp = chunk.timestamp;
  2123. if (this.firstTimestamp === null) {
  2124. this.firstTimestamp = chunk.timestamp;
  2125. } else {
  2126. this.firstTimestamp = Math.min(
  2127. this.firstTimestamp,
  2128. chunk.timestamp
  2129. );
  2130. }
  2131. }
  2132. const newTimestamp = Math.max(
  2133. 0,
  2134. chunk.timestamp - (this.firstTimestamp || 0)
  2135. );
  2136. const data = new Uint8Array(chunk.byteLength);
  2137. chunk.copyTo(data.buffer);
  2138. chunk.close?.();
  2139. adjustedChunk = new EncodedAudioChunk({
  2140. type: chunk.type,
  2141. timestamp: newTimestamp,
  2142. duration: chunk.duration ?? void 0,
  2143. data: data.buffer
  2144. });
  2145. } else if (typeof chunk.timestamp !== "number" && this.config.firstTimestampBehavior === "offset") {
  2146. }
  2147. this.muxer.addAudioChunk(adjustedChunk, adjustedMeta);
  2148. } catch (e) {
  2149. this.postMessageToMain({
  2150. type: "error",
  2151. errorDetail: {
  2152. message: `MP4: Error adding audio chunk: ${e.message}`,
  2153. type: "muxing-failed" /* MuxingFailed */,
  2154. stack: e.stack
  2155. }
  2156. });
  2157. }
  2158. }
  2159. finalize() {
  2160. if (this.config.latencyMode === "realtime") {
  2161. try {
  2162. this.muxer.finalize();
  2163. } catch (e) {
  2164. this.postMessageToMain({
  2165. type: "error",
  2166. errorDetail: {
  2167. message: `MP4: Error finalizing muxer (realtime): ${e.message}`,
  2168. type: "muxing-failed" /* MuxingFailed */,
  2169. stack: e.stack
  2170. }
  2171. });
  2172. }
  2173. return null;
  2174. }
  2175. if (!(this.target instanceof ArrayBufferTarget)) {
  2176. this.postMessageToMain({
  2177. type: "error",
  2178. errorDetail: {
  2179. message: "MP4: Muxer target is not ArrayBufferTarget in non-realtime mode.",
  2180. type: "unknown" /* Unknown */
  2181. }
  2182. });
  2183. return null;
  2184. }
  2185. try {
  2186. this.muxer.finalize();
  2187. const buffer = this.target.buffer;
  2188. this.target = new ArrayBufferTarget();
  2189. return new Uint8Array(buffer);
  2190. } catch (e) {
  2191. this.postMessageToMain({
  2192. type: "error",
  2193. errorDetail: {
  2194. message: `MP4: Error finalizing muxer (non-realtime): ${e.message}`,
  2195. type: "muxing-failed" /* MuxingFailed */,
  2196. stack: e.stack
  2197. }
  2198. });
  2199. return null;
  2200. }
  2201. }
  2202. };
  2203. // src/muxers/webmmuxer.ts
  2204. var import_webm_muxer = __toESM(require_webm_muxer(), 1);
  2205. var CallbackWritableStream = class {
  2206. constructor(onData) {
  2207. this.onData = onData;
  2208. this.position = 0;
  2209. }
  2210. write({ data, position }) {
  2211. this.onData(data, position);
  2212. this.position = position + data.byteLength;
  2213. }
  2214. };
  2215. var WebMMuxerWrapper = class {
  2216. constructor(config, postMessageCallback, options) {
  2217. this.videoConfigured = false;
  2218. this.audioConfigured = false;
  2219. this.firstAudioTimestamp = null;
  2220. this.firstVideoTimestamp = null;
  2221. this.firstTimestamp = null;
  2222. this.config = config;
  2223. this.postMessageToMain = postMessageCallback;
  2224. let disableAudio = options?.disableAudio ?? false;
  2225. const videoCodecOption = config.codec?.video ?? "vp9";
  2226. let muxerVideoCodec;
  2227. switch (videoCodecOption) {
  2228. case "vp8":
  2229. muxerVideoCodec = "V_VP8";
  2230. break;
  2231. case "vp9":
  2232. muxerVideoCodec = "V_VP9";
  2233. break;
  2234. case "av1":
  2235. muxerVideoCodec = "V_AV1";
  2236. break;
  2237. default:
  2238. muxerVideoCodec = "V_VP9";
  2239. break;
  2240. }
  2241. const requestedAudioCodec = config.codec?.audio ?? "opus";
  2242. let muxerAudioCodec = null;
  2243. switch (requestedAudioCodec) {
  2244. case "opus":
  2245. muxerAudioCodec = "A_OPUS";
  2246. break;
  2247. case "vorbis":
  2248. muxerAudioCodec = "A_VORBIS";
  2249. break;
  2250. case "flac":
  2251. muxerAudioCodec = "A_FLAC";
  2252. break;
  2253. default:
  2254. if (!disableAudio) {
  2255. console.warn(
  2256. `WebM muxer: Audio codec ${requestedAudioCodec} is not supported. Disabling audio track.`
  2257. );
  2258. disableAudio = true;
  2259. }
  2260. break;
  2261. }
  2262. const target = config.latencyMode === "realtime" ? new CallbackWritableStream((chunk, position) => {
  2263. const chunkCopy = new Uint8Array(chunk.slice(0));
  2264. const isHeader = position === 0;
  2265. const message = {
  2266. type: "dataChunk",
  2267. chunk: chunkCopy,
  2268. offset: position,
  2269. isHeader,
  2270. container: "webm"
  2271. };
  2272. this.postMessageToMain(message, [chunkCopy.buffer]);
  2273. }) : "buffer";
  2274. const videoDisabled = config.width === 0 || config.height === 0 || config.videoBitrate === 0;
  2275. const optionsForMuxer = {
  2276. target
  2277. };
  2278. if (!videoDisabled) {
  2279. optionsForMuxer.video = {
  2280. codec: muxerVideoCodec,
  2281. width: config.width,
  2282. height: config.height,
  2283. frameRate: config.frameRate
  2284. };
  2285. }
  2286. if (!disableAudio && muxerAudioCodec) {
  2287. optionsForMuxer.audio = {
  2288. codec: muxerAudioCodec,
  2289. numberOfChannels: config.channels,
  2290. sampleRate: config.sampleRate
  2291. };
  2292. }
  2293. this.muxer = new import_webm_muxer.default(optionsForMuxer);
  2294. this.videoConfigured = !videoDisabled;
  2295. this.audioConfigured = !disableAudio;
  2296. }
  2297. addVideoChunk(chunk, meta) {
  2298. if (!this.videoConfigured) {
  2299. this.postMessageToMain({
  2300. type: "error",
  2301. errorDetail: {
  2302. message: "WebM: Video track not configured.",
  2303. type: "configuration-error" /* ConfigurationError */
  2304. }
  2305. });
  2306. return;
  2307. }
  2308. try {
  2309. let adjustedChunk = chunk;
  2310. const adjustedMeta = meta;
  2311. if (this.config.firstTimestampBehavior === "offset" && typeof chunk.timestamp === "number") {
  2312. if (this.firstVideoTimestamp === null) {
  2313. this.firstVideoTimestamp = chunk.timestamp;
  2314. if (this.firstTimestamp === null) {
  2315. this.firstTimestamp = chunk.timestamp;
  2316. } else {
  2317. this.firstTimestamp = Math.min(
  2318. this.firstTimestamp,
  2319. chunk.timestamp
  2320. );
  2321. }
  2322. }
  2323. const newTimestamp = Math.max(
  2324. 0,
  2325. chunk.timestamp - (this.firstTimestamp || 0)
  2326. );
  2327. const data = new Uint8Array(chunk.byteLength);
  2328. chunk.copyTo(data.buffer);
  2329. chunk.close?.();
  2330. adjustedChunk = new EncodedVideoChunk({
  2331. type: chunk.type,
  2332. timestamp: newTimestamp,
  2333. duration: chunk.duration ?? void 0,
  2334. data: data.buffer
  2335. });
  2336. }
  2337. this.muxer.addVideoChunk(adjustedChunk, adjustedMeta);
  2338. } catch (e) {
  2339. this.postMessageToMain({
  2340. type: "error",
  2341. errorDetail: {
  2342. message: `WebM: Error adding video chunk: ${e.message}`,
  2343. type: "muxing-failed" /* MuxingFailed */,
  2344. stack: e.stack
  2345. }
  2346. });
  2347. }
  2348. }
  2349. addAudioChunk(chunk, meta) {
  2350. if (!this.audioConfigured) return;
  2351. try {
  2352. let adjustedChunk = chunk;
  2353. const adjustedMeta = meta;
  2354. if (this.config.firstTimestampBehavior === "offset" && typeof chunk.timestamp === "number") {
  2355. if (this.firstAudioTimestamp === null) {
  2356. this.firstAudioTimestamp = chunk.timestamp;
  2357. if (this.firstTimestamp === null) {
  2358. this.firstTimestamp = chunk.timestamp;
  2359. } else {
  2360. this.firstTimestamp = Math.min(
  2361. this.firstTimestamp,
  2362. chunk.timestamp
  2363. );
  2364. }
  2365. }
  2366. const newTimestamp = Math.max(
  2367. 0,
  2368. chunk.timestamp - (this.firstTimestamp || 0)
  2369. );
  2370. const data = new Uint8Array(chunk.byteLength);
  2371. chunk.copyTo(data.buffer);
  2372. chunk.close?.();
  2373. adjustedChunk = new EncodedAudioChunk({
  2374. type: chunk.type,
  2375. timestamp: newTimestamp,
  2376. duration: chunk.duration ?? void 0,
  2377. data: data.buffer
  2378. });
  2379. }
  2380. this.muxer.addAudioChunk(adjustedChunk, adjustedMeta);
  2381. } catch (e) {
  2382. this.postMessageToMain({
  2383. type: "error",
  2384. errorDetail: {
  2385. message: `WebM: Error adding audio chunk: ${e.message}`,
  2386. type: "muxing-failed" /* MuxingFailed */,
  2387. stack: e.stack
  2388. }
  2389. });
  2390. }
  2391. }
  2392. finalize() {
  2393. if (this.config.latencyMode === "realtime") {
  2394. try {
  2395. this.muxer.finalize();
  2396. } catch (e) {
  2397. this.postMessageToMain({
  2398. type: "error",
  2399. errorDetail: {
  2400. message: `WebM: Error finalizing muxer (realtime): ${e.message}`,
  2401. type: "muxing-failed" /* MuxingFailed */,
  2402. stack: e.stack
  2403. }
  2404. });
  2405. }
  2406. return null;
  2407. }
  2408. try {
  2409. const buffer = this.muxer.finalize();
  2410. if (buffer) return new Uint8Array(buffer);
  2411. this.postMessageToMain({
  2412. type: "error",
  2413. errorDetail: {
  2414. message: "WebM: Muxer finalized without output in non-realtime mode.",
  2415. type: "muxing-failed" /* MuxingFailed */
  2416. }
  2417. });
  2418. return null;
  2419. } catch (e) {
  2420. this.postMessageToMain({
  2421. type: "error",
  2422. errorDetail: {
  2423. message: `WebM: Error finalizing muxer (non-realtime): ${e.message}`,
  2424. type: "muxing-failed" /* MuxingFailed */,
  2425. stack: e.stack
  2426. }
  2427. });
  2428. return null;
  2429. }
  2430. }
  2431. };
  2432. // src/worker/encoder-worker.ts
  2433. if (typeof self !== "undefined" && typeof self.addEventListener === "function") {
  2434. self.addEventListener("error", (event) => {
  2435. console.error("Unhandled global error in worker. Event:", event);
  2436. const message = event.message || `Unhandled global error${event.filename ? ` at ${event.filename}` : ""}`;
  2437. self.postMessage({
  2438. type: "error",
  2439. errorDetail: {
  2440. message,
  2441. type: "worker-error" /* WorkerError */,
  2442. stack: event.error?.stack
  2443. }
  2444. });
  2445. });
  2446. }
  2447. if (typeof self !== "undefined" && typeof self.addEventListener === "function") {
  2448. self.addEventListener(
  2449. "unhandledrejection",
  2450. (event) => {
  2451. console.error(
  2452. "Unhandled promise rejection in worker. Reason:",
  2453. event.reason
  2454. );
  2455. const reason = event.reason;
  2456. const message = reason instanceof Error ? `Unhandled promise rejection: ${reason.message}` : `Unhandled promise rejection: ${String(reason)}`;
  2457. self.postMessage({
  2458. type: "error",
  2459. errorDetail: {
  2460. message,
  2461. type: "worker-error" /* WorkerError */,
  2462. stack: reason instanceof Error ? reason.stack : void 0
  2463. }
  2464. });
  2465. }
  2466. );
  2467. }
  2468. var getVideoEncoder = () => self.VideoEncoder ?? globalThis.VideoEncoder;
  2469. var getAudioEncoder = () => self.AudioEncoder ?? globalThis.AudioEncoder;
  2470. var getAudioData = () => self.AudioData ?? globalThis.AudioData;
  2471. var EncoderWorker = class {
  2472. constructor() {
  2473. this.videoEncoder = null;
  2474. this.audioEncoder = null;
  2475. this.muxer = null;
  2476. this.currentConfig = null;
  2477. this.processedFrames = 0;
  2478. this.videoFrameCount = 0;
  2479. this.isCancelled = false;
  2480. }
  2481. postMessageToMainThread(message, transfer) {
  2482. if (transfer && transfer.length > 0) {
  2483. self.postMessage(message, transfer);
  2484. } else {
  2485. self.postMessage(message);
  2486. }
  2487. }
  2488. defaultAvcCodecString(width, height, frameRate, profile) {
  2489. const mbPerSec = Math.ceil(width / 16) * Math.ceil(height / 16) * frameRate;
  2490. let level;
  2491. if (mbPerSec <= 108e3) level = 31;
  2492. else if (mbPerSec <= 216e3) level = 32;
  2493. else if (mbPerSec <= 245760) level = 40;
  2494. else if (mbPerSec <= 589824) level = 50;
  2495. else if (mbPerSec <= 983040) level = 51;
  2496. else level = 52;
  2497. const chosenProfile = profile ?? (width >= 1280 || height >= 720 ? "high" : "baseline");
  2498. const profileHex = chosenProfile === "high" ? "64" : chosenProfile === "main" ? "4d" : "42";
  2499. const levelHex = level.toString(16).padStart(2, "0");
  2500. return `avc1.${profileHex}00${levelHex}`;
  2501. }
  2502. getCodecString(codecType, width, height, frameRate) {
  2503. switch (codecType) {
  2504. case "avc":
  2505. return this.defaultAvcCodecString(width, height, frameRate);
  2506. case "vp9":
  2507. return "vp09.00.50.08";
  2508. case "vp8":
  2509. return "vp8";
  2510. case "hevc":
  2511. return "hvc1";
  2512. case "av1":
  2513. return "av01.0.04M.08";
  2514. default:
  2515. return codecType;
  2516. }
  2517. }
  2518. async isConfigSupportedWithHwFallback(Ctor, config, label) {
  2519. let support = await Ctor.isConfigSupported(config);
  2520. if (support?.supported && support.config) return support.config;
  2521. const pref = config.hardwareAcceleration;
  2522. if (pref) {
  2523. let altPref;
  2524. if (pref === "prefer-hardware") altPref = "prefer-software";
  2525. else if (pref === "prefer-software") altPref = "prefer-hardware";
  2526. if (altPref) {
  2527. const opposite = { ...config, hardwareAcceleration: altPref };
  2528. support = await Ctor.isConfigSupported(opposite);
  2529. if (support?.supported && support.config) {
  2530. console.warn(
  2531. `${label}: hardwareAcceleration preference '${pref}' not supported. Using '${altPref}'.`
  2532. );
  2533. return support.config;
  2534. }
  2535. }
  2536. const noPref = { ...config };
  2537. delete noPref.hardwareAcceleration;
  2538. support = await Ctor.isConfigSupported(noPref);
  2539. if (support?.supported && support.config) {
  2540. console.warn(
  2541. `${label}: hardwareAcceleration preference '${pref}' not supported. Using no preference.`
  2542. );
  2543. return support.config;
  2544. }
  2545. console.warn(
  2546. `${label}: Failed to find a supported hardware acceleration configuration for codec ${config.codec}.`
  2547. );
  2548. }
  2549. return null;
  2550. }
  2551. postQueueSize() {
  2552. this.postMessageToMainThread({
  2553. type: "queueSize",
  2554. videoQueueSize: this.videoEncoder?.encodeQueueSize ?? 0,
  2555. audioQueueSize: this.audioEncoder?.encodeQueueSize ?? 0
  2556. });
  2557. }
  2558. async prepareAudioCodec(container, audioDisabled) {
  2559. if (audioDisabled) {
  2560. return {
  2561. audioDisabled: true,
  2562. selectedCodec: null,
  2563. finalConfig: null,
  2564. encoderCtor: null
  2565. };
  2566. }
  2567. const AudioEncoderCtor = getAudioEncoder();
  2568. if (!AudioEncoderCtor) {
  2569. this.postMessageToMainThread({
  2570. type: "error",
  2571. errorDetail: {
  2572. message: "Worker: AudioEncoder not available",
  2573. type: "not-supported" /* NotSupported */
  2574. }
  2575. });
  2576. return {
  2577. audioDisabled: true,
  2578. selectedCodec: null,
  2579. finalConfig: null,
  2580. encoderCtor: null
  2581. };
  2582. }
  2583. const config = this.currentConfig;
  2584. if (!config) {
  2585. return {
  2586. audioDisabled: true,
  2587. selectedCodec: null,
  2588. finalConfig: null,
  2589. encoderCtor: AudioEncoderCtor
  2590. };
  2591. }
  2592. const requestedCodec = config.codec?.audio;
  2593. const requestedCodecString = config.codecString?.audio;
  2594. const preference = buildAudioCodecPreference(container, requestedCodec);
  2595. let attemptedDefaultCodec = false;
  2596. for (const candidate of preference) {
  2597. if (candidate === "aac") {
  2598. attemptedDefaultCodec = true;
  2599. }
  2600. const codecString = requestedCodec && requestedCodecString && candidate === requestedCodec ? requestedCodecString : getAudioEncoderCodecStringFromAudioCodec(candidate);
  2601. const baseConfig = {
  2602. codec: codecString,
  2603. sampleRate: config.sampleRate,
  2604. numberOfChannels: config.channels,
  2605. bitrate: config.audioBitrate,
  2606. ...config.audioBitrateMode && {
  2607. bitrateMode: config.audioBitrateMode
  2608. },
  2609. ...config.hardwareAcceleration && {
  2610. hardwareAcceleration: config.hardwareAcceleration
  2611. },
  2612. ...getAudioEncoderConfigOverridesForCodec(
  2613. candidate,
  2614. config.audioEncoderConfig
  2615. )
  2616. };
  2617. const support = await this.isConfigSupportedWithHwFallback(
  2618. AudioEncoderCtor,
  2619. baseConfig,
  2620. "AudioEncoder"
  2621. );
  2622. if (!support) {
  2623. if (candidate === "aac" && container === "mp4") {
  2624. console.warn(
  2625. "Worker: AAC audio codec is not supported. Falling back to MP3."
  2626. );
  2627. const mp3AttemptConfig = {
  2628. codec: getAudioEncoderCodecStringFromAudioCodec("mp3"),
  2629. sampleRate: config.sampleRate,
  2630. numberOfChannels: config.channels,
  2631. bitrate: config.audioBitrate,
  2632. ...config.audioBitrateMode && {
  2633. bitrateMode: config.audioBitrateMode
  2634. },
  2635. ...config.hardwareAcceleration && {
  2636. hardwareAcceleration: config.hardwareAcceleration
  2637. },
  2638. ...getAudioEncoderConfigOverridesForCodec(
  2639. "mp3",
  2640. config.audioEncoderConfig
  2641. )
  2642. };
  2643. const mp3Support = await this.isConfigSupportedWithHwFallback(
  2644. AudioEncoderCtor,
  2645. mp3AttemptConfig,
  2646. "AudioEncoder"
  2647. );
  2648. if (mp3Support) {
  2649. const resolvedMp3Config = mp3Support;
  2650. if (resolvedMp3Config.numberOfChannels !== void 0 && resolvedMp3Config.numberOfChannels !== config.channels) {
  2651. this.postMessageToMainThread({
  2652. type: "error",
  2653. errorDetail: {
  2654. message: `AudioEncoder reported numberOfChannels (${resolvedMp3Config.numberOfChannels}) does not match configured channels (${config.channels}).`,
  2655. type: "configuration-error" /* ConfigurationError */
  2656. }
  2657. });
  2658. return {
  2659. audioDisabled: true,
  2660. selectedCodec: null,
  2661. finalConfig: null,
  2662. encoderCtor: AudioEncoderCtor
  2663. };
  2664. }
  2665. if (resolvedMp3Config.sampleRate !== void 0 && resolvedMp3Config.sampleRate !== config.sampleRate) {
  2666. this.postMessageToMainThread({
  2667. type: "error",
  2668. errorDetail: {
  2669. message: `AudioEncoder reported sampleRate (${resolvedMp3Config.sampleRate}) does not match configured sampleRate (${config.sampleRate}).`,
  2670. type: "configuration-error" /* ConfigurationError */
  2671. }
  2672. });
  2673. return {
  2674. audioDisabled: true,
  2675. selectedCodec: null,
  2676. finalConfig: null,
  2677. encoderCtor: AudioEncoderCtor
  2678. };
  2679. }
  2680. if (!isAudioCodecMuxerCompatible(container, "mp3")) {
  2681. console.warn(
  2682. "Worker: Audio codec mp3 is not compatible with MP4 muxer. Audio will be disabled."
  2683. );
  2684. } else {
  2685. console.warn("Worker: Falling back to MP3 for MP4 container.");
  2686. return {
  2687. audioDisabled: false,
  2688. selectedCodec: "mp3",
  2689. finalConfig: resolvedMp3Config,
  2690. encoderCtor: AudioEncoderCtor
  2691. };
  2692. }
  2693. }
  2694. } else {
  2695. console.warn(
  2696. `Worker: Audio codec ${candidate} not supported or config invalid.`
  2697. );
  2698. }
  2699. continue;
  2700. }
  2701. const resolvedConfig = support;
  2702. if (resolvedConfig.numberOfChannels !== void 0 && resolvedConfig.numberOfChannels !== config.channels) {
  2703. this.postMessageToMainThread({
  2704. type: "error",
  2705. errorDetail: {
  2706. message: `AudioEncoder reported numberOfChannels (${resolvedConfig.numberOfChannels}) does not match configured channels (${config.channels}).`,
  2707. type: "configuration-error" /* ConfigurationError */
  2708. }
  2709. });
  2710. return {
  2711. audioDisabled: true,
  2712. selectedCodec: null,
  2713. finalConfig: null,
  2714. encoderCtor: AudioEncoderCtor
  2715. };
  2716. }
  2717. if (resolvedConfig.sampleRate !== void 0 && resolvedConfig.sampleRate !== config.sampleRate) {
  2718. this.postMessageToMainThread({
  2719. type: "error",
  2720. errorDetail: {
  2721. message: `AudioEncoder reported sampleRate (${resolvedConfig.sampleRate}) does not match configured sampleRate (${config.sampleRate}).`,
  2722. type: "configuration-error" /* ConfigurationError */
  2723. }
  2724. });
  2725. return {
  2726. audioDisabled: true,
  2727. selectedCodec: null,
  2728. finalConfig: null,
  2729. encoderCtor: AudioEncoderCtor
  2730. };
  2731. }
  2732. if (!isAudioCodecMuxerCompatible(container, candidate)) {
  2733. console.warn(
  2734. `Worker: Audio codec ${candidate} is not compatible with ${container.toUpperCase()} muxer. Trying fallback codec.`
  2735. );
  2736. continue;
  2737. }
  2738. if (candidate === "aac") {
  2739. attemptedDefaultCodec = true;
  2740. if (container === "mp4" && requestedCodec && requestedCodec !== "aac") {
  2741. console.warn("Worker: Falling back to AAC for MP4 container.");
  2742. }
  2743. }
  2744. if (container === "mp4" && candidate === "mp3" && attemptedDefaultCodec) {
  2745. console.warn("Worker: Falling back to MP3 for MP4 container.");
  2746. }
  2747. return {
  2748. audioDisabled: false,
  2749. selectedCodec: candidate,
  2750. finalConfig: resolvedConfig,
  2751. encoderCtor: AudioEncoderCtor
  2752. };
  2753. }
  2754. const defaultCodec = DEFAULT_AUDIO_CODEC_BY_CONTAINER[container];
  2755. const noCodecMessage = container === "mp4" ? "Worker: No supported audio codec (AAC, MP3) found for MP4 container." : `Worker: No supported audio codec found. Requested: ${requestedCodec ?? "(auto)"}. Tried: ${preference.join(", ")}.`;
  2756. this.postMessageToMainThread({
  2757. type: "error",
  2758. errorDetail: {
  2759. message: noCodecMessage,
  2760. type: "not-supported" /* NotSupported */
  2761. }
  2762. });
  2763. console.warn(
  2764. `Worker: Disabling audio. Consider using ${defaultCodec} for container ${container}.`
  2765. );
  2766. return {
  2767. audioDisabled: true,
  2768. selectedCodec: null,
  2769. finalConfig: null,
  2770. encoderCtor: AudioEncoderCtor
  2771. };
  2772. }
  2773. async initializeEncoders(data) {
  2774. this.currentConfig = data.config;
  2775. this.totalFramesToProcess = data.totalFrames;
  2776. this.processedFrames = 0;
  2777. this.videoFrameCount = 0;
  2778. this.isCancelled = false;
  2779. if (!this.currentConfig) {
  2780. this.postMessageToMainThread({
  2781. type: "error",
  2782. errorDetail: {
  2783. message: "Worker: Configuration is missing.",
  2784. type: "initialization-failed" /* InitializationFailed */
  2785. }
  2786. });
  2787. return;
  2788. }
  2789. let audioDisabled = !this.currentConfig.audioBitrate || this.currentConfig.audioBitrate <= 0 || !this.currentConfig.channels || this.currentConfig.channels <= 0 || !this.currentConfig.sampleRate || this.currentConfig.sampleRate <= 0 || !this.currentConfig.codec?.audio;
  2790. const containerType = getContainerType(this.currentConfig.container);
  2791. const audioOriginallyDisabled = audioDisabled;
  2792. const audioPlan = await this.prepareAudioCodec(
  2793. containerType,
  2794. audioDisabled
  2795. );
  2796. audioDisabled = audioPlan.audioDisabled;
  2797. let selectedAudioCodec = audioPlan.selectedCodec;
  2798. let finalAudioEncoderConfig = audioPlan.finalConfig;
  2799. const preparedAudioEncoderCtor = audioPlan.encoderCtor;
  2800. if (audioDisabled) {
  2801. selectedAudioCodec = null;
  2802. finalAudioEncoderConfig = null;
  2803. }
  2804. if (!audioOriginallyDisabled && audioDisabled) {
  2805. this.cleanup();
  2806. return;
  2807. }
  2808. const videoDisabled = this.currentConfig.width === 0 || this.currentConfig.height === 0 || this.currentConfig.videoBitrate === 0;
  2809. let videoCodec = this.currentConfig.codec?.video ?? (this.currentConfig.container === "webm" ? "vp9" : "avc");
  2810. const requestedVideoCodec = videoCodec;
  2811. let finalVideoEncoderConfig = null;
  2812. let resolvedVideoCodecString = null;
  2813. let VideoEncoderCtor;
  2814. if (!videoDisabled) {
  2815. if (this.currentConfig.container === "webm" && (videoCodec === "avc" || videoCodec === "hevc")) {
  2816. console.warn(
  2817. `Worker: Video codec ${videoCodec} not compatible with WebM. Switching to VP9.`
  2818. );
  2819. videoCodec = "vp9";
  2820. }
  2821. resolvedVideoCodecString = (this.currentConfig.codecString?.video && videoCodec === requestedVideoCodec ? this.currentConfig.codecString.video : void 0) ?? (videoCodec === "avc" ? this.defaultAvcCodecString(
  2822. this.currentConfig.width,
  2823. this.currentConfig.height,
  2824. this.currentConfig.frameRate
  2825. ) : videoCodec === "vp9" ? "vp09.00.50.08" : videoCodec === "vp8" ? "vp8" : videoCodec === "hevc" ? "hvc1" : videoCodec === "av1" ? "av01.0.04M.08" : videoCodec);
  2826. const videoEncoderConfig = {
  2827. codec: resolvedVideoCodecString,
  2828. width: this.currentConfig.width,
  2829. height: this.currentConfig.height,
  2830. bitrate: this.currentConfig.videoBitrate,
  2831. framerate: this.currentConfig.frameRate,
  2832. ...this.currentConfig.container === "mp4" && videoCodec === "avc" ? { avc: { format: "avc" } } : {},
  2833. ...this.currentConfig.hardwareAcceleration ? { hardwareAcceleration: this.currentConfig.hardwareAcceleration } : {},
  2834. ...getVideoEncoderConfigOverridesForCodec(
  2835. videoCodec,
  2836. this.currentConfig.videoEncoderConfig
  2837. )
  2838. };
  2839. VideoEncoderCtor = getVideoEncoder();
  2840. if (!VideoEncoderCtor) {
  2841. this.postMessageToMainThread({
  2842. type: "error",
  2843. errorDetail: {
  2844. message: "Worker: VideoEncoder not available",
  2845. type: "not-supported" /* NotSupported */
  2846. }
  2847. });
  2848. this.cleanup();
  2849. return;
  2850. }
  2851. const initialSupport = await VideoEncoderCtor.isConfigSupported(videoEncoderConfig);
  2852. if (initialSupport?.supported && initialSupport.config) {
  2853. finalVideoEncoderConfig = initialSupport.config;
  2854. } else {
  2855. if (videoCodec === "vp9" || videoCodec === "vp8" || videoCodec === "av1") {
  2856. console.warn(
  2857. "Worker: Video codec " + videoCodec + " not supported or config invalid. Looking for fallback..."
  2858. );
  2859. let fallbackSuccessful = false;
  2860. if (this.currentConfig.container === "webm") {
  2861. const webmCodecs = ["vp9", "vp8"];
  2862. for (const fallbackCodec of webmCodecs) {
  2863. if (fallbackCodec === videoCodec) continue;
  2864. console.warn(
  2865. `Worker: Trying fallback to ${fallbackCodec} for WebM container.`
  2866. );
  2867. const fallbackCodecString = this.getCodecString(
  2868. fallbackCodec,
  2869. this.currentConfig.width,
  2870. this.currentConfig.height,
  2871. this.currentConfig.frameRate
  2872. );
  2873. const fallbackConfig = {
  2874. ...videoEncoderConfig,
  2875. codec: fallbackCodecString,
  2876. ...getVideoEncoderConfigOverridesForCodec(
  2877. fallbackCodec,
  2878. this.currentConfig.videoEncoderConfig
  2879. )
  2880. };
  2881. const support = await this.isConfigSupportedWithHwFallback(
  2882. VideoEncoderCtor,
  2883. fallbackConfig,
  2884. "VideoEncoder"
  2885. );
  2886. if (support) {
  2887. console.warn(
  2888. `Worker: Successfully fell back to ${fallbackCodec} for WebM.`
  2889. );
  2890. videoCodec = fallbackCodec;
  2891. finalVideoEncoderConfig = support;
  2892. fallbackSuccessful = true;
  2893. break;
  2894. }
  2895. }
  2896. if (!fallbackSuccessful) {
  2897. this.postMessageToMainThread({
  2898. type: "error",
  2899. errorDetail: {
  2900. message: "Worker: No compatible video codec (VP9, VP8) found for WebM container.",
  2901. type: "not-supported" /* NotSupported */
  2902. }
  2903. });
  2904. this.cleanup();
  2905. return;
  2906. }
  2907. } else {
  2908. console.warn("Worker: Falling back to AVC for MP4 container.");
  2909. videoCodec = "avc";
  2910. const avcCodecString = this.defaultAvcCodecString(
  2911. this.currentConfig.width,
  2912. this.currentConfig.height,
  2913. this.currentConfig.frameRate
  2914. );
  2915. const avcConfig = {
  2916. ...videoEncoderConfig,
  2917. codec: avcCodecString,
  2918. ...this.currentConfig.container === "mp4" ? { avc: { format: "avc" } } : {},
  2919. ...getVideoEncoderConfigOverridesForCodec(
  2920. "avc",
  2921. this.currentConfig.videoEncoderConfig
  2922. )
  2923. };
  2924. const support = await this.isConfigSupportedWithHwFallback(
  2925. VideoEncoderCtor,
  2926. avcConfig,
  2927. "VideoEncoder"
  2928. );
  2929. if (support) {
  2930. finalVideoEncoderConfig = support;
  2931. fallbackSuccessful = true;
  2932. } else {
  2933. this.postMessageToMainThread({
  2934. type: "error",
  2935. errorDetail: {
  2936. message: "Worker: AVC (H.264) video codec is not supported after fallback.",
  2937. type: "not-supported" /* NotSupported */
  2938. }
  2939. });
  2940. this.cleanup();
  2941. return;
  2942. }
  2943. }
  2944. } else {
  2945. const result = await this.isConfigSupportedWithHwFallback(
  2946. VideoEncoderCtor,
  2947. videoEncoderConfig,
  2948. "VideoEncoder"
  2949. );
  2950. if (result) {
  2951. finalVideoEncoderConfig = result;
  2952. } else {
  2953. this.postMessageToMainThread({
  2954. type: "error",
  2955. errorDetail: {
  2956. message: `Worker: Video codec ${videoCodec} config not supported.`,
  2957. type: "not-supported" /* NotSupported */
  2958. }
  2959. });
  2960. this.cleanup();
  2961. return;
  2962. }
  2963. }
  2964. }
  2965. } else {
  2966. videoCodec = void 0;
  2967. }
  2968. const codecConfigForMuxer = {
  2969. ...this.currentConfig.codec ?? {},
  2970. video: videoDisabled ? void 0 : videoCodec,
  2971. audio: audioDisabled || !selectedAudioCodec ? void 0 : selectedAudioCodec
  2972. };
  2973. this.currentConfig.codec = codecConfigForMuxer;
  2974. try {
  2975. const MuxerCtor = containerType === "webm" ? WebMMuxerWrapper : Mp4MuxerWrapper;
  2976. this.muxer = new MuxerCtor(
  2977. this.currentConfig,
  2978. this.postMessageToMainThread.bind(this),
  2979. {
  2980. disableAudio: audioDisabled
  2981. }
  2982. );
  2983. } catch (e) {
  2984. this.postMessageToMainThread({
  2985. type: "error",
  2986. errorDetail: {
  2987. message: `Worker: Failed to initialize Muxer: ${e.message}`,
  2988. type: "initialization-failed" /* InitializationFailed */,
  2989. stack: e.stack
  2990. }
  2991. });
  2992. this.cleanup();
  2993. return;
  2994. }
  2995. if (!videoDisabled) {
  2996. try {
  2997. if (!VideoEncoderCtor) {
  2998. this.postMessageToMainThread({
  2999. type: "error",
  3000. errorDetail: {
  3001. message: "Worker: VideoEncoder not available",
  3002. type: "not-supported" /* NotSupported */
  3003. }
  3004. });
  3005. this.cleanup();
  3006. return;
  3007. }
  3008. this.videoEncoder = new VideoEncoderCtor({
  3009. output: (chunk, meta) => {
  3010. if (this.isCancelled || !this.muxer) return;
  3011. this.muxer.addVideoChunk(chunk, meta);
  3012. },
  3013. error: (error) => {
  3014. if (this.isCancelled) return;
  3015. this.postMessageToMainThread({
  3016. type: "error",
  3017. errorDetail: {
  3018. message: `VideoEncoder error: ${error.message}`,
  3019. type: "video-encoding-error" /* VideoEncodingError */,
  3020. stack: error.stack
  3021. }
  3022. });
  3023. this.cleanup();
  3024. }
  3025. });
  3026. if (finalVideoEncoderConfig) {
  3027. if (this.videoEncoder) {
  3028. this.videoEncoder.configure(finalVideoEncoderConfig);
  3029. } else {
  3030. this.postMessageToMainThread({
  3031. type: "error",
  3032. errorDetail: {
  3033. message: "Worker: VideoEncoder instance is null after creation.",
  3034. type: "initialization-failed" /* InitializationFailed */
  3035. }
  3036. });
  3037. this.cleanup();
  3038. return;
  3039. }
  3040. } else {
  3041. this.postMessageToMainThread({
  3042. type: "error",
  3043. errorDetail: {
  3044. message: `Worker: VideoEncoder: Failed to find a supported hardware acceleration configuration for codec ${resolvedVideoCodecString ?? "(unknown)"}`,
  3045. type: "not-supported" /* NotSupported */
  3046. }
  3047. });
  3048. this.cleanup();
  3049. return;
  3050. }
  3051. } catch (e) {
  3052. this.postMessageToMainThread({
  3053. type: "error",
  3054. errorDetail: {
  3055. message: `Worker: Failed to initialize VideoEncoder: ${e.message}`,
  3056. type: "initialization-failed" /* InitializationFailed */,
  3057. stack: e.stack
  3058. }
  3059. });
  3060. this.cleanup();
  3061. return;
  3062. }
  3063. }
  3064. if (!audioDisabled) {
  3065. if (!selectedAudioCodec || !finalAudioEncoderConfig || !preparedAudioEncoderCtor) {
  3066. this.cleanup();
  3067. return;
  3068. }
  3069. try {
  3070. this.audioEncoder = new preparedAudioEncoderCtor({
  3071. output: (chunk, meta) => {
  3072. if (this.isCancelled || !this.muxer) return;
  3073. this.muxer.addAudioChunk(chunk, meta);
  3074. },
  3075. error: (error) => {
  3076. if (this.isCancelled) return;
  3077. this.postMessageToMainThread({
  3078. type: "error",
  3079. errorDetail: {
  3080. message: `AudioEncoder error: ${error.message}`,
  3081. type: "audio-encoding-error" /* AudioEncodingError */,
  3082. stack: error.stack
  3083. }
  3084. });
  3085. this.cleanup();
  3086. }
  3087. });
  3088. if (this.audioEncoder) {
  3089. this.audioEncoder.configure(finalAudioEncoderConfig);
  3090. } else {
  3091. this.postMessageToMainThread({
  3092. type: "error",
  3093. errorDetail: {
  3094. message: "Worker: AudioEncoder instance is null after creation.",
  3095. type: "initialization-failed" /* InitializationFailed */
  3096. }
  3097. });
  3098. this.cleanup();
  3099. return;
  3100. }
  3101. } catch (e) {
  3102. this.postMessageToMainThread({
  3103. type: "error",
  3104. errorDetail: {
  3105. message: `Worker: Failed to initialize AudioEncoder: ${e.message}`,
  3106. type: "initialization-failed" /* InitializationFailed */,
  3107. stack: e.stack
  3108. }
  3109. });
  3110. this.cleanup();
  3111. return;
  3112. }
  3113. }
  3114. this.postMessageToMainThread({
  3115. type: "initialized",
  3116. actualVideoCodec: finalVideoEncoderConfig?.codec,
  3117. actualAudioCodec: audioDisabled ? null : finalAudioEncoderConfig?.codec
  3118. });
  3119. console.warn("Worker: Initialized successfully");
  3120. }
  3121. async handleAddVideoFrame(data) {
  3122. if (this.isCancelled || !this.videoEncoder || !this.currentConfig) return;
  3123. try {
  3124. const frame = data.frame;
  3125. const currentQueueSize = this.videoEncoder.encodeQueueSize;
  3126. const maxQueueSize = this.currentConfig.maxVideoQueueSize || 30;
  3127. const strategy = this.currentConfig.backpressureStrategy || "drop";
  3128. if (currentQueueSize >= maxQueueSize) {
  3129. if (strategy === "drop") {
  3130. console.warn(
  3131. `Video queue full (${currentQueueSize}/${maxQueueSize}), dropping frame`
  3132. );
  3133. try {
  3134. frame.close();
  3135. } catch (closeErr) {
  3136. console.warn(
  3137. "Worker: Ignored error closing dropped VideoFrame",
  3138. closeErr
  3139. );
  3140. }
  3141. return;
  3142. } else if (strategy === "wait") {
  3143. let waitTime = 10;
  3144. const maxWaitTime = 100;
  3145. const maxRetries = 5;
  3146. let attempts = 0;
  3147. while (this.videoEncoder.encodeQueueSize >= maxQueueSize && attempts < maxRetries) {
  3148. await new Promise((resolve) => setTimeout(resolve, waitTime));
  3149. waitTime = Math.min(waitTime * 1.5, maxWaitTime);
  3150. attempts++;
  3151. }
  3152. if (this.videoEncoder.encodeQueueSize >= maxQueueSize) {
  3153. console.warn(
  3154. `Video queue still full after waiting, dropping frame`
  3155. );
  3156. try {
  3157. frame.close();
  3158. } catch (closeErr) {
  3159. console.warn(
  3160. "Worker: Ignored error closing waited VideoFrame",
  3161. closeErr
  3162. );
  3163. }
  3164. return;
  3165. }
  3166. }
  3167. }
  3168. const interval = this.currentConfig.keyFrameInterval;
  3169. const opts = interval && this.videoFrameCount % interval === 0 ? { keyFrame: true } : void 0;
  3170. this.videoEncoder.encode(frame, opts);
  3171. try {
  3172. frame.close();
  3173. } catch (closeErr) {
  3174. console.warn("Worker: Ignored error closing VideoFrame", closeErr);
  3175. }
  3176. this.videoFrameCount++;
  3177. this.processedFrames++;
  3178. const progressMessage = {
  3179. type: "progress",
  3180. processedFrames: this.processedFrames
  3181. };
  3182. if (typeof this.totalFramesToProcess !== "undefined") {
  3183. progressMessage.totalFrames = this.totalFramesToProcess;
  3184. }
  3185. this.postMessageToMainThread(progressMessage);
  3186. this.postQueueSize();
  3187. } catch (error) {
  3188. this.postMessageToMainThread({
  3189. type: "error",
  3190. errorDetail: {
  3191. message: `Error encoding video frame: ${error.message}`,
  3192. type: "video-encoding-error" /* VideoEncodingError */,
  3193. stack: error.stack
  3194. }
  3195. });
  3196. this.cleanup();
  3197. }
  3198. }
  3199. async handleAddAudioData(data) {
  3200. if (this.isCancelled || !this.audioEncoder || !this.currentConfig) return;
  3201. if (data.audio) {
  3202. const audioData = data.audio;
  3203. let audioClosed = false;
  3204. const closeAudioData = (context) => {
  3205. if (audioClosed) return;
  3206. try {
  3207. audioData.close();
  3208. audioClosed = true;
  3209. } catch (closeErr) {
  3210. console.warn(`Worker: Ignored error closing ${context}`, closeErr);
  3211. }
  3212. };
  3213. try {
  3214. const currentQueueSize = this.audioEncoder.encodeQueueSize;
  3215. const maxQueueSize = this.currentConfig.maxAudioQueueSize || 30;
  3216. const strategy = this.currentConfig.backpressureStrategy || "drop";
  3217. if (currentQueueSize >= maxQueueSize) {
  3218. if (strategy === "drop") {
  3219. console.warn(
  3220. `Audio queue full (${currentQueueSize}/${maxQueueSize}), dropping audio data`
  3221. );
  3222. closeAudioData("dropped AudioData");
  3223. return;
  3224. } else if (strategy === "wait") {
  3225. let waitTime = 10;
  3226. const maxWaitTime = 100;
  3227. const maxRetries = 5;
  3228. let attempts = 0;
  3229. while (this.audioEncoder.encodeQueueSize >= maxQueueSize && attempts < maxRetries) {
  3230. await new Promise((resolve) => setTimeout(resolve, waitTime));
  3231. waitTime = Math.min(waitTime * 1.5, maxWaitTime);
  3232. attempts++;
  3233. }
  3234. if (this.audioEncoder.encodeQueueSize >= maxQueueSize) {
  3235. console.warn(
  3236. `Audio queue still full after waiting, dropping audio data`
  3237. );
  3238. closeAudioData("waited AudioData");
  3239. return;
  3240. }
  3241. }
  3242. }
  3243. this.audioEncoder.encode(audioData);
  3244. this.postQueueSize();
  3245. } catch (error) {
  3246. this.postMessageToMainThread({
  3247. type: "error",
  3248. errorDetail: {
  3249. message: `Error encoding audio data: ${error.message}`,
  3250. type: "audio-encoding-error" /* AudioEncodingError */,
  3251. stack: error.stack
  3252. }
  3253. });
  3254. this.cleanup();
  3255. } finally {
  3256. closeAudioData("AudioData");
  3257. }
  3258. return;
  3259. }
  3260. if (!data.audioData || data.audioData.length === 0) return;
  3261. if (data.audioData.length !== this.currentConfig.channels) {
  3262. this.postMessageToMainThread({
  3263. type: "error",
  3264. errorDetail: {
  3265. message: `Audio data channel count (${data.audioData.length}) does not match configured channels (${this.currentConfig.channels}).`,
  3266. type: "configuration-error" /* ConfigurationError */
  3267. }
  3268. });
  3269. return;
  3270. }
  3271. const AudioDataCtor = getAudioData();
  3272. if (!AudioDataCtor) {
  3273. this.postMessageToMainThread({
  3274. type: "error",
  3275. errorDetail: {
  3276. message: "Worker: AudioData not available",
  3277. type: "not-supported" /* NotSupported */
  3278. }
  3279. });
  3280. this.cleanup();
  3281. return;
  3282. }
  3283. try {
  3284. const interleaveFloat32Arrays = (planarArrays) => {
  3285. if (!planarArrays || planarArrays.length === 0) {
  3286. return new Float32Array(0);
  3287. }
  3288. const numChannels = planarArrays.length;
  3289. const numFrames = Math.min(...planarArrays.map((arr) => arr.length));
  3290. const interleaved = new Float32Array(numFrames * numChannels);
  3291. for (let i = 0; i < numFrames; i++) {
  3292. for (let ch = 0; ch < numChannels; ch++) {
  3293. interleaved[i * numChannels + ch] = planarArrays[ch][i];
  3294. }
  3295. }
  3296. return interleaved;
  3297. };
  3298. const interleavedData = interleaveFloat32Arrays(data.audioData);
  3299. const audioData = new AudioDataCtor({
  3300. format: "f32",
  3301. sampleRate: data.sampleRate,
  3302. numberOfFrames: data.numberOfFrames,
  3303. numberOfChannels: data.numberOfChannels,
  3304. timestamp: data.timestamp,
  3305. data: interleavedData.buffer
  3306. });
  3307. try {
  3308. this.audioEncoder.encode(audioData);
  3309. this.postQueueSize();
  3310. } finally {
  3311. audioData.close();
  3312. }
  3313. } catch (error) {
  3314. this.postMessageToMainThread({
  3315. type: "error",
  3316. errorDetail: {
  3317. message: `Error encoding audio data: ${error.message}`,
  3318. type: "audio-encoding-error" /* AudioEncodingError */,
  3319. stack: error.stack
  3320. }
  3321. });
  3322. this.cleanup();
  3323. }
  3324. }
  3325. async handleFinalize(_message) {
  3326. if (this.isCancelled) return;
  3327. try {
  3328. if (this.videoEncoder) await this.videoEncoder.flush();
  3329. if (this.audioEncoder) await this.audioEncoder.flush();
  3330. if (this.muxer) {
  3331. const uint8ArrayOrNullOutput = this.muxer.finalize();
  3332. if (uint8ArrayOrNullOutput) {
  3333. this.postMessageToMainThread(
  3334. { type: "finalized", output: uint8ArrayOrNullOutput },
  3335. [uint8ArrayOrNullOutput.buffer]
  3336. );
  3337. } else if (this.currentConfig?.latencyMode === "realtime") {
  3338. this.postMessageToMainThread({ type: "finalized", output: null });
  3339. } else {
  3340. this.postMessageToMainThread({
  3341. type: "error",
  3342. errorDetail: {
  3343. message: "Muxer finalized without output in non-realtime mode.",
  3344. type: "muxing-failed" /* MuxingFailed */
  3345. }
  3346. });
  3347. }
  3348. } else {
  3349. this.postMessageToMainThread({
  3350. type: "error",
  3351. errorDetail: {
  3352. message: "Muxer not initialized during finalize.",
  3353. type: "muxing-failed" /* MuxingFailed */
  3354. }
  3355. });
  3356. }
  3357. } catch (error) {
  3358. this.postMessageToMainThread({
  3359. type: "error",
  3360. errorDetail: {
  3361. message: `Error during finalization: ${error.message}`,
  3362. type: "muxing-failed" /* MuxingFailed */,
  3363. stack: error.stack
  3364. }
  3365. });
  3366. } finally {
  3367. this.cleanup();
  3368. }
  3369. }
  3370. handleCancel(_message) {
  3371. if (this.isCancelled) return;
  3372. this.isCancelled = true;
  3373. console.warn("Worker: Received cancel signal.");
  3374. this.postMessageToMainThread({ type: "cancelled" });
  3375. this.videoEncoder?.close();
  3376. this.audioEncoder?.close();
  3377. this.cleanup();
  3378. }
  3379. cleanup() {
  3380. console.warn("Worker: Cleaning up resources.");
  3381. if (this.videoEncoder && this.videoEncoder.state !== "closed")
  3382. this.videoEncoder.close();
  3383. if (this.audioEncoder && this.audioEncoder.state !== "closed")
  3384. this.audioEncoder.close();
  3385. this.videoEncoder = null;
  3386. this.audioEncoder = null;
  3387. this.muxer = null;
  3388. this.currentConfig = null;
  3389. this.totalFramesToProcess = void 0;
  3390. this.processedFrames = 0;
  3391. this.videoFrameCount = 0;
  3392. }
  3393. async handleMessage(eventData) {
  3394. if (this.isCancelled && eventData.type !== "initialize" && eventData.type !== "cancel") {
  3395. console.warn(
  3396. `Worker: Ignoring message type '${eventData.type}' because worker is cancelled.`
  3397. );
  3398. return;
  3399. }
  3400. try {
  3401. switch (eventData.type) {
  3402. case "initialize":
  3403. this.isCancelled = false;
  3404. this.cleanup();
  3405. await this.initializeEncoders(eventData);
  3406. break;
  3407. case "addVideoFrame":
  3408. await this.handleAddVideoFrame(eventData);
  3409. break;
  3410. case "addAudioData":
  3411. await this.handleAddAudioData(eventData);
  3412. break;
  3413. case "finalize":
  3414. await this.handleFinalize(eventData);
  3415. break;
  3416. case "cancel":
  3417. this.handleCancel(eventData);
  3418. break;
  3419. default:
  3420. console.warn(
  3421. "Worker received unknown message type:",
  3422. eventData.type
  3423. );
  3424. }
  3425. } catch (error) {
  3426. this.postMessageToMainThread({
  3427. type: "error",
  3428. errorDetail: {
  3429. message: `Unhandled error in worker onmessage: ${error.message}`,
  3430. type: "unknown" /* Unknown */,
  3431. stack: error.stack
  3432. }
  3433. });
  3434. this.cleanup();
  3435. }
  3436. }
  3437. };
  3438. var encoder = new EncoderWorker();
  3439. self.onmessage = async (event) => {
  3440. await encoder.handleMessage(event.data);
  3441. };
  3442. var DEFAULT_AUDIO_CODEC_BY_CONTAINER = {
  3443. mp4: "aac",
  3444. webm: "opus"
  3445. };
  3446. var AUDIO_ENCODER_CODEC_MAP = {
  3447. aac: "mp4a.40.2",
  3448. opus: "opus",
  3449. flac: "flac",
  3450. mp3: "mp3",
  3451. vorbis: "vorbis",
  3452. pcm: "pcm",
  3453. ulaw: "ulaw",
  3454. alaw: "alaw"
  3455. };
  3456. var MUXER_COMPATIBLE_AUDIO = {
  3457. mp4: /* @__PURE__ */ new Set(["aac", "mp3"]),
  3458. webm: /* @__PURE__ */ new Set(["opus", "vorbis", "flac"])
  3459. };
  3460. function getAudioEncoderCodecStringFromAudioCodec(codec) {
  3461. return AUDIO_ENCODER_CODEC_MAP[codec] ?? codec;
  3462. }
  3463. function getVideoEncoderConfigOverridesForCodec(codec, overrides) {
  3464. if (!overrides) {
  3465. return {};
  3466. }
  3467. const sanitized = { ...overrides };
  3468. if (codec !== "avc") {
  3469. delete sanitized.avc;
  3470. }
  3471. if (codec !== "hevc") {
  3472. delete sanitized.hevc;
  3473. }
  3474. return sanitized;
  3475. }
  3476. function getAudioEncoderConfigOverridesForCodec(codec, overrides) {
  3477. if (!overrides) {
  3478. return {};
  3479. }
  3480. const sanitized = { ...overrides };
  3481. if (codec !== "aac") {
  3482. delete sanitized.aac;
  3483. }
  3484. return sanitized;
  3485. }
  3486. function getContainerType(container) {
  3487. return container === "webm" ? "webm" : "mp4";
  3488. }
  3489. function buildAudioCodecPreference(container, requested) {
  3490. const preference = [];
  3491. const addCodec = (codec) => {
  3492. if (!preference.includes(codec)) {
  3493. preference.push(codec);
  3494. }
  3495. };
  3496. if (requested) {
  3497. addCodec(requested);
  3498. }
  3499. addCodec(DEFAULT_AUDIO_CODEC_BY_CONTAINER[container]);
  3500. for (const codec of MUXER_COMPATIBLE_AUDIO[container]) {
  3501. addCodec(codec);
  3502. }
  3503. if (container === "mp4") {
  3504. addCodec("aac");
  3505. addCodec("mp3");
  3506. } else {
  3507. addCodec("opus");
  3508. addCodec("vorbis");
  3509. addCodec("flac");
  3510. addCodec("aac");
  3511. }
  3512. return preference;
  3513. }
  3514. function isAudioCodecMuxerCompatible(container, codec) {
  3515. return MUXER_COMPATIBLE_AUDIO[container].has(codec);
  3516. }
  3517. })();
  3518. //# sourceMappingURL=worker.js.map