vpxenc.c 79 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_VP8_ENCODER || CONFIG_VP9_ENCODER
36
#include "vpx/vp8cx.h"
John Koleszar's avatar
John Koleszar committed
37
#endif
38
#if CONFIG_VP8_DECODER || 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[] = {
95
96
#if CONFIG_VP8_ENCODER && CONFIG_VP8_DECODER
  {"vp8", &vpx_codec_vp8_cx, &vpx_codec_vp8_dx, 0x30385056},
97
#elif CONFIG_VP8_ENCODER && !CONFIG_VP8_DECODER
98
99
  {"vp8", &vpx_codec_vp8_cx, NULL, 0x30385056},
#endif
John Koleszar's avatar
John Koleszar committed
100
#if CONFIG_VP9_ENCODER && CONFIG_VP9_DECODER
101
  {"vp9", &vpx_codec_vp9_cx, &vpx_codec_vp9_dx, 0x30395056},
102
#elif CONFIG_VP9_ENCODER && !CONFIG_VP9_DECODER
103
  {"vp9", &vpx_codec_vp9_cx, NULL, 0x30395056},
104
105
106
#endif
};

John Koleszar's avatar
John Koleszar committed
107
108
static void usage_exit();

John Koleszar's avatar
John Koleszar committed
109
110
111
112
113
114
115
116
117
118
119
120
#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
121
void die(const char *fmt, ...) {
John Koleszar's avatar
John Koleszar committed
122
  LOG_ERROR(NULL);
John Koleszar's avatar
John Koleszar committed
123
  usage_exit();
John Koleszar's avatar
John Koleszar committed
124
125
}

John Koleszar's avatar
John Koleszar committed
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

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
142
143
  if (ctx->err) {
    const char *detail = vpx_codec_error_detail(ctx);
John Koleszar's avatar
John Koleszar committed
144

John Koleszar's avatar
John Koleszar committed
145
146
    vfprintf(stderr, s, ap);
    fprintf(stderr, ": %s\n", vpx_codec_error(ctx));
John Koleszar's avatar
John Koleszar committed
147

John Koleszar's avatar
John Koleszar committed
148
149
    if (detail)
      fprintf(stderr, "    %s\n", detail);
John Koleszar's avatar
John Koleszar committed
150

John Koleszar's avatar
John Koleszar committed
151
152
    exit(EXIT_FAILURE);
  }
John Koleszar's avatar
John Koleszar committed
153
154
155
156
157
}

/* This structure is used to abstract the different ways of handling
 * first pass statistics.
 */
John Koleszar's avatar
John Koleszar committed
158
159
160
161
162
163
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
164
165
} stats_io_t;

John Koleszar's avatar
John Koleszar committed
166
167
int stats_open_file(stats_io_t *stats, const char *fpf, int pass) {
  int res;
John Koleszar's avatar
John Koleszar committed
168

John Koleszar's avatar
John Koleszar committed
169
  stats->pass = pass;
John Koleszar's avatar
John Koleszar committed
170

John Koleszar's avatar
John Koleszar committed
171
172
173
174
175
176
  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
177
178
#if 0
#elif USE_POSIX_MMAP
John Koleszar's avatar
John Koleszar committed
179
180
181
182
183
184
185
186
187
188
    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
189
#else
John Koleszar's avatar
John Koleszar committed
190
    size_t nbytes;
John Koleszar's avatar
John Koleszar committed
191

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

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

John Koleszar's avatar
John Koleszar committed
197
198
    stats->buf.sz = stats->buf_alloc_sz = ftell(stats->file);
    rewind(stats->file);
John Koleszar's avatar
John Koleszar committed
199

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

John Koleszar's avatar
John Koleszar committed
202
203
204
    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
205

John Koleszar's avatar
John Koleszar committed
206
207
    nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file);
    res = (nbytes == stats->buf.sz);
John Koleszar's avatar
John Koleszar committed
208
#endif
John Koleszar's avatar
John Koleszar committed
209
  }
John Koleszar's avatar
John Koleszar committed
210

John Koleszar's avatar
John Koleszar committed
211
  return res;
John Koleszar's avatar
John Koleszar committed
212
213
}

John Koleszar's avatar
John Koleszar committed
214
215
216
int stats_open_mem(stats_io_t *stats, int pass) {
  int res;
  stats->pass = pass;
John Koleszar's avatar
John Koleszar committed
217

John Koleszar's avatar
John Koleszar committed
218
219
220
221
222
  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
223

John Koleszar's avatar
John Koleszar committed
224
225
226
  stats->buf_ptr = stats->buf.buf;
  res = (stats->buf.buf != NULL);
  return res;
John Koleszar's avatar
John Koleszar committed
227
228
229
}


John Koleszar's avatar
John Koleszar committed
230
231
232
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
233
234
#if 0
#elif USE_POSIX_MMAP
John Koleszar's avatar
John Koleszar committed
235
      munmap(stats->buf.buf, stats->buf.sz);
John Koleszar's avatar
John Koleszar committed
236
#else
John Koleszar's avatar
John Koleszar committed
237
      free(stats->buf.buf);
John Koleszar's avatar
John Koleszar committed
238
239
#endif
    }
John Koleszar's avatar
John Koleszar committed
240
241
242
243
244
245
246

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

John Koleszar's avatar
John Koleszar committed
249
250
void stats_write(stats_io_t *stats, const void *pkt, size_t len) {
  if (stats->file) {
John Koleszar's avatar
John Koleszar committed
251
    (void) fwrite(pkt, 1, len, stats->file);
John Koleszar's avatar
John Koleszar committed
252
253
254
255
256
257
258
259
260
  } 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
261
262
      } else
        fatal("Failed to realloc firstpass stats buffer.");
John Koleszar's avatar
John Koleszar committed
263
264
    }

John Koleszar's avatar
John Koleszar committed
265
266
267
268
    memcpy(stats->buf_ptr, pkt, len);
    stats->buf.sz += len;
    stats->buf_ptr += len;
  }
John Koleszar's avatar
John Koleszar committed
269
270
}

John Koleszar's avatar
John Koleszar committed
271
272
vpx_fixed_buf_t stats_get(stats_io_t *stats) {
  return stats->buf;
John Koleszar's avatar
John Koleszar committed
273
274
}

275
/* Stereo 3D packed frame format */
John Koleszar's avatar
John Koleszar committed
276
277
278
279
280
281
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
282
283
} stereo_format_t;

John Koleszar's avatar
John Koleszar committed
284
285
286
287
enum video_file_type {
  FILE_TYPE_RAW,
  FILE_TYPE_IVF,
  FILE_TYPE_Y4M
288
289
};

290
struct detect_buffer {
John Koleszar's avatar
John Koleszar committed
291
292
293
  char buf[4];
  size_t buf_read;
  size_t position;
294
295
296
};


John Koleszar's avatar
John Koleszar committed
297
298
299
300
301
302
303
304
305
306
307
308
309
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
310
#define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */
John Koleszar's avatar
John Koleszar committed
311
312
313
314
315
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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  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
330
      (void) fread(junk, 1, IVF_FRAME_HDR_SZ, f);
John Koleszar's avatar
John Koleszar committed
331
    }
332

John Koleszar's avatar
John Koleszar committed
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
360
361
362
363
    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
364
        }
John Koleszar's avatar
John Koleszar committed
365
366
        if (needed > 0) {
          shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
John Koleszar's avatar
John Koleszar committed
367
        }
John Koleszar's avatar
John Koleszar committed
368
369
370

        ptr += img->stride[plane];
      }
John Koleszar's avatar
John Koleszar committed
371
    }
John Koleszar's avatar
John Koleszar committed
372
  }
John Koleszar's avatar
John Koleszar committed
373

John Koleszar's avatar
John Koleszar committed
374
  return !shortread;
John Koleszar's avatar
John Koleszar committed
375
376
377
}


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

John Koleszar's avatar
John Koleszar committed
387
#define IVF_FILE_HDR_SZ (32)
John Koleszar's avatar
John Koleszar committed
388
389
unsigned int file_is_ivf(struct input_state *input,
                         unsigned int *fourcc) {
John Koleszar's avatar
John Koleszar committed
390
391
  char raw_hdr[IVF_FILE_HDR_SZ];
  int is_ivf = 0;
John Koleszar's avatar
John Koleszar committed
392
393
394
395
  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
396

John Koleszar's avatar
John Koleszar committed
397
398
  if (memcmp(detect->buf, "DKIF", 4) != 0)
    return 0;
399

John Koleszar's avatar
John Koleszar committed
400
401
402
403
404
  /* 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
405
    {
John Koleszar's avatar
John Koleszar committed
406
      is_ivf = 1;
John Koleszar's avatar
John Koleszar committed
407

John Koleszar's avatar
John Koleszar committed
408
      if (mem_get_le16(raw_hdr + 4) != 0)
John Koleszar's avatar
John Koleszar committed
409
410
        warn("Unrecognized IVF version! This file may not decode "
             "properly.");
John Koleszar's avatar
John Koleszar committed
411

John Koleszar's avatar
John Koleszar committed
412
      *fourcc = mem_get_le32(raw_hdr + 8);
John Koleszar's avatar
John Koleszar committed
413
    }
John Koleszar's avatar
John Koleszar committed
414
  }
John Koleszar's avatar
John Koleszar committed
415

John Koleszar's avatar
John Koleszar committed
416
417
418
419
420
  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
421

John Koleszar's avatar
John Koleszar committed
422
  return is_ivf;
John Koleszar's avatar
John Koleszar committed
423
424
425
426
427
428
}


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
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
                                  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
449
  (void) fwrite(header, 1, 32, outfile);
John Koleszar's avatar
John Koleszar committed
450
451
452
453
}


static void write_ivf_frame_header(FILE *outfile,
John Koleszar's avatar
John Koleszar committed
454
455
456
                                   const vpx_codec_cx_pkt_t *pkt) {
  char             header[12];
  vpx_codec_pts_t  pts;
John Koleszar's avatar
John Koleszar committed
457

John Koleszar's avatar
John Koleszar committed
458
459
  if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
    return;
John Koleszar's avatar
John Koleszar committed
460

John Koleszar's avatar
John Koleszar committed
461
  pts = pkt->data.frame.pts;
John Koleszar's avatar
John Koleszar committed
462
  mem_put_le32(header, (int)pkt->data.frame.sz);
John Koleszar's avatar
John Koleszar committed
463
464
  mem_put_le32(header + 4, pts & 0xFFFFFFFF);
  mem_put_le32(header + 8, pts >> 32);
John Koleszar's avatar
John Koleszar committed
465

John Koleszar's avatar
John Koleszar committed
466
467
468
469
470
471
472
  (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
473
474
}

John Koleszar's avatar
John Koleszar committed
475
476
477
478

typedef off_t EbmlLoc;


John Koleszar's avatar
John Koleszar committed
479
480
481
struct cue_entry {
  unsigned int time;
  uint64_t     loc;
John Koleszar's avatar
John Koleszar committed
482
483
484
};


John Koleszar's avatar
John Koleszar committed
485
486
struct EbmlGlobal {
  int debug;
487

John Koleszar's avatar
John Koleszar committed
488
489
490
  FILE    *stream;
  int64_t last_pts_ms;
  vpx_rational_t  framerate;
John Koleszar's avatar
John Koleszar committed
491

John Koleszar's avatar
John Koleszar committed
492
493
494
495
496
497
498
  /* 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
499

John Koleszar's avatar
John Koleszar committed
500
501
  /* This pointer is to a specific element to be serialized */
  off_t    track_id_pos;
John Koleszar's avatar
John Koleszar committed
502

John Koleszar's avatar
John Koleszar committed
503
504
505
  /* These pointers are to the size field of the element */
  EbmlLoc  startSegment;
  EbmlLoc  startCluster;
John Koleszar's avatar
John Koleszar committed
506

John Koleszar's avatar
John Koleszar committed
507
508
  uint32_t cluster_timecode;
  int      cluster_open;
John Koleszar's avatar
John Koleszar committed
509

John Koleszar's avatar
John Koleszar committed
510
511
  struct cue_entry *cue_list;
  unsigned int      cues;
John Koleszar's avatar
John Koleszar committed
512
513
514
515

};


John Koleszar's avatar
John Koleszar committed
516
void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
John Koleszar's avatar
John Koleszar committed
517
  (void) fwrite(buffer_in, 1, len, glob->stream);
John Koleszar's avatar
John Koleszar committed
518
519
}

520
#define WRITE_BUFFER(s) \
John Koleszar's avatar
John Koleszar committed
521
522
  for(i = len-1; i>=0; i--)\
  { \
John Koleszar's avatar
John Koleszar committed
523
    x = (char)(*(const s *)buffer_in >> (i * CHAR_BIT)); \
524
    Ebml_Write(glob, &x, 1); \
John Koleszar's avatar
John Koleszar committed
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  }
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
552
}
553
#undef WRITE_BUFFER
John Koleszar's avatar
John Koleszar committed
554

555
/* Need a fixed size serializer for the track ID. libmkv provides a 64 bit
John Koleszar's avatar
John Koleszar committed
556
557
 * one, but not a 32 bit one.
 */
John Koleszar's avatar
John Koleszar committed
558
559
560
561
562
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
563
564
565
}


John Koleszar's avatar
John Koleszar committed
566
567
static void
Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc,
John Koleszar's avatar
John Koleszar committed
568
                     unsigned long class_id) {
John Koleszar's avatar
John Koleszar committed
569
570
571
  /* 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
572
573
574
575

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

static void
John Koleszar's avatar
John Koleszar committed
579
580
581
Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
  off_t pos;
  uint64_t size;
John Koleszar's avatar
John Koleszar committed
582

John Koleszar's avatar
John Koleszar committed
583
584
  /* Save the current stream pointer */
  pos = ftello(glob->stream);
John Koleszar's avatar
John Koleszar committed
585

John Koleszar's avatar
John Koleszar committed
586
587
  /* Calculate the size of this element */
  size = pos - *ebmlLoc - 8;
John Koleszar's avatar
John Koleszar committed
588
  size |= LITERALU64(0x01000000, 0x00000000);
John Koleszar's avatar
John Koleszar committed
589

John Koleszar's avatar
John Koleszar committed
590
591
592
  /* 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
593

John Koleszar's avatar
John Koleszar committed
594
595
  /* Reset the stream pointer */
  fseeko(glob->stream, pos, SEEK_SET);
John Koleszar's avatar
John Koleszar committed
596
597
}

John Koleszar's avatar
John Koleszar committed
598
599

static void
John Koleszar's avatar
John Koleszar committed
600
601
602
603
604
605
606
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
607
608
609
610
}


static void
John Koleszar's avatar
John Koleszar committed
611
write_webm_seek_info(EbmlGlobal *ebml) {
John Koleszar's avatar
John Koleszar committed
612

John Koleszar's avatar
John Koleszar committed
613
  off_t pos;
John Koleszar's avatar
John Koleszar committed
614

John Koleszar's avatar
John Koleszar committed
615
616
  /* Save the current stream pointer */
  pos = ftello(ebml->stream);
John Koleszar's avatar
John Koleszar committed
617

John Koleszar's avatar
John Koleszar committed
618
619
620
621
  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
622

John Koleszar's avatar
John Koleszar committed
623
624
  {
    EbmlLoc start;
John Koleszar's avatar
John Koleszar committed
625

John Koleszar's avatar
John Koleszar committed
626
627
628
629
630
631
632
    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
633
    /* segment info */
John Koleszar's avatar
John Koleszar committed
634
635
    EbmlLoc startInfo;
    uint64_t frame_time;
John Koleszar's avatar
John Koleszar committed
636
637
638
639
640
641
642
643
644
645
646
    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
647
648
649
650
651
652
653

    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
654
655
656
                        (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
657
658
    Ebml_EndSubElement(ebml, &startInfo);
  }
John Koleszar's avatar
John Koleszar committed
659
660
661
662
663
664
}


static void
write_webm_file_header(EbmlGlobal                *glob,
                       const vpx_codec_enc_cfg_t *cfg,
665
                       const struct vpx_rational *fps,
John Koleszar's avatar
John Koleszar committed
666
667
668
669
670
                       stereo_format_t            stereo_fmt) {
  {
    EbmlLoc start;
    Ebml_StartSubElement(glob, &start, EBML);
    Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
John Koleszar's avatar
John Koleszar committed
671
672
673
674
675
676
    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
677
678
679
    Ebml_EndSubElement(glob, &start);
  }
  {
John Koleszar's avatar
John Koleszar committed
680
    Ebml_StartSubElement(glob, &glob->startSegment, Segment);
John Koleszar's avatar
John Koleszar committed
681
682
683
684
    glob->position_reference = ftello(glob->stream);
    glob->framerate = *fps;
    write_webm_seek_info(glob);

John Koleszar's avatar
John Koleszar committed
685
    {
John Koleszar's avatar
John Koleszar committed
686
687
688
689
690
691
      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
692

John Koleszar's avatar
John Koleszar committed
693
694
695
696
697
        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
698
        Ebml_SerializeUnsigned(glob, TrackType, 1);
John Koleszar's avatar
John Koleszar committed
699
        Ebml_SerializeString(glob, CodecID, "V_VP8");
John Koleszar's avatar
John Koleszar committed
700
        {
John Koleszar's avatar
John Koleszar committed
701
702
703
704
705
706
707
708
709
710
          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
711
          Ebml_EndSubElement(glob, &videoStart);
John Koleszar's avatar
John Koleszar committed
712
        }
John Koleszar's avatar
John Koleszar committed
713
        Ebml_EndSubElement(glob, &start); /* Track Entry */
John Koleszar's avatar
John Koleszar committed
714
715
      }
      Ebml_EndSubElement(glob, &trackStart);
John Koleszar's avatar
John Koleszar committed
716
    }
John Koleszar's avatar
John Koleszar committed
717
    /* segment element is open */
John Koleszar's avatar
John Koleszar committed
718
  }
John Koleszar's avatar
John Koleszar committed
719
720
721
722
723
724
}


static void
write_webm_block(EbmlGlobal                *glob,
                 const vpx_codec_enc_cfg_t *cfg,
John Koleszar's avatar
John Koleszar committed
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
                 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
744
    block_timecode = (unsigned short)pts_ms - glob->cluster_timecode;
John Koleszar's avatar
John Koleszar committed
745
746
747
748
749
750
751
752
753

  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
754
    glob->cluster_timecode = (uint32_t)pts_ms;
John Koleszar's avatar
John Koleszar committed
755
    glob->cluster_pos = ftello(glob->stream);
John Koleszar's avatar
John Koleszar committed
756
    Ebml_StartSubElement(glob, &glob->startCluster, Cluster); /* cluster */
John Koleszar's avatar
John Koleszar committed
757
758
759
760
761
762
763
764
765
766
    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
767
768
      else
        fatal("Failed to realloc cue list.");
John Koleszar's avatar
John Koleszar committed
769

John Koleszar's avatar
John Koleszar committed
770
771
772
773
      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
774
    }
John Koleszar's avatar
John Koleszar committed
775
  }
John Koleszar's avatar
John Koleszar committed
776

John Koleszar's avatar
John Koleszar committed
777
778
  /* Write the Simple Block */
  Ebml_WriteID(glob, SimpleBlock);
John Koleszar's avatar
John Koleszar committed
779

John Koleszar's avatar
John Koleszar committed
780
  block_length = (unsigned long)pkt->data.frame.sz + 4;
John Koleszar's avatar
John Koleszar committed
781
782
  block_length |= 0x10000000;
  Ebml_Serialize(glob, &block_length, sizeof(block_length), 4);
John Koleszar's avatar
John Koleszar committed
783

John Koleszar's avatar
John Koleszar committed
784
785
786
  track_number = 1;
  track_number |= 0x80;
  Ebml_Write(glob, &track_number, 1);
John Koleszar's avatar
John Koleszar committed
787

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

John Koleszar's avatar
John Koleszar committed
790
791
792
793
794
795
  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
796

John Koleszar's avatar
John Koleszar committed
797
  Ebml_Write(glob, pkt->data.frame.buf, (unsigned long)pkt->data.frame.sz);
John Koleszar's avatar
John Koleszar committed
798
799
800
801
}


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

John Koleszar's avatar
John Koleszar committed
804
805
  if (glob->cluster_open)
    Ebml_EndSubElement(glob, &glob->startCluster);
John Koleszar's avatar
John Koleszar committed
806

John Koleszar's avatar
John Koleszar committed
807
808
  {
    EbmlLoc start;
John Koleszar's avatar
John Koleszar committed
809
    unsigned int i;
John Koleszar's avatar
John Koleszar committed
810

John Koleszar's avatar
John Koleszar committed
811
812
813
814
815
    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
816

John Koleszar's avatar
John Koleszar committed
817
818
819
      Ebml_StartSubElement(glob, &start, CuePoint);
      {
        EbmlLoc start;
John Koleszar's avatar
John Koleszar committed
820

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

John Koleszar's avatar
John Koleszar committed
823
824
825
826
        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
827
        Ebml_EndSubElement(glob, &start);
John Koleszar's avatar
John Koleszar committed
828
829
      }
      Ebml_EndSubElement(glob, &start);
John Koleszar's avatar
John Koleszar committed
830
    }
John Koleszar's avatar
John Koleszar committed
831
832
    Ebml_EndSubElement(glob, &start);
  }
John Koleszar's avatar
John Koleszar committed
833

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

John Koleszar's avatar
John Koleszar committed
836
837
  /* Patch up the seek info block */
  write_webm_seek_info(glob);
John Koleszar's avatar
John Koleszar committed
838

John Koleszar's avatar
John Koleszar committed
839
840
841
  /* 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
842

John Koleszar's avatar
John Koleszar committed
843
  fseeko(glob->stream, 0, SEEK_END);
John Koleszar's avatar
John Koleszar committed
844
845
846
}


John Koleszar's avatar
John Koleszar committed
847
/* Murmur hash derived from public domain reference implementation at
John Koleszar's avatar
John Koleszar committed
848
 *   http:// sites.google.com/site/murmurhash/
John Koleszar's avatar
John Koleszar committed
849
 */
John Koleszar's avatar
John Koleszar committed
850
851
852
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
853

John Koleszar's avatar
John Koleszar committed
854
  unsigned int h = seed ^ len;
John Koleszar's avatar
John Koleszar committed
855

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

John Koleszar's avatar
John Koleszar committed
858
859
  while (len >= 4) {
    unsigned int k;
John Koleszar's avatar
John Koleszar committed
860

John Koleszar's avatar
John Koleszar committed
861
862
863
864
    k  = data[0];
    k |= data[1] << 8;
    k |= data[2] << 16;
    k |= data[3] << 24;
John Koleszar's avatar
John Koleszar committed
865

John Koleszar's avatar
John Koleszar committed
866
867
868
    k *= m;
    k ^= k >> r;
    k *= m;
John Koleszar's avatar
John Koleszar committed
869
870

    h *= m;
John Koleszar's avatar
John Koleszar committed
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
    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
892
893
}

894
#include "math.h"
895
#define MAX_PSNR 100
John Koleszar's avatar
John Koleszar committed
896
897
static double vp8_mse2psnr(double Samples, double Peak, double Mse) {
  double psnr;
898

John Koleszar's avatar
John Koleszar committed
899
900
901
  if ((double)Mse > 0.0)
    psnr = 10.0 * log10(Peak * Peak * Samples / Mse);
  else
John Koleszar's avatar
John Koleszar committed
902
    psnr = MAX_PSNR;      /* Limit to prevent / 0 */
903

John Koleszar's avatar
John Koleszar committed
904
905
  if (psnr > MAX_PSNR)
    psnr = MAX_PSNR;
906

John Koleszar's avatar
John Koleszar committed
907
  return psnr;
908
909
}

John Koleszar's avatar
John Koleszar committed
910

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

static const arg_def_t usage            = ARG_DEF("u", "usage", 1,
John Koleszar's avatar
John Koleszar committed
967
                                                  "Usage profile number to use");
John Koleszar's avatar
John Koleszar committed
968
static const arg_def_t threads          = ARG_DEF("t", "threads", 1,
John Koleszar's avatar
John Koleszar committed
969
                                                  "Max number of threads to use");
John Koleszar's avatar
John Koleszar committed
970
static const arg_def_t profile          = ARG_DEF(NULL, "profile", 1,
John Koleszar's avatar
John Koleszar committed
971
                                                  "Bitstream profile number to use");
John Koleszar's avatar
John Koleszar committed
972
static const arg_def_t width            = ARG_DEF("w", "width", 1,
John Koleszar's avatar
John Koleszar committed
973
                                                  "Frame width");
John Koleszar's avatar
John Koleszar committed
974
static const arg_def_t height           = ARG_DEF("h", "height", 1,
John Koleszar's avatar
John Koleszar committed
975
                                                  "Frame height");
976
static const struct arg_enum_list stereo_mode_enum[] = {
John Koleszar's avatar
John Koleszar committed
977
978
979
980
981
982
  {"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}
983
984
};
static const arg_def_t stereo_mode      = ARG_DEF_ENUM(NULL, "stereo-mode", 1,
John Koleszar's avatar
John Koleszar committed
985
                                                       "Stereo 3D video format", stereo_mode_enum);
John Koleszar's avatar
John Koleszar committed
986
static const arg_def_t timebase         = ARG_DEF(NULL, "timebase", 1,
John Koleszar's avatar
John Koleszar committed
987
                                                  "Output timestamp precision (fractional seconds)");
John Koleszar's avatar
John Koleszar committed
988
static const arg_def_t error_resilient  = ARG_DEF(NULL, "error-resilient", 1,
John Koleszar's avatar
John Koleszar committed
989
                                                  "Enable error resiliency features");
John Koleszar's avatar
John Koleszar committed
990
static const arg_def_t lag_in_frames    = ARG_DEF(NULL, "lag-in-frames", 1,
John Koleszar's avatar
John Koleszar committed
991
                                                  "Max number of frames to lag");
John Koleszar's avatar
John Koleszar committed
992

John Koleszar's avatar
John Koleszar committed
993
994
995
996
static const arg_def_t *global_args[] = {
  &use_yv12, &use_i420, &usage, &threads, &profile,
  &width, &height, &stereo_mode, &timebase, &framerate, &error_resilient,
  &lag_in_frames, NULL
John Koleszar's avatar
John Koleszar committed
997
998
999
};

static const arg_def_t dropframe_thresh   = ARG_DEF(NULL, "drop-frame", 1,
John Koleszar's avatar
John Koleszar committed
1000
                                                    "Temporal resampling threshold (buf %)");
John Koleszar's avatar
John Koleszar committed
1001
static const arg_def_t resize_allowed     = ARG_DEF(NULL, "resize-allowed", 1,
John Koleszar's avatar
John Koleszar committed
1002
                                                    "Spatial resampling enabled (bool)");
John Koleszar's avatar
John Koleszar committed
1003
static const arg_def_t resize_up_thresh   = ARG_DEF(NULL, "resize-up", 1,
John Koleszar's avatar
John Koleszar committed
1004
                                                    "Upscale threshold (buf %)");
John Koleszar's avatar
John Koleszar committed
1005
static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1,
John Koleszar's avatar
John Koleszar committed
1006
                                                    "Downscale threshold (buf %)");
1007
static const struct arg_enum_list end_usage_enum[] = {
John Koleszar's avatar
John Koleszar committed
1008
1009
1010
1011
  {"vbr", VPX_VBR},
  {"cbr", VPX_CBR},
  {"cq",  VPX_CQ},
  {NULL, 0}
1012
1013
};
static const arg_def_t end_usage          = ARG_DEF_ENUM(NULL, "end-usage", 1,
John Koleszar's avatar
John Koleszar committed
1014
                                                         "Rate control mode", end_usage_enum);
John Koleszar's avatar
John Koleszar committed
1015
static const arg_def_t target_bitrate     = ARG_DEF(NULL, "target-bitrate", 1,
John Koleszar's avatar
John Koleszar committed
1016
                                                    "Bitrate (kbps)");
John Koleszar's avatar
John Koleszar committed
1017
static const arg_def_t min_quantizer      = ARG_DEF(NULL, "min-q", 1,
John Koleszar's avatar
John Koleszar committed
1018
                                                    "Minimum (best) quantizer");
John Koleszar's avatar
John Koleszar committed
1019
static const arg_def_t max_quantizer      = ARG_DEF(NULL, "max-q", 1,
John Koleszar's avatar
John Koleszar committed
1020
                                                    "Maximum (worst) quantizer");
John Koleszar's avatar
John Koleszar committed
1021
static const arg_def_t undershoot_pct     = ARG_DEF(NULL, "undershoot-pct", 1,
John Koleszar's avatar
John Koleszar committed
1022
                                                    "Datarate undershoot (min) target (%)");
John Koleszar's avatar
John Koleszar committed
1023
static const arg_def_t overshoot_pct      = ARG_DEF(NULL, "overshoot-pct", 1,
John Koleszar's avatar
John Koleszar committed
1024
                                                    "Datarate overshoot (max) target (%)");
John Koleszar's avatar
John Koleszar committed
1025
static const arg_def_t buf_sz             = ARG_DEF(NULL, "buf-sz", 1,
John Koleszar's avatar
John Koleszar committed
1026
                                                    "Client buffer size (ms)");
John Koleszar's avatar
John Koleszar committed
1027
static const arg_def_t buf_initial_sz     = ARG_DEF(NULL, "buf-initial-sz", 1,
John Koleszar's avatar
John Koleszar committed
1028
                                                    "Client initial buffer size (ms)");
John Koleszar's avatar
John Koleszar committed
1029
static const arg_def_t buf_optimal_sz     = ARG_DEF(NULL, "buf-optimal-sz", 1,
John Koleszar's avatar
John Koleszar committed
1030
1031
1032
1033
1034
1035
                                                    "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
1036
1037
1038
1039
};


static const arg_def_t bias_pct = ARG_DEF(NULL, "bias-pct", 1,
John Koleszar's avatar
John Koleszar committed
1040
                                          "CBR/VBR bias (0=CBR, 100=VBR)");
John Koleszar's avatar
John Koleszar committed
1041
static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1,
John Koleszar's avatar
John Koleszar committed
1042
                                                "GOP min bitrate (% of target)");
John Koleszar's avatar
John Koleszar committed
1043
static const arg_def_t maxsection_pct = ARG_DEF(NULL, "maxsection-pct", 1,
John Koleszar's avatar
John Koleszar committed
1044
1045
1046
                                                "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
1047
1048
1049
1050
};


static const arg_def_t kf_min_dist = ARG_DEF(NULL, "kf-min-dist", 1,
John Koleszar's avatar
John Koleszar committed
1051
                                             "Minimum keyframe interval (frames)");
John Koleszar's avatar
John Koleszar committed
1052
static const arg_def_t kf_max_dist = ARG_DEF(NULL, "kf-max-dist", 1,
John Koleszar's avatar
John Koleszar committed
1053
                                             "Maximum keyframe interval (frames)");
1054
static const arg_def_t kf_disabled = ARG_DEF(NULL, "disable-kf", 0,
John Koleszar's avatar
John Koleszar committed
1055
1056
1057
                                             "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
1058
1059
1060
1061
};


static const arg_def_t noise_sens = ARG_DEF(NULL, "noise-sensitivity", 1,
John Koleszar's avatar
John Koleszar committed