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
20#define SAVE_STATUS(ctx,var) (ctx?(ctx->err = var):var)
21
22vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t      *ctx,
23                                       vpx_codec_iface_t    *iface,
24                                       vpx_codec_enc_cfg_t  *cfg,
25                                       vpx_codec_flags_t     flags,
26                                       int                   ver)
27{
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
44    {
45        ctx->iface = iface;
46        ctx->name = iface->name;
47        ctx->priv = NULL;
48        ctx->init_flags = flags;
49        ctx->config.enc = cfg;
50        res = ctx->iface->init(ctx);
51
52        if (res)
53        {
54            ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL;
55            vpx_codec_destroy(ctx);
56        }
57
58        if (ctx->priv)
59            ctx->priv->iface = ctx->iface;
60    }
61
62    return SAVE_STATUS(ctx, res);
63}
64
65
66
67vpx_codec_err_t  vpx_codec_enc_config_default(vpx_codec_iface_t    *iface,
68        vpx_codec_enc_cfg_t  *cfg,
69        unsigned int          usage)
70{
71    vpx_codec_err_t res;
72    vpx_codec_enc_cfg_map_t *map;
73
74    if (!iface || !cfg || usage > INT_MAX)
75        res = VPX_CODEC_INVALID_PARAM;
76    else if (!(iface->caps & VPX_CODEC_CAP_ENCODER))
77        res = VPX_CODEC_INCAPABLE;
78    else
79    {
80        res = VPX_CODEC_INVALID_PARAM;
81
82        for (map = iface->enc.cfg_maps; map->usage >= 0; map++)
83        {
84            if (map->usage == (int)usage)
85            {
86                *cfg = map->cfg;
87                cfg->g_usage = usage;
88                res = VPX_CODEC_OK;
89                break;
90            }
91        }
92    }
93
94    return res;
95}
96
97
98#if ARCH_X86 || ARCH_X86_64
99/* On X86, disable the x87 unit's internal 80 bit precision for better
100 * consistency with the SSE unit's 64 bit precision.
101 */
102#include "vpx_ports/x86.h"
103#define FLOATING_POINT_INIT() do {\
104        unsigned short x87_orig_mode = x87_set_double_precision();
105#define FLOATING_POINT_RESTORE() \
106    x87_set_control_word(x87_orig_mode); }while(0)
107
108
109#else
110static void FLOATING_POINT_INIT() {}
111static void FLOATING_POINT_RESTORE() {}
112#endif
113
114
115vpx_codec_err_t  vpx_codec_encode(vpx_codec_ctx_t            *ctx,
116                                  const vpx_image_t          *img,
117                                  vpx_codec_pts_t             pts,
118                                  unsigned long               duration,
119                                  vpx_enc_frame_flags_t       flags,
120                                  unsigned long               deadline)
121{
122    vpx_codec_err_t res;
123
124    if (!ctx || (img && !duration))
125        res = VPX_CODEC_INVALID_PARAM;
126    else if (!ctx->iface || !ctx->priv)
127        res = VPX_CODEC_ERROR;
128    else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
129        res = VPX_CODEC_INCAPABLE;
130    else
131    {
132        /* Execute in a normalized floating point environment, if the platform
133         * requires it.
134         */
135        FLOATING_POINT_INIT();
136        res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts,
137                                     duration, flags, deadline);
138        FLOATING_POINT_RESTORE();
139    }
140
141    return SAVE_STATUS(ctx, res);
142}
143
144
145const vpx_codec_cx_pkt_t *vpx_codec_get_cx_data(vpx_codec_ctx_t   *ctx,
146        vpx_codec_iter_t  *iter)
147{
148    const vpx_codec_cx_pkt_t *pkt = NULL;
149
150    if (ctx)
151    {
152        if (!iter)
153            ctx->err = VPX_CODEC_INVALID_PARAM;
154        else if (!ctx->iface || !ctx->priv)
155            ctx->err = VPX_CODEC_ERROR;
156        else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
157            ctx->err = VPX_CODEC_INCAPABLE;
158        else
159            pkt = ctx->iface->enc.get_cx_data(ctx->priv->alg_priv, iter);
160    }
161
162    if (pkt && pkt->kind == VPX_CODEC_CX_FRAME_PKT)
163    {
164        /* If the application has specified a destination area for the
165         * compressed data, and the codec has not placed the data there,
166         * and it fits, copy it.
167         */
168        char *dst_buf = ctx->priv->enc.cx_data_dst_buf.buf;
169
170        if (dst_buf
171            && pkt->data.raw.buf != dst_buf
172            && pkt->data.raw.sz
173            + ctx->priv->enc.cx_data_pad_before
174            + ctx->priv->enc.cx_data_pad_after
175            <= ctx->priv->enc.cx_data_dst_buf.sz)
176        {
177            vpx_codec_cx_pkt_t *modified_pkt = &ctx->priv->enc.cx_data_pkt;
178
179            memcpy(dst_buf + ctx->priv->enc.cx_data_pad_before,
180                   pkt->data.raw.buf, pkt->data.raw.sz);
181            *modified_pkt = *pkt;
182            modified_pkt->data.raw.buf = dst_buf;
183            modified_pkt->data.raw.sz += ctx->priv->enc.cx_data_pad_before
184                                         + ctx->priv->enc.cx_data_pad_after;
185            pkt = modified_pkt;
186        }
187
188        if (dst_buf == pkt->data.raw.buf)
189        {
190            ctx->priv->enc.cx_data_dst_buf.buf = dst_buf + pkt->data.raw.sz;
191            ctx->priv->enc.cx_data_dst_buf.sz -= pkt->data.raw.sz;
192        }
193    }
194
195    return pkt;
196}
197
198
199vpx_codec_err_t vpx_codec_set_cx_data_buf(vpx_codec_ctx_t       *ctx,
200        const vpx_fixed_buf_t *buf,
201        unsigned int           pad_before,
202        unsigned int           pad_after)
203{
204    if (!ctx || !ctx->priv)
205        return VPX_CODEC_INVALID_PARAM;
206
207    if (buf)
208    {
209        ctx->priv->enc.cx_data_dst_buf = *buf;
210        ctx->priv->enc.cx_data_pad_before = pad_before;
211        ctx->priv->enc.cx_data_pad_after = pad_after;
212    }
213    else
214    {
215        ctx->priv->enc.cx_data_dst_buf.buf = NULL;
216        ctx->priv->enc.cx_data_dst_buf.sz = 0;
217        ctx->priv->enc.cx_data_pad_before = 0;
218        ctx->priv->enc.cx_data_pad_after = 0;
219    }
220
221    return VPX_CODEC_OK;
222}
223
224
225const vpx_image_t *vpx_codec_get_preview_frame(vpx_codec_ctx_t   *ctx)
226{
227    vpx_image_t *img = NULL;
228
229    if (ctx)
230    {
231        if (!ctx->iface || !ctx->priv)
232            ctx->err = VPX_CODEC_ERROR;
233        else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
234            ctx->err = VPX_CODEC_INCAPABLE;
235        else if (!ctx->iface->enc.get_preview)
236            ctx->err = VPX_CODEC_INCAPABLE;
237        else
238            img = ctx->iface->enc.get_preview(ctx->priv->alg_priv);
239    }
240
241    return img;
242}
243
244
245vpx_fixed_buf_t *vpx_codec_get_global_headers(vpx_codec_ctx_t   *ctx)
246{
247    vpx_fixed_buf_t *buf = NULL;
248
249    if (ctx)
250    {
251        if (!ctx->iface || !ctx->priv)
252            ctx->err = VPX_CODEC_ERROR;
253        else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
254            ctx->err = VPX_CODEC_INCAPABLE;
255        else if (!ctx->iface->enc.get_glob_hdrs)
256            ctx->err = VPX_CODEC_INCAPABLE;
257        else
258            buf = ctx->iface->enc.get_glob_hdrs(ctx->priv->alg_priv);
259    }
260
261    return buf;
262}
263
264
265vpx_codec_err_t  vpx_codec_enc_config_set(vpx_codec_ctx_t            *ctx,
266        const vpx_codec_enc_cfg_t  *cfg)
267{
268    vpx_codec_err_t res;
269
270    if (!ctx || !ctx->iface || !ctx->priv || !cfg)
271        res = VPX_CODEC_INVALID_PARAM;
272    else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
273        res = VPX_CODEC_INCAPABLE;
274    else
275        res = ctx->iface->enc.cfg_set(ctx->priv->alg_priv, cfg);
276
277    return SAVE_STATUS(ctx, res);
278}
279
280
281int vpx_codec_pkt_list_add(struct vpx_codec_pkt_list *list,
282                           const struct vpx_codec_cx_pkt *pkt)
283{
284    if (list->cnt < list->max)
285    {
286        list->pkts[list->cnt++] = *pkt;
287        return 0;
288    }
289
290    return 1;
291}
292
293
294const vpx_codec_cx_pkt_t *vpx_codec_pkt_list_get(struct vpx_codec_pkt_list *list,
295        vpx_codec_iter_t           *iter)
296{
297    const vpx_codec_cx_pkt_t *pkt;
298
299    if (!(*iter))
300    {
301        *iter = list->pkts;
302    }
303
304    pkt = (const void *) * iter;
305
306    if ((size_t)(pkt - list->pkts) < list->cnt)
307        *iter = pkt + 1;
308    else
309        pkt = NULL;
310
311    return pkt;
312}
313