Home | History | Annotate | Download | only in libvpx
      1 /*
      2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  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.
      9  */
     10 
     11 
     12 /* This is a simple program that encodes YV12 files and generates ivf
     13  * files using the new interface.
     14  */
     15 #if defined(_WIN32) || !CONFIG_OS_SUPPORT
     16 #define USE_POSIX_MMAP 0
     17 #else
     18 #define USE_POSIX_MMAP 1
     19 #endif
     20 
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <stdarg.h>
     24 #include <string.h>
     25 #include <limits.h>
     26 #include "vpx/vpx_encoder.h"
     27 #if USE_POSIX_MMAP
     28 #include <sys/types.h>
     29 #include <sys/stat.h>
     30 #include <sys/mman.h>
     31 #include <fcntl.h>
     32 #include <unistd.h>
     33 #endif
     34 #include "vpx_version.h"
     35 #include "vpx/vp8cx.h"
     36 #include "vpx_ports/mem_ops.h"
     37 #include "vpx_ports/vpx_timer.h"
     38 #include "tools_common.h"
     39 #include "y4minput.h"
     40 #include "libmkv/EbmlWriter.h"
     41 #include "libmkv/EbmlIDs.h"
     42 
     43 /* Need special handling of these functions on Windows */
     44 #if defined(_MSC_VER)
     45 /* MSVS doesn't define off_t, and uses _f{seek,tell}i64 */
     46 typedef __int64 off_t;
     47 #define fseeko _fseeki64
     48 #define ftello _ftelli64
     49 #elif defined(_WIN32)
     50 /* MinGW defines off_t, and uses f{seek,tell}o64 */
     51 #define fseeko fseeko64
     52 #define ftello ftello64
     53 #endif
     54 
     55 #if defined(_MSC_VER)
     56 #define LITERALU64(n) n
     57 #else
     58 #define LITERALU64(n) n##LLU
     59 #endif
     60 
     61 /* We should use 32-bit file operations in WebM file format
     62  * when building ARM executable file (.axf) with RVCT */
     63 #if !CONFIG_OS_SUPPORT
     64 typedef long off_t;
     65 #define fseeko fseek
     66 #define ftello ftell
     67 #endif
     68 
     69 static const char *exec_name;
     70 
     71 static const struct codec_item
     72 {
     73     char const              *name;
     74     const vpx_codec_iface_t *iface;
     75     unsigned int             fourcc;
     76 } codecs[] =
     77 {
     78 #if CONFIG_VP8_ENCODER
     79     {"vp8",  &vpx_codec_vp8_cx_algo, 0x30385056},
     80 #endif
     81 };
     82 
     83 static void usage_exit();
     84 
     85 void die(const char *fmt, ...)
     86 {
     87     va_list ap;
     88     va_start(ap, fmt);
     89     vfprintf(stderr, fmt, ap);
     90     fprintf(stderr, "\n");
     91     usage_exit();
     92 }
     93 
     94 static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s)
     95 {
     96     if (ctx->err)
     97     {
     98         const char *detail = vpx_codec_error_detail(ctx);
     99 
    100         fprintf(stderr, "%s: %s\n", s, vpx_codec_error(ctx));
    101 
    102         if (detail)
    103             fprintf(stderr, "    %s\n", detail);
    104 
    105         exit(EXIT_FAILURE);
    106     }
    107 }
    108 
    109 /* This structure is used to abstract the different ways of handling
    110  * first pass statistics.
    111  */
    112 typedef struct
    113 {
    114     vpx_fixed_buf_t buf;
    115     int             pass;
    116     FILE           *file;
    117     char           *buf_ptr;
    118     size_t          buf_alloc_sz;
    119 } stats_io_t;
    120 
    121 int stats_open_file(stats_io_t *stats, const char *fpf, int pass)
    122 {
    123     int res;
    124 
    125     stats->pass = pass;
    126 
    127     if (pass == 0)
    128     {
    129         stats->file = fopen(fpf, "wb");
    130         stats->buf.sz = 0;
    131         stats->buf.buf = NULL,
    132                    res = (stats->file != NULL);
    133     }
    134     else
    135     {
    136 #if 0
    137 #elif USE_POSIX_MMAP
    138         struct stat stat_buf;
    139         int fd;
    140 
    141         fd = open(fpf, O_RDONLY);
    142         stats->file = fdopen(fd, "rb");
    143         fstat(fd, &stat_buf);
    144         stats->buf.sz = stat_buf.st_size;
    145         stats->buf.buf = mmap(NULL, stats->buf.sz, PROT_READ, MAP_PRIVATE,
    146                               fd, 0);
    147         res = (stats->buf.buf != NULL);
    148 #else
    149         size_t nbytes;
    150 
    151         stats->file = fopen(fpf, "rb");
    152 
    153         if (fseek(stats->file, 0, SEEK_END))
    154         {
    155             fprintf(stderr, "First-pass stats file must be seekable!\n");
    156             exit(EXIT_FAILURE);
    157         }
    158 
    159         stats->buf.sz = stats->buf_alloc_sz = ftell(stats->file);
    160         rewind(stats->file);
    161 
    162         stats->buf.buf = malloc(stats->buf_alloc_sz);
    163 
    164         if (!stats->buf.buf)
    165         {
    166             fprintf(stderr, "Failed to allocate first-pass stats buffer (%lu bytes)\n",
    167                     (unsigned long)stats->buf_alloc_sz);
    168             exit(EXIT_FAILURE);
    169         }
    170 
    171         nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file);
    172         res = (nbytes == stats->buf.sz);
    173 #endif
    174     }
    175 
    176     return res;
    177 }
    178 
    179 int stats_open_mem(stats_io_t *stats, int pass)
    180 {
    181     int res;
    182     stats->pass = pass;
    183 
    184     if (!pass)
    185     {
    186         stats->buf.sz = 0;
    187         stats->buf_alloc_sz = 64 * 1024;
    188         stats->buf.buf = malloc(stats->buf_alloc_sz);
    189     }
    190 
    191     stats->buf_ptr = stats->buf.buf;
    192     res = (stats->buf.buf != NULL);
    193     return res;
    194 }
    195 
    196 
    197 void stats_close(stats_io_t *stats, int last_pass)
    198 {
    199     if (stats->file)
    200     {
    201         if (stats->pass == last_pass)
    202         {
    203 #if 0
    204 #elif USE_POSIX_MMAP
    205             munmap(stats->buf.buf, stats->buf.sz);
    206 #else
    207             free(stats->buf.buf);
    208 #endif
    209         }
    210 
    211         fclose(stats->file);
    212         stats->file = NULL;
    213     }
    214     else
    215     {
    216         if (stats->pass == last_pass)
    217             free(stats->buf.buf);
    218     }
    219 }
    220 
    221 void stats_write(stats_io_t *stats, const void *pkt, size_t len)
    222 {
    223     if (stats->file)
    224     {
    225         if(fwrite(pkt, 1, len, stats->file));
    226     }
    227     else
    228     {
    229         if (stats->buf.sz + len > stats->buf_alloc_sz)
    230         {
    231             size_t  new_sz = stats->buf_alloc_sz + 64 * 1024;
    232             char   *new_ptr = realloc(stats->buf.buf, new_sz);
    233 
    234             if (new_ptr)
    235             {
    236                 stats->buf_ptr = new_ptr + (stats->buf_ptr - (char *)stats->buf.buf);
    237                 stats->buf.buf = new_ptr;
    238                 stats->buf_alloc_sz = new_sz;
    239             }
    240             else
    241             {
    242                 fprintf(stderr,
    243                         "\nFailed to realloc firstpass stats buffer.\n");
    244                 exit(EXIT_FAILURE);
    245             }
    246         }
    247 
    248         memcpy(stats->buf_ptr, pkt, len);
    249         stats->buf.sz += len;
    250         stats->buf_ptr += len;
    251     }
    252 }
    253 
    254 vpx_fixed_buf_t stats_get(stats_io_t *stats)
    255 {
    256     return stats->buf;
    257 }
    258 
    259 enum video_file_type
    260 {
    261     FILE_TYPE_RAW,
    262     FILE_TYPE_IVF,
    263     FILE_TYPE_Y4M
    264 };
    265 
    266 struct detect_buffer {
    267     char buf[4];
    268     size_t buf_read;
    269     size_t position;
    270 };
    271 
    272 
    273 #define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */
    274 static int read_frame(FILE *f, vpx_image_t *img, unsigned int file_type,
    275                       y4m_input *y4m, struct detect_buffer *detect)
    276 {
    277     int plane = 0;
    278     int shortread = 0;
    279 
    280     if (file_type == FILE_TYPE_Y4M)
    281     {
    282         if (y4m_input_fetch_frame(y4m, f, img) < 1)
    283            return 0;
    284     }
    285     else
    286     {
    287         if (file_type == FILE_TYPE_IVF)
    288         {
    289             char junk[IVF_FRAME_HDR_SZ];
    290 
    291             /* Skip the frame header. We know how big the frame should be. See
    292              * write_ivf_frame_header() for documentation on the frame header
    293              * layout.
    294              */
    295             if(fread(junk, 1, IVF_FRAME_HDR_SZ, f));
    296         }
    297 
    298         for (plane = 0; plane < 3; plane++)
    299         {
    300             unsigned char *ptr;
    301             int w = (plane ? (1 + img->d_w) / 2 : img->d_w);
    302             int h = (plane ? (1 + img->d_h) / 2 : img->d_h);
    303             int r;
    304 
    305             /* Determine the correct plane based on the image format. The for-loop
    306              * always counts in Y,U,V order, but this may not match the order of
    307              * the data on disk.
    308              */
    309             switch (plane)
    310             {
    311             case 1:
    312                 ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12? VPX_PLANE_V : VPX_PLANE_U];
    313                 break;
    314             case 2:
    315                 ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12?VPX_PLANE_U : VPX_PLANE_V];
    316                 break;
    317             default:
    318                 ptr = img->planes[plane];
    319             }
    320 
    321             for (r = 0; r < h; r++)
    322             {
    323                 size_t needed = w;
    324                 size_t buf_position = 0;
    325                 const size_t left = detect->buf_read - detect->position;
    326                 if (left > 0)
    327                 {
    328                     const size_t more = (left < needed) ? left : needed;
    329                     memcpy(ptr, detect->buf + detect->position, more);
    330                     buf_position = more;
    331                     needed -= more;
    332                     detect->position += more;
    333                 }
    334                 if (needed > 0)
    335                 {
    336                     shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
    337                 }
    338 
    339                 ptr += img->stride[plane];
    340             }
    341         }
    342     }
    343 
    344     return !shortread;
    345 }
    346 
    347 
    348 unsigned int file_is_y4m(FILE      *infile,
    349                          y4m_input *y4m,
    350                          char       detect[4])
    351 {
    352     if(memcmp(detect, "YUV4", 4) == 0)
    353     {
    354         return 1;
    355     }
    356     return 0;
    357 }
    358 
    359 #define IVF_FILE_HDR_SZ (32)
    360 unsigned int file_is_ivf(FILE *infile,
    361                          unsigned int *fourcc,
    362                          unsigned int *width,
    363                          unsigned int *height,
    364                          struct detect_buffer *detect)
    365 {
    366     char raw_hdr[IVF_FILE_HDR_SZ];
    367     int is_ivf = 0;
    368 
    369     if(memcmp(detect->buf, "DKIF", 4) != 0)
    370         return 0;
    371 
    372     /* See write_ivf_file_header() for more documentation on the file header
    373      * layout.
    374      */
    375     if (fread(raw_hdr + 4, 1, IVF_FILE_HDR_SZ - 4, infile)
    376         == IVF_FILE_HDR_SZ - 4)
    377     {
    378         {
    379             is_ivf = 1;
    380 
    381             if (mem_get_le16(raw_hdr + 4) != 0)
    382                 fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
    383                         " decode properly.");
    384 
    385             *fourcc = mem_get_le32(raw_hdr + 8);
    386         }
    387     }
    388 
    389     if (is_ivf)
    390     {
    391         *width = mem_get_le16(raw_hdr + 12);
    392         *height = mem_get_le16(raw_hdr + 14);
    393         detect->position = 4;
    394     }
    395 
    396     return is_ivf;
    397 }
    398 
    399 
    400 static void write_ivf_file_header(FILE *outfile,
    401                                   const vpx_codec_enc_cfg_t *cfg,
    402                                   unsigned int fourcc,
    403                                   int frame_cnt)
    404 {
    405     char header[32];
    406 
    407     if (cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
    408         return;
    409 
    410     header[0] = 'D';
    411     header[1] = 'K';
    412     header[2] = 'I';
    413     header[3] = 'F';
    414     mem_put_le16(header + 4,  0);                 /* version */
    415     mem_put_le16(header + 6,  32);                /* headersize */
    416     mem_put_le32(header + 8,  fourcc);            /* headersize */
    417     mem_put_le16(header + 12, cfg->g_w);          /* width */
    418     mem_put_le16(header + 14, cfg->g_h);          /* height */
    419     mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */
    420     mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */
    421     mem_put_le32(header + 24, frame_cnt);         /* length */
    422     mem_put_le32(header + 28, 0);                 /* unused */
    423 
    424     if(fwrite(header, 1, 32, outfile));
    425 }
    426 
    427 
    428 static void write_ivf_frame_header(FILE *outfile,
    429                                    const vpx_codec_cx_pkt_t *pkt)
    430 {
    431     char             header[12];
    432     vpx_codec_pts_t  pts;
    433 
    434     if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
    435         return;
    436 
    437     pts = pkt->data.frame.pts;
    438     mem_put_le32(header, pkt->data.frame.sz);
    439     mem_put_le32(header + 4, pts & 0xFFFFFFFF);
    440     mem_put_le32(header + 8, pts >> 32);
    441 
    442     if(fwrite(header, 1, 12, outfile));
    443 }
    444 
    445 
    446 typedef off_t EbmlLoc;
    447 
    448 
    449 struct cue_entry
    450 {
    451     unsigned int time;
    452     uint64_t     loc;
    453 };
    454 
    455 
    456 struct EbmlGlobal
    457 {
    458     int debug;
    459 
    460     FILE    *stream;
    461     int64_t last_pts_ms;
    462     vpx_rational_t  framerate;
    463 
    464     /* These pointers are to the start of an element */
    465     off_t    position_reference;
    466     off_t    seek_info_pos;
    467     off_t    segment_info_pos;
    468     off_t    track_pos;
    469     off_t    cue_pos;
    470     off_t    cluster_pos;
    471 
    472     /* This pointer is to a specific element to be serialized */
    473     off_t    track_id_pos;
    474 
    475     /* These pointers are to the size field of the element */
    476     EbmlLoc  startSegment;
    477     EbmlLoc  startCluster;
    478 
    479     uint32_t cluster_timecode;
    480     int      cluster_open;
    481 
    482     struct cue_entry *cue_list;
    483     unsigned int      cues;
    484 
    485 };
    486 
    487 
    488 void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len)
    489 {
    490     if(fwrite(buffer_in, 1, len, glob->stream));
    491 }
    492 
    493 
    494 void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, unsigned long len)
    495 {
    496     const unsigned char *q = (const unsigned char *)buffer_in + len - 1;
    497 
    498     for(; len; len--)
    499         Ebml_Write(glob, q--, 1);
    500 }
    501 
    502 
    503 /* Need a fixed size serializer for the track ID. libmkv provdes a 64 bit
    504  * one, but not a 32 bit one.
    505  */
    506 static void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, uint64_t ui)
    507 {
    508     unsigned char sizeSerialized = 4 | 0x80;
    509     Ebml_WriteID(glob, class_id);
    510     Ebml_Serialize(glob, &sizeSerialized, 1);
    511     Ebml_Serialize(glob, &ui, 4);
    512 }
    513 
    514 
    515 static void
    516 Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc,
    517                           unsigned long class_id)
    518 {
    519     //todo this is always taking 8 bytes, this may need later optimization
    520     //this is a key that says lenght unknown
    521     unsigned long long unknownLen =  LITERALU64(0x01FFFFFFFFFFFFFF);
    522 
    523     Ebml_WriteID(glob, class_id);
    524     *ebmlLoc = ftello(glob->stream);
    525     Ebml_Serialize(glob, &unknownLen, 8);
    526 }
    527 
    528 static void
    529 Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc)
    530 {
    531     off_t pos;
    532     uint64_t size;
    533 
    534     /* Save the current stream pointer */
    535     pos = ftello(glob->stream);
    536 
    537     /* Calculate the size of this element */
    538     size = pos - *ebmlLoc - 8;
    539     size |=  LITERALU64(0x0100000000000000);
    540 
    541     /* Seek back to the beginning of the element and write the new size */
    542     fseeko(glob->stream, *ebmlLoc, SEEK_SET);
    543     Ebml_Serialize(glob, &size, 8);
    544 
    545     /* Reset the stream pointer */
    546     fseeko(glob->stream, pos, SEEK_SET);
    547 }
    548 
    549 
    550 static void
    551 write_webm_seek_element(EbmlGlobal *ebml, unsigned long id, off_t pos)
    552 {
    553     uint64_t offset = pos - ebml->position_reference;
    554     EbmlLoc start;
    555     Ebml_StartSubElement(ebml, &start, Seek);
    556     Ebml_SerializeBinary(ebml, SeekID, id);
    557     Ebml_SerializeUnsigned64(ebml, SeekPosition, offset);
    558     Ebml_EndSubElement(ebml, &start);
    559 }
    560 
    561 
    562 static void
    563 write_webm_seek_info(EbmlGlobal *ebml)
    564 {
    565 
    566     off_t pos;
    567 
    568     /* Save the current stream pointer */
    569     pos = ftello(ebml->stream);
    570 
    571     if(ebml->seek_info_pos)
    572         fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET);
    573     else
    574         ebml->seek_info_pos = pos;
    575 
    576     {
    577         EbmlLoc start;
    578 
    579         Ebml_StartSubElement(ebml, &start, SeekHead);
    580         write_webm_seek_element(ebml, Tracks, ebml->track_pos);
    581         write_webm_seek_element(ebml, Cues,   ebml->cue_pos);
    582         write_webm_seek_element(ebml, Info,   ebml->segment_info_pos);
    583         Ebml_EndSubElement(ebml, &start);
    584     }
    585     {
    586         //segment info
    587         EbmlLoc startInfo;
    588         uint64_t frame_time;
    589 
    590         frame_time = (uint64_t)1000 * ebml->framerate.den
    591                      / ebml->framerate.num;
    592         ebml->segment_info_pos = ftello(ebml->stream);
    593         Ebml_StartSubElement(ebml, &startInfo, Info);
    594         Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000);
    595         Ebml_SerializeFloat(ebml, Segment_Duration,
    596                             ebml->last_pts_ms + frame_time);
    597         Ebml_SerializeString(ebml, 0x4D80,
    598             ebml->debug ? "vpxenc" : "vpxenc" VERSION_STRING);
    599         Ebml_SerializeString(ebml, 0x5741,
    600             ebml->debug ? "vpxenc" : "vpxenc" VERSION_STRING);
    601         Ebml_EndSubElement(ebml, &startInfo);
    602     }
    603 }
    604 
    605 
    606 static void
    607 write_webm_file_header(EbmlGlobal                *glob,
    608                        const vpx_codec_enc_cfg_t *cfg,
    609                        const struct vpx_rational *fps)
    610 {
    611     {
    612         EbmlLoc start;
    613         Ebml_StartSubElement(glob, &start, EBML);
    614         Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
    615         Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); //EBML Read Version
    616         Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); //EBML Max ID Length
    617         Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); //EBML Max Size Length
    618         Ebml_SerializeString(glob, DocType, "webm"); //Doc Type
    619         Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); //Doc Type Version
    620         Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); //Doc Type Read Version
    621         Ebml_EndSubElement(glob, &start);
    622     }
    623     {
    624         Ebml_StartSubElement(glob, &glob->startSegment, Segment); //segment
    625         glob->position_reference = ftello(glob->stream);
    626         glob->framerate = *fps;
    627         write_webm_seek_info(glob);
    628 
    629         {
    630             EbmlLoc trackStart;
    631             glob->track_pos = ftello(glob->stream);
    632             Ebml_StartSubElement(glob, &trackStart, Tracks);
    633             {
    634                 unsigned int trackNumber = 1;
    635                 uint64_t     trackID = 0;
    636 
    637                 EbmlLoc start;
    638                 Ebml_StartSubElement(glob, &start, TrackEntry);
    639                 Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
    640                 glob->track_id_pos = ftello(glob->stream);
    641                 Ebml_SerializeUnsigned32(glob, TrackUID, trackID);
    642                 Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1
    643                 Ebml_SerializeString(glob, CodecID, "V_VP8");
    644                 {
    645                     unsigned int pixelWidth = cfg->g_w;
    646                     unsigned int pixelHeight = cfg->g_h;
    647                     float        frameRate   = (float)fps->num/(float)fps->den;
    648 
    649                     EbmlLoc videoStart;
    650                     Ebml_StartSubElement(glob, &videoStart, Video);
    651                     Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
    652                     Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
    653                     Ebml_SerializeFloat(glob, FrameRate, frameRate);
    654                     Ebml_EndSubElement(glob, &videoStart); //Video
    655                 }
    656                 Ebml_EndSubElement(glob, &start); //Track Entry
    657             }
    658             Ebml_EndSubElement(glob, &trackStart);
    659         }
    660         // segment element is open
    661     }
    662 }
    663 
    664 
    665 static void
    666 write_webm_block(EbmlGlobal                *glob,
    667                  const vpx_codec_enc_cfg_t *cfg,
    668                  const vpx_codec_cx_pkt_t  *pkt)
    669 {
    670     unsigned long  block_length;
    671     unsigned char  track_number;
    672     unsigned short block_timecode = 0;
    673     unsigned char  flags;
    674     int64_t        pts_ms;
    675     int            start_cluster = 0, is_keyframe;
    676 
    677     /* Calculate the PTS of this frame in milliseconds */
    678     pts_ms = pkt->data.frame.pts * 1000
    679              * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den;
    680     if(pts_ms <= glob->last_pts_ms)
    681         pts_ms = glob->last_pts_ms + 1;
    682     glob->last_pts_ms = pts_ms;
    683 
    684     /* Calculate the relative time of this block */
    685     if(pts_ms - glob->cluster_timecode > SHRT_MAX)
    686         start_cluster = 1;
    687     else
    688         block_timecode = pts_ms - glob->cluster_timecode;
    689 
    690     is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY);
    691     if(start_cluster || is_keyframe)
    692     {
    693         if(glob->cluster_open)
    694             Ebml_EndSubElement(glob, &glob->startCluster);
    695 
    696         /* Open the new cluster */
    697         block_timecode = 0;
    698         glob->cluster_open = 1;
    699         glob->cluster_timecode = pts_ms;
    700         glob->cluster_pos = ftello(glob->stream);
    701         Ebml_StartSubElement(glob, &glob->startCluster, Cluster); //cluster
    702         Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode);
    703 
    704         /* Save a cue point if this is a keyframe. */
    705         if(is_keyframe)
    706         {
    707             struct cue_entry *cue, *new_cue_list;
    708 
    709             new_cue_list = realloc(glob->cue_list,
    710                                    (glob->cues+1) * sizeof(struct cue_entry));
    711             if(new_cue_list)
    712                 glob->cue_list = new_cue_list;
    713             else
    714             {
    715                 fprintf(stderr, "\nFailed to realloc cue list.\n");
    716                 exit(EXIT_FAILURE);
    717             }
    718 
    719             cue = &glob->cue_list[glob->cues];
    720             cue->time = glob->cluster_timecode;
    721             cue->loc = glob->cluster_pos;
    722             glob->cues++;
    723         }
    724     }
    725 
    726     /* Write the Simple Block */
    727     Ebml_WriteID(glob, SimpleBlock);
    728 
    729     block_length = pkt->data.frame.sz + 4;
    730     block_length |= 0x10000000;
    731     Ebml_Serialize(glob, &block_length, 4);
    732 
    733     track_number = 1;
    734     track_number |= 0x80;
    735     Ebml_Write(glob, &track_number, 1);
    736 
    737     Ebml_Serialize(glob, &block_timecode, 2);
    738 
    739     flags = 0;
    740     if(is_keyframe)
    741         flags |= 0x80;
    742     if(pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
    743         flags |= 0x08;
    744     Ebml_Write(glob, &flags, 1);
    745 
    746     Ebml_Write(glob, pkt->data.frame.buf, pkt->data.frame.sz);
    747 }
    748 
    749 
    750 static void
    751 write_webm_file_footer(EbmlGlobal *glob, long hash)
    752 {
    753 
    754     if(glob->cluster_open)
    755         Ebml_EndSubElement(glob, &glob->startCluster);
    756 
    757     {
    758         EbmlLoc start;
    759         int i;
    760 
    761         glob->cue_pos = ftello(glob->stream);
    762         Ebml_StartSubElement(glob, &start, Cues);
    763         for(i=0; i<glob->cues; i++)
    764         {
    765             struct cue_entry *cue = &glob->cue_list[i];
    766             EbmlLoc start;
    767 
    768             Ebml_StartSubElement(glob, &start, CuePoint);
    769             {
    770                 EbmlLoc start;
    771 
    772                 Ebml_SerializeUnsigned(glob, CueTime, cue->time);
    773 
    774                 Ebml_StartSubElement(glob, &start, CueTrackPositions);
    775                 Ebml_SerializeUnsigned(glob, CueTrack, 1);
    776                 Ebml_SerializeUnsigned64(glob, CueClusterPosition,
    777                                          cue->loc - glob->position_reference);
    778                 //Ebml_SerializeUnsigned(glob, CueBlockNumber, cue->blockNumber);
    779                 Ebml_EndSubElement(glob, &start);
    780             }
    781             Ebml_EndSubElement(glob, &start);
    782         }
    783         Ebml_EndSubElement(glob, &start);
    784     }
    785 
    786     Ebml_EndSubElement(glob, &glob->startSegment);
    787 
    788     /* Patch up the seek info block */
    789     write_webm_seek_info(glob);
    790 
    791     /* Patch up the track id */
    792     fseeko(glob->stream, glob->track_id_pos, SEEK_SET);
    793     Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash);
    794 
    795     fseeko(glob->stream, 0, SEEK_END);
    796 }
    797 
    798 
    799 /* Murmur hash derived from public domain reference implementation at
    800  *   http://sites.google.com/site/murmurhash/
    801  */
    802 static unsigned int murmur ( const void * key, int len, unsigned int seed )
    803 {
    804     const unsigned int m = 0x5bd1e995;
    805     const int r = 24;
    806 
    807     unsigned int h = seed ^ len;
    808 
    809     const unsigned char * data = (const unsigned char *)key;
    810 
    811     while(len >= 4)
    812     {
    813         unsigned int k;
    814 
    815         k  = data[0];
    816         k |= data[1] << 8;
    817         k |= data[2] << 16;
    818         k |= data[3] << 24;
    819 
    820         k *= m;
    821         k ^= k >> r;
    822         k *= m;
    823 
    824         h *= m;
    825         h ^= k;
    826 
    827         data += 4;
    828         len -= 4;
    829     }
    830 
    831     switch(len)
    832     {
    833     case 3: h ^= data[2] << 16;
    834     case 2: h ^= data[1] << 8;
    835     case 1: h ^= data[0];
    836             h *= m;
    837     };
    838 
    839     h ^= h >> 13;
    840     h *= m;
    841     h ^= h >> 15;
    842 
    843     return h;
    844 }
    845 
    846 #include "math.h"
    847 
    848 static double vp8_mse2psnr(double Samples, double Peak, double Mse)
    849 {
    850     double psnr;
    851 
    852     if ((double)Mse > 0.0)
    853         psnr = 10.0 * log10(Peak * Peak * Samples / Mse);
    854     else
    855         psnr = 60;      // Limit to prevent / 0
    856 
    857     if (psnr > 60)
    858         psnr = 60;
    859 
    860     return psnr;
    861 }
    862 
    863 
    864 #include "args.h"
    865 
    866 static const arg_def_t debugmode = ARG_DEF("D", "debug", 0,
    867         "Debug mode (makes output deterministic)");
    868 static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
    869         "Output filename");
    870 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
    871                                   "Input file is YV12 ");
    872 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
    873                                   "Input file is I420 (default)");
    874 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
    875                                   "Codec to use");
    876 static const arg_def_t passes           = ARG_DEF("p", "passes", 1,
    877         "Number of passes (1/2)");
    878 static const arg_def_t pass_arg         = ARG_DEF(NULL, "pass", 1,
    879         "Pass to execute (1/2)");
    880 static const arg_def_t fpf_name         = ARG_DEF(NULL, "fpf", 1,
    881         "First pass statistics file name");
    882 static const arg_def_t limit = ARG_DEF(NULL, "limit", 1,
    883                                        "Stop encoding after n input frames");
    884 static const arg_def_t deadline         = ARG_DEF("d", "deadline", 1,
    885         "Deadline per frame (usec)");
    886 static const arg_def_t best_dl          = ARG_DEF(NULL, "best", 0,
    887         "Use Best Quality Deadline");
    888 static const arg_def_t good_dl          = ARG_DEF(NULL, "good", 0,
    889         "Use Good Quality Deadline");
    890 static const arg_def_t rt_dl            = ARG_DEF(NULL, "rt", 0,
    891         "Use Realtime Quality Deadline");
    892 static const arg_def_t verbosearg       = ARG_DEF("v", "verbose", 0,
    893         "Show encoder parameters");
    894 static const arg_def_t psnrarg          = ARG_DEF(NULL, "psnr", 0,
    895         "Show PSNR in status line");
    896 static const arg_def_t framerate        = ARG_DEF(NULL, "fps", 1,
    897         "Stream frame rate (rate/scale)");
    898 static const arg_def_t use_ivf          = ARG_DEF(NULL, "ivf", 0,
    899         "Output IVF (default is WebM)");
    900 static const arg_def_t *main_args[] =
    901 {
    902     &debugmode,
    903     &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &deadline,
    904     &best_dl, &good_dl, &rt_dl,
    905     &verbosearg, &psnrarg, &use_ivf, &framerate,
    906     NULL
    907 };
    908 
    909 static const arg_def_t usage            = ARG_DEF("u", "usage", 1,
    910         "Usage profile number to use");
    911 static const arg_def_t threads          = ARG_DEF("t", "threads", 1,
    912         "Max number of threads to use");
    913 static const arg_def_t profile          = ARG_DEF(NULL, "profile", 1,
    914         "Bitstream profile number to use");
    915 static const arg_def_t width            = ARG_DEF("w", "width", 1,
    916         "Frame width");
    917 static const arg_def_t height           = ARG_DEF("h", "height", 1,
    918         "Frame height");
    919 static const arg_def_t timebase         = ARG_DEF(NULL, "timebase", 1,
    920         "Stream timebase (frame duration)");
    921 static const arg_def_t error_resilient  = ARG_DEF(NULL, "error-resilient", 1,
    922         "Enable error resiliency features");
    923 static const arg_def_t lag_in_frames    = ARG_DEF(NULL, "lag-in-frames", 1,
    924         "Max number of frames to lag");
    925 
    926 static const arg_def_t *global_args[] =
    927 {
    928     &use_yv12, &use_i420, &usage, &threads, &profile,
    929     &width, &height, &timebase, &framerate, &error_resilient,
    930     &lag_in_frames, NULL
    931 };
    932 
    933 static const arg_def_t dropframe_thresh   = ARG_DEF(NULL, "drop-frame", 1,
    934         "Temporal resampling threshold (buf %)");
    935 static const arg_def_t resize_allowed     = ARG_DEF(NULL, "resize-allowed", 1,
    936         "Spatial resampling enabled (bool)");
    937 static const arg_def_t resize_up_thresh   = ARG_DEF(NULL, "resize-up", 1,
    938         "Upscale threshold (buf %)");
    939 static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1,
    940         "Downscale threshold (buf %)");
    941 static const struct arg_enum_list end_usage_enum[] = {
    942     {"vbr", VPX_VBR},
    943     {"cbr", VPX_CBR},
    944     {"cq",  VPX_CQ},
    945     {NULL, 0}
    946 };
    947 static const arg_def_t end_usage          = ARG_DEF_ENUM(NULL, "end-usage", 1,
    948         "Rate control mode", end_usage_enum);
    949 static const arg_def_t target_bitrate     = ARG_DEF(NULL, "target-bitrate", 1,
    950         "Bitrate (kbps)");
    951 static const arg_def_t min_quantizer      = ARG_DEF(NULL, "min-q", 1,
    952         "Minimum (best) quantizer");
    953 static const arg_def_t max_quantizer      = ARG_DEF(NULL, "max-q", 1,
    954         "Maximum (worst) quantizer");
    955 static const arg_def_t undershoot_pct     = ARG_DEF(NULL, "undershoot-pct", 1,
    956         "Datarate undershoot (min) target (%)");
    957 static const arg_def_t overshoot_pct      = ARG_DEF(NULL, "overshoot-pct", 1,
    958         "Datarate overshoot (max) target (%)");
    959 static const arg_def_t buf_sz             = ARG_DEF(NULL, "buf-sz", 1,
    960         "Client buffer size (ms)");
    961 static const arg_def_t buf_initial_sz     = ARG_DEF(NULL, "buf-initial-sz", 1,
    962         "Client initial buffer size (ms)");
    963 static const arg_def_t buf_optimal_sz     = ARG_DEF(NULL, "buf-optimal-sz", 1,
    964         "Client optimal buffer size (ms)");
    965 static const arg_def_t *rc_args[] =
    966 {
    967     &dropframe_thresh, &resize_allowed, &resize_up_thresh, &resize_down_thresh,
    968     &end_usage, &target_bitrate, &min_quantizer, &max_quantizer,
    969     &undershoot_pct, &overshoot_pct, &buf_sz, &buf_initial_sz, &buf_optimal_sz,
    970     NULL
    971 };
    972 
    973 
    974 static const arg_def_t bias_pct = ARG_DEF(NULL, "bias-pct", 1,
    975                                   "CBR/VBR bias (0=CBR, 100=VBR)");
    976 static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1,
    977                                         "GOP min bitrate (% of target)");
    978 static const arg_def_t maxsection_pct = ARG_DEF(NULL, "maxsection-pct", 1,
    979                                         "GOP max bitrate (% of target)");
    980 static const arg_def_t *rc_twopass_args[] =
    981 {
    982     &bias_pct, &minsection_pct, &maxsection_pct, NULL
    983 };
    984 
    985 
    986 static const arg_def_t kf_min_dist = ARG_DEF(NULL, "kf-min-dist", 1,
    987                                      "Minimum keyframe interval (frames)");
    988 static const arg_def_t kf_max_dist = ARG_DEF(NULL, "kf-max-dist", 1,
    989                                      "Maximum keyframe interval (frames)");
    990 static const arg_def_t kf_disabled = ARG_DEF(NULL, "disable-kf", 0,
    991                                      "Disable keyframe placement");
    992 static const arg_def_t *kf_args[] =
    993 {
    994     &kf_min_dist, &kf_max_dist, &kf_disabled, NULL
    995 };
    996 
    997 
    998 #if CONFIG_VP8_ENCODER
    999 static const arg_def_t noise_sens = ARG_DEF(NULL, "noise-sensitivity", 1,
   1000                                     "Noise sensitivity (frames to blur)");
   1001 static const arg_def_t sharpness = ARG_DEF(NULL, "sharpness", 1,
   1002                                    "Filter sharpness (0-7)");
   1003 static const arg_def_t static_thresh = ARG_DEF(NULL, "static-thresh", 1,
   1004                                        "Motion detection threshold");
   1005 #endif
   1006 
   1007 #if CONFIG_VP8_ENCODER
   1008 static const arg_def_t cpu_used = ARG_DEF(NULL, "cpu-used", 1,
   1009                                   "CPU Used (-16..16)");
   1010 #endif
   1011 
   1012 
   1013 #if CONFIG_VP8_ENCODER
   1014 static const arg_def_t token_parts = ARG_DEF(NULL, "token-parts", 1,
   1015                                      "Number of token partitions to use, log2");
   1016 static const arg_def_t auto_altref = ARG_DEF(NULL, "auto-alt-ref", 1,
   1017                                      "Enable automatic alt reference frames");
   1018 static const arg_def_t arnr_maxframes = ARG_DEF(NULL, "arnr-maxframes", 1,
   1019                                         "AltRef Max Frames");
   1020 static const arg_def_t arnr_strength = ARG_DEF(NULL, "arnr-strength", 1,
   1021                                        "AltRef Strength");
   1022 static const arg_def_t arnr_type = ARG_DEF(NULL, "arnr-type", 1,
   1023                                    "AltRef Type");
   1024 static const struct arg_enum_list tuning_enum[] = {
   1025     {"psnr", VP8_TUNE_PSNR},
   1026     {"ssim", VP8_TUNE_SSIM},
   1027     {NULL, 0}
   1028 };
   1029 static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1,
   1030                                    "Material to favor", tuning_enum);
   1031 static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1,
   1032                                    "Constrained Quality Level");
   1033 
   1034 static const arg_def_t *vp8_args[] =
   1035 {
   1036     &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh,
   1037     &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type,
   1038     &tune_ssim, &cq_level, NULL
   1039 };
   1040 static const int vp8_arg_ctrl_map[] =
   1041 {
   1042     VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
   1043     VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
   1044     VP8E_SET_TOKEN_PARTITIONS,
   1045     VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH , VP8E_SET_ARNR_TYPE,
   1046     VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, 0
   1047 };
   1048 #endif
   1049 
   1050 static const arg_def_t *no_args[] = { NULL };
   1051 
   1052 static void usage_exit()
   1053 {
   1054     int i;
   1055 
   1056     fprintf(stderr, "Usage: %s <options> -o dst_filename src_filename \n",
   1057             exec_name);
   1058 
   1059     fprintf(stderr, "\nOptions:\n");
   1060     arg_show_usage(stdout, main_args);
   1061     fprintf(stderr, "\nEncoder Global Options:\n");
   1062     arg_show_usage(stdout, global_args);
   1063     fprintf(stderr, "\nRate Control Options:\n");
   1064     arg_show_usage(stdout, rc_args);
   1065     fprintf(stderr, "\nTwopass Rate Control Options:\n");
   1066     arg_show_usage(stdout, rc_twopass_args);
   1067     fprintf(stderr, "\nKeyframe Placement Options:\n");
   1068     arg_show_usage(stdout, kf_args);
   1069 #if CONFIG_VP8_ENCODER
   1070     fprintf(stderr, "\nVP8 Specific Options:\n");
   1071     arg_show_usage(stdout, vp8_args);
   1072 #endif
   1073     fprintf(stderr, "\n"
   1074            "Included encoders:\n"
   1075            "\n");
   1076 
   1077     for (i = 0; i < sizeof(codecs) / sizeof(codecs[0]); i++)
   1078         fprintf(stderr, "    %-6s - %s\n",
   1079                codecs[i].name,
   1080                vpx_codec_iface_name(codecs[i].iface));
   1081 
   1082     exit(EXIT_FAILURE);
   1083 }
   1084 
   1085 #define ARG_CTRL_CNT_MAX 10
   1086 
   1087 
   1088 int main(int argc, const char **argv_)
   1089 {
   1090     vpx_codec_ctx_t        encoder;
   1091     const char                  *in_fn = NULL, *out_fn = NULL, *stats_fn = NULL;
   1092     int                    i;
   1093     FILE                  *infile, *outfile;
   1094     vpx_codec_enc_cfg_t    cfg;
   1095     vpx_codec_err_t        res;
   1096     int                    pass, one_pass_only = 0;
   1097     stats_io_t             stats;
   1098     vpx_image_t            raw;
   1099     const struct codec_item  *codec = codecs;
   1100     int                    frame_avail, got_data;
   1101 
   1102     struct arg               arg;
   1103     char                   **argv, **argi, **argj;
   1104     int                      arg_usage = 0, arg_passes = 1, arg_deadline = 0;
   1105     int                      arg_ctrls[ARG_CTRL_CNT_MAX][2], arg_ctrl_cnt = 0;
   1106     int                      arg_limit = 0;
   1107     static const arg_def_t **ctrl_args = no_args;
   1108     static const int        *ctrl_args_map = NULL;
   1109     int                      verbose = 0, show_psnr = 0;
   1110     int                      arg_use_i420 = 1;
   1111     unsigned long            cx_time = 0;
   1112     unsigned int             file_type, fourcc;
   1113     y4m_input                y4m;
   1114     struct vpx_rational      arg_framerate = {30, 1};
   1115     int                      arg_have_framerate = 0;
   1116     int                      write_webm = 1;
   1117     EbmlGlobal               ebml = {0};
   1118     uint32_t                 hash = 0;
   1119     uint64_t                 psnr_sse_total = 0;
   1120     uint64_t                 psnr_samples_total = 0;
   1121     double                   psnr_totals[4] = {0, 0, 0, 0};
   1122     int                      psnr_count = 0;
   1123 
   1124     exec_name = argv_[0];
   1125     ebml.last_pts_ms = -1;
   1126 
   1127     if (argc < 3)
   1128         usage_exit();
   1129 
   1130 
   1131     /* First parse the codec and usage values, because we want to apply other
   1132      * parameters on top of the default configuration provided by the codec.
   1133      */
   1134     argv = argv_dup(argc - 1, argv_ + 1);
   1135 
   1136     for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
   1137     {
   1138         arg.argv_step = 1;
   1139 
   1140         if (arg_match(&arg, &codecarg, argi))
   1141         {
   1142             int j, k = -1;
   1143 
   1144             for (j = 0; j < sizeof(codecs) / sizeof(codecs[0]); j++)
   1145                 if (!strcmp(codecs[j].name, arg.val))
   1146                     k = j;
   1147 
   1148             if (k >= 0)
   1149                 codec = codecs + k;
   1150             else
   1151                 die("Error: Unrecognized argument (%s) to --codec\n",
   1152                     arg.val);
   1153 
   1154         }
   1155         else if (arg_match(&arg, &passes, argi))
   1156         {
   1157             arg_passes = arg_parse_uint(&arg);
   1158 
   1159             if (arg_passes < 1 || arg_passes > 2)
   1160                 die("Error: Invalid number of passes (%d)\n", arg_passes);
   1161         }
   1162         else if (arg_match(&arg, &pass_arg, argi))
   1163         {
   1164             one_pass_only = arg_parse_uint(&arg);
   1165 
   1166             if (one_pass_only < 1 || one_pass_only > 2)
   1167                 die("Error: Invalid pass selected (%d)\n", one_pass_only);
   1168         }
   1169         else if (arg_match(&arg, &fpf_name, argi))
   1170             stats_fn = arg.val;
   1171         else if (arg_match(&arg, &usage, argi))
   1172             arg_usage = arg_parse_uint(&arg);
   1173         else if (arg_match(&arg, &deadline, argi))
   1174             arg_deadline = arg_parse_uint(&arg);
   1175         else if (arg_match(&arg, &best_dl, argi))
   1176             arg_deadline = VPX_DL_BEST_QUALITY;
   1177         else if (arg_match(&arg, &good_dl, argi))
   1178             arg_deadline = VPX_DL_GOOD_QUALITY;
   1179         else if (arg_match(&arg, &rt_dl, argi))
   1180             arg_deadline = VPX_DL_REALTIME;
   1181         else if (arg_match(&arg, &use_yv12, argi))
   1182         {
   1183             arg_use_i420 = 0;
   1184         }
   1185         else if (arg_match(&arg, &use_i420, argi))
   1186         {
   1187             arg_use_i420 = 1;
   1188         }
   1189         else if (arg_match(&arg, &verbosearg, argi))
   1190             verbose = 1;
   1191         else if (arg_match(&arg, &limit, argi))
   1192             arg_limit = arg_parse_uint(&arg);
   1193         else if (arg_match(&arg, &psnrarg, argi))
   1194             show_psnr = 1;
   1195         else if (arg_match(&arg, &framerate, argi))
   1196         {
   1197             arg_framerate = arg_parse_rational(&arg);
   1198             arg_have_framerate = 1;
   1199         }
   1200         else if (arg_match(&arg, &use_ivf, argi))
   1201             write_webm = 0;
   1202         else if (arg_match(&arg, &outputfile, argi))
   1203             out_fn = arg.val;
   1204         else if (arg_match(&arg, &debugmode, argi))
   1205             ebml.debug = 1;
   1206         else
   1207             argj++;
   1208     }
   1209 
   1210     /* Ensure that --passes and --pass are consistent. If --pass is set and --passes=2,
   1211      * ensure --fpf was set.
   1212      */
   1213     if (one_pass_only)
   1214     {
   1215         /* DWIM: Assume the user meant passes=2 if pass=2 is specified */
   1216         if (one_pass_only > arg_passes)
   1217         {
   1218             fprintf(stderr, "Warning: Assuming --pass=%d implies --passes=%d\n",
   1219                    one_pass_only, one_pass_only);
   1220             arg_passes = one_pass_only;
   1221         }
   1222 
   1223         if (arg_passes == 2 && !stats_fn)
   1224             die("Must specify --fpf when --pass=%d and --passes=2\n", one_pass_only);
   1225     }
   1226 
   1227     /* Populate encoder configuration */
   1228     res = vpx_codec_enc_config_default(codec->iface, &cfg, arg_usage);
   1229 
   1230     if (res)
   1231     {
   1232         fprintf(stderr, "Failed to get config: %s\n",
   1233                 vpx_codec_err_to_string(res));
   1234         return EXIT_FAILURE;
   1235     }
   1236 
   1237     /* Change the default timebase to a high enough value so that the encoder
   1238      * will always create strictly increasing timestamps.
   1239      */
   1240     cfg.g_timebase.den = 1000;
   1241 
   1242     /* Never use the library's default resolution, require it be parsed
   1243      * from the file or set on the command line.
   1244      */
   1245     cfg.g_w = 0;
   1246     cfg.g_h = 0;
   1247 
   1248     /* Now parse the remainder of the parameters. */
   1249     for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
   1250     {
   1251         arg.argv_step = 1;
   1252 
   1253         if (0);
   1254         else if (arg_match(&arg, &threads, argi))
   1255             cfg.g_threads = arg_parse_uint(&arg);
   1256         else if (arg_match(&arg, &profile, argi))
   1257             cfg.g_profile = arg_parse_uint(&arg);
   1258         else if (arg_match(&arg, &width, argi))
   1259             cfg.g_w = arg_parse_uint(&arg);
   1260         else if (arg_match(&arg, &height, argi))
   1261             cfg.g_h = arg_parse_uint(&arg);
   1262         else if (arg_match(&arg, &timebase, argi))
   1263             cfg.g_timebase = arg_parse_rational(&arg);
   1264         else if (arg_match(&arg, &error_resilient, argi))
   1265             cfg.g_error_resilient = arg_parse_uint(&arg);
   1266         else if (arg_match(&arg, &lag_in_frames, argi))
   1267             cfg.g_lag_in_frames = arg_parse_uint(&arg);
   1268         else if (arg_match(&arg, &dropframe_thresh, argi))
   1269             cfg.rc_dropframe_thresh = arg_parse_uint(&arg);
   1270         else if (arg_match(&arg, &resize_allowed, argi))
   1271             cfg.rc_resize_allowed = arg_parse_uint(&arg);
   1272         else if (arg_match(&arg, &resize_up_thresh, argi))
   1273             cfg.rc_resize_up_thresh = arg_parse_uint(&arg);
   1274         else if (arg_match(&arg, &resize_down_thresh, argi))
   1275             cfg.rc_resize_down_thresh = arg_parse_uint(&arg);
   1276         else if (arg_match(&arg, &resize_down_thresh, argi))
   1277             cfg.rc_resize_down_thresh = arg_parse_uint(&arg);
   1278         else if (arg_match(&arg, &end_usage, argi))
   1279             cfg.rc_end_usage = arg_parse_enum_or_int(&arg);
   1280         else if (arg_match(&arg, &target_bitrate, argi))
   1281             cfg.rc_target_bitrate = arg_parse_uint(&arg);
   1282         else if (arg_match(&arg, &min_quantizer, argi))
   1283             cfg.rc_min_quantizer = arg_parse_uint(&arg);
   1284         else if (arg_match(&arg, &max_quantizer, argi))
   1285             cfg.rc_max_quantizer = arg_parse_uint(&arg);
   1286         else if (arg_match(&arg, &undershoot_pct, argi))
   1287             cfg.rc_undershoot_pct = arg_parse_uint(&arg);
   1288         else if (arg_match(&arg, &overshoot_pct, argi))
   1289             cfg.rc_overshoot_pct = arg_parse_uint(&arg);
   1290         else if (arg_match(&arg, &buf_sz, argi))
   1291             cfg.rc_buf_sz = arg_parse_uint(&arg);
   1292         else if (arg_match(&arg, &buf_initial_sz, argi))
   1293             cfg.rc_buf_initial_sz = arg_parse_uint(&arg);
   1294         else if (arg_match(&arg, &buf_optimal_sz, argi))
   1295             cfg.rc_buf_optimal_sz = arg_parse_uint(&arg);
   1296         else if (arg_match(&arg, &bias_pct, argi))
   1297         {
   1298             cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg);
   1299 
   1300             if (arg_passes < 2)
   1301                 fprintf(stderr,
   1302                         "Warning: option %s ignored in one-pass mode.\n",
   1303                         arg.name);
   1304         }
   1305         else if (arg_match(&arg, &minsection_pct, argi))
   1306         {
   1307             cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg);
   1308 
   1309             if (arg_passes < 2)
   1310                 fprintf(stderr,
   1311                         "Warning: option %s ignored in one-pass mode.\n",
   1312                         arg.name);
   1313         }
   1314         else if (arg_match(&arg, &maxsection_pct, argi))
   1315         {
   1316             cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg);
   1317 
   1318             if (arg_passes < 2)
   1319                 fprintf(stderr,
   1320                         "Warning: option %s ignored in one-pass mode.\n",
   1321                         arg.name);
   1322         }
   1323         else if (arg_match(&arg, &kf_min_dist, argi))
   1324             cfg.kf_min_dist = arg_parse_uint(&arg);
   1325         else if (arg_match(&arg, &kf_max_dist, argi))
   1326             cfg.kf_max_dist = arg_parse_uint(&arg);
   1327         else if (arg_match(&arg, &kf_disabled, argi))
   1328             cfg.kf_mode = VPX_KF_DISABLED;
   1329         else
   1330             argj++;
   1331     }
   1332 
   1333     /* Handle codec specific options */
   1334 #if CONFIG_VP8_ENCODER
   1335 
   1336     if (codec->iface == &vpx_codec_vp8_cx_algo)
   1337     {
   1338         ctrl_args = vp8_args;
   1339         ctrl_args_map = vp8_arg_ctrl_map;
   1340     }
   1341 
   1342 #endif
   1343 
   1344     for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
   1345     {
   1346         int match = 0;
   1347 
   1348         arg.argv_step = 1;
   1349 
   1350         for (i = 0; ctrl_args[i]; i++)
   1351         {
   1352             if (arg_match(&arg, ctrl_args[i], argi))
   1353             {
   1354                 match = 1;
   1355 
   1356                 if (arg_ctrl_cnt < ARG_CTRL_CNT_MAX)
   1357                 {
   1358                     arg_ctrls[arg_ctrl_cnt][0] = ctrl_args_map[i];
   1359                     arg_ctrls[arg_ctrl_cnt][1] = arg_parse_enum_or_int(&arg);
   1360                     arg_ctrl_cnt++;
   1361                 }
   1362             }
   1363         }
   1364 
   1365         if (!match)
   1366             argj++;
   1367     }
   1368 
   1369     /* Check for unrecognized options */
   1370     for (argi = argv; *argi; argi++)
   1371         if (argi[0][0] == '-' && argi[0][1])
   1372             die("Error: Unrecognized option %s\n", *argi);
   1373 
   1374     /* Handle non-option arguments */
   1375     in_fn = argv[0];
   1376 
   1377     if (!in_fn)
   1378         usage_exit();
   1379 
   1380     if(!out_fn)
   1381         die("Error: Output file is required (specify with -o)\n");
   1382 
   1383     memset(&stats, 0, sizeof(stats));
   1384 
   1385     for (pass = one_pass_only ? one_pass_only - 1 : 0; pass < arg_passes; pass++)
   1386     {
   1387         int frames_in = 0, frames_out = 0;
   1388         unsigned long nbytes = 0;
   1389         struct detect_buffer detect;
   1390 
   1391         /* Parse certain options from the input file, if possible */
   1392         infile = strcmp(in_fn, "-") ? fopen(in_fn, "rb")
   1393                                     : set_binary_mode(stdin);
   1394 
   1395         if (!infile)
   1396         {
   1397             fprintf(stderr, "Failed to open input file\n");
   1398             return EXIT_FAILURE;
   1399         }
   1400 
   1401         /* For RAW input sources, these bytes will applied on the first frame
   1402          *  in read_frame().
   1403          */
   1404         detect.buf_read = fread(detect.buf, 1, 4, infile);
   1405         detect.position = 0;
   1406 
   1407         if (detect.buf_read == 4 && file_is_y4m(infile, &y4m, detect.buf))
   1408         {
   1409             if (y4m_input_open(&y4m, infile, detect.buf, 4) >= 0)
   1410             {
   1411                 file_type = FILE_TYPE_Y4M;
   1412                 cfg.g_w = y4m.pic_w;
   1413                 cfg.g_h = y4m.pic_h;
   1414 
   1415                 /* Use the frame rate from the file only if none was specified
   1416                  * on the command-line.
   1417                  */
   1418                 if (!arg_have_framerate)
   1419                 {
   1420                     arg_framerate.num = y4m.fps_n;
   1421                     arg_framerate.den = y4m.fps_d;
   1422                 }
   1423 
   1424                 arg_use_i420 = 0;
   1425             }
   1426             else
   1427             {
   1428                 fprintf(stderr, "Unsupported Y4M stream.\n");
   1429                 return EXIT_FAILURE;
   1430             }
   1431         }
   1432         else if (detect.buf_read == 4 &&
   1433                  file_is_ivf(infile, &fourcc, &cfg.g_w, &cfg.g_h, &detect))
   1434         {
   1435             file_type = FILE_TYPE_IVF;
   1436             switch (fourcc)
   1437             {
   1438             case 0x32315659:
   1439                 arg_use_i420 = 0;
   1440                 break;
   1441             case 0x30323449:
   1442                 arg_use_i420 = 1;
   1443                 break;
   1444             default:
   1445                 fprintf(stderr, "Unsupported fourcc (%08x) in IVF\n", fourcc);
   1446                 return EXIT_FAILURE;
   1447             }
   1448         }
   1449         else
   1450         {
   1451             file_type = FILE_TYPE_RAW;
   1452         }
   1453 
   1454         if(!cfg.g_w || !cfg.g_h)
   1455         {
   1456             fprintf(stderr, "Specify stream dimensions with --width (-w) "
   1457                             " and --height (-h).\n");
   1458             return EXIT_FAILURE;
   1459         }
   1460 
   1461 #define SHOW(field) fprintf(stderr, "    %-28s = %d\n", #field, cfg.field)
   1462 
   1463         if (verbose && pass == 0)
   1464         {
   1465             fprintf(stderr, "Codec: %s\n", vpx_codec_iface_name(codec->iface));
   1466             fprintf(stderr, "Source file: %s Format: %s\n", in_fn,
   1467                     arg_use_i420 ? "I420" : "YV12");
   1468             fprintf(stderr, "Destination file: %s\n", out_fn);
   1469             fprintf(stderr, "Encoder parameters:\n");
   1470 
   1471             SHOW(g_usage);
   1472             SHOW(g_threads);
   1473             SHOW(g_profile);
   1474             SHOW(g_w);
   1475             SHOW(g_h);
   1476             SHOW(g_timebase.num);
   1477             SHOW(g_timebase.den);
   1478             SHOW(g_error_resilient);
   1479             SHOW(g_pass);
   1480             SHOW(g_lag_in_frames);
   1481             SHOW(rc_dropframe_thresh);
   1482             SHOW(rc_resize_allowed);
   1483             SHOW(rc_resize_up_thresh);
   1484             SHOW(rc_resize_down_thresh);
   1485             SHOW(rc_end_usage);
   1486             SHOW(rc_target_bitrate);
   1487             SHOW(rc_min_quantizer);
   1488             SHOW(rc_max_quantizer);
   1489             SHOW(rc_undershoot_pct);
   1490             SHOW(rc_overshoot_pct);
   1491             SHOW(rc_buf_sz);
   1492             SHOW(rc_buf_initial_sz);
   1493             SHOW(rc_buf_optimal_sz);
   1494             SHOW(rc_2pass_vbr_bias_pct);
   1495             SHOW(rc_2pass_vbr_minsection_pct);
   1496             SHOW(rc_2pass_vbr_maxsection_pct);
   1497             SHOW(kf_mode);
   1498             SHOW(kf_min_dist);
   1499             SHOW(kf_max_dist);
   1500         }
   1501 
   1502         if(pass == (one_pass_only ? one_pass_only - 1 : 0)) {
   1503             if (file_type == FILE_TYPE_Y4M)
   1504                 /*The Y4M reader does its own allocation.
   1505                   Just initialize this here to avoid problems if we never read any
   1506                    frames.*/
   1507                 memset(&raw, 0, sizeof(raw));
   1508             else
   1509                 vpx_img_alloc(&raw, arg_use_i420 ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_YV12,
   1510                               cfg.g_w, cfg.g_h, 1);
   1511         }
   1512 
   1513         outfile = strcmp(out_fn, "-") ? fopen(out_fn, "wb")
   1514                                       : set_binary_mode(stdout);
   1515 
   1516         if (!outfile)
   1517         {
   1518             fprintf(stderr, "Failed to open output file\n");
   1519             return EXIT_FAILURE;
   1520         }
   1521 
   1522         if(write_webm && fseek(outfile, 0, SEEK_CUR))
   1523         {
   1524             fprintf(stderr, "WebM output to pipes not supported.\n");
   1525             return EXIT_FAILURE;
   1526         }
   1527 
   1528         if (stats_fn)
   1529         {
   1530             if (!stats_open_file(&stats, stats_fn, pass))
   1531             {
   1532                 fprintf(stderr, "Failed to open statistics store\n");
   1533                 return EXIT_FAILURE;
   1534             }
   1535         }
   1536         else
   1537         {
   1538             if (!stats_open_mem(&stats, pass))
   1539             {
   1540                 fprintf(stderr, "Failed to open statistics store\n");
   1541                 return EXIT_FAILURE;
   1542             }
   1543         }
   1544 
   1545         cfg.g_pass = arg_passes == 2
   1546                      ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS
   1547                  : VPX_RC_ONE_PASS;
   1548 #if VPX_ENCODER_ABI_VERSION > (1 + VPX_CODEC_ABI_VERSION)
   1549 
   1550         if (pass)
   1551         {
   1552             cfg.rc_twopass_stats_in = stats_get(&stats);
   1553         }
   1554 
   1555 #endif
   1556 
   1557         if(write_webm)
   1558         {
   1559             ebml.stream = outfile;
   1560             write_webm_file_header(&ebml, &cfg, &arg_framerate);
   1561         }
   1562         else
   1563             write_ivf_file_header(outfile, &cfg, codec->fourcc, 0);
   1564 
   1565 
   1566         /* Construct Encoder Context */
   1567         vpx_codec_enc_init(&encoder, codec->iface, &cfg,
   1568                            show_psnr ? VPX_CODEC_USE_PSNR : 0);
   1569         ctx_exit_on_error(&encoder, "Failed to initialize encoder");
   1570 
   1571         /* Note that we bypass the vpx_codec_control wrapper macro because
   1572          * we're being clever to store the control IDs in an array. Real
   1573          * applications will want to make use of the enumerations directly
   1574          */
   1575         for (i = 0; i < arg_ctrl_cnt; i++)
   1576         {
   1577             if (vpx_codec_control_(&encoder, arg_ctrls[i][0], arg_ctrls[i][1]))
   1578                 fprintf(stderr, "Error: Tried to set control %d = %d\n",
   1579                         arg_ctrls[i][0], arg_ctrls[i][1]);
   1580 
   1581             ctx_exit_on_error(&encoder, "Failed to control codec");
   1582         }
   1583 
   1584         frame_avail = 1;
   1585         got_data = 0;
   1586 
   1587         while (frame_avail || got_data)
   1588         {
   1589             vpx_codec_iter_t iter = NULL;
   1590             const vpx_codec_cx_pkt_t *pkt;
   1591             struct vpx_usec_timer timer;
   1592             int64_t frame_start, next_frame_start;
   1593 
   1594             if (!arg_limit || frames_in < arg_limit)
   1595             {
   1596                 frame_avail = read_frame(infile, &raw, file_type, &y4m,
   1597                                          &detect);
   1598 
   1599                 if (frame_avail)
   1600                     frames_in++;
   1601 
   1602                 fprintf(stderr,
   1603                         "\rPass %d/%d frame %4d/%-4d %7ldB \033[K", pass + 1,
   1604                         arg_passes, frames_in, frames_out, nbytes);
   1605             }
   1606             else
   1607                 frame_avail = 0;
   1608 
   1609             vpx_usec_timer_start(&timer);
   1610 
   1611             frame_start = (cfg.g_timebase.den * (int64_t)(frames_in - 1)
   1612                           * arg_framerate.den) / cfg.g_timebase.num / arg_framerate.num;
   1613             next_frame_start = (cfg.g_timebase.den * (int64_t)(frames_in)
   1614                                 * arg_framerate.den)
   1615                                 / cfg.g_timebase.num / arg_framerate.num;
   1616             vpx_codec_encode(&encoder, frame_avail ? &raw : NULL, frame_start,
   1617                              next_frame_start - frame_start,
   1618                              0, arg_deadline);
   1619             vpx_usec_timer_mark(&timer);
   1620             cx_time += vpx_usec_timer_elapsed(&timer);
   1621             ctx_exit_on_error(&encoder, "Failed to encode frame");
   1622             got_data = 0;
   1623 
   1624             while ((pkt = vpx_codec_get_cx_data(&encoder, &iter)))
   1625             {
   1626                 got_data = 1;
   1627 
   1628                 switch (pkt->kind)
   1629                 {
   1630                 case VPX_CODEC_CX_FRAME_PKT:
   1631                     frames_out++;
   1632                     fprintf(stderr, " %6luF",
   1633                             (unsigned long)pkt->data.frame.sz);
   1634 
   1635                     if(write_webm)
   1636                     {
   1637                         /* Update the hash */
   1638                         if(!ebml.debug)
   1639                             hash = murmur(pkt->data.frame.buf,
   1640                                           pkt->data.frame.sz, hash);
   1641 
   1642                         write_webm_block(&ebml, &cfg, pkt);
   1643                     }
   1644                     else
   1645                     {
   1646                         write_ivf_frame_header(outfile, pkt);
   1647                         if(fwrite(pkt->data.frame.buf, 1,
   1648                                   pkt->data.frame.sz, outfile));
   1649                     }
   1650                     nbytes += pkt->data.raw.sz;
   1651                     break;
   1652                 case VPX_CODEC_STATS_PKT:
   1653                     frames_out++;
   1654                     fprintf(stderr, " %6luS",
   1655                            (unsigned long)pkt->data.twopass_stats.sz);
   1656                     stats_write(&stats,
   1657                                 pkt->data.twopass_stats.buf,
   1658                                 pkt->data.twopass_stats.sz);
   1659                     nbytes += pkt->data.raw.sz;
   1660                     break;
   1661                 case VPX_CODEC_PSNR_PKT:
   1662 
   1663                     if (show_psnr)
   1664                     {
   1665                         int i;
   1666 
   1667                         psnr_sse_total += pkt->data.psnr.sse[0];
   1668                         psnr_samples_total += pkt->data.psnr.samples[0];
   1669                         for (i = 0; i < 4; i++)
   1670                         {
   1671                             fprintf(stderr, "%.3lf ", pkt->data.psnr.psnr[i]);
   1672                             psnr_totals[i] += pkt->data.psnr.psnr[i];
   1673                         }
   1674                         psnr_count++;
   1675                     }
   1676 
   1677                     break;
   1678                 default:
   1679                     break;
   1680                 }
   1681             }
   1682 
   1683             fflush(stdout);
   1684         }
   1685 
   1686         fprintf(stderr,
   1687                "\rPass %d/%d frame %4d/%-4d %7ldB %7ldb/f %7"PRId64"b/s"
   1688                " %7lu %s (%.2f fps)\033[K", pass + 1,
   1689                arg_passes, frames_in, frames_out, nbytes, nbytes * 8 / frames_in,
   1690                nbytes * 8 *(int64_t)arg_framerate.num / arg_framerate.den / frames_in,
   1691                cx_time > 9999999 ? cx_time / 1000 : cx_time,
   1692                cx_time > 9999999 ? "ms" : "us",
   1693                (float)frames_in * 1000000.0 / (float)cx_time);
   1694 
   1695         if ( (show_psnr) && (psnr_count>0) )
   1696         {
   1697             int i;
   1698             double ovpsnr = vp8_mse2psnr(psnr_samples_total, 255.0,
   1699                                          psnr_sse_total);
   1700 
   1701             fprintf(stderr, "\nPSNR (Overall/Avg/Y/U/V)");
   1702 
   1703             fprintf(stderr, " %.3lf", ovpsnr);
   1704             for (i = 0; i < 4; i++)
   1705             {
   1706                 fprintf(stderr, " %.3lf", psnr_totals[i]/psnr_count);
   1707             }
   1708         }
   1709 
   1710         vpx_codec_destroy(&encoder);
   1711 
   1712         fclose(infile);
   1713 
   1714         if(write_webm)
   1715         {
   1716             write_webm_file_footer(&ebml, hash);
   1717         }
   1718         else
   1719         {
   1720             if (!fseek(outfile, 0, SEEK_SET))
   1721                 write_ivf_file_header(outfile, &cfg, codec->fourcc, frames_out);
   1722         }
   1723 
   1724         fclose(outfile);
   1725         stats_close(&stats, arg_passes-1);
   1726         fprintf(stderr, "\n");
   1727 
   1728         if (one_pass_only)
   1729             break;
   1730     }
   1731 
   1732     vpx_img_free(&raw);
   1733     free(argv);
   1734     return EXIT_SUCCESS;
   1735 }
   1736