• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define SAVE_STATUS(ctx, var) (ctx ? (ctx->err = var) : var)
32 
get_alg_priv(aom_codec_ctx_t * ctx)33 static aom_codec_alg_priv_t *get_alg_priv(aom_codec_ctx_t *ctx) {
34   return (aom_codec_alg_priv_t *)ctx->priv;
35 }
36 
aom_codec_enc_init_ver(aom_codec_ctx_t * ctx,aom_codec_iface_t * iface,const aom_codec_enc_cfg_t * cfg,aom_codec_flags_t flags,int ver)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                                        aom_codec_flags_t flags, int ver) {
41   aom_codec_err_t res;
42   // The value of AOM_ENCODER_ABI_VERSION in libaom v3.0.0 and v3.1.0 - v3.1.3.
43   //
44   // We are compatible with these older libaom releases. AOM_ENCODER_ABI_VERSION
45   // was incremented after these releases for two reasons:
46   // 1. AOM_ENCODER_ABI_VERSION takes contribution from
47   //    AOM_EXT_PART_ABI_VERSION. The external partition API is still
48   //    experimental, so it should not be considered as part of the stable ABI.
49   //    fd9ed8366 External partition: Define APIs
50   //    https://aomedia-review.googlesource.com/c/aom/+/135663
51   // 2. As a way to detect the presence of speeds 7-9 in all-intra mode. I (wtc)
52   //    suggested this change because I misunderstood how
53   //    AOM_ENCODER_ABI_VERSION was used.
54   //    bbdfa68d1 AllIntra: Redefine all-intra mode speed features for speed 7+
55   //    https://aomedia-review.googlesource.com/c/aom/+/140624
56   const int aom_encoder_abi_version_25 = 25;
57 
58   // TODO(bug aomedia:3228): Remove the check for aom_encoder_abi_version_25 in
59   // libaom v4.0.0.
60   if (ver != AOM_ENCODER_ABI_VERSION && ver != aom_encoder_abi_version_25)
61     res = AOM_CODEC_ABI_MISMATCH;
62   else if (!ctx || !iface || !cfg)
63     res = AOM_CODEC_INVALID_PARAM;
64   else if (iface->abi_version != AOM_CODEC_INTERNAL_ABI_VERSION)
65     res = AOM_CODEC_ABI_MISMATCH;
66   else if (!(iface->caps & AOM_CODEC_CAP_ENCODER))
67     res = AOM_CODEC_INCAPABLE;
68   else if ((flags & AOM_CODEC_USE_PSNR) && !(iface->caps & AOM_CODEC_CAP_PSNR))
69     res = AOM_CODEC_INCAPABLE;
70   else if (cfg->g_bit_depth > 8 && (flags & AOM_CODEC_USE_HIGHBITDEPTH) == 0) {
71     res = AOM_CODEC_INVALID_PARAM;
72     ctx->err_detail =
73         "High bit-depth used without the AOM_CODEC_USE_HIGHBITDEPTH flag.";
74   } else {
75     ctx->iface = iface;
76     ctx->name = iface->name;
77     ctx->priv = NULL;
78     ctx->init_flags = flags;
79     ctx->config.enc = cfg;
80     res = ctx->iface->init(ctx);
81 
82     if (res) {
83       ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL;
84       aom_codec_destroy(ctx);
85     }
86   }
87 
88   return SAVE_STATUS(ctx, res);
89 }
90 
aom_codec_enc_config_default(aom_codec_iface_t * iface,aom_codec_enc_cfg_t * cfg,unsigned int usage)91 aom_codec_err_t aom_codec_enc_config_default(aom_codec_iface_t *iface,
92                                              aom_codec_enc_cfg_t *cfg,
93                                              unsigned int usage) {
94   aom_codec_err_t res;
95   int i;
96 
97   if (!iface || !cfg)
98     res = AOM_CODEC_INVALID_PARAM;
99   else if (!(iface->caps & AOM_CODEC_CAP_ENCODER))
100     res = AOM_CODEC_INCAPABLE;
101   else {
102     res = AOM_CODEC_INVALID_PARAM;
103 
104     for (i = 0; i < iface->enc.cfg_count; ++i) {
105       if (iface->enc.cfgs[i].g_usage == usage) {
106         *cfg = iface->enc.cfgs[i];
107         res = AOM_CODEC_OK;
108         break;
109       }
110     }
111   }
112   /* default values */
113   if (cfg) {
114     memset(&cfg->encoder_cfg, 0, sizeof(cfg->encoder_cfg));
115     cfg->encoder_cfg.super_block_size = 0;  // Dynamic
116     cfg->encoder_cfg.max_partition_size = 128;
117     cfg->encoder_cfg.min_partition_size = 4;
118     cfg->encoder_cfg.disable_trellis_quant = 3;
119   }
120   return res;
121 }
122 
123 #if ARCH_X86 || ARCH_X86_64
124 /* On X86, disable the x87 unit's internal 80 bit precision for better
125  * consistency with the SSE unit's 64 bit precision.
126  */
127 #include "aom_ports/x86.h"
128 #define FLOATING_POINT_SET_PRECISION \
129   unsigned short x87_orig_mode = x87_set_double_precision();
130 #define FLOATING_POINT_RESTORE_PRECISION x87_set_control_word(x87_orig_mode);
131 #else
132 #define FLOATING_POINT_SET_PRECISION
133 #define FLOATING_POINT_RESTORE_PRECISION
134 #endif  // ARCH_X86 || ARCH_X86_64
135 
136 #if HAVE_FEXCEPT && CONFIG_DEBUG
137 #define FLOATING_POINT_SET_EXCEPTIONS \
138   const int float_excepts =           \
139       feenableexcept(FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW);
140 #define FLOATING_POINT_RESTORE_EXCEPTIONS \
141   fedisableexcept(FE_ALL_EXCEPT);         \
142   feenableexcept(float_excepts);
143 #else
144 #define FLOATING_POINT_SET_EXCEPTIONS
145 #define FLOATING_POINT_RESTORE_EXCEPTIONS
146 #endif  // HAVE_FEXCEPT && CONFIG_DEBUG
147 
148 /* clang-format off */
149 #define FLOATING_POINT_INIT    \
150   do {                         \
151   FLOATING_POINT_SET_PRECISION \
152   FLOATING_POINT_SET_EXCEPTIONS
153 
154 #define FLOATING_POINT_RESTORE      \
155   FLOATING_POINT_RESTORE_EXCEPTIONS \
156   FLOATING_POINT_RESTORE_PRECISION  \
157   } while (0);
158 /* clang-format on */
159 
aom_codec_encode(aom_codec_ctx_t * ctx,const aom_image_t * img,aom_codec_pts_t pts,unsigned long duration,aom_enc_frame_flags_t flags)160 aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img,
161                                  aom_codec_pts_t pts, unsigned long duration,
162                                  aom_enc_frame_flags_t flags) {
163   aom_codec_err_t res = AOM_CODEC_OK;
164 
165   if (!ctx || (img && !duration))
166     res = AOM_CODEC_INVALID_PARAM;
167   else if (!ctx->iface || !ctx->priv)
168     res = AOM_CODEC_ERROR;
169   else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
170     res = AOM_CODEC_INCAPABLE;
171   else {
172     /* Execute in a normalized floating point environment, if the platform
173      * requires it.
174      */
175     FLOATING_POINT_INIT
176     res = ctx->iface->enc.encode(get_alg_priv(ctx), img, pts, duration, flags);
177     FLOATING_POINT_RESTORE
178   }
179 
180   return SAVE_STATUS(ctx, res);
181 }
182 
aom_codec_get_cx_data(aom_codec_ctx_t * ctx,aom_codec_iter_t * iter)183 const aom_codec_cx_pkt_t *aom_codec_get_cx_data(aom_codec_ctx_t *ctx,
184                                                 aom_codec_iter_t *iter) {
185   const aom_codec_cx_pkt_t *pkt = NULL;
186 
187   if (ctx) {
188     if (!iter)
189       ctx->err = AOM_CODEC_INVALID_PARAM;
190     else if (!ctx->iface || !ctx->priv)
191       ctx->err = AOM_CODEC_ERROR;
192     else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
193       ctx->err = AOM_CODEC_INCAPABLE;
194     else
195       pkt = ctx->iface->enc.get_cx_data(get_alg_priv(ctx), iter);
196   }
197 
198   if (pkt && pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
199     // If the application has specified a destination area for the
200     // compressed data, and the codec has not placed the data there,
201     // and it fits, copy it.
202     aom_codec_priv_t *const priv = ctx->priv;
203     char *const dst_buf = (char *)priv->enc.cx_data_dst_buf.buf;
204 
205     if (dst_buf && pkt->data.raw.buf != dst_buf &&
206         pkt->data.raw.sz + priv->enc.cx_data_pad_before +
207                 priv->enc.cx_data_pad_after <=
208             priv->enc.cx_data_dst_buf.sz) {
209       aom_codec_cx_pkt_t *modified_pkt = &priv->enc.cx_data_pkt;
210 
211       memcpy(dst_buf + priv->enc.cx_data_pad_before, pkt->data.raw.buf,
212              pkt->data.raw.sz);
213       *modified_pkt = *pkt;
214       modified_pkt->data.raw.buf = dst_buf;
215       modified_pkt->data.raw.sz +=
216           priv->enc.cx_data_pad_before + priv->enc.cx_data_pad_after;
217       pkt = modified_pkt;
218     }
219 
220     if (dst_buf == pkt->data.raw.buf) {
221       priv->enc.cx_data_dst_buf.buf = dst_buf + pkt->data.raw.sz;
222       priv->enc.cx_data_dst_buf.sz -= pkt->data.raw.sz;
223     }
224   }
225 
226   return pkt;
227 }
228 
aom_codec_set_cx_data_buf(aom_codec_ctx_t * ctx,const aom_fixed_buf_t * buf,unsigned int pad_before,unsigned int pad_after)229 aom_codec_err_t aom_codec_set_cx_data_buf(aom_codec_ctx_t *ctx,
230                                           const aom_fixed_buf_t *buf,
231                                           unsigned int pad_before,
232                                           unsigned int pad_after) {
233   if (!ctx || !ctx->priv) return AOM_CODEC_INVALID_PARAM;
234 
235   if (buf) {
236     ctx->priv->enc.cx_data_dst_buf = *buf;
237     ctx->priv->enc.cx_data_pad_before = pad_before;
238     ctx->priv->enc.cx_data_pad_after = pad_after;
239   } else {
240     ctx->priv->enc.cx_data_dst_buf.buf = NULL;
241     ctx->priv->enc.cx_data_dst_buf.sz = 0;
242     ctx->priv->enc.cx_data_pad_before = 0;
243     ctx->priv->enc.cx_data_pad_after = 0;
244   }
245 
246   return AOM_CODEC_OK;
247 }
248 
aom_codec_get_preview_frame(aom_codec_ctx_t * ctx)249 const aom_image_t *aom_codec_get_preview_frame(aom_codec_ctx_t *ctx) {
250   aom_image_t *img = NULL;
251 
252   if (ctx) {
253     if (!ctx->iface || !ctx->priv)
254       ctx->err = AOM_CODEC_ERROR;
255     else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
256       ctx->err = AOM_CODEC_INCAPABLE;
257     else if (!ctx->iface->enc.get_preview)
258       ctx->err = AOM_CODEC_INCAPABLE;
259     else
260       img = ctx->iface->enc.get_preview(get_alg_priv(ctx));
261   }
262 
263   return img;
264 }
265 
aom_codec_get_global_headers(aom_codec_ctx_t * ctx)266 aom_fixed_buf_t *aom_codec_get_global_headers(aom_codec_ctx_t *ctx) {
267   aom_fixed_buf_t *buf = NULL;
268 
269   if (ctx) {
270     if (!ctx->iface || !ctx->priv)
271       ctx->err = AOM_CODEC_ERROR;
272     else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
273       ctx->err = AOM_CODEC_INCAPABLE;
274     else if (!ctx->iface->enc.get_glob_hdrs)
275       ctx->err = AOM_CODEC_INCAPABLE;
276     else
277       buf = ctx->iface->enc.get_glob_hdrs(get_alg_priv(ctx));
278   }
279 
280   return buf;
281 }
282 
aom_codec_enc_config_set(aom_codec_ctx_t * ctx,const aom_codec_enc_cfg_t * cfg)283 aom_codec_err_t aom_codec_enc_config_set(aom_codec_ctx_t *ctx,
284                                          const aom_codec_enc_cfg_t *cfg) {
285   aom_codec_err_t res;
286 
287   if (!ctx || !ctx->iface || !ctx->priv || !cfg)
288     res = AOM_CODEC_INVALID_PARAM;
289   else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
290     res = AOM_CODEC_INCAPABLE;
291   else
292     res = ctx->iface->enc.cfg_set(get_alg_priv(ctx), cfg);
293 
294   return SAVE_STATUS(ctx, res);
295 }
296 
aom_codec_pkt_list_add(struct aom_codec_pkt_list * list,const struct aom_codec_cx_pkt * pkt)297 int aom_codec_pkt_list_add(struct aom_codec_pkt_list *list,
298                            const struct aom_codec_cx_pkt *pkt) {
299   if (list->cnt < list->max) {
300     list->pkts[list->cnt++] = *pkt;
301     return 0;
302   }
303 
304   return 1;
305 }
306 
aom_codec_pkt_list_get(struct aom_codec_pkt_list * list,aom_codec_iter_t * iter)307 const aom_codec_cx_pkt_t *aom_codec_pkt_list_get(
308     struct aom_codec_pkt_list *list, aom_codec_iter_t *iter) {
309   const aom_codec_cx_pkt_t *pkt;
310 
311   if (!(*iter)) {
312     *iter = list->pkts;
313   }
314 
315   pkt = (const aom_codec_cx_pkt_t *)*iter;
316 
317   if ((size_t)(pkt - list->pkts) < list->cnt)
318     *iter = pkt + 1;
319   else
320     pkt = NULL;
321 
322   return pkt;
323 }
324