/work/aom/aom/src/aom_encoder.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016, Alliance for Open Media. All rights reserved |
3 | | * |
4 | | * 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. |
10 | | */ |
11 | | |
12 | | /*!\file |
13 | | * \brief Provides the high level interface to wrap encoder algorithms. |
14 | | * |
15 | | */ |
16 | | #include "config/aom_config.h" |
17 | | |
18 | | #if HAVE_FEXCEPT |
19 | | #ifndef _GNU_SOURCE |
20 | | #define _GNU_SOURCE |
21 | | #endif |
22 | | #include <fenv.h> |
23 | | #endif |
24 | | |
25 | | #include <limits.h> |
26 | | #include <string.h> |
27 | | |
28 | | #include "aom/aom_encoder.h" |
29 | | #include "aom/internal/aom_codec_internal.h" |
30 | | |
31 | 2.46k | #define SAVE_STATUS(ctx, var) (ctx ? (ctx->err = var) : var) |
32 | | |
33 | 4.11k | static aom_codec_alg_priv_t *get_alg_priv(aom_codec_ctx_t *ctx) { |
34 | 4.11k | return (aom_codec_alg_priv_t *)ctx->priv; |
35 | 4.11k | } |
36 | | |
37 | | aom_codec_err_t aom_codec_enc_init_ver(aom_codec_ctx_t *ctx, |
38 | | aom_codec_iface_t *iface, |
39 | | const aom_codec_enc_cfg_t *cfg, |
40 | 822 | aom_codec_flags_t flags, int ver) { |
41 | 822 | aom_codec_err_t res; |
42 | | |
43 | 822 | if (ver != AOM_ENCODER_ABI_VERSION) |
44 | 0 | res = AOM_CODEC_ABI_MISMATCH; |
45 | 822 | else if (!ctx || !iface || !cfg) |
46 | 0 | res = AOM_CODEC_INVALID_PARAM; |
47 | 822 | else if (iface->abi_version != AOM_CODEC_INTERNAL_ABI_VERSION) |
48 | 0 | res = AOM_CODEC_ABI_MISMATCH; |
49 | 822 | else if (!(iface->caps & AOM_CODEC_CAP_ENCODER)) |
50 | 0 | res = AOM_CODEC_INCAPABLE; |
51 | 822 | else if ((flags & AOM_CODEC_USE_PSNR) && !(iface->caps & AOM_CODEC_CAP_PSNR)) |
52 | 0 | res = AOM_CODEC_INCAPABLE; |
53 | 822 | else if (cfg->g_bit_depth > 8 && (flags & AOM_CODEC_USE_HIGHBITDEPTH) == 0) { |
54 | 0 | res = AOM_CODEC_INVALID_PARAM; |
55 | 0 | ctx->err_detail = |
56 | 0 | "High bit-depth used without the AOM_CODEC_USE_HIGHBITDEPTH flag."; |
57 | 822 | } else { |
58 | 822 | ctx->iface = iface; |
59 | 822 | ctx->name = iface->name; |
60 | 822 | ctx->priv = NULL; |
61 | 822 | ctx->init_flags = flags; |
62 | 822 | ctx->config.enc = cfg; |
63 | 822 | res = ctx->iface->init(ctx); |
64 | | |
65 | 822 | if (res) { |
66 | 0 | ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL; |
67 | 0 | aom_codec_destroy(ctx); |
68 | 0 | } |
69 | 822 | } |
70 | | |
71 | 822 | return SAVE_STATUS(ctx, res); |
72 | 822 | } |
73 | | |
74 | | aom_codec_err_t aom_codec_enc_config_default(aom_codec_iface_t *iface, |
75 | | aom_codec_enc_cfg_t *cfg, |
76 | 822 | unsigned int usage) { |
77 | 822 | aom_codec_err_t res; |
78 | 822 | int i; |
79 | | |
80 | 822 | if (!iface || !cfg) |
81 | 0 | res = AOM_CODEC_INVALID_PARAM; |
82 | 822 | else if (!(iface->caps & AOM_CODEC_CAP_ENCODER)) |
83 | 0 | res = AOM_CODEC_INCAPABLE; |
84 | 822 | else { |
85 | 822 | res = AOM_CODEC_INVALID_PARAM; |
86 | | |
87 | 2.46k | for (i = 0; i < iface->enc.cfg_count; ++i) { |
88 | 2.46k | if (iface->enc.cfgs[i].g_usage == usage) { |
89 | 822 | *cfg = iface->enc.cfgs[i]; |
90 | 822 | res = AOM_CODEC_OK; |
91 | 822 | break; |
92 | 822 | } |
93 | 2.46k | } |
94 | 822 | } |
95 | | /* default values */ |
96 | 822 | if (cfg) { |
97 | 822 | memset(&cfg->encoder_cfg, 0, sizeof(cfg->encoder_cfg)); |
98 | 822 | cfg->encoder_cfg.super_block_size = 0; // Dynamic |
99 | 822 | cfg->encoder_cfg.max_partition_size = 128; |
100 | 822 | cfg->encoder_cfg.min_partition_size = 4; |
101 | 822 | cfg->encoder_cfg.disable_trellis_quant = 3; |
102 | 822 | } |
103 | 822 | return res; |
104 | 822 | } |
105 | | |
106 | | #if ARCH_X86 || ARCH_X86_64 |
107 | | /* On X86, disable the x87 unit's internal 80 bit precision for better |
108 | | * consistency with the SSE unit's 64 bit precision. |
109 | | */ |
110 | | #include "aom_ports/x86.h" |
111 | | #define FLOATING_POINT_SET_PRECISION \ |
112 | | unsigned short x87_orig_mode = x87_set_double_precision(); |
113 | | #define FLOATING_POINT_RESTORE_PRECISION x87_set_control_word(x87_orig_mode); |
114 | | #else |
115 | | #define FLOATING_POINT_SET_PRECISION |
116 | | #define FLOATING_POINT_RESTORE_PRECISION |
117 | | #endif // ARCH_X86 || ARCH_X86_64 |
118 | | |
119 | | #if HAVE_FEXCEPT && CONFIG_DEBUG |
120 | | #define FLOATING_POINT_SET_EXCEPTIONS \ |
121 | | const int float_excepts = \ |
122 | | feenableexcept(FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW); |
123 | | #define FLOATING_POINT_RESTORE_EXCEPTIONS \ |
124 | | fedisableexcept(FE_ALL_EXCEPT); \ |
125 | | feenableexcept(float_excepts); |
126 | | #else |
127 | | #define FLOATING_POINT_SET_EXCEPTIONS |
128 | | #define FLOATING_POINT_RESTORE_EXCEPTIONS |
129 | | #endif // HAVE_FEXCEPT && CONFIG_DEBUG |
130 | | |
131 | | /* clang-format off */ |
132 | | #define FLOATING_POINT_INIT \ |
133 | 1.64k | do { \ |
134 | 1.64k | FLOATING_POINT_SET_PRECISION \ |
135 | 1.64k | FLOATING_POINT_SET_EXCEPTIONS |
136 | | |
137 | | #define FLOATING_POINT_RESTORE \ |
138 | 1.64k | FLOATING_POINT_RESTORE_EXCEPTIONS \ |
139 | 1.64k | FLOATING_POINT_RESTORE_PRECISION \ |
140 | 1.64k | } while (0); |
141 | | /* clang-format on */ |
142 | | |
143 | | aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img, |
144 | | aom_codec_pts_t pts, unsigned long duration, |
145 | 1.64k | aom_enc_frame_flags_t flags) { |
146 | 1.64k | aom_codec_err_t res = AOM_CODEC_OK; |
147 | | |
148 | 1.64k | if (!ctx || (img && !duration)) |
149 | 0 | res = AOM_CODEC_INVALID_PARAM; |
150 | 1.64k | else if (!ctx->iface || !ctx->priv) |
151 | 0 | res = AOM_CODEC_ERROR; |
152 | 1.64k | else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER)) |
153 | 0 | res = AOM_CODEC_INCAPABLE; |
154 | 1.64k | else { |
155 | | /* Execute in a normalized floating point environment, if the platform |
156 | | * requires it. |
157 | | */ |
158 | 1.64k | FLOATING_POINT_INIT |
159 | 1.64k | res = ctx->iface->enc.encode(get_alg_priv(ctx), img, pts, duration, flags); |
160 | 1.64k | FLOATING_POINT_RESTORE |
161 | 1.64k | } |
162 | | |
163 | 1.64k | return SAVE_STATUS(ctx, res); |
164 | 1.64k | } |
165 | | |
166 | | const aom_codec_cx_pkt_t *aom_codec_get_cx_data(aom_codec_ctx_t *ctx, |
167 | 2.46k | aom_codec_iter_t *iter) { |
168 | 2.46k | const aom_codec_cx_pkt_t *pkt = NULL; |
169 | | |
170 | 2.46k | if (ctx) { |
171 | 2.46k | if (!iter) |
172 | 0 | ctx->err = AOM_CODEC_INVALID_PARAM; |
173 | 2.46k | else if (!ctx->iface || !ctx->priv) |
174 | 0 | ctx->err = AOM_CODEC_ERROR; |
175 | 2.46k | else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER)) |
176 | 0 | ctx->err = AOM_CODEC_INCAPABLE; |
177 | 2.46k | else |
178 | 2.46k | pkt = ctx->iface->enc.get_cx_data(get_alg_priv(ctx), iter); |
179 | 2.46k | } |
180 | | |
181 | 2.46k | if (pkt && pkt->kind == AOM_CODEC_CX_FRAME_PKT) { |
182 | | // If the application has specified a destination area for the |
183 | | // compressed data, and the codec has not placed the data there, |
184 | | // and it fits, copy it. |
185 | 822 | aom_codec_priv_t *const priv = ctx->priv; |
186 | 822 | char *const dst_buf = (char *)priv->enc.cx_data_dst_buf.buf; |
187 | | |
188 | 822 | if (dst_buf && pkt->data.raw.buf != dst_buf && |
189 | 0 | pkt->data.raw.sz + priv->enc.cx_data_pad_before + |
190 | 0 | priv->enc.cx_data_pad_after <= |
191 | 0 | priv->enc.cx_data_dst_buf.sz) { |
192 | 0 | aom_codec_cx_pkt_t *modified_pkt = &priv->enc.cx_data_pkt; |
193 | |
|
194 | 0 | memcpy(dst_buf + priv->enc.cx_data_pad_before, pkt->data.raw.buf, |
195 | 0 | pkt->data.raw.sz); |
196 | 0 | *modified_pkt = *pkt; |
197 | 0 | modified_pkt->data.raw.buf = dst_buf; |
198 | 0 | modified_pkt->data.raw.sz += |
199 | 0 | priv->enc.cx_data_pad_before + priv->enc.cx_data_pad_after; |
200 | 0 | pkt = modified_pkt; |
201 | 0 | } |
202 | | |
203 | 822 | if (dst_buf == pkt->data.raw.buf) { |
204 | 0 | priv->enc.cx_data_dst_buf.buf = dst_buf + pkt->data.raw.sz; |
205 | 0 | priv->enc.cx_data_dst_buf.sz -= pkt->data.raw.sz; |
206 | 0 | } |
207 | 822 | } |
208 | | |
209 | 2.46k | return pkt; |
210 | 2.46k | } |
211 | | |
212 | | aom_codec_err_t aom_codec_set_cx_data_buf(aom_codec_ctx_t *ctx, |
213 | | const aom_fixed_buf_t *buf, |
214 | | unsigned int pad_before, |
215 | 0 | unsigned int pad_after) { |
216 | 0 | if (!ctx || !ctx->priv) return AOM_CODEC_INVALID_PARAM; |
217 | | |
218 | 0 | if (buf) { |
219 | 0 | ctx->priv->enc.cx_data_dst_buf = *buf; |
220 | 0 | ctx->priv->enc.cx_data_pad_before = pad_before; |
221 | 0 | ctx->priv->enc.cx_data_pad_after = pad_after; |
222 | 0 | } else { |
223 | 0 | ctx->priv->enc.cx_data_dst_buf.buf = NULL; |
224 | 0 | ctx->priv->enc.cx_data_dst_buf.sz = 0; |
225 | 0 | ctx->priv->enc.cx_data_pad_before = 0; |
226 | 0 | ctx->priv->enc.cx_data_pad_after = 0; |
227 | 0 | } |
228 | |
|
229 | 0 | return AOM_CODEC_OK; |
230 | 0 | } |
231 | | |
232 | 0 | const aom_image_t *aom_codec_get_preview_frame(aom_codec_ctx_t *ctx) { |
233 | 0 | aom_image_t *img = NULL; |
234 | |
|
235 | 0 | if (ctx) { |
236 | 0 | if (!ctx->iface || !ctx->priv) |
237 | 0 | ctx->err = AOM_CODEC_ERROR; |
238 | 0 | else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER)) |
239 | 0 | ctx->err = AOM_CODEC_INCAPABLE; |
240 | 0 | else if (!ctx->iface->enc.get_preview) |
241 | 0 | ctx->err = AOM_CODEC_INCAPABLE; |
242 | 0 | else |
243 | 0 | img = ctx->iface->enc.get_preview(get_alg_priv(ctx)); |
244 | 0 | } |
245 | |
|
246 | 0 | return img; |
247 | 0 | } |
248 | | |
249 | 0 | aom_fixed_buf_t *aom_codec_get_global_headers(aom_codec_ctx_t *ctx) { |
250 | 0 | aom_fixed_buf_t *buf = NULL; |
251 | |
|
252 | 0 | if (ctx) { |
253 | 0 | if (!ctx->iface || !ctx->priv) |
254 | 0 | ctx->err = AOM_CODEC_ERROR; |
255 | 0 | else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER)) |
256 | 0 | ctx->err = AOM_CODEC_INCAPABLE; |
257 | 0 | else if (!ctx->iface->enc.get_glob_hdrs) |
258 | 0 | ctx->err = AOM_CODEC_INCAPABLE; |
259 | 0 | else |
260 | 0 | buf = ctx->iface->enc.get_glob_hdrs(get_alg_priv(ctx)); |
261 | 0 | } |
262 | |
|
263 | 0 | return buf; |
264 | 0 | } |
265 | | |
266 | | aom_codec_err_t aom_codec_enc_config_set(aom_codec_ctx_t *ctx, |
267 | 0 | const aom_codec_enc_cfg_t *cfg) { |
268 | 0 | aom_codec_err_t res; |
269 | |
|
270 | 0 | if (!ctx || !ctx->iface || !ctx->priv || !cfg) |
271 | 0 | res = AOM_CODEC_INVALID_PARAM; |
272 | 0 | else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER)) |
273 | 0 | res = AOM_CODEC_INCAPABLE; |
274 | 0 | else |
275 | 0 | res = ctx->iface->enc.cfg_set(get_alg_priv(ctx), cfg); |
276 | |
|
277 | 0 | return SAVE_STATUS(ctx, res); |
278 | 0 | } |
279 | | |
280 | | int aom_codec_pkt_list_add(struct aom_codec_pkt_list *list, |
281 | 822 | const struct aom_codec_cx_pkt *pkt) { |
282 | 822 | if (list->cnt < list->max) { |
283 | 822 | list->pkts[list->cnt++] = *pkt; |
284 | 822 | return 0; |
285 | 822 | } |
286 | | |
287 | 0 | return 1; |
288 | 822 | } |
289 | | |
290 | | const aom_codec_cx_pkt_t *aom_codec_pkt_list_get( |
291 | 2.46k | struct aom_codec_pkt_list *list, aom_codec_iter_t *iter) { |
292 | 2.46k | const aom_codec_cx_pkt_t *pkt; |
293 | | |
294 | 2.46k | if (!(*iter)) { |
295 | 1.64k | *iter = list->pkts; |
296 | 1.64k | } |
297 | | |
298 | 2.46k | pkt = (const aom_codec_cx_pkt_t *)*iter; |
299 | | |
300 | 2.46k | if ((size_t)(pkt - list->pkts) < list->cnt) |
301 | 822 | *iter = pkt + 1; |
302 | 1.64k | else |
303 | 1.64k | pkt = NULL; |
304 | | |
305 | 2.46k | return pkt; |
306 | 2.46k | } |