diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2012-11-13 09:55:24 +0100 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2012-11-13 09:55:24 +0100 |
commit | 9ef73e44ebbe9ee63bb364fe5afe530077687df5 (patch) | |
tree | d236875060320fe41ae38f336f3fdcae611bc635 /src/video_decode.c | |
parent | e98457cea9e3c1b7603ef928c293bacdefb3124d (diff) | |
download | advtime-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.c | 151 |
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); +} |