Refactor to load wasm module in a web worker to prevent blocking main browser thread. Update FS to use WORKERFS.

This commit is contained in:
Alf
2020-12-21 22:38:14 -08:00
parent 8dadddcb24
commit 3a7d96443c
6 changed files with 26 additions and 48 deletions

View File

@@ -1,4 +1,4 @@
FROM emscripten/emsdk as build FROM emscripten/emsdk:2.0.11 as build
ARG FFMPEG_VERSION=4.3.1 ARG FFMPEG_VERSION=4.3.1
ARG X264_VERSION=20170226-2245-stable ARG X264_VERSION=20170226-2245-stable
@@ -30,7 +30,7 @@ RUN cd /tmp/ && \
wget http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ wget http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \
tar zxf ffmpeg-${FFMPEG_VERSION}.tar.gz && rm ffmpeg-${FFMPEG_VERSION}.tar.gz tar zxf ffmpeg-${FFMPEG_VERSION}.tar.gz && rm ffmpeg-${FFMPEG_VERSION}.tar.gz
ARG CFLAGS="-s USE_PTHREADS -O3 -I${PREFIX}/include" ARG CFLAGS="-s USE_PTHREADS=1 -O3 -I${PREFIX}/include"
ARG LDFLAGS="$CFLAGS -L${PREFIX}/lib -s INITIAL_MEMORY=33554432" ARG LDFLAGS="$CFLAGS -L${PREFIX}/lib -s INITIAL_MEMORY=33554432"
# Compile ffmpeg. # Compile ffmpeg.

View File

@@ -6,7 +6,8 @@ dist/ffprobe-wasm.js:
-I/opt/ffmpeg/include/ \ -I/opt/ffmpeg/include/ \
-s EXTRA_EXPORTED_RUNTIME_METHODS="[FS, cwrap, ccall, getValue, setValue, writeAsciiToMemory]" \ -s EXTRA_EXPORTED_RUNTIME_METHODS="[FS, cwrap, ccall, getValue, setValue, writeAsciiToMemory]" \
-s INITIAL_MEMORY=268435456 \ -s INITIAL_MEMORY=268435456 \
-lavcodec -lavformat -lavfilter -lavdevice -lswresample -lswscale -lavutil -lm -lx264 \
-pthread \ -pthread \
-lavcodec -lavformat -lavfilter -lavdevice -lswresample -lswscale -lavutil -lm -lx264 -pthread \ -lworkerfs.js \
-o dist/ffprobe-wasm.js \ -o dist/ffprobe-wasm.js \
src/ffprobe-wasm-wrapper.cpp src/ffprobe-wasm-wrapper.cpp

View File

@@ -1,5 +1,6 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <vector>
#include <inttypes.h> #include <inttypes.h>
#include <emscripten.h> #include <emscripten.h>
#include <emscripten/bind.h> #include <emscripten/bind.h>
@@ -65,8 +66,8 @@ typedef struct FramesResponse {
int nb_frames; int nb_frames;
} FramesResponse; } FramesResponse;
FileInfoResponse get_file_info() { FileInfoResponse get_file_info(std::string filename) {
FILE *file = fopen("file", "rb"); FILE *file = fopen(filename.c_str(), "rb");
if (!file) { if (!file) {
printf("cannot open file\n"); printf("cannot open file\n");
} }
@@ -79,9 +80,8 @@ FileInfoResponse get_file_info() {
// Open the file and read header. // Open the file and read header.
int ret; int ret;
if ((ret = avformat_open_input(&pFormatContext, "file", NULL, NULL)) < 0) { if ((ret = avformat_open_input(&pFormatContext, filename.c_str(), NULL, NULL)) < 0) {
printf("ERROR: could not open the file. Error: %d\n", ret); printf("ERROR: %s\n", av_err2str(ret));
printf("%s", av_err2str(ret));
} }
// Get stream info from format. // Get stream info from format.
@@ -135,10 +135,10 @@ FileInfoResponse get_file_info() {
return r; return r;
} }
FramesResponse get_frames(int offset) { FramesResponse get_frames(std::string filename, int offset) {
av_log_set_level(AV_LOG_QUIET); // No logging output for libav. av_log_set_level(AV_LOG_QUIET); // No logging output for libav.
FILE *file = fopen("file", "rb"); FILE *file = fopen(filename.c_str(), "rb");
if (!file) { if (!file) {
printf("cannot open file\n"); printf("cannot open file\n");
} }
@@ -151,9 +151,8 @@ FramesResponse get_frames(int offset) {
// Open the file and read header. // Open the file and read header.
int ret; int ret;
if ((ret = avformat_open_input(&pFormatContext, "file", NULL, NULL)) < 0) { if ((ret = avformat_open_input(&pFormatContext, filename.c_str(), NULL, NULL)) < 0) {
printf("ERROR: could not open the file. Error: %d\n", ret); printf("ERROR: %s\n", av_err2str(ret));
printf("%s", av_err2str(ret));
} }
// Get stream info from format. // Get stream info from format.
@@ -239,7 +238,6 @@ FramesResponse get_frames(int offset) {
return r; return r;
} }
EMSCRIPTEN_BINDINGS(constants) { EMSCRIPTEN_BINDINGS(constants) {
function("avformat_version", &c_avformat_version); function("avformat_version", &c_avformat_version);
function("avcodec_version", &c_avcodec_version); function("avcodec_version", &c_avcodec_version);

View File

@@ -12,7 +12,6 @@
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript> </noscript>
<div id="app"></div> <div id="app"></div>
<script src="ffprobe-wasm.js"></script>
<!-- built files will be auto injected --> <!-- built files will be auto injected -->
</body> </body>
</html> </html>

View File

@@ -18,12 +18,12 @@
:value="progress" :value="progress"
max="100"></b-progress> max="100"></b-progress>
<div v-if="data"> <div v-if="info">
<div class="mt-3">Selected file: {{ file ? `${file.name}: ${file.size} bytes` : '' }}</div> <div class="mt-3">Selected file: {{ file ? `${file.name}: ${file.size} bytes` : '' }}</div>
<b-tabs class="mt-4"> <b-tabs class="mt-4">
<b-tab title="Overview" class="mt-2"> <b-tab title="Overview" class="mt-2">
<div v-if="data"> <div v-if="info">
<Overview :info="info" /> <Overview :info="info" />
</div> </div>
</b-tab> </b-tab>
@@ -39,6 +39,8 @@
import Overview from './Overview.vue'; import Overview from './Overview.vue';
import Frames from './Frames.vue'; import Frames from './Frames.vue';
const worker = new Worker('ffprobe-worker.js');
export default { export default {
name: 'File', name: 'File',
components: { components: {
@@ -49,13 +51,14 @@ export default {
return { return {
file: null, file: null,
data: null, data: null,
info: null,
progress: 0, progress: 0,
showProgress: false, showProgress: false,
} }
}, },
computed: { created() {
info() { worker.onmessage = (e) => {
return this.data && window.Module.get_file_info(); this.info = e.data;
} }
}, },
methods: { methods: {
@@ -65,21 +68,7 @@ export default {
this.showProgress = true; this.showProgress = true;
const file = event.dataTransfer ? event.dataTransfer.files[0] : event.target.files[0]; const file = event.dataTransfer ? event.dataTransfer.files[0] : event.target.files[0];
const reader = new FileReader(); worker.postMessage([ file ]);
// reader.onload = e => this.$emit("load", event.target.result);
reader.onload = (event) => {
this.progress = 100;
this.data = new Uint8Array(event.target.result);
window.Module.FS.writeFile('file', new Uint8Array(this.data));
setTimeout(() => { this.showProgress = false; }, 2000);
}
reader.onprogress = (event) => {
if (event.lengthComputable) {
this.progress = parseInt(((event.loaded / event.total) * 100), 10);
}
}
reader.readAsArrayBuffer(file);
} }
} }
} }

View File

@@ -7,7 +7,7 @@
<b-table stacked :items="items"></b-table> <b-table stacked :items="items"></b-table>
<h4>Streams</h4> <h4>Streams</h4>
<b-table striped hover :items="streams"></b-table> <b-table striped hover :items="info.streams"></b-table>
</div> </div>
</template> </template>
@@ -15,15 +15,6 @@
export default { export default {
name: 'Overview', name: 'Overview',
props: ['info'], props: ['info'],
computed: {
streams() {
const s = [];
for (let i = 0; i < this.info.streams.size(); i++) {
s.push(this.info.streams.get(i));
}
return s;
}
},
data() { data() {
return { return {
items: [ items: [
@@ -38,9 +29,9 @@ export default {
], ],
versions: [ versions: [
{ {
libavutil: window.Module.avutil_version(), libavutil: this.info.versions.libavutil,
libavcodec: window.Module.avcodec_version(), libavcodec: this.info.versions.libavcodec,
libavformat: window.Module.avformat_version(), libavformat: this.info.versions.libavformat,
} }
] ]
} }