diff --git a/examples.mk b/examples.mk index 16f3c8fa2..3324fd929 100644 --- a/examples.mk +++ b/examples.mk @@ -23,6 +23,7 @@ vpxdec.SRCS += md5_utils.c md5_utils.h vpxdec.SRCS += vpx_ports/vpx_timer.h vpxdec.SRCS += vpx/vpx_integer.h vpxdec.SRCS += args.c args.h +vpxdec.SRCS += ivfdec.c ivfdec.h vpxdec.SRCS += tools_common.c tools_common.h vpxdec.SRCS += nestegg/halloc/halloc.h vpxdec.SRCS += nestegg/halloc/src/align.h @@ -36,6 +37,8 @@ vpxdec.GUID = BA5FE66F-38DD-E034-F542-B1578C5FB950 vpxdec.DESCRIPTION = Full featured decoder UTILS-$(CONFIG_ENCODERS) += vpxenc.c vpxenc.SRCS += args.c args.h y4minput.c y4minput.h +vpxenc.SRCS += ivfdec.c ivfdec.h +vpxenc.SRCS += ivfenc.c ivfenc.h vpxenc.SRCS += tools_common.c tools_common.h vpxenc.SRCS += webmenc.c webmenc.h vpxenc.SRCS += vpx_ports/mem_ops.h @@ -53,18 +56,11 @@ vp8_scalable_patterns.GUID = 0D6A210B-F482-4D6F-8570-4A9C01ACC88C vp8_scalable_patterns.DESCRIPTION = Temporal Scalability Encoder UTILS-$(CONFIG_VP9_ENCODER) += vp9_spatial_scalable_encoder.c vp9_spatial_scalable_encoder.SRCS += args.c args.h +vp9_spatial_scalable_encoder.SRCS += ivfenc.c ivfenc.h +vp9_spatial_scalable_encoder.SRCS += tools_common.c tools_common.h vp9_spatial_scalable_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D vp9_spatial_scalable_encoder.DESCRIPTION = Spatial Scalable Encoder -# Clean up old ivfenc, ivfdec binaries. -ifeq ($(CONFIG_MSVS),yes) -CLEAN-OBJS += $(foreach p,$(VS_PLATFORMS),$(p)/Release/ivfenc.exe) -CLEAN-OBJS += $(foreach p,$(VS_PLATFORMS),$(p)/Release/ivfdec.exe) -else -CLEAN-OBJS += ivfenc{.c.o,.c.d,.dox,.exe,} -CLEAN-OBJS += ivfdec{.c.o,.c.d,.dox,.exe,} -endif - # XMA example disabled for now, not used in VP8 #UTILS-$(CONFIG_DECODERS) += example_xma.c #example_xma.GUID = A955FC4A-73F1-44F7-135E-30D84D32F022 diff --git a/ivfdec.c b/ivfdec.c new file mode 100644 index 000000000..51f4a094a --- /dev/null +++ b/ivfdec.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013 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 "./ivfdec.h" + +#include +#include + +int file_is_ivf(struct VpxInputContext *input_ctx) { + char raw_hdr[32]; + int is_ivf = 0; + + // TODO(tomfinegan): This can eventually go away, but for now it's required + // because the means by which file types are detected differ in vpxdec and + // vpxenc. + rewind(input_ctx->file); + + if (fread(raw_hdr, 1, 32, input_ctx->file) == 32) { + if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K' && + raw_hdr[2] == 'I' && raw_hdr[3] == 'F') { + is_ivf = 1; + + if (mem_get_le16(raw_hdr + 4) != 0) { + fprintf(stderr, "Error: Unrecognized IVF version! This file may not" + " decode properly."); + } + + input_ctx->fourcc = mem_get_le32(raw_hdr + 8); + input_ctx->width = mem_get_le16(raw_hdr + 12); + input_ctx->height = mem_get_le16(raw_hdr + 14); + input_ctx->framerate.numerator = mem_get_le32(raw_hdr + 16); + input_ctx->framerate.denominator = mem_get_le32(raw_hdr + 20); + + /* Some versions of vpxenc used 1/(2*fps) for the timebase, so + * we can guess the framerate using only the timebase in this + * case. Other files would require reading ahead to guess the + * timebase, like we do for webm. + */ + if (input_ctx->framerate.numerator < 1000) { + /* Correct for the factor of 2 applied to the timebase in the + * encoder. + */ + if (input_ctx->framerate.numerator & 1) + input_ctx->framerate.denominator <<= 1; + else + input_ctx->framerate.numerator >>= 1; + } else { + /* Don't know FPS for sure, and don't have readahead code + * (yet?), so just default to 30fps. + */ + input_ctx->framerate.numerator = 30; + input_ctx->framerate.denominator = 1; + } + } + } + + if (!is_ivf) + rewind(input_ctx->file); + else + input_ctx->detect.position = 4; + + return is_ivf; +} + +int ivf_read_frame(struct VpxInputContext *input_ctx, + uint8_t **buffer, + size_t *bytes_read, + size_t *buffer_size) { + char raw_header[IVF_FRAME_HDR_SZ] = {0}; + size_t frame_size = 0; + FILE *infile = input_ctx->file; + + if (input_ctx->file_type != FILE_TYPE_IVF) + return 0; + + if (fread(raw_header, IVF_FRAME_HDR_SZ, 1, infile) != 1) { + if (!feof(infile)) + warn("Failed to read frame size\n"); + } else { + frame_size = mem_get_le32(raw_header); + + if (frame_size > 256 * 1024 * 1024) { + warn("Read invalid frame size (%u)\n", (unsigned int)frame_size); + frame_size = 0; + } + + if (frame_size > *buffer_size) { + uint8_t *new_buffer = realloc(*buffer, 2 * frame_size); + + if (new_buffer) { + *buffer = new_buffer; + *buffer_size = 2 * frame_size; + } else { + warn("Failed to allocate compressed data buffer\n"); + frame_size = 0; + } + } + } + + if (!feof(infile)) { + if (fread(*buffer, 1, frame_size, infile) != frame_size) { + warn("Failed to read full frame\n"); + return 1; + } + + *bytes_read = frame_size; + return 0; + } + + return 1; +} diff --git a/ivfdec.h b/ivfdec.h new file mode 100644 index 000000000..b1468a9f3 --- /dev/null +++ b/ivfdec.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 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 IVFDEC_H_ +#define IVFDEC_H_ + +#include "./tools_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int file_is_ivf(struct VpxInputContext *input); + +int ivf_read_frame(struct VpxInputContext *input, + uint8_t **buffer, + size_t *bytes_read, + size_t *buffer_size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* IVFDEC_H_ */ diff --git a/ivfenc.c b/ivfenc.c new file mode 100644 index 000000000..fa92566f8 --- /dev/null +++ b/ivfenc.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 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 "./ivfenc.h" + +#include "./tools_common.h" +#include "vpx/vpx_encoder.h" +#include "vpx_ports/mem_ops.h" + +void ivf_write_file_header(FILE *outfile, + const struct vpx_codec_enc_cfg *cfg, + unsigned int fourcc, + 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); /* four CC */ + 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); +} + +void ivf_write_frame_header(FILE *outfile, const struct vpx_codec_cx_pkt *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, (int)pkt->data.frame.sz); + mem_put_le32(header + 4, pts & 0xFFFFFFFF); + mem_put_le32(header + 8, pts >> 32); + + (void) fwrite(header, 1, 12, outfile); +} + +void ivf_write_frame_size(FILE *outfile, size_t size) { + char header[4]; + mem_put_le32(header, (int)size); + (void) fwrite(header, 1, 4, outfile); +} diff --git a/ivfenc.h b/ivfenc.h new file mode 100644 index 000000000..a332c7dfd --- /dev/null +++ b/ivfenc.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 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 IVFENC_H_ +#define IVFENC_H_ + +#include "./tools_common.h" + +struct vpx_codec_enc_cfg; +struct vpx_codec_cx_pkt; + +#ifdef __cplusplus +extern "C" { +#endif + +void ivf_write_file_header(FILE *outfile, + const struct vpx_codec_enc_cfg *cfg, + uint32_t fourcc, + int frame_cnt); +void ivf_write_frame_header(FILE *outfile, const struct vpx_codec_cx_pkt *pkt); +void ivf_write_frame_size(FILE *outfile, size_t size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* IVFENC_H_ */ diff --git a/tools_common.c b/tools_common.c index 44b2a3fa0..9c24983de 100644 --- a/tools_common.c +++ b/tools_common.c @@ -7,10 +7,13 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ + #include "tools_common.h" #include +#include #include +#include #if defined(_WIN32) || defined(__OS2__) #include @@ -56,3 +59,74 @@ void fatal(const char *fmt, ...) { void warn(const char *fmt, ...) { LOG_ERROR("Warning"); } + +uint16_t mem_get_le16(const void *data) { + uint16_t val; + const uint8_t *mem = (const uint8_t*)data; + + val = mem[1] << 8; + val |= mem[0]; + return val; +} + +uint32_t mem_get_le32(const void *data) { + uint32_t val; + const uint8_t *mem = (const uint8_t*)data; + + val = mem[3] << 24; + val |= mem[2] << 16; + val |= mem[1] << 8; + val |= mem[0]; + return val; +} + +int read_yuv_frame(struct VpxInputContext *input_ctx, vpx_image_t *yuv_frame) { + FILE *f = input_ctx->file; + struct FileTypeDetectionBuffer *detect = &input_ctx->detect; + int plane = 0; + int shortread = 0; + + for (plane = 0; plane < 3; ++plane) { + uint8_t *ptr; + const int w = (plane ? (1 + yuv_frame->d_w) / 2 : yuv_frame->d_w); + const int h = (plane ? (1 + yuv_frame->d_h) / 2 : yuv_frame->d_h); + int r; + + /* Determine the correct plane based on the image format. The for-loop + * always counts in Y,U,V order, but this may not match the order of + * the data on disk. + */ + switch (plane) { + case 1: + ptr = yuv_frame->planes[ + yuv_frame->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_V : VPX_PLANE_U]; + break; + case 2: + ptr = yuv_frame->planes[ + yuv_frame->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_U : VPX_PLANE_V]; + break; + default: + ptr = yuv_frame->planes[plane]; + } + + for (r = 0; r < h; ++r) { + size_t needed = w; + size_t buf_position = 0; + const size_t left = detect->buf_read - detect->position; + if (left > 0) { + const size_t more = (left < needed) ? left : needed; + memcpy(ptr, detect->buf + detect->position, more); + buf_position = more; + needed -= more; + detect->position += more; + } + if (needed > 0) { + shortread |= (fread(ptr + buf_position, 1, needed, f) < needed); + } + + ptr += yuv_frame->stride[plane]; + } + } + + return shortread; +} diff --git a/tools_common.h b/tools_common.h index 068e7b518..353f90aaa 100644 --- a/tools_common.h +++ b/tools_common.h @@ -13,6 +13,12 @@ #include #include "./vpx_config.h" +#include "vpx/vpx_image.h" +#include "vpx/vpx_integer.h" + +#if CONFIG_ENCODERS +#include "./y4minput.h" +#endif #if defined(_MSC_VER) /* MSVS doesn't define off_t, and uses _f{seek,tell}i64. */ @@ -52,11 +58,55 @@ typedef long off_t; /* NOLINT */ #define PATH_MAX 512 #endif +#define IVF_FRAME_HDR_SZ (4 + 8) /* 4 byte size + 8 byte timestamp */ +#define IVF_FILE_HDR_SZ 32 + +#define RAW_FRAME_HDR_SZ sizeof(uint32_t) + #define VP8_FOURCC (0x30385056) #define VP9_FOURCC (0x30395056) #define VP8_FOURCC_MASK (0x00385056) #define VP9_FOURCC_MASK (0x00395056) +enum VideoFileType { + FILE_TYPE_RAW, + FILE_TYPE_IVF, + FILE_TYPE_Y4M, + FILE_TYPE_WEBM +}; + +struct FileTypeDetectionBuffer { + char buf[4]; + size_t buf_read; + size_t position; +}; + +struct VpxRational { + int numerator; + int denominator; +}; + +struct VpxInputContext { + const char *filename; + FILE *file; + off_t length; + struct FileTypeDetectionBuffer detect; + enum VideoFileType file_type; + unsigned int width; + unsigned int height; + int use_i420; + int only_i420; + unsigned int fourcc; + struct VpxRational framerate; +#if CONFIG_ENCODERS + y4m_input y4m; +#endif +}; + +#ifdef __cplusplus +extern "C" { +#endif + /* Sets a stdio stream into binary mode */ FILE *set_binary_mode(FILE *stream); @@ -67,4 +117,13 @@ void warn(const char *fmt, ...); /* The tool including this file must define usage_exit() */ void usage_exit(); +uint16_t mem_get_le16(const void *data); +uint32_t mem_get_le32(const void *data); + +int read_yuv_frame(struct VpxInputContext *input_ctx, vpx_image_t *yuv_frame); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif // TOOLS_COMMON_H_ diff --git a/vp9_spatial_scalable_encoder.c b/vp9_spatial_scalable_encoder.c index 9acfa29bc..9aaec825b 100644 --- a/vp9_spatial_scalable_encoder.c +++ b/vp9_spatial_scalable_encoder.c @@ -19,12 +19,12 @@ #include #include #include "./args.h" +#include "./ivfenc.h" +#include "./tools_common.h" #include "vpx/svc_context.h" #include "vpx/vp8cx.h" #include "vpx/vpx_encoder.h" -#define VP90_FOURCC 0x30395056 - static const struct arg_enum_list encoding_mode_enum[] = { {"i", INTER_LAYER_PREDICTION_I}, {"alt-ip", ALT_INTER_LAYER_PREDICTION_IP}, @@ -77,25 +77,13 @@ static const uint32_t default_kf_dist = 100; static const int default_use_dummy_frame = 1; typedef struct { - char *input_filename; char *output_filename; uint32_t frames_to_code; uint32_t frames_to_skip; + struct VpxInputContext input_ctx; } AppInput; -static void mem_put_le16(char *mem, uint32_t val) { - mem[0] = val; - mem[1] = val >> 8; -} - -static void mem_put_le32(char *mem, uint32_t val) { - mem[0] = val; - mem[1] = val >> 8; - mem[2] = val >> 16; - mem[3] = val >> 24; -} - -static void usage(const char *exec_name) { +void usage_exit(const char *exec_name) { fprintf(stderr, "Usage: %s input_filename output_filename\n", exec_name); fprintf(stderr, "Options:\n"); @@ -103,15 +91,6 @@ static void usage(const char *exec_name) { exit(EXIT_FAILURE); } -void die(const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - if (fmt[strlen(fmt) - 1] != '\n') printf("\n"); - exit(EXIT_FAILURE); -} - static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { const char *detail = vpx_codec_error_detail(ctx); @@ -120,83 +99,12 @@ static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { exit(EXIT_FAILURE); } -static int read_frame(FILE *f, vpx_image_t *img) { - size_t nbytes; - int res = 1; - int plane; - - for (plane = 0; plane < 3; ++plane) { - uint8_t *ptr; - const int w = (plane ? (1 + img->d_w) / 2 : img->d_w); - const int h = (plane ? (1 + img->d_h) / 2 : img->d_h); - int r; - - switch (plane) { - case 1: - ptr = img->planes[VPX_PLANE_U]; - break; - case 2: - ptr = img->planes[VPX_PLANE_V]; - break; - default: - ptr = img->planes[plane]; - } - for (r = 0; r < h; ++r) { - const int to_read = w; - - nbytes = fread(ptr, 1, to_read, f); - if (nbytes != to_read) { - res = 0; - if (nbytes > 0) - printf("Warning: Read partial frame. Check your width & height!\n"); - break; - } - ptr += img->stride[plane]; - } - if (!res) break; - } - return res; -} - static int create_dummy_frame(vpx_image_t *img) { const size_t buf_size = img->w * img->h * 3 / 2; memset(img->planes[0], 129, buf_size); return 1; } -static void write_ivf_file_header(FILE *outfile, - uint32_t width, uint32_t height, - int timebase_num, int timebase_den, - int frame_cnt) { - char header[32]; - - 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, VP90_FOURCC); /* fourcc */ - mem_put_le16(header + 12, width); /* width */ - mem_put_le16(header + 14, height); /* height */ - mem_put_le32(header + 16, timebase_den); /* rate */ - mem_put_le32(header + 20, timebase_num); /* scale */ - mem_put_le32(header + 24, frame_cnt); /* length */ - mem_put_le32(header + 28, 0); /* unused */ - - (void)fwrite(header, 1, 32, outfile); -} - -static void write_ivf_frame_header(FILE *outfile, vpx_codec_pts_t pts, - size_t sz) { - char header[12]; - mem_put_le32(header, (uint32_t)sz); - mem_put_le32(header + 4, pts & 0xFFFFFFFF); - mem_put_le32(header + 8, pts >> 32); - - (void)fwrite(header, 1, 12, outfile); -} - static void parse_command_line(int argc, const char **argv_, AppInput *app_input, SvcContext *svc_ctx, vpx_codec_enc_cfg_t *enc_cfg) { @@ -272,9 +180,9 @@ static void parse_command_line(int argc, const char **argv_, die("Error: Unrecognized option %s\n", *argi); if (argv[0] == NULL || argv[1] == 0) { - usage(argv_[0]); + usage_exit(argv_[0]); } - app_input->input_filename = argv[0]; + app_input->input_ctx.filename = argv[0]; app_input->output_filename = argv[1]; free(argv); @@ -298,7 +206,7 @@ static void parse_command_line(int argc, const char **argv_, int main(int argc, const char **argv) { AppInput app_input = {0}; - FILE *infile, *outfile; + FILE *outfile; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t enc_cfg; SvcContext svc_ctx; @@ -308,6 +216,8 @@ int main(int argc, const char **argv) { vpx_codec_err_t res; int pts = 0; /* PTS starts at 0 */ int frame_duration = 1; /* 1 timebase tick per frame */ + vpx_codec_cx_pkt_t packet = {0}; + packet.kind = VPX_CODEC_CX_FRAME_PKT; memset(&svc_ctx, 0, sizeof(svc_ctx)); svc_ctx.log_print = 1; @@ -317,8 +227,8 @@ int main(int argc, const char **argv) { if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32)) die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h); - if (!(infile = fopen(app_input.input_filename, "rb"))) - die("Failed to open %s for reading\n", app_input.input_filename); + if (!(app_input.input_ctx.file = fopen(app_input.input_ctx.filename, "rb"))) + die("Failed to open %s for reading\n", app_input.input_ctx.filename); if (!(outfile = fopen(app_input.output_filename, "wb"))) die("Failed to open %s for writing\n", app_input.output_filename); @@ -328,12 +238,11 @@ int main(int argc, const char **argv) { VPX_CODEC_OK) die("Failed to initialize encoder\n"); - write_ivf_file_header(outfile, enc_cfg.g_w, enc_cfg.g_h, - enc_cfg.g_timebase.num, enc_cfg.g_timebase.den, 0); + ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, 0); // skip initial frames for (i = 0; i < app_input.frames_to_skip; ++i) { - read_frame(infile, &raw); + read_yuv_frame(&app_input.input_ctx, &raw); } // Encode frames @@ -341,7 +250,7 @@ int main(int argc, const char **argv) { if (frame_cnt == 0 && svc_ctx.first_frame_full_size) { create_dummy_frame(&raw); } else { - if (!read_frame(infile, &raw)) break; + if (!read_yuv_frame(&app_input.input_ctx, &raw)) break; } res = vpx_svc_encode(&svc_ctx, &codec, &raw, pts, frame_duration, VPX_DL_REALTIME); @@ -350,7 +259,9 @@ int main(int argc, const char **argv) { die_codec(&codec, "Failed to encode frame"); } if (vpx_svc_get_frame_size(&svc_ctx) > 0) { - write_ivf_frame_header(outfile, pts, vpx_svc_get_frame_size(&svc_ctx)); + packet.data.frame.pts = pts; + packet.data.frame.sz = vpx_svc_get_frame_size(&svc_ctx); + ivf_write_frame_header(outfile, &packet); (void)fwrite(vpx_svc_get_buffer(&svc_ctx), 1, vpx_svc_get_frame_size(&svc_ctx), outfile); } @@ -360,14 +271,12 @@ int main(int argc, const char **argv) { printf("Processed %d frames\n", frame_cnt - svc_ctx.first_frame_full_size); - fclose(infile); + fclose(app_input.input_ctx.file); if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); // rewrite the output file headers with the actual frame count if (!fseek(outfile, 0, SEEK_SET)) { - write_ivf_file_header(outfile, enc_cfg.g_w, enc_cfg.g_h, - enc_cfg.g_timebase.num, enc_cfg.g_timebase.den, - frame_cnt); + ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, frame_cnt); } fclose(outfile); vpx_img_free(&raw); diff --git a/vpxdec.c b/vpxdec.c index 110e4ac24..a5bb1c556 100644 --- a/vpxdec.c +++ b/vpxdec.c @@ -8,10 +8,6 @@ * be found in the AUTHORS file in the root of the source tree. */ - -/* This is a simple program that reads ivf files and decodes them - * using the new interface. Decoded frames are output as YV12 raw. - */ #include #include #include @@ -19,17 +15,22 @@ #include #include +#include "./ivfdec.h" + #define VPX_CODEC_DISABLE_COMPAT 1 -#include "vpx_config.h" +#include "./vpx_config.h" #include "vpx/vpx_decoder.h" #include "vpx_ports/vpx_timer.h" + #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER #include "vpx/vp8dx.h" #endif + #if CONFIG_MD5 #include "md5_utils.h" #endif -#include "tools_common.h" + +#include "./tools_common.h" #include "nestegg/include/nestegg/nestegg.h" #include "third_party/libyuv/include/libyuv/scale.h" @@ -161,53 +162,24 @@ void usage_exit() { exit(EXIT_FAILURE); } -static unsigned int mem_get_le16(const void *vmem) { - unsigned int val; - const unsigned char *mem = (const unsigned char *)vmem; - - val = mem[1] << 8; - val |= mem[0]; - return val; -} - -static unsigned int mem_get_le32(const void *vmem) { - unsigned int val; - const unsigned char *mem = (const unsigned char *)vmem; - - val = mem[3] << 24; - val |= mem[2] << 16; - val |= mem[1] << 8; - val |= mem[0]; - return val; -} - -enum file_kind { - RAW_FILE, - IVF_FILE, - WEBM_FILE -}; - -struct input_ctx { - enum file_kind kind; - FILE *infile; - nestegg *nestegg_ctx; +struct VpxDecInputContext { + nestegg *nestegg_ctx; nestegg_packet *pkt; - unsigned int chunk; - unsigned int chunks; - unsigned int video_track; + unsigned int chunk; + unsigned int chunks; + unsigned int video_track; + struct VpxInputContext *vpx_input_ctx; }; -#define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t)) -#define RAW_FRAME_HDR_SZ (sizeof(uint32_t)) -static int read_frame(struct input_ctx *input, - uint8_t **buf, - size_t *buf_sz, - size_t *buf_alloc_sz) { - char raw_hdr[IVF_FRAME_HDR_SZ]; - size_t new_buf_sz; - FILE *infile = input->infile; - enum file_kind kind = input->kind; - if (kind == WEBM_FILE) { +static int read_frame(struct VpxDecInputContext *input, + uint8_t **buf, + size_t *bytes_in_buffer, + size_t *buffer_size) { + char raw_hdr[RAW_FRAME_HDR_SZ]; + size_t bytes_to_read = 0; + FILE *infile = input->vpx_input_ctx->file; + enum VideoFileType kind = input->vpx_input_ctx->file_type; + if (kind == FILE_TYPE_WEBM) { if (input->chunk >= input->chunks) { unsigned int track; @@ -227,54 +199,49 @@ static int read_frame(struct input_ctx *input, input->chunk = 0; } - if (nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz)) + if (nestegg_packet_data(input->pkt, input->chunk, buf, bytes_in_buffer)) return 1; input->chunk++; return 0; - } - /* For both the raw and ivf formats, the frame size is the first 4 bytes - * of the frame header. We just need to special case on the header - * size. - */ - else if (fread(raw_hdr, kind == IVF_FILE - ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) { - if (!feof(infile)) - fprintf(stderr, "Failed to read frame size\n"); + } else if (kind == FILE_TYPE_RAW) { + if (fread(raw_hdr, RAW_FRAME_HDR_SZ, 1, infile) != 1) { + if (!feof(infile)) + warn("Failed to read RAW frame size\n"); + } else { + const int kCorruptFrameThreshold = 256 * 1024 * 1024; + const int kFrameTooSmallThreshold = 256 * 1024; + bytes_to_read = mem_get_le32(raw_hdr); - new_buf_sz = 0; - } else { - new_buf_sz = mem_get_le32(raw_hdr); + if (bytes_to_read > kCorruptFrameThreshold) { + warn("Read invalid frame size (%u)\n", (unsigned int)bytes_to_read); + bytes_to_read = 0; + } - if (new_buf_sz > 256 * 1024 * 1024) { - fprintf(stderr, "Error: Read invalid frame size (%u)\n", - (unsigned int)new_buf_sz); - new_buf_sz = 0; - } + if (kind == FILE_TYPE_RAW && bytes_to_read < kFrameTooSmallThreshold) { + warn("Warning: Read invalid frame size (%u) - not a raw file?\n", + (unsigned int)bytes_to_read); + } - if (kind == RAW_FILE && new_buf_sz > 256 * 1024) - fprintf(stderr, "Warning: Read invalid frame size (%u)" - " - not a raw file?\n", (unsigned int)new_buf_sz); + if (bytes_to_read > *buffer_size) { + uint8_t *new_buf = realloc(*buf, 2 * bytes_to_read); - if (new_buf_sz > *buf_alloc_sz) { - uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz); - - if (new_buf) { - *buf = new_buf; - *buf_alloc_sz = 2 * new_buf_sz; - } else { - fprintf(stderr, "Failed to allocate compressed data buffer\n"); - new_buf_sz = 0; + if (new_buf) { + *buf = new_buf; + *buffer_size = 2 * bytes_to_read; + } else { + warn("Failed to allocate compressed data buffer\n"); + bytes_to_read = 0; + } } } - } - *buf_sz = new_buf_sz; - - if (!feof(infile)) { - if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) { - fprintf(stderr, "Failed to read full frame\n"); - return 1; + if (!feof(infile)) { + if (fread(*buf, 1, bytes_to_read, infile) != bytes_to_read) { + warn("Failed to read full frame\n"); + return 1; + } + *bytes_in_buffer = bytes_to_read; } return 0; @@ -297,8 +264,7 @@ void *out_open(const char *out_fn, int do_md5) { : set_binary_mode(stdout); if (!outfile) { - fprintf(stderr, "Failed to output file"); - exit(EXIT_FAILURE); + fatal("Failed to output file"); } } @@ -334,88 +300,33 @@ void out_close(void *out, const char *out_fn, int do_md5) { } } -unsigned int file_is_ivf(FILE *infile, - unsigned int *fourcc, - unsigned int *width, - unsigned int *height, - unsigned int *fps_den, - unsigned int *fps_num) { - char raw_hdr[32]; - int is_ivf = 0; - - if (fread(raw_hdr, 1, 32, infile) == 32) { - if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K' - && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') { - is_ivf = 1; - - if (mem_get_le16(raw_hdr + 4) != 0) - fprintf(stderr, "Error: Unrecognized IVF version! This file may not" - " decode properly."); - - *fourcc = mem_get_le32(raw_hdr + 8); - *width = mem_get_le16(raw_hdr + 12); - *height = mem_get_le16(raw_hdr + 14); - *fps_num = mem_get_le32(raw_hdr + 16); - *fps_den = mem_get_le32(raw_hdr + 20); - - /* Some versions of vpxenc used 1/(2*fps) for the timebase, so - * we can guess the framerate using only the timebase in this - * case. Other files would require reading ahead to guess the - * timebase, like we do for webm. - */ - if (*fps_num < 1000) { - /* Correct for the factor of 2 applied to the timebase in the - * encoder. - */ - if (*fps_num & 1)*fps_den <<= 1; - else *fps_num >>= 1; - } else { - /* Don't know FPS for sure, and don't have readahead code - * (yet?), so just default to 30fps. - */ - *fps_num = 30; - *fps_den = 1; - } - } - } - - if (!is_ivf) - rewind(infile); - - return is_ivf; -} - - -unsigned int file_is_raw(FILE *infile, - unsigned int *fourcc, - unsigned int *width, - unsigned int *height, - unsigned int *fps_den, - unsigned int *fps_num) { - unsigned char buf[32]; +int file_is_raw(struct VpxInputContext *input) { + uint8_t buf[32]; int is_raw = 0; vpx_codec_stream_info_t si; si.sz = sizeof(si); - if (fread(buf, 1, 32, infile) == 32) { + if (fread(buf, 1, 32, input->file) == 32) { int i; - if (mem_get_le32(buf) < 256 * 1024 * 1024) - for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) + if (mem_get_le32(buf) < 256 * 1024 * 1024) { + for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) { if (!vpx_codec_peek_stream_info(ifaces[i].iface(), buf + 4, 32 - 4, &si)) { is_raw = 1; - *fourcc = ifaces[i].fourcc; - *width = si.w; - *height = si.h; - *fps_num = 30; - *fps_den = 1; + input->fourcc = ifaces[i].fourcc; + input->width = si.w; + input->height = si.h; + input->framerate.numerator = 30; + input->framerate.denominator = 1; break; } + } + } } - rewind(infile); + rewind(input->file); return is_raw; } @@ -470,18 +381,15 @@ nestegg_log_cb(nestegg *context, unsigned int severity, char const *format, static int -webm_guess_framerate(struct input_ctx *input, - unsigned int *fps_den, - unsigned int *fps_num) { +webm_guess_framerate(struct VpxDecInputContext *input) { unsigned int i; uint64_t tstamp = 0; /* Check to see if we can seek before we parse any data. */ if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) { - fprintf(stderr, - "WARNING: Failed to guess framerate (no Cues), set to 30fps.\n"); - *fps_num = 30; - *fps_den = 1; + warn("WARNING: Failed to guess framerate (no Cues), set to 30fps.\n"); + input->vpx_input_ctx->framerate.numerator = 30; + input->vpx_input_ctx->framerate.denominator = 1; return 0; } @@ -507,32 +415,27 @@ webm_guess_framerate(struct input_ctx *input, if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) goto fail; - *fps_num = (i - 1) * 1000000; - *fps_den = (unsigned int)(tstamp / 1000); + input->vpx_input_ctx->framerate.numerator = (i - 1) * 1000000; + input->vpx_input_ctx->framerate.denominator = (int)(tstamp / 1000); return 0; fail: nestegg_destroy(input->nestegg_ctx); input->nestegg_ctx = NULL; - rewind(input->infile); + rewind(input->vpx_input_ctx->file); return 1; } static int -file_is_webm(struct input_ctx *input, - unsigned int *fourcc, - unsigned int *width, - unsigned int *height, - unsigned int *fps_den, - unsigned int *fps_num) { +file_is_webm(struct VpxDecInputContext *input) { unsigned int i, n; - int track_type = -1; - int codec_id; + int track_type = -1; + int codec_id; nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0}; nestegg_video_params params; - io.userdata = input->infile; + io.userdata = input->vpx_input_ctx->file; if (nestegg_init(&input->nestegg_ctx, io, NULL)) goto fail; @@ -550,9 +453,9 @@ file_is_webm(struct input_ctx *input, codec_id = nestegg_track_codec_id(input->nestegg_ctx, i); if (codec_id == NESTEGG_CODEC_VP8) { - *fourcc = VP8_FOURCC_MASK; + input->vpx_input_ctx->fourcc = VP8_FOURCC_MASK; } else if (codec_id == NESTEGG_CODEC_VP9) { - *fourcc = VP9_FOURCC_MASK; + input->vpx_input_ctx->fourcc = VP9_FOURCC_MASK; } else { fprintf(stderr, "Not VPx video, quitting.\n"); exit(1); @@ -563,14 +466,14 @@ file_is_webm(struct input_ctx *input, if (nestegg_track_video_params(input->nestegg_ctx, i, ¶ms)) goto fail; - *fps_den = 0; - *fps_num = 0; - *width = params.width; - *height = params.height; + input->vpx_input_ctx->framerate.denominator = 0; + input->vpx_input_ctx->framerate.numerator = 0; + input->vpx_input_ctx->width = params.width; + input->vpx_input_ctx->height = params.height; return 1; fail: input->nestegg_ctx = NULL; - rewind(input->infile); + rewind(input->vpx_input_ctx->file); return 0; } @@ -663,18 +566,18 @@ void generate_filename(const char *pattern, char *out, size_t q_len, int main_loop(int argc, const char **argv_) { - vpx_codec_ctx_t decoder; + vpx_codec_ctx_t decoder; char *fn = NULL; int i; uint8_t *buf = NULL; - size_t buf_sz = 0, buf_alloc_sz = 0; + size_t bytes_in_buffer = 0, buffer_size = 0; FILE *infile; - int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0; + int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0; + int do_md5 = 0, progress = 0; int stop_after = 0, postproc = 0, summary = 0, quiet = 1; int arg_skip = 0; int ec_enabled = 0; vpx_codec_iface_t *iface = NULL; - unsigned int fourcc; unsigned long dx_time = 0; struct arg arg; char **argv, **argi, **argj; @@ -682,10 +585,6 @@ int main_loop(int argc, const char **argv_) { char outfile[PATH_MAX]; int single_file; int use_y4m = 1; - unsigned int width; - unsigned int height; - unsigned int fps_den; - unsigned int fps_num; void *out = NULL; vpx_codec_dec_cfg_t cfg = {0}; #if CONFIG_VP8_DECODER @@ -695,7 +594,6 @@ int main_loop(int argc, const char **argv_) { int vp8_dbg_color_b_modes = 0; int vp8_dbg_display_mv = 0; #endif - struct input_ctx input = {0}; int frames_corrupted = 0; int dec_flags = 0; int do_scale = 0; @@ -703,6 +601,10 @@ int main_loop(int argc, const char **argv_) { vpx_image_t *scaled_img = NULL; int frame_avail, got_data; + struct VpxDecInputContext input = {0}; + struct VpxInputContext vpx_input_ctx = {0}; + input.vpx_input_ctx = &vpx_input_ctx; + /* Parse command line */ exec_name = argv_[0]; argv = argv_dup(argc - 1, argv_ + 1); @@ -840,14 +742,13 @@ int main_loop(int argc, const char **argv_) { return EXIT_FAILURE; } #endif - input.infile = infile; - if (file_is_ivf(infile, &fourcc, &width, &height, &fps_den, - &fps_num)) - input.kind = IVF_FILE; - else if (file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num)) - input.kind = WEBM_FILE; - else if (file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num)) - input.kind = RAW_FILE; + input.vpx_input_ctx->file = infile; + if (file_is_ivf(input.vpx_input_ctx)) + input.vpx_input_ctx->file_type = FILE_TYPE_IVF; + else if (file_is_webm(&input)) + input.vpx_input_ctx->file_type = FILE_TYPE_WEBM; + else if (file_is_raw(input.vpx_input_ctx)) + input.vpx_input_ctx->file_type = FILE_TYPE_RAW; else { fprintf(stderr, "Unrecognized input file type.\n"); return EXIT_FAILURE; @@ -874,7 +775,7 @@ int main_loop(int argc, const char **argv_) { if (single_file && !noblit) { generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1, - width, height, 0); + vpx_input_ctx.width, vpx_input_ctx.height, 0); out = out_open(outfile, do_md5); } @@ -887,8 +788,8 @@ int main_loop(int argc, const char **argv_) { return EXIT_FAILURE; } - if (input.kind == WEBM_FILE) - if (webm_guess_framerate(&input, &fps_den, &fps_num)) { + if (vpx_input_ctx.file_type == FILE_TYPE_WEBM) + if (webm_guess_framerate(&input)) { fprintf(stderr, "Failed to guess framerate -- error parsing " "webm file?\n"); return EXIT_FAILURE; @@ -899,21 +800,23 @@ int main_loop(int argc, const char **argv_) { store one, and neither does VP8. That will have to wait until these tools support WebM natively.*/ snprintf(buffer, sizeof(buffer), "YUV4MPEG2 W%u H%u F%u:%u I%c ", - width, height, fps_num, fps_den, 'p'); + vpx_input_ctx.width, vpx_input_ctx.height, + vpx_input_ctx.framerate.numerator, + vpx_input_ctx.framerate.denominator, + 'p'); out_put(out, (unsigned char *)buffer, (unsigned int)strlen(buffer), do_md5); } /* Try to determine the codec from the fourcc. */ for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) - if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) { - vpx_codec_iface_t *ivf_iface = ifaces[i].iface(); + if ((vpx_input_ctx.fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) { + vpx_codec_iface_t *vpx_iface = ifaces[i].iface(); - if (iface && iface != ivf_iface) - fprintf(stderr, "Notice -- IVF header indicates codec: %s\n", - ifaces[i].name); + if (iface && iface != vpx_iface) + warn("Header indicates codec: %s\n", ifaces[i].name); else - iface = ivf_iface; + iface = vpx_iface; break; } @@ -963,10 +866,10 @@ int main_loop(int argc, const char **argv_) { #endif - if(arg_skip) + if (arg_skip) fprintf(stderr, "Skiping first %d frames.\n", arg_skip); while (arg_skip) { - if (read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) + if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) break; arg_skip--; } @@ -983,13 +886,13 @@ int main_loop(int argc, const char **argv_) { frame_avail = 0; if (!stop_after || frame_in < stop_after) { - if(!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) { + if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) { frame_avail = 1; frame_in++; vpx_usec_timer_start(&timer); - if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0)) { + if (vpx_codec_decode(&decoder, buf, bytes_in_buffer, NULL, 0)) { const char *detail = vpx_codec_error_detail(&decoder); fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder)); @@ -1133,7 +1036,7 @@ fail: if (input.nestegg_ctx) nestegg_destroy(input.nestegg_ctx); - if (input.kind != WEBM_FILE) + if (input.vpx_input_ctx->file_type != FILE_TYPE_WEBM) free(buf); fclose(infile); free(argv); diff --git a/vpxenc.c b/vpxenc.c index b7897dbf3..377e38b81 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -10,32 +10,23 @@ #include "./vpx_config.h" -#if defined(_WIN32) || defined(__OS2__) || !CONFIG_OS_SUPPORT -#define USE_POSIX_MMAP 0 -#else -#define USE_POSIX_MMAP 1 -#endif - +#include +#include #include +#include #include #include -#include #include -#include -#include + #include "vpx/vpx_encoder.h" #if CONFIG_DECODERS #include "vpx/vpx_decoder.h" #endif -#if USE_POSIX_MMAP -#include -#include -#include -#include -#include -#endif #include "third_party/libyuv/include/libyuv/scale.h" +#include "./args.h" +#include "./ivfdec.h" +#include "./ivfenc.h" #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER #include "vpx/vp8cx.h" @@ -118,199 +109,28 @@ static void warn_or_exit_on_error(vpx_codec_ctx_t *ctx, int fatal, va_end(ap); } -enum video_file_type { - FILE_TYPE_RAW, - FILE_TYPE_IVF, - FILE_TYPE_Y4M -}; - -struct detect_buffer { - char buf[4]; - size_t buf_read; - size_t position; -}; - - -struct input_state { - char *fn; - FILE *file; - off_t length; - y4m_input y4m; - struct detect_buffer detect; - enum video_file_type file_type; - unsigned int w; - unsigned int h; - struct vpx_rational framerate; - int use_i420; - int only_i420; -}; - -#define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */ -static int read_frame(struct input_state *input, vpx_image_t *img) { - FILE *f = input->file; - enum video_file_type file_type = input->file_type; - y4m_input *y4m = &input->y4m; - struct detect_buffer *detect = &input->detect; - int plane = 0; +int read_frame(struct VpxInputContext *input_ctx, vpx_image_t *img) { + FILE *f = input_ctx->file; + y4m_input *y4m = &input_ctx->y4m; int shortread = 0; - if (file_type == FILE_TYPE_Y4M) { + if (input_ctx->file_type == FILE_TYPE_Y4M) { if (y4m_input_fetch_frame(y4m, f, img) < 1) return 0; } else { - if (file_type == FILE_TYPE_IVF) { - char junk[IVF_FRAME_HDR_SZ]; - - /* Skip the frame header. We know how big the frame should be. See - * write_ivf_frame_header() for documentation on the frame header - * layout. - */ - (void) fread(junk, 1, IVF_FRAME_HDR_SZ, f); - } - - for (plane = 0; plane < 3; plane++) { - unsigned char *ptr; - int w = (plane ? (1 + img->d_w) / 2 : img->d_w); - int h = (plane ? (1 + img->d_h) / 2 : img->d_h); - int r; - - /* Determine the correct plane based on the image format. The for-loop - * always counts in Y,U,V order, but this may not match the order of - * the data on disk. - */ - switch (plane) { - case 1: - ptr = img->planes[img->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_V : VPX_PLANE_U]; - break; - case 2: - ptr = img->planes[img->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_U : VPX_PLANE_V]; - break; - default: - ptr = img->planes[plane]; - } - - for (r = 0; r < h; r++) { - size_t needed = w; - size_t buf_position = 0; - const size_t left = detect->buf_read - detect->position; - if (left > 0) { - const size_t more = (left < needed) ? left : needed; - memcpy(ptr, detect->buf + detect->position, more); - buf_position = more; - needed -= more; - detect->position += more; - } - if (needed > 0) { - shortread |= (fread(ptr + buf_position, 1, needed, f) < needed); - } - - ptr += img->stride[plane]; - } - } + shortread = read_yuv_frame(input_ctx, img); } return !shortread; } - -unsigned int file_is_y4m(FILE *infile, - y4m_input *y4m, - char detect[4]) { +int file_is_y4m(FILE *infile, y4m_input *y4m, const char detect[4]) { if (memcmp(detect, "YUV4", 4) == 0) { return 1; } return 0; } -#define IVF_FILE_HDR_SZ (32) -unsigned int file_is_ivf(struct input_state *input, - unsigned int *fourcc) { - char raw_hdr[IVF_FILE_HDR_SZ]; - int is_ivf = 0; - FILE *infile = input->file; - unsigned int *width = &input->w; - unsigned int *height = &input->h; - struct detect_buffer *detect = &input->detect; - - if (memcmp(detect->buf, "DKIF", 4) != 0) - return 0; - - /* See write_ivf_file_header() for more documentation on the file header - * layout. - */ - if (fread(raw_hdr + 4, 1, IVF_FILE_HDR_SZ - 4, infile) - == IVF_FILE_HDR_SZ - 4) { - { - is_ivf = 1; - - if (mem_get_le16(raw_hdr + 4) != 0) - warn("Unrecognized IVF version! This file may not decode " - "properly."); - - *fourcc = mem_get_le32(raw_hdr + 8); - } - } - - if (is_ivf) { - *width = mem_get_le16(raw_hdr + 12); - *height = mem_get_le16(raw_hdr + 14); - detect->position = 4; - } - - return is_ivf; -} - - -static void write_ivf_file_header(FILE *outfile, - const vpx_codec_enc_cfg_t *cfg, - unsigned int fourcc, - 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); -} - - -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, (int)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 void write_ivf_frame_size(FILE *outfile, size_t size) { - char header[4]; - mem_put_le32(header, (int)size); - (void) fwrite(header, 1, 4, outfile); -} - - /* Murmur hash derived from public domain reference implementation at * http:// sites.google.com/site/murmurhash/ @@ -360,7 +180,6 @@ static unsigned int murmur(const void *key, int len, unsigned int seed) { } -#include "args.h" static const arg_def_t debugmode = ARG_DEF("D", "debug", 0, "Debug mode (makes output deterministic)"); static const arg_def_t outputfile = ARG_DEF("o", "output", 1, @@ -814,9 +633,9 @@ struct rate_hist { }; -static void init_rate_histogram(struct rate_hist *hist, +static void init_rate_histogram(struct rate_hist *hist, const vpx_codec_enc_cfg_t *cfg, - const vpx_rational_t *fps) { + const vpx_rational_t *fps) { int i; /* Determine the number of samples in the buffer. Use the file's framerate @@ -1212,12 +1031,10 @@ static void parse_global_config(struct global_config *global, char **argv) { } -void open_input_file(struct input_state *input) { - unsigned int fourcc; - +void open_input_file(struct VpxInputContext *input) { /* Parse certain options from the input file, if possible */ - input->file = strcmp(input->fn, "-") ? fopen(input->fn, "rb") - : set_binary_mode(stdin); + input->file = strcmp(input->filename, "-") + ? fopen(input->filename, "rb") : set_binary_mode(stdin); if (!input->file) fatal("Failed to open input file"); @@ -1241,14 +1058,14 @@ void open_input_file(struct input_state *input) { if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4, input->only_i420) >= 0) { input->file_type = FILE_TYPE_Y4M; - input->w = input->y4m.pic_w; - input->h = input->y4m.pic_h; - input->framerate.num = input->y4m.fps_n; - input->framerate.den = input->y4m.fps_d; + input->width = input->y4m.pic_w; + input->height = input->y4m.pic_h; + input->framerate.numerator = input->y4m.fps_n; + input->framerate.denominator = input->y4m.fps_d; input->use_i420 = 0; } else fatal("Unsupported Y4M stream."); - } else if (input->detect.buf_read == 4 && file_is_ivf(input, &fourcc)) { + } else if (input->detect.buf_read == 4 && file_is_ivf(input)) { fatal("IVF is not supported as input."); } else { input->file_type = FILE_TYPE_RAW; @@ -1256,7 +1073,7 @@ void open_input_file(struct input_state *input) { } -static void close_input_file(struct input_state *input) { +static void close_input_file(struct VpxInputContext *input) { fclose(input->file); if (input->file_type == FILE_TYPE_Y4M) y4m_input_close(&input->y4m); @@ -1531,7 +1348,7 @@ static void set_default_kf_interval(struct stream_state *stream, static void show_stream_config(struct stream_state *stream, struct global_config *global, - struct input_state *input) { + struct VpxInputContext *input) { #define SHOW(field) \ fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field) @@ -1539,7 +1356,7 @@ static void show_stream_config(struct stream_state *stream, if (stream->index == 0) { fprintf(stderr, "Codec: %s\n", vpx_codec_iface_name(global->codec->iface())); - fprintf(stderr, "Source file: %s Format: %s\n", input->fn, + fprintf(stderr, "Source file: %s Format: %s\n", input->filename, input->use_i420 ? "I420" : "YV12"); } if (stream->next || stream->index) @@ -1598,7 +1415,7 @@ static void open_output_file(struct stream_state *stream, stream->config.stereo_fmt, global->codec->fourcc); } else - write_ivf_file_header(stream->file, &stream->config.cfg, + ivf_write_file_header(stream->file, &stream->config.cfg, global->codec->fourcc, 0); } @@ -1611,7 +1428,7 @@ static void close_output_file(struct stream_state *stream, stream->ebml.cue_list = NULL; } else { if (!fseek(stream->file, 0, SEEK_SET)) - write_ivf_file_header(stream->file, &stream->config.cfg, + ivf_write_file_header(stream->file, &stream->config.cfg, fourcc, stream->frames_out); } @@ -1771,14 +1588,14 @@ static void get_cx_data(struct stream_state *stream, ivf_header_pos = ftello(stream->file); fsize = pkt->data.frame.sz; - write_ivf_frame_header(stream->file, pkt); + ivf_write_frame_header(stream->file, pkt); } else { fsize += pkt->data.frame.sz; if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) { off_t currpos = ftello(stream->file); fseeko(stream->file, ivf_header_pos, SEEK_SET); - write_ivf_frame_size(stream->file, fsize); + ivf_write_frame_size(stream->file, fsize); fseeko(stream->file, currpos, SEEK_SET); } } @@ -1936,8 +1753,8 @@ int main(int argc, const char **argv_) { vpx_image_t raw; int frame_avail, got_data; - struct input_state input = {0}; - struct global_config global; + struct VpxInputContext input = {0}; + struct global_config global; struct stream_state *streams = NULL; char **argv, **argi; uint64_t cx_time = 0; @@ -1950,8 +1767,8 @@ int main(int argc, const char **argv_) { usage_exit(); /* Setup default input stream settings */ - input.framerate.num = 30; - input.framerate.den = 1; + input.framerate.numerator = 30; + input.framerate.denominator = 1; input.use_i420 = 1; input.only_i420 = 1; @@ -1983,9 +1800,9 @@ int main(int argc, const char **argv_) { die("Error: Unrecognized option %s\n", *argi); /* Handle non-option arguments */ - input.fn = argv[0]; + input.filename = argv[0]; - if (!input.fn) + if (!input.filename) usage_exit(); #if CONFIG_NON420 @@ -2005,20 +1822,20 @@ int main(int argc, const char **argv_) { /* If the input file doesn't specify its w/h (raw files), try to get * the data from the first stream's configuration. */ - if (!input.w || !input.h) + if (!input.width || !input.height) FOREACH_STREAM( { if (stream->config.cfg.g_w && stream->config.cfg.g_h) { - input.w = stream->config.cfg.g_w; - input.h = stream->config.cfg.g_h; + input.width = stream->config.cfg.g_w; + input.height = stream->config.cfg.g_h; break; } }); /* Update stream configurations from the input file's parameters */ - if (!input.w || !input.h) + if (!input.width || !input.height) fatal("Specify stream dimensions with --width (-w) " " and --height (-h)"); - FOREACH_STREAM(set_stream_dimensions(stream, input.w, input.h)); + FOREACH_STREAM(set_stream_dimensions(stream, input.width, input.height)); FOREACH_STREAM(validate_stream_config(stream)); /* Ensure that --passes and --pass are consistent. If --pass is set and @@ -2034,8 +1851,10 @@ int main(int argc, const char **argv_) { /* Use the frame rate from the file only if none was specified * on the command-line. */ - if (!global.have_framerate) - global.framerate = input.framerate; + if (!global.have_framerate) { + global.framerate.num = input.framerate.numerator; + global.framerate.den = input.framerate.denominator; + } FOREACH_STREAM(set_default_kf_interval(stream, &global)); @@ -2053,7 +1872,7 @@ int main(int argc, const char **argv_) { vpx_img_alloc(&raw, input.use_i420 ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_YV12, - input.w, input.h, 32); + input.width, input.height, 32); FOREACH_STREAM(init_rate_histogram(&stream->rate_hist, &stream->config.cfg,