Add stream metadata tags. (#17)

This commit is contained in:
Alfred Gutierrez
2022-05-28 16:48:14 -07:00
committed by GitHub
parent ff36b01373
commit 48507f53a6
3 changed files with 90 additions and 24 deletions

View File

@@ -27,6 +27,11 @@ const std::string c_avutil_version() {
return AV_STRINGIFY(LIBAVUTIL_VERSION); return AV_STRINGIFY(LIBAVUTIL_VERSION);
} }
typedef struct Tag {
std::string key;
std::string value;
} Tag;
typedef struct Stream { typedef struct Stream {
int id; int id;
int start_time; int start_time;
@@ -42,13 +47,9 @@ typedef struct Stream {
int channels; int channels;
int sample_rate; int sample_rate;
int frame_size; int frame_size;
std::vector<Tag> tags;
} Stream; } Stream;
typedef struct Tag {
std::string key;
std::string value;
} Tag;
typedef struct Chapter { typedef struct Chapter {
int id; int id;
std::string time_base; std::string time_base;
@@ -152,6 +153,17 @@ FileInfoResponse get_file_info(std::string filename) {
.sample_rate = (int)pLocalCodecParameters->sample_rate, .sample_rate = (int)pLocalCodecParameters->sample_rate,
.frame_size = (int)pLocalCodecParameters->frame_size, .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); r.streams.push_back(stream);
free(fourcc); free(fourcc);
} }
@@ -322,6 +334,12 @@ EMSCRIPTEN_BINDINGS(constants) {
} }
EMSCRIPTEN_BINDINGS(structs) { EMSCRIPTEN_BINDINGS(structs) {
emscripten::value_object<Tag>("Tag")
.field("key", &Tag::key)
.field("value", &Tag::value)
;
register_vector<Tag>("Tag");
emscripten::value_object<Stream>("Stream") emscripten::value_object<Stream>("Stream")
.field("id", &Stream::id) .field("id", &Stream::id)
.field("start_time", &Stream::start_time) .field("start_time", &Stream::start_time)
@@ -337,15 +355,10 @@ EMSCRIPTEN_BINDINGS(structs) {
.field("channels", &Stream::channels) .field("channels", &Stream::channels)
.field("sample_rate", &Stream::sample_rate) .field("sample_rate", &Stream::sample_rate)
.field("frame_size", &Stream::frame_size) .field("frame_size", &Stream::frame_size)
.field("tags", &Stream::tags)
; ;
register_vector<Stream>("Stream"); register_vector<Stream>("Stream");
emscripten::value_object<Tag>("Tag")
.field("key", &Tag::key)
.field("value", &Tag::value)
;
register_vector<Tag>("Tag");
emscripten::value_object<Chapter>("Chapter") emscripten::value_object<Chapter>("Chapter")
.field("id", &Chapter::id) .field("id", &Chapter::id)
.field("time_base", &Chapter::time_base) .field("time_base", &Chapter::time_base)

View File

@@ -18,19 +18,22 @@ onmessage = (e) => {
// Remap streams into collection. // Remap streams into collection.
const s = []; const s = [];
for (let i = 0; i < info.streams.size(); i++) { 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. // Remap chapters into collection.
const c = []; const c = [];
for (let i = 0; i < info.chapters.size(); i++) { for (let i = 0; i < info.chapters.size(); i++) {
const t = info.chapters.get(i).tags.get(0); const tags = {};
for (let j = 0; j < info.chapters.get(i).tags.size(); j++) {
// Remap tags too. const t = info.chapters.get(i).tags.get(j);
const tags = []; tags[t.key] = t.value;
const obj = {}; }
obj[t.key] = t.value;
tags.push(obj);
c.push({...info.chapters.get(i), ...{tags}}); c.push({...info.chapters.get(i), ...{tags}});
} }

View File

@@ -7,13 +7,41 @@
<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="info.streams"></b-table> <b-table striped hover :items="info.streams" :fields="stream_fields">
<template #cell(show_details)="row">
<b-button size="sm" @click="row.toggleDetails" class="mr-2">
{{ row.detailsShowing ? 'Hide' : 'Show'}}
</b-button>
</template>
<template #row-details="row">
<b-card>
<div v-for="(value, key) in row.item.tags" :key="key">
<b-row class="mb-2">
<b-col sm="3" class="text-sm-right"><b>{{ key }}:</b></b-col>
<b-col>{{ value }}</b-col>
</b-row>
</div>
</b-card>
</template>
</b-table>
<div v-show="info.chapters.length > 0"> <div v-show="info.chapters.length > 0">
<h4>Chapters</h4> <h4>Chapters</h4>
<b-table striped hover :items="info.chapters"> <b-table striped hover :items="info.chapters" :fields="chapter_fields">
<template #cell(tags)="data"> <template #cell(show_details)="row">
<b-table-lite small stacked outlined :items="data.item.tags"></b-table-lite> <b-button size="sm" @click="row.toggleDetails" class="mr-2">
{{ row.detailsShowing ? 'Hide' : 'Show'}}
</b-button>
</template>
<template #row-details="row">
<b-card>
<div v-for="(value, key) in row.item.tags" :key="key">
<b-row class="mb-2">
<b-col sm="3" class="text-sm-right"><b>{{ key }}:</b></b-col>
<b-col>{{ value }}</b-col>
</b-row>
</div>
</b-card>
</template> </template>
</b-table> </b-table>
</div> </div>
@@ -24,6 +52,28 @@
export default { export default {
name: 'Overview', name: 'Overview',
props: ['info'], 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: { computed: {
items() { items() {
return [ return [