Add more bindings for AVFormatContext data. Add Overview page in Vue. Add required CORS headers for supporting SharedArrayBuffer in Firefox.

This commit is contained in:
Alf
2020-09-25 22:13:48 -07:00
parent 039388eaf0
commit 00d4b8fdba
6 changed files with 122 additions and 88 deletions

View File

@@ -1,16 +1,6 @@
# dist/ffmpeg-webtools.js:
# mkdir -p dist && \
# emcc -L/opt/ffmpeg/lib -I/opt/ffmpeg/include/ src/main.c \
# -s EXPORTED_FUNCTIONS='["_c_avformat_version", "_openfile", "_addOne"]' \
# -s EXTRA_EXPORTED_RUNTIME_METHODS="[FS, cwrap, ccall, getValue, setValue, writeAsciiToMemory]" \
# -s INITIAL_MEMORY=268435456 \
# -lavcodec -lavformat -lavfilter -lavdevice -lswresample -lswscale -lavutil -lm -lx264 -pthread \
# -o www/public/ffmpeg-webtools.js
dist/ffmpeg-webtools.js: dist/ffmpeg-webtools.js:
mkdir -p dist && \ mkdir -p dist && \
emcc \ emcc --bind \
--bind \
-L/opt/ffmpeg/lib \ -L/opt/ffmpeg/lib \
-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]" \

View File

@@ -1,38 +0,0 @@
#include <stdio.h>
#include <math.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
void version() {
printf("%s\n", AV_STRINGIFY(LIBAVFORMAT_VERSION));
}
void openfile() {
FILE *file = fopen("testingfs", "rb");
if (!file) {
printf("cannot open file\n");
}
fclose(file);
AVFormatContext *pFormatContext = avformat_alloc_context();
if (!pFormatContext) {
printf("ERROR: could not allocate memory for Format Context\n");
}
printf("opening the input file: %s and loading format (container) header\n", "testingfs");
// Open the file and read header.
int ret;
if ((ret = avformat_open_input(&pFormatContext, "testingfs", NULL, NULL)) < 0) {
printf("ERROR: could not open the file. Error: %d\n", ret);
printf("%s", av_err2str(ret));
}
printf("format: %s, duration: %lld us, bit_rate: %lld\n",
pFormatContext->iformat->name,
pFormatContext->duration,
pFormatContext->bit_rate);
}

View File

@@ -1,29 +1,40 @@
#include <vector>
#include <emscripten.h> #include <emscripten.h>
#include <emscripten/bind.h> #include <emscripten/bind.h>
using namespace emscripten; using namespace emscripten;
extern "C" { extern "C" {
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavutil/avutil.h> #include <libavutil/avutil.h>
};
const std::string c_avformat_version() { const std::string c_avformat_version() {
return AV_STRINGIFY(LIBAVFORMAT_VERSION); return AV_STRINGIFY(LIBAVFORMAT_VERSION);
} }
struct Response { struct Stream {
int id;
int start_time;
int duration;
int codec_type;
};
typedef struct Stream Stream;
struct FileInfoResponse {
std::string name; std::string name;
int bit_rate; int bit_rate;
int duration; int duration;
std::string url;
int nb_streams;
int flags;
std::vector<Stream> streams;
}; };
typedef struct FileInfoResponse FileInfoResponse;
Response c_openfile() { FileInfoResponse get_file_info() {
FILE *file = fopen("testingfs", "rb"); FILE *file = fopen("file", "rb");
if (!file) { if (!file) {
printf("cannot open file\n"); printf("cannot open file\n");
} }
@@ -33,40 +44,65 @@ Response c_openfile() {
if (!pFormatContext) { if (!pFormatContext) {
printf("ERROR: could not allocate memory for Format Context\n"); printf("ERROR: could not allocate memory for Format Context\n");
} }
printf("%p\n", pFormatContext);
printf("opening the input file: %s and loading format (container) header\n", "testingfs");
// Open the file and read header. // Open the file and read header.
int ret; int ret;
if ((ret = avformat_open_input(&pFormatContext, "testingfs", NULL, NULL)) < 0) { if ((ret = avformat_open_input(&pFormatContext, "file", NULL, NULL)) < 0) {
printf("ERROR: could not open the file. Error: %d\n", ret); printf("ERROR: could not open the file. Error: %d\n", ret);
printf("%s", av_err2str(ret)); printf("%s", av_err2str(ret));
} }
printf("format: %s, duration: %lld us, bit_rate: %lld\n", // Initialize response struct with format data.
pFormatContext->iformat->name, FileInfoResponse r = {
pFormatContext->duration, .name = pFormatContext->iformat->name,
pFormatContext->bit_rate); .bit_rate = (int)pFormatContext->bit_rate,
.duration = (int)pFormatContext->duration,
.url = pFormatContext->url,
.nb_streams = (int)pFormatContext->nb_streams,
.flags = pFormatContext->flags
};
Response r; // Get streams data.
r.name = pFormatContext->iformat->name; AVCodec *pCodec = NULL;
r.duration = pFormatContext->duration; AVCodecParameters *pCodecParameters = NULL;
r.bit_rate = pFormatContext->bit_rate; int video_stream_index = -1;
// Loop through the streams and print its information.
for (int i = 0; i < pFormatContext->nb_streams; i++) {
AVCodecParameters *pLocalCodecParameters = NULL;
pLocalCodecParameters = pFormatContext->streams[i]->codecpar;
Stream s = {
.id = (int)pFormatContext->streams[i]->id,
.start_time = (int)pFormatContext->streams[i]->start_time,
.duration = (int)pFormatContext->streams[i]->duration,
.codec_type = (int)pLocalCodecParameters->codec_type
};
r.streams.push_back(s);
}
return r; return r;
} }
};
EMSCRIPTEN_BINDINGS(my_constant_example) { EMSCRIPTEN_BINDINGS(my_constant_example) {
function("c_avformat_version", &c_avformat_version); function("c_avformat_version", &c_avformat_version);
} }
EMSCRIPTEN_BINDINGS(a_struct) { EMSCRIPTEN_BINDINGS(FileInfoResponse_struct) {
emscripten::value_object<Response>("Response") emscripten::value_object<Stream>("Stream")
.field("name", &Response::name) .field("id", &Stream::id)
.field("duration", &Response::duration) .field("start_time", &Stream::start_time)
.field("bit_rate", &Response::bit_rate) .field("duration", &Stream::duration)
.field("codec_type", &Stream::codec_type)
; ;
function("c_openfile", &c_openfile); register_vector<Stream>("Stream");
emscripten::value_object<FileInfoResponse>("FileInfoResponse")
.field("name", &FileInfoResponse::name)
.field("duration", &FileInfoResponse::duration)
.field("bit_rate", &FileInfoResponse::bit_rate)
.field("url", &FileInfoResponse::url)
.field("nb_streams", &FileInfoResponse::nb_streams)
.field("flags", &FileInfoResponse::flags)
.field("streams", &FileInfoResponse::streams)
;
function("get_file_info", &get_file_info);
} }

View File

@@ -20,19 +20,25 @@
<div v-if="data"> <div v-if="data">
<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>
<hr />
{{ info }}
avformat_version: {{ avformat_version }} <b-tabs class="mt-4">
<b-tab title="Overview" class="mt-2">
<div v-if="data">
<Overview :info="info" />
</div>
</b-tab>
</b-tabs>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import Overview from './Overview.vue';
export default { export default {
name: 'File', name: 'File',
components: { components: {
Overview,
}, },
data() { data() {
return { return {
@@ -44,18 +50,10 @@ export default {
}, },
computed: { computed: {
avformat_version() { avformat_version() {
// return window.Module.ccall('c_avformat_version', 'string');
return window.Module.c_avformat_version(); return window.Module.c_avformat_version();
}, },
info() { info() {
const data = this.data; return this.data && window.Module.get_file_info();
console.log('writing data to memfs');
window.Module.FS.writeFile('testingfs', new Uint8Array(data));
console.log('writing data to memfs done');
// window.Module.ccall('version');
// Window.Module.ccall('openfile');
return 'info';
} }
}, },
methods: { methods: {
@@ -71,6 +69,7 @@ export default {
reader.onload = (event) => { reader.onload = (event) => {
this.progress = 100; this.progress = 100;
this.data = new Uint8Array(event.target.result); this.data = new Uint8Array(event.target.result);
window.Module.FS.writeFile('file', new Uint8Array(this.data));
setTimeout(() => { this.showProgress = false; }, 2000); setTimeout(() => { this.showProgress = false; }, 2000);
} }
reader.onprogress = (event) => { reader.onprogress = (event) => {

View File

@@ -0,0 +1,39 @@
<template>
<div>
<h4>AVContext Info</h4>
<b-table stacked :items="items"></b-table>
<h4>AVContext Streams</h4>
<b-table striped hover :items="streams"></b-table>
</div>
</template>
<script>
export default {
name: 'Overview',
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() {
return {
items: [
{
name: this.info.name,
duration: this.info.duration,
bit_rate: this.info.bit_rate,
url: this.info.url,
nb_streams: this.info.nb_streams,
flags: this.info.flags,
},
]
}
}
}
</script>

View File

@@ -8,4 +8,12 @@ module.exports = {
publicPath: process.env.NODE_ENV === 'production' publicPath: process.env.NODE_ENV === 'production'
? '/ffmpeg-webtools/' ? '/ffmpeg-webtools/'
: '/', : '/',
configureWebpack: {
devServer: {
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
}
}
},
}; };