|
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 /*!\file |
|
13 * \brief Provides the high level interface to wrap encoder algorithms. |
|
14 * |
|
15 */ |
|
16 #include <limits.h> |
|
17 #include <string.h> |
|
18 #include "vpx/internal/vpx_codec_internal.h" |
|
19 #include "vpx_config.h" |
|
20 |
|
21 #define SAVE_STATUS(ctx,var) (ctx?(ctx->err = var):var) |
|
22 |
|
23 vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t *ctx, |
|
24 vpx_codec_iface_t *iface, |
|
25 vpx_codec_enc_cfg_t *cfg, |
|
26 vpx_codec_flags_t flags, |
|
27 int ver) { |
|
28 vpx_codec_err_t res; |
|
29 |
|
30 if (ver != VPX_ENCODER_ABI_VERSION) |
|
31 res = VPX_CODEC_ABI_MISMATCH; |
|
32 else if (!ctx || !iface || !cfg) |
|
33 res = VPX_CODEC_INVALID_PARAM; |
|
34 else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION) |
|
35 res = VPX_CODEC_ABI_MISMATCH; |
|
36 else if (!(iface->caps & VPX_CODEC_CAP_ENCODER)) |
|
37 res = VPX_CODEC_INCAPABLE; |
|
38 else if ((flags & VPX_CODEC_USE_XMA) && !(iface->caps & VPX_CODEC_CAP_XMA)) |
|
39 res = VPX_CODEC_INCAPABLE; |
|
40 else if ((flags & VPX_CODEC_USE_PSNR) |
|
41 && !(iface->caps & VPX_CODEC_CAP_PSNR)) |
|
42 res = VPX_CODEC_INCAPABLE; |
|
43 else if ((flags & VPX_CODEC_USE_OUTPUT_PARTITION) |
|
44 && !(iface->caps & VPX_CODEC_CAP_OUTPUT_PARTITION)) |
|
45 res = VPX_CODEC_INCAPABLE; |
|
46 else { |
|
47 ctx->iface = iface; |
|
48 ctx->name = iface->name; |
|
49 ctx->priv = NULL; |
|
50 ctx->init_flags = flags; |
|
51 ctx->config.enc = cfg; |
|
52 res = ctx->iface->init(ctx, NULL); |
|
53 |
|
54 if (res) { |
|
55 ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL; |
|
56 vpx_codec_destroy(ctx); |
|
57 } |
|
58 |
|
59 if (ctx->priv) |
|
60 ctx->priv->iface = ctx->iface; |
|
61 } |
|
62 |
|
63 return SAVE_STATUS(ctx, res); |
|
64 } |
|
65 |
|
66 vpx_codec_err_t vpx_codec_enc_init_multi_ver(vpx_codec_ctx_t *ctx, |
|
67 vpx_codec_iface_t *iface, |
|
68 vpx_codec_enc_cfg_t *cfg, |
|
69 int num_enc, |
|
70 vpx_codec_flags_t flags, |
|
71 vpx_rational_t *dsf, |
|
72 int ver) { |
|
73 vpx_codec_err_t res = 0; |
|
74 |
|
75 if (ver != VPX_ENCODER_ABI_VERSION) |
|
76 res = VPX_CODEC_ABI_MISMATCH; |
|
77 else if (!ctx || !iface || !cfg || (num_enc > 16 || num_enc < 1)) |
|
78 res = VPX_CODEC_INVALID_PARAM; |
|
79 else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION) |
|
80 res = VPX_CODEC_ABI_MISMATCH; |
|
81 else if (!(iface->caps & VPX_CODEC_CAP_ENCODER)) |
|
82 res = VPX_CODEC_INCAPABLE; |
|
83 else if ((flags & VPX_CODEC_USE_XMA) && !(iface->caps & VPX_CODEC_CAP_XMA)) |
|
84 res = VPX_CODEC_INCAPABLE; |
|
85 else if ((flags & VPX_CODEC_USE_PSNR) |
|
86 && !(iface->caps & VPX_CODEC_CAP_PSNR)) |
|
87 res = VPX_CODEC_INCAPABLE; |
|
88 else if ((flags & VPX_CODEC_USE_OUTPUT_PARTITION) |
|
89 && !(iface->caps & VPX_CODEC_CAP_OUTPUT_PARTITION)) |
|
90 res = VPX_CODEC_INCAPABLE; |
|
91 else { |
|
92 int i; |
|
93 void *mem_loc = NULL; |
|
94 |
|
95 if (!(res = iface->enc.mr_get_mem_loc(cfg, &mem_loc))) { |
|
96 for (i = 0; i < num_enc; i++) { |
|
97 vpx_codec_priv_enc_mr_cfg_t mr_cfg; |
|
98 |
|
99 /* Validate down-sampling factor. */ |
|
100 if (dsf->num < 1 || dsf->num > 4096 || dsf->den < 1 || |
|
101 dsf->den > dsf->num) { |
|
102 res = VPX_CODEC_INVALID_PARAM; |
|
103 break; |
|
104 } |
|
105 |
|
106 mr_cfg.mr_low_res_mode_info = mem_loc; |
|
107 mr_cfg.mr_total_resolutions = num_enc; |
|
108 mr_cfg.mr_encoder_id = num_enc - 1 - i; |
|
109 mr_cfg.mr_down_sampling_factor.num = dsf->num; |
|
110 mr_cfg.mr_down_sampling_factor.den = dsf->den; |
|
111 |
|
112 /* Force Key-frame synchronization. Namely, encoder at higher |
|
113 * resolution always use the same frame_type chosen by the |
|
114 * lowest-resolution encoder. |
|
115 */ |
|
116 if (mr_cfg.mr_encoder_id) |
|
117 cfg->kf_mode = VPX_KF_DISABLED; |
|
118 |
|
119 ctx->iface = iface; |
|
120 ctx->name = iface->name; |
|
121 ctx->priv = NULL; |
|
122 ctx->init_flags = flags; |
|
123 ctx->config.enc = cfg; |
|
124 res = ctx->iface->init(ctx, &mr_cfg); |
|
125 |
|
126 if (res) { |
|
127 const char *error_detail = |
|
128 ctx->priv ? ctx->priv->err_detail : NULL; |
|
129 /* Destroy current ctx */ |
|
130 ctx->err_detail = error_detail; |
|
131 vpx_codec_destroy(ctx); |
|
132 |
|
133 /* Destroy already allocated high-level ctx */ |
|
134 while (i) { |
|
135 ctx--; |
|
136 ctx->err_detail = error_detail; |
|
137 vpx_codec_destroy(ctx); |
|
138 i--; |
|
139 } |
|
140 } |
|
141 |
|
142 if (ctx->priv) |
|
143 ctx->priv->iface = ctx->iface; |
|
144 |
|
145 if (res) |
|
146 break; |
|
147 |
|
148 ctx++; |
|
149 cfg++; |
|
150 dsf++; |
|
151 } |
|
152 } |
|
153 } |
|
154 |
|
155 return SAVE_STATUS(ctx, res); |
|
156 } |
|
157 |
|
158 |
|
159 vpx_codec_err_t vpx_codec_enc_config_default(vpx_codec_iface_t *iface, |
|
160 vpx_codec_enc_cfg_t *cfg, |
|
161 unsigned int usage) { |
|
162 vpx_codec_err_t res; |
|
163 vpx_codec_enc_cfg_map_t *map; |
|
164 |
|
165 if (!iface || !cfg || usage > INT_MAX) |
|
166 res = VPX_CODEC_INVALID_PARAM; |
|
167 else if (!(iface->caps & VPX_CODEC_CAP_ENCODER)) |
|
168 res = VPX_CODEC_INCAPABLE; |
|
169 else { |
|
170 res = VPX_CODEC_INVALID_PARAM; |
|
171 |
|
172 for (map = iface->enc.cfg_maps; map->usage >= 0; map++) { |
|
173 if (map->usage == (int)usage) { |
|
174 *cfg = map->cfg; |
|
175 cfg->g_usage = usage; |
|
176 res = VPX_CODEC_OK; |
|
177 break; |
|
178 } |
|
179 } |
|
180 } |
|
181 |
|
182 return res; |
|
183 } |
|
184 |
|
185 |
|
186 #if ARCH_X86 || ARCH_X86_64 |
|
187 /* On X86, disable the x87 unit's internal 80 bit precision for better |
|
188 * consistency with the SSE unit's 64 bit precision. |
|
189 */ |
|
190 #include "vpx_ports/x86.h" |
|
191 #define FLOATING_POINT_INIT() do {\ |
|
192 unsigned short x87_orig_mode = x87_set_double_precision(); |
|
193 #define FLOATING_POINT_RESTORE() \ |
|
194 x87_set_control_word(x87_orig_mode); }while(0) |
|
195 |
|
196 |
|
197 #else |
|
198 static void FLOATING_POINT_INIT() {} |
|
199 static void FLOATING_POINT_RESTORE() {} |
|
200 #endif |
|
201 |
|
202 |
|
203 vpx_codec_err_t vpx_codec_encode(vpx_codec_ctx_t *ctx, |
|
204 const vpx_image_t *img, |
|
205 vpx_codec_pts_t pts, |
|
206 unsigned long duration, |
|
207 vpx_enc_frame_flags_t flags, |
|
208 unsigned long deadline) { |
|
209 vpx_codec_err_t res = 0; |
|
210 |
|
211 if (!ctx || (img && !duration)) |
|
212 res = VPX_CODEC_INVALID_PARAM; |
|
213 else if (!ctx->iface || !ctx->priv) |
|
214 res = VPX_CODEC_ERROR; |
|
215 else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) |
|
216 res = VPX_CODEC_INCAPABLE; |
|
217 else { |
|
218 unsigned int num_enc = ctx->priv->enc.total_encoders; |
|
219 |
|
220 /* Execute in a normalized floating point environment, if the platform |
|
221 * requires it. |
|
222 */ |
|
223 FLOATING_POINT_INIT(); |
|
224 |
|
225 if (num_enc == 1) |
|
226 res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts, |
|
227 duration, flags, deadline); |
|
228 else { |
|
229 /* Multi-resolution encoding: |
|
230 * Encode multi-levels in reverse order. For example, |
|
231 * if mr_total_resolutions = 3, first encode level 2, |
|
232 * then encode level 1, and finally encode level 0. |
|
233 */ |
|
234 int i; |
|
235 |
|
236 ctx += num_enc - 1; |
|
237 if (img) img += num_enc - 1; |
|
238 |
|
239 for (i = num_enc - 1; i >= 0; i--) { |
|
240 if ((res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts, |
|
241 duration, flags, deadline))) |
|
242 break; |
|
243 |
|
244 ctx--; |
|
245 if (img) img--; |
|
246 } |
|
247 ctx++; |
|
248 } |
|
249 |
|
250 FLOATING_POINT_RESTORE(); |
|
251 } |
|
252 |
|
253 return SAVE_STATUS(ctx, res); |
|
254 } |
|
255 |
|
256 |
|
257 const vpx_codec_cx_pkt_t *vpx_codec_get_cx_data(vpx_codec_ctx_t *ctx, |
|
258 vpx_codec_iter_t *iter) { |
|
259 const vpx_codec_cx_pkt_t *pkt = NULL; |
|
260 |
|
261 if (ctx) { |
|
262 if (!iter) |
|
263 ctx->err = VPX_CODEC_INVALID_PARAM; |
|
264 else if (!ctx->iface || !ctx->priv) |
|
265 ctx->err = VPX_CODEC_ERROR; |
|
266 else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) |
|
267 ctx->err = VPX_CODEC_INCAPABLE; |
|
268 else |
|
269 pkt = ctx->iface->enc.get_cx_data(ctx->priv->alg_priv, iter); |
|
270 } |
|
271 |
|
272 if (pkt && pkt->kind == VPX_CODEC_CX_FRAME_PKT) { |
|
273 /* If the application has specified a destination area for the |
|
274 * compressed data, and the codec has not placed the data there, |
|
275 * and it fits, copy it. |
|
276 */ |
|
277 char *dst_buf = ctx->priv->enc.cx_data_dst_buf.buf; |
|
278 |
|
279 if (dst_buf |
|
280 && pkt->data.raw.buf != dst_buf |
|
281 && pkt->data.raw.sz |
|
282 + ctx->priv->enc.cx_data_pad_before |
|
283 + ctx->priv->enc.cx_data_pad_after |
|
284 <= ctx->priv->enc.cx_data_dst_buf.sz) { |
|
285 vpx_codec_cx_pkt_t *modified_pkt = &ctx->priv->enc.cx_data_pkt; |
|
286 |
|
287 memcpy(dst_buf + ctx->priv->enc.cx_data_pad_before, |
|
288 pkt->data.raw.buf, pkt->data.raw.sz); |
|
289 *modified_pkt = *pkt; |
|
290 modified_pkt->data.raw.buf = dst_buf; |
|
291 modified_pkt->data.raw.sz += ctx->priv->enc.cx_data_pad_before |
|
292 + ctx->priv->enc.cx_data_pad_after; |
|
293 pkt = modified_pkt; |
|
294 } |
|
295 |
|
296 if (dst_buf == pkt->data.raw.buf) { |
|
297 ctx->priv->enc.cx_data_dst_buf.buf = dst_buf + pkt->data.raw.sz; |
|
298 ctx->priv->enc.cx_data_dst_buf.sz -= pkt->data.raw.sz; |
|
299 } |
|
300 } |
|
301 |
|
302 return pkt; |
|
303 } |
|
304 |
|
305 |
|
306 vpx_codec_err_t vpx_codec_set_cx_data_buf(vpx_codec_ctx_t *ctx, |
|
307 const vpx_fixed_buf_t *buf, |
|
308 unsigned int pad_before, |
|
309 unsigned int pad_after) { |
|
310 if (!ctx || !ctx->priv) |
|
311 return VPX_CODEC_INVALID_PARAM; |
|
312 |
|
313 if (buf) { |
|
314 ctx->priv->enc.cx_data_dst_buf = *buf; |
|
315 ctx->priv->enc.cx_data_pad_before = pad_before; |
|
316 ctx->priv->enc.cx_data_pad_after = pad_after; |
|
317 } else { |
|
318 ctx->priv->enc.cx_data_dst_buf.buf = NULL; |
|
319 ctx->priv->enc.cx_data_dst_buf.sz = 0; |
|
320 ctx->priv->enc.cx_data_pad_before = 0; |
|
321 ctx->priv->enc.cx_data_pad_after = 0; |
|
322 } |
|
323 |
|
324 return VPX_CODEC_OK; |
|
325 } |
|
326 |
|
327 |
|
328 const vpx_image_t *vpx_codec_get_preview_frame(vpx_codec_ctx_t *ctx) { |
|
329 vpx_image_t *img = NULL; |
|
330 |
|
331 if (ctx) { |
|
332 if (!ctx->iface || !ctx->priv) |
|
333 ctx->err = VPX_CODEC_ERROR; |
|
334 else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) |
|
335 ctx->err = VPX_CODEC_INCAPABLE; |
|
336 else if (!ctx->iface->enc.get_preview) |
|
337 ctx->err = VPX_CODEC_INCAPABLE; |
|
338 else |
|
339 img = ctx->iface->enc.get_preview(ctx->priv->alg_priv); |
|
340 } |
|
341 |
|
342 return img; |
|
343 } |
|
344 |
|
345 |
|
346 vpx_fixed_buf_t *vpx_codec_get_global_headers(vpx_codec_ctx_t *ctx) { |
|
347 vpx_fixed_buf_t *buf = NULL; |
|
348 |
|
349 if (ctx) { |
|
350 if (!ctx->iface || !ctx->priv) |
|
351 ctx->err = VPX_CODEC_ERROR; |
|
352 else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) |
|
353 ctx->err = VPX_CODEC_INCAPABLE; |
|
354 else if (!ctx->iface->enc.get_glob_hdrs) |
|
355 ctx->err = VPX_CODEC_INCAPABLE; |
|
356 else |
|
357 buf = ctx->iface->enc.get_glob_hdrs(ctx->priv->alg_priv); |
|
358 } |
|
359 |
|
360 return buf; |
|
361 } |
|
362 |
|
363 |
|
364 vpx_codec_err_t vpx_codec_enc_config_set(vpx_codec_ctx_t *ctx, |
|
365 const vpx_codec_enc_cfg_t *cfg) { |
|
366 vpx_codec_err_t res; |
|
367 |
|
368 if (!ctx || !ctx->iface || !ctx->priv || !cfg) |
|
369 res = VPX_CODEC_INVALID_PARAM; |
|
370 else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER)) |
|
371 res = VPX_CODEC_INCAPABLE; |
|
372 else |
|
373 res = ctx->iface->enc.cfg_set(ctx->priv->alg_priv, cfg); |
|
374 |
|
375 return SAVE_STATUS(ctx, res); |
|
376 } |
|
377 |
|
378 |
|
379 int vpx_codec_pkt_list_add(struct vpx_codec_pkt_list *list, |
|
380 const struct vpx_codec_cx_pkt *pkt) { |
|
381 if (list->cnt < list->max) { |
|
382 list->pkts[list->cnt++] = *pkt; |
|
383 return 0; |
|
384 } |
|
385 |
|
386 return 1; |
|
387 } |
|
388 |
|
389 |
|
390 const vpx_codec_cx_pkt_t *vpx_codec_pkt_list_get(struct vpx_codec_pkt_list *list, |
|
391 vpx_codec_iter_t *iter) { |
|
392 const vpx_codec_cx_pkt_t *pkt; |
|
393 |
|
394 if (!(*iter)) { |
|
395 *iter = list->pkts; |
|
396 } |
|
397 |
|
398 pkt = (const void *) * iter; |
|
399 |
|
400 if ((size_t)(pkt - list->pkts) < list->cnt) |
|
401 *iter = pkt + 1; |
|
402 else |
|
403 pkt = NULL; |
|
404 |
|
405 return pkt; |
|
406 } |