diff options
-rw-r--r-- | src/.gitignore | 1 | ||||
-rw-r--r-- | src/Makefile | 6 | ||||
-rw-r--r-- | src/decode_frame.c | 180 |
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; +} |