• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
die(const char * fmt,...)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 
ctx_exit_on_error(vpx_codec_ctx_t * ctx,const char * s)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 
stats_open_file(stats_io_t * stats,const char * fpf,int pass)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 
stats_open_mem(stats_io_t * stats,int pass)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 
stats_close(stats_io_t * stats,int last_pass)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 
stats_write(stats_io_t * stats,const void * pkt,size_t len)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 
stats_get(stats_io_t * stats)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 */
read_frame(FILE * f,vpx_image_t * img,unsigned int file_type,y4m_input * y4m,struct detect_buffer * detect)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 
file_is_y4m(FILE * infile,y4m_input * y4m,char detect[4])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)
file_is_ivf(FILE * infile,unsigned int * fourcc,unsigned int * width,unsigned int * height,struct detect_buffer * detect)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 
write_ivf_file_header(FILE * outfile,const vpx_codec_enc_cfg_t * cfg,unsigned int fourcc,int frame_cnt)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 
write_ivf_frame_header(FILE * outfile,const vpx_codec_cx_pkt_t * pkt)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 
Ebml_Write(EbmlGlobal * glob,const void * buffer_in,unsigned long len)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 
Ebml_Serialize(EbmlGlobal * glob,const void * buffer_in,unsigned long len)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  */
Ebml_SerializeUnsigned32(EbmlGlobal * glob,unsigned long class_id,uint64_t ui)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
Ebml_StartSubElement(EbmlGlobal * glob,EbmlLoc * ebmlLoc,unsigned long class_id)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
Ebml_EndSubElement(EbmlGlobal * glob,EbmlLoc * ebmlLoc)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
write_webm_seek_element(EbmlGlobal * ebml,unsigned long id,off_t pos)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
write_webm_seek_info(EbmlGlobal * ebml)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
write_webm_file_header(EbmlGlobal * glob,const vpx_codec_enc_cfg_t * cfg,const struct vpx_rational * fps)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
write_webm_block(EbmlGlobal * glob,const vpx_codec_enc_cfg_t * cfg,const vpx_codec_cx_pkt_t * pkt)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
write_webm_file_footer(EbmlGlobal * glob,long hash)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  */
murmur(const void * key,int len,unsigned int seed)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 
vp8_mse2psnr(double Samples,double Peak,double Mse)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 
usage_exit()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 
main(int argc,const char ** argv_)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