diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile | 7 | ||||
| -rw-r--r-- | src/frame_to_pgm.c | 44 | ||||
| -rw-r--r-- | src/video_decode.c | 151 | ||||
| -rw-r--r-- | src/video_decode.h | 19 | 
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);  | 
