Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 1 | /* |
Adrian Grange | 45f4b87 | 2012-02-06 15:02:33 -0800 | [diff] [blame] | 2 | * Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | |
| 12 | /* |
| 13 | * This is an example demonstrating how to implement a multi-layer VP8 |
| 14 | * encoding scheme based on temporal scalability for video applications |
| 15 | * that benefit from a scalable bitstream. |
| 16 | */ |
| 17 | #include <stdio.h> |
| 18 | #include <stdlib.h> |
| 19 | #include <stdarg.h> |
| 20 | #include <string.h> |
| 21 | #define VPX_CODEC_DISABLE_COMPAT 1 |
| 22 | #include "vpx/vpx_encoder.h" |
| 23 | #include "vpx/vp8cx.h" |
| 24 | #define interface (vpx_codec_vp8_cx()) |
| 25 | #define fourcc 0x30385056 |
| 26 | |
| 27 | #define IVF_FILE_HDR_SZ (32) |
| 28 | #define IVF_FRAME_HDR_SZ (12) |
| 29 | |
| 30 | static void mem_put_le16(char *mem, unsigned int val) { |
| 31 | mem[0] = val; |
| 32 | mem[1] = val>>8; |
| 33 | } |
| 34 | |
| 35 | static void mem_put_le32(char *mem, unsigned int val) { |
| 36 | mem[0] = val; |
| 37 | mem[1] = val>>8; |
| 38 | mem[2] = val>>16; |
| 39 | mem[3] = val>>24; |
| 40 | } |
| 41 | |
| 42 | static void die(const char *fmt, ...) { |
| 43 | va_list ap; |
| 44 | |
| 45 | va_start(ap, fmt); |
| 46 | vprintf(fmt, ap); |
| 47 | if(fmt[strlen(fmt)-1] != '\n') |
| 48 | printf("\n"); |
| 49 | exit(EXIT_FAILURE); |
| 50 | } |
| 51 | |
| 52 | static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { |
| 53 | const char *detail = vpx_codec_error_detail(ctx); |
| 54 | |
| 55 | printf("%s: %s\n", s, vpx_codec_error(ctx)); |
| 56 | if(detail) |
| 57 | printf(" %s\n",detail); |
| 58 | exit(EXIT_FAILURE); |
| 59 | } |
| 60 | |
| 61 | static int read_frame(FILE *f, vpx_image_t *img) { |
| 62 | size_t nbytes, to_read; |
| 63 | int res = 1; |
| 64 | |
| 65 | to_read = img->w*img->h*3/2; |
| 66 | nbytes = fread(img->planes[0], 1, to_read, f); |
| 67 | if(nbytes != to_read) { |
| 68 | res = 0; |
| 69 | if(nbytes > 0) |
| 70 | printf("Warning: Read partial frame. Check your width & height!\n"); |
| 71 | } |
| 72 | return res; |
| 73 | } |
| 74 | |
| 75 | static void write_ivf_file_header(FILE *outfile, |
| 76 | const vpx_codec_enc_cfg_t *cfg, |
| 77 | int frame_cnt) { |
| 78 | char header[32]; |
| 79 | |
| 80 | if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) |
| 81 | return; |
| 82 | header[0] = 'D'; |
| 83 | header[1] = 'K'; |
| 84 | header[2] = 'I'; |
| 85 | header[3] = 'F'; |
| 86 | mem_put_le16(header+4, 0); /* version */ |
| 87 | mem_put_le16(header+6, 32); /* headersize */ |
| 88 | mem_put_le32(header+8, fourcc); /* headersize */ |
| 89 | mem_put_le16(header+12, cfg->g_w); /* width */ |
| 90 | mem_put_le16(header+14, cfg->g_h); /* height */ |
| 91 | mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ |
| 92 | mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ |
| 93 | mem_put_le32(header+24, frame_cnt); /* length */ |
| 94 | mem_put_le32(header+28, 0); /* unused */ |
| 95 | |
Johann | c8a88a7 | 2012-05-02 14:12:57 -0700 | [diff] [blame] | 96 | (void) fwrite(header, 1, 32, outfile); |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | |
| 100 | static void write_ivf_frame_header(FILE *outfile, |
| 101 | const vpx_codec_cx_pkt_t *pkt) |
| 102 | { |
| 103 | char header[12]; |
| 104 | vpx_codec_pts_t pts; |
| 105 | |
| 106 | if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) |
| 107 | return; |
| 108 | |
| 109 | pts = pkt->data.frame.pts; |
| 110 | mem_put_le32(header, pkt->data.frame.sz); |
| 111 | mem_put_le32(header+4, pts&0xFFFFFFFF); |
| 112 | mem_put_le32(header+8, pts >> 32); |
| 113 | |
Johann | c8a88a7 | 2012-05-02 14:12:57 -0700 | [diff] [blame] | 114 | (void) fwrite(header, 1, 12, outfile); |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 115 | } |
| 116 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 117 | static int mode_to_num_layers[9] = {2, 2, 3, 3, 3, 3, 5, 2, 3}; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 118 | |
| 119 | int main(int argc, char **argv) { |
John Koleszar | d46ddd0 | 2012-05-02 16:21:52 -0700 | [diff] [blame] | 120 | FILE *infile, *outfile[VPX_TS_MAX_LAYERS]; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 121 | vpx_codec_ctx_t codec; |
| 122 | vpx_codec_enc_cfg_t cfg; |
| 123 | int frame_cnt = 0; |
| 124 | vpx_image_t raw; |
| 125 | vpx_codec_err_t res; |
| 126 | unsigned int width; |
| 127 | unsigned int height; |
| 128 | int frame_avail; |
| 129 | int got_data; |
| 130 | int flags = 0; |
| 131 | int i; |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 132 | int pts = 0; /* PTS starts at 0 */ |
| 133 | int frame_duration = 1; /* 1 timebase tick per frame */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 134 | |
| 135 | int layering_mode = 0; |
John Koleszar | d46ddd0 | 2012-05-02 16:21:52 -0700 | [diff] [blame] | 136 | int frames_in_layer[VPX_TS_MAX_LAYERS] = {0}; |
| 137 | int layer_flags[VPX_TS_MAX_PERIODICITY] = {0}; |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 138 | int flag_periodicity; |
| 139 | int max_intra_size_pct; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 140 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 141 | /* Check usage and arguments */ |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 142 | if (argc < 9) |
| 143 | die("Usage: %s <infile> <outfile> <width> <height> <rate_num> " |
| 144 | " <rate_den> <mode> <Rate_0> ... <Rate_nlayers-1>\n", argv[0]); |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 145 | |
| 146 | width = strtol (argv[3], NULL, 0); |
| 147 | height = strtol (argv[4], NULL, 0); |
| 148 | if (width < 16 || width%2 || height <16 || height%2) |
| 149 | die ("Invalid resolution: %d x %d", width, height); |
| 150 | |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 151 | if (!sscanf(argv[7], "%d", &layering_mode)) |
| 152 | die ("Invalid mode %s", argv[7]); |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 153 | if (layering_mode<0 || layering_mode>8) |
| 154 | die ("Invalid mode (0..8) %s", argv[7]); |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 155 | |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 156 | if (argc != 8+mode_to_num_layers[layering_mode]) |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 157 | die ("Invalid number of arguments"); |
| 158 | |
James Zern | 1e1799c | 2012-05-18 19:22:26 -0700 | [diff] [blame] | 159 | if (!vpx_img_alloc (&raw, VPX_IMG_FMT_I420, width, height, 32)) |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 160 | die ("Failed to allocate image", width, height); |
| 161 | |
| 162 | printf("Using %s\n",vpx_codec_iface_name(interface)); |
| 163 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 164 | /* Populate encoder configuration */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 165 | res = vpx_codec_enc_config_default(interface, &cfg, 0); |
| 166 | if(res) { |
| 167 | printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); |
| 168 | return EXIT_FAILURE; |
| 169 | } |
| 170 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 171 | /* Update the default configuration with our settings */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 172 | cfg.g_w = width; |
| 173 | cfg.g_h = height; |
| 174 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 175 | /* Timebase format e.g. 30fps: numerator=1, demoninator=30 */ |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 176 | if (!sscanf (argv[5], "%d", &cfg.g_timebase.num )) |
| 177 | die ("Invalid timebase numerator %s", argv[5]); |
| 178 | if (!sscanf (argv[6], "%d", &cfg.g_timebase.den )) |
| 179 | die ("Invalid timebase denominator %s", argv[6]); |
| 180 | |
| 181 | for (i=8; i<8+mode_to_num_layers[layering_mode]; i++) |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 182 | if (!sscanf(argv[i], "%ud", &cfg.ts_target_bitrate[i-8])) |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 183 | die ("Invalid data rate %s", argv[i]); |
| 184 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 185 | /* Real time parameters */ |
| 186 | cfg.rc_dropframe_thresh = 0; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 187 | cfg.rc_end_usage = VPX_CBR; |
| 188 | cfg.rc_resize_allowed = 0; |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 189 | cfg.rc_min_quantizer = 8; |
| 190 | cfg.rc_max_quantizer = 56; |
| 191 | cfg.rc_undershoot_pct = 100; |
| 192 | cfg.rc_overshoot_pct = 15; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 193 | cfg.rc_buf_initial_sz = 500; |
| 194 | cfg.rc_buf_optimal_sz = 600; |
| 195 | cfg.rc_buf_sz = 1000; |
| 196 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 197 | /* Enable error resilient mode */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 198 | cfg.g_error_resilient = 1; |
| 199 | cfg.g_lag_in_frames = 0; |
| 200 | cfg.kf_mode = VPX_KF_DISABLED; |
| 201 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 202 | /* Disable automatic keyframe placement */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 203 | cfg.kf_min_dist = cfg.kf_max_dist = 1000; |
| 204 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 205 | /* Temporal scaling parameters: */ |
| 206 | /* NOTE: The 3 prediction frames cannot be used interchangeably due to |
| 207 | * differences in the way they are handled throughout the code. The |
| 208 | * frames should be allocated to layers in the order LAST, GF, ARF. |
| 209 | * Other combinations work, but may produce slightly inferior results. |
| 210 | */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 211 | switch (layering_mode) |
| 212 | { |
| 213 | |
| 214 | case 0: |
| 215 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 216 | /* 2-layers, 2-frame period */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 217 | int ids[2] = {0,1}; |
| 218 | cfg.ts_number_layers = 2; |
| 219 | cfg.ts_periodicity = 2; |
| 220 | cfg.ts_rate_decimator[0] = 2; |
| 221 | cfg.ts_rate_decimator[1] = 1; |
| 222 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 223 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 224 | flag_periodicity = cfg.ts_periodicity; |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 225 | #if 1 |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 226 | /* 0=L, 1=GF, Intra-layer prediction enabled */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 227 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 228 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | |
| 229 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; |
| 230 | layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | |
| 231 | VP8_EFLAG_NO_REF_ARF; |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 232 | #else |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 233 | /* 0=L, 1=GF, Intra-layer prediction disabled */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 234 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 235 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | |
| 236 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; |
| 237 | layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | |
| 238 | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST; |
| 239 | #endif |
| 240 | break; |
| 241 | } |
| 242 | |
| 243 | case 1: |
| 244 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 245 | /* 2-layers, 3-frame period */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 246 | int ids[3] = {0,1,1}; |
| 247 | cfg.ts_number_layers = 2; |
| 248 | cfg.ts_periodicity = 3; |
| 249 | cfg.ts_rate_decimator[0] = 3; |
| 250 | cfg.ts_rate_decimator[1] = 1; |
| 251 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 252 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 253 | flag_periodicity = cfg.ts_periodicity; |
| 254 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 255 | /* 0=L, 1=GF, Intra-layer prediction enabled */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 256 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 257 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 258 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 259 | layer_flags[1] = |
| 260 | layer_flags[2] = VP8_EFLAG_NO_REF_GF | |
| 261 | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | |
| 262 | VP8_EFLAG_NO_UPD_LAST; |
| 263 | break; |
| 264 | } |
| 265 | |
| 266 | case 2: |
| 267 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 268 | /* 3-layers, 6-frame period */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 269 | int ids[6] = {0,2,2,1,2,2}; |
| 270 | cfg.ts_number_layers = 3; |
| 271 | cfg.ts_periodicity = 6; |
| 272 | cfg.ts_rate_decimator[0] = 6; |
| 273 | cfg.ts_rate_decimator[1] = 3; |
| 274 | cfg.ts_rate_decimator[2] = 1; |
| 275 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 276 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 277 | flag_periodicity = cfg.ts_periodicity; |
| 278 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 279 | /* 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 280 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 281 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 282 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 283 | layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | |
| 284 | VP8_EFLAG_NO_UPD_LAST; |
| 285 | layer_flags[1] = |
| 286 | layer_flags[2] = |
| 287 | layer_flags[4] = |
| 288 | layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; |
| 289 | break; |
| 290 | } |
| 291 | |
| 292 | case 3: |
| 293 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 294 | /* 3-layers, 4-frame period */ |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 295 | int ids[4] = {0,2,1,2}; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 296 | cfg.ts_number_layers = 3; |
| 297 | cfg.ts_periodicity = 4; |
| 298 | cfg.ts_rate_decimator[0] = 4; |
| 299 | cfg.ts_rate_decimator[1] = 2; |
| 300 | cfg.ts_rate_decimator[2] = 1; |
| 301 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 302 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 303 | flag_periodicity = cfg.ts_periodicity; |
| 304 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 305 | /* 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 306 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 307 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 308 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 309 | layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 310 | VP8_EFLAG_NO_UPD_ARF | |
| 311 | VP8_EFLAG_NO_UPD_LAST; |
| 312 | layer_flags[1] = |
| 313 | layer_flags[3] = VP8_EFLAG_NO_REF_ARF | |
| 314 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | |
| 315 | VP8_EFLAG_NO_UPD_ARF; |
| 316 | break; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 317 | } |
| 318 | |
| 319 | case 4: |
| 320 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 321 | /* 3-layers, 4-frame period */ |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 322 | int ids[4] = {0,2,1,2}; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 323 | cfg.ts_number_layers = 3; |
| 324 | cfg.ts_periodicity = 4; |
| 325 | cfg.ts_rate_decimator[0] = 4; |
| 326 | cfg.ts_rate_decimator[1] = 2; |
| 327 | cfg.ts_rate_decimator[2] = 1; |
| 328 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 329 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 330 | flag_periodicity = cfg.ts_periodicity; |
| 331 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 332 | /* 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, |
| 333 | * disabled in layer 2 |
| 334 | */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 335 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 336 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 337 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 338 | layer_flags[2] = VP8_EFLAG_NO_REF_ARF | |
| 339 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; |
| 340 | layer_flags[1] = |
| 341 | layer_flags[3] = VP8_EFLAG_NO_REF_ARF | |
| 342 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | |
| 343 | VP8_EFLAG_NO_UPD_ARF; |
| 344 | break; |
| 345 | } |
| 346 | |
| 347 | case 5: |
| 348 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 349 | /* 3-layers, 4-frame period */ |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 350 | int ids[4] = {0,2,1,2}; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 351 | cfg.ts_number_layers = 3; |
| 352 | cfg.ts_periodicity = 4; |
| 353 | cfg.ts_rate_decimator[0] = 4; |
| 354 | cfg.ts_rate_decimator[1] = 2; |
| 355 | cfg.ts_rate_decimator[2] = 1; |
| 356 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 357 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 358 | flag_periodicity = cfg.ts_periodicity; |
| 359 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 360 | /* 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 361 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 362 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 363 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 364 | layer_flags[2] = VP8_EFLAG_NO_REF_ARF | |
| 365 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; |
| 366 | layer_flags[1] = |
| 367 | layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; |
| 368 | break; |
| 369 | } |
| 370 | |
| 371 | case 6: |
| 372 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 373 | /* NOTE: Probably of academic interest only */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 374 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 375 | /* 5-layers, 16-frame period */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 376 | int ids[16] = {0,4,3,4,2,4,3,4,1,4,3,4,2,4,3,4}; |
| 377 | cfg.ts_number_layers = 5; |
| 378 | cfg.ts_periodicity = 16; |
| 379 | cfg.ts_rate_decimator[0] = 16; |
| 380 | cfg.ts_rate_decimator[1] = 8; |
| 381 | cfg.ts_rate_decimator[2] = 4; |
| 382 | cfg.ts_rate_decimator[3] = 2; |
| 383 | cfg.ts_rate_decimator[4] = 1; |
| 384 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 385 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 386 | flag_periodicity = cfg.ts_periodicity; |
| 387 | |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 388 | layer_flags[0] = VPX_EFLAG_FORCE_KF; |
| 389 | layer_flags[1] = |
| 390 | layer_flags[3] = |
| 391 | layer_flags[5] = |
| 392 | layer_flags[7] = |
| 393 | layer_flags[9] = |
| 394 | layer_flags[11] = |
| 395 | layer_flags[13] = |
| 396 | layer_flags[15] = VP8_EFLAG_NO_UPD_LAST | |
| 397 | VP8_EFLAG_NO_UPD_GF | |
Adrian Grange | 45f4b87 | 2012-02-06 15:02:33 -0800 | [diff] [blame] | 398 | VP8_EFLAG_NO_UPD_ARF; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 399 | layer_flags[2] = |
| 400 | layer_flags[6] = |
| 401 | layer_flags[10] = |
Adrian Grange | 45f4b87 | 2012-02-06 15:02:33 -0800 | [diff] [blame] | 402 | layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 403 | layer_flags[4] = |
Adrian Grange | 45f4b87 | 2012-02-06 15:02:33 -0800 | [diff] [blame] | 404 | layer_flags[12] = VP8_EFLAG_NO_REF_LAST | |
| 405 | VP8_EFLAG_NO_UPD_ARF; |
| 406 | layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 407 | break; |
| 408 | } |
| 409 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 410 | case 7: |
| 411 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 412 | /* 2-layers */ |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 413 | int ids[2] = {0,1}; |
| 414 | cfg.ts_number_layers = 2; |
| 415 | cfg.ts_periodicity = 2; |
| 416 | cfg.ts_rate_decimator[0] = 2; |
| 417 | cfg.ts_rate_decimator[1] = 1; |
| 418 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 419 | |
| 420 | flag_periodicity = 8; |
| 421 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 422 | /* 0=L, 1=GF */ |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 423 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 424 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 425 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 426 | layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 427 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; |
| 428 | layer_flags[2] = |
| 429 | layer_flags[4] = |
| 430 | layer_flags[6] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 431 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 432 | layer_flags[3] = |
| 433 | layer_flags[5] = VP8_EFLAG_NO_REF_ARF | |
| 434 | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; |
| 435 | layer_flags[7] = VP8_EFLAG_NO_REF_ARF | |
| 436 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | |
| 437 | VP8_EFLAG_NO_UPD_ARF | |
| 438 | VP8_EFLAG_NO_UPD_ENTROPY; |
| 439 | break; |
| 440 | } |
| 441 | |
| 442 | case 8: |
Attila Nagy | 14c9fce | 2012-04-27 13:41:58 +0300 | [diff] [blame] | 443 | default: |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 444 | { |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 445 | /* 3-layers */ |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 446 | int ids[4] = {0,2,1,2}; |
| 447 | cfg.ts_number_layers = 3; |
| 448 | cfg.ts_periodicity = 4; |
| 449 | cfg.ts_rate_decimator[0] = 4; |
| 450 | cfg.ts_rate_decimator[1] = 2; |
| 451 | cfg.ts_rate_decimator[2] = 1; |
| 452 | memcpy(cfg.ts_layer_id, ids, sizeof(ids)); |
| 453 | |
| 454 | flag_periodicity = 8; |
| 455 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 456 | /* 0=L, 1=GF, 2=ARF */ |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 457 | layer_flags[0] = VPX_EFLAG_FORCE_KF | |
| 458 | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 459 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 460 | layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 461 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; |
| 462 | layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 463 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; |
| 464 | layer_flags[3] = |
| 465 | layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; |
| 466 | layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | |
| 467 | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| 468 | layer_flags[6] = VP8_EFLAG_NO_REF_ARF | |
| 469 | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; |
| 470 | layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | |
| 471 | VP8_EFLAG_NO_UPD_ARF | |
| 472 | VP8_EFLAG_NO_UPD_ENTROPY; |
| 473 | break; |
| 474 | } |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 475 | } |
| 476 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 477 | /* Open input file */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 478 | if(!(infile = fopen(argv[1], "rb"))) |
| 479 | die("Failed to open %s for reading", argv[1]); |
| 480 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 481 | /* Open an output file for each stream */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 482 | for (i=0; i<cfg.ts_number_layers; i++) |
| 483 | { |
| 484 | char file_name[512]; |
| 485 | sprintf (file_name, "%s_%d.ivf", argv[2], i); |
| 486 | if (!(outfile[i] = fopen(file_name, "wb"))) |
| 487 | die("Failed to open %s for writing", file_name); |
| 488 | write_ivf_file_header(outfile[i], &cfg, 0); |
| 489 | } |
| 490 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 491 | /* Initialize codec */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 492 | if (vpx_codec_enc_init (&codec, interface, &cfg, 0)) |
| 493 | die_codec (&codec, "Failed to initialize encoder"); |
| 494 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 495 | /* Cap CPU & first I-frame size */ |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 496 | vpx_codec_control (&codec, VP8E_SET_CPUUSED, -6); |
| 497 | vpx_codec_control (&codec, VP8E_SET_STATIC_THRESHOLD, 800); |
Jim Bankoski | 57faddb | 2012-05-24 07:44:03 -0700 | [diff] [blame] | 498 | vpx_codec_control (&codec, VP8E_SET_NOISE_SENSITIVITY, 1); |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 499 | |
| 500 | max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5) |
| 501 | * ((double) cfg.g_timebase.den / cfg.g_timebase.num) |
| 502 | / 10.0); |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 503 | /* printf ("max_intra_size_pct=%d\n", max_intra_size_pct); */ |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 504 | |
| 505 | vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, |
| 506 | max_intra_size_pct); |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 507 | |
| 508 | frame_avail = 1; |
| 509 | while (frame_avail || got_data) { |
| 510 | vpx_codec_iter_t iter = NULL; |
| 511 | const vpx_codec_cx_pkt_t *pkt; |
| 512 | |
Adrian Grange | 8978358 | 2012-01-26 16:50:15 -0800 | [diff] [blame] | 513 | flags = layer_flags[frame_cnt % flag_periodicity]; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 514 | |
| 515 | frame_avail = read_frame(infile, &raw); |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 516 | if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 517 | 1, flags, VPX_DL_REALTIME)) |
| 518 | die_codec(&codec, "Failed to encode frame"); |
| 519 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 520 | /* Reset KF flag */ |
Adrian Grange | 45f4b87 | 2012-02-06 15:02:33 -0800 | [diff] [blame] | 521 | if (layering_mode != 6) |
| 522 | layer_flags[0] &= ~VPX_EFLAG_FORCE_KF; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 523 | |
| 524 | got_data = 0; |
| 525 | while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) { |
| 526 | got_data = 1; |
| 527 | switch (pkt->kind) { |
| 528 | case VPX_CODEC_CX_FRAME_PKT: |
| 529 | for (i=cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; |
| 530 | i<cfg.ts_number_layers; i++) |
| 531 | { |
| 532 | write_ivf_frame_header(outfile[i], pkt); |
Johann | c8a88a7 | 2012-05-02 14:12:57 -0700 | [diff] [blame] | 533 | (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, |
| 534 | outfile[i]); |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 535 | frames_in_layer[i]++; |
| 536 | } |
| 537 | break; |
| 538 | default: |
| 539 | break; |
| 540 | } |
| 541 | printf (pkt->kind == VPX_CODEC_CX_FRAME_PKT |
| 542 | && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); |
| 543 | fflush (stdout); |
| 544 | } |
| 545 | frame_cnt++; |
Adrian Grange | e479379 | 2012-01-13 14:09:40 -0800 | [diff] [blame] | 546 | pts += frame_duration; |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 547 | } |
| 548 | printf ("\n"); |
| 549 | fclose (infile); |
| 550 | |
| 551 | printf ("Processed %d frames.\n",frame_cnt-1); |
| 552 | if (vpx_codec_destroy(&codec)) |
| 553 | die_codec (&codec, "Failed to destroy codec"); |
| 554 | |
John Koleszar | 0164a1c | 2012-05-21 14:30:56 -0700 | [diff] [blame] | 555 | /* Try to rewrite the output file headers with the actual frame count */ |
Adrian Grange | 217591f | 2011-10-06 15:49:11 -0700 | [diff] [blame] | 556 | for (i=0; i<cfg.ts_number_layers; i++) |
| 557 | { |
| 558 | if (!fseek(outfile[i], 0, SEEK_SET)) |
| 559 | write_ivf_file_header (outfile[i], &cfg, frames_in_layer[i]); |
| 560 | fclose (outfile[i]); |
| 561 | } |
| 562 | |
| 563 | return EXIT_SUCCESS; |
| 564 | } |