From: Dmitry Kovalev Date: Thu, 6 Feb 2014 02:34:46 +0000 (-0800) Subject: Adding video reader/writer APIs. X-Git-Tag: v1.4.0~2467^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=37e6fd3d765e192f24de65c472fb0cef6a3d9a77;p=platform%2Fupstream%2Flibvpx.git Adding video reader/writer APIs. Right now only IVF format is supported which is enough for example code. Other formats like y4m, webm, raw yuv will be supported later. Change-Id: I34c6f20731c1851947587ca5c589d7856b675164 --- diff --git a/examples.mk b/examples.mk index b2bdf68..078ce34 100644 --- a/examples.mk +++ b/examples.mk @@ -77,20 +77,29 @@ EXAMPLES-$(CONFIG_VP8_DECODER) += simple_decoder.c simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC simple_decoder.SRCS += ivfdec.h ivfdec.c simple_decoder.SRCS += tools_common.h tools_common.c +simple_decoder.SRCS += video_common.h +simple_decoder.SRCS += video_reader.h video_reader.c simple_decoder.DESCRIPTION = Simplified decoder loop EXAMPLES-$(CONFIG_VP8_DECODER) += postproc.c postproc.SRCS += ivfdec.h ivfdec.c postproc.SRCS += tools_common.h tools_common.c +postproc.SRCS += video_common.h +postproc.SRCS += video_reader.h video_reader.c postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7 postproc.DESCRIPTION = Decoder postprocessor control EXAMPLES-$(CONFIG_VP8_DECODER) += decode_to_md5.c decode_to_md5.SRCS += md5_utils.h md5_utils.c decode_to_md5.SRCS += ivfdec.h ivfdec.c decode_to_md5.SRCS += tools_common.h tools_common.c +decode_to_md5.SRCS += video_common.h +decode_to_md5.SRCS += video_reader.h video_reader.c decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42 decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum - EXAMPLES-$(CONFIG_VP8_ENCODER) += simple_encoder.c +simple_encoder.SRCS += ivfenc.h ivfenc.c +simple_encoder.SRCS += tools_common.h tools_common.c +simple_encoder.SRCS += video_common.h +simple_encoder.SRCS += video_writer.h video_writer.c simple_encoder.GUID = 4607D299-8A71-4D2C-9B1D-071899B6FBFD simple_encoder.DESCRIPTION = Simplified encoder loop EXAMPLES-$(CONFIG_VP8_ENCODER) += twopass_encoder.c @@ -103,6 +112,8 @@ ifeq ($(CONFIG_DECODERS),yes) EXAMPLES-$(CONFIG_VP8_ENCODER) += decode_with_drops.c decode_with_drops.SRCS += ivfdec.h ivfdec.c decode_with_drops.SRCS += tools_common.h tools_common.c +decode_with_drops.SRCS += video_common.h +decode_with_drops.SRCS += video_reader.h video_reader.c endif decode_with_drops.GUID = CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26 decode_with_drops.DESCRIPTION = Drops frames while decoding diff --git a/examples/decode_to_md5.c b/examples/decode_to_md5.c index bba2182..077513c 100644 --- a/examples/decode_to_md5.c +++ b/examples/decode_to_md5.c @@ -38,9 +38,9 @@ #include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" -#include "./ivfdec.h" #include "./md5_utils.h" #include "./tools_common.h" +#include "./video_reader.h" #include "./vpx_config.h" static void get_image_md5(const vpx_image_t *img, unsigned char digest[16]) { @@ -79,41 +79,42 @@ void usage_exit() { } int main(int argc, char **argv) { - FILE *infile, *outfile; + int frame_cnt = 0; + FILE *outfile = NULL; vpx_codec_ctx_t codec; - vpx_codec_iface_t *iface; - int flags = 0, frame_cnt = 0; - vpx_video_t *video; + vpx_codec_iface_t *iface = NULL; + VpxVideoReader *reader = NULL; + const VpxVideoInfo *info = NULL; exec_name = argv[0]; if (argc != 3) - die("Invalid number of arguments"); + die("Invalid number of arguments."); - if (!(infile = fopen(argv[1], "rb"))) - die("Failed to open %s for reading", argv[1]); + reader = vpx_video_reader_open(argv[1]); + if (!reader) + die("Failed to open %s for reading.", argv[1]); if (!(outfile = fopen(argv[2], "wb"))) - die("Failed to open %s for writing", argv[2]); + die("Failed to open %s for writing.", argv[2]); - video = vpx_video_open_file(infile); - if (!video) - die("%s is not an IVF file.", argv[1]); + info = vpx_video_reader_get_info(reader); - iface = get_codec_interface(vpx_video_get_fourcc(video)); + iface = get_codec_interface(info->codec_fourcc); if (!iface) - die("Unknown FOURCC code."); + die("Unknown input codec."); printf("Using %s\n", vpx_codec_iface_name(iface)); - if (vpx_codec_dec_init(&codec, iface, NULL, flags)) + if (vpx_codec_dec_init(&codec, iface, NULL, 0)) die_codec(&codec, "Failed to initialize decoder"); - while (vpx_video_read_frame(video)) { + while (vpx_video_reader_read_frame(reader)) { vpx_codec_iter_t iter = NULL; vpx_image_t *img = NULL; size_t frame_size = 0; - const unsigned char *frame = vpx_video_get_frame(video, &frame_size); + const unsigned char *frame = vpx_video_reader_get_frame(reader, + &frame_size); if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0)) die_codec(&codec, "Failed to decode frame"); @@ -129,11 +130,10 @@ int main(int argc, char **argv) { printf("Processed %d frames.\n", frame_cnt); if (vpx_codec_destroy(&codec)) - die_codec(&codec, "Failed to destroy codec"); + die_codec(&codec, "Failed to destroy codec."); - vpx_video_close(video); + vpx_video_reader_close(reader); fclose(outfile); - fclose(infile); return EXIT_SUCCESS; } diff --git a/examples/decode_with_drops.c b/examples/decode_with_drops.c index 12686de..e8fc076 100644 --- a/examples/decode_with_drops.c +++ b/examples/decode_with_drops.c @@ -56,14 +56,13 @@ #include #include -#include "./ivfdec.h" - #define VPX_CODEC_DISABLE_COMPAT 1 #include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" #include "./tools_common.h" +#include "./video_reader.h" #include "./vpx_config.h" static const char *exec_name; @@ -74,52 +73,55 @@ void usage_exit() { } int main(int argc, char **argv) { - FILE *infile, *outfile; + int frame_cnt = 0; + FILE *outfile = NULL; vpx_codec_ctx_t codec; - vpx_codec_iface_t *iface; - int flags = 0, frame_cnt = 0; - vpx_video_t *video; - int n, m, is_range; - char *nptr; + vpx_codec_iface_t *iface = NULL; + VpxVideoReader *reader = NULL; + const VpxVideoInfo *info = NULL; + int n = 0; + int m = 0; + int is_range = 0; + char *nptr = NULL; exec_name = argv[0]; if (argc != 4) - die("Invalid number of arguments"); + die("Invalid number of arguments."); - if (!(infile = fopen(argv[1], "rb"))) - die("Failed to open %s for reading", argv[1]); + reader = vpx_video_reader_open(argv[1]); + if (!reader) + die("Failed to open %s for reading.", argv[1]); if (!(outfile = fopen(argv[2], "wb"))) - die("Failed to open %s for writing", argv[2]); + die("Failed to open %s for writing.", argv[2]); n = strtol(argv[3], &nptr, 0); m = strtol(nptr + 1, NULL, 0); is_range = (*nptr == '-'); if (!n || !m || (*nptr != '-' && *nptr != '/')) - die("Couldn't parse pattern %s\n", argv[3]); + die("Couldn't parse pattern %s.\n", argv[3]); - video = vpx_video_open_file(infile); - if (!video) - die("%s is not a supported input file.", argv[1]); + info = vpx_video_reader_get_info(reader); - iface = get_codec_interface(vpx_video_get_fourcc(video)); + iface = get_codec_interface(info->codec_fourcc); if (!iface) - die("Unknown FOURCC code."); + die("Unknown input codec."); printf("Using %s\n", vpx_codec_iface_name(iface)); - if (vpx_codec_dec_init(&codec, iface, NULL, flags)) - die_codec(&codec, "Failed to initialize decoder"); + if (vpx_codec_dec_init(&codec, iface, NULL, 0)) + die_codec(&codec, "Failed to initialize decoder."); - while (vpx_video_read_frame(video)) { + while (vpx_video_reader_read_frame(reader)) { vpx_codec_iter_t iter = NULL; vpx_image_t *img = NULL; size_t frame_size = 0; int skip; - const unsigned char *frame = vpx_video_get_frame(video, &frame_size); + const unsigned char *frame = vpx_video_reader_get_frame(reader, + &frame_size); if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0)) - die_codec(&codec, "Failed to decode frame"); + die_codec(&codec, "Failed to decode frame."); ++frame_cnt; @@ -140,15 +142,13 @@ int main(int argc, char **argv) { printf("Processed %d frames.\n", frame_cnt); if (vpx_codec_destroy(&codec)) - die_codec(&codec, "Failed to destroy codec"); + die_codec(&codec, "Failed to destroy codec."); printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n", - vpx_video_get_width(video), vpx_video_get_height(video), argv[2]); - - vpx_video_close(video); + info->frame_width, info->frame_height, argv[2]); + vpx_video_reader_close(reader); fclose(outfile); - fclose(infile); return EXIT_SUCCESS; } diff --git a/examples/postproc.c b/examples/postproc.c index 4ec2d1f..7281f1e 100644 --- a/examples/postproc.c +++ b/examples/postproc.c @@ -43,14 +43,13 @@ #include #include -#include "./ivfdec.h" - #define VPX_CODEC_DISABLE_COMPAT 1 #include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" #include "./tools_common.h" +#include "./video_reader.h" #include "./vpx_config.h" static const char *exec_name; @@ -61,35 +60,34 @@ void usage_exit() { } int main(int argc, char **argv) { - FILE *infile, *outfile; - vpx_codec_ctx_t codec; - vpx_codec_iface_t *iface; int frame_cnt = 0; - vpx_video_t *video; + FILE *outfile = NULL; + vpx_codec_ctx_t codec; vpx_codec_err_t res; + vpx_codec_iface_t *iface = NULL; + VpxVideoReader *reader = NULL; + const VpxVideoInfo *info = NULL; exec_name = argv[0]; if (argc != 3) - die("Invalid number of arguments"); + die("Invalid number of arguments."); - if (!(infile = fopen(argv[1], "rb"))) - die("Failed to open %s for reading", argv[1]); + reader = vpx_video_reader_open(argv[1]); + if (!reader) + die("Failed to open %s for reading.", argv[1]); if (!(outfile = fopen(argv[2], "wb"))) die("Failed to open %s for writing", argv[2]); - video = vpx_video_open_file(infile); - if (!video) - die("%s is not a supported input file.", argv[1]); + info = vpx_video_reader_get_info(reader); - iface = get_codec_interface(vpx_video_get_fourcc(video)); + iface = get_codec_interface(info->codec_fourcc); if (!iface) - die("Unknown FOURCC code."); + die("Unknown input codec."); printf("Using %s\n", vpx_codec_iface_name(iface)); - res = vpx_codec_dec_init(&codec, iface, NULL, VPX_CODEC_USE_POSTPROC); if (res == VPX_CODEC_INCAPABLE) { printf("NOTICE: Postproc not supported.\n"); @@ -97,13 +95,14 @@ int main(int argc, char **argv) { } if (res) - die_codec(&codec, "Failed to initialize decoder"); + die_codec(&codec, "Failed to initialize decoder."); - while (vpx_video_read_frame(video)) { + while (vpx_video_reader_read_frame(reader)) { vpx_codec_iter_t iter = NULL; vpx_image_t *img = NULL; size_t frame_size = 0; - const unsigned char *frame = vpx_video_get_frame(video, &frame_size); + const unsigned char *frame = vpx_video_reader_get_frame(reader, + &frame_size); ++frame_cnt; @@ -111,12 +110,12 @@ int main(int argc, char **argv) { vp8_postproc_cfg_t pp = {0, 0, 0}; if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp)) - die_codec(&codec, "Failed to turn off postproc"); + die_codec(&codec, "Failed to turn off postproc."); } else if (frame_cnt % 30 == 16) { vp8_postproc_cfg_t pp = {VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE, 4, 0}; if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp)) - die_codec(&codec, "Failed to turn on postproc"); + die_codec(&codec, "Failed to turn on postproc."); }; // Decode the frame with 15ms deadline @@ -133,11 +132,10 @@ int main(int argc, char **argv) { die_codec(&codec, "Failed to destroy codec"); printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n", - vpx_video_get_width(video), vpx_video_get_height(video), argv[2]); + info->frame_width, info->frame_height, argv[2]); - vpx_video_close(video); + vpx_video_reader_close(reader); fclose(outfile); - fclose(infile); return EXIT_SUCCESS; } diff --git a/examples/simple_decoder.c b/examples/simple_decoder.c index 23399f4..4dc9308 100644 --- a/examples/simple_decoder.c +++ b/examples/simple_decoder.c @@ -86,8 +86,8 @@ #include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" -#include "./ivfdec.h" #include "./tools_common.h" +#include "./video_reader.h" #include "./vpx_config.h" static const char *exec_name; @@ -98,43 +98,44 @@ void usage_exit() { } int main(int argc, char **argv) { - FILE *infile, *outfile; + int frame_cnt = 0; + FILE *outfile = NULL; vpx_codec_ctx_t codec; - vpx_codec_iface_t *iface; - int flags = 0, frame_cnt = 0; - vpx_video_t *video; + vpx_codec_iface_t *iface = NULL; + VpxVideoReader *reader = NULL; + const VpxVideoInfo *info = NULL; exec_name = argv[0]; if (argc != 3) - die("Invalid number of arguments"); + die("Invalid number of arguments."); - if (!(infile = fopen(argv[1], "rb"))) - die("Failed to open %s for reading", argv[1]); + reader = vpx_video_reader_open(argv[1]); + if (!reader) + die("Failed to open %s for reading.", argv[1]); if (!(outfile = fopen(argv[2], "wb"))) - die("Failed to open %s for writing", argv[2]); + die("Failed to open %s for writing.", argv[2]); - video = vpx_video_open_file(infile); - if (!video) - die("%s is not an IVF file.", argv[1]); + info = vpx_video_reader_get_info(reader); - iface = get_codec_interface(vpx_video_get_fourcc(video)); + iface = get_codec_interface(info->codec_fourcc); if (!iface) - die("Unknown FOURCC code."); + die("Unknown input codec."); printf("Using %s\n", vpx_codec_iface_name(iface)); - if (vpx_codec_dec_init(&codec, iface, NULL, flags)) - die_codec(&codec, "Failed to initialize decoder"); + if (vpx_codec_dec_init(&codec, iface, NULL, 0)) + die_codec(&codec, "Failed to initialize decoder."); - while (vpx_video_read_frame(video)) { + while (vpx_video_reader_read_frame(reader)) { vpx_codec_iter_t iter = NULL; vpx_image_t *img = NULL; size_t frame_size = 0; - const unsigned char *frame = vpx_video_get_frame(video, &frame_size); + const unsigned char *frame = vpx_video_reader_get_frame(reader, + &frame_size); if (vpx_codec_decode(&codec, frame, frame_size, NULL, 0)) - die_codec(&codec, "Failed to decode frame"); + die_codec(&codec, "Failed to decode frame."); while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL) { vpx_img_write(img, outfile); @@ -147,12 +148,11 @@ int main(int argc, char **argv) { die_codec(&codec, "Failed to destroy codec"); printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n", - vpx_video_get_width(video), vpx_video_get_height(video), argv[2]); + info->frame_width, info->frame_height, argv[2]); - vpx_video_close(video); + vpx_video_reader_close(reader); fclose(outfile); - fclose(infile); return EXIT_SUCCESS; } diff --git a/examples/simple_encoder.c b/examples/simple_encoder.c index e64a962..0ae012c 100644 --- a/examples/simple_encoder.c +++ b/examples/simple_encoder.c @@ -83,194 +83,131 @@ #include #include -#include #include -#define VPX_CODEC_DISABLE_COMPAT 1 -#include "vpx/vpx_encoder.h" -#include "vpx/vp8cx.h" -#define interface (vpx_codec_vp8_cx()) -#define fourcc 0x30385056 -#define IVF_FILE_HDR_SZ (32) -#define IVF_FRAME_HDR_SZ (12) - -static void mem_put_le16(char *mem, unsigned int val) { - mem[0] = val; - mem[1] = val>>8; -} +#define VPX_CODEC_DISABLE_COMPAT 1 -static void mem_put_le32(char *mem, unsigned int val) { - mem[0] = val; - mem[1] = val>>8; - mem[2] = val>>16; - mem[3] = val>>24; -} +#include "vpx/vp8cx.h" +#include "vpx/vpx_encoder.h" -static void die(const char *fmt, ...) { - va_list ap; +#include "./tools_common.h" +#include "./video_writer.h" - va_start(ap, fmt); - vprintf(fmt, ap); - if(fmt[strlen(fmt)-1] != '\n') - printf("\n"); - exit(EXIT_FAILURE); -} +#define interface (vpx_codec_vp8_cx()) -static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { - const char *detail = vpx_codec_error_detail(ctx); +static const char *exec_name; - printf("%s: %s\n", s, vpx_codec_error(ctx)); - if(detail) - printf(" %s\n",detail); - exit(EXIT_FAILURE); +void usage_exit() { + fprintf(stderr, "Usage: %s \n", exec_name); + exit(EXIT_FAILURE); } static int read_frame(FILE *f, vpx_image_t *img) { - size_t nbytes, to_read; - int res = 1; - - to_read = img->w*img->h*3/2; - nbytes = fread(img->planes[0], 1, to_read, f); - if(nbytes != to_read) { - res = 0; - if(nbytes > 0) - printf("Warning: Read partial frame. Check your width & height!\n"); - } - return res; -} - -static void write_ivf_file_header(FILE *outfile, - const vpx_codec_enc_cfg_t *cfg, - int frame_cnt) { - char header[32]; - - if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) - return; - header[0] = 'D'; - header[1] = 'K'; - header[2] = 'I'; - header[3] = 'F'; - mem_put_le16(header+4, 0); /* version */ - mem_put_le16(header+6, 32); /* headersize */ - mem_put_le32(header+8, fourcc); /* headersize */ - mem_put_le16(header+12, cfg->g_w); /* width */ - mem_put_le16(header+14, cfg->g_h); /* height */ - mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ - mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ - mem_put_le32(header+24, frame_cnt); /* length */ - mem_put_le32(header+28, 0); /* unused */ - - (void) fwrite(header, 1, 32, outfile); + int res = 1; + size_t to_read = img->w * img->h * 3 / 2; + size_t nbytes = fread(img->planes[0], 1, to_read, f); + if (nbytes != to_read) { + res = 0; + if (nbytes > 0) + printf("Warning: Read partial frame. Check your width & height!\n"); + } + return res; } - -static void write_ivf_frame_header(FILE *outfile, - const vpx_codec_cx_pkt_t *pkt) -{ - char header[12]; - vpx_codec_pts_t pts; - - if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) - return; - - pts = pkt->data.frame.pts; - mem_put_le32(header, pkt->data.frame.sz); - mem_put_le32(header+4, pts&0xFFFFFFFF); - mem_put_le32(header+8, pts >> 32); - - (void) fwrite(header, 1, 12, outfile); +static int is_valid_dimension(int value) { + return value >= 16 && (value % 2 == 0); } int main(int argc, char **argv) { - FILE *infile, *outfile; - vpx_codec_ctx_t codec; - vpx_codec_enc_cfg_t cfg; - int frame_cnt = 0; - vpx_image_t raw; - vpx_codec_err_t res; - long width; - long height; - int frame_avail; - int got_data; - int flags = 0; - - /* Open files */ - if(argc!=5) - die("Usage: %s \n", argv[0]); - width = strtol(argv[1], NULL, 0); - height = strtol(argv[2], NULL, 0); - if(width < 16 || width%2 || height <16 || height%2) - die("Invalid resolution: %ldx%ld", width, height); - if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1)) - die("Faile to allocate image", width, height); - if(!(outfile = fopen(argv[4], "wb"))) - die("Failed to open %s for writing", argv[4]); - - printf("Using %s\n",vpx_codec_iface_name(interface)); - - /* Populate encoder configuration */ - res = vpx_codec_enc_config_default(interface, &cfg, 0); - if(res) { - printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); - return EXIT_FAILURE; + FILE *infile; + vpx_codec_ctx_t codec; + vpx_codec_enc_cfg_t cfg; + int frame_count = 0; + vpx_image_t raw; + vpx_codec_err_t res; + VpxVideoInfo info; + VpxVideoWriter *writer; + const int fps = 30; // TODO(dkovalev) add command line argument + const int bitrate = 100; // kbit/s TODO(dkovalev) add command line argument + + exec_name = argv[0]; + + if (argc != 5) + die("Invalid number of arguments"); + + info.codec_fourcc = VP8_FOURCC; + info.frame_width = strtol(argv[1], NULL, 0); + info.frame_height = strtol(argv[2], NULL, 0); + info.time_base.numerator = 1; + info.time_base.denominator = fps; + + if (!is_valid_dimension(info.frame_width) || + !is_valid_dimension(info.frame_height)) + die("Invalid resolution: %dx%d", info.frame_width, info.frame_height); + + if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, + info.frame_height, 1)) + die("Failed to allocate image"); + + printf("Using %s\n", vpx_codec_iface_name(interface)); + + res = vpx_codec_enc_config_default(interface, &cfg, 0); + if (res) { + printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); + return EXIT_FAILURE; + } + + cfg.g_w = info.frame_width; + cfg.g_h = info.frame_height; + cfg.g_timebase.num = info.time_base.numerator; + cfg.g_timebase.den = info.time_base.denominator; + cfg.rc_target_bitrate = bitrate; + + writer = vpx_video_writer_open(argv[4], kContainerIVF, &info); + if (!writer) + die("Failed to open %s for writing.", argv[4]); + + // Open input file for this encoding pass + if (!(infile = fopen(argv[3], "rb"))) + die("Failed to open %s for reading.", argv[3]); + + // Initialize codec + if (vpx_codec_enc_init(&codec, interface, &cfg, 0)) + die_codec(&codec, "Failed to initialize encoder"); + + + while (read_frame(infile, &raw)) { + vpx_codec_iter_t iter = NULL; + const vpx_codec_cx_pkt_t *pkt = NULL; + res = vpx_codec_encode(&codec, &raw, frame_count, 1, 0, + VPX_DL_GOOD_QUALITY); + if (res != VPX_CODEC_OK) + die_codec(&codec, "Failed to encode frame"); + + ++frame_count; + + while ((pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) { + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { + const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; + if (!vpx_video_writer_write_frame(writer, + pkt->data.frame.buf, + pkt->data.frame.sz, + pkt->data.frame.pts)) + die_codec(&codec, "Failed to write compressed frame."); + printf(keyframe ? "K" : "."); + } } + } + printf("\n"); - /* Update the default configuration with our settings */ - cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate - / cfg.g_w / cfg.g_h; - cfg.g_w = width; - cfg.g_h = height; - - write_ivf_file_header(outfile, &cfg, 0); - - - /* Open input file for this encoding pass */ - if(!(infile = fopen(argv[3], "rb"))) - die("Failed to open %s for reading", argv[3]); - - /* Initialize codec */ - if(vpx_codec_enc_init(&codec, interface, &cfg, 0)) - die_codec(&codec, "Failed to initialize encoder"); - - frame_avail = 1; - got_data = 0; - while(frame_avail || got_data) { - vpx_codec_iter_t iter = NULL; - const vpx_codec_cx_pkt_t *pkt; + fclose(infile); - frame_avail = read_frame(infile, &raw); - if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt, - 1, flags, VPX_DL_REALTIME)) - die_codec(&codec, "Failed to encode frame"); - got_data = 0; - while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { - got_data = 1; - switch(pkt->kind) { - case VPX_CODEC_CX_FRAME_PKT: - write_ivf_frame_header(outfile, pkt); - (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, - outfile); - break; - default: - break; - } - printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT - && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); - fflush(stdout); - } - frame_cnt++; - } - printf("\n"); - fclose(infile); + printf("Processed %d frames.\n", frame_count); + vpx_img_free(&raw); + if (vpx_codec_destroy(&codec)) + die_codec(&codec, "Failed to destroy codec."); - printf("Processed %d frames.\n",frame_cnt-1); - vpx_img_free(&raw); - if(vpx_codec_destroy(&codec)) - die_codec(&codec, "Failed to destroy codec"); + vpx_video_writer_close(writer); - /* Try to rewrite the file header with the actual frame count */ - if(!fseek(outfile, 0, SEEK_SET)) - write_ivf_file_header(outfile, &cfg, frame_cnt-1); - fclose(outfile); - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/ivfdec.c b/ivfdec.c index b9fec26..40394a8 100644 --- a/ivfdec.c +++ b/ivfdec.c @@ -108,68 +108,3 @@ int ivf_read_frame(FILE *infile, uint8_t **buffer, return 1; } - -struct vpx_video { - FILE *file; - unsigned char *buffer; - size_t buffer_size; - size_t frame_size; - unsigned int fourcc; - int width; - int height; -}; - -vpx_video_t *vpx_video_open_file(FILE *file) { - char raw_hdr[32]; - vpx_video_t *video; - - if (fread(raw_hdr, 1, 32, file) != 32) - return NULL; // Can't read file header; - - if (memcmp(IVF_SIGNATURE, raw_hdr, 4) != 0) - return NULL; // Wrong IVF signature - - if (mem_get_le16(raw_hdr + 4) != 0) - return NULL; // Wrong IVF version - - video = (vpx_video_t *)malloc(sizeof(*video)); - video->file = file; - video->buffer = NULL; - video->buffer_size = 0; - video->frame_size = 0; - video->fourcc = mem_get_le32(raw_hdr + 8); - video->width = mem_get_le16(raw_hdr + 12); - video->height = mem_get_le16(raw_hdr + 14); - return video; -} - -void vpx_video_close(vpx_video_t *video) { - if (video) { - free(video->buffer); - free(video); - } -} - -int vpx_video_get_width(vpx_video_t *video) { - return video->width; -} - -int vpx_video_get_height(vpx_video_t *video) { - return video->height; -} - -unsigned int vpx_video_get_fourcc(vpx_video_t *video) { - return video->fourcc; -} - -int vpx_video_read_frame(vpx_video_t *video) { - return !ivf_read_frame(video->file, &video->buffer, &video->frame_size, - &video->buffer_size); -} - -const unsigned char *vpx_video_get_frame(vpx_video_t *video, size_t *size) { - if (size) - *size = video->frame_size; - - return video->buffer; -} diff --git a/ivfdec.h b/ivfdec.h index e960b4a..dd29cc6 100644 --- a/ivfdec.h +++ b/ivfdec.h @@ -21,34 +21,6 @@ int file_is_ivf(struct VpxInputContext *input); int ivf_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read, size_t *buffer_size); -// The following code is work in progress. It is going to be in a separate file -// and support transparent reading of IVF and Y4M formats. Right now only IVF -// format is supported for simplicity. The main goal the API is to be -// simple and easy to use in example code (and probably in vpxenc/vpxdec later). -// All low-level details like memory buffer management are hidden from API -// users. -struct vpx_video; -typedef struct vpx_video vpx_video_t; - -// Opens the input file and inspects it to determine file type. Returns an -// opaque vpx_video_t* upon success, or NULL upon failure. -vpx_video_t *vpx_video_open_file(FILE *file); - -// Frees all resources associated with vpx_video_t returned from -// vpx_video_open_file() call -void vpx_video_close(vpx_video_t *video); - -int vpx_video_get_width(vpx_video_t *video); -int vpx_video_get_height(vpx_video_t *video); -unsigned int vpx_video_get_fourcc(vpx_video_t *video); - -// Reads video frame bytes from the file and stores them into internal buffer. -int vpx_video_read_frame(vpx_video_t *video); - -// Returns the pointer to internal memory buffer with frame bytes read from -// last call to vpx_video_read_frame(). -const unsigned char *vpx_video_get_frame(vpx_video_t *video, size_t *size); - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/video_common.h b/video_common.h new file mode 100644 index 0000000..44b27a8 --- /dev/null +++ b/video_common.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VIDEO_COMMON_H_ +#define VIDEO_COMMON_H_ + +#include "./tools_common.h" + +typedef struct { + uint32_t codec_fourcc; + int frame_width; + int frame_height; + struct VpxRational time_base; +} VpxVideoInfo; + +#endif // VIDEO_COMMON_H_ diff --git a/video_reader.c b/video_reader.c new file mode 100644 index 0000000..4be7483 --- /dev/null +++ b/video_reader.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include + +#include "./ivfdec.h" +#include "./video_reader.h" + +static const char *const kIVFSignature = "DKIF"; + +struct VpxVideoReaderStruct { + VpxVideoInfo info; + FILE *file; + uint8_t *buffer; + size_t buffer_size; + size_t frame_size; +}; + +VpxVideoReader *vpx_video_reader_open(const char *filename) { + char header[32]; + VpxVideoReader *reader = NULL; + FILE *const file = fopen(filename, "rb"); + if (!file) + return NULL; // Can't open file + + if (fread(header, 1, 32, file) != 32) + return NULL; // Can't read file header + + if (memcmp(kIVFSignature, header, 4) != 0) + return NULL; // Wrong IVF signature + + if (mem_get_le16(header + 4) != 0) + return NULL; // Wrong IVF version + + reader = calloc(1, sizeof(*reader)); + if (!reader) + return NULL; // Can't allocate VpxVideoReader + + reader->file = file; + reader->info.codec_fourcc = mem_get_le32(header + 8); + reader->info.frame_width = mem_get_le16(header + 12); + reader->info.frame_height = mem_get_le16(header + 14); + reader->info.time_base.numerator = mem_get_le32(header + 16); + reader->info.time_base.denominator = mem_get_le32(header + 20); + + return reader; +} + +void vpx_video_reader_close(VpxVideoReader *reader) { + if (reader) { + fclose(reader->file); + free(reader->buffer); + free(reader); + } +} + +int vpx_video_reader_read_frame(VpxVideoReader *reader) { + return !ivf_read_frame(reader->file, &reader->buffer, &reader->frame_size, + &reader->buffer_size); +} + +const uint8_t *vpx_video_reader_get_frame(VpxVideoReader *reader, + size_t *size) { + if (size) + *size = reader->frame_size; + + return reader->buffer; +} + +const VpxVideoInfo *vpx_video_reader_get_info(VpxVideoReader *reader) { + return &reader->info; +} + diff --git a/video_reader.h b/video_reader.h new file mode 100644 index 0000000..a62c6d7 --- /dev/null +++ b/video_reader.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VIDEO_READER_H_ +#define VIDEO_READER_H_ + +#include "./video_common.h" + +// The following code is work in progress. It is going to support transparent +// reading of input files. Right now only IVF format is supported for +// simplicity. The main goal the API is to be simple and easy to use in example +// code and in vpxenc/vpxdec later. All low-level details like memory +// buffer management are hidden from API users. +struct VpxVideoReaderStruct; +typedef struct VpxVideoReaderStruct VpxVideoReader; + +#ifdef __cplusplus +extern "C" { +#endif + +// Opens the input file for reading and inspects it to determine file type. +// Returns an opaque VpxVideoReader* upon success, or NULL upon failure. +// Right now only IVF format is supported. +VpxVideoReader *vpx_video_reader_open(const char *filename); + +// Frees all resources associated with VpxVideoReader* returned from +// vpx_video_reader_open() call. +void vpx_video_reader_close(VpxVideoReader *reader); + +// Reads frame from the file and stores it in internal buffer. +int vpx_video_reader_read_frame(VpxVideoReader *reader); + +// Returns the pointer to memory buffer with frame data read by last call to +// vpx_video_reader_read_frame(). +const uint8_t *vpx_video_reader_get_frame(VpxVideoReader *reader, + size_t *size); + +// Fills VpxVideoInfo with information from opened video file. +const VpxVideoInfo *vpx_video_reader_get_info(VpxVideoReader *reader); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // VIDEO_READER_H_ diff --git a/video_writer.c b/video_writer.c new file mode 100644 index 0000000..3695236 --- /dev/null +++ b/video_writer.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "./ivfenc.h" +#include "./video_writer.h" +#include "vpx/vpx_encoder.h" + +struct VpxVideoWriterStruct { + VpxVideoInfo info; + FILE *file; + int frame_count; +}; + +static void write_header(FILE *file, const VpxVideoInfo *info, + int frame_count) { + struct vpx_codec_enc_cfg cfg; + cfg.g_w = info->frame_width; + cfg.g_h = info->frame_height; + cfg.g_timebase.num = info->time_base.numerator; + cfg.g_timebase.den = info->time_base.denominator; + + ivf_write_file_header(file, &cfg, info->codec_fourcc, frame_count); +} + +VpxVideoWriter *vpx_video_writer_open(const char *filename, + VpxContainer container, + const VpxVideoInfo *info) { + if (container == kContainerIVF) { + VpxVideoWriter *writer = NULL; + FILE *const file = fopen(filename, "wb"); + if (!file) + return NULL; + + writer = malloc(sizeof(*writer)); + if (!writer) + return NULL; + + writer->frame_count = 0; + writer->info = *info; + writer->file = file; + + write_header(writer->file, info, 0); + + return writer; + } + + return NULL; +} + +void vpx_video_writer_close(VpxVideoWriter *writer) { + if (writer) { + // Rewriting frame header with real frame count + rewind(writer->file); + write_header(writer->file, &writer->info, writer->frame_count); + + fclose(writer->file); + free(writer); + } +} + +int vpx_video_writer_write_frame(VpxVideoWriter *writer, + const uint8_t *buffer, size_t size, + int64_t pts) { + ivf_write_frame_header(writer->file, pts, size); + if (fwrite(buffer, 1, size, writer->file) != size) + return 0; + + ++writer->frame_count; + + return 1; +} diff --git a/video_writer.h b/video_writer.h new file mode 100644 index 0000000..5dbfe52 --- /dev/null +++ b/video_writer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VIDEO_WRITER_H_ +#define VIDEO_WRITER_H_ + +#include "./video_common.h" + +typedef enum { + kContainerIVF +} VpxContainer; + +struct VpxVideoWriterStruct; +typedef struct VpxVideoWriterStruct VpxVideoWriter; + +#ifdef __cplusplus +extern "C" { +#endif + +// Finds and opens writer for specified container format. +// Returns an opaque VpxVideoWriter* upon success, or NULL upon failure. +// Right now only IVF format is supported. +VpxVideoWriter *vpx_video_writer_open(const char *filename, + VpxContainer container, + const VpxVideoInfo *info); + +// Frees all resources associated with VpxVideoWriter* returned from +// vpx_video_writer_open() call. +void vpx_video_writer_close(VpxVideoWriter *writer); + +// Writes frame bytes to the file. +int vpx_video_writer_write_frame(VpxVideoWriter *writer, + const uint8_t *buffer, size_t size, + int64_t pts); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // VIDEO_WRITER_H_