Mercurial > libavcodec.hg
annotate libvpxenc.c @ 12092:de9e45d04063 libavcodec
DCA: Occasionally a false XCH sync word can turn up after the core DTS data,
to verify the sync word the extension fsize field should be compared to
the core data length field.
Patch by nick.nbrereton@net
author | banan |
---|---|
date | Mon, 05 Jul 2010 08:16:43 +0000 |
parents | 24a6c651c3f3 |
children | 3d186eff2224 |
rev | line source |
---|---|
11821 | 1 /* |
2 * Copyright (c) 2010, Google, Inc. | |
3 * | |
4 * This file is part of FFmpeg. | |
5 * | |
6 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software | |
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
19 */ | |
20 | |
21 /** | |
22 * @file | |
23 * VP8 encoder support via libvpx | |
24 */ | |
25 | |
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 "libavutil/base64.h" | |
33 | |
34 /** | |
35 * Portion of struct vpx_codec_cx_pkt from vpx_encoder.h. | |
36 * One encoded frame returned from the library. | |
37 */ | |
38 struct FrameListData { | |
39 void *buf; /**≤ compressed data buffer */ | |
40 size_t sz; /**≤ length of compressed data */ | |
41 int64_t pts; /**≤ time stamp to show frame | |
42 (in timebase units) */ | |
43 unsigned long duration; /**≤ duration to show frame | |
44 (in timebase units) */ | |
45 uint32_t flags; /**≤ flags for this frame */ | |
46 struct FrameListData *next; | |
47 }; | |
48 | |
49 typedef struct VP8EncoderContext { | |
50 struct vpx_codec_ctx encoder; | |
51 struct vpx_image rawimg; | |
52 struct vpx_fixed_buf twopass_stats; | |
53 unsigned long deadline; //i.e., RT/GOOD/BEST | |
54 struct FrameListData *coded_frame_list; | |
55 } VP8Context; | |
56 | |
57 /** String mappings for enum vp8e_enc_control_id */ | |
58 static const char *ctlidstr[] = { | |
59 [VP8E_UPD_ENTROPY] = "VP8E_UPD_ENTROPY", | |
60 [VP8E_UPD_REFERENCE] = "VP8E_UPD_REFERENCE", | |
61 [VP8E_USE_REFERENCE] = "VP8E_USE_REFERENCE", | |
62 [VP8E_SET_ROI_MAP] = "VP8E_SET_ROI_MAP", | |
63 [VP8E_SET_ACTIVEMAP] = "VP8E_SET_ACTIVEMAP", | |
64 [VP8E_SET_SCALEMODE] = "VP8E_SET_SCALEMODE", | |
65 [VP8E_SET_CPUUSED] = "VP8E_SET_CPUUSED", | |
66 [VP8E_SET_ENABLEAUTOALTREF] = "VP8E_SET_ENABLEAUTOALTREF", | |
67 [VP8E_SET_NOISE_SENSITIVITY] = "VP8E_SET_NOISE_SENSITIVITY", | |
68 [VP8E_SET_SHARPNESS] = "VP8E_SET_SHARPNESS", | |
69 [VP8E_SET_STATIC_THRESHOLD] = "VP8E_SET_STATIC_THRESHOLD", | |
70 [VP8E_SET_TOKEN_PARTITIONS] = "VP8E_SET_TOKEN_PARTITIONS", | |
71 [VP8E_GET_LAST_QUANTIZER] = "VP8E_GET_LAST_QUANTIZER", | |
72 [VP8E_SET_ARNR_MAXFRAMES] = "VP8E_SET_ARNR_MAXFRAMES", | |
73 [VP8E_SET_ARNR_STRENGTH] = "VP8E_SET_ARNR_STRENGTH", | |
74 [VP8E_SET_ARNR_TYPE] = "VP8E_SET_ARNR_TYPE", | |
75 }; | |
76 | |
77 static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc) | |
78 { | |
79 VP8Context *ctx = avctx->priv_data; | |
80 const char *error = vpx_codec_error(&ctx->encoder); | |
81 const char *detail = vpx_codec_error_detail(&ctx->encoder); | |
82 | |
83 av_log(avctx, AV_LOG_ERROR, "%s: %s\n", desc, error); | |
84 if (detail) | |
85 av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", detail); | |
86 } | |
87 | |
88 static av_cold void dump_enc_cfg(AVCodecContext *avctx, | |
89 const struct vpx_codec_enc_cfg *cfg) | |
90 { | |
91 int width = -30; | |
92 int level = AV_LOG_DEBUG; | |
93 | |
94 av_log(avctx, level, "vpx_codec_enc_cfg\n"); | |
95 av_log(avctx, level, "generic settings\n" | |
96 " %*s%u\n %*s%u\n %*s%u\n %*s%u\n %*s%u\n" | |
97 " %*s{%u/%u}\n %*s%u\n %*s%d\n %*s%u\n", | |
98 width, "g_usage:", cfg->g_usage, | |
99 width, "g_threads:", cfg->g_threads, | |
100 width, "g_profile:", cfg->g_profile, | |
101 width, "g_w:", cfg->g_w, | |
102 width, "g_h:", cfg->g_h, | |
103 width, "g_timebase:", cfg->g_timebase.num, cfg->g_timebase.den, | |
104 width, "g_error_resilient:", cfg->g_error_resilient, | |
105 width, "g_pass:", cfg->g_pass, | |
106 width, "g_lag_in_frames:", cfg->g_lag_in_frames); | |
107 av_log(avctx, level, "rate control settings\n" | |
108 " %*s%u\n %*s%u\n %*s%u\n %*s%u\n" | |
109 " %*s%d\n %*s%p(%zu)\n %*s%u\n", | |
110 width, "rc_dropframe_thresh:", cfg->rc_dropframe_thresh, | |
111 width, "rc_resize_allowed:", cfg->rc_resize_allowed, | |
112 width, "rc_resize_up_thresh:", cfg->rc_resize_up_thresh, | |
113 width, "rc_resize_down_thresh:", cfg->rc_resize_down_thresh, | |
114 width, "rc_end_usage:", cfg->rc_end_usage, | |
115 width, "rc_twopass_stats_in:", cfg->rc_twopass_stats_in.buf, cfg->rc_twopass_stats_in.sz, | |
116 width, "rc_target_bitrate:", cfg->rc_target_bitrate); | |
117 av_log(avctx, level, "quantizer settings\n" | |
118 " %*s%u\n %*s%u\n", | |
119 width, "rc_min_quantizer:", cfg->rc_min_quantizer, | |
120 width, "rc_max_quantizer:", cfg->rc_max_quantizer); | |
121 av_log(avctx, level, "bitrate tolerance\n" | |
122 " %*s%u\n %*s%u\n", | |
123 width, "rc_undershoot_pct:", cfg->rc_undershoot_pct, | |
124 width, "rc_overshoot_pct:", cfg->rc_overshoot_pct); | |
125 av_log(avctx, level, "decoder buffer model\n" | |
126 " %*s%u\n %*s%u\n %*s%u\n", | |
127 width, "rc_buf_sz:", cfg->rc_buf_sz, | |
128 width, "rc_buf_initial_sz:", cfg->rc_buf_initial_sz, | |
129 width, "rc_buf_optimal_sz:", cfg->rc_buf_optimal_sz); | |
130 av_log(avctx, level, "2 pass rate control settings\n" | |
131 " %*s%u\n %*s%u\n %*s%u\n", | |
132 width, "rc_2pass_vbr_bias_pct:", cfg->rc_2pass_vbr_bias_pct, | |
133 width, "rc_2pass_vbr_minsection_pct:", cfg->rc_2pass_vbr_minsection_pct, | |
134 width, "rc_2pass_vbr_maxsection_pct:", cfg->rc_2pass_vbr_maxsection_pct); | |
135 av_log(avctx, level, "keyframing settings\n" | |
136 " %*s%d\n %*s%u\n %*s%u\n", | |
137 width, "kf_mode:", cfg->kf_mode, | |
138 width, "kf_min_dist:", cfg->kf_min_dist, | |
139 width, "kf_max_dist:", cfg->kf_max_dist); | |
140 av_log(avctx, level, "\n"); | |
141 } | |
142 | |
143 static void coded_frame_add(void *list, struct FrameListData *cx_frame) | |
144 { | |
145 struct FrameListData **p = list; | |
146 | |
147 while (*p != NULL) | |
148 p = &(*p)->next; | |
149 *p = cx_frame; | |
150 cx_frame->next = NULL; | |
151 } | |
152 | |
153 static av_cold void free_coded_frame(struct FrameListData *cx_frame) | |
154 { | |
155 av_freep(&cx_frame->buf); | |
156 av_freep(&cx_frame); | |
157 } | |
158 | |
159 static av_cold void free_frame_list(struct FrameListData *list) | |
160 { | |
161 struct FrameListData *p = list; | |
162 | |
163 while (p) { | |
164 list = list->next; | |
165 free_coded_frame(p); | |
166 p = list; | |
167 } | |
168 } | |
169 | |
170 static av_cold int codecctl_int(AVCodecContext *avctx, | |
171 enum vp8e_enc_control_id id, int val) | |
172 { | |
173 VP8Context *ctx = avctx->priv_data; | |
174 char buf[80]; | |
175 int width = -30; | |
176 int res; | |
177 | |
178 snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]); | |
179 av_log(avctx, AV_LOG_DEBUG, " %*s%d\n", width, buf, val); | |
180 | |
181 res = vpx_codec_control(&ctx->encoder, id, val); | |
182 if (res != VPX_CODEC_OK) { | |
183 snprintf(buf, sizeof(buf), "Failed to set %s codec control", | |
184 ctlidstr[id]); | |
185 log_encoder_error(avctx, buf); | |
186 } | |
187 | |
188 return res == VPX_CODEC_OK ? 0 : AVERROR(EINVAL); | |
189 } | |
190 | |
191 static av_cold int vp8_free(AVCodecContext *avctx) | |
192 { | |
193 VP8Context *ctx = avctx->priv_data; | |
194 | |
195 vpx_codec_destroy(&ctx->encoder); | |
196 av_freep(&ctx->twopass_stats.buf); | |
197 av_freep(&avctx->coded_frame); | |
198 av_freep(&avctx->stats_out); | |
199 free_frame_list(ctx->coded_frame_list); | |
200 return 0; | |
201 } | |
202 | |
203 static av_cold int vp8_init(AVCodecContext *avctx) | |
204 { | |
205 VP8Context *ctx = avctx->priv_data; | |
206 const struct vpx_codec_iface *iface = &vpx_codec_vp8_cx_algo; | |
207 int cpuused = 3; | |
208 struct vpx_codec_enc_cfg enccfg; | |
209 int res; | |
210 | |
211 av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str()); | |
212 av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config()); | |
213 | |
214 if ((res = vpx_codec_enc_config_default(iface, &enccfg, 0)) != VPX_CODEC_OK) { | |
215 av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n", | |
216 vpx_codec_err_to_string(res)); | |
217 return AVERROR(EINVAL); | |
218 } | |
219 dump_enc_cfg(avctx, &enccfg); | |
220 | |
221 enccfg.g_w = avctx->width; | |
222 enccfg.g_h = avctx->height; | |
223 enccfg.g_timebase.num = avctx->time_base.num; | |
224 enccfg.g_timebase.den = avctx->time_base.den; | |
225 enccfg.g_threads = avctx->thread_count; | |
226 | |
227 if (avctx->flags & CODEC_FLAG_PASS1) | |
228 enccfg.g_pass = VPX_RC_FIRST_PASS; | |
229 else if (avctx->flags & CODEC_FLAG_PASS2) | |
230 enccfg.g_pass = VPX_RC_LAST_PASS; | |
231 else | |
232 enccfg.g_pass = VPX_RC_ONE_PASS; | |
233 | |
234 if (avctx->rc_min_rate == avctx->rc_max_rate && | |
235 avctx->rc_min_rate == avctx->bit_rate) | |
236 enccfg.rc_end_usage = VPX_CBR; | |
237 enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000, | |
238 AV_ROUND_NEAR_INF); | |
239 | |
240 //convert [1,51] -> [0,63] | |
241 enccfg.rc_min_quantizer = ((avctx->qmin * 5 + 1) >> 2) - 1; | |
242 enccfg.rc_max_quantizer = ((avctx->qmax * 5 + 1) >> 2) - 1; | |
11852
24a6c651c3f3
libvpx: Set the libvpx frame dropping threshold to frame_skip_threshold
mstorsjo
parents:
11851
diff
changeset
|
243 enccfg.rc_dropframe_thresh = avctx->frame_skip_threshold; |
11821 | 244 |
11851 | 245 //_enc_init() will balk if kf_min_dist differs from max w/VPX_KF_AUTO |
11821 | 246 if (avctx->keyint_min == avctx->gop_size) |
247 enccfg.kf_min_dist = avctx->keyint_min; | |
248 enccfg.kf_max_dist = avctx->gop_size; | |
249 | |
250 if (enccfg.g_pass == VPX_RC_FIRST_PASS) | |
251 enccfg.g_lag_in_frames = 0; | |
252 else if (enccfg.g_pass == VPX_RC_LAST_PASS) { | |
253 int decode_size; | |
254 | |
255 if (!avctx->stats_in) { | |
256 av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n"); | |
257 return AVERROR_INVALIDDATA; | |
258 } | |
259 | |
260 ctx->twopass_stats.sz = strlen(avctx->stats_in) * 3 / 4; | |
261 ctx->twopass_stats.buf = av_malloc(ctx->twopass_stats.sz); | |
262 if (!ctx->twopass_stats.buf) { | |
263 av_log(avctx, AV_LOG_ERROR, | |
264 "Stat buffer alloc (%zu bytes) failed\n", | |
265 ctx->twopass_stats.sz); | |
266 return AVERROR(ENOMEM); | |
267 } | |
268 decode_size = av_base64_decode(ctx->twopass_stats.buf, avctx->stats_in, | |
269 ctx->twopass_stats.sz); | |
270 if (decode_size < 0) { | |
271 av_log(avctx, AV_LOG_ERROR, "Stat buffer decode failed\n"); | |
272 return AVERROR_INVALIDDATA; | |
273 } | |
274 | |
275 ctx->twopass_stats.sz = decode_size; | |
276 enccfg.rc_twopass_stats_in = ctx->twopass_stats; | |
277 } | |
278 | |
279 ctx->deadline = VPX_DL_GOOD_QUALITY; | |
280 | |
281 dump_enc_cfg(avctx, &enccfg); | |
282 /* Construct Encoder Context */ | |
283 res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, 0); | |
284 if (res != VPX_CODEC_OK) { | |
285 log_encoder_error(avctx, "Failed to initialize encoder"); | |
286 return AVERROR(EINVAL); | |
287 } | |
288 | |
289 //codec control failures are currently treated only as warnings | |
290 av_log(avctx, AV_LOG_DEBUG, "vpx_codec_control\n"); | |
291 codecctl_int(avctx, VP8E_SET_CPUUSED, cpuused); | |
292 codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction); | |
293 | |
294 //provide dummy value to initialize wrapper, values will be updated each _encode() | |
295 vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1, | |
296 (unsigned char*)1); | |
297 | |
298 avctx->coded_frame = avcodec_alloc_frame(); | |
299 if (!avctx->coded_frame) { | |
300 av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n"); | |
301 vp8_free(avctx); | |
302 return AVERROR(ENOMEM); | |
303 } | |
304 return 0; | |
305 } | |
306 | |
307 static inline void cx_pktcpy(struct FrameListData *dst, | |
308 const struct vpx_codec_cx_pkt *src) | |
309 { | |
310 dst->pts = src->data.frame.pts; | |
311 dst->duration = src->data.frame.duration; | |
312 dst->flags = src->data.frame.flags; | |
313 dst->sz = src->data.frame.sz; | |
314 dst->buf = src->data.frame.buf; | |
315 } | |
316 | |
317 /** | |
318 * Store coded frame information in format suitable for return from encode(). | |
319 * | |
320 * Write buffer information from @a cx_frame to @a buf & @a buf_size. | |
321 * Timing/frame details to @a coded_frame. | |
322 * @return Frame size written to @a buf on success | |
323 * @return AVERROR(EINVAL) on error | |
324 */ | |
325 static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, | |
326 uint8_t *buf, int buf_size, AVFrame *coded_frame) | |
327 { | |
328 if ((int) cx_frame->sz <= buf_size) { | |
329 buf_size = cx_frame->sz; | |
330 memcpy(buf, cx_frame->buf, buf_size); | |
331 coded_frame->pts = cx_frame->pts; | |
332 coded_frame->key_frame = !!(cx_frame->flags & VPX_FRAME_IS_KEY); | |
333 | |
334 if (coded_frame->key_frame) | |
335 coded_frame->pict_type = FF_I_TYPE; | |
336 else | |
337 coded_frame->pict_type = FF_P_TYPE; | |
338 } else { | |
339 av_log(avctx, AV_LOG_ERROR, | |
340 "Compressed frame larger than storage provided! (%zu/%d)\n", | |
341 cx_frame->sz, buf_size); | |
342 return AVERROR(EINVAL); | |
343 } | |
344 return buf_size; | |
345 } | |
346 | |
347 /** | |
348 * Queue multiple output frames from the encoder, returning the front-most. | |
349 * In cases where vpx_codec_get_cx_data() returns more than 1 frame append | |
350 * the frame queue. Return the head frame if available. | |
351 * @return Stored frame size | |
352 * @return AVERROR(EINVAL) on output size error | |
353 * @return AVERROR(ENOMEM) on coded frame queue data allocation error | |
354 */ | |
355 static int queue_frames(AVCodecContext *avctx, uint8_t *buf, int buf_size, | |
356 AVFrame *coded_frame) | |
357 { | |
358 VP8Context *ctx = avctx->priv_data; | |
359 const struct vpx_codec_cx_pkt *pkt; | |
360 const void *iter = NULL; | |
361 int size = 0; | |
362 | |
363 if (ctx->coded_frame_list) { | |
364 struct FrameListData *cx_frame = ctx->coded_frame_list; | |
365 /* return the leading frame if we've already begun queueing */ | |
366 size = storeframe(avctx, cx_frame, buf, buf_size, coded_frame); | |
367 if (size < 0) | |
368 return AVERROR(EINVAL); | |
369 ctx->coded_frame_list = cx_frame->next; | |
370 free_coded_frame(cx_frame); | |
371 } | |
372 | |
373 /* consume all available output from the encoder before returning. buffers | |
374 are only good through the next vpx_codec call */ | |
375 while ((pkt = vpx_codec_get_cx_data(&ctx->encoder, &iter))) { | |
376 switch (pkt->kind) { | |
377 case VPX_CODEC_CX_FRAME_PKT: | |
378 if (!size) { | |
379 struct FrameListData cx_frame; | |
380 | |
381 /* avoid storing the frame when the list is empty and we haven't yet | |
382 provided a frame for output */ | |
383 assert(!ctx->coded_frame_list); | |
384 cx_pktcpy(&cx_frame, pkt); | |
385 size = storeframe(avctx, &cx_frame, buf, buf_size, coded_frame); | |
386 if (size < 0) | |
387 return AVERROR(EINVAL); | |
388 } else { | |
389 struct FrameListData *cx_frame = | |
390 av_malloc(sizeof(struct FrameListData)); | |
391 | |
392 if (!cx_frame) { | |
393 av_log(avctx, AV_LOG_ERROR, | |
394 "Frame queue element alloc failed\n"); | |
395 return AVERROR(ENOMEM); | |
396 } | |
397 cx_pktcpy(cx_frame, pkt); | |
398 cx_frame->buf = av_malloc(cx_frame->sz); | |
399 | |
400 if (!cx_frame->buf) { | |
401 av_log(avctx, AV_LOG_ERROR, | |
402 "Data buffer alloc (%zu bytes) failed\n", | |
403 cx_frame->sz); | |
404 return AVERROR(ENOMEM); | |
405 } | |
406 memcpy(cx_frame->buf, pkt->data.frame.buf, pkt->data.frame.sz); | |
407 coded_frame_add(&ctx->coded_frame_list, cx_frame); | |
408 } | |
409 break; | |
410 case VPX_CODEC_STATS_PKT: { | |
411 struct vpx_fixed_buf *stats = &ctx->twopass_stats; | |
412 stats->buf = av_realloc(stats->buf, | |
413 stats->sz + pkt->data.twopass_stats.sz); | |
414 if (!stats->buf) { | |
415 av_log(avctx, AV_LOG_ERROR, "Stat buffer realloc failed\n"); | |
416 return AVERROR(ENOMEM); | |
417 } | |
418 memcpy((uint8_t*)stats->buf + stats->sz, | |
419 pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz); | |
420 stats->sz += pkt->data.twopass_stats.sz; | |
421 break; | |
422 } | |
423 case VPX_CODEC_PSNR_PKT: //FIXME add support for CODEC_FLAG_PSNR | |
424 case VPX_CODEC_CUSTOM_PKT: | |
425 //ignore unsupported/unrecognized packet types | |
426 break; | |
427 } | |
428 } | |
429 | |
430 return size; | |
431 } | |
432 | |
433 static int vp8_encode(AVCodecContext *avctx, uint8_t *buf, int buf_size, | |
434 void *data) | |
435 { | |
436 VP8Context *ctx = avctx->priv_data; | |
437 AVFrame *frame = data; | |
438 struct vpx_image *rawimg = NULL; | |
439 int64_t timestamp = 0; | |
440 int res, coded_size; | |
441 | |
442 if (frame) { | |
443 rawimg = &ctx->rawimg; | |
444 rawimg->planes[VPX_PLANE_Y] = frame->data[0]; | |
445 rawimg->planes[VPX_PLANE_U] = frame->data[1]; | |
446 rawimg->planes[VPX_PLANE_V] = frame->data[2]; | |
447 rawimg->stride[VPX_PLANE_Y] = frame->linesize[0]; | |
448 rawimg->stride[VPX_PLANE_U] = frame->linesize[1]; | |
449 rawimg->stride[VPX_PLANE_V] = frame->linesize[2]; | |
450 timestamp = frame->pts; | |
451 } | |
452 | |
453 res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp, | |
454 avctx->ticks_per_frame, 0, ctx->deadline); | |
455 if (res != VPX_CODEC_OK) { | |
456 log_encoder_error(avctx, "Error encoding frame"); | |
457 return AVERROR_INVALIDDATA; | |
458 } | |
459 coded_size = queue_frames(avctx, buf, buf_size, avctx->coded_frame); | |
460 | |
461 if (!frame && avctx->flags & CODEC_FLAG_PASS1) { | |
11846 | 462 unsigned int b64_size = AV_BASE64_SIZE(ctx->twopass_stats.sz); |
11821 | 463 |
464 avctx->stats_out = av_malloc(b64_size); | |
465 if (!avctx->stats_out) { | |
466 av_log(avctx, AV_LOG_ERROR, "Stat buffer alloc (%d bytes) failed\n", | |
467 b64_size); | |
468 return AVERROR(ENOMEM); | |
469 } | |
470 av_base64_encode(avctx->stats_out, b64_size, ctx->twopass_stats.buf, | |
471 ctx->twopass_stats.sz); | |
472 } | |
473 return coded_size; | |
474 } | |
475 | |
476 AVCodec libvpx_encoder = { | |
477 "libvpx", | |
478 AVMEDIA_TYPE_VIDEO, | |
479 CODEC_ID_VP8, | |
480 sizeof(VP8Context), | |
481 vp8_init, | |
482 vp8_encode, | |
483 vp8_free, | |
484 NULL, | |
485 CODEC_CAP_DELAY, | |
486 .pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, | |
487 .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"), | |
488 }; |