summaryrefslogtreecommitdiff
path: root/src/video_decode.c
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2012-11-13 09:55:24 +0100
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2012-11-13 09:55:24 +0100
commit9ef73e44ebbe9ee63bb364fe5afe530077687df5 (patch)
treed236875060320fe41ae38f336f3fdcae611bc635 /src/video_decode.c
parente98457cea9e3c1b7603ef928c293bacdefb3124d (diff)
downloadadvtime-9ef73e44ebbe9ee63bb364fe5afe530077687df5.tar.gz
advtime-9ef73e44ebbe9ee63bb364fe5afe530077687df5.tar.bz2
advtime-9ef73e44ebbe9ee63bb364fe5afe530077687df5.zip
Add very simple abstraction [video_decode.c] of libav
..and an example program using it: frame_to_pgm.
Diffstat (limited to 'src/video_decode.c')
-rw-r--r--src/video_decode.c151
1 files changed, 151 insertions, 0 deletions
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);
+}