summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile6
-rw-r--r--src/decode_frame.c180
3 files changed, 187 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..75500be
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1 @@
+decode_frame
diff --git a/src/Makefile b/src/Makefile
index f61114a..29ffd29 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,5 +1,11 @@
CFLAGS=-std=c99 -Wall
LibAV=`pkg-config --cflags --libs libavcodec`
+LIBAV_DECODE_FLAGS=$(shell pkg-config --libs --cflags libavformat libavcodec libavutil libswscale)
+
+all: advtime decode_frame
advtime: advtime.c
gcc ${LibAV} advtime.c -o $@
+
+decode_frame: decode_frame.c
+ gcc $(CFLAGS) $(LIBAV_DECODE_FLAGS) decode_frame.c -o $@
diff --git a/src/decode_frame.c b/src/decode_frame.c
new file mode 100644
index 0000000..717e81c
--- /dev/null
+++ b/src/decode_frame.c
@@ -0,0 +1,180 @@
+#define DEBUG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <libavformat/avformat.h>
+#include <libavcodec/avcodec.h>
+#include <libavutil/avutil.h>
+#include <libswscale/swscale.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);
+}
+
+static void
+ppm_save(unsigned char *buf, int wrap, int xsize, int ysize, char *filename)
+{
+ FILE *f;
+ int i;
+
+ f = fopen(filename, "w");
+ fprintf(f,"P6\n%d %d\n%d\n", xsize, ysize, 255);
+ for(i=0; i < ysize; i++)
+ fwrite(buf + i * wrap, 3, xsize, f);
+ fclose(f);
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *filename = argv[1];
+ AVFormatContext *fmt_ctx = NULL;
+ int vid_stream = -1;
+ AVCodecContext *codec_ctx = NULL;
+ AVCodec *codec;
+ AVFrame *frame;
+ AVPacket packet;
+ int bytes_decoded, got_picture;
+ AVFrame *frame_rgb;
+ int nbytes;
+ uint8_t *buffer;
+ struct SwsContext *sws_ctx;
+ int timestamp = 0;
+
+ av_register_all();
+#if DEBUG
+ av_log_set_level(AV_LOG_DEBUG);
+ printf("file: %s\n", filename);
+#endif
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s filename [timestamp]\n", argv[0]);
+ exit(1);
+ }
+ if (avformat_open_input(&fmt_ctx, filename, NULL, NULL) != 0)
+ exit(2);
+
+ if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
+ exit(3);
+
+#if DEBUG
+ av_dump_format(fmt_ctx, 0, filename, 0);
+#endif
+
+ vid_stream = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO,
+ -1, -1, NULL, 0);
+ if (vid_stream == -1)
+ exit(4);
+ codec_ctx = fmt_ctx->streams[vid_stream]->codec;
+
+ timestamp = fmt_ctx->start_time==AV_NOPTS_VALUE ? 0:fmt_ctx->start_time;
+#if 1
+ if (argc == 3 && atoi(argv[2]) > 0)
+ timestamp += atoi(argv[2]);
+#endif
+ avformat_seek_file(fmt_ctx, -1, INT64_MIN, timestamp, INT64_MAX, 0);
+
+ codec = avcodec_find_decoder(codec_ctx->codec_id);
+ if (codec == NULL) {
+ fprintf(stderr, "Failed to find decoder!\n");
+ exit(5);
+ }
+
+#if DEBUG
+ printf("has cap truncated: %d\n",
+ codec->capabilities & CODEC_CAP_TRUNCATED);
+#endif
+#if 0
+ if (codec->capabilities & CODEC_CAP_TRUNCATED)
+ codec_ctx->flags |= CODEC_FLAG_TRUNCATED;
+#endif
+
+ if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
+ fprintf(stderr, "Failed to open codec!\n");
+ exit(6);
+ }
+
+ packet.data = NULL;
+ do {
+ if (packet.data != NULL)
+ av_free_packet(&packet);
+ if (av_read_frame(fmt_ctx, &packet) < 0) {
+ fprintf(stderr, "Found no video stream packet!\n");
+ exit(30);
+ }
+ } while (packet.stream_index != vid_stream);
+
+ frame = avcodec_alloc_frame();
+ do {
+#if DEBUG
+ printf("packet.data: %p, packet.size: %d, packet.stream_index: %d\n",
+ packet.data, packet.size, packet.stream_index);
+#endif
+
+ bytes_decoded = avcodec_decode_video2(codec_ctx, frame,
+ &got_picture, &packet);
+ if (bytes_decoded < 0) {
+ fprintf(stderr, "Error while decoding frame!\n");
+ exit(12);
+ }
+#if DEBUG
+ printf("bytes_decoded: %d, got_picture: %d\n",
+ bytes_decoded, got_picture);
+#endif
+
+ } while (got_picture == 0 && packet.size > 0);
+ av_free_packet(&packet);
+ if (got_picture == 0)
+ exit(9);
+
+ pgm_save(frame->data[0], frame->linesize[0],
+ codec_ctx->width, codec_ctx->height, "foo.pgm");
+
+#define CONVERT_TO_RGB 1
+#if CONVERT_TO_RGB
+ frame_rgb = avcodec_alloc_frame();
+ if (!frame_rgb)
+ exit(9);
+
+ nbytes = avpicture_get_size(PIX_FMT_RGB24,
+ codec_ctx->width, codec_ctx->height);
+ buffer = calloc(nbytes, sizeof(uint8_t));
+ if (!buffer)
+ exit(10);
+ avpicture_fill((AVPicture *) frame_rgb, buffer, PIX_FMT_RGB24,
+ codec_ctx->width, codec_ctx->height);
+
+ sws_ctx = sws_getCachedContext(NULL,
+ codec_ctx->width, codec_ctx->height,
+ codec_ctx->pix_fmt,
+ codec_ctx->width, codec_ctx->height,
+ PIX_FMT_RGB24, SWS_BILINEAR,
+ NULL, NULL, NULL);
+
+ sws_scale(sws_ctx,
+ (const uint8_t *const *) frame->data, frame->linesize, 0,
+ codec_ctx->height, frame_rgb->data, frame_rgb->linesize);
+
+ ppm_save(frame_rgb->data[0], frame_rgb->linesize[0],
+ codec_ctx->width, codec_ctx->height, "foo.ppm");
+#endif
+
+ free(buffer);
+ av_free(frame_rgb);
+ av_free(frame);
+ avcodec_close(codec_ctx);
+ avformat_close_input(&fmt_ctx);
+
+ return 0;
+}