00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <stdarg.h>
00020 #include <string.h>
00021 #define VPX_CODEC_DISABLE_COMPAT 1
00022 #include "vpx/vpx_encoder.h"
00023 #include "vpx/vp8cx.h"
00024 #define interface (vpx_codec_vp8_cx())
00025 #define fourcc 0x30385056
00026
00027 #define IVF_FILE_HDR_SZ (32)
00028 #define IVF_FRAME_HDR_SZ (12)
00029
00030 static void mem_put_le16(char *mem, unsigned int val) {
00031 mem[0] = val;
00032 mem[1] = val>>8;
00033 }
00034
00035 static void mem_put_le32(char *mem, unsigned int val) {
00036 mem[0] = val;
00037 mem[1] = val>>8;
00038 mem[2] = val>>16;
00039 mem[3] = val>>24;
00040 }
00041
00042 static void die(const char *fmt, ...) {
00043 va_list ap;
00044
00045 va_start(ap, fmt);
00046 vprintf(fmt, ap);
00047 if(fmt[strlen(fmt)-1] != '\n')
00048 printf("\n");
00049 exit(EXIT_FAILURE);
00050 }
00051
00052 static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
00053 const char *detail = vpx_codec_error_detail(ctx);
00054
00055 printf("%s: %s\n", s, vpx_codec_error(ctx));
00056 if(detail)
00057 printf(" %s\n",detail);
00058 exit(EXIT_FAILURE);
00059 }
00060
00061 static int read_frame(FILE *f, vpx_image_t *img) {
00062 size_t nbytes, to_read;
00063 int res = 1;
00064
00065 to_read = img->w*img->h*3/2;
00066 nbytes = fread(img->planes[0], 1, to_read, f);
00067 if(nbytes != to_read) {
00068 res = 0;
00069 if(nbytes > 0)
00070 printf("Warning: Read partial frame. Check your width & height!\n");
00071 }
00072 return res;
00073 }
00074
00075 static void write_ivf_file_header(FILE *outfile,
00076 const vpx_codec_enc_cfg_t *cfg,
00077 int frame_cnt) {
00078 char header[32];
00079
00080 if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
00081 return;
00082 header[0] = 'D';
00083 header[1] = 'K';
00084 header[2] = 'I';
00085 header[3] = 'F';
00086 mem_put_le16(header+4, 0);
00087 mem_put_le16(header+6, 32);
00088 mem_put_le32(header+8, fourcc);
00089 mem_put_le16(header+12, cfg->g_w);
00090 mem_put_le16(header+14, cfg->g_h);
00091 mem_put_le32(header+16, cfg->g_timebase.den);
00092 mem_put_le32(header+20, cfg->g_timebase.num);
00093 mem_put_le32(header+24, frame_cnt);
00094 mem_put_le32(header+28, 0);
00095
00096 if(fwrite(header, 1, 32, outfile));
00097 }
00098
00099
00100 static void write_ivf_frame_header(FILE *outfile,
00101 const vpx_codec_cx_pkt_t *pkt)
00102 {
00103 char header[12];
00104 vpx_codec_pts_t pts;
00105
00106 if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
00107 return;
00108
00109 pts = pkt->data.frame.pts;
00110 mem_put_le32(header, pkt->data.frame.sz);
00111 mem_put_le32(header+4, pts&0xFFFFFFFF);
00112 mem_put_le32(header+8, pts >> 32);
00113
00114 if(fwrite(header, 1, 12, outfile));
00115 }
00116
00117 static int mode_to_num_layers[9] = {2, 2, 3, 3, 3, 3, 5, 2, 3};
00118
00119 int main(int argc, char **argv) {
00120 FILE *infile, *outfile[VPX_TS_MAX_LAYERS];
00121 vpx_codec_ctx_t codec;
00122 vpx_codec_enc_cfg_t cfg;
00123 int frame_cnt = 0;
00124 vpx_image_t raw;
00125 vpx_codec_err_t res;
00126 unsigned int width;
00127 unsigned int height;
00128 int frame_avail;
00129 int got_data;
00130 int flags = 0;
00131 int i;
00132 int pts = 0;
00133 int frame_duration = 1;
00134
00135 int layering_mode = 0;
00136 int frames_in_layer[VPX_TS_MAX_LAYERS] = {0};
00137 int layer_flags[VPX_TS_MAX_PERIODICITY] = {0};
00138 int flag_periodicity;
00139 int max_intra_size_pct;
00140
00141
00142 if (argc < 9)
00143 die("Usage: %s <infile> <outfile> <width> <height> <rate_num> "
00144 " <rate_den> <mode> <Rate_0> ... <Rate_nlayers-1>\n", argv[0]);
00145
00146 width = strtol (argv[3], NULL, 0);
00147 height = strtol (argv[4], NULL, 0);
00148 if (width < 16 || width%2 || height <16 || height%2)
00149 die ("Invalid resolution: %d x %d", width, height);
00150
00151 if (!sscanf(argv[7], "%d", &layering_mode))
00152 die ("Invalid mode %s", argv[7]);
00153 if (layering_mode<0 || layering_mode>8)
00154 die ("Invalid mode (0..8) %s", argv[7]);
00155
00156 if (argc != 8+mode_to_num_layers[layering_mode])
00157 die ("Invalid number of arguments");
00158
00159 if (!vpx_img_alloc (&raw, VPX_IMG_FMT_I420, width, height, 1))
00160 die ("Failed to allocate image", width, height);
00161
00162 printf("Using %s\n",vpx_codec_iface_name(interface));
00163
00164
00165 res = vpx_codec_enc_config_default(interface, &cfg, 0);
00166 if(res) {
00167 printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
00168 return EXIT_FAILURE;
00169 }
00170
00171
00172 cfg.g_w = width;
00173 cfg.g_h = height;
00174
00175
00176 if (!sscanf (argv[5], "%d", &cfg.g_timebase.num ))
00177 die ("Invalid timebase numerator %s", argv[5]);
00178 if (!sscanf (argv[6], "%d", &cfg.g_timebase.den ))
00179 die ("Invalid timebase denominator %s", argv[6]);
00180
00181 for (i=8; i<8+mode_to_num_layers[layering_mode]; i++)
00182 if (!sscanf(argv[i], "%d", &cfg.ts_target_bitrate[i-8]))
00183 die ("Invalid data rate %s", argv[i]);
00184
00185
00186 cfg.rc_dropframe_thresh = 0;
00187 cfg.rc_end_usage = VPX_CBR;
00188 cfg.rc_resize_allowed = 0;
00189 cfg.rc_min_quantizer = 8;
00190 cfg.rc_max_quantizer = 56;
00191 cfg.rc_undershoot_pct = 100;
00192 cfg.rc_overshoot_pct = 15;
00193 cfg.rc_buf_initial_sz = 500;
00194 cfg.rc_buf_optimal_sz = 600;
00195 cfg.rc_buf_sz = 1000;
00196
00197
00198 cfg.g_error_resilient = 1;
00199 cfg.g_lag_in_frames = 0;
00200 cfg.kf_mode = VPX_KF_DISABLED;
00201
00202
00203 cfg.kf_min_dist = cfg.kf_max_dist = 1000;
00204
00205
00206
00207
00208
00209
00210 switch (layering_mode)
00211 {
00212
00213 case 0:
00214 {
00215
00216 int ids[2] = {0,1};
00217 cfg.ts_number_layers = 2;
00218 cfg.ts_periodicity = 2;
00219 cfg.ts_rate_decimator[0] = 2;
00220 cfg.ts_rate_decimator[1] = 1;
00221 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00222
00223 flag_periodicity = cfg.ts_periodicity;
00224 #if 1
00225
00226 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00227 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
00228 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
00229 layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
00230 VP8_EFLAG_NO_REF_ARF;
00231 #else
00232
00233 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00234 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
00235 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
00236 layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
00237 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST;
00238 #endif
00239 break;
00240 }
00241
00242 case 1:
00243 {
00244
00245 int ids[3] = {0,1,1};
00246 cfg.ts_number_layers = 2;
00247 cfg.ts_periodicity = 3;
00248 cfg.ts_rate_decimator[0] = 3;
00249 cfg.ts_rate_decimator[1] = 1;
00250 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00251
00252 flag_periodicity = cfg.ts_periodicity;
00253
00254
00255 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00256 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00257 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00258 layer_flags[1] =
00259 layer_flags[2] = VP8_EFLAG_NO_REF_GF |
00260 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
00261 VP8_EFLAG_NO_UPD_LAST;
00262 break;
00263 }
00264
00265 case 2:
00266 {
00267
00268 int ids[6] = {0,2,2,1,2,2};
00269 cfg.ts_number_layers = 3;
00270 cfg.ts_periodicity = 6;
00271 cfg.ts_rate_decimator[0] = 6;
00272 cfg.ts_rate_decimator[1] = 3;
00273 cfg.ts_rate_decimator[2] = 1;
00274 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00275
00276 flag_periodicity = cfg.ts_periodicity;
00277
00278
00279 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00280 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00281 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00282 layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
00283 VP8_EFLAG_NO_UPD_LAST;
00284 layer_flags[1] =
00285 layer_flags[2] =
00286 layer_flags[4] =
00287 layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
00288 break;
00289 }
00290
00291 case 3:
00292 {
00293
00294 int ids[4] = {0,2,1,2};
00295 cfg.ts_number_layers = 3;
00296 cfg.ts_periodicity = 4;
00297 cfg.ts_rate_decimator[0] = 4;
00298 cfg.ts_rate_decimator[1] = 2;
00299 cfg.ts_rate_decimator[2] = 1;
00300 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00301
00302 flag_periodicity = cfg.ts_periodicity;
00303
00304
00305 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00306 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00307 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00308 layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00309 VP8_EFLAG_NO_UPD_ARF |
00310 VP8_EFLAG_NO_UPD_LAST;
00311 layer_flags[1] =
00312 layer_flags[3] = VP8_EFLAG_NO_REF_ARF |
00313 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
00314 VP8_EFLAG_NO_UPD_ARF;
00315 break;
00316 }
00317
00318 case 4:
00319 {
00320
00321 int ids[4] = {0,2,1,2};
00322 cfg.ts_number_layers = 3;
00323 cfg.ts_periodicity = 4;
00324 cfg.ts_rate_decimator[0] = 4;
00325 cfg.ts_rate_decimator[1] = 2;
00326 cfg.ts_rate_decimator[2] = 1;
00327 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00328
00329 flag_periodicity = cfg.ts_periodicity;
00330
00331
00332
00333 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00334 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00335 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00336 layer_flags[2] = VP8_EFLAG_NO_REF_ARF |
00337 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
00338 layer_flags[1] =
00339 layer_flags[3] = VP8_EFLAG_NO_REF_ARF |
00340 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
00341 VP8_EFLAG_NO_UPD_ARF;
00342 break;
00343 }
00344
00345 case 5:
00346 {
00347
00348 int ids[4] = {0,2,1,2};
00349 cfg.ts_number_layers = 3;
00350 cfg.ts_periodicity = 4;
00351 cfg.ts_rate_decimator[0] = 4;
00352 cfg.ts_rate_decimator[1] = 2;
00353 cfg.ts_rate_decimator[2] = 1;
00354 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00355
00356 flag_periodicity = cfg.ts_periodicity;
00357
00358
00359 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00360 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00361 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00362 layer_flags[2] = VP8_EFLAG_NO_REF_ARF |
00363 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
00364 layer_flags[1] =
00365 layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
00366 break;
00367 }
00368
00369 case 6:
00370 {
00371
00372
00373
00374 int ids[16] = {0,4,3,4,2,4,3,4,1,4,3,4,2,4,3,4};
00375 cfg.ts_number_layers = 5;
00376 cfg.ts_periodicity = 16;
00377 cfg.ts_rate_decimator[0] = 16;
00378 cfg.ts_rate_decimator[1] = 8;
00379 cfg.ts_rate_decimator[2] = 4;
00380 cfg.ts_rate_decimator[3] = 2;
00381 cfg.ts_rate_decimator[4] = 1;
00382 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00383
00384 flag_periodicity = cfg.ts_periodicity;
00385
00386 layer_flags[0] = VPX_EFLAG_FORCE_KF;
00387 layer_flags[1] =
00388 layer_flags[3] =
00389 layer_flags[5] =
00390 layer_flags[7] =
00391 layer_flags[9] =
00392 layer_flags[11] =
00393 layer_flags[13] =
00394 layer_flags[15] = VP8_EFLAG_NO_UPD_LAST |
00395 VP8_EFLAG_NO_UPD_GF |
00396 VP8_EFLAG_NO_UPD_ARF;
00397 layer_flags[2] =
00398 layer_flags[6] =
00399 layer_flags[10] =
00400 layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF;
00401 layer_flags[4] =
00402 layer_flags[12] = VP8_EFLAG_NO_REF_LAST |
00403 VP8_EFLAG_NO_UPD_ARF;
00404 layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF;
00405 break;
00406 }
00407
00408 case 7:
00409 {
00410
00411 int ids[2] = {0,1};
00412 cfg.ts_number_layers = 2;
00413 cfg.ts_periodicity = 2;
00414 cfg.ts_rate_decimator[0] = 2;
00415 cfg.ts_rate_decimator[1] = 1;
00416 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00417
00418 flag_periodicity = 8;
00419
00420
00421 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00422 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00423 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00424 layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00425 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
00426 layer_flags[2] =
00427 layer_flags[4] =
00428 layer_flags[6] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00429 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00430 layer_flags[3] =
00431 layer_flags[5] = VP8_EFLAG_NO_REF_ARF |
00432 VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
00433 layer_flags[7] = VP8_EFLAG_NO_REF_ARF |
00434 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
00435 VP8_EFLAG_NO_UPD_ARF |
00436 VP8_EFLAG_NO_UPD_ENTROPY;
00437 break;
00438 }
00439
00440 case 8:
00441 default:
00442 {
00443
00444 int ids[4] = {0,2,1,2};
00445 cfg.ts_number_layers = 3;
00446 cfg.ts_periodicity = 4;
00447 cfg.ts_rate_decimator[0] = 4;
00448 cfg.ts_rate_decimator[1] = 2;
00449 cfg.ts_rate_decimator[2] = 1;
00450 memcpy(cfg.ts_layer_id, ids, sizeof(ids));
00451
00452 flag_periodicity = 8;
00453
00454
00455 layer_flags[0] = VPX_EFLAG_FORCE_KF |
00456 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00457 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00458 layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00459 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
00460 layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00461 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
00462 layer_flags[3] =
00463 layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
00464 layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
00465 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
00466 layer_flags[6] = VP8_EFLAG_NO_REF_ARF |
00467 VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
00468 layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
00469 VP8_EFLAG_NO_UPD_ARF |
00470 VP8_EFLAG_NO_UPD_ENTROPY;
00471 break;
00472 }
00473 }
00474
00475
00476 if(!(infile = fopen(argv[1], "rb")))
00477 die("Failed to open %s for reading", argv[1]);
00478
00479
00480 for (i=0; i<cfg.ts_number_layers; i++)
00481 {
00482 char file_name[512];
00483 sprintf (file_name, "%s_%d.ivf", argv[2], i);
00484 if (!(outfile[i] = fopen(file_name, "wb")))
00485 die("Failed to open %s for writing", file_name);
00486 write_ivf_file_header(outfile[i], &cfg, 0);
00487 }
00488
00489
00490 if (vpx_codec_enc_init (&codec, interface, &cfg, 0))
00491 die_codec (&codec, "Failed to initialize encoder");
00492
00493
00494 vpx_codec_control (&codec, VP8E_SET_CPUUSED, -6);
00495 vpx_codec_control (&codec, VP8E_SET_STATIC_THRESHOLD, 800);
00496 vpx_codec_control (&codec, VP8E_SET_NOISE_SENSITIVITY, 2);
00497
00498 max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5)
00499 * ((double) cfg.g_timebase.den / cfg.g_timebase.num)
00500 / 10.0);
00501
00502
00503 vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT,
00504 max_intra_size_pct);
00505
00506
00507
00508 frame_avail = 1;
00509 while (frame_avail || got_data) {
00510 vpx_codec_iter_t iter = NULL;
00511 const vpx_codec_cx_pkt_t *pkt;
00512
00513 flags = layer_flags[frame_cnt % flag_periodicity];
00514
00515 frame_avail = read_frame(infile, &raw);
00516 if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts,
00517 1, flags, VPX_DL_REALTIME))
00518 die_codec(&codec, "Failed to encode frame");
00519
00520
00521 if (layering_mode != 6)
00522 layer_flags[0] &= ~VPX_EFLAG_FORCE_KF;
00523
00524 got_data = 0;
00525 while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
00526 got_data = 1;
00527 switch (pkt->kind) {
00528 case VPX_CODEC_CX_FRAME_PKT:
00529 for (i=cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
00530 i<cfg.ts_number_layers; i++)
00531 {
00532 write_ivf_frame_header(outfile[i], pkt);
00533 if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
00534 outfile[i]));
00535 frames_in_layer[i]++;
00536 }
00537 break;
00538 default:
00539 break;
00540 }
00541 printf (pkt->kind == VPX_CODEC_CX_FRAME_PKT
00542 && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
00543 fflush (stdout);
00544 }
00545 frame_cnt++;
00546 pts += frame_duration;
00547 }
00548 printf ("\n");
00549 fclose (infile);
00550
00551 printf ("Processed %d frames.\n",frame_cnt-1);
00552 if (vpx_codec_destroy(&codec))
00553 die_codec (&codec, "Failed to destroy codec");
00554
00555
00556 for (i=0; i<cfg.ts_number_layers; i++)
00557 {
00558 if (!fseek(outfile[i], 0, SEEK_SET))
00559 write_ivf_file_header (outfile[i], &cfg, frames_in_layer[i]);
00560 fclose (outfile[i]);
00561 }
00562
00563 return EXIT_SUCCESS;
00564 }
00565