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