vpxenc

00001 /*
00002  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
00003  *
00004  *  Use of this source code is governed by a BSD-style license
00005  *  that can be found in the LICENSE file in the root of the source
00006  *  tree. An additional intellectual property rights grant can be found
00007  *  in the file PATENTS.  All contributing project authors may
00008  *  be found in the AUTHORS file in the root of the source tree.
00009  */
00010 
00011 #include "./vpx_config.h"
00012 
00013 #if defined(_WIN32) || defined(__OS2__) || !CONFIG_OS_SUPPORT
00014 #define USE_POSIX_MMAP 0
00015 #else
00016 #define USE_POSIX_MMAP 1
00017 #endif
00018 
00019 #include <math.h>
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <stdarg.h>
00023 #include <string.h>
00024 #include <limits.h>
00025 #include <assert.h>
00026 #include "vpx/vpx_encoder.h"
00027 #if CONFIG_DECODERS
00028 #include "vpx/vpx_decoder.h"
00029 #endif
00030 #if USE_POSIX_MMAP
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <sys/mman.h>
00034 #include <fcntl.h>
00035 #include <unistd.h>
00036 #endif
00037 
00038 #include "third_party/libyuv/include/libyuv/scale.h"
00039 
00040 #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
00041 #include "vpx/vp8cx.h"
00042 #endif
00043 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
00044 #include "vpx/vp8dx.h"
00045 #endif
00046 
00047 #include "./tools_common.h"
00048 #include "vpx_ports/mem_ops.h"
00049 #include "vpx_ports/vpx_timer.h"
00050 #include "./vpxstats.h"
00051 #include "./webmenc.h"
00052 #include "./y4minput.h"
00053 
00054 /* Swallow warnings about unused results of fread/fwrite */
00055 static size_t wrap_fread(void *ptr, size_t size, size_t nmemb,
00056                          FILE *stream) {
00057   return fread(ptr, size, nmemb, stream);
00058 }
00059 #define fread wrap_fread
00060 
00061 static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb,
00062                           FILE *stream) {
00063   return fwrite(ptr, size, nmemb, stream);
00064 }
00065 #define fwrite wrap_fwrite
00066 
00067 
00068 static const char *exec_name;
00069 
00070 static const struct codec_item {
00071   char const              *name;
00072   const vpx_codec_iface_t *(*iface)(void);
00073   const vpx_codec_iface_t *(*dx_iface)(void);
00074   unsigned int             fourcc;
00075 } codecs[] = {
00076 #if CONFIG_VP8_ENCODER && CONFIG_VP8_DECODER
00077   {"vp8", &vpx_codec_vp8_cx, &vpx_codec_vp8_dx, VP8_FOURCC},
00078 #elif CONFIG_VP8_ENCODER && !CONFIG_VP8_DECODER
00079   {"vp8", &vpx_codec_vp8_cx, NULL, VP8_FOURCC},
00080 #endif
00081 #if CONFIG_VP9_ENCODER && CONFIG_VP9_DECODER
00082   {"vp9", &vpx_codec_vp9_cx, &vpx_codec_vp9_dx, VP9_FOURCC},
00083 #elif CONFIG_VP9_ENCODER && !CONFIG_VP9_DECODER
00084   {"vp9", &vpx_codec_vp9_cx, NULL, VP9_FOURCC},
00085 #endif
00086 };
00087 
00088 static void warn_or_exit_on_errorv(vpx_codec_ctx_t *ctx, int fatal,
00089                                    const char *s, va_list ap) {
00090   if (ctx->err) {
00091     const char *detail = vpx_codec_error_detail(ctx);
00092 
00093     vfprintf(stderr, s, ap);
00094     fprintf(stderr, ": %s\n", vpx_codec_error(ctx));
00095 
00096     if (detail)
00097       fprintf(stderr, "    %s\n", detail);
00098 
00099     if (fatal)
00100       exit(EXIT_FAILURE);
00101   }
00102 }
00103 
00104 static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) {
00105   va_list ap;
00106 
00107   va_start(ap, s);
00108   warn_or_exit_on_errorv(ctx, 1, s, ap);
00109   va_end(ap);
00110 }
00111 
00112 static void warn_or_exit_on_error(vpx_codec_ctx_t *ctx, int fatal,
00113                                   const char *s, ...) {
00114   va_list ap;
00115 
00116   va_start(ap, s);
00117   warn_or_exit_on_errorv(ctx, fatal, s, ap);
00118   va_end(ap);
00119 }
00120 
00121 enum video_file_type {
00122   FILE_TYPE_RAW,
00123   FILE_TYPE_IVF,
00124   FILE_TYPE_Y4M
00125 };
00126 
00127 struct detect_buffer {
00128   char buf[4];
00129   size_t buf_read;
00130   size_t position;
00131 };
00132 
00133 
00134 struct input_state {
00135   char                 *fn;
00136   FILE                 *file;
00137   off_t                 length;
00138   y4m_input             y4m;
00139   struct detect_buffer  detect;
00140   enum video_file_type  file_type;
00141   unsigned int          w;
00142   unsigned int          h;
00143   struct vpx_rational   framerate;
00144   int                   use_i420;
00145   int                   only_i420;
00146 };
00147 
00148 #define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */
00149 static int read_frame(struct input_state *input, vpx_image_t *img) {
00150   FILE *f = input->file;
00151   enum video_file_type file_type = input->file_type;
00152   y4m_input *y4m = &input->y4m;
00153   struct detect_buffer *detect = &input->detect;
00154   int plane = 0;
00155   int shortread = 0;
00156 
00157   if (file_type == FILE_TYPE_Y4M) {
00158     if (y4m_input_fetch_frame(y4m, f, img) < 1)
00159       return 0;
00160   } else {
00161     if (file_type == FILE_TYPE_IVF) {
00162       char junk[IVF_FRAME_HDR_SZ];
00163 
00164       /* Skip the frame header. We know how big the frame should be. See
00165        * write_ivf_frame_header() for documentation on the frame header
00166        * layout.
00167        */
00168       (void) fread(junk, 1, IVF_FRAME_HDR_SZ, f);
00169     }
00170 
00171     for (plane = 0; plane < 3; plane++) {
00172       unsigned char *ptr;
00173       int w = (plane ? (1 + img->d_w) / 2 : img->d_w);
00174       int h = (plane ? (1 + img->d_h) / 2 : img->d_h);
00175       int r;
00176 
00177       /* Determine the correct plane based on the image format. The for-loop
00178        * always counts in Y,U,V order, but this may not match the order of
00179        * the data on disk.
00180        */
00181       switch (plane) {
00182         case 1:
00183           ptr = img->planes[img->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_V : VPX_PLANE_U];
00184           break;
00185         case 2:
00186           ptr = img->planes[img->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_U : VPX_PLANE_V];
00187           break;
00188         default:
00189           ptr = img->planes[plane];
00190       }
00191 
00192       for (r = 0; r < h; r++) {
00193         size_t needed = w;
00194         size_t buf_position = 0;
00195         const size_t left = detect->buf_read - detect->position;
00196         if (left > 0) {
00197           const size_t more = (left < needed) ? left : needed;
00198           memcpy(ptr, detect->buf + detect->position, more);
00199           buf_position = more;
00200           needed -= more;
00201           detect->position += more;
00202         }
00203         if (needed > 0) {
00204           shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
00205         }
00206 
00207         ptr += img->stride[plane];
00208       }
00209     }
00210   }
00211 
00212   return !shortread;
00213 }
00214 
00215 
00216 unsigned int file_is_y4m(FILE      *infile,
00217                          y4m_input *y4m,
00218                          char       detect[4]) {
00219   if (memcmp(detect, "YUV4", 4) == 0) {
00220     return 1;
00221   }
00222   return 0;
00223 }
00224 
00225 #define IVF_FILE_HDR_SZ (32)
00226 unsigned int file_is_ivf(struct input_state *input,
00227                          unsigned int *fourcc) {
00228   char raw_hdr[IVF_FILE_HDR_SZ];
00229   int is_ivf = 0;
00230   FILE *infile = input->file;
00231   unsigned int *width = &input->w;
00232   unsigned int *height = &input->h;
00233   struct detect_buffer *detect = &input->detect;
00234 
00235   if (memcmp(detect->buf, "DKIF", 4) != 0)
00236     return 0;
00237 
00238   /* See write_ivf_file_header() for more documentation on the file header
00239    * layout.
00240    */
00241   if (fread(raw_hdr + 4, 1, IVF_FILE_HDR_SZ - 4, infile)
00242       == IVF_FILE_HDR_SZ - 4) {
00243     {
00244       is_ivf = 1;
00245 
00246       if (mem_get_le16(raw_hdr + 4) != 0)
00247         warn("Unrecognized IVF version! This file may not decode "
00248              "properly.");
00249 
00250       *fourcc = mem_get_le32(raw_hdr + 8);
00251     }
00252   }
00253 
00254   if (is_ivf) {
00255     *width = mem_get_le16(raw_hdr + 12);
00256     *height = mem_get_le16(raw_hdr + 14);
00257     detect->position = 4;
00258   }
00259 
00260   return is_ivf;
00261 }
00262 
00263 
00264 static void write_ivf_file_header(FILE *outfile,
00265                                   const vpx_codec_enc_cfg_t *cfg,
00266                                   unsigned int fourcc,
00267                                   int frame_cnt) {
00268   char header[32];
00269 
00270   if (cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
00271     return;
00272 
00273   header[0] = 'D';
00274   header[1] = 'K';
00275   header[2] = 'I';
00276   header[3] = 'F';
00277   mem_put_le16(header + 4,  0);                 /* version */
00278   mem_put_le16(header + 6,  32);                /* headersize */
00279   mem_put_le32(header + 8,  fourcc);            /* headersize */
00280   mem_put_le16(header + 12, cfg->g_w);          /* width */
00281   mem_put_le16(header + 14, cfg->g_h);          /* height */
00282   mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */
00283   mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */
00284   mem_put_le32(header + 24, frame_cnt);         /* length */
00285   mem_put_le32(header + 28, 0);                 /* unused */
00286 
00287   (void) fwrite(header, 1, 32, outfile);
00288 }
00289 
00290 
00291 static void write_ivf_frame_header(FILE *outfile,
00292                                    const vpx_codec_cx_pkt_t *pkt) {
00293   char             header[12];
00294   vpx_codec_pts_t  pts;
00295 
00296   if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
00297     return;
00298 
00299   pts = pkt->data.frame.pts;
00300   mem_put_le32(header, (int)pkt->data.frame.sz);
00301   mem_put_le32(header + 4, pts & 0xFFFFFFFF);
00302   mem_put_le32(header + 8, pts >> 32);
00303 
00304   (void) fwrite(header, 1, 12, outfile);
00305 }
00306 
00307 static void write_ivf_frame_size(FILE *outfile, size_t size) {
00308   char             header[4];
00309   mem_put_le32(header, (int)size);
00310   (void) fwrite(header, 1, 4, outfile);
00311 }
00312 
00313 
00314 
00315 /* Murmur hash derived from public domain reference implementation at
00316  *   http:// sites.google.com/site/murmurhash/
00317  */
00318 static unsigned int murmur(const void *key, int len, unsigned int seed) {
00319   const unsigned int m = 0x5bd1e995;
00320   const int r = 24;
00321 
00322   unsigned int h = seed ^ len;
00323 
00324   const unsigned char *data = (const unsigned char *)key;
00325 
00326   while (len >= 4) {
00327     unsigned int k;
00328 
00329     k  = (unsigned int)data[0];
00330     k |= (unsigned int)data[1] << 8;
00331     k |= (unsigned int)data[2] << 16;
00332     k |= (unsigned int)data[3] << 24;
00333 
00334     k *= m;
00335     k ^= k >> r;
00336     k *= m;
00337 
00338     h *= m;
00339     h ^= k;
00340 
00341     data += 4;
00342     len -= 4;
00343   }
00344 
00345   switch (len) {
00346     case 3:
00347       h ^= data[2] << 16;
00348     case 2:
00349       h ^= data[1] << 8;
00350     case 1:
00351       h ^= data[0];
00352       h *= m;
00353   };
00354 
00355   h ^= h >> 13;
00356   h *= m;
00357   h ^= h >> 15;
00358 
00359   return h;
00360 }
00361 
00362 
00363 #include "args.h"
00364 static const arg_def_t debugmode = ARG_DEF("D", "debug", 0,
00365                                            "Debug mode (makes output deterministic)");
00366 static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
00367                                             "Output filename");
00368 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
00369                                           "Input file is YV12 ");
00370 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
00371                                           "Input file is I420 (default)");
00372 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
00373                                           "Codec to use");
00374 static const arg_def_t passes           = ARG_DEF("p", "passes", 1,
00375                                                   "Number of passes (1/2)");
00376 static const arg_def_t pass_arg         = ARG_DEF(NULL, "pass", 1,
00377                                                   "Pass to execute (1/2)");
00378 static const arg_def_t fpf_name         = ARG_DEF(NULL, "fpf", 1,
00379                                                   "First pass statistics file name");
00380 static const arg_def_t limit = ARG_DEF(NULL, "limit", 1,
00381                                        "Stop encoding after n input frames");
00382 static const arg_def_t skip = ARG_DEF(NULL, "skip", 1,
00383                                       "Skip the first n input frames");
00384 static const arg_def_t deadline         = ARG_DEF("d", "deadline", 1,
00385                                                   "Deadline per frame (usec)");
00386 static const arg_def_t best_dl          = ARG_DEF(NULL, "best", 0,
00387                                                   "Use Best Quality Deadline");
00388 static const arg_def_t good_dl          = ARG_DEF(NULL, "good", 0,
00389                                                   "Use Good Quality Deadline");
00390 static const arg_def_t rt_dl            = ARG_DEF(NULL, "rt", 0,
00391                                                   "Use Realtime Quality Deadline");
00392 static const arg_def_t quietarg         = ARG_DEF("q", "quiet", 0,
00393                                                   "Do not print encode progress");
00394 static const arg_def_t verbosearg       = ARG_DEF("v", "verbose", 0,
00395                                                   "Show encoder parameters");
00396 static const arg_def_t psnrarg          = ARG_DEF(NULL, "psnr", 0,
00397                                                   "Show PSNR in status line");
00398 enum TestDecodeFatality {
00399   TEST_DECODE_OFF,
00400   TEST_DECODE_FATAL,
00401   TEST_DECODE_WARN,
00402 };
00403 static const struct arg_enum_list test_decode_enum[] = {
00404   {"off",   TEST_DECODE_OFF},
00405   {"fatal", TEST_DECODE_FATAL},
00406   {"warn",  TEST_DECODE_WARN},
00407   {NULL, 0}
00408 };
00409 static const arg_def_t recontest = ARG_DEF_ENUM(NULL, "test-decode", 1,
00410                                                 "Test encode/decode mismatch",
00411                                                 test_decode_enum);
00412 static const arg_def_t framerate        = ARG_DEF(NULL, "fps", 1,
00413                                                   "Stream frame rate (rate/scale)");
00414 static const arg_def_t use_ivf          = ARG_DEF(NULL, "ivf", 0,
00415                                                   "Output IVF (default is WebM)");
00416 static const arg_def_t out_part = ARG_DEF("P", "output-partitions", 0,
00417                                           "Makes encoder output partitions. Requires IVF output!");
00418 static const arg_def_t q_hist_n         = ARG_DEF(NULL, "q-hist", 1,
00419                                                   "Show quantizer histogram (n-buckets)");
00420 static const arg_def_t rate_hist_n         = ARG_DEF(NULL, "rate-hist", 1,
00421                                                      "Show rate histogram (n-buckets)");
00422 static const arg_def_t *main_args[] = {
00423   &debugmode,
00424   &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &skip,
00425   &deadline, &best_dl, &good_dl, &rt_dl,
00426   &quietarg, &verbosearg, &psnrarg, &use_ivf, &out_part, &q_hist_n, &rate_hist_n,
00427   NULL
00428 };
00429 
00430 static const arg_def_t usage            = ARG_DEF("u", "usage", 1,
00431                                                   "Usage profile number to use");
00432 static const arg_def_t threads          = ARG_DEF("t", "threads", 1,
00433                                                   "Max number of threads to use");
00434 static const arg_def_t profile          = ARG_DEF(NULL, "profile", 1,
00435                                                   "Bitstream profile number to use");
00436 static const arg_def_t width            = ARG_DEF("w", "width", 1,
00437                                                   "Frame width");
00438 static const arg_def_t height           = ARG_DEF("h", "height", 1,
00439                                                   "Frame height");
00440 static const struct arg_enum_list stereo_mode_enum[] = {
00441   {"mono", STEREO_FORMAT_MONO},
00442   {"left-right", STEREO_FORMAT_LEFT_RIGHT},
00443   {"bottom-top", STEREO_FORMAT_BOTTOM_TOP},
00444   {"top-bottom", STEREO_FORMAT_TOP_BOTTOM},
00445   {"right-left", STEREO_FORMAT_RIGHT_LEFT},
00446   {NULL, 0}
00447 };
00448 static const arg_def_t stereo_mode      = ARG_DEF_ENUM(NULL, "stereo-mode", 1,
00449                                                        "Stereo 3D video format", stereo_mode_enum);
00450 static const arg_def_t timebase         = ARG_DEF(NULL, "timebase", 1,
00451                                                   "Output timestamp precision (fractional seconds)");
00452 static const arg_def_t error_resilient  = ARG_DEF(NULL, "error-resilient", 1,
00453                                                   "Enable error resiliency features");
00454 static const arg_def_t lag_in_frames    = ARG_DEF(NULL, "lag-in-frames", 1,
00455                                                   "Max number of frames to lag");
00456 
00457 static const arg_def_t *global_args[] = {
00458   &use_yv12, &use_i420, &usage, &threads, &profile,
00459   &width, &height, &stereo_mode, &timebase, &framerate,
00460   &error_resilient,
00461   &lag_in_frames, NULL
00462 };
00463 
00464 static const arg_def_t dropframe_thresh   = ARG_DEF(NULL, "drop-frame", 1,
00465                                                     "Temporal resampling threshold (buf %)");
00466 static const arg_def_t resize_allowed     = ARG_DEF(NULL, "resize-allowed", 1,
00467                                                     "Spatial resampling enabled (bool)");
00468 static const arg_def_t resize_up_thresh   = ARG_DEF(NULL, "resize-up", 1,
00469                                                     "Upscale threshold (buf %)");
00470 static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1,
00471                                                     "Downscale threshold (buf %)");
00472 static const struct arg_enum_list end_usage_enum[] = {
00473   {"vbr", VPX_VBR},
00474   {"cbr", VPX_CBR},
00475   {"cq",  VPX_CQ},
00476   {"q",   VPX_Q},
00477   {NULL, 0}
00478 };
00479 static const arg_def_t end_usage          = ARG_DEF_ENUM(NULL, "end-usage", 1,
00480                                                          "Rate control mode", end_usage_enum);
00481 static const arg_def_t target_bitrate     = ARG_DEF(NULL, "target-bitrate", 1,
00482                                                     "Bitrate (kbps)");
00483 static const arg_def_t min_quantizer      = ARG_DEF(NULL, "min-q", 1,
00484                                                     "Minimum (best) quantizer");
00485 static const arg_def_t max_quantizer      = ARG_DEF(NULL, "max-q", 1,
00486                                                     "Maximum (worst) quantizer");
00487 static const arg_def_t undershoot_pct     = ARG_DEF(NULL, "undershoot-pct", 1,
00488                                                     "Datarate undershoot (min) target (%)");
00489 static const arg_def_t overshoot_pct      = ARG_DEF(NULL, "overshoot-pct", 1,
00490                                                     "Datarate overshoot (max) target (%)");
00491 static const arg_def_t buf_sz             = ARG_DEF(NULL, "buf-sz", 1,
00492                                                     "Client buffer size (ms)");
00493 static const arg_def_t buf_initial_sz     = ARG_DEF(NULL, "buf-initial-sz", 1,
00494                                                     "Client initial buffer size (ms)");
00495 static const arg_def_t buf_optimal_sz     = ARG_DEF(NULL, "buf-optimal-sz", 1,
00496                                                     "Client optimal buffer size (ms)");
00497 static const arg_def_t *rc_args[] = {
00498   &dropframe_thresh, &resize_allowed, &resize_up_thresh, &resize_down_thresh,
00499   &end_usage, &target_bitrate, &min_quantizer, &max_quantizer,
00500   &undershoot_pct, &overshoot_pct, &buf_sz, &buf_initial_sz, &buf_optimal_sz,
00501   NULL
00502 };
00503 
00504 
00505 static const arg_def_t bias_pct = ARG_DEF(NULL, "bias-pct", 1,
00506                                           "CBR/VBR bias (0=CBR, 100=VBR)");
00507 static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1,
00508                                                 "GOP min bitrate (% of target)");
00509 static const arg_def_t maxsection_pct = ARG_DEF(NULL, "maxsection-pct", 1,
00510                                                 "GOP max bitrate (% of target)");
00511 static const arg_def_t *rc_twopass_args[] = {
00512   &bias_pct, &minsection_pct, &maxsection_pct, NULL
00513 };
00514 
00515 
00516 static const arg_def_t kf_min_dist = ARG_DEF(NULL, "kf-min-dist", 1,
00517                                              "Minimum keyframe interval (frames)");
00518 static const arg_def_t kf_max_dist = ARG_DEF(NULL, "kf-max-dist", 1,
00519                                              "Maximum keyframe interval (frames)");
00520 static const arg_def_t kf_disabled = ARG_DEF(NULL, "disable-kf", 0,
00521                                              "Disable keyframe placement");
00522 static const arg_def_t *kf_args[] = {
00523   &kf_min_dist, &kf_max_dist, &kf_disabled, NULL
00524 };
00525 
00526 
00527 static const arg_def_t noise_sens = ARG_DEF(NULL, "noise-sensitivity", 1,
00528                                             "Noise sensitivity (frames to blur)");
00529 static const arg_def_t sharpness = ARG_DEF(NULL, "sharpness", 1,
00530                                            "Filter sharpness (0-7)");
00531 static const arg_def_t static_thresh = ARG_DEF(NULL, "static-thresh", 1,
00532                                                "Motion detection threshold");
00533 static const arg_def_t cpu_used = ARG_DEF(NULL, "cpu-used", 1,
00534                                           "CPU Used (-16..16)");
00535 static const arg_def_t token_parts = ARG_DEF(NULL, "token-parts", 1,
00536                                      "Number of token partitions to use, log2");
00537 static const arg_def_t tile_cols = ARG_DEF(NULL, "tile-columns", 1,
00538                                          "Number of tile columns to use, log2");
00539 static const arg_def_t tile_rows = ARG_DEF(NULL, "tile-rows", 1,
00540                                            "Number of tile rows to use, log2");
00541 static const arg_def_t auto_altref = ARG_DEF(NULL, "auto-alt-ref", 1,
00542                                              "Enable automatic alt reference frames");
00543 static const arg_def_t arnr_maxframes = ARG_DEF(NULL, "arnr-maxframes", 1,
00544                                                 "AltRef Max Frames");
00545 static const arg_def_t arnr_strength = ARG_DEF(NULL, "arnr-strength", 1,
00546                                                "AltRef Strength");
00547 static const arg_def_t arnr_type = ARG_DEF(NULL, "arnr-type", 1,
00548                                            "AltRef Type");
00549 static const struct arg_enum_list tuning_enum[] = {
00550   {"psnr", VP8_TUNE_PSNR},
00551   {"ssim", VP8_TUNE_SSIM},
00552   {NULL, 0}
00553 };
00554 static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1,
00555                                                 "Material to favor", tuning_enum);
00556 static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1,
00557                                           "Constant/Constrained Quality level");
00558 static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1,
00559                                                     "Max I-frame bitrate (pct)");
00560 static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode");
00561 #if CONFIG_VP9_ENCODER
00562 static const arg_def_t frame_parallel_decoding  = ARG_DEF(
00563     NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
00564 static const arg_def_t aq_mode  = ARG_DEF(
00565     NULL, "aq-mode", 1,
00566     "Adaptive quantization mode (0: disabled (by default), 1: variance based)");
00567 #endif
00568 
00569 #if CONFIG_VP8_ENCODER
00570 static const arg_def_t *vp8_args[] = {
00571   &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh,
00572   &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type,
00573   &tune_ssim, &cq_level, &max_intra_rate_pct,
00574   NULL
00575 };
00576 static const int vp8_arg_ctrl_map[] = {
00577   VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
00578   VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
00579   VP8E_SET_TOKEN_PARTITIONS,
00580   VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
00581   VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
00582   0
00583 };
00584 #endif
00585 
00586 #if CONFIG_VP9_ENCODER
00587 static const arg_def_t *vp9_args[] = {
00588   &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh,
00589   &tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type,
00590   &tune_ssim, &cq_level, &max_intra_rate_pct, &lossless,
00591   &frame_parallel_decoding, &aq_mode,
00592   NULL
00593 };
00594 static const int vp9_arg_ctrl_map[] = {
00595   VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
00596   VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
00597   VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS,
00598   VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
00599   VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
00600   VP9E_SET_LOSSLESS, VP9E_SET_FRAME_PARALLEL_DECODING, VP9E_SET_AQ_MODE,
00601   0
00602 };
00603 #endif
00604 
00605 static const arg_def_t *no_args[] = { NULL };
00606 
00607 void usage_exit() {
00608   int i;
00609 
00610   fprintf(stderr, "Usage: %s <options> -o dst_filename src_filename \n",
00611           exec_name);
00612 
00613   fprintf(stderr, "\nOptions:\n");
00614   arg_show_usage(stderr, main_args);
00615   fprintf(stderr, "\nEncoder Global Options:\n");
00616   arg_show_usage(stderr, global_args);
00617   fprintf(stderr, "\nRate Control Options:\n");
00618   arg_show_usage(stderr, rc_args);
00619   fprintf(stderr, "\nTwopass Rate Control Options:\n");
00620   arg_show_usage(stderr, rc_twopass_args);
00621   fprintf(stderr, "\nKeyframe Placement Options:\n");
00622   arg_show_usage(stderr, kf_args);
00623 #if CONFIG_VP8_ENCODER
00624   fprintf(stderr, "\nVP8 Specific Options:\n");
00625   arg_show_usage(stderr, vp8_args);
00626 #endif
00627 #if CONFIG_VP9_ENCODER
00628   fprintf(stderr, "\nVP9 Specific Options:\n");
00629   arg_show_usage(stderr, vp9_args);
00630 #endif
00631   fprintf(stderr, "\nStream timebase (--timebase):\n"
00632           "  The desired precision of timestamps in the output, expressed\n"
00633           "  in fractional seconds. Default is 1/1000.\n");
00634   fprintf(stderr, "\n"
00635           "Included encoders:\n"
00636           "\n");
00637 
00638   for (i = 0; i < sizeof(codecs) / sizeof(codecs[0]); i++)
00639     fprintf(stderr, "    %-6s - %s\n",
00640             codecs[i].name,
00641             vpx_codec_iface_name(codecs[i].iface()));
00642 
00643   exit(EXIT_FAILURE);
00644 }
00645 
00646 
00647 #define HIST_BAR_MAX 40
00648 struct hist_bucket {
00649   int low, high, count;
00650 };
00651 
00652 
00653 static int merge_hist_buckets(struct hist_bucket *bucket,
00654                               int *buckets_,
00655                               int max_buckets) {
00656   int small_bucket = 0, merge_bucket = INT_MAX, big_bucket = 0;
00657   int buckets = *buckets_;
00658   int i;
00659 
00660   /* Find the extrema for this list of buckets */
00661   big_bucket = small_bucket = 0;
00662   for (i = 0; i < buckets; i++) {
00663     if (bucket[i].count < bucket[small_bucket].count)
00664       small_bucket = i;
00665     if (bucket[i].count > bucket[big_bucket].count)
00666       big_bucket = i;
00667   }
00668 
00669   /* If we have too many buckets, merge the smallest with an adjacent
00670    * bucket.
00671    */
00672   while (buckets > max_buckets) {
00673     int last_bucket = buckets - 1;
00674 
00675     /* merge the small bucket with an adjacent one. */
00676     if (small_bucket == 0)
00677       merge_bucket = 1;
00678     else if (small_bucket == last_bucket)
00679       merge_bucket = last_bucket - 1;
00680     else if (bucket[small_bucket - 1].count < bucket[small_bucket + 1].count)
00681       merge_bucket = small_bucket - 1;
00682     else
00683       merge_bucket = small_bucket + 1;
00684 
00685     assert(abs(merge_bucket - small_bucket) <= 1);
00686     assert(small_bucket < buckets);
00687     assert(big_bucket < buckets);
00688     assert(merge_bucket < buckets);
00689 
00690     if (merge_bucket < small_bucket) {
00691       bucket[merge_bucket].high = bucket[small_bucket].high;
00692       bucket[merge_bucket].count += bucket[small_bucket].count;
00693     } else {
00694       bucket[small_bucket].high = bucket[merge_bucket].high;
00695       bucket[small_bucket].count += bucket[merge_bucket].count;
00696       merge_bucket = small_bucket;
00697     }
00698 
00699     assert(bucket[merge_bucket].low != bucket[merge_bucket].high);
00700 
00701     buckets--;
00702 
00703     /* Remove the merge_bucket from the list, and find the new small
00704      * and big buckets while we're at it
00705      */
00706     big_bucket = small_bucket = 0;
00707     for (i = 0; i < buckets; i++) {
00708       if (i > merge_bucket)
00709         bucket[i] = bucket[i + 1];
00710 
00711       if (bucket[i].count < bucket[small_bucket].count)
00712         small_bucket = i;
00713       if (bucket[i].count > bucket[big_bucket].count)
00714         big_bucket = i;
00715     }
00716 
00717   }
00718 
00719   *buckets_ = buckets;
00720   return bucket[big_bucket].count;
00721 }
00722 
00723 
00724 static void show_histogram(const struct hist_bucket *bucket,
00725                            int                       buckets,
00726                            int                       total,
00727                            int                       scale) {
00728   const char *pat1, *pat2;
00729   int i;
00730 
00731   switch ((int)(log(bucket[buckets - 1].high) / log(10)) + 1) {
00732     case 1:
00733     case 2:
00734       pat1 = "%4d %2s: ";
00735       pat2 = "%4d-%2d: ";
00736       break;
00737     case 3:
00738       pat1 = "%5d %3s: ";
00739       pat2 = "%5d-%3d: ";
00740       break;
00741     case 4:
00742       pat1 = "%6d %4s: ";
00743       pat2 = "%6d-%4d: ";
00744       break;
00745     case 5:
00746       pat1 = "%7d %5s: ";
00747       pat2 = "%7d-%5d: ";
00748       break;
00749     case 6:
00750       pat1 = "%8d %6s: ";
00751       pat2 = "%8d-%6d: ";
00752       break;
00753     case 7:
00754       pat1 = "%9d %7s: ";
00755       pat2 = "%9d-%7d: ";
00756       break;
00757     default:
00758       pat1 = "%12d %10s: ";
00759       pat2 = "%12d-%10d: ";
00760       break;
00761   }
00762 
00763   for (i = 0; i < buckets; i++) {
00764     int len;
00765     int j;
00766     float pct;
00767 
00768     pct = (float)(100.0 * bucket[i].count / total);
00769     len = HIST_BAR_MAX * bucket[i].count / scale;
00770     if (len < 1)
00771       len = 1;
00772     assert(len <= HIST_BAR_MAX);
00773 
00774     if (bucket[i].low == bucket[i].high)
00775       fprintf(stderr, pat1, bucket[i].low, "");
00776     else
00777       fprintf(stderr, pat2, bucket[i].low, bucket[i].high);
00778 
00779     for (j = 0; j < HIST_BAR_MAX; j++)
00780       fprintf(stderr, j < len ? "=" : " ");
00781     fprintf(stderr, "\t%5d (%6.2f%%)\n", bucket[i].count, pct);
00782   }
00783 }
00784 
00785 
00786 static void show_q_histogram(const int counts[64], int max_buckets) {
00787   struct hist_bucket bucket[64];
00788   int buckets = 0;
00789   int total = 0;
00790   int scale;
00791   int i;
00792 
00793 
00794   for (i = 0; i < 64; i++) {
00795     if (counts[i]) {
00796       bucket[buckets].low = bucket[buckets].high = i;
00797       bucket[buckets].count = counts[i];
00798       buckets++;
00799       total += counts[i];
00800     }
00801   }
00802 
00803   fprintf(stderr, "\nQuantizer Selection:\n");
00804   scale = merge_hist_buckets(bucket, &buckets, max_buckets);
00805   show_histogram(bucket, buckets, total, scale);
00806 }
00807 
00808 
00809 #define RATE_BINS (100)
00810 struct rate_hist {
00811   int64_t            *pts;
00812   int                *sz;
00813   int                 samples;
00814   int                 frames;
00815   struct hist_bucket  bucket[RATE_BINS];
00816   int                 total;
00817 };
00818 
00819 
00820 static void init_rate_histogram(struct rate_hist          *hist,
00821                                 const vpx_codec_enc_cfg_t *cfg,
00822                                 const vpx_rational_t      *fps) {
00823   int i;
00824 
00825   /* Determine the number of samples in the buffer. Use the file's framerate
00826    * to determine the number of frames in rc_buf_sz milliseconds, with an
00827    * adjustment (5/4) to account for alt-refs
00828    */
00829   hist->samples = cfg->rc_buf_sz * 5 / 4 * fps->num / fps->den / 1000;
00830 
00831   /* prevent division by zero */
00832   if (hist->samples == 0)
00833     hist->samples = 1;
00834 
00835   hist->pts = calloc(hist->samples, sizeof(*hist->pts));
00836   hist->sz = calloc(hist->samples, sizeof(*hist->sz));
00837   for (i = 0; i < RATE_BINS; i++) {
00838     hist->bucket[i].low = INT_MAX;
00839     hist->bucket[i].high = 0;
00840     hist->bucket[i].count = 0;
00841   }
00842 }
00843 
00844 
00845 static void destroy_rate_histogram(struct rate_hist *hist) {
00846   free(hist->pts);
00847   free(hist->sz);
00848 }
00849 
00850 
00851 static void update_rate_histogram(struct rate_hist          *hist,
00852                                   const vpx_codec_enc_cfg_t *cfg,
00853                                   const vpx_codec_cx_pkt_t  *pkt) {
00854   int i, idx;
00855   int64_t now, then, sum_sz = 0, avg_bitrate;
00856 
00857   now = pkt->data.frame.pts * 1000
00858         * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den;
00859 
00860   idx = hist->frames++ % hist->samples;
00861   hist->pts[idx] = now;
00862   hist->sz[idx] = (int)pkt->data.frame.sz;
00863 
00864   if (now < cfg->rc_buf_initial_sz)
00865     return;
00866 
00867   then = now;
00868 
00869   /* Sum the size over the past rc_buf_sz ms */
00870   for (i = hist->frames; i > 0 && hist->frames - i < hist->samples; i--) {
00871     int i_idx = (i - 1) % hist->samples;
00872 
00873     then = hist->pts[i_idx];
00874     if (now - then > cfg->rc_buf_sz)
00875       break;
00876     sum_sz += hist->sz[i_idx];
00877   }
00878 
00879   if (now == then)
00880     return;
00881 
00882   avg_bitrate = sum_sz * 8 * 1000 / (now - then);
00883   idx = (int)(avg_bitrate * (RATE_BINS / 2) / (cfg->rc_target_bitrate * 1000));
00884   if (idx < 0)
00885     idx = 0;
00886   if (idx > RATE_BINS - 1)
00887     idx = RATE_BINS - 1;
00888   if (hist->bucket[idx].low > avg_bitrate)
00889     hist->bucket[idx].low = (int)avg_bitrate;
00890   if (hist->bucket[idx].high < avg_bitrate)
00891     hist->bucket[idx].high = (int)avg_bitrate;
00892   hist->bucket[idx].count++;
00893   hist->total++;
00894 }
00895 
00896 
00897 static void show_rate_histogram(struct rate_hist          *hist,
00898                                 const vpx_codec_enc_cfg_t *cfg,
00899                                 int                        max_buckets) {
00900   int i, scale;
00901   int buckets = 0;
00902 
00903   for (i = 0; i < RATE_BINS; i++) {
00904     if (hist->bucket[i].low == INT_MAX)
00905       continue;
00906     hist->bucket[buckets++] = hist->bucket[i];
00907   }
00908 
00909   fprintf(stderr, "\nRate (over %dms window):\n", cfg->rc_buf_sz);
00910   scale = merge_hist_buckets(hist->bucket, &buckets, max_buckets);
00911   show_histogram(hist->bucket, buckets, hist->total, scale);
00912 }
00913 
00914 #define mmin(a, b)  ((a) < (b) ? (a) : (b))
00915 static void find_mismatch(vpx_image_t *img1, vpx_image_t *img2,
00916                           int yloc[4], int uloc[4], int vloc[4]) {
00917   const unsigned int bsize = 64;
00918   const unsigned int bsizey = bsize >> img1->y_chroma_shift;
00919   const unsigned int bsizex = bsize >> img1->x_chroma_shift;
00920   const int c_w = (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
00921   const int c_h = (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
00922   unsigned int match = 1;
00923   unsigned int i, j;
00924   yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1;
00925   for (i = 0, match = 1; match && i < img1->d_h; i += bsize) {
00926     for (j = 0; match && j < img1->d_w; j += bsize) {
00927       int k, l;
00928       int si = mmin(i + bsize, img1->d_h) - i;
00929       int sj = mmin(j + bsize, img1->d_w) - j;
00930       for (k = 0; match && k < si; k++)
00931         for (l = 0; match && l < sj; l++) {
00932           if (*(img1->planes[VPX_PLANE_Y] +
00933                 (i + k) * img1->stride[VPX_PLANE_Y] + j + l) !=
00934               *(img2->planes[VPX_PLANE_Y] +
00935                 (i + k) * img2->stride[VPX_PLANE_Y] + j + l)) {
00936             yloc[0] = i + k;
00937             yloc[1] = j + l;
00938             yloc[2] = *(img1->planes[VPX_PLANE_Y] +
00939                         (i + k) * img1->stride[VPX_PLANE_Y] + j + l);
00940             yloc[3] = *(img2->planes[VPX_PLANE_Y] +
00941                         (i + k) * img2->stride[VPX_PLANE_Y] + j + l);
00942             match = 0;
00943             break;
00944           }
00945         }
00946     }
00947   }
00948 
00949   uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1;
00950   for (i = 0, match = 1; match && i < c_h; i += bsizey) {
00951     for (j = 0; match && j < c_w; j += bsizex) {
00952       int k, l;
00953       int si = mmin(i + bsizey, c_h - i);
00954       int sj = mmin(j + bsizex, c_w - j);
00955       for (k = 0; match && k < si; k++)
00956         for (l = 0; match && l < sj; l++) {
00957           if (*(img1->planes[VPX_PLANE_U] +
00958                 (i + k) * img1->stride[VPX_PLANE_U] + j + l) !=
00959               *(img2->planes[VPX_PLANE_U] +
00960                 (i + k) * img2->stride[VPX_PLANE_U] + j + l)) {
00961             uloc[0] = i + k;
00962             uloc[1] = j + l;
00963             uloc[2] = *(img1->planes[VPX_PLANE_U] +
00964                         (i + k) * img1->stride[VPX_PLANE_U] + j + l);
00965             uloc[3] = *(img2->planes[VPX_PLANE_U] +
00966                         (i + k) * img2->stride[VPX_PLANE_V] + j + l);
00967             match = 0;
00968             break;
00969           }
00970         }
00971     }
00972   }
00973   vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1;
00974   for (i = 0, match = 1; match && i < c_h; i += bsizey) {
00975     for (j = 0; match && j < c_w; j += bsizex) {
00976       int k, l;
00977       int si = mmin(i + bsizey, c_h - i);
00978       int sj = mmin(j + bsizex, c_w - j);
00979       for (k = 0; match && k < si; k++)
00980         for (l = 0; match && l < sj; l++) {
00981           if (*(img1->planes[VPX_PLANE_V] +
00982                 (i + k) * img1->stride[VPX_PLANE_V] + j + l) !=
00983               *(img2->planes[VPX_PLANE_V] +
00984                 (i + k) * img2->stride[VPX_PLANE_V] + j + l)) {
00985             vloc[0] = i + k;
00986             vloc[1] = j + l;
00987             vloc[2] = *(img1->planes[VPX_PLANE_V] +
00988                         (i + k) * img1->stride[VPX_PLANE_V] + j + l);
00989             vloc[3] = *(img2->planes[VPX_PLANE_V] +
00990                         (i + k) * img2->stride[VPX_PLANE_V] + j + l);
00991             match = 0;
00992             break;
00993           }
00994         }
00995     }
00996   }
00997 }
00998 
00999 static int compare_img(vpx_image_t *img1, vpx_image_t *img2)
01000 {
01001   const int c_w = (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
01002   const int c_h = (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
01003   int match = 1;
01004   unsigned int i;
01005 
01006   match &= (img1->fmt == img2->fmt);
01007   match &= (img1->w == img2->w);
01008   match &= (img1->h == img2->h);
01009 
01010   for (i = 0; i < img1->d_h; i++)
01011     match &= (memcmp(img1->planes[VPX_PLANE_Y]+i*img1->stride[VPX_PLANE_Y],
01012                      img2->planes[VPX_PLANE_Y]+i*img2->stride[VPX_PLANE_Y],
01013                      img1->d_w) == 0);
01014 
01015   for (i = 0; i < c_h; i++)
01016     match &= (memcmp(img1->planes[VPX_PLANE_U]+i*img1->stride[VPX_PLANE_U],
01017                      img2->planes[VPX_PLANE_U]+i*img2->stride[VPX_PLANE_U],
01018                      c_w) == 0);
01019 
01020   for (i = 0; i < c_h; i++)
01021     match &= (memcmp(img1->planes[VPX_PLANE_V]+i*img1->stride[VPX_PLANE_U],
01022                      img2->planes[VPX_PLANE_V]+i*img2->stride[VPX_PLANE_U],
01023                      c_w) == 0);
01024 
01025   return match;
01026 }
01027 
01028 
01029 #define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
01030 #define MAX(x,y) ((x)>(y)?(x):(y))
01031 #if CONFIG_VP8_ENCODER && !CONFIG_VP9_ENCODER
01032 #define ARG_CTRL_CNT_MAX NELEMENTS(vp8_arg_ctrl_map)
01033 #elif !CONFIG_VP8_ENCODER && CONFIG_VP9_ENCODER
01034 #define ARG_CTRL_CNT_MAX NELEMENTS(vp9_arg_ctrl_map)
01035 #else
01036 #define ARG_CTRL_CNT_MAX MAX(NELEMENTS(vp8_arg_ctrl_map), \
01037                              NELEMENTS(vp9_arg_ctrl_map))
01038 #endif
01039 
01040 /* Configuration elements common to all streams */
01041 struct global_config {
01042   const struct codec_item  *codec;
01043   int                       passes;
01044   int                       pass;
01045   int                       usage;
01046   int                       deadline;
01047   int                       use_i420;
01048   int                       quiet;
01049   int                       verbose;
01050   int                       limit;
01051   int                       skip_frames;
01052   int                       show_psnr;
01053   enum TestDecodeFatality   test_decode;
01054   int                       have_framerate;
01055   struct vpx_rational       framerate;
01056   int                       out_part;
01057   int                       debug;
01058   int                       show_q_hist_buckets;
01059   int                       show_rate_hist_buckets;
01060 };
01061 
01062 
01063 /* Per-stream configuration */
01064 struct stream_config {
01065   struct vpx_codec_enc_cfg  cfg;
01066   const char               *out_fn;
01067   const char               *stats_fn;
01068   stereo_format_t           stereo_fmt;
01069   int                       arg_ctrls[ARG_CTRL_CNT_MAX][2];
01070   int                       arg_ctrl_cnt;
01071   int                       write_webm;
01072   int                       have_kf_max_dist;
01073 };
01074 
01075 
01076 struct stream_state {
01077   int                       index;
01078   struct stream_state      *next;
01079   struct stream_config      config;
01080   FILE                     *file;
01081   struct rate_hist          rate_hist;
01082   struct EbmlGlobal         ebml;
01083   uint32_t                  hash;
01084   uint64_t                  psnr_sse_total;
01085   uint64_t                  psnr_samples_total;
01086   double                    psnr_totals[4];
01087   int                       psnr_count;
01088   int                       counts[64];
01089   vpx_codec_ctx_t           encoder;
01090   unsigned int              frames_out;
01091   uint64_t                  cx_time;
01092   size_t                    nbytes;
01093   stats_io_t                stats;
01094   struct vpx_image         *img;
01095   vpx_codec_ctx_t           decoder;
01096   int                       mismatch_seen;
01097 };
01098 
01099 
01100 void validate_positive_rational(const char          *msg,
01101                                 struct vpx_rational *rat) {
01102   if (rat->den < 0) {
01103     rat->num *= -1;
01104     rat->den *= -1;
01105   }
01106 
01107   if (rat->num < 0)
01108     die("Error: %s must be positive\n", msg);
01109 
01110   if (!rat->den)
01111     die("Error: %s has zero denominator\n", msg);
01112 }
01113 
01114 
01115 static void parse_global_config(struct global_config *global, char **argv) {
01116   char       **argi, **argj;
01117   struct arg   arg;
01118 
01119   /* Initialize default parameters */
01120   memset(global, 0, sizeof(*global));
01121   global->codec = codecs;
01122   global->passes = 0;
01123   global->use_i420 = 1;
01124   /* Assign default deadline to good quality */
01125   global->deadline = VPX_DL_GOOD_QUALITY;
01126 
01127   for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
01128     arg.argv_step = 1;
01129 
01130     if (arg_match(&arg, &codecarg, argi)) {
01131       int j, k = -1;
01132 
01133       for (j = 0; j < sizeof(codecs) / sizeof(codecs[0]); j++)
01134         if (!strcmp(codecs[j].name, arg.val))
01135           k = j;
01136 
01137       if (k >= 0)
01138         global->codec = codecs + k;
01139       else
01140         die("Error: Unrecognized argument (%s) to --codec\n",
01141             arg.val);
01142 
01143     } else if (arg_match(&arg, &passes, argi)) {
01144       global->passes = arg_parse_uint(&arg);
01145 
01146       if (global->passes < 1 || global->passes > 2)
01147         die("Error: Invalid number of passes (%d)\n", global->passes);
01148     } else if (arg_match(&arg, &pass_arg, argi)) {
01149       global->pass = arg_parse_uint(&arg);
01150 
01151       if (global->pass < 1 || global->pass > 2)
01152         die("Error: Invalid pass selected (%d)\n",
01153             global->pass);
01154     } else if (arg_match(&arg, &usage, argi))
01155       global->usage = arg_parse_uint(&arg);
01156     else if (arg_match(&arg, &deadline, argi))
01157       global->deadline = arg_parse_uint(&arg);
01158     else if (arg_match(&arg, &best_dl, argi))
01159       global->deadline = VPX_DL_BEST_QUALITY;
01160     else if (arg_match(&arg, &good_dl, argi))
01161       global->deadline = VPX_DL_GOOD_QUALITY;
01162     else if (arg_match(&arg, &rt_dl, argi))
01163       global->deadline = VPX_DL_REALTIME;
01164     else if (arg_match(&arg, &use_yv12, argi))
01165       global->use_i420 = 0;
01166     else if (arg_match(&arg, &use_i420, argi))
01167       global->use_i420 = 1;
01168     else if (arg_match(&arg, &quietarg, argi))
01169       global->quiet = 1;
01170     else if (arg_match(&arg, &verbosearg, argi))
01171       global->verbose = 1;
01172     else if (arg_match(&arg, &limit, argi))
01173       global->limit = arg_parse_uint(&arg);
01174     else if (arg_match(&arg, &skip, argi))
01175       global->skip_frames = arg_parse_uint(&arg);
01176     else if (arg_match(&arg, &psnrarg, argi))
01177       global->show_psnr = 1;
01178     else if (arg_match(&arg, &recontest, argi))
01179       global->test_decode = arg_parse_enum_or_int(&arg);
01180     else if (arg_match(&arg, &framerate, argi)) {
01181       global->framerate = arg_parse_rational(&arg);
01182       validate_positive_rational(arg.name, &global->framerate);
01183       global->have_framerate = 1;
01184     } else if (arg_match(&arg, &out_part, argi))
01185       global->out_part = 1;
01186     else if (arg_match(&arg, &debugmode, argi))
01187       global->debug = 1;
01188     else if (arg_match(&arg, &q_hist_n, argi))
01189       global->show_q_hist_buckets = arg_parse_uint(&arg);
01190     else if (arg_match(&arg, &rate_hist_n, argi))
01191       global->show_rate_hist_buckets = arg_parse_uint(&arg);
01192     else
01193       argj++;
01194   }
01195 
01196   /* Validate global config */
01197   if (global->passes == 0) {
01198 #if CONFIG_VP9_ENCODER
01199     // Make default VP9 passes = 2 until there is a better quality 1-pass
01200     // encoder
01201     global->passes = (global->codec->iface == vpx_codec_vp9_cx ? 2 : 1);
01202 #else
01203     global->passes = 1;
01204 #endif
01205   }
01206 
01207   if (global->pass) {
01208     /* DWIM: Assume the user meant passes=2 if pass=2 is specified */
01209     if (global->pass > global->passes) {
01210       warn("Assuming --pass=%d implies --passes=%d\n",
01211            global->pass, global->pass);
01212       global->passes = global->pass;
01213     }
01214   }
01215 }
01216 
01217 
01218 void open_input_file(struct input_state *input) {
01219   unsigned int fourcc;
01220 
01221   /* Parse certain options from the input file, if possible */
01222   input->file = strcmp(input->fn, "-") ? fopen(input->fn, "rb")
01223                 : set_binary_mode(stdin);
01224 
01225   if (!input->file)
01226     fatal("Failed to open input file");
01227 
01228   if (!fseeko(input->file, 0, SEEK_END)) {
01229     /* Input file is seekable. Figure out how long it is, so we can get
01230      * progress info.
01231      */
01232     input->length = ftello(input->file);
01233     rewind(input->file);
01234   }
01235 
01236   /* For RAW input sources, these bytes will applied on the first frame
01237    *  in read_frame().
01238    */
01239   input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file);
01240   input->detect.position = 0;
01241 
01242   if (input->detect.buf_read == 4
01243       && file_is_y4m(input->file, &input->y4m, input->detect.buf)) {
01244     if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4,
01245                        input->only_i420) >= 0) {
01246       input->file_type = FILE_TYPE_Y4M;
01247       input->w = input->y4m.pic_w;
01248       input->h = input->y4m.pic_h;
01249       input->framerate.num = input->y4m.fps_n;
01250       input->framerate.den = input->y4m.fps_d;
01251       input->use_i420 = 0;
01252     } else
01253       fatal("Unsupported Y4M stream.");
01254   } else if (input->detect.buf_read == 4 && file_is_ivf(input, &fourcc)) {
01255     fatal("IVF is not supported as input.");
01256   } else {
01257     input->file_type = FILE_TYPE_RAW;
01258   }
01259 }
01260 
01261 
01262 static void close_input_file(struct input_state *input) {
01263   fclose(input->file);
01264   if (input->file_type == FILE_TYPE_Y4M)
01265     y4m_input_close(&input->y4m);
01266 }
01267 
01268 static struct stream_state *new_stream(struct global_config *global,
01269                                        struct stream_state *prev) {
01270   struct stream_state *stream;
01271 
01272   stream = calloc(1, sizeof(*stream));
01273   if (!stream)
01274     fatal("Failed to allocate new stream.");
01275   if (prev) {
01276     memcpy(stream, prev, sizeof(*stream));
01277     stream->index++;
01278     prev->next = stream;
01279   } else {
01280     vpx_codec_err_t  res;
01281 
01282     /* Populate encoder configuration */
01283     res = vpx_codec_enc_config_default(global->codec->iface(),
01284                                        &stream->config.cfg,
01285                                        global->usage);
01286     if (res)
01287       fatal("Failed to get config: %s\n", vpx_codec_err_to_string(res));
01288 
01289     /* Change the default timebase to a high enough value so that the
01290      * encoder will always create strictly increasing timestamps.
01291      */
01292     stream->config.cfg.g_timebase.den = 1000;
01293 
01294     /* Never use the library's default resolution, require it be parsed
01295      * from the file or set on the command line.
01296      */
01297     stream->config.cfg.g_w = 0;
01298     stream->config.cfg.g_h = 0;
01299 
01300     /* Initialize remaining stream parameters */
01301     stream->config.stereo_fmt = STEREO_FORMAT_MONO;
01302     stream->config.write_webm = 1;
01303     stream->ebml.last_pts_ms = -1;
01304 
01305     /* Allows removal of the application version from the EBML tags */
01306     stream->ebml.debug = global->debug;
01307   }
01308 
01309   /* Output files must be specified for each stream */
01310   stream->config.out_fn = NULL;
01311 
01312   stream->next = NULL;
01313   return stream;
01314 }
01315 
01316 
01317 static int parse_stream_params(struct global_config *global,
01318                                struct stream_state  *stream,
01319                                char **argv) {
01320   char                   **argi, **argj;
01321   struct arg               arg;
01322   static const arg_def_t **ctrl_args = no_args;
01323   static const int        *ctrl_args_map = NULL;
01324   struct stream_config    *config = &stream->config;
01325   int                      eos_mark_found = 0;
01326 
01327   /* Handle codec specific options */
01328   if (0) {
01329 #if CONFIG_VP8_ENCODER
01330   } else if (global->codec->iface == vpx_codec_vp8_cx) {
01331     ctrl_args = vp8_args;
01332     ctrl_args_map = vp8_arg_ctrl_map;
01333 #endif
01334 #if CONFIG_VP9_ENCODER
01335   } else if (global->codec->iface == vpx_codec_vp9_cx) {
01336     ctrl_args = vp9_args;
01337     ctrl_args_map = vp9_arg_ctrl_map;
01338 #endif
01339   }
01340 
01341   for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
01342     arg.argv_step = 1;
01343 
01344     /* Once we've found an end-of-stream marker (--) we want to continue
01345      * shifting arguments but not consuming them.
01346      */
01347     if (eos_mark_found) {
01348       argj++;
01349       continue;
01350     } else if (!strcmp(*argj, "--")) {
01351       eos_mark_found = 1;
01352       continue;
01353     }
01354 
01355     if (0);
01356     else if (arg_match(&arg, &outputfile, argi))
01357       config->out_fn = arg.val;
01358     else if (arg_match(&arg, &fpf_name, argi))
01359       config->stats_fn = arg.val;
01360     else if (arg_match(&arg, &use_ivf, argi))
01361       config->write_webm = 0;
01362     else if (arg_match(&arg, &threads, argi))
01363       config->cfg.g_threads = arg_parse_uint(&arg);
01364     else if (arg_match(&arg, &profile, argi))
01365       config->cfg.g_profile = arg_parse_uint(&arg);
01366     else if (arg_match(&arg, &width, argi))
01367       config->cfg.g_w = arg_parse_uint(&arg);
01368     else if (arg_match(&arg, &height, argi))
01369       config->cfg.g_h = arg_parse_uint(&arg);
01370     else if (arg_match(&arg, &stereo_mode, argi))
01371       config->stereo_fmt = arg_parse_enum_or_int(&arg);
01372     else if (arg_match(&arg, &timebase, argi)) {
01373       config->cfg.g_timebase = arg_parse_rational(&arg);
01374       validate_positive_rational(arg.name, &config->cfg.g_timebase);
01375     } else if (arg_match(&arg, &error_resilient, argi))
01376       config->cfg.g_error_resilient = arg_parse_uint(&arg);
01377     else if (arg_match(&arg, &lag_in_frames, argi))
01378       config->cfg.g_lag_in_frames = arg_parse_uint(&arg);
01379     else if (arg_match(&arg, &dropframe_thresh, argi))
01380       config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg);
01381     else if (arg_match(&arg, &resize_allowed, argi))
01382       config->cfg.rc_resize_allowed = arg_parse_uint(&arg);
01383     else if (arg_match(&arg, &resize_up_thresh, argi))
01384       config->cfg.rc_resize_up_thresh = arg_parse_uint(&arg);
01385     else if (arg_match(&arg, &resize_down_thresh, argi))
01386       config->cfg.rc_resize_down_thresh = arg_parse_uint(&arg);
01387     else if (arg_match(&arg, &end_usage, argi))
01388       config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg);
01389     else if (arg_match(&arg, &target_bitrate, argi))
01390       config->cfg.rc_target_bitrate = arg_parse_uint(&arg);
01391     else if (arg_match(&arg, &min_quantizer, argi))
01392       config->cfg.rc_min_quantizer = arg_parse_uint(&arg);
01393     else if (arg_match(&arg, &max_quantizer, argi))
01394       config->cfg.rc_max_quantizer = arg_parse_uint(&arg);
01395     else if (arg_match(&arg, &undershoot_pct, argi))
01396       config->cfg.rc_undershoot_pct = arg_parse_uint(&arg);
01397     else if (arg_match(&arg, &overshoot_pct, argi))
01398       config->cfg.rc_overshoot_pct = arg_parse_uint(&arg);
01399     else if (arg_match(&arg, &buf_sz, argi))
01400       config->cfg.rc_buf_sz = arg_parse_uint(&arg);
01401     else if (arg_match(&arg, &buf_initial_sz, argi))
01402       config->cfg.rc_buf_initial_sz = arg_parse_uint(&arg);
01403     else if (arg_match(&arg, &buf_optimal_sz, argi))
01404       config->cfg.rc_buf_optimal_sz = arg_parse_uint(&arg);
01405     else if (arg_match(&arg, &bias_pct, argi)) {
01406       config->cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg);
01407 
01408       if (global->passes < 2)
01409         warn("option %s ignored in one-pass mode.\n", arg.name);
01410     } else if (arg_match(&arg, &minsection_pct, argi)) {
01411       config->cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg);
01412 
01413       if (global->passes < 2)
01414         warn("option %s ignored in one-pass mode.\n", arg.name);
01415     } else if (arg_match(&arg, &maxsection_pct, argi)) {
01416       config->cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg);
01417 
01418       if (global->passes < 2)
01419         warn("option %s ignored in one-pass mode.\n", arg.name);
01420     } else if (arg_match(&arg, &kf_min_dist, argi))
01421       config->cfg.kf_min_dist = arg_parse_uint(&arg);
01422     else if (arg_match(&arg, &kf_max_dist, argi)) {
01423       config->cfg.kf_max_dist = arg_parse_uint(&arg);
01424       config->have_kf_max_dist = 1;
01425     } else if (arg_match(&arg, &kf_disabled, argi))
01426       config->cfg.kf_mode = VPX_KF_DISABLED;
01427     else {
01428       int i, match = 0;
01429 
01430       for (i = 0; ctrl_args[i]; i++) {
01431         if (arg_match(&arg, ctrl_args[i], argi)) {
01432           int j;
01433           match = 1;
01434 
01435           /* Point either to the next free element or the first
01436           * instance of this control.
01437           */
01438           for (j = 0; j < config->arg_ctrl_cnt; j++)
01439             if (config->arg_ctrls[j][0] == ctrl_args_map[i])
01440               break;
01441 
01442           /* Update/insert */
01443           assert(j < ARG_CTRL_CNT_MAX);
01444           if (j < ARG_CTRL_CNT_MAX) {
01445             config->arg_ctrls[j][0] = ctrl_args_map[i];
01446             config->arg_ctrls[j][1] = arg_parse_enum_or_int(&arg);
01447             if (j == config->arg_ctrl_cnt)
01448               config->arg_ctrl_cnt++;
01449           }
01450 
01451         }
01452       }
01453 
01454       if (!match)
01455         argj++;
01456     }
01457   }
01458 
01459   return eos_mark_found;
01460 }
01461 
01462 
01463 #define FOREACH_STREAM(func)\
01464   do\
01465   {\
01466     struct stream_state  *stream;\
01467     \
01468     for(stream = streams; stream; stream = stream->next)\
01469       func;\
01470   }while(0)
01471 
01472 
01473 static void validate_stream_config(struct stream_state *stream) {
01474   struct stream_state *streami;
01475 
01476   if (!stream->config.cfg.g_w || !stream->config.cfg.g_h)
01477     fatal("Stream %d: Specify stream dimensions with --width (-w) "
01478           " and --height (-h)", stream->index);
01479 
01480   for (streami = stream; streami; streami = streami->next) {
01481     /* All streams require output files */
01482     if (!streami->config.out_fn)
01483       fatal("Stream %d: Output file is required (specify with -o)",
01484             streami->index);
01485 
01486     /* Check for two streams outputting to the same file */
01487     if (streami != stream) {
01488       const char *a = stream->config.out_fn;
01489       const char *b = streami->config.out_fn;
01490       if (!strcmp(a, b) && strcmp(a, "/dev/null") && strcmp(a, ":nul"))
01491         fatal("Stream %d: duplicate output file (from stream %d)",
01492               streami->index, stream->index);
01493     }
01494 
01495     /* Check for two streams sharing a stats file. */
01496     if (streami != stream) {
01497       const char *a = stream->config.stats_fn;
01498       const char *b = streami->config.stats_fn;
01499       if (a && b && !strcmp(a, b))
01500         fatal("Stream %d: duplicate stats file (from stream %d)",
01501               streami->index, stream->index);
01502     }
01503   }
01504 }
01505 
01506 
01507 static void set_stream_dimensions(struct stream_state *stream,
01508                                   unsigned int w,
01509                                   unsigned int h) {
01510   if (!stream->config.cfg.g_w) {
01511     if (!stream->config.cfg.g_h)
01512       stream->config.cfg.g_w = w;
01513     else
01514       stream->config.cfg.g_w = w * stream->config.cfg.g_h / h;
01515   }
01516   if (!stream->config.cfg.g_h) {
01517     stream->config.cfg.g_h = h * stream->config.cfg.g_w / w;
01518   }
01519 }
01520 
01521 
01522 static void set_default_kf_interval(struct stream_state  *stream,
01523                                     struct global_config *global) {
01524   /* Use a max keyframe interval of 5 seconds, if none was
01525    * specified on the command line.
01526    */
01527   if (!stream->config.have_kf_max_dist) {
01528     double framerate = (double)global->framerate.num / global->framerate.den;
01529     if (framerate > 0.0)
01530       stream->config.cfg.kf_max_dist = (unsigned int)(5.0 * framerate);
01531   }
01532 }
01533 
01534 
01535 static void show_stream_config(struct stream_state  *stream,
01536                                struct global_config *global,
01537                                struct input_state   *input) {
01538 
01539 #define SHOW(field) \
01540   fprintf(stderr, "    %-28s = %d\n", #field, stream->config.cfg.field)
01541 
01542   if (stream->index == 0) {
01543     fprintf(stderr, "Codec: %s\n",
01544             vpx_codec_iface_name(global->codec->iface()));
01545     fprintf(stderr, "Source file: %s Format: %s\n", input->fn,
01546             input->use_i420 ? "I420" : "YV12");
01547   }
01548   if (stream->next || stream->index)
01549     fprintf(stderr, "\nStream Index: %d\n", stream->index);
01550   fprintf(stderr, "Destination file: %s\n", stream->config.out_fn);
01551   fprintf(stderr, "Encoder parameters:\n");
01552 
01553   SHOW(g_usage);
01554   SHOW(g_threads);
01555   SHOW(g_profile);
01556   SHOW(g_w);
01557   SHOW(g_h);
01558   SHOW(g_timebase.num);
01559   SHOW(g_timebase.den);
01560   SHOW(g_error_resilient);
01561   SHOW(g_pass);
01562   SHOW(g_lag_in_frames);
01563   SHOW(rc_dropframe_thresh);
01564   SHOW(rc_resize_allowed);
01565   SHOW(rc_resize_up_thresh);
01566   SHOW(rc_resize_down_thresh);
01567   SHOW(rc_end_usage);
01568   SHOW(rc_target_bitrate);
01569   SHOW(rc_min_quantizer);
01570   SHOW(rc_max_quantizer);
01571   SHOW(rc_undershoot_pct);
01572   SHOW(rc_overshoot_pct);
01573   SHOW(rc_buf_sz);
01574   SHOW(rc_buf_initial_sz);
01575   SHOW(rc_buf_optimal_sz);
01576   SHOW(rc_2pass_vbr_bias_pct);
01577   SHOW(rc_2pass_vbr_minsection_pct);
01578   SHOW(rc_2pass_vbr_maxsection_pct);
01579   SHOW(kf_mode);
01580   SHOW(kf_min_dist);
01581   SHOW(kf_max_dist);
01582 }
01583 
01584 
01585 static void open_output_file(struct stream_state *stream,
01586                              struct global_config *global) {
01587   const char *fn = stream->config.out_fn;
01588 
01589   stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout);
01590 
01591   if (!stream->file)
01592     fatal("Failed to open output file");
01593 
01594   if (stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR))
01595     fatal("WebM output to pipes not supported.");
01596 
01597   if (stream->config.write_webm) {
01598     stream->ebml.stream = stream->file;
01599     write_webm_file_header(&stream->ebml, &stream->config.cfg,
01600                            &global->framerate,
01601                            stream->config.stereo_fmt,
01602                            global->codec->fourcc);
01603   } else
01604     write_ivf_file_header(stream->file, &stream->config.cfg,
01605                           global->codec->fourcc, 0);
01606 }
01607 
01608 
01609 static void close_output_file(struct stream_state *stream,
01610                               unsigned int         fourcc) {
01611   if (stream->config.write_webm) {
01612     write_webm_file_footer(&stream->ebml, stream->hash);
01613     free(stream->ebml.cue_list);
01614     stream->ebml.cue_list = NULL;
01615   } else {
01616     if (!fseek(stream->file, 0, SEEK_SET))
01617       write_ivf_file_header(stream->file, &stream->config.cfg,
01618                             fourcc,
01619                             stream->frames_out);
01620   }
01621 
01622   fclose(stream->file);
01623 }
01624 
01625 
01626 static void setup_pass(struct stream_state  *stream,
01627                        struct global_config *global,
01628                        int                   pass) {
01629   if (stream->config.stats_fn) {
01630     if (!stats_open_file(&stream->stats, stream->config.stats_fn,
01631                          pass))
01632       fatal("Failed to open statistics store");
01633   } else {
01634     if (!stats_open_mem(&stream->stats, pass))
01635       fatal("Failed to open statistics store");
01636   }
01637 
01638   stream->config.cfg.g_pass = global->passes == 2
01639                               ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS
01640                             : VPX_RC_ONE_PASS;
01641   if (pass)
01642     stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats);
01643 
01644   stream->cx_time = 0;
01645   stream->nbytes = 0;
01646   stream->frames_out = 0;
01647 }
01648 
01649 
01650 static void initialize_encoder(struct stream_state  *stream,
01651                                struct global_config *global) {
01652   int i;
01653   int flags = 0;
01654 
01655   flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0;
01656   flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0;
01657 
01658   /* Construct Encoder Context */
01659   vpx_codec_enc_init(&stream->encoder, global->codec->iface(),
01660                      &stream->config.cfg, flags);
01661   ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder");
01662 
01663   /* Note that we bypass the vpx_codec_control wrapper macro because
01664    * we're being clever to store the control IDs in an array. Real
01665    * applications will want to make use of the enumerations directly
01666    */
01667   for (i = 0; i < stream->config.arg_ctrl_cnt; i++) {
01668     int ctrl = stream->config.arg_ctrls[i][0];
01669     int value = stream->config.arg_ctrls[i][1];
01670     if (vpx_codec_control_(&stream->encoder, ctrl, value))
01671       fprintf(stderr, "Error: Tried to set control %d = %d\n",
01672               ctrl, value);
01673 
01674     ctx_exit_on_error(&stream->encoder, "Failed to control codec");
01675   }
01676 
01677 #if CONFIG_DECODERS
01678   if (global->test_decode != TEST_DECODE_OFF) {
01679     vpx_codec_dec_init(&stream->decoder, global->codec->dx_iface(), NULL, 0);
01680   }
01681 #endif
01682 }
01683 
01684 
01685 static void encode_frame(struct stream_state  *stream,
01686                          struct global_config *global,
01687                          struct vpx_image     *img,
01688                          unsigned int          frames_in) {
01689   vpx_codec_pts_t frame_start, next_frame_start;
01690   struct vpx_codec_enc_cfg *cfg = &stream->config.cfg;
01691   struct vpx_usec_timer timer;
01692 
01693   frame_start = (cfg->g_timebase.den * (int64_t)(frames_in - 1)
01694                  * global->framerate.den)
01695                 / cfg->g_timebase.num / global->framerate.num;
01696   next_frame_start = (cfg->g_timebase.den * (int64_t)(frames_in)
01697                       * global->framerate.den)
01698                      / cfg->g_timebase.num / global->framerate.num;
01699 
01700   /* Scale if necessary */
01701   if (img && (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) {
01702     if (!stream->img)
01703       stream->img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420,
01704                                   cfg->g_w, cfg->g_h, 16);
01705     I420Scale(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y],
01706               img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U],
01707               img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
01708               img->d_w, img->d_h,
01709               stream->img->planes[VPX_PLANE_Y],
01710               stream->img->stride[VPX_PLANE_Y],
01711               stream->img->planes[VPX_PLANE_U],
01712               stream->img->stride[VPX_PLANE_U],
01713               stream->img->planes[VPX_PLANE_V],
01714               stream->img->stride[VPX_PLANE_V],
01715               stream->img->d_w, stream->img->d_h,
01716               kFilterBox);
01717 
01718     img = stream->img;
01719   }
01720 
01721   vpx_usec_timer_start(&timer);
01722   vpx_codec_encode(&stream->encoder, img, frame_start,
01723                    (unsigned long)(next_frame_start - frame_start),
01724                    0, global->deadline);
01725   vpx_usec_timer_mark(&timer);
01726   stream->cx_time += vpx_usec_timer_elapsed(&timer);
01727   ctx_exit_on_error(&stream->encoder, "Stream %d: Failed to encode frame",
01728                     stream->index);
01729 }
01730 
01731 
01732 static void update_quantizer_histogram(struct stream_state *stream) {
01733   if (stream->config.cfg.g_pass != VPX_RC_FIRST_PASS) {
01734     int q;
01735 
01736     vpx_codec_control(&stream->encoder, VP8E_GET_LAST_QUANTIZER_64, &q);
01737     ctx_exit_on_error(&stream->encoder, "Failed to read quantizer");
01738     stream->counts[q]++;
01739   }
01740 }
01741 
01742 
01743 static void get_cx_data(struct stream_state  *stream,
01744                         struct global_config *global,
01745                         int                  *got_data) {
01746   const vpx_codec_cx_pkt_t *pkt;
01747   const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg;
01748   vpx_codec_iter_t iter = NULL;
01749 
01750   *got_data = 0;
01751   while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) {
01752     static size_t fsize = 0;
01753     static off_t ivf_header_pos = 0;
01754 
01755     switch (pkt->kind) {
01756       case VPX_CODEC_CX_FRAME_PKT:
01757         if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) {
01758           stream->frames_out++;
01759         }
01760         if (!global->quiet)
01761           fprintf(stderr, " %6luF", (unsigned long)pkt->data.frame.sz);
01762 
01763         update_rate_histogram(&stream->rate_hist, cfg, pkt);
01764         if (stream->config.write_webm) {
01765           /* Update the hash */
01766           if (!stream->ebml.debug)
01767             stream->hash = murmur(pkt->data.frame.buf,
01768                                   (int)pkt->data.frame.sz,
01769                                   stream->hash);
01770 
01771           write_webm_block(&stream->ebml, cfg, pkt);
01772         } else {
01773           if (pkt->data.frame.partition_id <= 0) {
01774             ivf_header_pos = ftello(stream->file);
01775             fsize = pkt->data.frame.sz;
01776 
01777             write_ivf_frame_header(stream->file, pkt);
01778           } else {
01779             fsize += pkt->data.frame.sz;
01780 
01781             if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) {
01782               off_t currpos = ftello(stream->file);
01783               fseeko(stream->file, ivf_header_pos, SEEK_SET);
01784               write_ivf_frame_size(stream->file, fsize);
01785               fseeko(stream->file, currpos, SEEK_SET);
01786             }
01787           }
01788 
01789           (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
01790                         stream->file);
01791         }
01792         stream->nbytes += pkt->data.raw.sz;
01793 
01794         *got_data = 1;
01795 #if CONFIG_DECODERS
01796         if (global->test_decode != TEST_DECODE_OFF && !stream->mismatch_seen) {
01797           vpx_codec_decode(&stream->decoder, pkt->data.frame.buf,
01798                            pkt->data.frame.sz, NULL, 0);
01799           if (stream->decoder.err) {
01800             warn_or_exit_on_error(&stream->decoder,
01801                                   global->test_decode == TEST_DECODE_FATAL,
01802                                   "Failed to decode frame %d in stream %d",
01803                                   stream->frames_out + 1, stream->index);
01804             stream->mismatch_seen = stream->frames_out + 1;
01805           }
01806         }
01807 #endif
01808         break;
01809       case VPX_CODEC_STATS_PKT:
01810         stream->frames_out++;
01811         stats_write(&stream->stats,
01812                     pkt->data.twopass_stats.buf,
01813                     pkt->data.twopass_stats.sz);
01814         stream->nbytes += pkt->data.raw.sz;
01815         break;
01816       case VPX_CODEC_PSNR_PKT:
01817 
01818         if (global->show_psnr) {
01819           int i;
01820 
01821           stream->psnr_sse_total += pkt->data.psnr.sse[0];
01822           stream->psnr_samples_total += pkt->data.psnr.samples[0];
01823           for (i = 0; i < 4; i++) {
01824             if (!global->quiet)
01825               fprintf(stderr, "%.3f ", pkt->data.psnr.psnr[i]);
01826             stream->psnr_totals[i] += pkt->data.psnr.psnr[i];
01827           }
01828           stream->psnr_count++;
01829         }
01830 
01831         break;
01832       default:
01833         break;
01834     }
01835   }
01836 }
01837 
01838 
01839 static void show_psnr(struct stream_state  *stream) {
01840   int i;
01841   double ovpsnr;
01842 
01843   if (!stream->psnr_count)
01844     return;
01845 
01846   fprintf(stderr, "Stream %d PSNR (Overall/Avg/Y/U/V)", stream->index);
01847   ovpsnr = vp8_mse2psnr((double)stream->psnr_samples_total, 255.0,
01848                         (double)stream->psnr_sse_total);
01849   fprintf(stderr, " %.3f", ovpsnr);
01850 
01851   for (i = 0; i < 4; i++) {
01852     fprintf(stderr, " %.3f", stream->psnr_totals[i] / stream->psnr_count);
01853   }
01854   fprintf(stderr, "\n");
01855 }
01856 
01857 
01858 static float usec_to_fps(uint64_t usec, unsigned int frames) {
01859   return (float)(usec > 0 ? frames * 1000000.0 / (float)usec : 0);
01860 }
01861 
01862 
01863 static void test_decode(struct stream_state  *stream,
01864                         enum TestDecodeFatality fatal,
01865                         const struct codec_item *codec) {
01866   vpx_image_t enc_img, dec_img;
01867 
01868   if (stream->mismatch_seen)
01869     return;
01870 
01871   /* Get the internal reference frame */
01872   if (codec->fourcc == VP8_FOURCC) {
01873     struct vpx_ref_frame ref_enc, ref_dec;
01874     int width, height;
01875 
01876     width = (stream->config.cfg.g_w + 15) & ~15;
01877     height = (stream->config.cfg.g_h + 15) & ~15;
01878     vpx_img_alloc(&ref_enc.img, VPX_IMG_FMT_I420, width, height, 1);
01879     enc_img = ref_enc.img;
01880     vpx_img_alloc(&ref_dec.img, VPX_IMG_FMT_I420, width, height, 1);
01881     dec_img = ref_dec.img;
01882 
01883     ref_enc.frame_type = VP8_LAST_FRAME;
01884     ref_dec.frame_type = VP8_LAST_FRAME;
01885     vpx_codec_control(&stream->encoder, VP8_COPY_REFERENCE, &ref_enc);
01886     vpx_codec_control(&stream->decoder, VP8_COPY_REFERENCE, &ref_dec);
01887   } else {
01888     struct vp9_ref_frame ref;
01889 
01890     ref.idx = 0;
01891     vpx_codec_control(&stream->encoder, VP9_GET_REFERENCE, &ref);
01892     enc_img = ref.img;
01893     vpx_codec_control(&stream->decoder, VP9_GET_REFERENCE, &ref);
01894     dec_img = ref.img;
01895   }
01896   ctx_exit_on_error(&stream->encoder, "Failed to get encoder reference frame");
01897   ctx_exit_on_error(&stream->decoder, "Failed to get decoder reference frame");
01898 
01899   if (!compare_img(&enc_img, &dec_img)) {
01900     int y[4], u[4], v[4];
01901     find_mismatch(&enc_img, &dec_img, y, u, v);
01902     stream->decoder.err = 1;
01903     warn_or_exit_on_error(&stream->decoder, fatal == TEST_DECODE_FATAL,
01904                           "Stream %d: Encode/decode mismatch on frame %d at"
01905                           " Y[%d, %d] {%d/%d},"
01906                           " U[%d, %d] {%d/%d},"
01907                           " V[%d, %d] {%d/%d}",
01908                           stream->index, stream->frames_out,
01909                           y[0], y[1], y[2], y[3],
01910                           u[0], u[1], u[2], u[3],
01911                           v[0], v[1], v[2], v[3]);
01912     stream->mismatch_seen = stream->frames_out;
01913   }
01914 
01915   vpx_img_free(&enc_img);
01916   vpx_img_free(&dec_img);
01917 }
01918 
01919 
01920 static void print_time(const char *label, int64_t etl) {
01921   int hours, mins, secs;
01922 
01923   if (etl >= 0) {
01924     hours = etl / 3600;
01925     etl -= hours * 3600;
01926     mins = etl / 60;
01927     etl -= mins * 60;
01928     secs = etl;
01929 
01930     fprintf(stderr, "[%3s %2d:%02d:%02d] ",
01931             label, hours, mins, secs);
01932   } else {
01933     fprintf(stderr, "[%3s  unknown] ", label);
01934   }
01935 }
01936 
01937 int main(int argc, const char **argv_) {
01938   int                    pass;
01939   vpx_image_t            raw;
01940   int                    frame_avail, got_data;
01941 
01942   struct input_state       input = {0};
01943   struct global_config     global;
01944   struct stream_state     *streams = NULL;
01945   char                   **argv, **argi;
01946   uint64_t                 cx_time = 0;
01947   int                      stream_cnt = 0;
01948   int                      res = 0;
01949 
01950   exec_name = argv_[0];
01951 
01952   if (argc < 3)
01953     usage_exit();
01954 
01955   /* Setup default input stream settings */
01956   input.framerate.num = 30;
01957   input.framerate.den = 1;
01958   input.use_i420 = 1;
01959   input.only_i420 = 1;
01960 
01961   /* First parse the global configuration values, because we want to apply
01962    * other parameters on top of the default configuration provided by the
01963    * codec.
01964    */
01965   argv = argv_dup(argc - 1, argv_ + 1);
01966   parse_global_config(&global, argv);
01967 
01968   {
01969     /* Now parse each stream's parameters. Using a local scope here
01970      * due to the use of 'stream' as loop variable in FOREACH_STREAM
01971      * loops
01972      */
01973     struct stream_state *stream = NULL;
01974 
01975     do {
01976       stream = new_stream(&global, stream);
01977       stream_cnt++;
01978       if (!streams)
01979         streams = stream;
01980     } while (parse_stream_params(&global, stream, argv));
01981   }
01982 
01983   /* Check for unrecognized options */
01984   for (argi = argv; *argi; argi++)
01985     if (argi[0][0] == '-' && argi[0][1])
01986       die("Error: Unrecognized option %s\n", *argi);
01987 
01988   /* Handle non-option arguments */
01989   input.fn = argv[0];
01990 
01991   if (!input.fn)
01992     usage_exit();
01993 
01994 #if CONFIG_NON420
01995   /* Decide if other chroma subsamplings than 4:2:0 are supported */
01996   if (global.codec->fourcc == VP9_FOURCC)
01997     input.only_i420 = 0;
01998 #endif
01999 
02000   for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) {
02001     int frames_in = 0, seen_frames = 0;
02002     int64_t estimated_time_left = -1;
02003     int64_t average_rate = -1;
02004     off_t lagged_count = 0;
02005 
02006     open_input_file(&input);
02007 
02008     /* If the input file doesn't specify its w/h (raw files), try to get
02009      * the data from the first stream's configuration.
02010      */
02011     if (!input.w || !input.h)
02012       FOREACH_STREAM( {
02013       if (stream->config.cfg.g_w && stream->config.cfg.g_h) {
02014         input.w = stream->config.cfg.g_w;
02015         input.h = stream->config.cfg.g_h;
02016         break;
02017       }
02018     });
02019 
02020     /* Update stream configurations from the input file's parameters */
02021     if (!input.w || !input.h)
02022       fatal("Specify stream dimensions with --width (-w) "
02023             " and --height (-h)");
02024     FOREACH_STREAM(set_stream_dimensions(stream, input.w, input.h));
02025     FOREACH_STREAM(validate_stream_config(stream));
02026 
02027     /* Ensure that --passes and --pass are consistent. If --pass is set and
02028      * --passes=2, ensure --fpf was set.
02029      */
02030     if (global.pass && global.passes == 2)
02031       FOREACH_STREAM( {
02032       if (!stream->config.stats_fn)
02033         die("Stream %d: Must specify --fpf when --pass=%d"
02034         " and --passes=2\n", stream->index, global.pass);
02035     });
02036 
02037     /* Use the frame rate from the file only if none was specified
02038      * on the command-line.
02039      */
02040     if (!global.have_framerate)
02041       global.framerate = input.framerate;
02042 
02043     FOREACH_STREAM(set_default_kf_interval(stream, &global));
02044 
02045     /* Show configuration */
02046     if (global.verbose && pass == 0)
02047       FOREACH_STREAM(show_stream_config(stream, &global, &input));
02048 
02049     if (pass == (global.pass ? global.pass - 1 : 0)) {
02050       if (input.file_type == FILE_TYPE_Y4M)
02051         /*The Y4M reader does its own allocation.
02052           Just initialize this here to avoid problems if we never read any
02053            frames.*/
02054         memset(&raw, 0, sizeof(raw));
02055       else
02056         vpx_img_alloc(&raw,
02057                       input.use_i420 ? VPX_IMG_FMT_I420
02058                       : VPX_IMG_FMT_YV12,
02059                       input.w, input.h, 32);
02060 
02061       FOREACH_STREAM(init_rate_histogram(&stream->rate_hist,
02062                                          &stream->config.cfg,
02063                                          &global.framerate));
02064     }
02065 
02066     FOREACH_STREAM(setup_pass(stream, &global, pass));
02067     FOREACH_STREAM(open_output_file(stream, &global));
02068     FOREACH_STREAM(initialize_encoder(stream, &global));
02069 
02070     frame_avail = 1;
02071     got_data = 0;
02072 
02073     while (frame_avail || got_data) {
02074       struct vpx_usec_timer timer;
02075 
02076       if (!global.limit || frames_in < global.limit) {
02077         frame_avail = read_frame(&input, &raw);
02078 
02079         if (frame_avail)
02080           frames_in++;
02081         seen_frames = frames_in > global.skip_frames ?
02082                           frames_in - global.skip_frames : 0;
02083 
02084         if (!global.quiet) {
02085           float fps = usec_to_fps(cx_time, seen_frames);
02086           fprintf(stderr, "\rPass %d/%d ", pass + 1, global.passes);
02087 
02088           if (stream_cnt == 1)
02089             fprintf(stderr,
02090                     "frame %4d/%-4d %7"PRId64"B ",
02091                     frames_in, streams->frames_out, (int64_t)streams->nbytes);
02092           else
02093             fprintf(stderr, "frame %4d ", frames_in);
02094 
02095           fprintf(stderr, "%7"PRId64" %s %.2f %s ",
02096                   cx_time > 9999999 ? cx_time / 1000 : cx_time,
02097                   cx_time > 9999999 ? "ms" : "us",
02098                   fps >= 1.0 ? fps : fps * 60,
02099                   fps >= 1.0 ? "fps" : "fpm");
02100           print_time("ETA", estimated_time_left);
02101           fprintf(stderr, "\033[K");
02102         }
02103 
02104       } else
02105         frame_avail = 0;
02106 
02107       if (frames_in > global.skip_frames) {
02108         vpx_usec_timer_start(&timer);
02109         FOREACH_STREAM(encode_frame(stream, &global,
02110                                     frame_avail ? &raw : NULL,
02111                                     frames_in));
02112         vpx_usec_timer_mark(&timer);
02113         cx_time += vpx_usec_timer_elapsed(&timer);
02114 
02115         FOREACH_STREAM(update_quantizer_histogram(stream));
02116 
02117         got_data = 0;
02118         FOREACH_STREAM(get_cx_data(stream, &global, &got_data));
02119 
02120         if (!got_data && input.length && !streams->frames_out) {
02121           lagged_count = global.limit ? seen_frames : ftello(input.file);
02122         } else if (input.length) {
02123           int64_t remaining;
02124           int64_t rate;
02125 
02126           if (global.limit) {
02127             int frame_in_lagged = (seen_frames - lagged_count) * 1000;
02128 
02129             rate = cx_time ? frame_in_lagged * (int64_t)1000000 / cx_time : 0;
02130             remaining = 1000 * (global.limit - global.skip_frames
02131                                 - seen_frames + lagged_count);
02132           } else {
02133             off_t input_pos = ftello(input.file);
02134             off_t input_pos_lagged = input_pos - lagged_count;
02135             int64_t limit = input.length;
02136 
02137             rate = cx_time ? input_pos_lagged * (int64_t)1000000 / cx_time : 0;
02138             remaining = limit - input_pos + lagged_count;
02139           }
02140 
02141           average_rate = (average_rate <= 0)
02142               ? rate
02143               : (average_rate * 7 + rate) / 8;
02144           estimated_time_left = average_rate ? remaining / average_rate : -1;
02145         }
02146 
02147         if (got_data && global.test_decode != TEST_DECODE_OFF)
02148           FOREACH_STREAM(test_decode(stream, global.test_decode, global.codec));
02149       }
02150 
02151       fflush(stdout);
02152     }
02153 
02154     if (stream_cnt > 1)
02155       fprintf(stderr, "\n");
02156 
02157     if (!global.quiet)
02158       FOREACH_STREAM(fprintf(
02159                        stderr,
02160                        "\rPass %d/%d frame %4d/%-4d %7"PRId64"B %7lub/f %7"PRId64"b/s"
02161                        " %7"PRId64" %s (%.2f fps)\033[K\n", pass + 1,
02162                        global.passes, frames_in, stream->frames_out, (int64_t)stream->nbytes,
02163                        seen_frames ? (unsigned long)(stream->nbytes * 8 / seen_frames) : 0,
02164                        seen_frames ? (int64_t)stream->nbytes * 8
02165                        * (int64_t)global.framerate.num / global.framerate.den
02166                        / seen_frames
02167                        : 0,
02168                        stream->cx_time > 9999999 ? stream->cx_time / 1000 : stream->cx_time,
02169                        stream->cx_time > 9999999 ? "ms" : "us",
02170                        usec_to_fps(stream->cx_time, seen_frames));
02171                     );
02172 
02173     if (global.show_psnr)
02174       FOREACH_STREAM(show_psnr(stream));
02175 
02176     FOREACH_STREAM(vpx_codec_destroy(&stream->encoder));
02177 
02178     if (global.test_decode != TEST_DECODE_OFF) {
02179       FOREACH_STREAM(vpx_codec_destroy(&stream->decoder));
02180     }
02181 
02182     close_input_file(&input);
02183 
02184     if (global.test_decode == TEST_DECODE_FATAL) {
02185       FOREACH_STREAM(res |= stream->mismatch_seen);
02186     }
02187     FOREACH_STREAM(close_output_file(stream, global.codec->fourcc));
02188 
02189     FOREACH_STREAM(stats_close(&stream->stats, global.passes - 1));
02190 
02191     if (global.pass)
02192       break;
02193   }
02194 
02195   if (global.show_q_hist_buckets)
02196     FOREACH_STREAM(show_q_histogram(stream->counts,
02197                                     global.show_q_hist_buckets));
02198 
02199   if (global.show_rate_hist_buckets)
02200     FOREACH_STREAM(show_rate_histogram(&stream->rate_hist,
02201                                        &stream->config.cfg,
02202                                        global.show_rate_hist_buckets));
02203   FOREACH_STREAM(destroy_rate_histogram(&stream->rate_hist));
02204 
02205 #if CONFIG_INTERNAL_STATS
02206   /* TODO(jkoleszar): This doesn't belong in this executable. Do it for now,
02207    * to match some existing utilities.
02208    */
02209   if (!(global.pass == 1 && global.passes == 2))
02210     FOREACH_STREAM({
02211       FILE *f = fopen("opsnr.stt", "a");
02212       if (stream->mismatch_seen) {
02213         fprintf(f, "First mismatch occurred in frame %d\n",
02214                 stream->mismatch_seen);
02215       } else {
02216         fprintf(f, "No mismatch detected in recon buffers\n");
02217       }
02218       fclose(f);
02219     });
02220 #endif
02221 
02222   vpx_img_free(&raw);
02223   free(argv);
02224   free(streams);
02225   return res ? EXIT_FAILURE : EXIT_SUCCESS;
02226 }

Generated on 4 Dec 2017 for WebM VP8 Codec SDK by  doxygen 1.6.1