forked from forks/ffprobe-wasm
Read frames from file and add to table.
This commit is contained in:
6
Makefile
6
Makefile
@@ -4,9 +4,9 @@ dist/ffprobe-wasm.js:
|
||||
-O3 \
|
||||
-L/opt/ffmpeg/lib \
|
||||
-I/opt/ffmpeg/include/ \
|
||||
-s EXTRA_EXPORTED_RUNTIME_METHODS="[FS, cwrap, ccall, getValue, setValue, writeAsciiToMemory]" \
|
||||
-s INITIAL_MEMORY=268435456 \
|
||||
-s EXTRA_EXPORTED_RUNTIME_METHODS="[FS, cwrap, ccall, getValue, setValue, writeAsciiToMemory]" \
|
||||
-s INITIAL_MEMORY=268435456 \
|
||||
-pthread \
|
||||
-lavcodec -lavformat -lavfilter -lavdevice -lswresample -lswscale -lavutil -lm -lx264 -pthread \
|
||||
-lavcodec -lavformat -lavfilter -lavdevice -lswresample -lswscale -lavutil -lm -lx264 -pthread \
|
||||
-o dist/ffprobe-wasm.js \
|
||||
src/ffprobe-wasm-wrapper.cpp
|
||||
@@ -34,6 +34,12 @@ typedef struct Stream {
|
||||
int frame_size;
|
||||
} Stream;
|
||||
|
||||
typedef struct Frame {
|
||||
char pict_type;
|
||||
int frame_number;
|
||||
int pkt_size;
|
||||
} Frame;
|
||||
|
||||
typedef struct FileInfoResponse {
|
||||
std::string name;
|
||||
int bit_rate;
|
||||
@@ -44,6 +50,10 @@ typedef struct FileInfoResponse {
|
||||
std::vector<Stream> streams;
|
||||
} FileInfoResponse;
|
||||
|
||||
typedef struct FramesResponse {
|
||||
std::vector<Frame> frames;
|
||||
} FramesResponse;
|
||||
|
||||
FileInfoResponse get_file_info() {
|
||||
FILE *file = fopen("file", "rb");
|
||||
if (!file) {
|
||||
@@ -79,11 +89,11 @@ FileInfoResponse get_file_info() {
|
||||
};
|
||||
|
||||
// Get streams data.
|
||||
AVCodec *pCodec = NULL;
|
||||
AVCodecParameters *pCodecParameters = NULL;
|
||||
int video_stream_index = -1;
|
||||
// AVCodec *pCodec = NULL;
|
||||
// AVCodecParameters *pCodecParameters = NULL;
|
||||
// int video_stream_index = -1;
|
||||
|
||||
// Loop through the streams and print its information.
|
||||
// Loop through the streams.
|
||||
for (int i = 0; i < pFormatContext->nb_streams; i++) {
|
||||
AVCodecParameters *pLocalCodecParameters = NULL;
|
||||
pLocalCodecParameters = pFormatContext->streams[i]->codecpar;
|
||||
@@ -118,6 +128,87 @@ FileInfoResponse get_file_info() {
|
||||
return r;
|
||||
}
|
||||
|
||||
FramesResponse get_frames() {
|
||||
av_log_set_level(AV_LOG_QUIET); // No logging output for libav.
|
||||
|
||||
FILE *file = fopen("file", "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");
|
||||
}
|
||||
|
||||
// Open the file and read header.
|
||||
int ret;
|
||||
if ((ret = avformat_open_input(&pFormatContext, "file", NULL, NULL)) < 0) {
|
||||
printf("ERROR: could not open the file. Error: %d\n", ret);
|
||||
printf("%s", av_err2str(ret));
|
||||
}
|
||||
|
||||
// Get stream info from format.
|
||||
if (avformat_find_stream_info(pFormatContext, NULL) < 0) {
|
||||
printf("ERROR: could not get stream info\n");
|
||||
}
|
||||
|
||||
// Get streams data.
|
||||
AVCodec *pCodec = NULL;
|
||||
AVCodecParameters *pCodecParameters = NULL;
|
||||
int video_stream_index = -1;
|
||||
|
||||
// Loop through the streams.
|
||||
for (int i = 0; i < pFormatContext->nb_streams; i++) {
|
||||
AVCodecParameters *pLocalCodecParameters = NULL;
|
||||
pLocalCodecParameters = pFormatContext->streams[i]->codecpar;
|
||||
|
||||
// Print out the decoded frame info.
|
||||
AVCodec *pLocalCodec = avcodec_find_decoder(pLocalCodecParameters->codec_id);
|
||||
if (pLocalCodecParameters->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
if (video_stream_index == -1) {
|
||||
video_stream_index = i;
|
||||
pCodec = pLocalCodec;
|
||||
pCodecParameters = pLocalCodecParameters;
|
||||
}
|
||||
|
||||
printf("Video Codec: resolution %d x %d\n",
|
||||
pLocalCodecParameters->width, pLocalCodecParameters->height);
|
||||
} else if (pLocalCodecParameters->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
printf("Audio Codec: %d channels, sample rate %d\n",
|
||||
pLocalCodecParameters->channels, pLocalCodecParameters->sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
FramesResponse r;
|
||||
|
||||
AVCodecContext *pCodecContext = avcodec_alloc_context3(pCodec);
|
||||
avcodec_parameters_to_context(pCodecContext, pCodecParameters);
|
||||
avcodec_open2(pCodecContext, pCodec, NULL);
|
||||
|
||||
AVPacket *pPacket = av_packet_alloc();
|
||||
AVFrame *pFrame = av_frame_alloc();
|
||||
|
||||
int how_many_packets_to_process = 100;
|
||||
// av_seek_frame(pFormatContext, 1, 1001*30, AVSEEK_FLAG_ANY);
|
||||
while (av_read_frame(pFormatContext, pPacket) >= 0) {
|
||||
if (pPacket->stream_index == video_stream_index) {
|
||||
|
||||
avcodec_send_packet(pCodecContext, pPacket);
|
||||
avcodec_receive_frame(pCodecContext, pFrame);
|
||||
Frame f = {
|
||||
.pict_type = (char) av_get_picture_type_char(pFrame->pict_type),
|
||||
.frame_number = pCodecContext->frame_number,
|
||||
.pkt_size = pFrame->pkt_size,
|
||||
};
|
||||
r.frames.push_back(f);
|
||||
}
|
||||
if (--how_many_packets_to_process <= 0) break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_BINDINGS(my_constant_example) {
|
||||
function("c_avformat_version", &c_avformat_version);
|
||||
@@ -142,6 +233,12 @@ EMSCRIPTEN_BINDINGS(FileInfoResponse_struct) {
|
||||
;
|
||||
register_vector<Stream>("Stream");
|
||||
|
||||
emscripten::value_object<Frame>("Frame")
|
||||
.field("frame_type", &Frame::pict_type)
|
||||
.field("frame_number", &Frame::frame_number)
|
||||
.field("frame_size", &Frame::pkt_size);
|
||||
register_vector<Frame>("Frame");
|
||||
|
||||
emscripten::value_object<FileInfoResponse>("FileInfoResponse")
|
||||
.field("name", &FileInfoResponse::name)
|
||||
.field("duration", &FileInfoResponse::duration)
|
||||
@@ -152,4 +249,9 @@ EMSCRIPTEN_BINDINGS(FileInfoResponse_struct) {
|
||||
.field("streams", &FileInfoResponse::streams)
|
||||
;
|
||||
function("get_file_info", &get_file_info);
|
||||
|
||||
emscripten::value_object<FramesResponse>("FramesResponse")
|
||||
.field("frames", &FramesResponse::frames)
|
||||
;
|
||||
function("get_frames", &get_frames);
|
||||
}
|
||||
@@ -28,7 +28,9 @@
|
||||
</div>
|
||||
</b-tab>
|
||||
<b-tab title="Streams" class="mt-2" disabled></b-tab>
|
||||
<b-tab title="Frames" class="mt-2" disabled></b-tab>
|
||||
<b-tab title="Frames" class="mt-2" lazy>
|
||||
<Frames />
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
</div>
|
||||
</div>
|
||||
@@ -36,11 +38,13 @@
|
||||
|
||||
<script>
|
||||
import Overview from './Overview.vue';
|
||||
import Frames from './Frames.vue';
|
||||
|
||||
export default {
|
||||
name: 'File',
|
||||
components: {
|
||||
Overview,
|
||||
Frames,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -83,11 +87,4 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tree-view {
|
||||
overflow: auto;
|
||||
height: 60vh;
|
||||
}
|
||||
</style>
|
||||
</script>
|
||||
35
www/src/components/Frames.vue
Normal file
35
www/src/components/Frames.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<h4>Frames</h4>
|
||||
<b-table striped hover :items="frames">
|
||||
<template #cell(frame_type)="data">
|
||||
{{ String.fromCharCode(data.value) }}
|
||||
</template>
|
||||
|
||||
</b-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Frames',
|
||||
props: [''],
|
||||
data() {
|
||||
return {
|
||||
data: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
frames() {
|
||||
const s = [];
|
||||
for (let i = 0; i < this.data.frames.size(); i++) {
|
||||
s.push(this.data.frames.get(i));
|
||||
}
|
||||
return s;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.data = window.Module.get_frames();
|
||||
},
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user