| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "vpx_config.h" | 11 #include "./vpxenc.h" |
| 12 #include "./vpx_config.h" |
| 12 | 13 |
| 13 #if defined(_WIN32) || defined(__OS2__) || !CONFIG_OS_SUPPORT | 14 #include <assert.h> |
| 14 #define USE_POSIX_MMAP 0 | 15 #include <limits.h> |
| 15 #else | 16 #include <math.h> |
| 16 #define USE_POSIX_MMAP 1 | 17 #include <stdarg.h> |
| 17 #endif | |
| 18 | |
| 19 #include <stdio.h> | 18 #include <stdio.h> |
| 20 #include <stdlib.h> | 19 #include <stdlib.h> |
| 21 #include <stdarg.h> | |
| 22 #include <string.h> | 20 #include <string.h> |
| 23 #include <limits.h> | 21 |
| 24 #include <assert.h> | |
| 25 #include "vpx/vpx_encoder.h" | 22 #include "vpx/vpx_encoder.h" |
| 26 #if CONFIG_DECODERS | 23 #if CONFIG_DECODERS |
| 27 #include "vpx/vpx_decoder.h" | 24 #include "vpx/vpx_decoder.h" |
| 28 #endif | 25 #endif |
| 29 #if USE_POSIX_MMAP | 26 |
| 30 #include <sys/types.h> | 27 #include "third_party/libyuv/include/libyuv/scale.h" |
| 31 #include <sys/stat.h> | 28 #include "./args.h" |
| 32 #include <sys/mman.h> | 29 #include "./ivfdec.h" |
| 33 #include <fcntl.h> | 30 #include "./ivfenc.h" |
| 34 #include <unistd.h> | |
| 35 #endif | |
| 36 | 31 |
| 37 #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER | 32 #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER |
| 38 #include "vpx/vp8cx.h" | 33 #include "vpx/vp8cx.h" |
| 39 #endif | 34 #endif |
| 40 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER | 35 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER |
| 41 #include "vpx/vp8dx.h" | 36 #include "vpx/vp8dx.h" |
| 42 #endif | 37 #endif |
| 43 | 38 |
| 39 #include "./tools_common.h" |
| 44 #include "vpx_ports/mem_ops.h" | 40 #include "vpx_ports/mem_ops.h" |
| 45 #include "vpx_ports/vpx_timer.h" | 41 #include "vpx_ports/vpx_timer.h" |
| 46 #include "tools_common.h" | 42 #include "./vpxstats.h" |
| 47 #include "y4minput.h" | 43 #include "./warnings.h" |
| 48 #include "third_party/libmkv/EbmlWriter.h" | 44 #include "./webmenc.h" |
| 49 #include "third_party/libmkv/EbmlIDs.h" | 45 #include "./y4minput.h" |
| 50 #include "third_party/libyuv/include/libyuv/scale.h" | |
| 51 | |
| 52 /* Need special handling of these functions on Windows */ | |
| 53 #if defined(_MSC_VER) | |
| 54 /* MSVS doesn't define off_t, and uses _f{seek,tell}i64 */ | |
| 55 typedef __int64 off_t; | |
| 56 #define fseeko _fseeki64 | |
| 57 #define ftello _ftelli64 | |
| 58 #elif defined(_WIN32) | |
| 59 /* MinGW defines off_t as long | |
| 60 and uses f{seek,tell}o64/off64_t for large files */ | |
| 61 #define fseeko fseeko64 | |
| 62 #define ftello ftello64 | |
| 63 #define off_t off64_t | |
| 64 #endif | |
| 65 | |
| 66 #define LITERALU64(hi,lo) ((((uint64_t)hi)<<32)|lo) | |
| 67 | |
| 68 /* We should use 32-bit file operations in WebM file format | |
| 69 * when building ARM executable file (.axf) with RVCT */ | |
| 70 #if !CONFIG_OS_SUPPORT | |
| 71 typedef long off_t; | |
| 72 #define fseeko fseek | |
| 73 #define ftello ftell | |
| 74 #endif | |
| 75 | 46 |
| 76 /* Swallow warnings about unused results of fread/fwrite */ | 47 /* Swallow warnings about unused results of fread/fwrite */ |
| 77 static size_t wrap_fread(void *ptr, size_t size, size_t nmemb, | 48 static size_t wrap_fread(void *ptr, size_t size, size_t nmemb, |
| 78 FILE *stream) { | 49 FILE *stream) { |
| 79 return fread(ptr, size, nmemb, stream); | 50 return fread(ptr, size, nmemb, stream); |
| 80 } | 51 } |
| 81 #define fread wrap_fread | 52 #define fread wrap_fread |
| 82 | 53 |
| 83 static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb, | 54 static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb, |
| 84 FILE *stream) { | 55 FILE *stream) { |
| 85 return fwrite(ptr, size, nmemb, stream); | 56 return fwrite(ptr, size, nmemb, stream); |
| 86 } | 57 } |
| 87 #define fwrite wrap_fwrite | 58 #define fwrite wrap_fwrite |
| 88 | 59 |
| 89 | 60 |
| 90 static const char *exec_name; | 61 static const char *exec_name; |
| 91 | 62 |
| 92 #define VP8_FOURCC (0x30385056) | |
| 93 #define VP9_FOURCC (0x30395056) | |
| 94 static const struct codec_item { | 63 static const struct codec_item { |
| 95 char const *name; | 64 char const *name; |
| 96 const vpx_codec_iface_t *(*iface)(void); | 65 const vpx_codec_iface_t *(*iface)(void); |
| 97 const vpx_codec_iface_t *(*dx_iface)(void); | 66 const vpx_codec_iface_t *(*dx_iface)(void); |
| 98 unsigned int fourcc; | 67 unsigned int fourcc; |
| 99 } codecs[] = { | 68 } codecs[] = { |
| 100 #if CONFIG_VP8_ENCODER && CONFIG_VP8_DECODER | 69 #if CONFIG_VP8_ENCODER && CONFIG_VP8_DECODER |
| 101 {"vp8", &vpx_codec_vp8_cx, &vpx_codec_vp8_dx, VP8_FOURCC}, | 70 {"vp8", &vpx_codec_vp8_cx, &vpx_codec_vp8_dx, VP8_FOURCC}, |
| 102 #elif CONFIG_VP8_ENCODER && !CONFIG_VP8_DECODER | 71 #elif CONFIG_VP8_ENCODER && !CONFIG_VP8_DECODER |
| 103 {"vp8", &vpx_codec_vp8_cx, NULL, VP8_FOURCC}, | 72 {"vp8", &vpx_codec_vp8_cx, NULL, VP8_FOURCC}, |
| 104 #endif | 73 #endif |
| 105 #if CONFIG_VP9_ENCODER && CONFIG_VP9_DECODER | 74 #if CONFIG_VP9_ENCODER && CONFIG_VP9_DECODER |
| 106 {"vp9", &vpx_codec_vp9_cx, &vpx_codec_vp9_dx, VP9_FOURCC}, | 75 {"vp9", &vpx_codec_vp9_cx, &vpx_codec_vp9_dx, VP9_FOURCC}, |
| 107 #elif CONFIG_VP9_ENCODER && !CONFIG_VP9_DECODER | 76 #elif CONFIG_VP9_ENCODER && !CONFIG_VP9_DECODER |
| 108 {"vp9", &vpx_codec_vp9_cx, NULL, VP9_FOURCC}, | 77 {"vp9", &vpx_codec_vp9_cx, NULL, VP9_FOURCC}, |
| 109 #endif | 78 #endif |
| 110 }; | 79 }; |
| 111 | 80 |
| 112 static void usage_exit(); | |
| 113 | |
| 114 #define LOG_ERROR(label) do \ | |
| 115 {\ | |
| 116 const char *l=label;\ | |
| 117 va_list ap;\ | |
| 118 va_start(ap, fmt);\ | |
| 119 if(l)\ | |
| 120 fprintf(stderr, "%s: ", l);\ | |
| 121 vfprintf(stderr, fmt, ap);\ | |
| 122 fprintf(stderr, "\n");\ | |
| 123 va_end(ap);\ | |
| 124 } while(0) | |
| 125 | |
| 126 void die(const char *fmt, ...) { | |
| 127 LOG_ERROR(NULL); | |
| 128 usage_exit(); | |
| 129 } | |
| 130 | |
| 131 | |
| 132 void fatal(const char *fmt, ...) { | |
| 133 LOG_ERROR("Fatal"); | |
| 134 exit(EXIT_FAILURE); | |
| 135 } | |
| 136 | |
| 137 | |
| 138 void warn(const char *fmt, ...) { | |
| 139 LOG_ERROR("Warning"); | |
| 140 } | |
| 141 | |
| 142 | |
| 143 static void warn_or_exit_on_errorv(vpx_codec_ctx_t *ctx, int fatal, | 81 static void warn_or_exit_on_errorv(vpx_codec_ctx_t *ctx, int fatal, |
| 144 const char *s, va_list ap) { | 82 const char *s, va_list ap) { |
| 145 if (ctx->err) { | 83 if (ctx->err) { |
| 146 const char *detail = vpx_codec_error_detail(ctx); | 84 const char *detail = vpx_codec_error_detail(ctx); |
| 147 | 85 |
| 148 vfprintf(stderr, s, ap); | 86 vfprintf(stderr, s, ap); |
| 149 fprintf(stderr, ": %s\n", vpx_codec_error(ctx)); | 87 fprintf(stderr, ": %s\n", vpx_codec_error(ctx)); |
| 150 | 88 |
| 151 if (detail) | 89 if (detail) |
| 152 fprintf(stderr, " %s\n", detail); | 90 fprintf(stderr, " %s\n", detail); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 166 | 104 |
| 167 static void warn_or_exit_on_error(vpx_codec_ctx_t *ctx, int fatal, | 105 static void warn_or_exit_on_error(vpx_codec_ctx_t *ctx, int fatal, |
| 168 const char *s, ...) { | 106 const char *s, ...) { |
| 169 va_list ap; | 107 va_list ap; |
| 170 | 108 |
| 171 va_start(ap, s); | 109 va_start(ap, s); |
| 172 warn_or_exit_on_errorv(ctx, fatal, s, ap); | 110 warn_or_exit_on_errorv(ctx, fatal, s, ap); |
| 173 va_end(ap); | 111 va_end(ap); |
| 174 } | 112 } |
| 175 | 113 |
| 176 /* This structure is used to abstract the different ways of handling | 114 int read_frame(struct VpxInputContext *input_ctx, vpx_image_t *img) { |
| 177 * first pass statistics. | 115 FILE *f = input_ctx->file; |
| 178 */ | 116 y4m_input *y4m = &input_ctx->y4m; |
| 179 typedef struct { | |
| 180 vpx_fixed_buf_t buf; | |
| 181 int pass; | |
| 182 FILE *file; | |
| 183 char *buf_ptr; | |
| 184 size_t buf_alloc_sz; | |
| 185 } stats_io_t; | |
| 186 | |
| 187 int stats_open_file(stats_io_t *stats, const char *fpf, int pass) { | |
| 188 int res; | |
| 189 | |
| 190 stats->pass = pass; | |
| 191 | |
| 192 if (pass == 0) { | |
| 193 stats->file = fopen(fpf, "wb"); | |
| 194 stats->buf.sz = 0; | |
| 195 stats->buf.buf = NULL, | |
| 196 res = (stats->file != NULL); | |
| 197 } else { | |
| 198 #if 0 | |
| 199 #elif USE_POSIX_MMAP | |
| 200 struct stat stat_buf; | |
| 201 int fd; | |
| 202 | |
| 203 fd = open(fpf, O_RDONLY); | |
| 204 stats->file = fdopen(fd, "rb"); | |
| 205 fstat(fd, &stat_buf); | |
| 206 stats->buf.sz = stat_buf.st_size; | |
| 207 stats->buf.buf = mmap(NULL, stats->buf.sz, PROT_READ, MAP_PRIVATE, | |
| 208 fd, 0); | |
| 209 res = (stats->buf.buf != NULL); | |
| 210 #else | |
| 211 size_t nbytes; | |
| 212 | |
| 213 stats->file = fopen(fpf, "rb"); | |
| 214 | |
| 215 if (fseek(stats->file, 0, SEEK_END)) | |
| 216 fatal("First-pass stats file must be seekable!"); | |
| 217 | |
| 218 stats->buf.sz = stats->buf_alloc_sz = ftell(stats->file); | |
| 219 rewind(stats->file); | |
| 220 | |
| 221 stats->buf.buf = malloc(stats->buf_alloc_sz); | |
| 222 | |
| 223 if (!stats->buf.buf) | |
| 224 fatal("Failed to allocate first-pass stats buffer (%lu bytes)", | |
| 225 (unsigned long)stats->buf_alloc_sz); | |
| 226 | |
| 227 nbytes = fread(stats->buf.buf, 1, stats->buf.sz, stats->file); | |
| 228 res = (nbytes == stats->buf.sz); | |
| 229 #endif | |
| 230 } | |
| 231 | |
| 232 return res; | |
| 233 } | |
| 234 | |
| 235 int stats_open_mem(stats_io_t *stats, int pass) { | |
| 236 int res; | |
| 237 stats->pass = pass; | |
| 238 | |
| 239 if (!pass) { | |
| 240 stats->buf.sz = 0; | |
| 241 stats->buf_alloc_sz = 64 * 1024; | |
| 242 stats->buf.buf = malloc(stats->buf_alloc_sz); | |
| 243 } | |
| 244 | |
| 245 stats->buf_ptr = stats->buf.buf; | |
| 246 res = (stats->buf.buf != NULL); | |
| 247 return res; | |
| 248 } | |
| 249 | |
| 250 | |
| 251 void stats_close(stats_io_t *stats, int last_pass) { | |
| 252 if (stats->file) { | |
| 253 if (stats->pass == last_pass) { | |
| 254 #if 0 | |
| 255 #elif USE_POSIX_MMAP | |
| 256 munmap(stats->buf.buf, stats->buf.sz); | |
| 257 #else | |
| 258 free(stats->buf.buf); | |
| 259 #endif | |
| 260 } | |
| 261 | |
| 262 fclose(stats->file); | |
| 263 stats->file = NULL; | |
| 264 } else { | |
| 265 if (stats->pass == last_pass) | |
| 266 free(stats->buf.buf); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 void stats_write(stats_io_t *stats, const void *pkt, size_t len) { | |
| 271 if (stats->file) { | |
| 272 (void) fwrite(pkt, 1, len, stats->file); | |
| 273 } else { | |
| 274 if (stats->buf.sz + len > stats->buf_alloc_sz) { | |
| 275 size_t new_sz = stats->buf_alloc_sz + 64 * 1024; | |
| 276 char *new_ptr = realloc(stats->buf.buf, new_sz); | |
| 277 | |
| 278 if (new_ptr) { | |
| 279 stats->buf_ptr = new_ptr + (stats->buf_ptr - (char *)stats->buf.buf); | |
| 280 stats->buf.buf = new_ptr; | |
| 281 stats->buf_alloc_sz = new_sz; | |
| 282 } else | |
| 283 fatal("Failed to realloc firstpass stats buffer."); | |
| 284 } | |
| 285 | |
| 286 memcpy(stats->buf_ptr, pkt, len); | |
| 287 stats->buf.sz += len; | |
| 288 stats->buf_ptr += len; | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 vpx_fixed_buf_t stats_get(stats_io_t *stats) { | |
| 293 return stats->buf; | |
| 294 } | |
| 295 | |
| 296 /* Stereo 3D packed frame format */ | |
| 297 typedef enum stereo_format { | |
| 298 STEREO_FORMAT_MONO = 0, | |
| 299 STEREO_FORMAT_LEFT_RIGHT = 1, | |
| 300 STEREO_FORMAT_BOTTOM_TOP = 2, | |
| 301 STEREO_FORMAT_TOP_BOTTOM = 3, | |
| 302 STEREO_FORMAT_RIGHT_LEFT = 11 | |
| 303 } stereo_format_t; | |
| 304 | |
| 305 enum video_file_type { | |
| 306 FILE_TYPE_RAW, | |
| 307 FILE_TYPE_IVF, | |
| 308 FILE_TYPE_Y4M | |
| 309 }; | |
| 310 | |
| 311 struct detect_buffer { | |
| 312 char buf[4]; | |
| 313 size_t buf_read; | |
| 314 size_t position; | |
| 315 }; | |
| 316 | |
| 317 | |
| 318 struct input_state { | |
| 319 char *fn; | |
| 320 FILE *file; | |
| 321 off_t length; | |
| 322 y4m_input y4m; | |
| 323 struct detect_buffer detect; | |
| 324 enum video_file_type file_type; | |
| 325 unsigned int w; | |
| 326 unsigned int h; | |
| 327 struct vpx_rational framerate; | |
| 328 int use_i420; | |
| 329 int only_i420; | |
| 330 }; | |
| 331 | |
| 332 | |
| 333 #define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */ | |
| 334 static int read_frame(struct input_state *input, vpx_image_t *img) { | |
| 335 FILE *f = input->file; | |
| 336 enum video_file_type file_type = input->file_type; | |
| 337 y4m_input *y4m = &input->y4m; | |
| 338 struct detect_buffer *detect = &input->detect; | |
| 339 int plane = 0; | |
| 340 int shortread = 0; | 117 int shortread = 0; |
| 341 | 118 |
| 342 if (file_type == FILE_TYPE_Y4M) { | 119 if (input_ctx->file_type == FILE_TYPE_Y4M) { |
| 343 if (y4m_input_fetch_frame(y4m, f, img) < 1) | 120 if (y4m_input_fetch_frame(y4m, f, img) < 1) |
| 344 return 0; | 121 return 0; |
| 345 } else { | 122 } else { |
| 346 if (file_type == FILE_TYPE_IVF) { | 123 shortread = read_yuv_frame(input_ctx, img); |
| 347 char junk[IVF_FRAME_HDR_SZ]; | |
| 348 | |
| 349 /* Skip the frame header. We know how big the frame should be. See | |
| 350 * write_ivf_frame_header() for documentation on the frame header | |
| 351 * layout. | |
| 352 */ | |
| 353 (void) fread(junk, 1, IVF_FRAME_HDR_SZ, f); | |
| 354 } | |
| 355 | |
| 356 for (plane = 0; plane < 3; plane++) { | |
| 357 unsigned char *ptr; | |
| 358 int w = (plane ? (1 + img->d_w) / 2 : img->d_w); | |
| 359 int h = (plane ? (1 + img->d_h) / 2 : img->d_h); | |
| 360 int r; | |
| 361 | |
| 362 /* Determine the correct plane based on the image format. The for-loop | |
| 363 * always counts in Y,U,V order, but this may not match the order of | |
| 364 * the data on disk. | |
| 365 */ | |
| 366 switch (plane) { | |
| 367 case 1: | |
| 368 ptr = img->planes[img->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_V : VPX_PLA
NE_U]; | |
| 369 break; | |
| 370 case 2: | |
| 371 ptr = img->planes[img->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_U : VPX_PLA
NE_V]; | |
| 372 break; | |
| 373 default: | |
| 374 ptr = img->planes[plane]; | |
| 375 } | |
| 376 | |
| 377 for (r = 0; r < h; r++) { | |
| 378 size_t needed = w; | |
| 379 size_t buf_position = 0; | |
| 380 const size_t left = detect->buf_read - detect->position; | |
| 381 if (left > 0) { | |
| 382 const size_t more = (left < needed) ? left : needed; | |
| 383 memcpy(ptr, detect->buf + detect->position, more); | |
| 384 buf_position = more; | |
| 385 needed -= more; | |
| 386 detect->position += more; | |
| 387 } | |
| 388 if (needed > 0) { | |
| 389 shortread |= (fread(ptr + buf_position, 1, needed, f) < needed); | |
| 390 } | |
| 391 | |
| 392 ptr += img->stride[plane]; | |
| 393 } | |
| 394 } | |
| 395 } | 124 } |
| 396 | 125 |
| 397 return !shortread; | 126 return !shortread; |
| 398 } | 127 } |
| 399 | 128 |
| 400 | 129 int file_is_y4m(FILE *infile, y4m_input *y4m, const char detect[4]) { |
| 401 unsigned int file_is_y4m(FILE *infile, | |
| 402 y4m_input *y4m, | |
| 403 char detect[4]) { | |
| 404 if (memcmp(detect, "YUV4", 4) == 0) { | 130 if (memcmp(detect, "YUV4", 4) == 0) { |
| 405 return 1; | 131 return 1; |
| 406 } | 132 } |
| 407 return 0; | 133 return 0; |
| 408 } | 134 } |
| 409 | 135 |
| 410 #define IVF_FILE_HDR_SZ (32) | |
| 411 unsigned int file_is_ivf(struct input_state *input, | |
| 412 unsigned int *fourcc) { | |
| 413 char raw_hdr[IVF_FILE_HDR_SZ]; | |
| 414 int is_ivf = 0; | |
| 415 FILE *infile = input->file; | |
| 416 unsigned int *width = &input->w; | |
| 417 unsigned int *height = &input->h; | |
| 418 struct detect_buffer *detect = &input->detect; | |
| 419 | |
| 420 if (memcmp(detect->buf, "DKIF", 4) != 0) | |
| 421 return 0; | |
| 422 | |
| 423 /* See write_ivf_file_header() for more documentation on the file header | |
| 424 * layout. | |
| 425 */ | |
| 426 if (fread(raw_hdr + 4, 1, IVF_FILE_HDR_SZ - 4, infile) | |
| 427 == IVF_FILE_HDR_SZ - 4) { | |
| 428 { | |
| 429 is_ivf = 1; | |
| 430 | |
| 431 if (mem_get_le16(raw_hdr + 4) != 0) | |
| 432 warn("Unrecognized IVF version! This file may not decode " | |
| 433 "properly."); | |
| 434 | |
| 435 *fourcc = mem_get_le32(raw_hdr + 8); | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 if (is_ivf) { | |
| 440 *width = mem_get_le16(raw_hdr + 12); | |
| 441 *height = mem_get_le16(raw_hdr + 14); | |
| 442 detect->position = 4; | |
| 443 } | |
| 444 | |
| 445 return is_ivf; | |
| 446 } | |
| 447 | |
| 448 | |
| 449 static void write_ivf_file_header(FILE *outfile, | |
| 450 const vpx_codec_enc_cfg_t *cfg, | |
| 451 unsigned int fourcc, | |
| 452 int frame_cnt) { | |
| 453 char header[32]; | |
| 454 | |
| 455 if (cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) | |
| 456 return; | |
| 457 | |
| 458 header[0] = 'D'; | |
| 459 header[1] = 'K'; | |
| 460 header[2] = 'I'; | |
| 461 header[3] = 'F'; | |
| 462 mem_put_le16(header + 4, 0); /* version */ | |
| 463 mem_put_le16(header + 6, 32); /* headersize */ | |
| 464 mem_put_le32(header + 8, fourcc); /* headersize */ | |
| 465 mem_put_le16(header + 12, cfg->g_w); /* width */ | |
| 466 mem_put_le16(header + 14, cfg->g_h); /* height */ | |
| 467 mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */ | |
| 468 mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */ | |
| 469 mem_put_le32(header + 24, frame_cnt); /* length */ | |
| 470 mem_put_le32(header + 28, 0); /* unused */ | |
| 471 | |
| 472 (void) fwrite(header, 1, 32, outfile); | |
| 473 } | |
| 474 | |
| 475 | |
| 476 static void write_ivf_frame_header(FILE *outfile, | |
| 477 const vpx_codec_cx_pkt_t *pkt) { | |
| 478 char header[12]; | |
| 479 vpx_codec_pts_t pts; | |
| 480 | |
| 481 if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) | |
| 482 return; | |
| 483 | |
| 484 pts = pkt->data.frame.pts; | |
| 485 mem_put_le32(header, (int)pkt->data.frame.sz); | |
| 486 mem_put_le32(header + 4, pts & 0xFFFFFFFF); | |
| 487 mem_put_le32(header + 8, pts >> 32); | |
| 488 | |
| 489 (void) fwrite(header, 1, 12, outfile); | |
| 490 } | |
| 491 | |
| 492 static void write_ivf_frame_size(FILE *outfile, size_t size) { | |
| 493 char header[4]; | |
| 494 mem_put_le32(header, (int)size); | |
| 495 (void) fwrite(header, 1, 4, outfile); | |
| 496 } | |
| 497 | |
| 498 | |
| 499 typedef off_t EbmlLoc; | |
| 500 | |
| 501 | |
| 502 struct cue_entry { | |
| 503 unsigned int time; | |
| 504 uint64_t loc; | |
| 505 }; | |
| 506 | |
| 507 | |
| 508 struct EbmlGlobal { | |
| 509 int debug; | |
| 510 | |
| 511 FILE *stream; | |
| 512 int64_t last_pts_ms; | |
| 513 vpx_rational_t framerate; | |
| 514 | |
| 515 /* These pointers are to the start of an element */ | |
| 516 off_t position_reference; | |
| 517 off_t seek_info_pos; | |
| 518 off_t segment_info_pos; | |
| 519 off_t track_pos; | |
| 520 off_t cue_pos; | |
| 521 off_t cluster_pos; | |
| 522 | |
| 523 /* This pointer is to a specific element to be serialized */ | |
| 524 off_t track_id_pos; | |
| 525 | |
| 526 /* These pointers are to the size field of the element */ | |
| 527 EbmlLoc startSegment; | |
| 528 EbmlLoc startCluster; | |
| 529 | |
| 530 uint32_t cluster_timecode; | |
| 531 int cluster_open; | |
| 532 | |
| 533 struct cue_entry *cue_list; | |
| 534 unsigned int cues; | |
| 535 | |
| 536 }; | |
| 537 | |
| 538 | |
| 539 void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) { | |
| 540 (void) fwrite(buffer_in, 1, len, glob->stream); | |
| 541 } | |
| 542 | |
| 543 #define WRITE_BUFFER(s) \ | |
| 544 for(i = len-1; i>=0; i--)\ | |
| 545 { \ | |
| 546 x = (char)(*(const s *)buffer_in >> (i * CHAR_BIT)); \ | |
| 547 Ebml_Write(glob, &x, 1); \ | |
| 548 } | |
| 549 void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, un
signed long len) { | |
| 550 char x; | |
| 551 int i; | |
| 552 | |
| 553 /* buffer_size: | |
| 554 * 1 - int8_t; | |
| 555 * 2 - int16_t; | |
| 556 * 3 - int32_t; | |
| 557 * 4 - int64_t; | |
| 558 */ | |
| 559 switch (buffer_size) { | |
| 560 case 1: | |
| 561 WRITE_BUFFER(int8_t) | |
| 562 break; | |
| 563 case 2: | |
| 564 WRITE_BUFFER(int16_t) | |
| 565 break; | |
| 566 case 4: | |
| 567 WRITE_BUFFER(int32_t) | |
| 568 break; | |
| 569 case 8: | |
| 570 WRITE_BUFFER(int64_t) | |
| 571 break; | |
| 572 default: | |
| 573 break; | |
| 574 } | |
| 575 } | |
| 576 #undef WRITE_BUFFER | |
| 577 | |
| 578 /* Need a fixed size serializer for the track ID. libmkv provides a 64 bit | |
| 579 * one, but not a 32 bit one. | |
| 580 */ | |
| 581 static void Ebml_SerializeUnsigned32(EbmlGlobal *glob, unsigned long class_id, u
int64_t ui) { | |
| 582 unsigned char sizeSerialized = 4 | 0x80; | |
| 583 Ebml_WriteID(glob, class_id); | |
| 584 Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1); | |
| 585 Ebml_Serialize(glob, &ui, sizeof(ui), 4); | |
| 586 } | |
| 587 | |
| 588 | |
| 589 static void | |
| 590 Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, | |
| 591 unsigned long class_id) { | |
| 592 /* todo this is always taking 8 bytes, this may need later optimization */ | |
| 593 /* this is a key that says length unknown */ | |
| 594 uint64_t unknownLen = LITERALU64(0x01FFFFFF, 0xFFFFFFFF); | |
| 595 | |
| 596 Ebml_WriteID(glob, class_id); | |
| 597 *ebmlLoc = ftello(glob->stream); | |
| 598 Ebml_Serialize(glob, &unknownLen, sizeof(unknownLen), 8); | |
| 599 } | |
| 600 | |
| 601 static void | |
| 602 Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) { | |
| 603 off_t pos; | |
| 604 uint64_t size; | |
| 605 | |
| 606 /* Save the current stream pointer */ | |
| 607 pos = ftello(glob->stream); | |
| 608 | |
| 609 /* Calculate the size of this element */ | |
| 610 size = pos - *ebmlLoc - 8; | |
| 611 size |= LITERALU64(0x01000000, 0x00000000); | |
| 612 | |
| 613 /* Seek back to the beginning of the element and write the new size */ | |
| 614 fseeko(glob->stream, *ebmlLoc, SEEK_SET); | |
| 615 Ebml_Serialize(glob, &size, sizeof(size), 8); | |
| 616 | |
| 617 /* Reset the stream pointer */ | |
| 618 fseeko(glob->stream, pos, SEEK_SET); | |
| 619 } | |
| 620 | |
| 621 | |
| 622 static void | |
| 623 write_webm_seek_element(EbmlGlobal *ebml, unsigned long id, off_t pos) { | |
| 624 uint64_t offset = pos - ebml->position_reference; | |
| 625 EbmlLoc start; | |
| 626 Ebml_StartSubElement(ebml, &start, Seek); | |
| 627 Ebml_SerializeBinary(ebml, SeekID, id); | |
| 628 Ebml_SerializeUnsigned64(ebml, SeekPosition, offset); | |
| 629 Ebml_EndSubElement(ebml, &start); | |
| 630 } | |
| 631 | |
| 632 | |
| 633 static void | |
| 634 write_webm_seek_info(EbmlGlobal *ebml) { | |
| 635 | |
| 636 off_t pos; | |
| 637 | |
| 638 /* Save the current stream pointer */ | |
| 639 pos = ftello(ebml->stream); | |
| 640 | |
| 641 if (ebml->seek_info_pos) | |
| 642 fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET); | |
| 643 else | |
| 644 ebml->seek_info_pos = pos; | |
| 645 | |
| 646 { | |
| 647 EbmlLoc start; | |
| 648 | |
| 649 Ebml_StartSubElement(ebml, &start, SeekHead); | |
| 650 write_webm_seek_element(ebml, Tracks, ebml->track_pos); | |
| 651 write_webm_seek_element(ebml, Cues, ebml->cue_pos); | |
| 652 write_webm_seek_element(ebml, Info, ebml->segment_info_pos); | |
| 653 Ebml_EndSubElement(ebml, &start); | |
| 654 } | |
| 655 { | |
| 656 /* segment info */ | |
| 657 EbmlLoc startInfo; | |
| 658 uint64_t frame_time; | |
| 659 char version_string[64]; | |
| 660 | |
| 661 /* Assemble version string */ | |
| 662 if (ebml->debug) | |
| 663 strcpy(version_string, "vpxenc"); | |
| 664 else { | |
| 665 strcpy(version_string, "vpxenc "); | |
| 666 strncat(version_string, | |
| 667 vpx_codec_version_str(), | |
| 668 sizeof(version_string) - 1 - strlen(version_string)); | |
| 669 } | |
| 670 | |
| 671 frame_time = (uint64_t)1000 * ebml->framerate.den | |
| 672 / ebml->framerate.num; | |
| 673 ebml->segment_info_pos = ftello(ebml->stream); | |
| 674 Ebml_StartSubElement(ebml, &startInfo, Info); | |
| 675 Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000); | |
| 676 Ebml_SerializeFloat(ebml, Segment_Duration, | |
| 677 (double)(ebml->last_pts_ms + frame_time)); | |
| 678 Ebml_SerializeString(ebml, 0x4D80, version_string); | |
| 679 Ebml_SerializeString(ebml, 0x5741, version_string); | |
| 680 Ebml_EndSubElement(ebml, &startInfo); | |
| 681 } | |
| 682 } | |
| 683 | |
| 684 | |
| 685 static void | |
| 686 write_webm_file_header(EbmlGlobal *glob, | |
| 687 const vpx_codec_enc_cfg_t *cfg, | |
| 688 const struct vpx_rational *fps, | |
| 689 stereo_format_t stereo_fmt, | |
| 690 unsigned int fourcc) { | |
| 691 { | |
| 692 EbmlLoc start; | |
| 693 Ebml_StartSubElement(glob, &start, EBML); | |
| 694 Ebml_SerializeUnsigned(glob, EBMLVersion, 1); | |
| 695 Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); | |
| 696 Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); | |
| 697 Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); | |
| 698 Ebml_SerializeString(glob, DocType, "webm"); | |
| 699 Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); | |
| 700 Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); | |
| 701 Ebml_EndSubElement(glob, &start); | |
| 702 } | |
| 703 { | |
| 704 Ebml_StartSubElement(glob, &glob->startSegment, Segment); | |
| 705 glob->position_reference = ftello(glob->stream); | |
| 706 glob->framerate = *fps; | |
| 707 write_webm_seek_info(glob); | |
| 708 | |
| 709 { | |
| 710 EbmlLoc trackStart; | |
| 711 glob->track_pos = ftello(glob->stream); | |
| 712 Ebml_StartSubElement(glob, &trackStart, Tracks); | |
| 713 { | |
| 714 unsigned int trackNumber = 1; | |
| 715 uint64_t trackID = 0; | |
| 716 | |
| 717 EbmlLoc start; | |
| 718 Ebml_StartSubElement(glob, &start, TrackEntry); | |
| 719 Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); | |
| 720 glob->track_id_pos = ftello(glob->stream); | |
| 721 Ebml_SerializeUnsigned32(glob, TrackUID, trackID); | |
| 722 Ebml_SerializeUnsigned(glob, TrackType, 1); | |
| 723 Ebml_SerializeString(glob, CodecID, | |
| 724 fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9"); | |
| 725 { | |
| 726 unsigned int pixelWidth = cfg->g_w; | |
| 727 unsigned int pixelHeight = cfg->g_h; | |
| 728 | |
| 729 EbmlLoc videoStart; | |
| 730 Ebml_StartSubElement(glob, &videoStart, Video); | |
| 731 Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); | |
| 732 Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); | |
| 733 Ebml_SerializeUnsigned(glob, StereoMode, stereo_fmt); | |
| 734 Ebml_EndSubElement(glob, &videoStart); | |
| 735 } | |
| 736 Ebml_EndSubElement(glob, &start); /* Track Entry */ | |
| 737 } | |
| 738 Ebml_EndSubElement(glob, &trackStart); | |
| 739 } | |
| 740 /* segment element is open */ | |
| 741 } | |
| 742 } | |
| 743 | |
| 744 | |
| 745 static void | |
| 746 write_webm_block(EbmlGlobal *glob, | |
| 747 const vpx_codec_enc_cfg_t *cfg, | |
| 748 const vpx_codec_cx_pkt_t *pkt) { | |
| 749 unsigned long block_length; | |
| 750 unsigned char track_number; | |
| 751 unsigned short block_timecode = 0; | |
| 752 unsigned char flags; | |
| 753 int64_t pts_ms; | |
| 754 int start_cluster = 0, is_keyframe; | |
| 755 | |
| 756 /* Calculate the PTS of this frame in milliseconds */ | |
| 757 pts_ms = pkt->data.frame.pts * 1000 | |
| 758 * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den; | |
| 759 if (pts_ms <= glob->last_pts_ms) | |
| 760 pts_ms = glob->last_pts_ms + 1; | |
| 761 glob->last_pts_ms = pts_ms; | |
| 762 | |
| 763 /* Calculate the relative time of this block */ | |
| 764 if (pts_ms - glob->cluster_timecode > SHRT_MAX) | |
| 765 start_cluster = 1; | |
| 766 else | |
| 767 block_timecode = (unsigned short)pts_ms - glob->cluster_timecode; | |
| 768 | |
| 769 is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY); | |
| 770 if (start_cluster || is_keyframe) { | |
| 771 if (glob->cluster_open) | |
| 772 Ebml_EndSubElement(glob, &glob->startCluster); | |
| 773 | |
| 774 /* Open the new cluster */ | |
| 775 block_timecode = 0; | |
| 776 glob->cluster_open = 1; | |
| 777 glob->cluster_timecode = (uint32_t)pts_ms; | |
| 778 glob->cluster_pos = ftello(glob->stream); | |
| 779 Ebml_StartSubElement(glob, &glob->startCluster, Cluster); /* cluster */ | |
| 780 Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode); | |
| 781 | |
| 782 /* Save a cue point if this is a keyframe. */ | |
| 783 if (is_keyframe) { | |
| 784 struct cue_entry *cue, *new_cue_list; | |
| 785 | |
| 786 new_cue_list = realloc(glob->cue_list, | |
| 787 (glob->cues + 1) * sizeof(struct cue_entry)); | |
| 788 if (new_cue_list) | |
| 789 glob->cue_list = new_cue_list; | |
| 790 else | |
| 791 fatal("Failed to realloc cue list."); | |
| 792 | |
| 793 cue = &glob->cue_list[glob->cues]; | |
| 794 cue->time = glob->cluster_timecode; | |
| 795 cue->loc = glob->cluster_pos; | |
| 796 glob->cues++; | |
| 797 } | |
| 798 } | |
| 799 | |
| 800 /* Write the Simple Block */ | |
| 801 Ebml_WriteID(glob, SimpleBlock); | |
| 802 | |
| 803 block_length = (unsigned long)pkt->data.frame.sz + 4; | |
| 804 block_length |= 0x10000000; | |
| 805 Ebml_Serialize(glob, &block_length, sizeof(block_length), 4); | |
| 806 | |
| 807 track_number = 1; | |
| 808 track_number |= 0x80; | |
| 809 Ebml_Write(glob, &track_number, 1); | |
| 810 | |
| 811 Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2); | |
| 812 | |
| 813 flags = 0; | |
| 814 if (is_keyframe) | |
| 815 flags |= 0x80; | |
| 816 if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) | |
| 817 flags |= 0x08; | |
| 818 Ebml_Write(glob, &flags, 1); | |
| 819 | |
| 820 Ebml_Write(glob, pkt->data.frame.buf, (unsigned long)pkt->data.frame.sz); | |
| 821 } | |
| 822 | |
| 823 | |
| 824 static void | |
| 825 write_webm_file_footer(EbmlGlobal *glob, long hash) { | |
| 826 | |
| 827 if (glob->cluster_open) | |
| 828 Ebml_EndSubElement(glob, &glob->startCluster); | |
| 829 | |
| 830 { | |
| 831 EbmlLoc start; | |
| 832 unsigned int i; | |
| 833 | |
| 834 glob->cue_pos = ftello(glob->stream); | |
| 835 Ebml_StartSubElement(glob, &start, Cues); | |
| 836 for (i = 0; i < glob->cues; i++) { | |
| 837 struct cue_entry *cue = &glob->cue_list[i]; | |
| 838 EbmlLoc start; | |
| 839 | |
| 840 Ebml_StartSubElement(glob, &start, CuePoint); | |
| 841 { | |
| 842 EbmlLoc start; | |
| 843 | |
| 844 Ebml_SerializeUnsigned(glob, CueTime, cue->time); | |
| 845 | |
| 846 Ebml_StartSubElement(glob, &start, CueTrackPositions); | |
| 847 Ebml_SerializeUnsigned(glob, CueTrack, 1); | |
| 848 Ebml_SerializeUnsigned64(glob, CueClusterPosition, | |
| 849 cue->loc - glob->position_reference); | |
| 850 Ebml_EndSubElement(glob, &start); | |
| 851 } | |
| 852 Ebml_EndSubElement(glob, &start); | |
| 853 } | |
| 854 Ebml_EndSubElement(glob, &start); | |
| 855 } | |
| 856 | |
| 857 Ebml_EndSubElement(glob, &glob->startSegment); | |
| 858 | |
| 859 /* Patch up the seek info block */ | |
| 860 write_webm_seek_info(glob); | |
| 861 | |
| 862 /* Patch up the track id */ | |
| 863 fseeko(glob->stream, glob->track_id_pos, SEEK_SET); | |
| 864 Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash); | |
| 865 | |
| 866 fseeko(glob->stream, 0, SEEK_END); | |
| 867 } | |
| 868 | |
| 869 | 136 |
| 870 /* Murmur hash derived from public domain reference implementation at | 137 /* Murmur hash derived from public domain reference implementation at |
| 871 * http:// sites.google.com/site/murmurhash/ | 138 * http:// sites.google.com/site/murmurhash/ |
| 872 */ | 139 */ |
| 873 static unsigned int murmur(const void *key, int len, unsigned int seed) { | 140 static unsigned int murmur(const void *key, int len, unsigned int seed) { |
| 874 const unsigned int m = 0x5bd1e995; | 141 const unsigned int m = 0x5bd1e995; |
| 875 const int r = 24; | 142 const int r = 24; |
| 876 | 143 |
| 877 unsigned int h = seed ^ len; | 144 unsigned int h = seed ^ len; |
| 878 | 145 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 907 h *= m; | 174 h *= m; |
| 908 }; | 175 }; |
| 909 | 176 |
| 910 h ^= h >> 13; | 177 h ^= h >> 13; |
| 911 h *= m; | 178 h *= m; |
| 912 h ^= h >> 15; | 179 h ^= h >> 15; |
| 913 | 180 |
| 914 return h; | 181 return h; |
| 915 } | 182 } |
| 916 | 183 |
| 917 #include "math.h" | |
| 918 #define MAX_PSNR 100 | |
| 919 static double vp8_mse2psnr(double Samples, double Peak, double Mse) { | |
| 920 double psnr; | |
| 921 | 184 |
| 922 if ((double)Mse > 0.0) | |
| 923 psnr = 10.0 * log10(Peak * Peak * Samples / Mse); | |
| 924 else | |
| 925 psnr = MAX_PSNR; /* Limit to prevent / 0 */ | |
| 926 | |
| 927 if (psnr > MAX_PSNR) | |
| 928 psnr = MAX_PSNR; | |
| 929 | |
| 930 return psnr; | |
| 931 } | |
| 932 | |
| 933 | |
| 934 #include "args.h" | |
| 935 static const arg_def_t debugmode = ARG_DEF("D", "debug", 0, | 185 static const arg_def_t debugmode = ARG_DEF("D", "debug", 0, |
| 936 "Debug mode (makes output determinist
ic)"); | 186 "Debug mode (makes output determinist
ic)"); |
| 937 static const arg_def_t outputfile = ARG_DEF("o", "output", 1, | 187 static const arg_def_t outputfile = ARG_DEF("o", "output", 1, |
| 938 "Output filename"); | 188 "Output filename"); |
| 939 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, | 189 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, |
| 940 "Input file is YV12 "); | 190 "Input file is YV12 "); |
| 941 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, | 191 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, |
| 942 "Input file is I420 (default)"); | 192 "Input file is I420 (default)"); |
| 943 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, | 193 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, |
| 944 "Codec to use"); | 194 "Codec to use"); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 959 static const arg_def_t good_dl = ARG_DEF(NULL, "good", 0, | 209 static const arg_def_t good_dl = ARG_DEF(NULL, "good", 0, |
| 960 "Use Good Quality Deadline"); | 210 "Use Good Quality Deadline"); |
| 961 static const arg_def_t rt_dl = ARG_DEF(NULL, "rt", 0, | 211 static const arg_def_t rt_dl = ARG_DEF(NULL, "rt", 0, |
| 962 "Use Realtime Quality Deadline
"); | 212 "Use Realtime Quality Deadline
"); |
| 963 static const arg_def_t quietarg = ARG_DEF("q", "quiet", 0, | 213 static const arg_def_t quietarg = ARG_DEF("q", "quiet", 0, |
| 964 "Do not print encode progress"
); | 214 "Do not print encode progress"
); |
| 965 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, | 215 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, |
| 966 "Show encoder parameters"); | 216 "Show encoder parameters"); |
| 967 static const arg_def_t psnrarg = ARG_DEF(NULL, "psnr", 0, | 217 static const arg_def_t psnrarg = ARG_DEF(NULL, "psnr", 0, |
| 968 "Show PSNR in status line"); | 218 "Show PSNR in status line"); |
| 969 enum TestDecodeFatality { | 219 |
| 970 TEST_DECODE_OFF, | |
| 971 TEST_DECODE_FATAL, | |
| 972 TEST_DECODE_WARN, | |
| 973 }; | |
| 974 static const struct arg_enum_list test_decode_enum[] = { | 220 static const struct arg_enum_list test_decode_enum[] = { |
| 975 {"off", TEST_DECODE_OFF}, | 221 {"off", TEST_DECODE_OFF}, |
| 976 {"fatal", TEST_DECODE_FATAL}, | 222 {"fatal", TEST_DECODE_FATAL}, |
| 977 {"warn", TEST_DECODE_WARN}, | 223 {"warn", TEST_DECODE_WARN}, |
| 978 {NULL, 0} | 224 {NULL, 0} |
| 979 }; | 225 }; |
| 980 static const arg_def_t recontest = ARG_DEF_ENUM(NULL, "test-decode", 1, | 226 static const arg_def_t recontest = ARG_DEF_ENUM(NULL, "test-decode", 1, |
| 981 "Test encode/decode mismatch", | 227 "Test encode/decode mismatch", |
| 982 test_decode_enum); | 228 test_decode_enum); |
| 983 static const arg_def_t framerate = ARG_DEF(NULL, "fps", 1, | 229 static const arg_def_t framerate = ARG_DEF(NULL, "fps", 1, |
| 984 "Stream frame rate (rate/scale
)"); | 230 "Stream frame rate (rate/scale
)"); |
| 985 static const arg_def_t use_ivf = ARG_DEF(NULL, "ivf", 0, | 231 static const arg_def_t use_ivf = ARG_DEF(NULL, "ivf", 0, |
| 986 "Output IVF (default is WebM)"
); | 232 "Output IVF (default is WebM)"
); |
| 987 static const arg_def_t out_part = ARG_DEF("P", "output-partitions", 0, | 233 static const arg_def_t out_part = ARG_DEF("P", "output-partitions", 0, |
| 988 "Makes encoder output partitions. Requ
ires IVF output!"); | 234 "Makes encoder output partitions. Requ
ires IVF output!"); |
| 989 static const arg_def_t q_hist_n = ARG_DEF(NULL, "q-hist", 1, | 235 static const arg_def_t q_hist_n = ARG_DEF(NULL, "q-hist", 1, |
| 990 "Show quantizer histogram (n-b
uckets)"); | 236 "Show quantizer histogram (n-b
uckets)"); |
| 991 static const arg_def_t rate_hist_n = ARG_DEF(NULL, "rate-hist", 1, | 237 static const arg_def_t rate_hist_n = ARG_DEF(NULL, "rate-hist", 1, |
| 992 "Show rate histogram (n-buc
kets)"); | 238 "Show rate histogram (n-buc
kets)"); |
| 239 static const arg_def_t disable_warnings = |
| 240 ARG_DEF(NULL, "disable-warnings", 0, |
| 241 "Disable warnings about potentially incorrect encode settings."); |
| 242 static const arg_def_t disable_warning_prompt = |
| 243 ARG_DEF("y", "disable-warning-prompt", 0, |
| 244 "Display warnings, but do not prompt user to continue."); |
| 245 |
| 993 static const arg_def_t *main_args[] = { | 246 static const arg_def_t *main_args[] = { |
| 994 &debugmode, | 247 &debugmode, |
| 995 &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &skip, | 248 &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &skip, |
| 996 &deadline, &best_dl, &good_dl, &rt_dl, | 249 &deadline, &best_dl, &good_dl, &rt_dl, |
| 997 &quietarg, &verbosearg, &psnrarg, &use_ivf, &out_part, &q_hist_n, &rate_hist_n
, | 250 &quietarg, &verbosearg, &psnrarg, &use_ivf, &out_part, &q_hist_n, |
| 251 &rate_hist_n, &disable_warnings, &disable_warning_prompt, |
| 998 NULL | 252 NULL |
| 999 }; | 253 }; |
| 1000 | 254 |
| 1001 static const arg_def_t usage = ARG_DEF("u", "usage", 1, | 255 static const arg_def_t usage = ARG_DEF("u", "usage", 1, |
| 1002 "Usage profile number to use")
; | 256 "Usage profile number to use")
; |
| 1003 static const arg_def_t threads = ARG_DEF("t", "threads", 1, | 257 static const arg_def_t threads = ARG_DEF("t", "threads", 1, |
| 1004 "Max number of threads to use"
); | 258 "Max number of threads to use"
); |
| 1005 static const arg_def_t profile = ARG_DEF(NULL, "profile", 1, | 259 static const arg_def_t profile = ARG_DEF(NULL, "profile", 1, |
| 1006 "Bitstream profile number to u
se"); | 260 "Bitstream profile number to u
se"); |
| 1007 static const arg_def_t width = ARG_DEF("w", "width", 1, | 261 static const arg_def_t width = ARG_DEF("w", "width", 1, |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1125 static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1, | 379 static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1, |
| 1126 "Material to favor", tuning_enum
); | 380 "Material to favor", tuning_enum
); |
| 1127 static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1, | 381 static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1, |
| 1128 "Constant/Constrained Quality level"); | 382 "Constant/Constrained Quality level"); |
| 1129 static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1, | 383 static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1, |
| 1130 "Max I-frame bitrate (pct)")
; | 384 "Max I-frame bitrate (pct)")
; |
| 1131 static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode"); | 385 static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode"); |
| 1132 #if CONFIG_VP9_ENCODER | 386 #if CONFIG_VP9_ENCODER |
| 1133 static const arg_def_t frame_parallel_decoding = ARG_DEF( | 387 static const arg_def_t frame_parallel_decoding = ARG_DEF( |
| 1134 NULL, "frame-parallel", 1, "Enable frame parallel decodability features"); | 388 NULL, "frame-parallel", 1, "Enable frame parallel decodability features"); |
| 389 static const arg_def_t aq_mode = ARG_DEF( |
| 390 NULL, "aq-mode", 1, |
| 391 "Adaptive q mode (0: off (by default), 1: variance 2: complexity)"); |
| 1135 #endif | 392 #endif |
| 1136 | 393 |
| 1137 #if CONFIG_VP8_ENCODER | 394 #if CONFIG_VP8_ENCODER |
| 1138 static const arg_def_t *vp8_args[] = { | 395 static const arg_def_t *vp8_args[] = { |
| 1139 &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, | 396 &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, |
| 1140 &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type, | 397 &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type, |
| 1141 &tune_ssim, &cq_level, &max_intra_rate_pct, | 398 &tune_ssim, &cq_level, &max_intra_rate_pct, |
| 1142 NULL | 399 NULL |
| 1143 }; | 400 }; |
| 1144 static const int vp8_arg_ctrl_map[] = { | 401 static const int vp8_arg_ctrl_map[] = { |
| 1145 VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, | 402 VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, |
| 1146 VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, | 403 VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, |
| 1147 VP8E_SET_TOKEN_PARTITIONS, | 404 VP8E_SET_TOKEN_PARTITIONS, |
| 1148 VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE, | 405 VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE, |
| 1149 VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, | 406 VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, |
| 1150 0 | 407 0 |
| 1151 }; | 408 }; |
| 1152 #endif | 409 #endif |
| 1153 | 410 |
| 1154 #if CONFIG_VP9_ENCODER | 411 #if CONFIG_VP9_ENCODER |
| 1155 static const arg_def_t *vp9_args[] = { | 412 static const arg_def_t *vp9_args[] = { |
| 1156 &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, | 413 &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, |
| 1157 &tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type, | 414 &tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type, |
| 1158 &tune_ssim, &cq_level, &max_intra_rate_pct, &lossless, | 415 &tune_ssim, &cq_level, &max_intra_rate_pct, &lossless, |
| 1159 &frame_parallel_decoding, | 416 &frame_parallel_decoding, &aq_mode, |
| 1160 NULL | 417 NULL |
| 1161 }; | 418 }; |
| 1162 static const int vp9_arg_ctrl_map[] = { | 419 static const int vp9_arg_ctrl_map[] = { |
| 1163 VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, | 420 VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, |
| 1164 VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, | 421 VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, |
| 1165 VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS, | 422 VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS, |
| 1166 VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE, | 423 VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE, |
| 1167 VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, | 424 VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, |
| 1168 VP9E_SET_LOSSLESS, VP9E_SET_FRAME_PARALLEL_DECODING, | 425 VP9E_SET_LOSSLESS, VP9E_SET_FRAME_PARALLEL_DECODING, VP9E_SET_AQ_MODE, |
| 1169 0 | 426 0 |
| 1170 }; | 427 }; |
| 1171 #endif | 428 #endif |
| 1172 | 429 |
| 1173 static const arg_def_t *no_args[] = { NULL }; | 430 static const arg_def_t *no_args[] = { NULL }; |
| 1174 | 431 |
| 1175 static void usage_exit() { | 432 void usage_exit() { |
| 1176 int i; | 433 int i; |
| 1177 | 434 |
| 1178 fprintf(stderr, "Usage: %s <options> -o dst_filename src_filename \n", | 435 fprintf(stderr, "Usage: %s <options> -o dst_filename src_filename \n", |
| 1179 exec_name); | 436 exec_name); |
| 1180 | 437 |
| 1181 fprintf(stderr, "\nOptions:\n"); | 438 fprintf(stderr, "\nOptions:\n"); |
| 1182 arg_show_usage(stderr, main_args); | 439 arg_show_usage(stderr, main_args); |
| 1183 fprintf(stderr, "\nEncoder Global Options:\n"); | 440 fprintf(stderr, "\nEncoder Global Options:\n"); |
| 1184 arg_show_usage(stderr, global_args); | 441 arg_show_usage(stderr, global_args); |
| 1185 fprintf(stderr, "\nRate Control Options:\n"); | 442 fprintf(stderr, "\nRate Control Options:\n"); |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1378 struct rate_hist { | 635 struct rate_hist { |
| 1379 int64_t *pts; | 636 int64_t *pts; |
| 1380 int *sz; | 637 int *sz; |
| 1381 int samples; | 638 int samples; |
| 1382 int frames; | 639 int frames; |
| 1383 struct hist_bucket bucket[RATE_BINS]; | 640 struct hist_bucket bucket[RATE_BINS]; |
| 1384 int total; | 641 int total; |
| 1385 }; | 642 }; |
| 1386 | 643 |
| 1387 | 644 |
| 1388 static void init_rate_histogram(struct rate_hist *hist, | 645 static void init_rate_histogram(struct rate_hist *hist, |
| 1389 const vpx_codec_enc_cfg_t *cfg, | 646 const vpx_codec_enc_cfg_t *cfg, |
| 1390 const vpx_rational_t *fps) { | 647 const vpx_rational_t *fps) { |
| 1391 int i; | 648 int i; |
| 1392 | 649 |
| 1393 /* Determine the number of samples in the buffer. Use the file's framerate | 650 /* Determine the number of samples in the buffer. Use the file's framerate |
| 1394 * to determine the number of frames in rc_buf_sz milliseconds, with an | 651 * to determine the number of frames in rc_buf_sz milliseconds, with an |
| 1395 * adjustment (5/4) to account for alt-refs | 652 * adjustment (5/4) to account for alt-refs |
| 1396 */ | 653 */ |
| 1397 hist->samples = cfg->rc_buf_sz * 5 / 4 * fps->num / fps->den / 1000; | 654 hist->samples = cfg->rc_buf_sz * 5 / 4 * fps->num / fps->den / 1000; |
| 1398 | 655 |
| 1399 /* prevent division by zero */ | 656 /* prevent division by zero */ |
| 1400 if (hist->samples == 0) | 657 if (hist->samples == 0) |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1598 #define MAX(x,y) ((x)>(y)?(x):(y)) | 855 #define MAX(x,y) ((x)>(y)?(x):(y)) |
| 1599 #if CONFIG_VP8_ENCODER && !CONFIG_VP9_ENCODER | 856 #if CONFIG_VP8_ENCODER && !CONFIG_VP9_ENCODER |
| 1600 #define ARG_CTRL_CNT_MAX NELEMENTS(vp8_arg_ctrl_map) | 857 #define ARG_CTRL_CNT_MAX NELEMENTS(vp8_arg_ctrl_map) |
| 1601 #elif !CONFIG_VP8_ENCODER && CONFIG_VP9_ENCODER | 858 #elif !CONFIG_VP8_ENCODER && CONFIG_VP9_ENCODER |
| 1602 #define ARG_CTRL_CNT_MAX NELEMENTS(vp9_arg_ctrl_map) | 859 #define ARG_CTRL_CNT_MAX NELEMENTS(vp9_arg_ctrl_map) |
| 1603 #else | 860 #else |
| 1604 #define ARG_CTRL_CNT_MAX MAX(NELEMENTS(vp8_arg_ctrl_map), \ | 861 #define ARG_CTRL_CNT_MAX MAX(NELEMENTS(vp8_arg_ctrl_map), \ |
| 1605 NELEMENTS(vp9_arg_ctrl_map)) | 862 NELEMENTS(vp9_arg_ctrl_map)) |
| 1606 #endif | 863 #endif |
| 1607 | 864 |
| 1608 /* Configuration elements common to all streams */ | |
| 1609 struct global_config { | |
| 1610 const struct codec_item *codec; | |
| 1611 int passes; | |
| 1612 int pass; | |
| 1613 int usage; | |
| 1614 int deadline; | |
| 1615 int use_i420; | |
| 1616 int quiet; | |
| 1617 int verbose; | |
| 1618 int limit; | |
| 1619 int skip_frames; | |
| 1620 int show_psnr; | |
| 1621 enum TestDecodeFatality test_decode; | |
| 1622 int have_framerate; | |
| 1623 struct vpx_rational framerate; | |
| 1624 int out_part; | |
| 1625 int debug; | |
| 1626 int show_q_hist_buckets; | |
| 1627 int show_rate_hist_buckets; | |
| 1628 }; | |
| 1629 | |
| 1630 | |
| 1631 /* Per-stream configuration */ | 865 /* Per-stream configuration */ |
| 1632 struct stream_config { | 866 struct stream_config { |
| 1633 struct vpx_codec_enc_cfg cfg; | 867 struct vpx_codec_enc_cfg cfg; |
| 1634 const char *out_fn; | 868 const char *out_fn; |
| 1635 const char *stats_fn; | 869 const char *stats_fn; |
| 1636 stereo_format_t stereo_fmt; | 870 stereo_format_t stereo_fmt; |
| 1637 int arg_ctrls[ARG_CTRL_CNT_MAX][2]; | 871 int arg_ctrls[ARG_CTRL_CNT_MAX][2]; |
| 1638 int arg_ctrl_cnt; | 872 int arg_ctrl_cnt; |
| 1639 int write_webm; | 873 int write_webm; |
| 1640 int have_kf_max_dist; | 874 int have_kf_max_dist; |
| 1641 }; | 875 }; |
| 1642 | 876 |
| 1643 | 877 |
| 1644 struct stream_state { | 878 struct stream_state { |
| 1645 int index; | 879 int index; |
| 1646 struct stream_state *next; | 880 struct stream_state *next; |
| 1647 struct stream_config config; | 881 struct stream_config config; |
| 1648 FILE *file; | 882 FILE *file; |
| 1649 struct rate_hist rate_hist; | 883 struct rate_hist rate_hist; |
| 1650 EbmlGlobal ebml; | 884 struct EbmlGlobal ebml; |
| 1651 uint32_t hash; | 885 uint32_t hash; |
| 1652 uint64_t psnr_sse_total; | 886 uint64_t psnr_sse_total; |
| 1653 uint64_t psnr_samples_total; | 887 uint64_t psnr_samples_total; |
| 1654 double psnr_totals[4]; | 888 double psnr_totals[4]; |
| 1655 int psnr_count; | 889 int psnr_count; |
| 1656 int counts[64]; | 890 int counts[64]; |
| 1657 vpx_codec_ctx_t encoder; | 891 vpx_codec_ctx_t encoder; |
| 1658 unsigned int frames_out; | 892 unsigned int frames_out; |
| 1659 uint64_t cx_time; | 893 uint64_t cx_time; |
| 1660 size_t nbytes; | 894 size_t nbytes; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1673 } | 907 } |
| 1674 | 908 |
| 1675 if (rat->num < 0) | 909 if (rat->num < 0) |
| 1676 die("Error: %s must be positive\n", msg); | 910 die("Error: %s must be positive\n", msg); |
| 1677 | 911 |
| 1678 if (!rat->den) | 912 if (!rat->den) |
| 1679 die("Error: %s has zero denominator\n", msg); | 913 die("Error: %s has zero denominator\n", msg); |
| 1680 } | 914 } |
| 1681 | 915 |
| 1682 | 916 |
| 1683 static void parse_global_config(struct global_config *global, char **argv) { | 917 static void parse_global_config(struct VpxEncoderConfig *global, char **argv) { |
| 1684 char **argi, **argj; | 918 char **argi, **argj; |
| 1685 struct arg arg; | 919 struct arg arg; |
| 1686 | 920 |
| 1687 /* Initialize default parameters */ | 921 /* Initialize default parameters */ |
| 1688 memset(global, 0, sizeof(*global)); | 922 memset(global, 0, sizeof(*global)); |
| 1689 global->codec = codecs; | 923 global->codec = codecs; |
| 1690 global->passes = 0; | 924 global->passes = 0; |
| 1691 global->use_i420 = 1; | 925 global->use_i420 = 1; |
| 1692 /* Assign default deadline to good quality */ | 926 /* Assign default deadline to good quality */ |
| 1693 global->deadline = VPX_DL_GOOD_QUALITY; | 927 global->deadline = VPX_DL_GOOD_QUALITY; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1750 validate_positive_rational(arg.name, &global->framerate); | 984 validate_positive_rational(arg.name, &global->framerate); |
| 1751 global->have_framerate = 1; | 985 global->have_framerate = 1; |
| 1752 } else if (arg_match(&arg, &out_part, argi)) | 986 } else if (arg_match(&arg, &out_part, argi)) |
| 1753 global->out_part = 1; | 987 global->out_part = 1; |
| 1754 else if (arg_match(&arg, &debugmode, argi)) | 988 else if (arg_match(&arg, &debugmode, argi)) |
| 1755 global->debug = 1; | 989 global->debug = 1; |
| 1756 else if (arg_match(&arg, &q_hist_n, argi)) | 990 else if (arg_match(&arg, &q_hist_n, argi)) |
| 1757 global->show_q_hist_buckets = arg_parse_uint(&arg); | 991 global->show_q_hist_buckets = arg_parse_uint(&arg); |
| 1758 else if (arg_match(&arg, &rate_hist_n, argi)) | 992 else if (arg_match(&arg, &rate_hist_n, argi)) |
| 1759 global->show_rate_hist_buckets = arg_parse_uint(&arg); | 993 global->show_rate_hist_buckets = arg_parse_uint(&arg); |
| 994 else if (arg_match(&arg, &disable_warnings, argi)) |
| 995 global->disable_warnings = 1; |
| 996 else if (arg_match(&arg, &disable_warning_prompt, argi)) |
| 997 global->disable_warning_prompt = 1; |
| 1760 else | 998 else |
| 1761 argj++; | 999 argj++; |
| 1762 } | 1000 } |
| 1763 | 1001 |
| 1764 /* Validate global config */ | 1002 /* Validate global config */ |
| 1765 if (global->passes == 0) { | 1003 if (global->passes == 0) { |
| 1766 #if CONFIG_VP9_ENCODER | 1004 #if CONFIG_VP9_ENCODER |
| 1767 // Make default VP9 passes = 2 until there is a better quality 1-pass | 1005 // Make default VP9 passes = 2 until there is a better quality 1-pass |
| 1768 // encoder | 1006 // encoder |
| 1769 global->passes = (global->codec->iface == vpx_codec_vp9_cx ? 2 : 1); | 1007 global->passes = (global->codec->iface == vpx_codec_vp9_cx ? 2 : 1); |
| 1770 #else | 1008 #else |
| 1771 global->passes = 1; | 1009 global->passes = 1; |
| 1772 #endif | 1010 #endif |
| 1773 } | 1011 } |
| 1774 | 1012 |
| 1775 if (global->pass) { | 1013 if (global->pass) { |
| 1776 /* DWIM: Assume the user meant passes=2 if pass=2 is specified */ | 1014 /* DWIM: Assume the user meant passes=2 if pass=2 is specified */ |
| 1777 if (global->pass > global->passes) { | 1015 if (global->pass > global->passes) { |
| 1778 warn("Assuming --pass=%d implies --passes=%d\n", | 1016 warn("Assuming --pass=%d implies --passes=%d\n", |
| 1779 global->pass, global->pass); | 1017 global->pass, global->pass); |
| 1780 global->passes = global->pass; | 1018 global->passes = global->pass; |
| 1781 } | 1019 } |
| 1782 } | 1020 } |
| 1783 } | 1021 } |
| 1784 | 1022 |
| 1785 | 1023 |
| 1786 void open_input_file(struct input_state *input) { | 1024 void open_input_file(struct VpxInputContext *input) { |
| 1787 unsigned int fourcc; | |
| 1788 | |
| 1789 /* Parse certain options from the input file, if possible */ | 1025 /* Parse certain options from the input file, if possible */ |
| 1790 input->file = strcmp(input->fn, "-") ? fopen(input->fn, "rb") | 1026 input->file = strcmp(input->filename, "-") |
| 1791 : set_binary_mode(stdin); | 1027 ? fopen(input->filename, "rb") : set_binary_mode(stdin); |
| 1792 | 1028 |
| 1793 if (!input->file) | 1029 if (!input->file) |
| 1794 fatal("Failed to open input file"); | 1030 fatal("Failed to open input file"); |
| 1795 | 1031 |
| 1796 if (!fseeko(input->file, 0, SEEK_END)) { | 1032 if (!fseeko(input->file, 0, SEEK_END)) { |
| 1797 /* Input file is seekable. Figure out how long it is, so we can get | 1033 /* Input file is seekable. Figure out how long it is, so we can get |
| 1798 * progress info. | 1034 * progress info. |
| 1799 */ | 1035 */ |
| 1800 input->length = ftello(input->file); | 1036 input->length = ftello(input->file); |
| 1801 rewind(input->file); | 1037 rewind(input->file); |
| 1802 } | 1038 } |
| 1803 | 1039 |
| 1804 /* For RAW input sources, these bytes will applied on the first frame | 1040 /* For RAW input sources, these bytes will applied on the first frame |
| 1805 * in read_frame(). | 1041 * in read_frame(). |
| 1806 */ | 1042 */ |
| 1807 input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file); | 1043 input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file); |
| 1808 input->detect.position = 0; | 1044 input->detect.position = 0; |
| 1809 | 1045 |
| 1810 if (input->detect.buf_read == 4 | 1046 if (input->detect.buf_read == 4 |
| 1811 && file_is_y4m(input->file, &input->y4m, input->detect.buf)) { | 1047 && file_is_y4m(input->file, &input->y4m, input->detect.buf)) { |
| 1812 if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4, | 1048 if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4, |
| 1813 input->only_i420) >= 0) { | 1049 input->only_i420) >= 0) { |
| 1814 input->file_type = FILE_TYPE_Y4M; | 1050 input->file_type = FILE_TYPE_Y4M; |
| 1815 input->w = input->y4m.pic_w; | 1051 input->width = input->y4m.pic_w; |
| 1816 input->h = input->y4m.pic_h; | 1052 input->height = input->y4m.pic_h; |
| 1817 input->framerate.num = input->y4m.fps_n; | 1053 input->framerate.numerator = input->y4m.fps_n; |
| 1818 input->framerate.den = input->y4m.fps_d; | 1054 input->framerate.denominator = input->y4m.fps_d; |
| 1819 input->use_i420 = 0; | 1055 input->use_i420 = 0; |
| 1820 } else | 1056 } else |
| 1821 fatal("Unsupported Y4M stream."); | 1057 fatal("Unsupported Y4M stream."); |
| 1822 } else if (input->detect.buf_read == 4 && file_is_ivf(input, &fourcc)) { | 1058 } else if (input->detect.buf_read == 4 && file_is_ivf(input)) { |
| 1823 input->file_type = FILE_TYPE_IVF; | 1059 fatal("IVF is not supported as input."); |
| 1824 switch (fourcc) { | |
| 1825 case 0x32315659: | |
| 1826 input->use_i420 = 0; | |
| 1827 break; | |
| 1828 case 0x30323449: | |
| 1829 input->use_i420 = 1; | |
| 1830 break; | |
| 1831 default: | |
| 1832 fatal("Unsupported fourcc (%08x) in IVF", fourcc); | |
| 1833 } | |
| 1834 } else { | 1060 } else { |
| 1835 input->file_type = FILE_TYPE_RAW; | 1061 input->file_type = FILE_TYPE_RAW; |
| 1836 } | 1062 } |
| 1837 } | 1063 } |
| 1838 | 1064 |
| 1839 | 1065 |
| 1840 static void close_input_file(struct input_state *input) { | 1066 static void close_input_file(struct VpxInputContext *input) { |
| 1841 fclose(input->file); | 1067 fclose(input->file); |
| 1842 if (input->file_type == FILE_TYPE_Y4M) | 1068 if (input->file_type == FILE_TYPE_Y4M) |
| 1843 y4m_input_close(&input->y4m); | 1069 y4m_input_close(&input->y4m); |
| 1844 } | 1070 } |
| 1845 | 1071 |
| 1846 static struct stream_state *new_stream(struct global_config *global, | 1072 static struct stream_state *new_stream(struct VpxEncoderConfig *global, |
| 1847 struct stream_state *prev) { | 1073 struct stream_state *prev) { |
| 1848 struct stream_state *stream; | 1074 struct stream_state *stream; |
| 1849 | 1075 |
| 1850 stream = calloc(1, sizeof(*stream)); | 1076 stream = calloc(1, sizeof(*stream)); |
| 1851 if (!stream) | 1077 if (!stream) |
| 1852 fatal("Failed to allocate new stream."); | 1078 fatal("Failed to allocate new stream."); |
| 1853 if (prev) { | 1079 if (prev) { |
| 1854 memcpy(stream, prev, sizeof(*stream)); | 1080 memcpy(stream, prev, sizeof(*stream)); |
| 1855 stream->index++; | 1081 stream->index++; |
| 1856 prev->next = stream; | 1082 prev->next = stream; |
| 1857 } else { | 1083 } else { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1885 } | 1111 } |
| 1886 | 1112 |
| 1887 /* Output files must be specified for each stream */ | 1113 /* Output files must be specified for each stream */ |
| 1888 stream->config.out_fn = NULL; | 1114 stream->config.out_fn = NULL; |
| 1889 | 1115 |
| 1890 stream->next = NULL; | 1116 stream->next = NULL; |
| 1891 return stream; | 1117 return stream; |
| 1892 } | 1118 } |
| 1893 | 1119 |
| 1894 | 1120 |
| 1895 static int parse_stream_params(struct global_config *global, | 1121 static int parse_stream_params(struct VpxEncoderConfig *global, |
| 1896 struct stream_state *stream, | 1122 struct stream_state *stream, |
| 1897 char **argv) { | 1123 char **argv) { |
| 1898 char **argi, **argj; | 1124 char **argi, **argj; |
| 1899 struct arg arg; | 1125 struct arg arg; |
| 1900 static const arg_def_t **ctrl_args = no_args; | 1126 static const arg_def_t **ctrl_args = no_args; |
| 1901 static const int *ctrl_args_map = NULL; | 1127 static const int *ctrl_args_map = NULL; |
| 1902 struct stream_config *config = &stream->config; | 1128 struct stream_config *config = &stream->config; |
| 1903 int eos_mark_found = 0; | 1129 int eos_mark_found = 0; |
| 1904 | 1130 |
| 1905 /* Handle codec specific options */ | 1131 /* Handle codec specific options */ |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2031 | 1257 |
| 2032 if (!match) | 1258 if (!match) |
| 2033 argj++; | 1259 argj++; |
| 2034 } | 1260 } |
| 2035 } | 1261 } |
| 2036 | 1262 |
| 2037 return eos_mark_found; | 1263 return eos_mark_found; |
| 2038 } | 1264 } |
| 2039 | 1265 |
| 2040 | 1266 |
| 2041 #define FOREACH_STREAM(func)\ | 1267 #define FOREACH_STREAM(func) \ |
| 2042 do\ | 1268 do { \ |
| 2043 {\ | 1269 struct stream_state *stream; \ |
| 2044 struct stream_state *stream;\ | 1270 for (stream = streams; stream; stream = stream->next) { \ |
| 2045 \ | 1271 func; \ |
| 2046 for(stream = streams; stream; stream = stream->next)\ | 1272 } \ |
| 2047 func;\ | 1273 } while (0) |
| 2048 }while(0) | |
| 2049 | 1274 |
| 2050 | 1275 |
| 2051 static void validate_stream_config(struct stream_state *stream) { | 1276 static void validate_stream_config(struct stream_state *stream) { |
| 2052 struct stream_state *streami; | 1277 struct stream_state *streami; |
| 2053 | 1278 |
| 2054 if (!stream->config.cfg.g_w || !stream->config.cfg.g_h) | 1279 if (!stream->config.cfg.g_w || !stream->config.cfg.g_h) |
| 2055 fatal("Stream %d: Specify stream dimensions with --width (-w) " | 1280 fatal("Stream %d: Specify stream dimensions with --width (-w) " |
| 2056 " and --height (-h)", stream->index); | 1281 " and --height (-h)", stream->index); |
| 2057 | 1282 |
| 2058 for (streami = stream; streami; streami = streami->next) { | 1283 for (streami = stream; streami; streami = streami->next) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2090 stream->config.cfg.g_w = w; | 1315 stream->config.cfg.g_w = w; |
| 2091 else | 1316 else |
| 2092 stream->config.cfg.g_w = w * stream->config.cfg.g_h / h; | 1317 stream->config.cfg.g_w = w * stream->config.cfg.g_h / h; |
| 2093 } | 1318 } |
| 2094 if (!stream->config.cfg.g_h) { | 1319 if (!stream->config.cfg.g_h) { |
| 2095 stream->config.cfg.g_h = h * stream->config.cfg.g_w / w; | 1320 stream->config.cfg.g_h = h * stream->config.cfg.g_w / w; |
| 2096 } | 1321 } |
| 2097 } | 1322 } |
| 2098 | 1323 |
| 2099 | 1324 |
| 2100 static void set_default_kf_interval(struct stream_state *stream, | 1325 static void set_default_kf_interval(struct stream_state *stream, |
| 2101 struct global_config *global) { | 1326 struct VpxEncoderConfig *global) { |
| 2102 /* Use a max keyframe interval of 5 seconds, if none was | 1327 /* Use a max keyframe interval of 5 seconds, if none was |
| 2103 * specified on the command line. | 1328 * specified on the command line. |
| 2104 */ | 1329 */ |
| 2105 if (!stream->config.have_kf_max_dist) { | 1330 if (!stream->config.have_kf_max_dist) { |
| 2106 double framerate = (double)global->framerate.num / global->framerate.den; | 1331 double framerate = (double)global->framerate.num / global->framerate.den; |
| 2107 if (framerate > 0.0) | 1332 if (framerate > 0.0) |
| 2108 stream->config.cfg.kf_max_dist = (unsigned int)(5.0 * framerate); | 1333 stream->config.cfg.kf_max_dist = (unsigned int)(5.0 * framerate); |
| 2109 } | 1334 } |
| 2110 } | 1335 } |
| 2111 | 1336 |
| 2112 | 1337 |
| 2113 static void show_stream_config(struct stream_state *stream, | 1338 static void show_stream_config(struct stream_state *stream, |
| 2114 struct global_config *global, | 1339 struct VpxEncoderConfig *global, |
| 2115 struct input_state *input) { | 1340 struct VpxInputContext *input) { |
| 2116 | 1341 |
| 2117 #define SHOW(field) \ | 1342 #define SHOW(field) \ |
| 2118 fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field) | 1343 fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field) |
| 2119 | 1344 |
| 2120 if (stream->index == 0) { | 1345 if (stream->index == 0) { |
| 2121 fprintf(stderr, "Codec: %s\n", | 1346 fprintf(stderr, "Codec: %s\n", |
| 2122 vpx_codec_iface_name(global->codec->iface())); | 1347 vpx_codec_iface_name(global->codec->iface())); |
| 2123 fprintf(stderr, "Source file: %s Format: %s\n", input->fn, | 1348 fprintf(stderr, "Source file: %s Format: %s\n", input->filename, |
| 2124 input->use_i420 ? "I420" : "YV12"); | 1349 input->use_i420 ? "I420" : "YV12"); |
| 2125 } | 1350 } |
| 2126 if (stream->next || stream->index) | 1351 if (stream->next || stream->index) |
| 2127 fprintf(stderr, "\nStream Index: %d\n", stream->index); | 1352 fprintf(stderr, "\nStream Index: %d\n", stream->index); |
| 2128 fprintf(stderr, "Destination file: %s\n", stream->config.out_fn); | 1353 fprintf(stderr, "Destination file: %s\n", stream->config.out_fn); |
| 2129 fprintf(stderr, "Encoder parameters:\n"); | 1354 fprintf(stderr, "Encoder parameters:\n"); |
| 2130 | 1355 |
| 2131 SHOW(g_usage); | 1356 SHOW(g_usage); |
| 2132 SHOW(g_threads); | 1357 SHOW(g_threads); |
| 2133 SHOW(g_profile); | 1358 SHOW(g_profile); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2154 SHOW(rc_2pass_vbr_bias_pct); | 1379 SHOW(rc_2pass_vbr_bias_pct); |
| 2155 SHOW(rc_2pass_vbr_minsection_pct); | 1380 SHOW(rc_2pass_vbr_minsection_pct); |
| 2156 SHOW(rc_2pass_vbr_maxsection_pct); | 1381 SHOW(rc_2pass_vbr_maxsection_pct); |
| 2157 SHOW(kf_mode); | 1382 SHOW(kf_mode); |
| 2158 SHOW(kf_min_dist); | 1383 SHOW(kf_min_dist); |
| 2159 SHOW(kf_max_dist); | 1384 SHOW(kf_max_dist); |
| 2160 } | 1385 } |
| 2161 | 1386 |
| 2162 | 1387 |
| 2163 static void open_output_file(struct stream_state *stream, | 1388 static void open_output_file(struct stream_state *stream, |
| 2164 struct global_config *global) { | 1389 struct VpxEncoderConfig *global) { |
| 2165 const char *fn = stream->config.out_fn; | 1390 const char *fn = stream->config.out_fn; |
| 2166 | 1391 |
| 2167 stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout); | 1392 stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout); |
| 2168 | 1393 |
| 2169 if (!stream->file) | 1394 if (!stream->file) |
| 2170 fatal("Failed to open output file"); | 1395 fatal("Failed to open output file"); |
| 2171 | 1396 |
| 2172 if (stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR)) | 1397 if (stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR)) |
| 2173 fatal("WebM output to pipes not supported."); | 1398 fatal("WebM output to pipes not supported."); |
| 2174 | 1399 |
| 2175 if (stream->config.write_webm) { | 1400 if (stream->config.write_webm) { |
| 2176 stream->ebml.stream = stream->file; | 1401 stream->ebml.stream = stream->file; |
| 2177 write_webm_file_header(&stream->ebml, &stream->config.cfg, | 1402 write_webm_file_header(&stream->ebml, &stream->config.cfg, |
| 2178 &global->framerate, | 1403 &global->framerate, |
| 2179 stream->config.stereo_fmt, | 1404 stream->config.stereo_fmt, |
| 2180 global->codec->fourcc); | 1405 global->codec->fourcc); |
| 2181 } else | 1406 } else |
| 2182 write_ivf_file_header(stream->file, &stream->config.cfg, | 1407 ivf_write_file_header(stream->file, &stream->config.cfg, |
| 2183 global->codec->fourcc, 0); | 1408 global->codec->fourcc, 0); |
| 2184 } | 1409 } |
| 2185 | 1410 |
| 2186 | 1411 |
| 2187 static void close_output_file(struct stream_state *stream, | 1412 static void close_output_file(struct stream_state *stream, |
| 2188 unsigned int fourcc) { | 1413 unsigned int fourcc) { |
| 2189 if (stream->config.write_webm) { | 1414 if (stream->config.write_webm) { |
| 2190 write_webm_file_footer(&stream->ebml, stream->hash); | 1415 write_webm_file_footer(&stream->ebml, stream->hash); |
| 2191 free(stream->ebml.cue_list); | 1416 free(stream->ebml.cue_list); |
| 2192 stream->ebml.cue_list = NULL; | 1417 stream->ebml.cue_list = NULL; |
| 2193 } else { | 1418 } else { |
| 2194 if (!fseek(stream->file, 0, SEEK_SET)) | 1419 if (!fseek(stream->file, 0, SEEK_SET)) |
| 2195 write_ivf_file_header(stream->file, &stream->config.cfg, | 1420 ivf_write_file_header(stream->file, &stream->config.cfg, |
| 2196 fourcc, | 1421 fourcc, |
| 2197 stream->frames_out); | 1422 stream->frames_out); |
| 2198 } | 1423 } |
| 2199 | 1424 |
| 2200 fclose(stream->file); | 1425 fclose(stream->file); |
| 2201 } | 1426 } |
| 2202 | 1427 |
| 2203 | 1428 |
| 2204 static void setup_pass(struct stream_state *stream, | 1429 static void setup_pass(struct stream_state *stream, |
| 2205 struct global_config *global, | 1430 struct VpxEncoderConfig *global, |
| 2206 int pass) { | 1431 int pass) { |
| 2207 if (stream->config.stats_fn) { | 1432 if (stream->config.stats_fn) { |
| 2208 if (!stats_open_file(&stream->stats, stream->config.stats_fn, | 1433 if (!stats_open_file(&stream->stats, stream->config.stats_fn, |
| 2209 pass)) | 1434 pass)) |
| 2210 fatal("Failed to open statistics store"); | 1435 fatal("Failed to open statistics store"); |
| 2211 } else { | 1436 } else { |
| 2212 if (!stats_open_mem(&stream->stats, pass)) | 1437 if (!stats_open_mem(&stream->stats, pass)) |
| 2213 fatal("Failed to open statistics store"); | 1438 fatal("Failed to open statistics store"); |
| 2214 } | 1439 } |
| 2215 | 1440 |
| 2216 stream->config.cfg.g_pass = global->passes == 2 | 1441 stream->config.cfg.g_pass = global->passes == 2 |
| 2217 ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS | 1442 ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS |
| 2218 : VPX_RC_ONE_PASS; | 1443 : VPX_RC_ONE_PASS; |
| 2219 if (pass) | 1444 if (pass) |
| 2220 stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats); | 1445 stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats); |
| 2221 | 1446 |
| 2222 stream->cx_time = 0; | 1447 stream->cx_time = 0; |
| 2223 stream->nbytes = 0; | 1448 stream->nbytes = 0; |
| 2224 stream->frames_out = 0; | 1449 stream->frames_out = 0; |
| 2225 } | 1450 } |
| 2226 | 1451 |
| 2227 | 1452 |
| 2228 static void initialize_encoder(struct stream_state *stream, | 1453 static void initialize_encoder(struct stream_state *stream, |
| 2229 struct global_config *global) { | 1454 struct VpxEncoderConfig *global) { |
| 2230 int i; | 1455 int i; |
| 2231 int flags = 0; | 1456 int flags = 0; |
| 2232 | 1457 |
| 2233 flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0; | 1458 flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0; |
| 2234 flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0; | 1459 flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0; |
| 2235 | 1460 |
| 2236 /* Construct Encoder Context */ | 1461 /* Construct Encoder Context */ |
| 2237 vpx_codec_enc_init(&stream->encoder, global->codec->iface(), | 1462 vpx_codec_enc_init(&stream->encoder, global->codec->iface(), |
| 2238 &stream->config.cfg, flags); | 1463 &stream->config.cfg, flags); |
| 2239 ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder"); | 1464 ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder"); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2253 } | 1478 } |
| 2254 | 1479 |
| 2255 #if CONFIG_DECODERS | 1480 #if CONFIG_DECODERS |
| 2256 if (global->test_decode != TEST_DECODE_OFF) { | 1481 if (global->test_decode != TEST_DECODE_OFF) { |
| 2257 vpx_codec_dec_init(&stream->decoder, global->codec->dx_iface(), NULL, 0); | 1482 vpx_codec_dec_init(&stream->decoder, global->codec->dx_iface(), NULL, 0); |
| 2258 } | 1483 } |
| 2259 #endif | 1484 #endif |
| 2260 } | 1485 } |
| 2261 | 1486 |
| 2262 | 1487 |
| 2263 static void encode_frame(struct stream_state *stream, | 1488 static void encode_frame(struct stream_state *stream, |
| 2264 struct global_config *global, | 1489 struct VpxEncoderConfig *global, |
| 2265 struct vpx_image *img, | 1490 struct vpx_image *img, |
| 2266 unsigned int frames_in) { | 1491 unsigned int frames_in) { |
| 2267 vpx_codec_pts_t frame_start, next_frame_start; | 1492 vpx_codec_pts_t frame_start, next_frame_start; |
| 2268 struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; | 1493 struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; |
| 2269 struct vpx_usec_timer timer; | 1494 struct vpx_usec_timer timer; |
| 2270 | 1495 |
| 2271 frame_start = (cfg->g_timebase.den * (int64_t)(frames_in - 1) | 1496 frame_start = (cfg->g_timebase.den * (int64_t)(frames_in - 1) |
| 2272 * global->framerate.den) | 1497 * global->framerate.den) |
| 2273 / cfg->g_timebase.num / global->framerate.num; | 1498 / cfg->g_timebase.num / global->framerate.num; |
| 2274 next_frame_start = (cfg->g_timebase.den * (int64_t)(frames_in) | 1499 next_frame_start = (cfg->g_timebase.den * (int64_t)(frames_in) |
| 2275 * global->framerate.den) | 1500 * global->framerate.den) |
| 2276 / cfg->g_timebase.num / global->framerate.num; | 1501 / cfg->g_timebase.num / global->framerate.num; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2311 if (stream->config.cfg.g_pass != VPX_RC_FIRST_PASS) { | 1536 if (stream->config.cfg.g_pass != VPX_RC_FIRST_PASS) { |
| 2312 int q; | 1537 int q; |
| 2313 | 1538 |
| 2314 vpx_codec_control(&stream->encoder, VP8E_GET_LAST_QUANTIZER_64, &q); | 1539 vpx_codec_control(&stream->encoder, VP8E_GET_LAST_QUANTIZER_64, &q); |
| 2315 ctx_exit_on_error(&stream->encoder, "Failed to read quantizer"); | 1540 ctx_exit_on_error(&stream->encoder, "Failed to read quantizer"); |
| 2316 stream->counts[q]++; | 1541 stream->counts[q]++; |
| 2317 } | 1542 } |
| 2318 } | 1543 } |
| 2319 | 1544 |
| 2320 | 1545 |
| 2321 static void get_cx_data(struct stream_state *stream, | 1546 static void get_cx_data(struct stream_state *stream, |
| 2322 struct global_config *global, | 1547 struct VpxEncoderConfig *global, |
| 2323 int *got_data) { | 1548 int *got_data) { |
| 2324 const vpx_codec_cx_pkt_t *pkt; | 1549 const vpx_codec_cx_pkt_t *pkt; |
| 2325 const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; | 1550 const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; |
| 2326 vpx_codec_iter_t iter = NULL; | 1551 vpx_codec_iter_t iter = NULL; |
| 2327 | 1552 |
| 2328 *got_data = 0; | 1553 *got_data = 0; |
| 2329 while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) { | 1554 while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) { |
| 2330 static size_t fsize = 0; | 1555 static size_t fsize = 0; |
| 2331 static off_t ivf_header_pos = 0; | 1556 static off_t ivf_header_pos = 0; |
| 2332 | 1557 |
| 2333 switch (pkt->kind) { | 1558 switch (pkt->kind) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2345 stream->hash = murmur(pkt->data.frame.buf, | 1570 stream->hash = murmur(pkt->data.frame.buf, |
| 2346 (int)pkt->data.frame.sz, | 1571 (int)pkt->data.frame.sz, |
| 2347 stream->hash); | 1572 stream->hash); |
| 2348 | 1573 |
| 2349 write_webm_block(&stream->ebml, cfg, pkt); | 1574 write_webm_block(&stream->ebml, cfg, pkt); |
| 2350 } else { | 1575 } else { |
| 2351 if (pkt->data.frame.partition_id <= 0) { | 1576 if (pkt->data.frame.partition_id <= 0) { |
| 2352 ivf_header_pos = ftello(stream->file); | 1577 ivf_header_pos = ftello(stream->file); |
| 2353 fsize = pkt->data.frame.sz; | 1578 fsize = pkt->data.frame.sz; |
| 2354 | 1579 |
| 2355 write_ivf_frame_header(stream->file, pkt); | 1580 ivf_write_frame_header(stream->file, pkt); |
| 2356 } else { | 1581 } else { |
| 2357 fsize += pkt->data.frame.sz; | 1582 fsize += pkt->data.frame.sz; |
| 2358 | 1583 |
| 2359 if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) { | 1584 if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) { |
| 2360 off_t currpos = ftello(stream->file); | 1585 off_t currpos = ftello(stream->file); |
| 2361 fseeko(stream->file, ivf_header_pos, SEEK_SET); | 1586 fseeko(stream->file, ivf_header_pos, SEEK_SET); |
| 2362 write_ivf_frame_size(stream->file, fsize); | 1587 ivf_write_frame_size(stream->file, fsize); |
| 2363 fseeko(stream->file, currpos, SEEK_SET); | 1588 fseeko(stream->file, currpos, SEEK_SET); |
| 2364 } | 1589 } |
| 2365 } | 1590 } |
| 2366 | 1591 |
| 2367 (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, | 1592 (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, |
| 2368 stream->file); | 1593 stream->file); |
| 2369 } | 1594 } |
| 2370 stream->nbytes += pkt->data.raw.sz; | 1595 stream->nbytes += pkt->data.raw.sz; |
| 2371 | 1596 |
| 2372 *got_data = 1; | 1597 *got_data = 1; |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2505 etl -= mins * 60; | 1730 etl -= mins * 60; |
| 2506 secs = etl; | 1731 secs = etl; |
| 2507 | 1732 |
| 2508 fprintf(stderr, "[%3s %2d:%02d:%02d] ", | 1733 fprintf(stderr, "[%3s %2d:%02d:%02d] ", |
| 2509 label, hours, mins, secs); | 1734 label, hours, mins, secs); |
| 2510 } else { | 1735 } else { |
| 2511 fprintf(stderr, "[%3s unknown] ", label); | 1736 fprintf(stderr, "[%3s unknown] ", label); |
| 2512 } | 1737 } |
| 2513 } | 1738 } |
| 2514 | 1739 |
| 1740 |
| 2515 int main(int argc, const char **argv_) { | 1741 int main(int argc, const char **argv_) { |
| 2516 int pass; | 1742 int pass; |
| 2517 vpx_image_t raw; | 1743 vpx_image_t raw; |
| 2518 int frame_avail, got_data; | 1744 int frame_avail, got_data; |
| 2519 | 1745 |
| 2520 struct input_state input = {0}; | 1746 struct VpxInputContext input = {0}; |
| 2521 struct global_config global; | 1747 struct VpxEncoderConfig global; |
| 2522 struct stream_state *streams = NULL; | 1748 struct stream_state *streams = NULL; |
| 2523 char **argv, **argi; | 1749 char **argv, **argi; |
| 2524 uint64_t cx_time = 0; | 1750 uint64_t cx_time = 0; |
| 2525 int stream_cnt = 0; | 1751 int stream_cnt = 0; |
| 2526 int res = 0; | 1752 int res = 0; |
| 2527 | 1753 |
| 2528 exec_name = argv_[0]; | 1754 exec_name = argv_[0]; |
| 2529 | 1755 |
| 2530 if (argc < 3) | 1756 if (argc < 3) |
| 2531 usage_exit(); | 1757 usage_exit(); |
| 2532 | 1758 |
| 2533 /* Setup default input stream settings */ | 1759 /* Setup default input stream settings */ |
| 2534 input.framerate.num = 30; | 1760 input.framerate.numerator = 30; |
| 2535 input.framerate.den = 1; | 1761 input.framerate.denominator = 1; |
| 2536 input.use_i420 = 1; | 1762 input.use_i420 = 1; |
| 2537 input.only_i420 = 1; | 1763 input.only_i420 = 1; |
| 2538 | 1764 |
| 2539 /* First parse the global configuration values, because we want to apply | 1765 /* First parse the global configuration values, because we want to apply |
| 2540 * other parameters on top of the default configuration provided by the | 1766 * other parameters on top of the default configuration provided by the |
| 2541 * codec. | 1767 * codec. |
| 2542 */ | 1768 */ |
| 2543 argv = argv_dup(argc - 1, argv_ + 1); | 1769 argv = argv_dup(argc - 1, argv_ + 1); |
| 2544 parse_global_config(&global, argv); | 1770 parse_global_config(&global, argv); |
| 2545 | 1771 |
| 1772 |
| 2546 { | 1773 { |
| 2547 /* Now parse each stream's parameters. Using a local scope here | 1774 /* Now parse each stream's parameters. Using a local scope here |
| 2548 * due to the use of 'stream' as loop variable in FOREACH_STREAM | 1775 * due to the use of 'stream' as loop variable in FOREACH_STREAM |
| 2549 * loops | 1776 * loops |
| 2550 */ | 1777 */ |
| 2551 struct stream_state *stream = NULL; | 1778 struct stream_state *stream = NULL; |
| 2552 | 1779 |
| 2553 do { | 1780 do { |
| 2554 stream = new_stream(&global, stream); | 1781 stream = new_stream(&global, stream); |
| 2555 stream_cnt++; | 1782 stream_cnt++; |
| 2556 if (!streams) | 1783 if (!streams) |
| 2557 streams = stream; | 1784 streams = stream; |
| 2558 } while (parse_stream_params(&global, stream, argv)); | 1785 } while (parse_stream_params(&global, stream, argv)); |
| 2559 } | 1786 } |
| 2560 | 1787 |
| 2561 /* Check for unrecognized options */ | 1788 /* Check for unrecognized options */ |
| 2562 for (argi = argv; *argi; argi++) | 1789 for (argi = argv; *argi; argi++) |
| 2563 if (argi[0][0] == '-' && argi[0][1]) | 1790 if (argi[0][0] == '-' && argi[0][1]) |
| 2564 die("Error: Unrecognized option %s\n", *argi); | 1791 die("Error: Unrecognized option %s\n", *argi); |
| 2565 | 1792 |
| 1793 FOREACH_STREAM(check_encoder_config(global.disable_warning_prompt, |
| 1794 &global, &stream->config.cfg);); |
| 1795 |
| 2566 /* Handle non-option arguments */ | 1796 /* Handle non-option arguments */ |
| 2567 input.fn = argv[0]; | 1797 input.filename = argv[0]; |
| 2568 | 1798 |
| 2569 if (!input.fn) | 1799 if (!input.filename) |
| 2570 usage_exit(); | 1800 usage_exit(); |
| 2571 | 1801 |
| 2572 #if CONFIG_NON420 | 1802 #if CONFIG_NON420 |
| 2573 /* Decide if other chroma subsamplings than 4:2:0 are supported */ | 1803 /* Decide if other chroma subsamplings than 4:2:0 are supported */ |
| 2574 if (global.codec->fourcc == VP9_FOURCC) | 1804 if (global.codec->fourcc == VP9_FOURCC) |
| 2575 input.only_i420 = 0; | 1805 input.only_i420 = 0; |
| 2576 #endif | 1806 #endif |
| 2577 | 1807 |
| 2578 for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) { | 1808 for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) { |
| 2579 int frames_in = 0, seen_frames = 0; | 1809 int frames_in = 0, seen_frames = 0; |
| 2580 int64_t estimated_time_left = -1; | 1810 int64_t estimated_time_left = -1; |
| 2581 int64_t average_rate = -1; | 1811 int64_t average_rate = -1; |
| 2582 off_t lagged_count = 0; | 1812 off_t lagged_count = 0; |
| 2583 | 1813 |
| 2584 open_input_file(&input); | 1814 open_input_file(&input); |
| 2585 | 1815 |
| 2586 /* If the input file doesn't specify its w/h (raw files), try to get | 1816 /* If the input file doesn't specify its w/h (raw files), try to get |
| 2587 * the data from the first stream's configuration. | 1817 * the data from the first stream's configuration. |
| 2588 */ | 1818 */ |
| 2589 if (!input.w || !input.h) | 1819 if (!input.width || !input.height) |
| 2590 FOREACH_STREAM( { | 1820 FOREACH_STREAM( { |
| 2591 if (stream->config.cfg.g_w && stream->config.cfg.g_h) { | 1821 if (stream->config.cfg.g_w && stream->config.cfg.g_h) { |
| 2592 input.w = stream->config.cfg.g_w; | 1822 input.width = stream->config.cfg.g_w; |
| 2593 input.h = stream->config.cfg.g_h; | 1823 input.height = stream->config.cfg.g_h; |
| 2594 break; | 1824 break; |
| 2595 } | 1825 } |
| 2596 }); | 1826 }); |
| 2597 | 1827 |
| 2598 /* Update stream configurations from the input file's parameters */ | 1828 /* Update stream configurations from the input file's parameters */ |
| 2599 if (!input.w || !input.h) | 1829 if (!input.width || !input.height) |
| 2600 fatal("Specify stream dimensions with --width (-w) " | 1830 fatal("Specify stream dimensions with --width (-w) " |
| 2601 " and --height (-h)"); | 1831 " and --height (-h)"); |
| 2602 FOREACH_STREAM(set_stream_dimensions(stream, input.w, input.h)); | 1832 FOREACH_STREAM(set_stream_dimensions(stream, input.width, input.height)); |
| 2603 FOREACH_STREAM(validate_stream_config(stream)); | 1833 FOREACH_STREAM(validate_stream_config(stream)); |
| 2604 | 1834 |
| 2605 /* Ensure that --passes and --pass are consistent. If --pass is set and | 1835 /* Ensure that --passes and --pass are consistent. If --pass is set and |
| 2606 * --passes=2, ensure --fpf was set. | 1836 * --passes=2, ensure --fpf was set. |
| 2607 */ | 1837 */ |
| 2608 if (global.pass && global.passes == 2) | 1838 if (global.pass && global.passes == 2) |
| 2609 FOREACH_STREAM( { | 1839 FOREACH_STREAM( { |
| 2610 if (!stream->config.stats_fn) | 1840 if (!stream->config.stats_fn) |
| 2611 die("Stream %d: Must specify --fpf when --pass=%d" | 1841 die("Stream %d: Must specify --fpf when --pass=%d" |
| 2612 " and --passes=2\n", stream->index, global.pass); | 1842 " and --passes=2\n", stream->index, global.pass); |
| 2613 }); | 1843 }); |
| 2614 | 1844 |
| 2615 /* Use the frame rate from the file only if none was specified | 1845 /* Use the frame rate from the file only if none was specified |
| 2616 * on the command-line. | 1846 * on the command-line. |
| 2617 */ | 1847 */ |
| 2618 if (!global.have_framerate) | 1848 if (!global.have_framerate) { |
| 2619 global.framerate = input.framerate; | 1849 global.framerate.num = input.framerate.numerator; |
| 1850 global.framerate.den = input.framerate.denominator; |
| 1851 } |
| 2620 | 1852 |
| 2621 FOREACH_STREAM(set_default_kf_interval(stream, &global)); | 1853 FOREACH_STREAM(set_default_kf_interval(stream, &global)); |
| 2622 | 1854 |
| 2623 /* Show configuration */ | 1855 /* Show configuration */ |
| 2624 if (global.verbose && pass == 0) | 1856 if (global.verbose && pass == 0) |
| 2625 FOREACH_STREAM(show_stream_config(stream, &global, &input)); | 1857 FOREACH_STREAM(show_stream_config(stream, &global, &input)); |
| 2626 | 1858 |
| 2627 if (pass == (global.pass ? global.pass - 1 : 0)) { | 1859 if (pass == (global.pass ? global.pass - 1 : 0)) { |
| 2628 if (input.file_type == FILE_TYPE_Y4M) | 1860 if (input.file_type == FILE_TYPE_Y4M) |
| 2629 /*The Y4M reader does its own allocation. | 1861 /*The Y4M reader does its own allocation. |
| 2630 Just initialize this here to avoid problems if we never read any | 1862 Just initialize this here to avoid problems if we never read any |
| 2631 frames.*/ | 1863 frames.*/ |
| 2632 memset(&raw, 0, sizeof(raw)); | 1864 memset(&raw, 0, sizeof(raw)); |
| 2633 else | 1865 else |
| 2634 vpx_img_alloc(&raw, | 1866 vpx_img_alloc(&raw, |
| 2635 input.use_i420 ? VPX_IMG_FMT_I420 | 1867 input.use_i420 ? VPX_IMG_FMT_I420 |
| 2636 : VPX_IMG_FMT_YV12, | 1868 : VPX_IMG_FMT_YV12, |
| 2637 input.w, input.h, 32); | 1869 input.width, input.height, 32); |
| 2638 | 1870 |
| 2639 FOREACH_STREAM(init_rate_histogram(&stream->rate_hist, | 1871 FOREACH_STREAM(init_rate_histogram(&stream->rate_hist, |
| 2640 &stream->config.cfg, | 1872 &stream->config.cfg, |
| 2641 &global.framerate)); | 1873 &global.framerate)); |
| 2642 } | 1874 } |
| 2643 | 1875 |
| 2644 FOREACH_STREAM(setup_pass(stream, &global, pass)); | 1876 FOREACH_STREAM(setup_pass(stream, &global, pass)); |
| 2645 FOREACH_STREAM(open_output_file(stream, &global)); | 1877 FOREACH_STREAM(open_output_file(stream, &global)); |
| 2646 FOREACH_STREAM(initialize_encoder(stream, &global)); | 1878 FOREACH_STREAM(initialize_encoder(stream, &global)); |
| 2647 | 1879 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2795 } | 2027 } |
| 2796 fclose(f); | 2028 fclose(f); |
| 2797 }); | 2029 }); |
| 2798 #endif | 2030 #endif |
| 2799 | 2031 |
| 2800 vpx_img_free(&raw); | 2032 vpx_img_free(&raw); |
| 2801 free(argv); | 2033 free(argv); |
| 2802 free(streams); | 2034 free(streams); |
| 2803 return res ? EXIT_FAILURE : EXIT_SUCCESS; | 2035 return res ? EXIT_FAILURE : EXIT_SUCCESS; |
| 2804 } | 2036 } |
| OLD | NEW |