vpxenc.c 77.6 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5 6
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS.  All contributing project authors may
8
 *  be found in the AUTHORS file in the root of the source tree.
John Koleszar's avatar
John Koleszar committed
9 10
 */

Christian Duvivier's avatar
Christian Duvivier committed
11
#include "vpx_config.h"
John Koleszar's avatar
John Koleszar committed
12

13
#if defined(_WIN32) || !CONFIG_OS_SUPPORT
14 15 16 17
#define USE_POSIX_MMAP 0
#else
#define USE_POSIX_MMAP 1
#endif
John Koleszar's avatar
John Koleszar committed
18 19 20 21 22

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
John Koleszar's avatar
John Koleszar committed
23
#include <limits.h>
24
#include <assert.h>
25
#include "vpx/vpx_encoder.h"
John Koleszar's avatar
John Koleszar committed
26
#include "vpx/vpx_decoder.h"
John Koleszar's avatar
John Koleszar committed
27 28 29 30 31 32 33
#if USE_POSIX_MMAP
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#endif
John Koleszar's avatar
John Koleszar committed
34 35

#if CONFIG_VP9_ENCODER
36
#include "vpx/vp8cx.h"
John Koleszar's avatar
John Koleszar committed
37 38
#endif
#if CONFIG_VP9_DECODER
39
#include "vpx/vp8dx.h"
John Koleszar's avatar
John Koleszar committed
40 41
#endif

John Koleszar's avatar
John Koleszar committed
42 43
#include "vpx_ports/mem_ops.h"
#include "vpx_ports/vpx_timer.h"
John Koleszar's avatar
John Koleszar committed
44
#include "tools_common.h"
45
#include "y4minput.h"
John Koleszar's avatar
John Koleszar committed
46 47 48 49 50 51 52 53 54 55
#include "libmkv/EbmlWriter.h"
#include "libmkv/EbmlIDs.h"

/* Need special handling of these functions on Windows */
#if defined(_MSC_VER)
/* MSVS doesn't define off_t, and uses _f{seek,tell}i64 */
typedef __int64 off_t;
#define fseeko _fseeki64
#define ftello _ftelli64
#elif defined(_WIN32)
John Koleszar's avatar
John Koleszar committed
56 57
/* MinGW defines off_t as long
   and uses f{seek,tell}o64/off64_t for large files */
John Koleszar's avatar
John Koleszar committed
58 59
#define fseeko fseeko64
#define ftello ftello64
John Koleszar's avatar
John Koleszar committed
60
#define off_t off64_t
John Koleszar's avatar
John Koleszar committed
61 62
#endif

John Koleszar's avatar
John Koleszar committed
63
#define LITERALU64(hi,lo) ((((uint64_t)hi)<<32)|lo)
John Koleszar's avatar
John Koleszar committed
64

65 66 67 68 69 70 71 72
/* We should use 32-bit file operations in WebM file format
 * when building ARM executable file (.axf) with RVCT */
#if !CONFIG_OS_SUPPORT
typedef long off_t;
#define fseeko fseek
#define ftello ftell
#endif

John Koleszar's avatar
John Koleszar committed
73 74 75 76 77 78
/* Swallow warnings about unused results of fread/fwrite */
static size_t wrap_fread(void *ptr, size_t size, size_t nmemb,
                         FILE *stream) {
  return fread(ptr, size, nmemb, stream);
}
#define fread wrap_fread
John Koleszar's avatar
John Koleszar committed
79

John Koleszar's avatar
John Koleszar committed
80 81 82 83 84
static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb,
                          FILE *stream) {
  return fwrite(ptr, size, nmemb, stream);
}
#define fwrite wrap_fwrite
John Koleszar's avatar
John Koleszar committed
85

Jim Bankoski's avatar
Jim Bankoski committed
86

John Koleszar's avatar
John Koleszar committed
87
static const char *exec_name;
Jim Bankoski's avatar
Jim Bankoski committed
88 89

static const struct codec_item {
John Koleszar's avatar
John Koleszar committed
90
  char const              *name;
Jim Bankoski's avatar
Jim Bankoski committed
91
  const vpx_codec_iface_t *(*iface)(void);
John Koleszar's avatar
John Koleszar committed
92
  const vpx_codec_iface_t *(*dx_iface)(void);
Jim Bankoski's avatar
Jim Bankoski committed
93 94
  unsigned int             fourcc;
} codecs[] = {
John Koleszar's avatar
John Koleszar committed
95 96 97 98 99
#if CONFIG_VP9_ENCODER && CONFIG_VP9_DECODER
  {"vp9", &vpx_codec_vp8_cx, &vpx_codec_vp8_dx, 0x30385056},
#endif
#if CONFIG_VP9_ENCODER && !CONFIG_VP9_DECODER
  {"vp9", &vpx_codec_vp8_cx, NULL, 0x30385056},
100 101 102
#endif
};

John Koleszar's avatar
John Koleszar committed
103 104
static void usage_exit();

John Koleszar's avatar
John Koleszar committed
105 106 107 108 109 110 111 112 113 114 115 116
#define LOG_ERROR(label) do \
  {\
    const char *l=label;\
    va_list ap;\
    va_start(ap, fmt);\
    if(l)\
      fprintf(stderr, "%s: ", l);\
    vfprintf(stderr, fmt, ap);\
    fprintf(stderr, "\n");\
    va_end(ap);\
  } while(0)

John Koleszar's avatar
John Koleszar committed
117
void die(const char *fmt, ...) {
John Koleszar's avatar
John Koleszar committed
118
  LOG_ERROR(NULL);
John Koleszar's avatar
John Koleszar committed
119
  usage_exit();
John Koleszar's avatar
John Koleszar committed
120 121
}

John Koleszar's avatar
John Koleszar committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137

void fatal(const char *fmt, ...) {
  LOG_ERROR("Fatal");
  exit(EXIT_FAILURE);
}


void warn(const char *fmt, ...) {
  LOG_ERROR("Warning");
}


static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) {
  va_list ap;

  va_start(ap, s);
John Koleszar's avatar
John Koleszar committed
138 139
  if (ctx->err) {
    const char *detail = vpx_codec_error_detail(ctx);
John Koleszar's avatar
John Koleszar committed
140

John Koleszar's avatar
John Koleszar committed
141 142
    vfprintf(stderr, s, ap);
    fprintf(stderr, ": %s\n", vpx_codec_error(ctx));
John Koleszar's avatar
John Koleszar committed
143

John Koleszar's avatar
John Koleszar committed
144 145
    if (detail)
      fprintf(stderr, "    %s\n", detail);
John Koleszar's avatar
John Koleszar committed
146

John Koleszar's avatar
John Koleszar committed
147 148
    exit(EXIT_FAILURE);
  }
John Koleszar's avatar
John Koleszar committed
149 150 151 152 153
}

/* This structure is used to abstract the different ways of handling
 * first pass statistics.
 */
John Koleszar's avatar
John Koleszar committed
154 155 156 157 158 159
typedef struct {
  vpx_fixed_buf_t buf;
  int             pass;
  FILE           *file;
  char           *buf_ptr;
  size_t          buf_alloc_sz;
John Koleszar's avatar
John Koleszar committed
160 161
} stats_io_t;

John Koleszar's avatar
John Koleszar committed
162 163
int stats_open_file(stats_io_t *stats, const char *fpf, int pass) {
  int res;
John Koleszar's avatar
John Koleszar committed
164

John Koleszar's avatar
John Koleszar committed
165
  stats->pass = pass;
John Koleszar's avatar
John Koleszar committed
166

John Koleszar's avatar
John Koleszar committed
167 168 169 170 171 172
  if (pass == 0) {
    stats->file = fopen(fpf, "wb");
    stats->buf.sz = 0;
    stats->buf.buf = NULL,
               res = (stats->file != NULL);
  } else {
John Koleszar's avatar
John Koleszar committed
173 174
#if 0
#elif USE_POSIX_MMAP
John Koleszar's avatar
John Koleszar committed
175 176 177 178 179 180 181 182 183 184
    struct stat stat_buf;
    int fd;

    fd = open(fpf, O_RDONLY);
    stats->file = fdopen(fd, "rb");
    fstat(fd, &stat_buf);
    stats->buf.sz = stat_buf.st_size;
    stats->buf.buf = mmap(NULL, stats->buf.sz, PROT_READ, MAP_PRIVATE,
                          fd, 0);
    res = (stats->buf.buf != NULL);
John Koleszar's avatar
John Koleszar committed
185
#else
John Koleszar's avatar
John Koleszar committed
186
    size_t nbytes;
John Koleszar's avatar
John Koleszar committed
187

John Koleszar's avatar
John Koleszar committed
188
    stats->file = fopen(fpf, "rb");
John Koleszar's avatar
John Koleszar committed
189

John Koleszar's avatar
John Koleszar committed
190 191
    if (fseek(stats->file, 0, SEEK_END))
      fatal("First-pass stats file must be seekable!");
John Koleszar's avatar
John Koleszar committed
192

John Koleszar's avatar
John Koleszar committed
193 194
    stats->buf.sz = stats->buf_alloc_sz = ftell(stats->file);
    rewind(stats->file);
John Koleszar's avatar
John Koleszar committed
195

John Koleszar's avatar
John Koleszar committed
196
    stats->buf.buf = malloc(stats->buf_alloc_sz);
John Koleszar's avatar
John Koleszar committed
197

John Koleszar's avatar
John Koleszar committed
198 199 200
    if (!stats->buf.buf)
      fatal("Failed to allocate first-pass stats buffer (%lu bytes)",
            (unsigned long)stats->buf_alloc_sz);
John Koleszar's avatar
John Koleszar committed
201

John Koleszar's avatar
John Koleszar committed
202 203
    nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file);
    res = (nbytes == stats->buf.sz);
John Koleszar's avatar
John Koleszar committed
204
#endif
John Koleszar's avatar
John Koleszar committed
205
  }
John Koleszar's avatar
John Koleszar committed
206

John Koleszar's avatar
John Koleszar committed
207
  return res;
John Koleszar's avatar
John Koleszar committed
208 209
}

John Koleszar's avatar
John Koleszar committed
210 211 212
int stats_open_mem(stats_io_t *stats, int pass) {
  int res;
  stats->pass = pass;
John Koleszar's avatar
John Koleszar committed
213

John Koleszar's avatar
John Koleszar committed
214 215 216 217 218
  if (!pass) {
    stats->buf.sz = 0;
    stats->buf_alloc_sz = 64 * 1024;
    stats->buf.buf = malloc(stats->buf_alloc_sz);
  }
John Koleszar's avatar
John Koleszar committed
219

John Koleszar's avatar
John Koleszar committed
220 221 222
  stats->buf_ptr = stats->buf.buf;
  res = (stats->buf.buf != NULL);
  return res;
John Koleszar's avatar
John Koleszar committed
223 224 225
}


John Koleszar's avatar
John Koleszar committed
226 227 228
void stats_close(stats_io_t *stats, int last_pass) {
  if (stats->file) {
    if (stats->pass == last_pass) {
John Koleszar's avatar
John Koleszar committed
229 230
#if 0
#elif USE_POSIX_MMAP
John Koleszar's avatar
John Koleszar committed
231
      munmap(stats->buf.buf, stats->buf.sz);
John Koleszar's avatar
John Koleszar committed
232
#else
John Koleszar's avatar
John Koleszar committed
233
      free(stats->buf.buf);
John Koleszar's avatar
John Koleszar committed
234 235
#endif
    }
John Koleszar's avatar
John Koleszar committed
236 237 238 239 240 241 242

    fclose(stats->file);
    stats->file = NULL;
  } else {
    if (stats->pass == last_pass)
      free(stats->buf.buf);
  }
John Koleszar's avatar
John Koleszar committed
243 244
}

John Koleszar's avatar
John Koleszar committed
245 246
void stats_write(stats_io_t *stats, const void *pkt, size_t len) {
  if (stats->file) {
John Koleszar's avatar
John Koleszar committed
247
    (void) fwrite(pkt, 1, len, stats->file);
John Koleszar's avatar
John Koleszar committed
248 249 250 251 252 253 254 255 256
  } else {
    if (stats->buf.sz + len > stats->buf_alloc_sz) {
      size_t  new_sz = stats->buf_alloc_sz + 64 * 1024;
      char   *new_ptr = realloc(stats->buf.buf, new_sz);

      if (new_ptr) {
        stats->buf_ptr = new_ptr + (stats->buf_ptr - (char *)stats->buf.buf);
        stats->buf.buf = new_ptr;
        stats->buf_alloc_sz = new_sz;
John Koleszar's avatar
John Koleszar committed
257 258
      } else
        fatal("Failed to realloc firstpass stats buffer.");
John Koleszar's avatar
John Koleszar committed
259 260
    }

John Koleszar's avatar
John Koleszar committed
261 262 263 264
    memcpy(stats->buf_ptr, pkt, len);
    stats->buf.sz += len;
    stats->buf_ptr += len;
  }
John Koleszar's avatar
John Koleszar committed
265 266
}

John Koleszar's avatar
John Koleszar committed
267 268
vpx_fixed_buf_t stats_get(stats_io_t *stats) {
  return stats->buf;
John Koleszar's avatar
John Koleszar committed
269 270
}

271
/* Stereo 3D packed frame format */
John Koleszar's avatar
John Koleszar committed
272 273 274 275 276 277
typedef enum stereo_format {
  STEREO_FORMAT_MONO       = 0,
  STEREO_FORMAT_LEFT_RIGHT = 1,
  STEREO_FORMAT_BOTTOM_TOP = 2,
  STEREO_FORMAT_TOP_BOTTOM = 3,
  STEREO_FORMAT_RIGHT_LEFT = 11
278 279
} stereo_format_t;

John Koleszar's avatar
John Koleszar committed
280 281 282 283
enum video_file_type {
  FILE_TYPE_RAW,
  FILE_TYPE_IVF,
  FILE_TYPE_Y4M
284 285
};

286
struct detect_buffer {
John Koleszar's avatar
John Koleszar committed
287 288 289
  char buf[4];
  size_t buf_read;
  size_t position;
290 291 292
};


John Koleszar's avatar
John Koleszar committed
293 294 295 296 297 298 299 300 301 302 303 304 305
struct input_state {
  char                 *fn;
  FILE                 *file;
  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;
};


John Koleszar's avatar
John Koleszar committed
306
#define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */
John Koleszar's avatar
John Koleszar committed
307 308 309 310 311
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;
John Koleszar's avatar
John Koleszar committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325
  int plane = 0;
  int shortread = 0;

  if (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.
       */
John Koleszar's avatar
John Koleszar committed
326
      (void) fread(junk, 1, IVF_FRAME_HDR_SZ, f);
John Koleszar's avatar
John Koleszar committed
327
    }
328

John Koleszar's avatar
John Koleszar committed
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
    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;
John Koleszar's avatar
John Koleszar committed
360
        }
John Koleszar's avatar
John Koleszar committed
361 362
        if (needed > 0) {
          shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
John Koleszar's avatar
John Koleszar committed
363
        }
John Koleszar's avatar
John Koleszar committed
364 365 366

        ptr += img->stride[plane];
      }
John Koleszar's avatar
John Koleszar committed
367
    }
John Koleszar's avatar
John Koleszar committed
368
  }
John Koleszar's avatar
John Koleszar committed
369

John Koleszar's avatar
John Koleszar committed
370
  return !shortread;
John Koleszar's avatar
John Koleszar committed
371 372 373
}


374
unsigned int file_is_y4m(FILE      *infile,
375
                         y4m_input *y4m,
John Koleszar's avatar
John Koleszar committed
376 377 378 379 380
                         char       detect[4]) {
  if (memcmp(detect, "YUV4", 4) == 0) {
    return 1;
  }
  return 0;
381 382
}

John Koleszar's avatar
John Koleszar committed
383
#define IVF_FILE_HDR_SZ (32)
John Koleszar's avatar
John Koleszar committed
384 385
unsigned int file_is_ivf(struct input_state *input,
                         unsigned int *fourcc) {
John Koleszar's avatar
John Koleszar committed
386 387
  char raw_hdr[IVF_FILE_HDR_SZ];
  int is_ivf = 0;
John Koleszar's avatar
John Koleszar committed
388 389 390 391
  FILE *infile = input->file;
  unsigned int *width = &input->w;
  unsigned int *height = &input->h;
  struct detect_buffer *detect = &input->detect;
John Koleszar's avatar
John Koleszar committed
392

John Koleszar's avatar
John Koleszar committed
393 394
  if (memcmp(detect->buf, "DKIF", 4) != 0)
    return 0;
395

John Koleszar's avatar
John Koleszar committed
396 397 398 399 400
  /* 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) {
John Koleszar's avatar
John Koleszar committed
401
    {
John Koleszar's avatar
John Koleszar committed
402
      is_ivf = 1;
John Koleszar's avatar
John Koleszar committed
403

John Koleszar's avatar
John Koleszar committed
404
      if (mem_get_le16(raw_hdr + 4) != 0)
John Koleszar's avatar
John Koleszar committed
405 406
        warn("Unrecognized IVF version! This file may not decode "
             "properly.");
John Koleszar's avatar
John Koleszar committed
407

John Koleszar's avatar
John Koleszar committed
408
      *fourcc = mem_get_le32(raw_hdr + 8);
John Koleszar's avatar
John Koleszar committed
409
    }
John Koleszar's avatar
John Koleszar committed
410
  }
John Koleszar's avatar
John Koleszar committed
411

John Koleszar's avatar
John Koleszar committed
412 413 414 415 416
  if (is_ivf) {
    *width = mem_get_le16(raw_hdr + 12);
    *height = mem_get_le16(raw_hdr + 14);
    detect->position = 4;
  }
John Koleszar's avatar
John Koleszar committed
417

John Koleszar's avatar
John Koleszar committed
418
  return is_ivf;
John Koleszar's avatar
John Koleszar committed
419 420 421 422 423 424
}


static void write_ivf_file_header(FILE *outfile,
                                  const vpx_codec_enc_cfg_t *cfg,
                                  unsigned int fourcc,
John Koleszar's avatar
John Koleszar committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
                                  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 */

John Koleszar's avatar
John Koleszar committed
445
  (void) fwrite(header, 1, 32, outfile);
John Koleszar's avatar
John Koleszar committed
446 447 448 449
}


static void write_ivf_frame_header(FILE *outfile,
John Koleszar's avatar
John Koleszar committed
450 451 452
                                   const vpx_codec_cx_pkt_t *pkt) {
  char             header[12];
  vpx_codec_pts_t  pts;
John Koleszar's avatar
John Koleszar committed
453

John Koleszar's avatar
John Koleszar committed
454 455
  if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
    return;
John Koleszar's avatar
John Koleszar committed
456

John Koleszar's avatar
John Koleszar committed
457
  pts = pkt->data.frame.pts;
John Koleszar's avatar
John Koleszar committed
458
  mem_put_le32(header, (int)pkt->data.frame.sz);
John Koleszar's avatar
John Koleszar committed
459 460
  mem_put_le32(header + 4, pts & 0xFFFFFFFF);
  mem_put_le32(header + 8, pts >> 32);
John Koleszar's avatar
John Koleszar committed
461

John Koleszar's avatar
John Koleszar committed
462 463 464 465 466 467 468
  (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);
John Koleszar's avatar
John Koleszar committed
469 470
}

John Koleszar's avatar
John Koleszar committed
471 472 473 474

typedef off_t EbmlLoc;


John Koleszar's avatar
John Koleszar committed
475 476 477
struct cue_entry {
  unsigned int time;
  uint64_t     loc;
John Koleszar's avatar
John Koleszar committed
478 479 480
};


John Koleszar's avatar
John Koleszar committed
481 482
struct EbmlGlobal {
  int debug;
483

John Koleszar's avatar
John Koleszar committed
484 485 486
  FILE    *stream;
  int64_t last_pts_ms;
  vpx_rational_t  framerate;
John Koleszar's avatar
John Koleszar committed
487

John Koleszar's avatar
John Koleszar committed
488 489 490 491 492 493 494
  /* These pointers are to the start of an element */
  off_t    position_reference;
  off_t    seek_info_pos;
  off_t    segment_info_pos;
  off_t    track_pos;
  off_t    cue_pos;
  off_t    cluster_pos;
John Koleszar's avatar
John Koleszar committed
495

John Koleszar's avatar
John Koleszar committed
496 497
  /* This pointer is to a specific element to be serialized */
  off_t    track_id_pos;
John Koleszar's avatar
John Koleszar committed
498

John Koleszar's avatar
John Koleszar committed
499 500 501
  /* These pointers are to the size field of the element */
  EbmlLoc  startSegment;
  EbmlLoc  startCluster;
John Koleszar's avatar
John Koleszar committed
502

John Koleszar's avatar
John Koleszar committed
503 504
  uint32_t cluster_timecode;
  int      cluster_open;
John Koleszar's avatar
John Koleszar committed
505

John Koleszar's avatar
John Koleszar committed
506 507
  struct cue_entry *cue_list;
  unsigned int      cues;
John Koleszar's avatar
John Koleszar committed
508 509 510 511

};


John Koleszar's avatar
John Koleszar committed
512
void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
John Koleszar's avatar
John Koleszar committed
513
  (void) fwrite(buffer_in, 1, len, glob->stream);
John Koleszar's avatar
John Koleszar committed
514 515
}

516
#define WRITE_BUFFER(s) \
John Koleszar's avatar
John Koleszar committed
517 518
  for(i = len-1; i>=0; i--)\
  { \
John Koleszar's avatar
John Koleszar committed
519
    x = (char)(*(const s *)buffer_in >> (i * CHAR_BIT)); \
520
    Ebml_Write(glob, &x, 1); \
John Koleszar's avatar
John Koleszar committed
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
  }
void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, unsigned long len) {
  char x;
  int i;

  /* buffer_size:
   * 1 - int8_t;
   * 2 - int16_t;
   * 3 - int32_t;
   * 4 - int64_t;
   */
  switch (buffer_size) {
    case 1:
      WRITE_BUFFER(int8_t)
      break;
    case 2:
      WRITE_BUFFER(int16_t)
      break;
    case 4:
      WRITE_BUFFER(int32_t)
      break;
    case 8:
      WRITE_BUFFER(int64_t)
      break;
    default:
      break;
  }
John Koleszar's avatar
John Koleszar committed
548
}
549
#undef WRITE_BUFFER
John Koleszar's avatar
John Koleszar committed
550

551
/* Need a fixed size serializer for the track ID. libmkv provides a 64 bit
John Koleszar's avatar
John Koleszar committed
552 553
 * one, but not a 32 bit one.
 */
John Koleszar's avatar
John Koleszar committed
554 555 556 557 558
static void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint64_t ui) {
  unsigned char sizeSerialized = 4 | 0x80;
  Ebml_WriteID(glob, class_id);
  Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
  Ebml_Serialize(glob, &ui, sizeof(ui), 4);
John Koleszar's avatar
John Koleszar committed
559 560 561
}


John Koleszar's avatar
John Koleszar committed
562 563
static void
Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc,
John Koleszar's avatar
John Koleszar committed
564
                     unsigned long class_id) {
John Koleszar's avatar
John Koleszar committed
565 566 567
  /* todo this is always taking 8 bytes, this may need later optimization */
  /* this is a key that says length unknown */
  uint64_t unknownLen = LITERALU64(0x01FFFFFF, 0xFFFFFFFF);
John Koleszar's avatar
John Koleszar committed
568 569 570 571

  Ebml_WriteID(glob, class_id);
  *ebmlLoc = ftello(glob->stream);
  Ebml_Serialize(glob, &unknownLen, sizeof(unknownLen), 8);
John Koleszar's avatar
John Koleszar committed
572 573 574
}

static void
John Koleszar's avatar
John Koleszar committed
575 576 577
Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
  off_t pos;
  uint64_t size;
John Koleszar's avatar
John Koleszar committed
578

John Koleszar's avatar
John Koleszar committed
579 580
  /* Save the current stream pointer */
  pos = ftello(glob->stream);
John Koleszar's avatar
John Koleszar committed
581

John Koleszar's avatar
John Koleszar committed
582 583
  /* Calculate the size of this element */
  size = pos - *ebmlLoc - 8;
John Koleszar's avatar
John Koleszar committed
584
  size |= LITERALU64(0x01000000, 0x00000000);
John Koleszar's avatar
John Koleszar committed
585

John Koleszar's avatar
John Koleszar committed
586 587 588
  /* Seek back to the beginning of the element and write the new size */
  fseeko(glob->stream, *ebmlLoc, SEEK_SET);
  Ebml_Serialize(glob, &size, sizeof(size), 8);
John Koleszar's avatar
John Koleszar committed
589

John Koleszar's avatar
John Koleszar committed
590 591
  /* Reset the stream pointer */
  fseeko(glob->stream, pos, SEEK_SET);
John Koleszar's avatar
John Koleszar committed
592 593
}

John Koleszar's avatar
John Koleszar committed
594 595

static void
John Koleszar's avatar
John Koleszar committed
596 597 598 599 600 601 602
write_webm_seek_element(EbmlGlobal *ebml, unsigned long id, off_t pos) {
  uint64_t offset = pos - ebml->position_reference;
  EbmlLoc start;
  Ebml_StartSubElement(ebml, &start, Seek);
  Ebml_SerializeBinary(ebml, SeekID, id);
  Ebml_SerializeUnsigned64(ebml, SeekPosition, offset);
  Ebml_EndSubElement(ebml, &start);
John Koleszar's avatar
John Koleszar committed
603 604 605 606
}


static void
John Koleszar's avatar
John Koleszar committed
607
write_webm_seek_info(EbmlGlobal *ebml) {
John Koleszar's avatar
John Koleszar committed
608

John Koleszar's avatar
John Koleszar committed
609
  off_t pos;
John Koleszar's avatar
John Koleszar committed
610

John Koleszar's avatar
John Koleszar committed
611 612
  /* Save the current stream pointer */
  pos = ftello(ebml->stream);
John Koleszar's avatar
John Koleszar committed
613

John Koleszar's avatar
John Koleszar committed
614 615 616 617
  if (ebml->seek_info_pos)
    fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET);
  else
    ebml->seek_info_pos = pos;
John Koleszar's avatar
John Koleszar committed
618

John Koleszar's avatar
John Koleszar committed
619 620
  {
    EbmlLoc start;
John Koleszar's avatar
John Koleszar committed
621

John Koleszar's avatar
John Koleszar committed
622 623 624 625 626 627 628
    Ebml_StartSubElement(ebml, &start, SeekHead);
    write_webm_seek_element(ebml, Tracks, ebml->track_pos);
    write_webm_seek_element(ebml, Cues,   ebml->cue_pos);
    write_webm_seek_element(ebml, Info,   ebml->segment_info_pos);
    Ebml_EndSubElement(ebml, &start);
  }
  {
John Koleszar's avatar
John Koleszar committed
629
    /* segment info */
John Koleszar's avatar
John Koleszar committed
630 631
    EbmlLoc startInfo;
    uint64_t frame_time;
John Koleszar's avatar
John Koleszar committed
632 633 634 635 636 637 638 639 640 641 642
    char version_string[64];

    /* Assemble version string */
    if (ebml->debug)
      strcpy(version_string, "vpxenc");
    else {
      strcpy(version_string, "vpxenc ");
      strncat(version_string,
              vpx_codec_version_str(),
              sizeof(version_string) - 1 - strlen(version_string));
    }
John Koleszar's avatar
John Koleszar committed
643 644 645 646 647 648 649

    frame_time = (uint64_t)1000 * ebml->framerate.den
                 / ebml->framerate.num;
    ebml->segment_info_pos = ftello(ebml->stream);
    Ebml_StartSubElement(ebml, &startInfo, Info);
    Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000);
    Ebml_SerializeFloat(ebml, Segment_Duration,
John Koleszar's avatar
John Koleszar committed
650 651 652
                        (double)(ebml->last_pts_ms + frame_time));
    Ebml_SerializeString(ebml, 0x4D80, version_string);
    Ebml_SerializeString(ebml, 0x5741, version_string);
John Koleszar's avatar
John Koleszar committed
653 654
    Ebml_EndSubElement(ebml, &startInfo);
  }
John Koleszar's avatar
John Koleszar committed
655 656 657 658 659 660
}


static void
write_webm_file_header(EbmlGlobal                *glob,
                       const vpx_codec_enc_cfg_t *cfg,
661
                       const struct vpx_rational *fps,
John Koleszar's avatar
John Koleszar committed
662 663 664 665 666
                       stereo_format_t            stereo_fmt) {
  {
    EbmlLoc start;
    Ebml_StartSubElement(glob, &start, EBML);
    Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
John Koleszar's avatar
John Koleszar committed
667 668 669 670 671 672
    Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1);
    Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4);
    Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8);
    Ebml_SerializeString(glob, DocType, "webm");
    Ebml_SerializeUnsigned(glob, DocTypeVersion, 2);
    Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2);
John Koleszar's avatar
John Koleszar committed
673 674 675
    Ebml_EndSubElement(glob, &start);
  }
  {
John Koleszar's avatar
John Koleszar committed
676
    Ebml_StartSubElement(glob, &glob->startSegment, Segment);
John Koleszar's avatar
John Koleszar committed
677 678 679 680
    glob->position_reference = ftello(glob->stream);
    glob->framerate = *fps;
    write_webm_seek_info(glob);

John Koleszar's avatar
John Koleszar committed
681
    {
John Koleszar's avatar
John Koleszar committed
682 683 684 685 686 687
      EbmlLoc trackStart;
      glob->track_pos = ftello(glob->stream);
      Ebml_StartSubElement(glob, &trackStart, Tracks);
      {
        unsigned int trackNumber = 1;
        uint64_t     trackID = 0;
John Koleszar's avatar
John Koleszar committed
688

John Koleszar's avatar
John Koleszar committed
689 690 691 692 693
        EbmlLoc start;
        Ebml_StartSubElement(glob, &start, TrackEntry);
        Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
        glob->track_id_pos = ftello(glob->stream);
        Ebml_SerializeUnsigned32(glob, TrackUID, trackID);
John Koleszar's avatar
John Koleszar committed
694
        Ebml_SerializeUnsigned(glob, TrackType, 1);
John Koleszar's avatar
John Koleszar committed
695
        Ebml_SerializeString(glob, CodecID, "V_VP8");
John Koleszar's avatar
John Koleszar committed
696
        {
John Koleszar's avatar
John Koleszar committed
697 698 699 700 701 702 703 704 705 706
          unsigned int pixelWidth = cfg->g_w;
          unsigned int pixelHeight = cfg->g_h;
          float        frameRate   = (float)fps->num / (float)fps->den;

          EbmlLoc videoStart;
          Ebml_StartSubElement(glob, &videoStart, Video);
          Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
          Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
          Ebml_SerializeUnsigned(glob, StereoMode, stereo_fmt);
          Ebml_SerializeFloat(glob, FrameRate, frameRate);
John Koleszar's avatar
John Koleszar committed
707
          Ebml_EndSubElement(glob, &videoStart);
John Koleszar's avatar
John Koleszar committed
708
        }
John Koleszar's avatar
John Koleszar committed
709
        Ebml_EndSubElement(glob, &start); /* Track Entry */
John Koleszar's avatar
John Koleszar committed
710 711
      }
      Ebml_EndSubElement(glob, &trackStart);
John Koleszar's avatar
John Koleszar committed
712
    }
John Koleszar's avatar
John Koleszar committed
713
    /* segment element is open */
John Koleszar's avatar
John Koleszar committed
714
  }
John Koleszar's avatar
John Koleszar committed
715 716 717 718 719 720
}


static void
write_webm_block(EbmlGlobal                *glob,
                 const vpx_codec_enc_cfg_t *cfg,
John Koleszar's avatar
John Koleszar committed
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
                 const vpx_codec_cx_pkt_t  *pkt) {
  unsigned long  block_length;
  unsigned char  track_number;
  unsigned short block_timecode = 0;
  unsigned char  flags;
  int64_t        pts_ms;
  int            start_cluster = 0, is_keyframe;

  /* Calculate the PTS of this frame in milliseconds */
  pts_ms = pkt->data.frame.pts * 1000
           * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den;
  if (pts_ms <= glob->last_pts_ms)
    pts_ms = glob->last_pts_ms + 1;
  glob->last_pts_ms = pts_ms;

  /* Calculate the relative time of this block */
  if (pts_ms - glob->cluster_timecode > SHRT_MAX)
    start_cluster = 1;
  else
John Koleszar's avatar
John Koleszar committed
740
    block_timecode = (unsigned short)pts_ms - glob->cluster_timecode;
John Koleszar's avatar
John Koleszar committed
741 742 743 744 745 746 747 748 749

  is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY);
  if (start_cluster || is_keyframe) {
    if (glob->cluster_open)
      Ebml_EndSubElement(glob, &glob->startCluster);

    /* Open the new cluster */
    block_timecode = 0;
    glob->cluster_open = 1;
John Koleszar's avatar
John Koleszar committed
750
    glob->cluster_timecode = (uint32_t)pts_ms;
John Koleszar's avatar
John Koleszar committed
751
    glob->cluster_pos = ftello(glob->stream);
John Koleszar's avatar
John Koleszar committed
752
    Ebml_StartSubElement(glob, &glob->startCluster, Cluster); /* cluster */
John Koleszar's avatar
John Koleszar committed
753 754 755 756 757 758 759 760 761 762
    Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode);

    /* Save a cue point if this is a keyframe. */
    if (is_keyframe) {
      struct cue_entry *cue, *new_cue_list;

      new_cue_list = realloc(glob->cue_list,
                             (glob->cues + 1) * sizeof(struct cue_entry));
      if (new_cue_list)
        glob->cue_list = new_cue_list;
John Koleszar's avatar
John Koleszar committed
763 764
      else
        fatal("Failed to realloc cue list.");
John Koleszar's avatar
John Koleszar committed
765

John Koleszar's avatar
John Koleszar committed
766 767 768 769
      cue = &glob->cue_list[glob->cues];
      cue->time = glob->cluster_timecode;
      cue->loc = glob->cluster_pos;
      glob->cues++;
John Koleszar's avatar
John Koleszar committed
770
    }
John Koleszar's avatar
John Koleszar committed
771
  }
John Koleszar's avatar
John Koleszar committed
772

John Koleszar's avatar
John Koleszar committed
773 774
  /* Write the Simple Block */
  Ebml_WriteID(glob, SimpleBlock);
John Koleszar's avatar
John Koleszar committed
775

John Koleszar's avatar
John Koleszar committed
776
  block_length = (unsigned long)pkt->data.frame.sz + 4;
John Koleszar's avatar
John Koleszar committed
777 778
  block_length |= 0x10000000;
  Ebml_Serialize(glob, &block_length, sizeof(block_length), 4);
John Koleszar's avatar
John Koleszar committed
779

John Koleszar's avatar
John Koleszar committed
780 781 782
  track_number = 1;
  track_number |= 0x80;
  Ebml_Write(glob, &track_number, 1);
John Koleszar's avatar
John Koleszar committed
783

John Koleszar's avatar
John Koleszar committed
784
  Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2);
John Koleszar's avatar
John Koleszar committed
785

John Koleszar's avatar
John Koleszar committed
786 787 788 789 790 791
  flags = 0;
  if (is_keyframe)
    flags |= 0x80;
  if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
    flags |= 0x08;
  Ebml_Write(glob, &flags, 1);
John Koleszar's avatar
John Koleszar committed
792

John Koleszar's avatar
John Koleszar committed
793
  Ebml_Write(glob, pkt->data.frame.buf, (unsigned long)pkt->data.frame.sz);
John Koleszar's avatar
John Koleszar committed
794 795 796 797
}


static void
John Koleszar's avatar
John Koleszar committed
798
write_webm_file_footer(EbmlGlobal *glob, long hash) {
John Koleszar's avatar
John Koleszar committed
799

John Koleszar's avatar
John Koleszar committed
800 801
  if (glob->cluster_open)
    Ebml_EndSubElement(glob, &glob->startCluster);
John Koleszar's avatar
John Koleszar committed
802

John Koleszar's avatar
John Koleszar committed
803 804
  {
    EbmlLoc start;
John Koleszar's avatar
John Koleszar committed
805
    unsigned int i;
John Koleszar's avatar
John Koleszar committed
806

John Koleszar's avatar
John Koleszar committed
807 808 809 810 811
    glob->cue_pos = ftello(glob->stream);
    Ebml_StartSubElement(glob, &start, Cues);
    for (i = 0; i < glob->cues; i++) {
      struct cue_entry *cue = &glob->cue_list[i];
      EbmlLoc start;
John Koleszar's avatar
John Koleszar committed
812

John Koleszar's avatar
John Koleszar committed
813 814 815
      Ebml_StartSubElement(glob, &start, CuePoint);
      {
        EbmlLoc start;
John Koleszar's avatar
John Koleszar committed
816

John Koleszar's avatar
John Koleszar committed
817
        Ebml_SerializeUnsigned(glob, CueTime, cue->time);
John Koleszar's avatar
John Koleszar committed
818

John Koleszar's avatar
John Koleszar committed
819 820 821 822
        Ebml_StartSubElement(glob, &start, CueTrackPositions);
        Ebml_SerializeUnsigned(glob, CueTrack, 1);
        Ebml_SerializeUnsigned64(glob, CueClusterPosition,
                                 cue->loc - glob->position_reference);
John Koleszar's avatar
John Koleszar committed
823
        Ebml_EndSubElement(glob, &start);
John Koleszar's avatar
John Koleszar committed
824 825
      }
      Ebml_EndSubElement(glob, &start);
John Koleszar's avatar
John Koleszar committed
826
    }
John Koleszar's avatar
John Koleszar committed
827 828
    Ebml_EndSubElement(glob, &start);
  }
John Koleszar's avatar
John Koleszar committed
829

John Koleszar's avatar
John Koleszar committed
830
  Ebml_EndSubElement(glob, &glob->startSegment);
John Koleszar's avatar
John Koleszar committed
831

John Koleszar's avatar
John Koleszar committed
832 833
  /* Patch up the seek info block */
  write_webm_seek_info(glob);
John Koleszar's avatar
John Koleszar committed
834

John Koleszar's avatar
John Koleszar committed
835 836 837
  /* Patch up the track id */
  fseeko(glob->stream, glob->track_id_pos, SEEK_SET);
  Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash);
John Koleszar's avatar
John Koleszar committed
838

John Koleszar's avatar
John Koleszar committed
839
  fseeko(glob->stream, 0, SEEK_END);
John Koleszar's avatar
John Koleszar committed
840 841 842
}


John Koleszar's avatar
John Koleszar committed
843
/* Murmur hash derived from public domain reference implementation at
John Koleszar's avatar
John Koleszar committed
844
 *   http:// sites.google.com/site/murmurhash/
John Koleszar's avatar
John Koleszar committed
845
 */
John Koleszar's avatar
John Koleszar committed
846 847 848
static unsigned int murmur(const void *key, int len, unsigned int seed) {
  const unsigned int m = 0x5bd1e995;
  const int r = 24;
John Koleszar's avatar
John Koleszar committed
849

John Koleszar's avatar
John Koleszar committed
850
  unsigned int h = seed ^ len;
John Koleszar's avatar
John Koleszar committed
851

John Koleszar's avatar
John Koleszar committed
852
  const unsigned char *data = (const unsigned char *)key;
John Koleszar's avatar
John Koleszar committed
853

John Koleszar's avatar
John Koleszar committed
854 855
  while (len >= 4) {
    unsigned int k;
John Koleszar's avatar
John Koleszar committed
856

John Koleszar's avatar
John Koleszar committed
857 858 859 860
    k  = data[0];
    k |= data[1] << 8;
    k |= data[2] << 16;
    k |= data[3] << 24;
John Koleszar's avatar
John Koleszar committed
861

John Koleszar's avatar
John Koleszar committed
862 863 864
    k *= m;
    k ^= k >> r;
    k *= m;
John Koleszar's avatar
John Koleszar committed
865 866

    h *= m;
John Koleszar's avatar
John Koleszar committed
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
    h ^= k;

    data += 4;
    len -= 4;
  }

  switch (len) {
    case 3:
      h ^= data[2] << 16;
    case 2:
      h ^= data[1] << 8;
    case 1:
      h ^= data[0];
      h *= m;
  };

  h ^= h >> 13;
  h *= m;
  h ^= h >> 15;

  return h;
John Koleszar's avatar
John Koleszar committed
888 889
}

890
#include "math.h"
891
#define MAX_PSNR 100
John Koleszar's avatar
John Koleszar committed
892 893
static double vp8_mse2psnr(double Samples, double Peak, double Mse) {
  double psnr;
894

John Koleszar's avatar
John Koleszar committed
895 896 897
  if ((double)Mse > 0.0)
    psnr = 10.0 * log10(Peak * Peak * Samples / Mse);
  else
John Koleszar's avatar
John Koleszar committed
898
    psnr = MAX_PSNR;      /* Limit to prevent / 0 */
899

John Koleszar's avatar
John Koleszar committed
900 901
  if (psnr > MAX_PSNR)
    psnr = MAX_PSNR;
902

John Koleszar's avatar
John Koleszar committed
903
  return psnr;
904 905
}

John Koleszar's avatar
John Koleszar committed
906

John Koleszar's avatar
John Koleszar committed
907
#include "args.h"
908
static const arg_def_t debugmode = ARG_DEF("D", "debug", 0,
John Koleszar's avatar
John Koleszar committed
909
                                           "Debug mode (makes output deterministic)");
910
static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
John Koleszar's avatar
John Koleszar committed
911
                                            "Output filename");
John Koleszar's avatar
John Koleszar committed
912
static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
John Koleszar's avatar
John Koleszar committed
913
                                          "Input file is YV12 ");
John Koleszar's avatar
John Koleszar committed
914
static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
John Koleszar's avatar
John Koleszar committed
915
                                          "Input file is I420 (default)");
John Koleszar's avatar
John Koleszar committed
916
static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
John Koleszar's avatar
John Koleszar committed
917
                                          "Codec to use");
John Koleszar's avatar
John Koleszar committed
918
static const arg_def_t passes           = ARG_DEF("p", "passes", 1,
John Koleszar's avatar
John Koleszar committed
919
                                                  "Number of passes (1/2)");
John Koleszar's avatar
John Koleszar committed
920
static const arg_def_t pass_arg         = ARG_DEF(NULL, "pass", 1,
John Koleszar's avatar
John Koleszar committed
921
                                                  "Pass to execute (1/2)");
John Koleszar's avatar
John Koleszar committed
922
static const arg_def_t fpf_name         = ARG_DEF(NULL, "fpf", 1,
John Koleszar's avatar
John Koleszar committed
923
                                                  "First pass statistics file name");
John Koleszar's avatar
John Koleszar committed
924 925
static const arg_def_t limit = ARG_DEF(NULL, "limit", 1,
                                       "Stop encoding after n input frames");
926
static const arg_def_t skip = ARG_DEF(NULL, "skip", 1,
John Koleszar's avatar
John Koleszar committed
927
                                      "Skip the first n input frames");
John Koleszar's avatar
John Koleszar committed
928
static const arg_def_t deadline         = ARG_DEF("d", "deadline", 1,
John Koleszar's avatar
John Koleszar committed
929
                                                  "Deadline per frame (usec)");
John Koleszar's avatar
John Koleszar committed
930
static const arg_def_t best_dl          = ARG_DEF(NULL, "best", 0,
John Koleszar's avatar
John Koleszar committed
931
                                                  "Use Best Quality Deadline");
John Koleszar's avatar
John Koleszar committed
932
static const arg_def_t good_dl          = ARG_DEF(NULL, "good", 0,
John Koleszar's avatar
John Koleszar committed
933
                                                  "Use Good Quality Deadline");
John Koleszar's avatar
John Koleszar committed
934
static const arg_def_t rt_dl            = ARG_DEF(NULL, "rt", 0,
John Koleszar's avatar
John Koleszar committed
935
                                                  "Use Realtime Quality Deadline");
John Koleszar's avatar
John Koleszar committed
936 937
static const arg_def_t quietarg         = ARG_DEF("q", "quiet", 0,
                                                  "Do not print encode progress");
John Koleszar's avatar
John Koleszar committed
938
static const arg_def_t verbosearg       = ARG_DEF("v", "verbose", 0,
John Koleszar's avatar
John Koleszar committed
939
                                                  "Show encoder parameters");
John Koleszar's avatar
John Koleszar committed
940
static const arg_def_t psnrarg          = ARG_DEF(NULL, "psnr", 0,
John Koleszar's avatar
John Koleszar committed
941
                                                  "Show PSNR in status line");
942
static const arg_def_t recontest        = ARG_DEF(NULL, "test-decode", 0,
John Koleszar's avatar
John Koleszar committed
943
                                                  "Test encode/decode mismatch");
944
static const arg_def_t framerate        = ARG_DEF(NULL, "fps", 1,
John Koleszar's avatar
John Koleszar committed
945
                                                  "Stream frame rate (rate/scale)");
John Koleszar's avatar
John Koleszar committed
946
static const arg_def_t use_ivf          = ARG_DEF(NULL, "ivf", 0,
John Koleszar's avatar
John Koleszar committed
947
                                                  "Output IVF (default is WebM)");
John Koleszar's avatar
John Koleszar committed
948 949
static const arg_def_t out_part = ARG_DEF("P", "output-partitions", 0,
                                          "Makes encoder output partitions. Requires IVF output!");
950
static const arg_def_t q_hist_n         = ARG_DEF(NULL, "q-hist", 1,
John Koleszar's avatar
John Koleszar committed
951
                                                  "Show quantizer histogram (n-buckets)");
952
static const arg_def_t rate_hist_n         = ARG_DEF(NULL, "rate-hist", 1,
John Koleszar's avatar
John Koleszar committed
953 954 955 956
                                                     "Show rate histogram (n-buckets)");
static const arg_def_t *main_args[] = {
  &debugmode,
  &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &skip,
John Koleszar's avatar
John Koleszar committed
957 958
  &deadline, &best_dl, &good_dl, &rt_dl,
  &quietarg, &verbosearg, &psnrarg, &use_ivf, &out_part, &q_hist_n, &rate_hist_n,
John Koleszar's avatar
John Koleszar committed
959
  NULL
John Koleszar's avatar
John Koleszar committed
960 961