Adding video reader/writer APIs.
authorDmitry Kovalev <dkovalev@google.com>
Thu, 6 Feb 2014 02:34:46 +0000 (18:34 -0800)
committerDmitry Kovalev <dkovalev@google.com>
Thu, 6 Feb 2014 04:34:51 +0000 (20:34 -0800)
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

13 files changed:
examples.mk
examples/decode_to_md5.c
examples/decode_with_drops.c
examples/postproc.c
examples/simple_decoder.c
examples/simple_encoder.c
ivfdec.c
ivfdec.h
video_common.h [new file with mode: 0644]
video_reader.c [new file with mode: 0644]
video_reader.h [new file with mode: 0644]
video_writer.c [new file with mode: 0644]
video_writer.h [new file with mode: 0644]

index b2bdf68..078ce34 100644 (file)
@@ -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
index bba2182..077513c 100644 (file)
@@ -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;
 }
index 12686de..e8fc076 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#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;
 }
index 4ec2d1f..7281f1e 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#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;
 }
index 23399f4..4dc9308 100644 (file)
@@ -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;
 }
index e64a962..0ae012c 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <string.h>
-#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 <width> <height> <infile> <outfile>\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 <width> <height> <infile> <outfile>\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;
 }
index b9fec26..40394a8 100644 (file)
--- 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;
-}
index e960b4a..dd29cc6 100644 (file)
--- 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 (file)
index 0000000..44b27a8
--- /dev/null
@@ -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 (file)
index 0000000..4be7483
--- /dev/null
@@ -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 <stdlib.h>
+#include <string.h>
+
+#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 (file)
index 0000000..a62c6d7
--- /dev/null
@@ -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 (file)
index 0000000..3695236
--- /dev/null
@@ -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 <stdlib.h>
+
+#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 (file)
index 0000000..5dbfe52
--- /dev/null
@@ -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_