WebM VP8 Codec SDK
vp8_scalable_patterns
1 /*
2  * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3  *
4  * Use of this source code is governed by a BSD-style license
5  * that can be found in the LICENSE file in the root of the source
6  * tree. An additional intellectual property rights grant can be found
7  * in the file PATENTS. All contributing project authors may
8  * be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 
12 /*
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 
96  if(fwrite(header, 1, 32, outfile));
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 
114  if(fwrite(header, 1, 12, outfile));
115 }
116 
117 static int mode_to_num_layers[7] = {2, 2, 3, 3, 3, 3, 5};
118 
119 int main(int argc, char **argv) {
120  FILE *infile, *outfile[MAX_LAYERS];
121  vpx_codec_ctx_t codec;
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;
132  int pts = 0; // PTS starts at 0
133  int frame_duration = 1; // 1 timebase tick per frame
134 
135  int layering_mode = 0;
136  int frames_in_layer[MAX_LAYERS] = {0};
137  int layer_flags[MAX_PERIODICITY] = {0};
138 
139  // Check usage and arguments
140  if (argc < 9)
141  die("Usage: %s <infile> <outfile> <width> <height> <rate_num> "
142  " <rate_den> <mode> <Rate_0> ... <Rate_nlayers-1>\n", argv[0]);
143 
144  width = strtol (argv[3], NULL, 0);
145  height = strtol (argv[4], NULL, 0);
146  if (width < 16 || width%2 || height <16 || height%2)
147  die ("Invalid resolution: %d x %d", width, height);
148 
149  if (!sscanf(argv[7], "%d", &layering_mode))
150  die ("Invalid mode %s", argv[7]);
151  if (layering_mode<0 || layering_mode>6)
152  die ("Invalid mode (0..6) %s", argv[7]);
153 
154  if (argc != 8+mode_to_num_layers[layering_mode])
155  die ("Invalid number of arguments");
156 
157  if (!vpx_img_alloc (&raw, VPX_IMG_FMT_I420, width, height, 1))
158  die ("Failed to allocate image", width, height);
159 
160  printf("Using %s\n",vpx_codec_iface_name(interface));
161 
162  // Populate encoder configuration
163  res = vpx_codec_enc_config_default(interface, &cfg, 0);
164  if(res) {
165  printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
166  return EXIT_FAILURE;
167  }
168 
169  // Update the default configuration with our settings
170  cfg.g_w = width;
171  cfg.g_h = height;
172 
173  // Timebase format e.g. 30fps: numerator=1, demoninator=30
174  if (!sscanf (argv[5], "%d", &cfg.g_timebase.num ))
175  die ("Invalid timebase numerator %s", argv[5]);
176  if (!sscanf (argv[6], "%d", &cfg.g_timebase.den ))
177  die ("Invalid timebase denominator %s", argv[6]);
178 
179  for (i=8; i<8+mode_to_num_layers[layering_mode]; i++)
180  if (!sscanf(argv[i], "%d", &cfg.ts_target_bitrate[i-8]))
181  die ("Invalid data rate %s", argv[i]);
182 
183  // Real time parameters
184  cfg.rc_dropframe_thresh = 0;
185  cfg.rc_end_usage = VPX_CBR;
186  cfg.rc_resize_allowed = 0;
187  cfg.rc_min_quantizer = 4;
188  cfg.rc_max_quantizer = 63;
189  cfg.rc_undershoot_pct = 98;
190  cfg.rc_overshoot_pct = 100;
191  cfg.rc_buf_initial_sz = 500;
192  cfg.rc_buf_optimal_sz = 600;
193  cfg.rc_buf_sz = 1000;
194 
195  // Enable error resilient mode
196  cfg.g_error_resilient = 1;
197  cfg.g_lag_in_frames = 0;
198  cfg.kf_mode = VPX_KF_DISABLED;
199 
200  // Disable automatic keyframe placement
201  cfg.kf_min_dist = cfg.kf_max_dist = 1000;
202 
203  // Temporal scaling parameters:
204  // NOTE: The 3 prediction frames cannot be used interchangeably due to
205  // differences in the way they are handled throughout the code. The
206  // frames should be allocated to layers in the order LAST, GF, ARF.
207  // Other combinations work, but may produce slightly inferior results.
208  switch (layering_mode)
209  {
210 
211  case 0:
212  {
213  // 2-layers, 2-frame period
214  int ids[2] = {0,1};
215  cfg.ts_number_layers = 2;
216  cfg.ts_periodicity = 2;
217  cfg.ts_rate_decimator[0] = 2;
218  cfg.ts_rate_decimator[1] = 1;
219  memcpy(cfg.ts_layer_id, ids, sizeof(ids));
220 
221 #if 1
222  // 0=L, 1=GF, Intra-layer prediction enabled
223  layer_flags[0] = VPX_EFLAG_FORCE_KF |
226  layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
228 #else
229  // 0=L, 1=GF, Intra-layer prediction disabled
230  layer_flags[0] = VPX_EFLAG_FORCE_KF |
233  layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
235 #endif
236  break;
237  }
238 
239  case 1:
240  {
241  // 2-layers, 3-frame period
242  int ids[3] = {0,1,1};
243  cfg.ts_number_layers = 2;
244  cfg.ts_periodicity = 3;
245  cfg.ts_rate_decimator[0] = 3;
246  cfg.ts_rate_decimator[1] = 1;
247  memcpy(cfg.ts_layer_id, ids, sizeof(ids));
248 
249  // 0=L, 1=GF, Intra-layer prediction enabled
250  layer_flags[0] = VPX_EFLAG_FORCE_KF |
253  layer_flags[1] =
254  layer_flags[2] = VP8_EFLAG_NO_REF_GF |
257  break;
258  }
259 
260  case 2:
261  {
262  // 3-layers, 6-frame period
263  int ids[6] = {0,2,2,1,2,2};
264  cfg.ts_number_layers = 3;
265  cfg.ts_periodicity = 6;
266  cfg.ts_rate_decimator[0] = 6;
267  cfg.ts_rate_decimator[1] = 3;
268  cfg.ts_rate_decimator[2] = 1;
269  memcpy(cfg.ts_layer_id, ids, sizeof(ids));
270 
271  // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled
272  layer_flags[0] = VPX_EFLAG_FORCE_KF |
275  layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
277  layer_flags[1] =
278  layer_flags[2] =
279  layer_flags[4] =
280  layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
281  break;
282  }
283 
284  case 3:
285  {
286  // 3-layers, 4-frame period
287  int ids[4] = {0,2,1,2};
288  cfg.ts_number_layers = 3;
289  cfg.ts_periodicity = 4;
290  cfg.ts_rate_decimator[0] = 4;
291  cfg.ts_rate_decimator[1] = 2;
292  cfg.ts_rate_decimator[2] = 1;
293  memcpy(cfg.ts_layer_id, ids, sizeof(ids));
294 
295  // 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled
296  layer_flags[0] = VPX_EFLAG_FORCE_KF |
299  layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
302  layer_flags[1] =
303  layer_flags[3] = VP8_EFLAG_NO_REF_ARF |
306  break;
307  }
308 
309  case 4:
310  {
311  // 3-layers, 4-frame period
312  int ids[4] = {0,2,1,2};
313  cfg.ts_number_layers = 3;
314  cfg.ts_periodicity = 4;
315  cfg.ts_rate_decimator[0] = 4;
316  cfg.ts_rate_decimator[1] = 2;
317  cfg.ts_rate_decimator[2] = 1;
318  memcpy(cfg.ts_layer_id, ids, sizeof(ids));
319 
320  // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1,
321  // disabled in layer 2
322  layer_flags[0] = VPX_EFLAG_FORCE_KF |
325  layer_flags[2] = VP8_EFLAG_NO_REF_ARF |
327  layer_flags[1] =
328  layer_flags[3] = VP8_EFLAG_NO_REF_ARF |
331  break;
332  }
333 
334  case 5:
335  {
336  // 3-layers, 4-frame period
337  int ids[4] = {0,2,1,2};
338  cfg.ts_number_layers = 3;
339  cfg.ts_periodicity = 4;
340  cfg.ts_rate_decimator[0] = 4;
341  cfg.ts_rate_decimator[1] = 2;
342  cfg.ts_rate_decimator[2] = 1;
343  memcpy(cfg.ts_layer_id, ids, sizeof(ids));
344 
345  // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled
346  layer_flags[0] = VPX_EFLAG_FORCE_KF |
349  layer_flags[2] = VP8_EFLAG_NO_REF_ARF |
351  layer_flags[1] =
352  layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
353  break;
354  }
355 
356  case 6:
357  {
358  // NOTE: Probably of academic interest only
359 
360  // 5-layers, 16-frame period
361  int ids[16] = {0,4,3,4,2,4,3,4,1,4,3,4,2,4,3,4};
362  cfg.ts_number_layers = 5;
363  cfg.ts_periodicity = 16;
364  cfg.ts_rate_decimator[0] = 16;
365  cfg.ts_rate_decimator[1] = 8;
366  cfg.ts_rate_decimator[2] = 4;
367  cfg.ts_rate_decimator[3] = 2;
368  cfg.ts_rate_decimator[4] = 1;
369  memcpy(cfg.ts_layer_id, ids, sizeof(ids));
370 
371  layer_flags[0] = VPX_EFLAG_FORCE_KF;
372  layer_flags[1] =
373  layer_flags[3] =
374  layer_flags[5] =
375  layer_flags[7] =
376  layer_flags[9] =
377  layer_flags[11] =
378  layer_flags[13] =
379  layer_flags[15] = VP8_EFLAG_NO_UPD_LAST |
383  layer_flags[2] =
384  layer_flags[6] =
385  layer_flags[10] =
386  layer_flags[14] = 0;
387  layer_flags[4] =
388  layer_flags[12] = VP8_EFLAG_NO_REF_LAST;
389  layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF |
391  break;
392  }
393 
394  default:
395  break;
396  }
397 
398  // Open input file
399  if(!(infile = fopen(argv[1], "rb")))
400  die("Failed to open %s for reading", argv[1]);
401 
402  // Open an output file for each stream
403  for (i=0; i<cfg.ts_number_layers; i++)
404  {
405  char file_name[512];
406  sprintf (file_name, "%s_%d.ivf", argv[2], i);
407  if (!(outfile[i] = fopen(file_name, "wb")))
408  die("Failed to open %s for writing", file_name);
409  write_ivf_file_header(outfile[i], &cfg, 0);
410  }
411 
412  // Initialize codec
413  if (vpx_codec_enc_init (&codec, interface, &cfg, 0))
414  die_codec (&codec, "Failed to initialize encoder");
415 
416  // Cap CPU & first I-frame size
417  vpx_codec_control (&codec, VP8E_SET_CPUUSED, -6);
419 
420  frame_avail = 1;
421  while (frame_avail || got_data) {
422  vpx_codec_iter_t iter = NULL;
423  const vpx_codec_cx_pkt_t *pkt;
424 
425  flags = layer_flags[frame_cnt % cfg.ts_periodicity];
426 
427  frame_avail = read_frame(infile, &raw);
428  if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts,
429  1, flags, VPX_DL_REALTIME))
430  die_codec(&codec, "Failed to encode frame");
431 
432  // Reset KF flag
433  layer_flags[0] &= ~VPX_EFLAG_FORCE_KF;
434 
435  got_data = 0;
436  while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
437  got_data = 1;
438  switch (pkt->kind) {
440  for (i=cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
441  i<cfg.ts_number_layers; i++)
442  {
443  write_ivf_frame_header(outfile[i], pkt);
444  if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
445  outfile[i]));
446  frames_in_layer[i]++;
447  }
448  break;
449  default:
450  break;
451  }
452  printf (pkt->kind == VPX_CODEC_CX_FRAME_PKT
453  && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
454  fflush (stdout);
455  }
456  frame_cnt++;
457  pts += frame_duration;
458  }
459  printf ("\n");
460  fclose (infile);
461 
462  printf ("Processed %d frames.\n",frame_cnt-1);
463  if (vpx_codec_destroy(&codec))
464  die_codec (&codec, "Failed to destroy codec");
465 
466  // Try to rewrite the output file headers with the actual frame count
467  for (i=0; i<cfg.ts_number_layers; i++)
468  {
469  if (!fseek(outfile[i], 0, SEEK_SET))
470  write_ivf_file_header (outfile[i], &cfg, frames_in_layer[i]);
471  fclose (outfile[i]);
472  }
473 
474  return EXIT_SUCCESS;
475 }
476 
unsigned int rc_buf_initial_sz
Decoder Buffer Initial Size.
Definition: vpx_encoder.h:533
unsigned int ts_number_layers
Number of coding layers.
Definition: vpx_encoder.h:618
control function to set vp8 encoder cpuused
Definition: vp8cx.h:143
#define VP8_EFLAG_NO_REF_LAST
Don&#39;t reference the last frame.
Definition: vp8cx.h:48
#define VP8_EFLAG_NO_UPD_GF
Don&#39;t update the golden frame.
Definition: vp8cx.h:82
Image Descriptor.
Definition: vpx_image.h:97
Describes the encoder algorithm interface to applications.
const char * vpx_codec_iface_name(vpx_codec_iface_t *iface)
Return the name for a given interface.
const char * vpx_codec_err_to_string(vpx_codec_err_t err)
Convert error number to printable string.
struct vpx_rational g_timebase
Stream timebase units.
Definition: vpx_encoder.h:339
Definition: vpx_encoder.h:232
unsigned int rc_buf_sz
Decoder Buffer Size.
Definition: vpx_encoder.h:523
#define VP8_EFLAG_NO_REF_GF
Don&#39;t reference the golden frame.
Definition: vp8cx.h:57
enum vpx_kf_mode kf_mode
Keyframe placement mode.
Definition: vpx_encoder.h:588
int den
Definition: vpx_encoder.h:215
vpx_codec_err_t vpx_codec_encode(vpx_codec_ctx_t *ctx, const vpx_image_t *img, vpx_codec_pts_t pts, unsigned long duration, vpx_enc_frame_flags_t flags, unsigned long deadline)
Encode a frame.
unsigned int rc_max_quantizer
Maximum (Worst Quality) Quantizer.
Definition: vpx_encoder.h:475
unsigned int rc_min_quantizer
Minimum (Best Quality) Quantizer.
Definition: vpx_encoder.h:464
unsigned int kf_max_dist
Keyframe maximum interval.
Definition: vpx_encoder.h:608
unsigned int g_lag_in_frames
Allow lagged encoding.
Definition: vpx_encoder.h:371
Encoder configuration structure.
Definition: vpx_encoder.h:270
Max data rate for Intra frames.
Definition: vp8cx.h:180
Encoder output packet.
Definition: vpx_encoder.h:167
unsigned int rc_overshoot_pct
Rate control adaptation overshoot control.
Definition: vpx_encoder.h:506
unsigned int ts_rate_decimator[5]
Frame rate decimation factor for each layer.
Definition: vpx_encoder.h:631
unsigned int rc_buf_optimal_sz
Decoder Buffer Optimal Size.
Definition: vpx_encoder.h:543
unsigned int kf_min_dist
Keyframe minimum interval.
Definition: vpx_encoder.h:598
Definition: vpx_encoder.h:224
unsigned int ts_layer_id[16]
Template defining the membership of frames to coding layers.
Definition: vpx_encoder.h:649
struct vpx_codec_cx_pkt::@1::@2 frame
vpx_image_t * vpx_img_alloc(vpx_image_t *img, vpx_img_fmt_t fmt, unsigned int d_w, unsigned int d_h, unsigned int align)
Open a descriptor, allocating storage for the underlying image.
Definition: vpx_image.h:56
unsigned int g_w
Width of the frame.
Definition: vpx_encoder.h:314
unsigned int ts_target_bitrate[5]
Target bitrate for each layer.
Definition: vpx_encoder.h:624
unsigned int rc_undershoot_pct
Rate control adaptation undershoot control.
Definition: vpx_encoder.h:493
unsigned int g_h
Height of the frame.
Definition: vpx_encoder.h:324
enum vpx_codec_cx_pkt_kind kind
Definition: vpx_encoder.h:169
unsigned int rc_dropframe_thresh
Temporal resampling configuration, if supported by the codec.
Definition: vpx_encoder.h:394
#define VP8_EFLAG_NO_UPD_LAST
Don&#39;t update the last frame.
Definition: vp8cx.h:74
unsigned char * planes[4]
Definition: vpx_image.h:126
#define VPX_DL_REALTIME
Definition: vpx_encoder.h:788
int num
Definition: vpx_encoder.h:214
vpx_codec_err_t vpx_codec_enc_config_default(vpx_codec_iface_t *iface, vpx_codec_enc_cfg_t *cfg, unsigned int usage)
Get a default configuration.
enum vpx_enc_pass g_pass
Multi-pass Encoding Mode.
Definition: vpx_encoder.h:356
const char * vpx_codec_error_detail(vpx_codec_ctx_t *ctx)
Retrieve detailed error information for codec context.
Provides definitions for using the VP8 encoder algorithm within the vpx Codec Interface.
#define vpx_codec_enc_init(ctx, iface, cfg, flags)
Convenience macro for vpx_codec_enc_init_ver()
Definition: vpx_encoder.h:686
unsigned int rc_resize_allowed
Enable/disable spatial resampling, if supported by the codec.
Definition: vpx_encoder.h:404
unsigned int h
Definition: vpx_image.h:103
vpx_codec_err_t
Algorithm return codes.
Definition: vpx_codec.h:81
const vpx_codec_cx_pkt_t * vpx_codec_get_cx_data(vpx_codec_ctx_t *ctx, vpx_codec_iter_t *iter)
Encoded data iterator.
union vpx_codec_cx_pkt::@1 data
Definition: vpx_encoder.h:249
int64_t vpx_codec_pts_t
Time Stamp Type.
Definition: vpx_encoder.h:97
#define vpx_codec_control(ctx, id, data)
vpx_codec_control wrapper macro
Definition: vpx_codec.h:392
unsigned int ts_periodicity
Length of the sequence defining frame layer membership.
Definition: vpx_encoder.h:640
#define VP8_EFLAG_NO_REF_ARF
Don&#39;t reference the alternate reference frame.
Definition: vp8cx.h:66
vpx_codec_err_t vpx_codec_destroy(vpx_codec_ctx_t *ctx)
Destroy a codec instance.
unsigned int w
Definition: vpx_image.h:102
const char * vpx_codec_error(vpx_codec_ctx_t *ctx)
Retrieve error synopsis for codec context.
#define VPX_FRAME_IS_KEY
Definition: vpx_encoder.h:108
#define VPX_EFLAG_FORCE_KF
Definition: vpx_encoder.h:261
const void * vpx_codec_iter_t
Iterator.
Definition: vpx_codec.h:182
Definition: vpx_encoder.h:155
vpx_codec_er_flags_t g_error_resilient
Enable error resilient modes.
Definition: vpx_encoder.h:348
#define VP8_EFLAG_NO_UPD_ARF
Don&#39;t update the alternate reference frame.
Definition: vp8cx.h:90
#define VP8_EFLAG_NO_UPD_ENTROPY
Disable entropy update.
Definition: vp8cx.h:114
enum vpx_rc_mode rc_end_usage
Rate control algorithm to use.
Definition: vpx_encoder.h:433
Definition: vpx_encoder.h:222
Codec context structure.
Definition: vpx_codec.h:193