forked from forks/ffprobe-wasm
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:
@@ -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.
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -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
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user