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
23vpx_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
66vpx_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 = VPX_CODEC_OK;
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      ctx--;
153    }
154  }
155
156  return SAVE_STATUS(ctx, res);
157}
158
159
160vpx_codec_err_t  vpx_codec_enc_config_default(vpx_codec_iface_t    *iface,
161                                              vpx_codec_enc_cfg_t  *cfg,
162                                              unsigned int          usage) {
163  vpx_codec_err_t res;
164  vpx_codec_enc_cfg_map_t *map;
165
166  if (!iface || !cfg || usage > INT_MAX)
167    res = VPX_CODEC_INVALID_PARAM;
168  else if (!(iface->caps & VPX_CODEC_CAP_ENCODER))
169    res = VPX_CODEC_INCAPABLE;
170  else {
171    res = VPX_CODEC_INVALID_PARAM;
172
173    for (map = iface->enc.cfg_maps; map->usage >= 0; map++) {
174      if (map->usage == (int)usage) {
175        *cfg = map->cfg;
176        cfg->g_usage = usage;
177        res = VPX_CODEC_OK;
178        break;
179      }
180    }
181  }
182
183  return res;
184}
185
186
187#if ARCH_X86_32 || ARCH_X86_64
188/* On X86, disable the x87 unit's internal 80 bit precision for better
189 * consistency with the SSE unit's 64 bit precision.
190 */
191#include "vpx_ports/x86.h"
192#define FLOATING_POINT_INIT() do {\
193    unsigned short x87_orig_mode = x87_set_double_precision();
194#define FLOATING_POINT_RESTORE() \
195  x87_set_control_word(x87_orig_mode); }while(0)
196
197
198#else
199static void FLOATING_POINT_INIT() {}
200static void FLOATING_POINT_RESTORE() {}
201#endif
202
203
204vpx_codec_err_t  vpx_codec_encode(vpx_codec_ctx_t            *ctx,
205                                  const vpx_image_t          *img,
206                                  vpx_codec_pts_t             pts,
207                                  unsigned long               duration,
208                                  vpx_enc_frame_flags_t       flags,
209                                  unsigned long               deadline) {
210  vpx_codec_err_t res = VPX_CODEC_OK;
211
212  if (!ctx || (img && !duration))
213    res = VPX_CODEC_INVALID_PARAM;
214  else if (!ctx->iface || !ctx->priv)
215    res = VPX_CODEC_ERROR;
216  else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
217    res = VPX_CODEC_INCAPABLE;
218  else {
219    unsigned int num_enc = ctx->priv->enc.total_encoders;
220
221    /* Execute in a normalized floating point environment, if the platform
222     * requires it.
223     */
224    FLOATING_POINT_INIT();
225
226    if (num_enc == 1)
227      res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts,
228                                   duration, flags, deadline);
229    else {
230      /* Multi-resolution encoding:
231       * Encode multi-levels in reverse order. For example,
232       * if mr_total_resolutions = 3, first encode level 2,
233       * then encode level 1, and finally encode level 0.
234       */
235      int i;
236
237      ctx += num_enc - 1;
238      if (img) img += num_enc - 1;
239
240      for (i = num_enc - 1; i >= 0; i--) {
241        if ((res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts,
242                                          duration, flags, deadline)))
243          break;
244
245        ctx--;
246        if (img) img--;
247      }
248      ctx++;
249    }
250
251    FLOATING_POINT_RESTORE();
252  }
253
254  return SAVE_STATUS(ctx, res);
255}
256
257
258const vpx_codec_cx_pkt_t *vpx_codec_get_cx_data(vpx_codec_ctx_t *ctx,
259                                                vpx_codec_iter_t *iter) {
260  const vpx_codec_cx_pkt_t *pkt = NULL;
261
262  if (ctx) {
263    if (!iter)
264      ctx->err = VPX_CODEC_INVALID_PARAM;
265    else if (!ctx->iface || !ctx->priv)
266      ctx->err = VPX_CODEC_ERROR;
267    else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
268      ctx->err = VPX_CODEC_INCAPABLE;
269    else
270      pkt = ctx->iface->enc.get_cx_data(ctx->priv->alg_priv, iter);
271  }
272
273  if (pkt && pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
274    // If the application has specified a destination area for the
275    // compressed data, and the codec has not placed the data there,
276    // and it fits, copy it.
277    vpx_codec_priv_t *const priv = ctx->priv;
278    char *const dst_buf = (char *)priv->enc.cx_data_dst_buf.buf;
279
280    if (dst_buf &&
281        pkt->data.raw.buf != dst_buf &&
282        pkt->data.raw.sz + priv->enc.cx_data_pad_before +
283            priv->enc.cx_data_pad_after <= priv->enc.cx_data_dst_buf.sz) {
284      vpx_codec_cx_pkt_t *modified_pkt = &priv->enc.cx_data_pkt;
285
286      memcpy(dst_buf + priv->enc.cx_data_pad_before, pkt->data.raw.buf,
287             pkt->data.raw.sz);
288      *modified_pkt = *pkt;
289      modified_pkt->data.raw.buf = dst_buf;
290      modified_pkt->data.raw.sz += priv->enc.cx_data_pad_before +
291                                       priv->enc.cx_data_pad_after;
292      pkt = modified_pkt;
293    }
294
295    if (dst_buf == pkt->data.raw.buf) {
296      priv->enc.cx_data_dst_buf.buf = dst_buf + pkt->data.raw.sz;
297      priv->enc.cx_data_dst_buf.sz -= pkt->data.raw.sz;
298    }
299  }
300
301  return pkt;
302}
303
304
305vpx_codec_err_t vpx_codec_set_cx_data_buf(vpx_codec_ctx_t       *ctx,
306                                          const vpx_fixed_buf_t *buf,
307                                          unsigned int           pad_before,
308                                          unsigned int           pad_after) {
309  if (!ctx || !ctx->priv)
310    return VPX_CODEC_INVALID_PARAM;
311
312  if (buf) {
313    ctx->priv->enc.cx_data_dst_buf = *buf;
314    ctx->priv->enc.cx_data_pad_before = pad_before;
315    ctx->priv->enc.cx_data_pad_after = pad_after;
316  } else {
317    ctx->priv->enc.cx_data_dst_buf.buf = NULL;
318    ctx->priv->enc.cx_data_dst_buf.sz = 0;
319    ctx->priv->enc.cx_data_pad_before = 0;
320    ctx->priv->enc.cx_data_pad_after = 0;
321  }
322
323  return VPX_CODEC_OK;
324}
325
326
327const vpx_image_t *vpx_codec_get_preview_frame(vpx_codec_ctx_t   *ctx) {
328  vpx_image_t *img = NULL;
329
330  if (ctx) {
331    if (!ctx->iface || !ctx->priv)
332      ctx->err = VPX_CODEC_ERROR;
333    else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
334      ctx->err = VPX_CODEC_INCAPABLE;
335    else if (!ctx->iface->enc.get_preview)
336      ctx->err = VPX_CODEC_INCAPABLE;
337    else
338      img = ctx->iface->enc.get_preview(ctx->priv->alg_priv);
339  }
340
341  return img;
342}
343
344
345vpx_fixed_buf_t *vpx_codec_get_global_headers(vpx_codec_ctx_t   *ctx) {
346  vpx_fixed_buf_t *buf = NULL;
347
348  if (ctx) {
349    if (!ctx->iface || !ctx->priv)
350      ctx->err = VPX_CODEC_ERROR;
351    else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
352      ctx->err = VPX_CODEC_INCAPABLE;
353    else if (!ctx->iface->enc.get_glob_hdrs)
354      ctx->err = VPX_CODEC_INCAPABLE;
355    else
356      buf = ctx->iface->enc.get_glob_hdrs(ctx->priv->alg_priv);
357  }
358
359  return buf;
360}
361
362
363vpx_codec_err_t  vpx_codec_enc_config_set(vpx_codec_ctx_t            *ctx,
364                                          const vpx_codec_enc_cfg_t  *cfg) {
365  vpx_codec_err_t res;
366
367  if (!ctx || !ctx->iface || !ctx->priv || !cfg)
368    res = VPX_CODEC_INVALID_PARAM;
369  else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
370    res = VPX_CODEC_INCAPABLE;
371  else
372    res = ctx->iface->enc.cfg_set(ctx->priv->alg_priv, cfg);
373
374  return SAVE_STATUS(ctx, res);
375}
376
377
378int vpx_codec_pkt_list_add(struct vpx_codec_pkt_list *list,
379                           const struct vpx_codec_cx_pkt *pkt) {
380  if (list->cnt < list->max) {
381    list->pkts[list->cnt++] = *pkt;
382    return 0;
383  }
384
385  return 1;
386}
387
388
389const vpx_codec_cx_pkt_t *vpx_codec_pkt_list_get(struct vpx_codec_pkt_list *list,
390                                                 vpx_codec_iter_t           *iter) {
391  const vpx_codec_cx_pkt_t *pkt;
392
393  if (!(*iter)) {
394    *iter = list->pkts;
395  }
396
397  pkt = (const vpx_codec_cx_pkt_t *)*iter;
398
399  if ((size_t)(pkt - list->pkts) < list->cnt)
400    *iter = pkt + 1;
401  else
402    pkt = NULL;
403
404  return pkt;
405}
406