From 48507f53a64269453d8b5c99c2aaaa107c15769f Mon Sep 17 00:00:00 2001 From: Alfred Gutierrez Date: Sat, 28 May 2022 16:48:14 -0700 Subject: [PATCH] Add stream metadata tags. (#17) --- src/ffprobe-wasm-wrapper.cpp | 35 +++++++++++++------ www/public/ffprobe-worker.js | 19 ++++++----- www/src/components/Overview.vue | 60 ++++++++++++++++++++++++++++++--- 3 files changed, 90 insertions(+), 24 deletions(-) diff --git a/src/ffprobe-wasm-wrapper.cpp b/src/ffprobe-wasm-wrapper.cpp index 950f062..54b37f6 100644 --- a/src/ffprobe-wasm-wrapper.cpp +++ b/src/ffprobe-wasm-wrapper.cpp @@ -27,6 +27,11 @@ const std::string c_avutil_version() { return AV_STRINGIFY(LIBAVUTIL_VERSION); } +typedef struct Tag { + std::string key; + std::string value; +} Tag; + typedef struct Stream { int id; int start_time; @@ -42,13 +47,9 @@ typedef struct Stream { int channels; int sample_rate; int frame_size; + std::vector tags; } Stream; -typedef struct Tag { - std::string key; - std::string value; -} Tag; - typedef struct Chapter { int id; std::string time_base; @@ -152,6 +153,17 @@ FileInfoResponse get_file_info(std::string filename) { .sample_rate = (int)pLocalCodecParameters->sample_rate, .frame_size = (int)pLocalCodecParameters->frame_size, }; + + // Add tags to stream. + const AVDictionaryEntry *tag = NULL; + while ((tag = av_dict_get(pFormatContext->streams[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { + Tag t = { + .key = tag->key, + .value = tag->value, + }; + stream.tags.push_back(t); + } + r.streams.push_back(stream); free(fourcc); } @@ -322,6 +334,12 @@ EMSCRIPTEN_BINDINGS(constants) { } EMSCRIPTEN_BINDINGS(structs) { + emscripten::value_object("Tag") + .field("key", &Tag::key) + .field("value", &Tag::value) + ; + register_vector("Tag"); + emscripten::value_object("Stream") .field("id", &Stream::id) .field("start_time", &Stream::start_time) @@ -337,15 +355,10 @@ EMSCRIPTEN_BINDINGS(structs) { .field("channels", &Stream::channels) .field("sample_rate", &Stream::sample_rate) .field("frame_size", &Stream::frame_size) + .field("tags", &Stream::tags) ; register_vector("Stream"); - emscripten::value_object("Tag") - .field("key", &Tag::key) - .field("value", &Tag::value) - ; - register_vector("Tag"); - emscripten::value_object("Chapter") .field("id", &Chapter::id) .field("time_base", &Chapter::time_base) diff --git a/www/public/ffprobe-worker.js b/www/public/ffprobe-worker.js index 4b33fc2..b47783b 100644 --- a/www/public/ffprobe-worker.js +++ b/www/public/ffprobe-worker.js @@ -18,19 +18,22 @@ onmessage = (e) => { // Remap streams into collection. const s = []; for (let i = 0; i < info.streams.size(); i++) { - s.push(info.streams.get(i)); + const tags = {}; + for (let j = 0; j < info.streams.get(i).tags.size(); j++) { + const t = info.streams.get(i).tags.get(j); + tags[t.key] = t.value; + } + s.push({...info.streams.get(i), ...{ tags}}); } // Remap chapters into collection. const c = []; for (let i = 0; i < info.chapters.size(); i++) { - const t = info.chapters.get(i).tags.get(0); - - // Remap tags too. - const tags = []; - const obj = {}; - obj[t.key] = t.value; - tags.push(obj); + const tags = {}; + for (let j = 0; j < info.chapters.get(i).tags.size(); j++) { + const t = info.chapters.get(i).tags.get(j); + tags[t.key] = t.value; + } c.push({...info.chapters.get(i), ...{tags}}); } diff --git a/www/src/components/Overview.vue b/www/src/components/Overview.vue index 518d2f4..995a2a9 100644 --- a/www/src/components/Overview.vue +++ b/www/src/components/Overview.vue @@ -7,14 +7,42 @@

Streams

- + + + +

Chapters

- - + + +
@@ -24,6 +52,28 @@ export default { name: 'Overview', props: ['info'], + data() { + return { + stream_fields: [ + 'id', + 'start_time', + 'duration', + 'codec_type', + 'codec_name', + 'format', + 'bit_rate', + 'profile', + 'level', + 'width', + 'height', + 'channels', + 'sample_rate', + 'frame_size', + { key: 'show_details', label: 'Tags' }, + ], + chapter_fields: ['id', 'time_base', 'start', 'end', { key: 'show_details', label: 'Tags' }], + } + }, computed: { items() { return [