Mercurial > libavcodec.hg
annotate libvpxenc.c @ 12494:94eaea836bf4 libavcodec
Check avctx width/height more thoroughly (e.g. all values 0 except width would
have been accepted before).
Also do not fail if they are invalid but instead override them to 0.
This allows decoding e.g. MPEG video when only the container values are corrupted.
For encoding a value of 0,0 of course makes no sense, but was allowed
through before and will be caught by an extra check in the encode function.
author | reimar |
---|---|
date | Wed, 15 Sep 2010 04:46:55 +0000 |
parents | aa0714243f88 |
children |
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 { | |
12337 | 39 void *buf; /**< compressed data buffer */ |
40 size_t sz; /**< length of compressed data */ | |
41 int64_t pts; /**< time stamp to show frame | |
11821 | 42 (in timebase units) */ |
12337 | 43 unsigned long duration; /**< duration to show frame |
11821 | 44 (in timebase units) */ |
12337 | 45 uint32_t flags; /**< flags for this frame */ |
11821 | 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 | |
12152
d102b12f69dc
Do not map video quantizer scale (from 1-51 to 0-63) for libvpx anymore.
cehoyos
parents:
12140
diff
changeset
|
240 enccfg.rc_min_quantizer = avctx->qmin; |
d102b12f69dc
Do not map video quantizer scale (from 1-51 to 0-63) for libvpx anymore.
cehoyos
parents:
12140
diff
changeset
|
241 enccfg.rc_max_quantizer = avctx->qmax; |
11852
24a6c651c3f3
libvpx: Set the libvpx frame dropping threshold to frame_skip_threshold
mstorsjo
parents:
11851
diff
changeset
|
242 enccfg.rc_dropframe_thresh = avctx->frame_skip_threshold; |
11821 | 243 |
12226 | 244 //0-100 (0 => CBR, 100 => VBR) |
245 enccfg.rc_2pass_vbr_bias_pct = round(avctx->qcompress * 100); | |
246 enccfg.rc_2pass_vbr_minsection_pct = | |
247 avctx->rc_min_rate * 100 / avctx->bit_rate; | |
248 if (avctx->rc_max_rate) | |
249 enccfg.rc_2pass_vbr_maxsection_pct = | |
250 avctx->rc_max_rate * 100 / avctx->bit_rate; | |
251 | |
12295
bb7b7602b40e
Map rc_buffer_size to and c_initial_buffer_occupancy to their libvpx
cehoyos
parents:
12226
diff
changeset
|
252 if (avctx->rc_buffer_size) |
bb7b7602b40e
Map rc_buffer_size to and c_initial_buffer_occupancy to their libvpx
cehoyos
parents:
12226
diff
changeset
|
253 enccfg.rc_buf_sz = |
bb7b7602b40e
Map rc_buffer_size to and c_initial_buffer_occupancy to their libvpx
cehoyos
parents:
12226
diff
changeset
|
254 avctx->rc_buffer_size * 1000 / avctx->bit_rate; |
bb7b7602b40e
Map rc_buffer_size to and c_initial_buffer_occupancy to their libvpx
cehoyos
parents:
12226
diff
changeset
|
255 if (avctx->rc_initial_buffer_occupancy) |
bb7b7602b40e
Map rc_buffer_size to and c_initial_buffer_occupancy to their libvpx
cehoyos
parents:
12226
diff
changeset
|
256 enccfg.rc_buf_initial_sz = |
bb7b7602b40e
Map rc_buffer_size to and c_initial_buffer_occupancy to their libvpx
cehoyos
parents:
12226
diff
changeset
|
257 avctx->rc_initial_buffer_occupancy * 1000 / avctx->bit_rate; |
bb7b7602b40e
Map rc_buffer_size to and c_initial_buffer_occupancy to their libvpx
cehoyos
parents:
12226
diff
changeset
|
258 enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6; |
bb7b7602b40e
Map rc_buffer_size to and c_initial_buffer_occupancy to their libvpx
cehoyos
parents:
12226
diff
changeset
|
259 |
11851 | 260 //_enc_init() will balk if kf_min_dist differs from max w/VPX_KF_AUTO |
11821 | 261 if (avctx->keyint_min == avctx->gop_size) |
262 enccfg.kf_min_dist = avctx->keyint_min; | |
263 enccfg.kf_max_dist = avctx->gop_size; | |
264 | |
265 if (enccfg.g_pass == VPX_RC_FIRST_PASS) | |
266 enccfg.g_lag_in_frames = 0; | |
267 else if (enccfg.g_pass == VPX_RC_LAST_PASS) { | |
268 int decode_size; | |
269 | |
270 if (!avctx->stats_in) { | |
271 av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n"); | |
272 return AVERROR_INVALIDDATA; | |
273 } | |
274 | |
275 ctx->twopass_stats.sz = strlen(avctx->stats_in) * 3 / 4; | |
276 ctx->twopass_stats.buf = av_malloc(ctx->twopass_stats.sz); | |
277 if (!ctx->twopass_stats.buf) { | |
278 av_log(avctx, AV_LOG_ERROR, | |
279 "Stat buffer alloc (%zu bytes) failed\n", | |
280 ctx->twopass_stats.sz); | |
281 return AVERROR(ENOMEM); | |
282 } | |
283 decode_size = av_base64_decode(ctx->twopass_stats.buf, avctx->stats_in, | |
284 ctx->twopass_stats.sz); | |
285 if (decode_size < 0) { | |
286 av_log(avctx, AV_LOG_ERROR, "Stat buffer decode failed\n"); | |
287 return AVERROR_INVALIDDATA; | |
288 } | |
289 | |
290 ctx->twopass_stats.sz = decode_size; | |
291 enccfg.rc_twopass_stats_in = ctx->twopass_stats; | |
292 } | |
293 | |
294 ctx->deadline = VPX_DL_GOOD_QUALITY; | |
12140
3d186eff2224
Set libvpx encoding profile to libavcodec's profile.
cehoyos
parents:
11852
diff
changeset
|
295 /* 0-3: For non-zero values the encoder increasingly optimizes for reduced |
3d186eff2224
Set libvpx encoding profile to libavcodec's profile.
cehoyos
parents:
11852
diff
changeset
|
296 complexity playback on low powered devices at the expense of encode |
3d186eff2224
Set libvpx encoding profile to libavcodec's profile.
cehoyos
parents:
11852
diff
changeset
|
297 quality. */ |
3d186eff2224
Set libvpx encoding profile to libavcodec's profile.
cehoyos
parents:
11852
diff
changeset
|
298 if (avctx->profile != FF_PROFILE_UNKNOWN) |
3d186eff2224
Set libvpx encoding profile to libavcodec's profile.
cehoyos
parents:
11852
diff
changeset
|
299 enccfg.g_profile = avctx->profile; |
11821 | 300 |
301 dump_enc_cfg(avctx, &enccfg); | |
302 /* Construct Encoder Context */ | |
303 res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, 0); | |
304 if (res != VPX_CODEC_OK) { | |
305 log_encoder_error(avctx, "Failed to initialize encoder"); | |
306 return AVERROR(EINVAL); | |
307 } | |
308 | |
309 //codec control failures are currently treated only as warnings | |
310 av_log(avctx, AV_LOG_DEBUG, "vpx_codec_control\n"); | |
311 codecctl_int(avctx, VP8E_SET_CPUUSED, cpuused); | |
312 codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction); | |
313 | |
314 //provide dummy value to initialize wrapper, values will be updated each _encode() | |
315 vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1, | |
316 (unsigned char*)1); | |
317 | |
318 avctx->coded_frame = avcodec_alloc_frame(); | |
319 if (!avctx->coded_frame) { | |
320 av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n"); | |
321 vp8_free(avctx); | |
322 return AVERROR(ENOMEM); | |
323 } | |
324 return 0; | |
325 } | |
326 | |
327 static inline void cx_pktcpy(struct FrameListData *dst, | |
328 const struct vpx_codec_cx_pkt *src) | |
329 { | |
330 dst->pts = src->data.frame.pts; | |
331 dst->duration = src->data.frame.duration; | |
332 dst->flags = src->data.frame.flags; | |
333 dst->sz = src->data.frame.sz; | |
334 dst->buf = src->data.frame.buf; | |
335 } | |
336 | |
337 /** | |
338 * Store coded frame information in format suitable for return from encode(). | |
339 * | |
340 * Write buffer information from @a cx_frame to @a buf & @a buf_size. | |
341 * Timing/frame details to @a coded_frame. | |
342 * @return Frame size written to @a buf on success | |
343 * @return AVERROR(EINVAL) on error | |
344 */ | |
345 static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, | |
346 uint8_t *buf, int buf_size, AVFrame *coded_frame) | |
347 { | |
348 if ((int) cx_frame->sz <= buf_size) { | |
349 buf_size = cx_frame->sz; | |
350 memcpy(buf, cx_frame->buf, buf_size); | |
351 coded_frame->pts = cx_frame->pts; | |
352 coded_frame->key_frame = !!(cx_frame->flags & VPX_FRAME_IS_KEY); | |
353 | |
354 if (coded_frame->key_frame) | |
355 coded_frame->pict_type = FF_I_TYPE; | |
356 else | |
357 coded_frame->pict_type = FF_P_TYPE; | |
358 } else { | |
359 av_log(avctx, AV_LOG_ERROR, | |
360 "Compressed frame larger than storage provided! (%zu/%d)\n", | |
361 cx_frame->sz, buf_size); | |
362 return AVERROR(EINVAL); | |
363 } | |
364 return buf_size; | |
365 } | |
366 | |
367 /** | |
368 * Queue multiple output frames from the encoder, returning the front-most. | |
369 * In cases where vpx_codec_get_cx_data() returns more than 1 frame append | |
370 * the frame queue. Return the head frame if available. | |
371 * @return Stored frame size | |
372 * @return AVERROR(EINVAL) on output size error | |
373 * @return AVERROR(ENOMEM) on coded frame queue data allocation error | |
374 */ | |
375 static int queue_frames(AVCodecContext *avctx, uint8_t *buf, int buf_size, | |
376 AVFrame *coded_frame) | |
377 { | |
378 VP8Context *ctx = avctx->priv_data; | |
379 const struct vpx_codec_cx_pkt *pkt; | |
380 const void *iter = NULL; | |
381 int size = 0; | |
382 | |
383 if (ctx->coded_frame_list) { | |
384 struct FrameListData *cx_frame = ctx->coded_frame_list; | |
385 /* return the leading frame if we've already begun queueing */ | |
386 size = storeframe(avctx, cx_frame, buf, buf_size, coded_frame); | |
387 if (size < 0) | |
388 return AVERROR(EINVAL); | |
389 ctx->coded_frame_list = cx_frame->next; | |
390 free_coded_frame(cx_frame); | |
391 } | |
392 | |
393 /* consume all available output from the encoder before returning. buffers | |
394 are only good through the next vpx_codec call */ | |
395 while ((pkt = vpx_codec_get_cx_data(&ctx->encoder, &iter))) { | |
396 switch (pkt->kind) { | |
397 case VPX_CODEC_CX_FRAME_PKT: | |
398 if (!size) { | |
399 struct FrameListData cx_frame; | |
400 | |
401 /* avoid storing the frame when the list is empty and we haven't yet | |
402 provided a frame for output */ | |
403 assert(!ctx->coded_frame_list); | |
404 cx_pktcpy(&cx_frame, pkt); | |
405 size = storeframe(avctx, &cx_frame, buf, buf_size, coded_frame); | |
406 if (size < 0) | |
407 return AVERROR(EINVAL); | |
408 } else { | |
409 struct FrameListData *cx_frame = | |
410 av_malloc(sizeof(struct FrameListData)); | |
411 | |
412 if (!cx_frame) { | |
413 av_log(avctx, AV_LOG_ERROR, | |
414 "Frame queue element alloc failed\n"); | |
415 return AVERROR(ENOMEM); | |
416 } | |
417 cx_pktcpy(cx_frame, pkt); | |
418 cx_frame->buf = av_malloc(cx_frame->sz); | |
419 | |
420 if (!cx_frame->buf) { | |
421 av_log(avctx, AV_LOG_ERROR, | |
422 "Data buffer alloc (%zu bytes) failed\n", | |
423 cx_frame->sz); | |
424 return AVERROR(ENOMEM); | |
425 } | |
426 memcpy(cx_frame->buf, pkt->data.frame.buf, pkt->data.frame.sz); | |
427 coded_frame_add(&ctx->coded_frame_list, cx_frame); | |
428 } | |
429 break; | |
430 case VPX_CODEC_STATS_PKT: { | |
431 struct vpx_fixed_buf *stats = &ctx->twopass_stats; | |
432 stats->buf = av_realloc(stats->buf, | |
433 stats->sz + pkt->data.twopass_stats.sz); | |
434 if (!stats->buf) { | |
435 av_log(avctx, AV_LOG_ERROR, "Stat buffer realloc failed\n"); | |
436 return AVERROR(ENOMEM); | |
437 } | |
438 memcpy((uint8_t*)stats->buf + stats->sz, | |
439 pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz); | |
440 stats->sz += pkt->data.twopass_stats.sz; | |
441 break; | |
442 } | |
443 case VPX_CODEC_PSNR_PKT: //FIXME add support for CODEC_FLAG_PSNR | |
444 case VPX_CODEC_CUSTOM_PKT: | |
445 //ignore unsupported/unrecognized packet types | |
446 break; | |
447 } | |
448 } | |
449 | |
450 return size; | |
451 } | |
452 | |
453 static int vp8_encode(AVCodecContext *avctx, uint8_t *buf, int buf_size, | |
454 void *data) | |
455 { | |
456 VP8Context *ctx = avctx->priv_data; | |
457 AVFrame *frame = data; | |
458 struct vpx_image *rawimg = NULL; | |
459 int64_t timestamp = 0; | |
460 int res, coded_size; | |
461 | |
462 if (frame) { | |
463 rawimg = &ctx->rawimg; | |
464 rawimg->planes[VPX_PLANE_Y] = frame->data[0]; | |
465 rawimg->planes[VPX_PLANE_U] = frame->data[1]; | |
466 rawimg->planes[VPX_PLANE_V] = frame->data[2]; | |
467 rawimg->stride[VPX_PLANE_Y] = frame->linesize[0]; | |
468 rawimg->stride[VPX_PLANE_U] = frame->linesize[1]; | |
469 rawimg->stride[VPX_PLANE_V] = frame->linesize[2]; | |
470 timestamp = frame->pts; | |
471 } | |
472 | |
473 res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp, | |
474 avctx->ticks_per_frame, 0, ctx->deadline); | |
475 if (res != VPX_CODEC_OK) { | |
476 log_encoder_error(avctx, "Error encoding frame"); | |
477 return AVERROR_INVALIDDATA; | |
478 } | |
479 coded_size = queue_frames(avctx, buf, buf_size, avctx->coded_frame); | |
480 | |
481 if (!frame && avctx->flags & CODEC_FLAG_PASS1) { | |
11846 | 482 unsigned int b64_size = AV_BASE64_SIZE(ctx->twopass_stats.sz); |
11821 | 483 |
484 avctx->stats_out = av_malloc(b64_size); | |
485 if (!avctx->stats_out) { | |
486 av_log(avctx, AV_LOG_ERROR, "Stat buffer alloc (%d bytes) failed\n", | |
487 b64_size); | |
488 return AVERROR(ENOMEM); | |
489 } | |
490 av_base64_encode(avctx->stats_out, b64_size, ctx->twopass_stats.buf, | |
491 ctx->twopass_stats.sz); | |
492 } | |
493 return coded_size; | |
494 } | |
495 | |
496 AVCodec libvpx_encoder = { | |
497 "libvpx", | |
498 AVMEDIA_TYPE_VIDEO, | |
499 CODEC_ID_VP8, | |
500 sizeof(VP8Context), | |
501 vp8_init, | |
502 vp8_encode, | |
503 vp8_free, | |
504 NULL, | |
505 CODEC_CAP_DELAY, | |
506 .pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, | |
507 .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"), | |
508 }; |