summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile7
-rw-r--r--src/frame_to_pgm.c44
-rw-r--r--src/video_decode.c151
-rw-r--r--src/video_decode.h19
4 files changed, 219 insertions, 2 deletions
diff --git a/src/Makefile b/src/Makefile
index 29ffd29..fbdb424 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,11 +1,14 @@
-CFLAGS=-std=c99 -Wall
+CFLAGS=-std=c99 -Wall -Wstrict-prototypes -Wmissing-prototypes -Wno-unused-parameter
LibAV=`pkg-config --cflags --libs libavcodec`
LIBAV_DECODE_FLAGS=$(shell pkg-config --libs --cflags libavformat libavcodec libavutil libswscale)
-all: advtime decode_frame
+all: advtime decode_frame frame_to_pgm
advtime: advtime.c
gcc ${LibAV} advtime.c -o $@
decode_frame: decode_frame.c
gcc $(CFLAGS) $(LIBAV_DECODE_FLAGS) decode_frame.c -o $@
+
+frame_to_pgm: frame_to_pgm.c video_decode.c
+ gcc $(CFLAGS) $(LIBAV_DECODE_FLAGS) frame_to_pgm.c video_decode.c -o $@
diff --git a/src/frame_to_pgm.c b/src/frame_to_pgm.c
new file mode 100644
index 0000000..f018099
--- /dev/null
+++ b/src/frame_to_pgm.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "video_decode.h"
+
+static void
+pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, char *filename)
+{
+ FILE *f;
+ int i;
+
+ f = fopen(filename, "w");
+ fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
+ for(i=0; i < ysize; i++)
+ fwrite(buf + i * wrap, 1, xsize, f);
+ fclose(f);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct video_decode *vd;
+ struct video_frame *frame;
+ int ret;
+ int64_t timestamp = 0;
+
+ if (argc < 3)
+ return 1;
+
+ if (argc == 4 && strtol(argv[3], NULL, 10) > 0)
+ timestamp = strtol(argv[3], NULL, 10);
+
+ ret = video_decode_init(&vd, argv[1], timestamp);
+ if (ret < 0)
+ return -ret;
+
+ ret = video_decode_get_frame(vd, &frame);
+ if (ret < 0)
+ return -ret;
+
+ pgm_save(frame->data, frame->stride, frame->width, frame->height,
+ argv[2]);
+}
diff --git a/src/video_decode.c b/src/video_decode.c
new file mode 100644
index 0000000..87d3483
--- /dev/null
+++ b/src/video_decode.c
@@ -0,0 +1,151 @@
+#define DEBUG 1
+#include "video_decode.h"
+
+#include <libavutil/avutil.h>
+#include <libavformat/avformat.h>
+#include <libavcodec/avcodec.h>
+#include <libswscale/swscale.h>
+
+
+struct video_decode {
+ AVFormatContext *fmt_ctx;
+ AVCodecContext *codec_ctx;
+ AVCodec *codec;
+ int stream;
+};
+
+struct video_frame_priv {
+ struct video_frame base;
+ AVFrame *frame;
+};
+
+int
+video_decode_init(struct video_decode **vd_out, char *file, int64_t ts)
+{
+ struct video_decode *vd;
+
+ vd = calloc(1, sizeof *vd);
+ if (vd == NULL)
+ return -1;
+
+ av_register_all();
+
+ vd->fmt_ctx = NULL;
+ vd->codec_ctx = NULL;
+
+ if (avformat_open_input(&vd->fmt_ctx, file, NULL, NULL) != 0)
+ return -1;
+
+ if (avformat_find_stream_info(vd->fmt_ctx, NULL) < 0)
+ return -2;
+#if DEBUG
+ av_dump_format(vd->fmt_ctx, 0, file, 0);
+#endif
+ vd->stream = av_find_best_stream(vd->fmt_ctx, AVMEDIA_TYPE_VIDEO,
+ -1, -1, NULL, 0);
+ if (vd->stream == -1)
+ return -3;
+
+ vd->codec_ctx = vd->fmt_ctx->streams[vd->stream]->codec;
+
+ if (vd->fmt_ctx->start_time != AV_NOPTS_VALUE)
+ ts += vd->fmt_ctx->start_time;
+ /* FIXME: Check size */
+ avformat_seek_file(vd->fmt_ctx, vd->stream, INT64_MIN, ts, INT64_MAX,0);
+
+ vd->codec = avcodec_find_decoder(vd->codec_ctx->codec_id);
+ if (vd->codec == NULL) {
+ fprintf(stderr, "Failed to find decoder!\n");
+ return -4;
+ }
+#if DEBUG
+ printf("has cap truncated: %d\n",
+ vd->codec->capabilities & CODEC_CAP_TRUNCATED);
+#endif
+#if 0
+ if (codec->capabilities & CODEC_CAP_TRUNCATED)
+ codec_ctx->flags |= CODEC_FLAG_TRUNCATED;
+#endif
+ if (avcodec_open2(vd->codec_ctx, vd->codec, NULL) < 0) {
+ fprintf(stderr, "Failed to open codec!\n");
+ return -5;
+ }
+
+ *vd_out = vd;
+ return 0;
+}
+
+void
+video_decode_uninit(struct video_decode **_vd)
+{
+ struct video_decode *vd = *_vd;
+
+ *_vd = NULL;
+ avcodec_close(vd->codec_ctx);
+ avformat_close_input(&vd->fmt_ctx);
+ free(vd);
+}
+
+int
+video_decode_get_frame(struct video_decode *vd, struct video_frame **frame)
+{
+ struct video_frame_priv *f;
+ AVPacket packet;
+ int decoded, got_picture;
+
+ f = calloc(1, sizeof *f);
+ if (f == NULL)
+ return -1;
+
+ packet.data = NULL;
+ do {
+ if (packet.data != NULL)
+ av_free_packet(&packet);
+ if (av_read_frame(vd->fmt_ctx, &packet) < 0) {
+ fprintf(stderr, "Found no video stream packet!\n");
+ return -1;
+ }
+ } while (packet.stream_index != vd->stream);
+
+ f->frame = avcodec_alloc_frame();
+
+ do {
+#if DEBUG
+ printf("packet.data: %p, packet.siz: %d, packet.strm_idx: %d\n",
+ packet.data, packet.size, packet.stream_index);
+#endif
+ decoded = avcodec_decode_video2(vd->codec_ctx, f->frame,
+ &got_picture, &packet);
+ if (decoded < 0) {
+ fprintf(stderr, "Error while decoding frame!\n");
+ return -2;
+ }
+#if DEBUG
+ printf("bytes_decoded: %d, got_picture: %d\n",
+ decoded, got_picture);
+#endif
+
+ } while (got_picture == 0 && packet.size > 0);
+ av_free_packet(&packet);
+ if (got_picture == 0)
+ return -3;
+
+ f->base.data = f->frame->data[0];
+ f->base.width = vd->codec_ctx->width;
+ f->base.height = vd->codec_ctx->height;
+ f->base.stride = f->frame->linesize[0];
+
+ *frame = &f->base;
+
+ return 0;
+}
+
+void
+video_decode_free_frame(struct video_frame **frame)
+{
+ struct video_frame_priv *f = (struct video_frame_priv *) *frame;
+
+ *frame = NULL;
+ av_free(f->frame);
+ free(f);
+}
diff --git a/src/video_decode.h b/src/video_decode.h
new file mode 100644
index 0000000..64127f3
--- /dev/null
+++ b/src/video_decode.h
@@ -0,0 +1,19 @@
+#include <stdint.h>
+
+struct video_decode;
+struct video_frame {
+ uint8_t *data;
+ int width, height, stride;
+};
+
+int
+video_decode_init(struct video_decode **vd, char *file, int64_t timestamp);
+
+void
+video_decode_uninit(struct video_decode **vd);
+
+int
+video_decode_get_frame(struct video_decode *vd, struct video_frame **frame);
+
+void
+video_decode_free_frame(struct video_frame **frame);