vpxenc.c 76.9 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

KO Myung-Hun's avatar
KO Myung-Hun committed
13
#if defined(_WIN32) || defined(__OS2__) || !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"
26
#if CONFIG_DECODERS
John Koleszar's avatar
John Koleszar committed
27
#include "vpx/vpx_decoder.h"
28
#endif
John Koleszar's avatar
John Koleszar committed
29 30 31 32 33 34 35
#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
36

37 38
#include "third_party/libyuv/include/libyuv/scale.h"

39
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
40
#include "vpx/vp8cx.h"
John Koleszar's avatar
John Koleszar committed
41
#endif
42
#if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
43
#include "vpx/vp8dx.h"
John Koleszar's avatar
John Koleszar committed
44 45
#endif

John Koleszar's avatar
John Koleszar committed
46 47
#include "vpx_ports/mem_ops.h"
#include "vpx_ports/vpx_timer.h"
John Koleszar's avatar
John Koleszar committed
48
#include "tools_common.h"
49
#include "webmenc.h"
50
#include "y4minput.h"
51

John Koleszar's avatar
John Koleszar committed
52 53
/* Swallow warnings about unused results of fread/fwrite */
static size_t wrap_fread(void *ptr, size_t size, size_t nmemb,
John Koleszar's avatar
John Koleszar committed
54 55
                         FILE *stream) {
  return fread(ptr, size, nmemb, stream);
John Koleszar's avatar
John Koleszar committed
56 57 58 59
}
#define fread wrap_fread

static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb,
John Koleszar's avatar
John Koleszar committed
60 61
                          FILE *stream) {
  return fwrite(ptr, size, nmemb, stream);
John Koleszar's avatar
John Koleszar committed
62 63 64 65
}
#define fwrite wrap_fwrite


John Koleszar's avatar
John Koleszar committed
66 67
static const char *exec_name;

Jim Bankoski's avatar
Jim Bankoski committed
68
static const struct codec_item {
John Koleszar's avatar
John Koleszar committed
69
  char const              *name;
Jim Bankoski's avatar
Jim Bankoski committed
70
  const vpx_codec_iface_t *(*iface)(void);
John Koleszar's avatar
John Koleszar committed
71
  const vpx_codec_iface_t *(*dx_iface)(void);
Jim Bankoski's avatar
Jim Bankoski committed
72 73
  unsigned int             fourcc;
} codecs[] = {
74
#if CONFIG_VP8_ENCODER && CONFIG_VP8_DECODER
John Koleszar's avatar
John Koleszar committed
75
  {"vp8", &vpx_codec_vp8_cx, &vpx_codec_vp8_dx, VP8_FOURCC},
76
#elif CONFIG_VP8_ENCODER && !CONFIG_VP8_DECODER
John Koleszar's avatar
John Koleszar committed
77
  {"vp8", &vpx_codec_vp8_cx, NULL, VP8_FOURCC},
78
#endif
John Koleszar's avatar
John Koleszar committed
79
#if CONFIG_VP9_ENCODER && CONFIG_VP9_DECODER
John Koleszar's avatar
John Koleszar committed
80
  {"vp9", &vpx_codec_vp9_cx, &vpx_codec_vp9_dx, VP9_FOURCC},
81
#elif CONFIG_VP9_ENCODER && !CONFIG_VP9_DECODER
John Koleszar's avatar
John Koleszar committed
82
  {"vp9", &vpx_codec_vp9_cx, NULL, VP9_FOURCC},
John Koleszar's avatar
John Koleszar committed
83 84 85
#endif
};

86 87
static void warn_or_exit_on_errorv(vpx_codec_ctx_t *ctx, int fatal,
                                   const char *s, va_list ap) {
John Koleszar's avatar
John Koleszar committed
88 89
  if (ctx->err) {
    const char *detail = vpx_codec_error_detail(ctx);
John Koleszar's avatar
John Koleszar committed
90

John Koleszar's avatar
John Koleszar committed
91 92
    vfprintf(stderr, s, ap);
    fprintf(stderr, ": %s\n", vpx_codec_error(ctx));
John Koleszar's avatar
John Koleszar committed
93

John Koleszar's avatar
John Koleszar committed
94 95
    if (detail)
      fprintf(stderr, "    %s\n", detail);
John Koleszar's avatar
John Koleszar committed
96

97 98
    if (fatal)
      exit(EXIT_FAILURE);
John Koleszar's avatar
John Koleszar committed
99
  }
John Koleszar's avatar
John Koleszar committed
100 101
}

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) {
  va_list ap;

  va_start(ap, s);
  warn_or_exit_on_errorv(ctx, 1, s, ap);
  va_end(ap);
}

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

  va_start(ap, s);
  warn_or_exit_on_errorv(ctx, fatal, s, ap);
  va_end(ap);
}

John Koleszar's avatar
John Koleszar committed
119 120 121
/* This structure is used to abstract the different ways of handling
 * first pass statistics.
 */
John Koleszar's avatar
John Koleszar committed
122 123 124 125 126 127
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
128 129
} stats_io_t;

John Koleszar's avatar
John Koleszar committed
130 131
int stats_open_file(stats_io_t *stats, const char *fpf, int pass) {
  int res;
John Koleszar's avatar
John Koleszar committed
132

John Koleszar's avatar
John Koleszar committed
133
  stats->pass = pass;
John Koleszar's avatar
John Koleszar committed
134

John Koleszar's avatar
John Koleszar committed
135 136 137 138 139 140
  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
141 142
#if 0
#elif USE_POSIX_MMAP
John Koleszar's avatar
John Koleszar committed
143 144 145 146 147 148 149 150 151 152
    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
153
#else
John Koleszar's avatar
John Koleszar committed
154
    size_t nbytes;
John Koleszar's avatar
John Koleszar committed
155

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

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

John Koleszar's avatar
John Koleszar committed
161 162
    stats->buf.sz = stats->buf_alloc_sz = ftell(stats->file);
    rewind(stats->file);
John Koleszar's avatar
John Koleszar committed
163

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

John Koleszar's avatar
John Koleszar committed
166 167 168
    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
169

John Koleszar's avatar
John Koleszar committed
170 171
    nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file);
    res = (nbytes == stats->buf.sz);
John Koleszar's avatar
John Koleszar committed
172
#endif
John Koleszar's avatar
John Koleszar committed
173
  }
John Koleszar's avatar
John Koleszar committed
174

John Koleszar's avatar
John Koleszar committed
175
  return res;
John Koleszar's avatar
John Koleszar committed
176 177
}

John Koleszar's avatar
John Koleszar committed
178 179 180
int stats_open_mem(stats_io_t *stats, int pass) {
  int res;
  stats->pass = pass;
John Koleszar's avatar
John Koleszar committed
181

John Koleszar's avatar
John Koleszar committed
182 183 184 185 186
  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
187

John Koleszar's avatar
John Koleszar committed
188 189 190
  stats->buf_ptr = stats->buf.buf;
  res = (stats->buf.buf != NULL);
  return res;
John Koleszar's avatar
John Koleszar committed
191 192 193
}


John Koleszar's avatar
John Koleszar committed
194 195 196
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
197 198
#if 0
#elif USE_POSIX_MMAP
John Koleszar's avatar
John Koleszar committed
199
      munmap(stats->buf.buf, stats->buf.sz);
John Koleszar's avatar
John Koleszar committed
200
#else
John Koleszar's avatar
John Koleszar committed
201
      free(stats->buf.buf);
John Koleszar's avatar
John Koleszar committed
202 203
#endif
    }
John Koleszar's avatar
John Koleszar committed
204 205 206 207 208 209 210

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

John Koleszar's avatar
John Koleszar committed
213 214
void stats_write(stats_io_t *stats, const void *pkt, size_t len) {
  if (stats->file) {
John Koleszar's avatar
John Koleszar committed
215
    (void) fwrite(pkt, 1, len, stats->file);
John Koleszar's avatar
John Koleszar committed
216 217 218 219 220 221 222 223 224
  } 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
225 226
      } else
        fatal("Failed to realloc firstpass stats buffer.");
John Koleszar's avatar
John Koleszar committed
227 228
    }

John Koleszar's avatar
John Koleszar committed
229 230 231 232
    memcpy(stats->buf_ptr, pkt, len);
    stats->buf.sz += len;
    stats->buf_ptr += len;
  }
John Koleszar's avatar
John Koleszar committed
233 234
}

John Koleszar's avatar
John Koleszar committed
235 236
vpx_fixed_buf_t stats_get(stats_io_t *stats) {
  return stats->buf;
John Koleszar's avatar
John Koleszar committed
237 238
}

John Koleszar's avatar
John Koleszar committed
239 240 241 242
enum video_file_type {
  FILE_TYPE_RAW,
  FILE_TYPE_IVF,
  FILE_TYPE_Y4M
243 244
};

245
struct detect_buffer {
John Koleszar's avatar
John Koleszar committed
246 247 248
  char buf[4];
  size_t buf_read;
  size_t position;
249 250 251
};


John Koleszar's avatar
John Koleszar committed
252 253 254
struct input_state {
  char                 *fn;
  FILE                 *file;
255
  off_t                 length;
John Koleszar's avatar
John Koleszar committed
256 257 258 259 260 261 262
  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;
263
  int                   only_i420;
264 265 266
};


John Koleszar's avatar
John Koleszar committed
267
#define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */
John Koleszar's avatar
John Koleszar committed
268 269 270 271 272
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
273 274 275 276 277 278 279 280 281 282 283 284 285 286
  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
287
      (void) fread(junk, 1, IVF_FRAME_HDR_SZ, f);
John Koleszar's avatar
John Koleszar committed
288
    }
289

John Koleszar's avatar
John Koleszar committed
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
    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
321
        }
John Koleszar's avatar
John Koleszar committed
322 323
        if (needed > 0) {
          shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
John Koleszar's avatar
John Koleszar committed
324
        }
John Koleszar's avatar
John Koleszar committed
325 326 327

        ptr += img->stride[plane];
      }
John Koleszar's avatar
John Koleszar committed
328
    }
John Koleszar's avatar
John Koleszar committed
329
  }
John Koleszar's avatar
John Koleszar committed
330

John Koleszar's avatar
John Koleszar committed
331
  return !shortread;
John Koleszar's avatar
John Koleszar committed
332 333 334
}


335
unsigned int file_is_y4m(FILE      *infile,
336
                         y4m_input *y4m,
John Koleszar's avatar
John Koleszar committed
337 338 339 340 341
                         char       detect[4]) {
  if (memcmp(detect, "YUV4", 4) == 0) {
    return 1;
  }
  return 0;
342 343
}

John Koleszar's avatar
John Koleszar committed
344
#define IVF_FILE_HDR_SZ (32)
345
unsigned int file_is_ivf(struct input_state *input,
John Koleszar's avatar
John Koleszar committed
346
                         unsigned int *fourcc) {
John Koleszar's avatar
John Koleszar committed
347 348
  char raw_hdr[IVF_FILE_HDR_SZ];
  int is_ivf = 0;
John Koleszar's avatar
John Koleszar committed
349 350 351 352
  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
353

John Koleszar's avatar
John Koleszar committed
354 355
  if (memcmp(detect->buf, "DKIF", 4) != 0)
    return 0;
356

John Koleszar's avatar
John Koleszar committed
357 358 359 360 361
  /* 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
362
    {
John Koleszar's avatar
John Koleszar committed
363
      is_ivf = 1;
John Koleszar's avatar
John Koleszar committed
364

John Koleszar's avatar
John Koleszar committed
365
      if (mem_get_le16(raw_hdr + 4) != 0)
John Koleszar's avatar
John Koleszar committed
366 367
        warn("Unrecognized IVF version! This file may not decode "
             "properly.");
John Koleszar's avatar
John Koleszar committed
368

John Koleszar's avatar
John Koleszar committed
369
      *fourcc = mem_get_le32(raw_hdr + 8);
John Koleszar's avatar
John Koleszar committed
370
    }
John Koleszar's avatar
John Koleszar committed
371
  }
John Koleszar's avatar
John Koleszar committed
372

John Koleszar's avatar
John Koleszar committed
373 374 375 376 377
  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
378

John Koleszar's avatar
John Koleszar committed
379
  return is_ivf;
John Koleszar's avatar
John Koleszar committed
380 381 382 383 384 385
}


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
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
                                  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
406
  (void) fwrite(header, 1, 32, outfile);
John Koleszar's avatar
John Koleszar committed
407 408 409 410
}


static void write_ivf_frame_header(FILE *outfile,
John Koleszar's avatar
John Koleszar committed
411 412 413
                                   const vpx_codec_cx_pkt_t *pkt) {
  char             header[12];
  vpx_codec_pts_t  pts;
John Koleszar's avatar
John Koleszar committed
414

John Koleszar's avatar
John Koleszar committed
415 416
  if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
    return;
John Koleszar's avatar
John Koleszar committed
417

John Koleszar's avatar
John Koleszar committed
418
  pts = pkt->data.frame.pts;
John Koleszar's avatar
John Koleszar committed
419
  mem_put_le32(header, (int)pkt->data.frame.sz);
John Koleszar's avatar
John Koleszar committed
420 421
  mem_put_le32(header + 4, pts & 0xFFFFFFFF);
  mem_put_le32(header + 8, pts >> 32);
John Koleszar's avatar
John Koleszar committed
422

John Koleszar's avatar
John Koleszar committed
423
  (void) fwrite(header, 1, 12, outfile);
John Koleszar's avatar
John Koleszar committed
424 425
}

John Koleszar's avatar
John Koleszar committed
426 427 428 429
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);
430 431
}

John Koleszar's avatar
John Koleszar committed
432 433


John Koleszar's avatar
John Koleszar committed
434
/* Murmur hash derived from public domain reference implementation at
John Koleszar's avatar
John Koleszar committed
435
 *   http:// sites.google.com/site/murmurhash/
John Koleszar's avatar
John Koleszar committed
436
 */
John Koleszar's avatar
John Koleszar committed
437 438 439
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
440

John Koleszar's avatar
John Koleszar committed
441
  unsigned int h = seed ^ len;
John Koleszar's avatar
John Koleszar committed
442

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

John Koleszar's avatar
John Koleszar committed
445 446
  while (len >= 4) {
    unsigned int k;
John Koleszar's avatar
John Koleszar committed
447

Yaowu Xu's avatar
Yaowu Xu committed
448 449 450 451
    k  = (unsigned int)data[0];
    k |= (unsigned int)data[1] << 8;
    k |= (unsigned int)data[2] << 16;
    k |= (unsigned int)data[3] << 24;
John Koleszar's avatar
John Koleszar committed
452

John Koleszar's avatar
John Koleszar committed
453 454 455
    k *= m;
    k ^= k >> r;
    k *= m;
John Koleszar's avatar
John Koleszar committed
456 457

    h *= m;
John Koleszar's avatar
John Koleszar committed
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
    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
479 480
}

481
#include "math.h"
482
#define MAX_PSNR 100
John Koleszar's avatar
John Koleszar committed
483 484
static double vp8_mse2psnr(double Samples, double Peak, double Mse) {
  double psnr;
485

John Koleszar's avatar
John Koleszar committed
486 487 488
  if ((double)Mse > 0.0)
    psnr = 10.0 * log10(Peak * Peak * Samples / Mse);
  else
John Koleszar's avatar
John Koleszar committed
489
    psnr = MAX_PSNR;      /* Limit to prevent / 0 */
490

John Koleszar's avatar
John Koleszar committed
491 492
  if (psnr > MAX_PSNR)
    psnr = MAX_PSNR;
493

John Koleszar's avatar
John Koleszar committed
494
  return psnr;
495 496
}

John Koleszar's avatar
John Koleszar committed
497

John Koleszar's avatar
John Koleszar committed
498
#include "args.h"
499
static const arg_def_t debugmode = ARG_DEF("D", "debug", 0,
John Koleszar's avatar
John Koleszar committed
500
                                           "Debug mode (makes output deterministic)");
501
static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
John Koleszar's avatar
John Koleszar committed
502
                                            "Output filename");
John Koleszar's avatar
John Koleszar committed
503
static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
John Koleszar's avatar
John Koleszar committed
504
                                          "Input file is YV12 ");
John Koleszar's avatar
John Koleszar committed
505
static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
John Koleszar's avatar
John Koleszar committed
506
                                          "Input file is I420 (default)");
John Koleszar's avatar
John Koleszar committed
507
static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
John Koleszar's avatar
John Koleszar committed
508
                                          "Codec to use");
John Koleszar's avatar
John Koleszar committed
509
static const arg_def_t passes           = ARG_DEF("p", "passes", 1,
John Koleszar's avatar
John Koleszar committed
510
                                                  "Number of passes (1/2)");
John Koleszar's avatar
John Koleszar committed
511
static const arg_def_t pass_arg         = ARG_DEF(NULL, "pass", 1,
John Koleszar's avatar
John Koleszar committed
512
                                                  "Pass to execute (1/2)");
John Koleszar's avatar
John Koleszar committed
513
static const arg_def_t fpf_name         = ARG_DEF(NULL, "fpf", 1,
John Koleszar's avatar
John Koleszar committed
514
                                                  "First pass statistics file name");
John Koleszar's avatar
John Koleszar committed
515 516
static const arg_def_t limit = ARG_DEF(NULL, "limit", 1,
                                       "Stop encoding after n input frames");
517
static const arg_def_t skip = ARG_DEF(NULL, "skip", 1,
John Koleszar's avatar
John Koleszar committed
518
                                      "Skip the first n input frames");
John Koleszar's avatar
John Koleszar committed
519
static const arg_def_t deadline         = ARG_DEF("d", "deadline", 1,
John Koleszar's avatar
John Koleszar committed
520
                                                  "Deadline per frame (usec)");
John Koleszar's avatar
John Koleszar committed
521
static const arg_def_t best_dl          = ARG_DEF(NULL, "best", 0,
John Koleszar's avatar
John Koleszar committed
522
                                                  "Use Best Quality Deadline");
John Koleszar's avatar
John Koleszar committed
523
static const arg_def_t good_dl          = ARG_DEF(NULL, "good", 0,
John Koleszar's avatar
John Koleszar committed
524
                                                  "Use Good Quality Deadline");
John Koleszar's avatar
John Koleszar committed
525
static const arg_def_t rt_dl            = ARG_DEF(NULL, "rt", 0,
John Koleszar's avatar
John Koleszar committed
526
                                                  "Use Realtime Quality Deadline");
James Zern's avatar
James Zern committed
527
static const arg_def_t quietarg         = ARG_DEF("q", "quiet", 0,
John Koleszar's avatar
John Koleszar committed
528
                                                  "Do not print encode progress");
John Koleszar's avatar
John Koleszar committed
529
static const arg_def_t verbosearg       = ARG_DEF("v", "verbose", 0,
John Koleszar's avatar
John Koleszar committed
530
                                                  "Show encoder parameters");
John Koleszar's avatar
John Koleszar committed
531
static const arg_def_t psnrarg          = ARG_DEF(NULL, "psnr", 0,
John Koleszar's avatar
John Koleszar committed
532
                                                  "Show PSNR in status line");
533 534 535 536 537 538 539 540 541 542 543 544 545 546
enum TestDecodeFatality {
  TEST_DECODE_OFF,
  TEST_DECODE_FATAL,
  TEST_DECODE_WARN,
};
static const struct arg_enum_list test_decode_enum[] = {
  {"off",   TEST_DECODE_OFF},
  {"fatal", TEST_DECODE_FATAL},
  {"warn",  TEST_DECODE_WARN},
  {NULL, 0}
};
static const arg_def_t recontest = ARG_DEF_ENUM(NULL, "test-decode", 1,
                                                "Test encode/decode mismatch",
                                                test_decode_enum);
547
static const arg_def_t framerate        = ARG_DEF(NULL, "fps", 1,
John Koleszar's avatar
John Koleszar committed
548
                                                  "Stream frame rate (rate/scale)");
John Koleszar's avatar
John Koleszar committed
549
static const arg_def_t use_ivf          = ARG_DEF(NULL, "ivf", 0,
John Koleszar's avatar
John Koleszar committed
550
                                                  "Output IVF (default is WebM)");
551
static const arg_def_t out_part = ARG_DEF("P", "output-partitions", 0,
John Koleszar's avatar
John Koleszar committed
552
                                          "Makes encoder output partitions. Requires IVF output!");
553
static const arg_def_t q_hist_n         = ARG_DEF(NULL, "q-hist", 1,
John Koleszar's avatar
John Koleszar committed
554
                                                  "Show quantizer histogram (n-buckets)");
555
static const arg_def_t rate_hist_n         = ARG_DEF(NULL, "rate-hist", 1,
John Koleszar's avatar
John Koleszar committed
556 557 558 559
                                                     "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
560 561
  &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
562
  NULL
John Koleszar's avatar
John Koleszar committed
563 564 565
};

static const arg_def_t usage            = ARG_DEF("u", "usage", 1,
John Koleszar's avatar
John Koleszar committed
566
                                                  "Usage profile number to use");
John Koleszar's avatar
John Koleszar committed
567
static const arg_def_t threads          = ARG_DEF("t", "threads", 1,
John Koleszar's avatar
John Koleszar committed
568
                                                  "Max number of threads to use");
John Koleszar's avatar
John Koleszar committed
569
static const arg_def_t profile          = ARG_DEF(NULL, "profile", 1,
John Koleszar's avatar
John Koleszar committed
570
                                                  "Bitstream profile number to use");
John Koleszar's avatar
John Koleszar committed
571
static const arg_def_t width            = ARG_DEF("w", "width", 1,
John Koleszar's avatar
John Koleszar committed
572
                                                  "Frame width");
John Koleszar's avatar
John Koleszar committed
573
static const arg_def_t height           = ARG_DEF("h", "height", 1,
John Koleszar's avatar
John Koleszar committed
574
                                                  "Frame height");
575
static const struct arg_enum_list stereo_mode_enum[] = {
John Koleszar's avatar
John Koleszar committed
576 577 578 579 580 581
  {"mono", STEREO_FORMAT_MONO},
  {"left-right", STEREO_FORMAT_LEFT_RIGHT},
  {"bottom-top", STEREO_FORMAT_BOTTOM_TOP},
  {"top-bottom", STEREO_FORMAT_TOP_BOTTOM},
  {"right-left", STEREO_FORMAT_RIGHT_LEFT},
  {NULL, 0}
582 583
};
static const arg_def_t stereo_mode      = ARG_DEF_ENUM(NULL, "stereo-mode", 1,
John Koleszar's avatar
John Koleszar committed
584
                                                       "Stereo 3D video format", stereo_mode_enum);
John Koleszar's avatar
John Koleszar committed
585
static const arg_def_t timebase         = ARG_DEF(NULL, "timebase", 1,
John Koleszar's avatar
John Koleszar committed
586
                                                  "Output timestamp precision (fractional seconds)");
John Koleszar's avatar
John Koleszar committed
587
static const arg_def_t error_resilient  = ARG_DEF(NULL, "error-resilient", 1,
John Koleszar's avatar
John Koleszar committed
588
                                                  "Enable error resiliency features");
John Koleszar's avatar
John Koleszar committed
589
static const arg_def_t lag_in_frames    = ARG_DEF(NULL, "lag-in-frames", 1,
John Koleszar's avatar
John Koleszar committed
590
                                                  "Max number of frames to lag");
John Koleszar's avatar
John Koleszar committed
591

John Koleszar's avatar
John Koleszar committed
592 593
static const arg_def_t *global_args[] = {
  &use_yv12, &use_i420, &usage, &threads, &profile,
594 595
  &width, &height, &stereo_mode, &timebase, &framerate,
  &error_resilient,
John Koleszar's avatar
John Koleszar committed
596
  &lag_in_frames, NULL
John Koleszar's avatar
John Koleszar committed
597 598 599
};

static const arg_def_t dropframe_thresh   = ARG_DEF(NULL, "drop-frame", 1,
John Koleszar's avatar
John Koleszar committed
600
                                                    "Temporal resampling threshold (buf %)");
John Koleszar's avatar
John Koleszar committed
601
static const arg_def_t resize_allowed     = ARG_DEF(NULL, "resize-allowed", 1,
John Koleszar's avatar
John Koleszar committed
602
                                                    "Spatial resampling enabled (bool)");
John Koleszar's avatar
John Koleszar committed
603
static const arg_def_t resize_up_thresh   = ARG_DEF(NULL, "resize-up", 1,
John Koleszar's avatar
John Koleszar committed
604
                                                    "Upscale threshold (buf %)");
John Koleszar's avatar
John Koleszar committed
605
static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1,
John Koleszar's avatar
John Koleszar committed
606
                                                    "Downscale threshold (buf %)");
607
static const struct arg_enum_list end_usage_enum[] = {
John Koleszar's avatar
John Koleszar committed
608 609 610
  {"vbr", VPX_VBR},
  {"cbr", VPX_CBR},
  {"cq",  VPX_CQ},
611
  {"q",   VPX_Q},
John Koleszar's avatar
John Koleszar committed
612
  {NULL, 0}
613 614
};
static const arg_def_t end_usage          = ARG_DEF_ENUM(NULL, "end-usage", 1,
John Koleszar's avatar
John Koleszar committed
615
                                                         "Rate control mode", end_usage_enum);
John Koleszar's avatar
John Koleszar committed
616
static const arg_def_t target_bitrate     = ARG_DEF(NULL, "target-bitrate", 1,
John Koleszar's avatar
John Koleszar committed
617
                                                    "Bitrate (kbps)");
John Koleszar's avatar
John Koleszar committed
618
static const arg_def_t min_quantizer      = ARG_DEF(NULL, "min-q", 1,
John Koleszar's avatar
John Koleszar committed
619
                                                    "Minimum (best) quantizer");
John Koleszar's avatar
John Koleszar committed
620
static const arg_def_t max_quantizer      = ARG_DEF(NULL, "max-q", 1,
John Koleszar's avatar
John Koleszar committed
621
                                                    "Maximum (worst) quantizer");
John Koleszar's avatar
John Koleszar committed
622
static const arg_def_t undershoot_pct     = ARG_DEF(NULL, "undershoot-pct", 1,
John Koleszar's avatar
John Koleszar committed
623
                                                    "Datarate undershoot (min) target (%)");
John Koleszar's avatar
John Koleszar committed
624
static const arg_def_t overshoot_pct      = ARG_DEF(NULL, "overshoot-pct", 1,
John Koleszar's avatar
John Koleszar committed
625
                                                    "Datarate overshoot (max) target (%)");
John Koleszar's avatar
John Koleszar committed
626
static const arg_def_t buf_sz             = ARG_DEF(NULL, "buf-sz", 1,
John Koleszar's avatar
John Koleszar committed
627
                                                    "Client buffer size (ms)");
John Koleszar's avatar
John Koleszar committed
628
static const arg_def_t buf_initial_sz     = ARG_DEF(NULL, "buf-initial-sz", 1,
John Koleszar's avatar
John Koleszar committed
629
                                                    "Client initial buffer size (ms)");
John Koleszar's avatar
John Koleszar committed
630
static const arg_def_t buf_optimal_sz     = ARG_DEF(NULL, "buf-optimal-sz", 1,
John Koleszar's avatar
John Koleszar committed
631 632 633 634 635 636
                                                    "Client optimal buffer size (ms)");
static const arg_def_t *rc_args[] = {
  &dropframe_thresh, &resize_allowed, &resize_up_thresh, &resize_down_thresh,
  &end_usage, &target_bitrate, &min_quantizer, &max_quantizer,
  &undershoot_pct, &overshoot_pct, &buf_sz, &buf_initial_sz, &buf_optimal_sz,
  NULL
John Koleszar's avatar
John Koleszar committed
637 638 639 640
};


static const arg_def_t bias_pct = ARG_DEF(NULL, "bias-pct", 1,
John Koleszar's avatar
John Koleszar committed
641
                                          "CBR/VBR bias (0=CBR, 100=VBR)");
John Koleszar's avatar
John Koleszar committed
642
static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1,
John Koleszar's avatar
John Koleszar committed
643
                                                "GOP min bitrate (% of target)");
John Koleszar's avatar
John Koleszar committed
644
static const arg_def_t maxsection_pct = ARG_DEF(NULL, "maxsection-pct", 1,
John Koleszar's avatar
John Koleszar committed
645 646 647
                                                "GOP max bitrate (% of target)");
static const arg_def_t *rc_twopass_args[] = {
  &bias_pct, &minsection_pct, &maxsection_pct, NULL
John Koleszar's avatar
John Koleszar committed
648 649 650 651
};


static const arg_def_t kf_min_dist = ARG_DEF(NULL, "kf-min-dist", 1,
John Koleszar's avatar
John Koleszar committed
652
                                             "Minimum keyframe interval (frames)");
John Koleszar's avatar
John Koleszar committed
653
static const arg_def_t kf_max_dist = ARG_DEF(NULL, "kf-max-dist", 1,
John Koleszar's avatar
John Koleszar committed
654
                                             "Maximum keyframe interval (frames)");
655
static const arg_def_t kf_disabled = ARG_DEF(NULL, "disable-kf", 0,
John Koleszar's avatar
John Koleszar committed
656 657 658
                                             "Disable keyframe placement");
static const arg_def_t *kf_args[] = {
  &kf_min_dist, &kf_max_dist, &kf_disabled, NULL
John Koleszar's avatar
John Koleszar committed
659 660 661 662
};


static const arg_def_t noise_sens = ARG_DEF(NULL, "noise-sensitivity", 1,
John Koleszar's avatar
John Koleszar committed
663
                                            "Noise sensitivity (frames to blur)");
John Koleszar's avatar
John Koleszar committed
664
static const arg_def_t sharpness = ARG_DEF(NULL, "sharpness", 1,
John Koleszar's avatar
John Koleszar committed
665
                                           "Filter sharpness (0-7)");
John Koleszar's avatar
John Koleszar committed
666
static const arg_def_t static_thresh = ARG_DEF(NULL, "static-thresh", 1,
John Koleszar's avatar
John Koleszar committed
667
                                               "Motion detection threshold");
John Koleszar's avatar
John Koleszar committed
668
static const arg_def_t cpu_used = ARG_DEF(NULL, "cpu-used", 1,
John Koleszar's avatar
John Koleszar committed
669
                                          "CPU Used (-16..16)");
John Koleszar's avatar
John Koleszar committed
670
static const arg_def_t token_parts = ARG_DEF(NULL, "token-parts", 1,
671 672 673
                                     "Number of token partitions to use, log2");
static const arg_def_t tile_cols = ARG_DEF(NULL, "tile-columns", 1,
                                         "Number of tile columns to use, log2");
Ronald S. Bultje's avatar
Ronald S. Bultje committed
674 675
static const arg_def_t tile_rows = ARG_DEF(NULL, "tile-rows", 1,
                                           "Number of tile rows to use, log2");
John Koleszar's avatar
John Koleszar committed
676
static const arg_def_t auto_altref = ARG_DEF(NULL, "auto-alt-ref", 1,
John Koleszar's avatar
John Koleszar committed
677
                                             "Enable automatic alt reference frames");
John Koleszar's avatar
John Koleszar committed
678
static const arg_def_t arnr_maxframes = ARG_DEF(NULL, "arnr-maxframes", 1,
John Koleszar's avatar
John Koleszar committed
679
                                                "AltRef Max Frames");
John Koleszar's avatar
John Koleszar committed
680
static const arg_def_t arnr_strength = ARG_DEF(NULL, "arnr-strength", 1,
John Koleszar's avatar
John Koleszar committed
681
                                               "AltRef Strength");
John Koleszar's avatar
John Koleszar committed
682
static const arg_def_t arnr_type = ARG_DEF(NULL, "arnr-type", 1,
John Koleszar's avatar
John Koleszar committed
683
                                           "AltRef Type");
John Koleszar's avatar
John Koleszar committed
684
static const struct arg_enum_list tuning_enum[] = {
John Koleszar's avatar
John Koleszar committed
685 686 687
  {"psnr", VP8_TUNE_PSNR},
  {"ssim", VP8_TUNE_SSIM},
  {NULL, 0}
John Koleszar's avatar
John Koleszar committed
688 689
};
static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1,
John Koleszar's avatar
John Koleszar committed
690
                                                "Material to favor", tuning_enum);
Paul Wilkins's avatar
CQ Mode  
Paul Wilkins committed
691
static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1,
692
                                          "Constant/Constrained Quality level");
693
static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1,
John Koleszar's avatar
John Koleszar committed
694
                                                    "Max I-frame bitrate (pct)");
John Koleszar's avatar
John Koleszar committed
695
static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode");
696 697 698 699
#if CONFIG_VP9_ENCODER
static const arg_def_t frame_parallel_decoding  = ARG_DEF(
    NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
#endif
John Koleszar's avatar
John Koleszar committed
700

701
#if CONFIG_VP8_ENCODER
John Koleszar's avatar
John Koleszar committed
702 703 704
static const arg_def_t *vp8_args[] = {
  &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh,
  &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type,
John Koleszar's avatar
John Koleszar committed
705
  &tune_ssim, &cq_level, &max_intra_rate_pct,
706
  NULL
John Koleszar's avatar
John Koleszar committed
707
};
708 709 710 711 712 713 714 715 716 717 718 719 720
static const int vp8_arg_ctrl_map[] = {
  VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
  VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
  VP8E_SET_TOKEN_PARTITIONS,
  VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
  VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
  0
};
#endif

#if CONFIG_VP9_ENCODER
static const arg_def_t *vp9_args[] = {
  &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
721
  &tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type,
Yaowu Xu's avatar
Yaowu Xu committed
722
  &tune_ssim, &cq_level, &max_intra_rate_pct, &lossless,
723
  &frame_parallel_decoding,
John Koleszar's avatar
John Koleszar committed
724
  NULL
John Koleszar's avatar
John Koleszar committed
725
};
726
static const int vp9_arg_ctrl_map[] = {
John Koleszar's avatar
John Koleszar committed
727 728
  VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
  VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
729
  VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS,
John Koleszar's avatar
John Koleszar committed
730
  VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
John Koleszar's avatar
John Koleszar committed
731
  VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
732
  VP9E_SET_LOSSLESS, VP9E_SET_FRAME_PARALLEL_DECODING,
John Koleszar's avatar
John Koleszar committed
733
  0
John Koleszar's avatar
John Koleszar committed
734 735 736 737 738
};
#endif

static const arg_def_t *no_args[] = { NULL };

739
void usage_exit() {
John Koleszar's avatar
John Koleszar committed
740 741 742 743 744 745
  int i;

  fprintf(stderr, "Usage: %s <options> -o dst_filename src_filename \n",
          exec_name);

  fprintf(stderr, "\nOptions:\n");
John Koleszar's avatar
John Koleszar committed
746
  arg_show_usage(stderr, main_args);
John Koleszar's avatar
John Koleszar committed
747
  fprintf(stderr, "\nEncoder Global Options:\n");
John Koleszar's avatar
John Koleszar committed
748
  arg_show_usage(stderr, global_args);
John Koleszar's avatar
John Koleszar committed
749
  fprintf(stderr, "\nRate Control Options:\n");
John Koleszar's avatar
John Koleszar committed
750
  arg_show_usage(stderr, rc_args);
John Koleszar's avatar
John Koleszar committed
751
  fprintf(stderr, "\nTwopass Rate Control Options:\n");
John Koleszar's avatar
John Koleszar committed
752
  arg_show_usage(stderr, rc_twopass_args);
John Koleszar's avatar
John Koleszar committed
753
  fprintf(stderr, "\nKeyframe Placement Options:\n");
John Koleszar's avatar
John Koleszar committed
754
  arg_show_usage(stderr, kf_args);
John Koleszar's avatar
John Koleszar committed
755
#if CONFIG_VP8_ENCODER
John Koleszar's avatar
John Koleszar committed
756
  fprintf(stderr, "\nVP8 Specific Options:\n");
John Koleszar's avatar
John Koleszar committed
757
  arg_show_usage(stderr, vp8_args);
John Koleszar's avatar
John Koleszar committed
758
#endif
759 760
#if CONFIG_VP9_ENCODER
  fprintf(stderr, "\nVP9 Specific Options:\n");
John Koleszar's avatar
John Koleszar committed
761
  arg_show_usage(stderr, vp9_args);
John Koleszar's avatar
John Koleszar committed
762
#endif
John Koleszar's avatar
John Koleszar committed
763 764 765 766 767 768 769 770 771 772
  fprintf(stderr, "\nStream timebase (--timebase):\n"
          "  The desired precision of timestamps in the output, expressed\n"
          "  in fractional seconds. Default is 1/1000.\n");
  fprintf(stderr, "\n"
          "Included encoders:\n"
          "\n");

  for (i = 0; i < sizeof(codecs) / sizeof(codecs[0]); i++)
    fprintf(stderr, "    %-6s - %s\n",
            codecs[i].name,
Jim Bankoski's avatar
Jim Bankoski committed
773
            vpx_codec_iface_name(codecs[i].iface()));
John Koleszar's avatar
John Koleszar committed
774 775

  exit(EXIT_FAILURE);
John Koleszar's avatar
John Koleszar committed
776 777
}

778 779

#define HIST_BAR_MAX 40
John Koleszar's avatar
John Koleszar committed
780 781
struct hist_bucket {
  int low, high, count;
782 783 784 785 786
};


static int merge_hist_buckets(struct hist_bucket *bucket,
                              int *buckets_,
John Koleszar's avatar
John Koleszar committed
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
                              int max_buckets) {
  int small_bucket = 0, merge_bucket = INT_MAX, big_bucket = 0;
  int buckets = *buckets_;
  int i;

  /* Find the extrema for this list of buckets */
  big_bucket = small_bucket = 0;
  for (i = 0; i < buckets; i++) {
    if (bucket[i].count < bucket[small_bucket].count)
      small_bucket = i;
    if (bucket[i].count > bucket[big_bucket].count)
      big_bucket = i;
  }

  /* If we have too many buckets, merge the smallest with an adjacent
   * bucket.
   */
  while (buckets > max_buckets) {
    int last_bucket = buckets - 1;

John Koleszar's avatar
John Koleszar committed
807
    /* merge the small bucket with an adjacent one. */
John Koleszar's avatar
John Koleszar committed
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
    if (small_bucket == 0)
      merge_bucket = 1;
    else if (small_bucket == last_bucket)
      merge_bucket = last_bucket - 1;
    else if (bucket[small_bucket - 1].count < bucket[small_bucket + 1].count)
      merge_bucket = small_bucket - 1;
    else
      merge_bucket = small_bucket + 1;

    assert(abs(merge_bucket - small_bucket) <= 1);
    assert(small_bucket < buckets);
    assert(big_bucket < buckets);
    assert(merge_bucket < buckets);

    if (merge_bucket < small_bucket) {
      bucket[merge_bucket].high = bucket[small_bucket].high;
      bucket[merge_bucket].count += bucket[small_bucket].count;
    } else {
      bucket[small_bucket].high = bucket[merge_bucket].high;
      bucket[small_bucket].count += bucket[merge_bucket].count;
      merge_bucket = small_bucket;
829 830
    }

John Koleszar's avatar
John Koleszar committed
831
    assert(bucket[merge_bucket].low != bucket[merge_bucket].high);
832

John Koleszar's avatar
John Koleszar committed
833
    buckets--;
834

John Koleszar's avatar
John Koleszar committed
835 836 837 838 839 840 841 842 843 844 845 846
    /* Remove the merge_bucket from the list, and find the new small
     * and big buckets while we're at it
     */
    big_bucket = small_bucket = 0;
    for (i = 0; i < buckets; i++) {
      if (i > merge_bucket)
        bucket[i] = bucket[i + 1];

      if (bucket[i].count < bucket[small_bucket].count)
        small_bucket = i;
      if (bucket[i].count > bucket[big_bucket].count)
        big_bucket = i;
847 848
    }

John Koleszar's avatar
John Koleszar committed
849 850 851 852
  }

  *buckets_ = buckets;
  return bucket[big_bucket].count;
853 854 855 856 857 858
}


static void show_histogram(const struct hist_bucket *bucket,
                           int                       buckets,
                           int                       total,
John Koleszar's avatar
John Koleszar committed
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
                           int                       scale) {
  const char *pat1, *pat2;
  int i;

  switch ((int)(log(bucket[buckets - 1].high) / log(10)) + 1) {
    case 1:
    case 2:
      pat1 = "%4d %2s: ";
      pat2 = "%4d-%2d: ";
      break;
    case 3:
      pat1 = "%5d %3s: ";
      pat2 = "%5d-%3d: ";
      break;
    case 4:
      pat1 = "%6d %4s: ";
      pat2 = "%6d-%4d: ";
      break;
    case 5:
      pat1 = "%7d %5s: ";
      pat2 = "%7d-%5d: ";
      break;
    case 6:
      pat1 = "%8d %6s: ";
      pat2 = "%8d-%6d: ";
      break;
    case 7:
      pat1 = "%9d %7s: ";
      pat2 = "%9d-%7d: ";
      break;
    default:
      pat1 = "%12d %10s: ";
      pat2 = "%12d-%10d: ";
      break;
  }

  for (i = 0; i < buckets; i++) {
    int len;
    int j;
    float pct;

John Koleszar's avatar
John Koleszar committed
900
    pct = (float)(100.0 * bucket[i].count / total);