forked from forks/ffprobe-wasm
Merge pull request #8 from alfg/gop-size-pagination
Use gop size for perPage results. #3
This commit is contained in:
@@ -64,6 +64,7 @@ typedef struct FileInfoResponse {
|
|||||||
typedef struct FramesResponse {
|
typedef struct FramesResponse {
|
||||||
std::vector<Frame> frames;
|
std::vector<Frame> frames;
|
||||||
int nb_frames;
|
int nb_frames;
|
||||||
|
int gop_size;
|
||||||
} FramesResponse;
|
} FramesResponse;
|
||||||
|
|
||||||
FileInfoResponse get_file_info(std::string filename) {
|
FileInfoResponse get_file_info(std::string filename) {
|
||||||
@@ -200,8 +201,10 @@ FramesResponse get_frames(std::string filename, int offset) {
|
|||||||
AVPacket *pPacket = av_packet_alloc();
|
AVPacket *pPacket = av_packet_alloc();
|
||||||
AVFrame *pFrame = av_frame_alloc();
|
AVFrame *pFrame = av_frame_alloc();
|
||||||
|
|
||||||
int how_many_packets_to_process = 48; // per page.
|
int max_packets_to_process = 1000;
|
||||||
int frame_count = 1;
|
int frame_count = 0;
|
||||||
|
int key_frames = 0;
|
||||||
|
int gop_size = 0;
|
||||||
|
|
||||||
// Read video frames.
|
// Read video frames.
|
||||||
while (av_read_frame(pFormatContext, pPacket) >= 0) {
|
while (av_read_frame(pFormatContext, pPacket) >= 0) {
|
||||||
@@ -217,6 +220,12 @@ FramesResponse get_frames(std::string filename, int offset) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track keyframes so we paginate by each GOP.
|
||||||
|
if (pFrame->key_frame == 1) key_frames++;
|
||||||
|
|
||||||
|
// Break at the next keyframe found.
|
||||||
|
if (key_frames > 1) break;
|
||||||
|
|
||||||
Frame f = {
|
Frame f = {
|
||||||
.frame_number = frame_count,
|
.frame_number = frame_count,
|
||||||
.pict_type = (char) av_get_picture_type_char(pFrame->pict_type),
|
.pict_type = (char) av_get_picture_type_char(pFrame->pict_type),
|
||||||
@@ -226,7 +235,7 @@ FramesResponse get_frames(std::string filename, int offset) {
|
|||||||
};
|
};
|
||||||
r.frames.push_back(f);
|
r.frames.push_back(f);
|
||||||
|
|
||||||
if (--how_many_packets_to_process <= 0) break;
|
if (--max_packets_to_process <= 0) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame_count++;
|
frame_count++;
|
||||||
@@ -237,6 +246,8 @@ FramesResponse get_frames(std::string filename, int offset) {
|
|||||||
av_packet_free(&pPacket);
|
av_packet_free(&pPacket);
|
||||||
av_frame_free(&pFrame);
|
av_frame_free(&pFrame);
|
||||||
avcodec_free_context(&pCodecContext);
|
avcodec_free_context(&pCodecContext);
|
||||||
|
|
||||||
|
r.gop_size = frame_count - offset;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +298,7 @@ EMSCRIPTEN_BINDINGS(structs) {
|
|||||||
emscripten::value_object<FramesResponse>("FramesResponse")
|
emscripten::value_object<FramesResponse>("FramesResponse")
|
||||||
.field("frames", &FramesResponse::frames)
|
.field("frames", &FramesResponse::frames)
|
||||||
.field("nb_frames", &FramesResponse::nb_frames)
|
.field("nb_frames", &FramesResponse::nb_frames)
|
||||||
|
.field("gop_size", &FramesResponse::gop_size)
|
||||||
;
|
;
|
||||||
function("get_frames", &get_frames);
|
function("get_frames", &get_frames);
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<div v-if="info">
|
<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" v-model="tabIndex">
|
||||||
<b-tab title="Overview" class="mt-2">
|
<b-tab title="Overview" class="mt-2">
|
||||||
<div v-if="info">
|
<div v-if="info">
|
||||||
<Overview :info="info" />
|
<Overview :info="info" />
|
||||||
@@ -42,18 +42,16 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
file: null,
|
file: null,
|
||||||
data: null,
|
|
||||||
info: null,
|
info: null,
|
||||||
}
|
tabIndex: 0,
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.$worker.onmessage = (e) => {
|
|
||||||
this.info = e.data;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onFile(event) {
|
onFile(event) {
|
||||||
this.data = null;
|
this.tabIndex = 0;
|
||||||
|
this.$worker.onmessage = (e) => {
|
||||||
|
this.info = e.data;
|
||||||
|
}
|
||||||
const file = event.dataTransfer ? event.dataTransfer.files[0] : event.target.files[0];
|
const file = event.dataTransfer ? event.dataTransfer.files[0] : event.target.files[0];
|
||||||
this.$worker.postMessage([ 'get_file_info', file ]);
|
this.$worker.postMessage([ 'get_file_info', file ]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<h4>Frames</h4>
|
<h4>Frames</h4>
|
||||||
<div v-if="!data">Loading...</div>
|
<div v-if="!data">Loading...</div>
|
||||||
<div v-if="data">
|
<div v-if="data">
|
||||||
|
<p class="float-left">GOP Size: {{ data.gop_size }}</p>
|
||||||
<p class="text-right">Total: {{ data.nb_frames }}</p>
|
<p class="text-right">Total: {{ data.nb_frames }}</p>
|
||||||
|
|
||||||
<b-pagination
|
<b-pagination
|
||||||
@@ -19,6 +20,9 @@
|
|||||||
<b-spinner class="align-middle"></b-spinner>
|
<b-spinner class="align-middle"></b-spinner>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template #cell(frame_number)="data">
|
||||||
|
{{ data.value + 1 }}
|
||||||
|
</template>
|
||||||
<template #cell(pict_type)="data">
|
<template #cell(pict_type)="data">
|
||||||
{{ String.fromCharCode(data.value) }}
|
{{ String.fromCharCode(data.value) }}
|
||||||
</template>
|
</template>
|
||||||
@@ -43,11 +47,13 @@ export default {
|
|||||||
return {
|
return {
|
||||||
data: null,
|
data: null,
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
perPage: 48,
|
|
||||||
isBusy: false,
|
isBusy: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
perPage() {
|
||||||
|
return this.data.gop_size;
|
||||||
|
},
|
||||||
pages() {
|
pages() {
|
||||||
return this.data.nb_frames;
|
return this.data.nb_frames;
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user