libvpxenc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Google, Inc.
3  *
4  * This file is part of Libav.
5  *
6  * Libav is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * Libav is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Libav; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
26 #define VPX_DISABLE_CTRL_TYPECHECKS 1
27 #define VPX_CODEC_DISABLE_COMPAT 1
28 #include <vpx/vpx_encoder.h>
29 #include <vpx/vp8cx.h>
30 
31 #include "avcodec.h"
32 #include "internal.h"
33 #include "libavutil/base64.h"
34 #include "libavutil/mathematics.h"
35 #include "libavutil/opt.h"
36 
41 struct FrameListData {
42  void *buf;
43  size_t sz;
44  int64_t pts;
46  unsigned long duration;
48  uint32_t flags;
50 };
51 
52 typedef struct VP8EncoderContext {
53  AVClass *class;
54  struct vpx_codec_ctx encoder;
55  struct vpx_image rawimg;
56  struct vpx_fixed_buf twopass_stats;
57  unsigned long deadline; //i.e., RT/GOOD/BEST
59  int cpu_used;
63  int arnr_type;
66 } VP8Context;
67 
69 static const char *ctlidstr[] = {
70  [VP8E_UPD_ENTROPY] = "VP8E_UPD_ENTROPY",
71  [VP8E_UPD_REFERENCE] = "VP8E_UPD_REFERENCE",
72  [VP8E_USE_REFERENCE] = "VP8E_USE_REFERENCE",
73  [VP8E_SET_ROI_MAP] = "VP8E_SET_ROI_MAP",
74  [VP8E_SET_ACTIVEMAP] = "VP8E_SET_ACTIVEMAP",
75  [VP8E_SET_SCALEMODE] = "VP8E_SET_SCALEMODE",
76  [VP8E_SET_CPUUSED] = "VP8E_SET_CPUUSED",
77  [VP8E_SET_ENABLEAUTOALTREF] = "VP8E_SET_ENABLEAUTOALTREF",
78  [VP8E_SET_NOISE_SENSITIVITY] = "VP8E_SET_NOISE_SENSITIVITY",
79  [VP8E_SET_SHARPNESS] = "VP8E_SET_SHARPNESS",
80  [VP8E_SET_STATIC_THRESHOLD] = "VP8E_SET_STATIC_THRESHOLD",
81  [VP8E_SET_TOKEN_PARTITIONS] = "VP8E_SET_TOKEN_PARTITIONS",
82  [VP8E_GET_LAST_QUANTIZER] = "VP8E_GET_LAST_QUANTIZER",
83  [VP8E_SET_ARNR_MAXFRAMES] = "VP8E_SET_ARNR_MAXFRAMES",
84  [VP8E_SET_ARNR_STRENGTH] = "VP8E_SET_ARNR_STRENGTH",
85  [VP8E_SET_ARNR_TYPE] = "VP8E_SET_ARNR_TYPE",
86 };
87 
88 static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc)
89 {
90  VP8Context *ctx = avctx->priv_data;
91  const char *error = vpx_codec_error(&ctx->encoder);
92  const char *detail = vpx_codec_error_detail(&ctx->encoder);
93 
94  av_log(avctx, AV_LOG_ERROR, "%s: %s\n", desc, error);
95  if (detail)
96  av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", detail);
97 }
98 
99 static av_cold void dump_enc_cfg(AVCodecContext *avctx,
100  const struct vpx_codec_enc_cfg *cfg)
101 {
102  int width = -30;
103  int level = AV_LOG_DEBUG;
104 
105  av_log(avctx, level, "vpx_codec_enc_cfg\n");
106  av_log(avctx, level, "generic settings\n"
107  " %*s%u\n %*s%u\n %*s%u\n %*s%u\n %*s%u\n"
108  " %*s{%u/%u}\n %*s%u\n %*s%d\n %*s%u\n",
109  width, "g_usage:", cfg->g_usage,
110  width, "g_threads:", cfg->g_threads,
111  width, "g_profile:", cfg->g_profile,
112  width, "g_w:", cfg->g_w,
113  width, "g_h:", cfg->g_h,
114  width, "g_timebase:", cfg->g_timebase.num, cfg->g_timebase.den,
115  width, "g_error_resilient:", cfg->g_error_resilient,
116  width, "g_pass:", cfg->g_pass,
117  width, "g_lag_in_frames:", cfg->g_lag_in_frames);
118  av_log(avctx, level, "rate control settings\n"
119  " %*s%u\n %*s%u\n %*s%u\n %*s%u\n"
120  " %*s%d\n %*s%p(%zu)\n %*s%u\n",
121  width, "rc_dropframe_thresh:", cfg->rc_dropframe_thresh,
122  width, "rc_resize_allowed:", cfg->rc_resize_allowed,
123  width, "rc_resize_up_thresh:", cfg->rc_resize_up_thresh,
124  width, "rc_resize_down_thresh:", cfg->rc_resize_down_thresh,
125  width, "rc_end_usage:", cfg->rc_end_usage,
126  width, "rc_twopass_stats_in:", cfg->rc_twopass_stats_in.buf, cfg->rc_twopass_stats_in.sz,
127  width, "rc_target_bitrate:", cfg->rc_target_bitrate);
128  av_log(avctx, level, "quantizer settings\n"
129  " %*s%u\n %*s%u\n",
130  width, "rc_min_quantizer:", cfg->rc_min_quantizer,
131  width, "rc_max_quantizer:", cfg->rc_max_quantizer);
132  av_log(avctx, level, "bitrate tolerance\n"
133  " %*s%u\n %*s%u\n",
134  width, "rc_undershoot_pct:", cfg->rc_undershoot_pct,
135  width, "rc_overshoot_pct:", cfg->rc_overshoot_pct);
136  av_log(avctx, level, "decoder buffer model\n"
137  " %*s%u\n %*s%u\n %*s%u\n",
138  width, "rc_buf_sz:", cfg->rc_buf_sz,
139  width, "rc_buf_initial_sz:", cfg->rc_buf_initial_sz,
140  width, "rc_buf_optimal_sz:", cfg->rc_buf_optimal_sz);
141  av_log(avctx, level, "2 pass rate control settings\n"
142  " %*s%u\n %*s%u\n %*s%u\n",
143  width, "rc_2pass_vbr_bias_pct:", cfg->rc_2pass_vbr_bias_pct,
144  width, "rc_2pass_vbr_minsection_pct:", cfg->rc_2pass_vbr_minsection_pct,
145  width, "rc_2pass_vbr_maxsection_pct:", cfg->rc_2pass_vbr_maxsection_pct);
146  av_log(avctx, level, "keyframing settings\n"
147  " %*s%d\n %*s%u\n %*s%u\n",
148  width, "kf_mode:", cfg->kf_mode,
149  width, "kf_min_dist:", cfg->kf_min_dist,
150  width, "kf_max_dist:", cfg->kf_max_dist);
151  av_log(avctx, level, "\n");
152 }
153 
154 static void coded_frame_add(void *list, struct FrameListData *cx_frame)
155 {
156  struct FrameListData **p = list;
157 
158  while (*p != NULL)
159  p = &(*p)->next;
160  *p = cx_frame;
161  cx_frame->next = NULL;
162 }
163 
164 static av_cold void free_coded_frame(struct FrameListData *cx_frame)
165 {
166  av_freep(&cx_frame->buf);
167  av_freep(&cx_frame);
168 }
169 
170 static av_cold void free_frame_list(struct FrameListData *list)
171 {
172  struct FrameListData *p = list;
173 
174  while (p) {
175  list = list->next;
176  free_coded_frame(p);
177  p = list;
178  }
179 }
180 
182  enum vp8e_enc_control_id id, int val)
183 {
184  VP8Context *ctx = avctx->priv_data;
185  char buf[80];
186  int width = -30;
187  int res;
188 
189  snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]);
190  av_log(avctx, AV_LOG_DEBUG, " %*s%d\n", width, buf, val);
191 
192  res = vpx_codec_control(&ctx->encoder, id, val);
193  if (res != VPX_CODEC_OK) {
194  snprintf(buf, sizeof(buf), "Failed to set %s codec control",
195  ctlidstr[id]);
196  log_encoder_error(avctx, buf);
197  }
198 
199  return res == VPX_CODEC_OK ? 0 : AVERROR(EINVAL);
200 }
201 
202 static av_cold int vp8_free(AVCodecContext *avctx)
203 {
204  VP8Context *ctx = avctx->priv_data;
205 
206  vpx_codec_destroy(&ctx->encoder);
207  av_freep(&ctx->twopass_stats.buf);
208  av_freep(&avctx->coded_frame);
209  av_freep(&avctx->stats_out);
210  free_frame_list(ctx->coded_frame_list);
211  return 0;
212 }
213 
214 static av_cold int vp8_init(AVCodecContext *avctx)
215 {
216  VP8Context *ctx = avctx->priv_data;
217  const struct vpx_codec_iface *iface = &vpx_codec_vp8_cx_algo;
218  struct vpx_codec_enc_cfg enccfg;
219  int res;
220 
221  av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str());
222  av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config());
223 
224  if ((res = vpx_codec_enc_config_default(iface, &enccfg, 0)) != VPX_CODEC_OK) {
225  av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n",
226  vpx_codec_err_to_string(res));
227  return AVERROR(EINVAL);
228  }
229  dump_enc_cfg(avctx, &enccfg);
230 
231  enccfg.g_w = avctx->width;
232  enccfg.g_h = avctx->height;
233  enccfg.g_timebase.num = avctx->time_base.num;
234  enccfg.g_timebase.den = avctx->time_base.den;
235  enccfg.g_threads = avctx->thread_count;
236 
237  if (ctx->lag_in_frames >= 0)
238  enccfg.g_lag_in_frames = ctx->lag_in_frames;
239 
240  if (avctx->flags & CODEC_FLAG_PASS1)
241  enccfg.g_pass = VPX_RC_FIRST_PASS;
242  else if (avctx->flags & CODEC_FLAG_PASS2)
243  enccfg.g_pass = VPX_RC_LAST_PASS;
244  else
245  enccfg.g_pass = VPX_RC_ONE_PASS;
246 
247  if (avctx->rc_min_rate == avctx->rc_max_rate &&
248  avctx->rc_min_rate == avctx->bit_rate)
249  enccfg.rc_end_usage = VPX_CBR;
250  enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000,
252  if (avctx->qmin > 0)
253  enccfg.rc_min_quantizer = avctx->qmin;
254  if (avctx->qmax > 0)
255  enccfg.rc_max_quantizer = avctx->qmax;
256  enccfg.rc_dropframe_thresh = avctx->frame_skip_threshold;
257 
258  //0-100 (0 => CBR, 100 => VBR)
259  enccfg.rc_2pass_vbr_bias_pct = round(avctx->qcompress * 100);
260  enccfg.rc_2pass_vbr_minsection_pct =
261  avctx->rc_min_rate * 100LL / avctx->bit_rate;
262  if (avctx->rc_max_rate)
263  enccfg.rc_2pass_vbr_maxsection_pct =
264  avctx->rc_max_rate * 100LL / avctx->bit_rate;
265 
266  if (avctx->rc_buffer_size)
267  enccfg.rc_buf_sz =
268  avctx->rc_buffer_size * 1000LL / avctx->bit_rate;
269  if (avctx->rc_initial_buffer_occupancy)
270  enccfg.rc_buf_initial_sz =
271  avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate;
272  enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6;
273 
274  //_enc_init() will balk if kf_min_dist differs from max w/VPX_KF_AUTO
275  if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
276  enccfg.kf_min_dist = avctx->keyint_min;
277  if (avctx->gop_size >= 0)
278  enccfg.kf_max_dist = avctx->gop_size;
279 
280  if (enccfg.g_pass == VPX_RC_FIRST_PASS)
281  enccfg.g_lag_in_frames = 0;
282  else if (enccfg.g_pass == VPX_RC_LAST_PASS) {
283  int decode_size;
284 
285  if (!avctx->stats_in) {
286  av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n");
287  return AVERROR_INVALIDDATA;
288  }
289 
290  ctx->twopass_stats.sz = strlen(avctx->stats_in) * 3 / 4;
291  ctx->twopass_stats.buf = av_malloc(ctx->twopass_stats.sz);
292  if (!ctx->twopass_stats.buf) {
293  av_log(avctx, AV_LOG_ERROR,
294  "Stat buffer alloc (%zu bytes) failed\n",
295  ctx->twopass_stats.sz);
296  return AVERROR(ENOMEM);
297  }
298  decode_size = av_base64_decode(ctx->twopass_stats.buf, avctx->stats_in,
299  ctx->twopass_stats.sz);
300  if (decode_size < 0) {
301  av_log(avctx, AV_LOG_ERROR, "Stat buffer decode failed\n");
302  return AVERROR_INVALIDDATA;
303  }
304 
305  ctx->twopass_stats.sz = decode_size;
306  enccfg.rc_twopass_stats_in = ctx->twopass_stats;
307  }
308 
309  /* 0-3: For non-zero values the encoder increasingly optimizes for reduced
310  complexity playback on low powered devices at the expense of encode
311  quality. */
312  if (avctx->profile != FF_PROFILE_UNKNOWN)
313  enccfg.g_profile = avctx->profile;
314 
315  enccfg.g_error_resilient = ctx->error_resilient;
316 
317  dump_enc_cfg(avctx, &enccfg);
318  /* Construct Encoder Context */
319  res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, 0);
320  if (res != VPX_CODEC_OK) {
321  log_encoder_error(avctx, "Failed to initialize encoder");
322  return AVERROR(EINVAL);
323  }
324 
325  //codec control failures are currently treated only as warnings
326  av_log(avctx, AV_LOG_DEBUG, "vpx_codec_control\n");
327  if (ctx->cpu_used != INT_MIN)
328  codecctl_int(avctx, VP8E_SET_CPUUSED, ctx->cpu_used);
329  if (ctx->auto_alt_ref >= 0)
330  codecctl_int(avctx, VP8E_SET_ENABLEAUTOALTREF, ctx->auto_alt_ref);
331  if (ctx->arnr_max_frames >= 0)
332  codecctl_int(avctx, VP8E_SET_ARNR_MAXFRAMES, ctx->arnr_max_frames);
333  if (ctx->arnr_strength >= 0)
334  codecctl_int(avctx, VP8E_SET_ARNR_STRENGTH, ctx->arnr_strength);
335  if (ctx->arnr_type >= 0)
336  codecctl_int(avctx, VP8E_SET_ARNR_TYPE, ctx->arnr_type);
337  codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction);
338  codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices));
339  codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, avctx->mb_threshold);
340 
341  //provide dummy value to initialize wrapper, values will be updated each _encode()
342  vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
343  (unsigned char*)1);
344 
345  avctx->coded_frame = avcodec_alloc_frame();
346  if (!avctx->coded_frame) {
347  av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
348  vp8_free(avctx);
349  return AVERROR(ENOMEM);
350  }
351  return 0;
352 }
353 
354 static inline void cx_pktcpy(struct FrameListData *dst,
355  const struct vpx_codec_cx_pkt *src)
356 {
357  dst->pts = src->data.frame.pts;
358  dst->duration = src->data.frame.duration;
359  dst->flags = src->data.frame.flags;
360  dst->sz = src->data.frame.sz;
361  dst->buf = src->data.frame.buf;
362 }
363 
372 static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame,
373  uint8_t *buf, int buf_size, AVFrame *coded_frame)
374 {
375  if ((int) cx_frame->sz <= buf_size) {
376  buf_size = cx_frame->sz;
377  memcpy(buf, cx_frame->buf, buf_size);
378  coded_frame->pts = cx_frame->pts;
379  coded_frame->key_frame = !!(cx_frame->flags & VPX_FRAME_IS_KEY);
380 
381  if (coded_frame->key_frame)
382  coded_frame->pict_type = AV_PICTURE_TYPE_I;
383  else
384  coded_frame->pict_type = AV_PICTURE_TYPE_P;
385  } else {
386  av_log(avctx, AV_LOG_ERROR,
387  "Compressed frame larger than storage provided! (%zu/%d)\n",
388  cx_frame->sz, buf_size);
389  return AVERROR(EINVAL);
390  }
391  return buf_size;
392 }
393 
402 static int queue_frames(AVCodecContext *avctx, uint8_t *buf, int buf_size,
403  AVFrame *coded_frame)
404 {
405  VP8Context *ctx = avctx->priv_data;
406  const struct vpx_codec_cx_pkt *pkt;
407  const void *iter = NULL;
408  int size = 0;
409 
410  if (ctx->coded_frame_list) {
411  struct FrameListData *cx_frame = ctx->coded_frame_list;
412  /* return the leading frame if we've already begun queueing */
413  size = storeframe(avctx, cx_frame, buf, buf_size, coded_frame);
414  if (size < 0)
415  return AVERROR(EINVAL);
416  ctx->coded_frame_list = cx_frame->next;
417  free_coded_frame(cx_frame);
418  }
419 
420  /* consume all available output from the encoder before returning. buffers
421  are only good through the next vpx_codec call */
422  while ((pkt = vpx_codec_get_cx_data(&ctx->encoder, &iter))) {
423  switch (pkt->kind) {
424  case VPX_CODEC_CX_FRAME_PKT:
425  if (!size) {
426  struct FrameListData cx_frame;
427 
428  /* avoid storing the frame when the list is empty and we haven't yet
429  provided a frame for output */
430  assert(!ctx->coded_frame_list);
431  cx_pktcpy(&cx_frame, pkt);
432  size = storeframe(avctx, &cx_frame, buf, buf_size, coded_frame);
433  if (size < 0)
434  return AVERROR(EINVAL);
435  } else {
436  struct FrameListData *cx_frame =
437  av_malloc(sizeof(struct FrameListData));
438 
439  if (!cx_frame) {
440  av_log(avctx, AV_LOG_ERROR,
441  "Frame queue element alloc failed\n");
442  return AVERROR(ENOMEM);
443  }
444  cx_pktcpy(cx_frame, pkt);
445  cx_frame->buf = av_malloc(cx_frame->sz);
446 
447  if (!cx_frame->buf) {
448  av_log(avctx, AV_LOG_ERROR,
449  "Data buffer alloc (%zu bytes) failed\n",
450  cx_frame->sz);
451  return AVERROR(ENOMEM);
452  }
453  memcpy(cx_frame->buf, pkt->data.frame.buf, pkt->data.frame.sz);
454  coded_frame_add(&ctx->coded_frame_list, cx_frame);
455  }
456  break;
457  case VPX_CODEC_STATS_PKT: {
458  struct vpx_fixed_buf *stats = &ctx->twopass_stats;
459  stats->buf = av_realloc(stats->buf,
460  stats->sz + pkt->data.twopass_stats.sz);
461  if (!stats->buf) {
462  av_log(avctx, AV_LOG_ERROR, "Stat buffer realloc failed\n");
463  return AVERROR(ENOMEM);
464  }
465  memcpy((uint8_t*)stats->buf + stats->sz,
466  pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz);
467  stats->sz += pkt->data.twopass_stats.sz;
468  break;
469  }
470  case VPX_CODEC_PSNR_PKT: //FIXME add support for CODEC_FLAG_PSNR
471  case VPX_CODEC_CUSTOM_PKT:
472  //ignore unsupported/unrecognized packet types
473  break;
474  }
475  }
476 
477  return size;
478 }
479 
480 static int vp8_encode(AVCodecContext *avctx, uint8_t *buf, int buf_size,
481  void *data)
482 {
483  VP8Context *ctx = avctx->priv_data;
484  AVFrame *frame = data;
485  struct vpx_image *rawimg = NULL;
486  int64_t timestamp = 0;
487  int res, coded_size;
488 
489  if (frame) {
490  rawimg = &ctx->rawimg;
491  rawimg->planes[VPX_PLANE_Y] = frame->data[0];
492  rawimg->planes[VPX_PLANE_U] = frame->data[1];
493  rawimg->planes[VPX_PLANE_V] = frame->data[2];
494  rawimg->stride[VPX_PLANE_Y] = frame->linesize[0];
495  rawimg->stride[VPX_PLANE_U] = frame->linesize[1];
496  rawimg->stride[VPX_PLANE_V] = frame->linesize[2];
497  timestamp = frame->pts;
498  }
499 
500  res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp,
501  avctx->ticks_per_frame, 0, ctx->deadline);
502  if (res != VPX_CODEC_OK) {
503  log_encoder_error(avctx, "Error encoding frame");
504  return AVERROR_INVALIDDATA;
505  }
506  coded_size = queue_frames(avctx, buf, buf_size, avctx->coded_frame);
507 
508  if (!frame && avctx->flags & CODEC_FLAG_PASS1) {
509  unsigned int b64_size = AV_BASE64_SIZE(ctx->twopass_stats.sz);
510 
511  avctx->stats_out = av_malloc(b64_size);
512  if (!avctx->stats_out) {
513  av_log(avctx, AV_LOG_ERROR, "Stat buffer alloc (%d bytes) failed\n",
514  b64_size);
515  return AVERROR(ENOMEM);
516  }
517  av_base64_encode(avctx->stats_out, b64_size, ctx->twopass_stats.buf,
518  ctx->twopass_stats.sz);
519  }
520  return coded_size;
521 }
522 
523 #define OFFSET(x) offsetof(VP8Context, x)
524 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
525 static const AVOption options[] = {
526  { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {INT_MIN}, INT_MIN, INT_MAX, VE},
527  { "auto-alt-ref", "Enable use of alternate reference "
528  "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {-1}, -1, 1, VE},
529  { "lag-in-frames", "Number of frames to look ahead for "
530  "alternate reference frame selection", OFFSET(lag_in_frames), AV_OPT_TYPE_INT, {-1}, -1, INT_MAX, VE},
531  { "arnr-maxframes", "altref noise reduction max frame count", OFFSET(arnr_max_frames), AV_OPT_TYPE_INT, {-1}, -1, INT_MAX, VE},
532  { "arnr-strength", "altref noise reduction filter strength", OFFSET(arnr_strength), AV_OPT_TYPE_INT, {-1}, -1, INT_MAX, VE},
533  { "arnr-type", "altref noise reduction filter type", OFFSET(arnr_type), AV_OPT_TYPE_INT, {-1}, -1, INT_MAX, VE, "arnr_type"},
534  { "backward", NULL, 0, AV_OPT_TYPE_CONST, {1}, 0, 0, VE, "arnr_type" },
535  { "forward", NULL, 0, AV_OPT_TYPE_CONST, {2}, 0, 0, VE, "arnr_type" },
536  { "centered", NULL, 0, AV_OPT_TYPE_CONST, {3}, 0, 0, VE, "arnr_type" },
537  { "deadline", "Time to spend encoding, in microseconds.", OFFSET(deadline), AV_OPT_TYPE_INT, {VPX_DL_GOOD_QUALITY}, INT_MIN, INT_MAX, VE, "quality"},
538  { "best", NULL, 0, AV_OPT_TYPE_CONST, {VPX_DL_BEST_QUALITY}, 0, 0, VE, "quality"},
539  { "good", NULL, 0, AV_OPT_TYPE_CONST, {VPX_DL_GOOD_QUALITY}, 0, 0, VE, "quality"},
540  { "realtime", NULL, 0, AV_OPT_TYPE_CONST, {VPX_DL_REALTIME}, 0, 0, VE, "quality"},
541  { "error-resilient", "Error resilience configuration", OFFSET(error_resilient), AV_OPT_TYPE_FLAGS, {0}, INT_MIN, INT_MAX, VE, "er"},
542 #ifdef VPX_ERROR_RESILIENT_DEFAULT
543  { "default", "Improve resiliency against losses of whole frames", 0, AV_OPT_TYPE_CONST, {VPX_ERROR_RESILIENT_DEFAULT}, 0, 0, VE, "er"},
544  { "partitions", "The frame partitions are independently decodable "
545  "by the bool decoder, meaning that partitions can be decoded even "
546  "though earlier partitions have been lost. Note that intra predicition"
547  " is still done over the partition boundary.", 0, AV_OPT_TYPE_CONST, {VPX_ERROR_RESILIENT_PARTITIONS}, 0, 0, VE, "er"},
548 #endif
549  { NULL }
550 };
551 
552 static const AVClass class = {
553  .class_name = "libvpx encoder",
554  .item_name = av_default_item_name,
555  .option = options,
557 };
558 
559 static const AVCodecDefault defaults[] = {
560  { "qmin", "-1" },
561  { "qmax", "-1" },
562  { "g", "-1" },
563  { "keyint_min", "-1" },
564  { NULL },
565 };
566 
568  .name = "libvpx",
569  .type = AVMEDIA_TYPE_VIDEO,
570  .id = CODEC_ID_VP8,
571  .priv_data_size = sizeof(VP8Context),
572  .init = vp8_init,
573  .encode = vp8_encode,
574  .close = vp8_free,
575  .capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
576  .pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE},
577  .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"),
578  .priv_class = &class,
579  .defaults = defaults,
580 };