worker.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /// <reference no-default-lib="true" />
  2. /// <reference lib="esnext" />
  3. /// <reference lib="webworker" />
  4. import { CORE_URL, FFMessageType } from "./const.js";
  5. import { ERROR_UNKNOWN_MESSAGE_TYPE, ERROR_NOT_LOADED, ERROR_IMPORT_FAILURE, } from "./errors.js";
  6. let ffmpeg;
  7. const load = async ({ coreURL: _coreURL, wasmURL: _wasmURL, workerURL: _workerURL, }) => {
  8. const first = !ffmpeg;
  9. try {
  10. if (!_coreURL)
  11. _coreURL = CORE_URL;
  12. // when web worker type is `classic`.
  13. importScripts(_coreURL);
  14. }
  15. catch {
  16. if (!_coreURL)
  17. _coreURL = CORE_URL.replace('/umd/', '/esm/');
  18. // when web worker type is `module`.
  19. self.createFFmpegCore = (await import(
  20. /* webpackIgnore: true */ /* @vite-ignore */ _coreURL)).default;
  21. if (!self.createFFmpegCore) {
  22. throw ERROR_IMPORT_FAILURE;
  23. }
  24. }
  25. const coreURL = _coreURL;
  26. const wasmURL = _wasmURL ? _wasmURL : _coreURL.replace(/.js$/g, ".wasm");
  27. const workerURL = _workerURL
  28. ? _workerURL
  29. : _coreURL.replace(/.js$/g, ".worker.js");
  30. ffmpeg = await self.createFFmpegCore({
  31. // Fix `Overload resolution failed.` when using multi-threaded ffmpeg-core.
  32. // Encoded wasmURL and workerURL in the URL as a hack to fix locateFile issue.
  33. mainScriptUrlOrBlob: `${coreURL}#${btoa(JSON.stringify({ wasmURL, workerURL }))}`,
  34. });
  35. ffmpeg.setLogger((data) => self.postMessage({ type: FFMessageType.LOG, data }));
  36. ffmpeg.setProgress((data) => self.postMessage({
  37. type: FFMessageType.PROGRESS,
  38. data,
  39. }));
  40. return first;
  41. };
  42. const exec = ({ args, timeout = -1 }) => {
  43. ffmpeg.setTimeout(timeout);
  44. ffmpeg.exec(...args);
  45. const ret = ffmpeg.ret;
  46. ffmpeg.reset();
  47. return ret;
  48. };
  49. const writeFile = ({ path, data }) => {
  50. ffmpeg.FS.writeFile(path, data);
  51. return true;
  52. };
  53. const readFile = ({ path, encoding }) => ffmpeg.FS.readFile(path, { encoding });
  54. // TODO: check if deletion works.
  55. const deleteFile = ({ path }) => {
  56. ffmpeg.FS.unlink(path);
  57. return true;
  58. };
  59. const rename = ({ oldPath, newPath }) => {
  60. ffmpeg.FS.rename(oldPath, newPath);
  61. return true;
  62. };
  63. // TODO: check if creation works.
  64. const createDir = ({ path }) => {
  65. ffmpeg.FS.mkdir(path);
  66. return true;
  67. };
  68. const listDir = ({ path }) => {
  69. const names = ffmpeg.FS.readdir(path);
  70. const nodes = [];
  71. for (const name of names) {
  72. const stat = ffmpeg.FS.stat(`${path}/${name}`);
  73. const isDir = ffmpeg.FS.isDir(stat.mode);
  74. nodes.push({ name, isDir });
  75. }
  76. return nodes;
  77. };
  78. // TODO: check if deletion works.
  79. const deleteDir = ({ path }) => {
  80. ffmpeg.FS.rmdir(path);
  81. return true;
  82. };
  83. const mount = ({ fsType, options, mountPoint }) => {
  84. const str = fsType;
  85. const fs = ffmpeg.FS.filesystems[str];
  86. if (!fs)
  87. return false;
  88. ffmpeg.FS.mount(fs, options, mountPoint);
  89. return true;
  90. };
  91. const unmount = ({ mountPoint }) => {
  92. ffmpeg.FS.unmount(mountPoint);
  93. return true;
  94. };
  95. self.onmessage = async ({ data: { id, type, data: _data }, }) => {
  96. const trans = [];
  97. let data;
  98. try {
  99. if (type !== FFMessageType.LOAD && !ffmpeg)
  100. throw ERROR_NOT_LOADED; // eslint-disable-line
  101. switch (type) {
  102. case FFMessageType.LOAD:
  103. data = await load(_data);
  104. break;
  105. case FFMessageType.EXEC:
  106. data = exec(_data);
  107. break;
  108. case FFMessageType.WRITE_FILE:
  109. data = writeFile(_data);
  110. break;
  111. case FFMessageType.READ_FILE:
  112. data = readFile(_data);
  113. break;
  114. case FFMessageType.DELETE_FILE:
  115. data = deleteFile(_data);
  116. break;
  117. case FFMessageType.RENAME:
  118. data = rename(_data);
  119. break;
  120. case FFMessageType.CREATE_DIR:
  121. data = createDir(_data);
  122. break;
  123. case FFMessageType.LIST_DIR:
  124. data = listDir(_data);
  125. break;
  126. case FFMessageType.DELETE_DIR:
  127. data = deleteDir(_data);
  128. break;
  129. case FFMessageType.MOUNT:
  130. data = mount(_data);
  131. break;
  132. case FFMessageType.UNMOUNT:
  133. data = unmount(_data);
  134. break;
  135. default:
  136. throw ERROR_UNKNOWN_MESSAGE_TYPE;
  137. }
  138. }
  139. catch (e) {
  140. self.postMessage({
  141. id,
  142. type: FFMessageType.ERROR,
  143. data: e.toString(),
  144. });
  145. return;
  146. }
  147. if (data instanceof Uint8Array) {
  148. trans.push(data.buffer);
  149. }
  150. self.postMessage({ id, type, data }, trans);
  151. };