blob: 41c70ef1b4b177b320ffaa8b3d7a338f173d76dc [file] [log] [blame]
Yaowu Xuc27fc142016-08-22 16:08:15 -07001/*
Yaowu Xu9c01aa12016-09-01 14:32:49 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Yaowu Xuc27fc142016-08-22 16:08:15 -07003 *
Yaowu Xu9c01aa12016-09-01 14:32:49 -07004 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Yaowu Xuc27fc142016-08-22 16:08:15 -070010 */
11
12/*!\file
13 * \brief Provides the high level interface to wrap encoder algorithms.
14 *
15 */
16#include <limits.h>
17#include <string.h>
Yaowu Xuf883b422016-08-30 14:01:10 -070018#include "aom_config.h"
19#include "aom/internal/aom_codec_internal.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070020
21#define SAVE_STATUS(ctx, var) (ctx ? (ctx->err = var) : var)
22
Yaowu Xuf883b422016-08-30 14:01:10 -070023static aom_codec_alg_priv_t *get_alg_priv(aom_codec_ctx_t *ctx) {
24 return (aom_codec_alg_priv_t *)ctx->priv;
Yaowu Xuc27fc142016-08-22 16:08:15 -070025}
26
Yaowu Xuf883b422016-08-30 14:01:10 -070027aom_codec_err_t aom_codec_enc_init_ver(aom_codec_ctx_t *ctx,
28 aom_codec_iface_t *iface,
29 const aom_codec_enc_cfg_t *cfg,
30 aom_codec_flags_t flags, int ver) {
31 aom_codec_err_t res;
Yaowu Xuc27fc142016-08-22 16:08:15 -070032
Yaowu Xuf883b422016-08-30 14:01:10 -070033 if (ver != AOM_ENCODER_ABI_VERSION)
34 res = AOM_CODEC_ABI_MISMATCH;
Yaowu Xuc27fc142016-08-22 16:08:15 -070035 else if (!ctx || !iface || !cfg)
Yaowu Xuf883b422016-08-30 14:01:10 -070036 res = AOM_CODEC_INVALID_PARAM;
37 else if (iface->abi_version != AOM_CODEC_INTERNAL_ABI_VERSION)
38 res = AOM_CODEC_ABI_MISMATCH;
39 else if (!(iface->caps & AOM_CODEC_CAP_ENCODER))
40 res = AOM_CODEC_INCAPABLE;
41 else if ((flags & AOM_CODEC_USE_PSNR) && !(iface->caps & AOM_CODEC_CAP_PSNR))
42 res = AOM_CODEC_INCAPABLE;
43 else if ((flags & AOM_CODEC_USE_OUTPUT_PARTITION) &&
44 !(iface->caps & AOM_CODEC_CAP_OUTPUT_PARTITION))
45 res = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -070046 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;
Yaowu Xuf883b422016-08-30 14:01:10 -070056 aom_codec_destroy(ctx);
Yaowu Xuc27fc142016-08-22 16:08:15 -070057 }
58 }
59
60 return SAVE_STATUS(ctx, res);
61}
62
Yaowu Xuf883b422016-08-30 14:01:10 -070063aom_codec_err_t aom_codec_enc_init_multi_ver(
64 aom_codec_ctx_t *ctx, aom_codec_iface_t *iface, aom_codec_enc_cfg_t *cfg,
65 int num_enc, aom_codec_flags_t flags, aom_rational_t *dsf, int ver) {
66 aom_codec_err_t res = AOM_CODEC_OK;
Yaowu Xuc27fc142016-08-22 16:08:15 -070067
Yaowu Xuf883b422016-08-30 14:01:10 -070068 if (ver != AOM_ENCODER_ABI_VERSION)
69 res = AOM_CODEC_ABI_MISMATCH;
Yaowu Xuc27fc142016-08-22 16:08:15 -070070 else if (!ctx || !iface || !cfg || (num_enc > 16 || num_enc < 1))
Yaowu Xuf883b422016-08-30 14:01:10 -070071 res = AOM_CODEC_INVALID_PARAM;
72 else if (iface->abi_version != AOM_CODEC_INTERNAL_ABI_VERSION)
73 res = AOM_CODEC_ABI_MISMATCH;
74 else if (!(iface->caps & AOM_CODEC_CAP_ENCODER))
75 res = AOM_CODEC_INCAPABLE;
76 else if ((flags & AOM_CODEC_USE_PSNR) && !(iface->caps & AOM_CODEC_CAP_PSNR))
77 res = AOM_CODEC_INCAPABLE;
78 else if ((flags & AOM_CODEC_USE_OUTPUT_PARTITION) &&
79 !(iface->caps & AOM_CODEC_CAP_OUTPUT_PARTITION))
80 res = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -070081 else {
82 int i;
83 void *mem_loc = NULL;
84
85 if (!(res = iface->enc.mr_get_mem_loc(cfg, &mem_loc))) {
86 for (i = 0; i < num_enc; i++) {
Yaowu Xuf883b422016-08-30 14:01:10 -070087 aom_codec_priv_enc_mr_cfg_t mr_cfg;
Yaowu Xuc27fc142016-08-22 16:08:15 -070088
89 /* Validate down-sampling factor. */
90 if (dsf->num < 1 || dsf->num > 4096 || dsf->den < 1 ||
91 dsf->den > dsf->num) {
Yaowu Xuf883b422016-08-30 14:01:10 -070092 res = AOM_CODEC_INVALID_PARAM;
Yaowu Xuc27fc142016-08-22 16:08:15 -070093 break;
94 }
95
96 mr_cfg.mr_low_res_mode_info = mem_loc;
97 mr_cfg.mr_total_resolutions = num_enc;
98 mr_cfg.mr_encoder_id = num_enc - 1 - i;
99 mr_cfg.mr_down_sampling_factor.num = dsf->num;
100 mr_cfg.mr_down_sampling_factor.den = dsf->den;
101
102 /* Force Key-frame synchronization. Namely, encoder at higher
103 * resolution always use the same frame_type chosen by the
104 * lowest-resolution encoder.
105 */
Yaowu Xuf883b422016-08-30 14:01:10 -0700106 if (mr_cfg.mr_encoder_id) cfg->kf_mode = AOM_KF_DISABLED;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700107
108 ctx->iface = iface;
109 ctx->name = iface->name;
110 ctx->priv = NULL;
111 ctx->init_flags = flags;
112 ctx->config.enc = cfg;
113 res = ctx->iface->init(ctx, &mr_cfg);
114
115 if (res) {
116 const char *error_detail = ctx->priv ? ctx->priv->err_detail : NULL;
117 /* Destroy current ctx */
118 ctx->err_detail = error_detail;
Yaowu Xuf883b422016-08-30 14:01:10 -0700119 aom_codec_destroy(ctx);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700120
121 /* Destroy already allocated high-level ctx */
122 while (i) {
123 ctx--;
124 ctx->err_detail = error_detail;
Yaowu Xuf883b422016-08-30 14:01:10 -0700125 aom_codec_destroy(ctx);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700126 i--;
127 }
128 }
129
130 if (res) break;
131
132 ctx++;
133 cfg++;
134 dsf++;
135 }
136 ctx--;
137 }
138 }
139
140 return SAVE_STATUS(ctx, res);
141}
142
Yaowu Xuf883b422016-08-30 14:01:10 -0700143aom_codec_err_t aom_codec_enc_config_default(aom_codec_iface_t *iface,
144 aom_codec_enc_cfg_t *cfg,
Yaowu Xuc27fc142016-08-22 16:08:15 -0700145 unsigned int usage) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700146 aom_codec_err_t res;
147 aom_codec_enc_cfg_map_t *map;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700148 int i;
149
150 if (!iface || !cfg || usage > INT_MAX)
Yaowu Xuf883b422016-08-30 14:01:10 -0700151 res = AOM_CODEC_INVALID_PARAM;
152 else if (!(iface->caps & AOM_CODEC_CAP_ENCODER))
153 res = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700154 else {
Yaowu Xuf883b422016-08-30 14:01:10 -0700155 res = AOM_CODEC_INVALID_PARAM;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700156
157 for (i = 0; i < iface->enc.cfg_map_count; ++i) {
158 map = iface->enc.cfg_maps + i;
159 if (map->usage == (int)usage) {
160 *cfg = map->cfg;
161 cfg->g_usage = usage;
Yaowu Xuf883b422016-08-30 14:01:10 -0700162 res = AOM_CODEC_OK;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700163 break;
164 }
165 }
166 }
167
168 return res;
169}
170
171#if ARCH_X86 || ARCH_X86_64
172/* On X86, disable the x87 unit's internal 80 bit precision for better
173 * consistency with the SSE unit's 64 bit precision.
174 */
175#include "aom_ports/x86.h"
176#define FLOATING_POINT_INIT() \
177 do { \
178 unsigned short x87_orig_mode = x87_set_double_precision();
179#define FLOATING_POINT_RESTORE() \
180 x87_set_control_word(x87_orig_mode); \
181 } \
182 while (0)
183
184#else
185static void FLOATING_POINT_INIT() {}
186static void FLOATING_POINT_RESTORE() {}
187#endif
188
Yaowu Xuf883b422016-08-30 14:01:10 -0700189aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img,
190 aom_codec_pts_t pts, unsigned long duration,
191 aom_enc_frame_flags_t flags,
Yaowu Xuc27fc142016-08-22 16:08:15 -0700192 unsigned long deadline) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700193 aom_codec_err_t res = AOM_CODEC_OK;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700194
195 if (!ctx || (img && !duration))
Yaowu Xuf883b422016-08-30 14:01:10 -0700196 res = AOM_CODEC_INVALID_PARAM;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700197 else if (!ctx->iface || !ctx->priv)
Yaowu Xuf883b422016-08-30 14:01:10 -0700198 res = AOM_CODEC_ERROR;
199 else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
200 res = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700201 else {
202 unsigned int num_enc = ctx->priv->enc.total_encoders;
203
204 /* Execute in a normalized floating point environment, if the platform
205 * requires it.
206 */
207 FLOATING_POINT_INIT();
208
209 if (num_enc == 1)
210 res = ctx->iface->enc.encode(get_alg_priv(ctx), img, pts, duration, flags,
211 deadline);
212 else {
213 /* Multi-resolution encoding:
214 * Encode multi-levels in reverse order. For example,
215 * if mr_total_resolutions = 3, first encode level 2,
216 * then encode level 1, and finally encode level 0.
217 */
218 int i;
219
220 ctx += num_enc - 1;
221 if (img) img += num_enc - 1;
222
223 for (i = num_enc - 1; i >= 0; i--) {
224 if ((res = ctx->iface->enc.encode(get_alg_priv(ctx), img, pts, duration,
225 flags, deadline)))
226 break;
227
228 ctx--;
229 if (img) img--;
230 }
231 ctx++;
232 }
233
234 FLOATING_POINT_RESTORE();
235 }
236
237 return SAVE_STATUS(ctx, res);
238}
239
Yaowu Xuf883b422016-08-30 14:01:10 -0700240const aom_codec_cx_pkt_t *aom_codec_get_cx_data(aom_codec_ctx_t *ctx,
241 aom_codec_iter_t *iter) {
242 const aom_codec_cx_pkt_t *pkt = NULL;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700243
244 if (ctx) {
245 if (!iter)
Yaowu Xuf883b422016-08-30 14:01:10 -0700246 ctx->err = AOM_CODEC_INVALID_PARAM;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700247 else if (!ctx->iface || !ctx->priv)
Yaowu Xuf883b422016-08-30 14:01:10 -0700248 ctx->err = AOM_CODEC_ERROR;
249 else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
250 ctx->err = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700251 else
252 pkt = ctx->iface->enc.get_cx_data(get_alg_priv(ctx), iter);
253 }
254
Yaowu Xuf883b422016-08-30 14:01:10 -0700255 if (pkt && pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700256 // If the application has specified a destination area for the
257 // compressed data, and the codec has not placed the data there,
258 // and it fits, copy it.
Yaowu Xuf883b422016-08-30 14:01:10 -0700259 aom_codec_priv_t *const priv = ctx->priv;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700260 char *const dst_buf = (char *)priv->enc.cx_data_dst_buf.buf;
261
262 if (dst_buf && pkt->data.raw.buf != dst_buf &&
263 pkt->data.raw.sz + priv->enc.cx_data_pad_before +
264 priv->enc.cx_data_pad_after <=
265 priv->enc.cx_data_dst_buf.sz) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700266 aom_codec_cx_pkt_t *modified_pkt = &priv->enc.cx_data_pkt;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700267
268 memcpy(dst_buf + priv->enc.cx_data_pad_before, pkt->data.raw.buf,
269 pkt->data.raw.sz);
270 *modified_pkt = *pkt;
271 modified_pkt->data.raw.buf = dst_buf;
272 modified_pkt->data.raw.sz +=
273 priv->enc.cx_data_pad_before + priv->enc.cx_data_pad_after;
274 pkt = modified_pkt;
275 }
276
277 if (dst_buf == pkt->data.raw.buf) {
278 priv->enc.cx_data_dst_buf.buf = dst_buf + pkt->data.raw.sz;
279 priv->enc.cx_data_dst_buf.sz -= pkt->data.raw.sz;
280 }
281 }
282
283 return pkt;
284}
285
Yaowu Xuf883b422016-08-30 14:01:10 -0700286aom_codec_err_t aom_codec_set_cx_data_buf(aom_codec_ctx_t *ctx,
287 const aom_fixed_buf_t *buf,
Yaowu Xuc27fc142016-08-22 16:08:15 -0700288 unsigned int pad_before,
289 unsigned int pad_after) {
Yaowu Xuf883b422016-08-30 14:01:10 -0700290 if (!ctx || !ctx->priv) return AOM_CODEC_INVALID_PARAM;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700291
292 if (buf) {
293 ctx->priv->enc.cx_data_dst_buf = *buf;
294 ctx->priv->enc.cx_data_pad_before = pad_before;
295 ctx->priv->enc.cx_data_pad_after = pad_after;
296 } else {
297 ctx->priv->enc.cx_data_dst_buf.buf = NULL;
298 ctx->priv->enc.cx_data_dst_buf.sz = 0;
299 ctx->priv->enc.cx_data_pad_before = 0;
300 ctx->priv->enc.cx_data_pad_after = 0;
301 }
302
Yaowu Xuf883b422016-08-30 14:01:10 -0700303 return AOM_CODEC_OK;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700304}
305
Yaowu Xuf883b422016-08-30 14:01:10 -0700306const aom_image_t *aom_codec_get_preview_frame(aom_codec_ctx_t *ctx) {
307 aom_image_t *img = NULL;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700308
309 if (ctx) {
310 if (!ctx->iface || !ctx->priv)
Yaowu Xuf883b422016-08-30 14:01:10 -0700311 ctx->err = AOM_CODEC_ERROR;
312 else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
313 ctx->err = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700314 else if (!ctx->iface->enc.get_preview)
Yaowu Xuf883b422016-08-30 14:01:10 -0700315 ctx->err = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700316 else
317 img = ctx->iface->enc.get_preview(get_alg_priv(ctx));
318 }
319
320 return img;
321}
322
Yaowu Xuf883b422016-08-30 14:01:10 -0700323aom_fixed_buf_t *aom_codec_get_global_headers(aom_codec_ctx_t *ctx) {
324 aom_fixed_buf_t *buf = NULL;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700325
326 if (ctx) {
327 if (!ctx->iface || !ctx->priv)
Yaowu Xuf883b422016-08-30 14:01:10 -0700328 ctx->err = AOM_CODEC_ERROR;
329 else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
330 ctx->err = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700331 else if (!ctx->iface->enc.get_glob_hdrs)
Yaowu Xuf883b422016-08-30 14:01:10 -0700332 ctx->err = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700333 else
334 buf = ctx->iface->enc.get_glob_hdrs(get_alg_priv(ctx));
335 }
336
337 return buf;
338}
339
Yaowu Xuf883b422016-08-30 14:01:10 -0700340aom_codec_err_t aom_codec_enc_config_set(aom_codec_ctx_t *ctx,
341 const aom_codec_enc_cfg_t *cfg) {
342 aom_codec_err_t res;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700343
344 if (!ctx || !ctx->iface || !ctx->priv || !cfg)
Yaowu Xuf883b422016-08-30 14:01:10 -0700345 res = AOM_CODEC_INVALID_PARAM;
346 else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
347 res = AOM_CODEC_INCAPABLE;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700348 else
349 res = ctx->iface->enc.cfg_set(get_alg_priv(ctx), cfg);
350
351 return SAVE_STATUS(ctx, res);
352}
353
Yaowu Xuf883b422016-08-30 14:01:10 -0700354int aom_codec_pkt_list_add(struct aom_codec_pkt_list *list,
355 const struct aom_codec_cx_pkt *pkt) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700356 if (list->cnt < list->max) {
357 list->pkts[list->cnt++] = *pkt;
358 return 0;
359 }
360
361 return 1;
362}
363
Yaowu Xuf883b422016-08-30 14:01:10 -0700364const aom_codec_cx_pkt_t *aom_codec_pkt_list_get(
365 struct aom_codec_pkt_list *list, aom_codec_iter_t *iter) {
366 const aom_codec_cx_pkt_t *pkt;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700367
368 if (!(*iter)) {
369 *iter = list->pkts;
370 }
371
Yaowu Xuf883b422016-08-30 14:01:10 -0700372 pkt = (const aom_codec_cx_pkt_t *)*iter;
Yaowu Xuc27fc142016-08-22 16:08:15 -0700373
374 if ((size_t)(pkt - list->pkts) < list->cnt)
375 *iter = pkt + 1;
376 else
377 pkt = NULL;
378
379 return pkt;
380}