Home | History | Annotate | Download | only in src
      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 
     23 vpx_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 {
     29     vpx_codec_err_t res;
     30 
     31     if (ver != VPX_ENCODER_ABI_VERSION)
     32         res = VPX_CODEC_ABI_MISMATCH;
     33     else if (!ctx || !iface || !cfg)
     34         res = VPX_CODEC_INVALID_PARAM;
     35     else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION)
     36         res = VPX_CODEC_ABI_MISMATCH;
     37     else if (!(iface->caps & VPX_CODEC_CAP_ENCODER))
     38         res = VPX_CODEC_INCAPABLE;
     39     else if ((flags & VPX_CODEC_USE_XMA) && !(iface->caps & VPX_CODEC_CAP_XMA))
     40         res = VPX_CODEC_INCAPABLE;
     41     else if ((flags & VPX_CODEC_USE_PSNR)
     42              && !(iface->caps & VPX_CODEC_CAP_PSNR))
     43         res = VPX_CODEC_INCAPABLE;
     44     else if ((flags & VPX_CODEC_USE_OUTPUT_PARTITION)
     45              && !(iface->caps & VPX_CODEC_CAP_OUTPUT_PARTITION))
     46         res = VPX_CODEC_INCAPABLE;
     47     else
     48     {
     49         ctx->iface = iface;
     50         ctx->name = iface->name;
     51         ctx->priv = NULL;
     52         ctx->init_flags = flags;
     53         ctx->config.enc = cfg;
     54         res = ctx->iface->init(ctx, NULL);
     55 
     56         if (res)
     57         {
     58             ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL;
     59             vpx_codec_destroy(ctx);
     60         }
     61 
     62         if (ctx->priv)
     63             ctx->priv->iface = ctx->iface;
     64     }
     65 
     66     return SAVE_STATUS(ctx, res);
     67 }
     68 
     69 vpx_codec_err_t vpx_codec_enc_init_multi_ver(vpx_codec_ctx_t      *ctx,
     70                                              vpx_codec_iface_t    *iface,
     71                                              vpx_codec_enc_cfg_t  *cfg,
     72                                              int                   num_enc,
     73                                              vpx_codec_flags_t     flags,
     74                                              vpx_rational_t       *dsf,
     75                                              int                   ver)
     76 {
     77     vpx_codec_err_t res = 0;
     78 
     79     if (ver != VPX_ENCODER_ABI_VERSION)
     80         res = VPX_CODEC_ABI_MISMATCH;
     81     else if (!ctx || !iface || !cfg || (num_enc > 16 || num_enc < 1))
     82         res = VPX_CODEC_INVALID_PARAM;
     83     else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION)
     84         res = VPX_CODEC_ABI_MISMATCH;
     85     else if (!(iface->caps & VPX_CODEC_CAP_ENCODER))
     86         res = VPX_CODEC_INCAPABLE;
     87     else if ((flags & VPX_CODEC_USE_XMA) && !(iface->caps & VPX_CODEC_CAP_XMA))
     88         res = VPX_CODEC_INCAPABLE;
     89     else if ((flags & VPX_CODEC_USE_PSNR)
     90              && !(iface->caps & VPX_CODEC_CAP_PSNR))
     91         res = VPX_CODEC_INCAPABLE;
     92     else if ((flags & VPX_CODEC_USE_OUTPUT_PARTITION)
     93              && !(iface->caps & VPX_CODEC_CAP_OUTPUT_PARTITION))
     94         res = VPX_CODEC_INCAPABLE;
     95     else
     96     {
     97         int i;
     98         void *mem_loc = NULL;
     99 
    100         if(!(res = iface->enc.mr_get_mem_loc(cfg, &mem_loc)))
    101         {
    102             for (i = 0; i < num_enc; i++)
    103             {
    104                 vpx_codec_priv_enc_mr_cfg_t mr_cfg;
    105 
    106                 /* Validate down-sampling factor. */
    107                 if(dsf->num < 1 || dsf->num > 4096 || dsf->den < 1 ||
    108                    dsf->den > dsf->num)
    109                 {
    110                     res = VPX_CODEC_INVALID_PARAM;
    111                     break;
    112                 }
    113 
    114                 mr_cfg.mr_low_res_mode_info = mem_loc;
    115                 mr_cfg.mr_total_resolutions = num_enc;
    116                 mr_cfg.mr_encoder_id = num_enc-1-i;
    117                 mr_cfg.mr_down_sampling_factor.num = dsf->num;
    118                 mr_cfg.mr_down_sampling_factor.den = dsf->den;
    119 
    120                 /* Force Key-frame synchronization. Namely, encoder at higher
    121                  * resolution always use the same frame_type chosen by the
    122                  * lowest-resolution encoder.
    123                  */
    124                 if(mr_cfg.mr_encoder_id)
    125                     cfg->kf_mode = VPX_KF_DISABLED;
    126 
    127                 ctx->iface = iface;
    128                 ctx->name = iface->name;
    129                 ctx->priv = NULL;
    130                 ctx->init_flags = flags;
    131                 ctx->config.enc = cfg;
    132                 res = ctx->iface->init(ctx, &mr_cfg);
    133 
    134                 if (res)
    135                 {
    136                     const char *error_detail =
    137                         ctx->priv ? ctx->priv->err_detail : NULL;
    138                     /* Destroy current ctx */
    139                     ctx->err_detail = error_detail;
    140                     vpx_codec_destroy(ctx);
    141 
    142                     /* Destroy already allocated high-level ctx */
    143                     while (i)
    144                     {
    145                         ctx--;
    146                         ctx->err_detail = error_detail;
    147                         vpx_codec_destroy(ctx);
    148                         i--;
    149                     }
    150                 }
    151 
    152                 if (ctx->priv)
    153                     ctx->priv->iface = ctx->iface;
    154 
    155                 if (res)
    156                     break;
    157 
    158                 ctx++;
    159                 cfg++;
    160                 dsf++;
    161             }
    162         }
    163     }
    164 
    165     return SAVE_STATUS(ctx, res);
    166 }
    167 
    168 
    169 vpx_codec_err_t  vpx_codec_enc_config_default(vpx_codec_iface_t    *iface,
    170         vpx_codec_enc_cfg_t  *cfg,
    171         unsigned int          usage)
    172 {
    173     vpx_codec_err_t res;
    174     vpx_codec_enc_cfg_map_t *map;
    175 
    176     if (!iface || !cfg || usage > INT_MAX)
    177         res = VPX_CODEC_INVALID_PARAM;
    178     else if (!(iface->caps & VPX_CODEC_CAP_ENCODER))
    179         res = VPX_CODEC_INCAPABLE;
    180     else
    181     {
    182         res = VPX_CODEC_INVALID_PARAM;
    183 
    184         for (map = iface->enc.cfg_maps; map->usage >= 0; map++)
    185         {
    186             if (map->usage == (int)usage)
    187             {
    188                 *cfg = map->cfg;
    189                 cfg->g_usage = usage;
    190                 res = VPX_CODEC_OK;
    191                 break;
    192             }
    193         }
    194     }
    195 
    196     return res;
    197 }
    198 
    199 
    200 #if ARCH_X86 || ARCH_X86_64
    201 /* On X86, disable the x87 unit's internal 80 bit precision for better
    202  * consistency with the SSE unit's 64 bit precision.
    203  */
    204 #include "vpx_ports/x86.h"
    205 #define FLOATING_POINT_INIT() do {\
    206         unsigned short x87_orig_mode = x87_set_double_precision();
    207 #define FLOATING_POINT_RESTORE() \
    208     x87_set_control_word(x87_orig_mode); }while(0)
    209 
    210 
    211 #else
    212 static void FLOATING_POINT_INIT() {}
    213 static void FLOATING_POINT_RESTORE() {}
    214 #endif
    215 
    216 
    217 vpx_codec_err_t  vpx_codec_encode(vpx_codec_ctx_t            *ctx,
    218                                   const vpx_image_t          *img,
    219                                   vpx_codec_pts_t             pts,
    220                                   unsigned long               duration,
    221                                   vpx_enc_frame_flags_t       flags,
    222                                   unsigned long               deadline)
    223 {
    224     vpx_codec_err_t res = 0;
    225 
    226     if (!ctx || (img && !duration))
    227         res = VPX_CODEC_INVALID_PARAM;
    228     else if (!ctx->iface || !ctx->priv)
    229         res = VPX_CODEC_ERROR;
    230     else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
    231         res = VPX_CODEC_INCAPABLE;
    232     else
    233     {
    234         /* Execute in a normalized floating point environment, if the platform
    235          * requires it.
    236          */
    237         unsigned int num_enc =ctx->priv->enc.total_encoders;
    238 
    239         FLOATING_POINT_INIT();
    240 
    241         if (num_enc == 1)
    242             res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts,
    243                                          duration, flags, deadline);
    244         else
    245         {
    246             /* Multi-resolution encoding:
    247              * Encode multi-levels in reverse order. For example,
    248              * if mr_total_resolutions = 3, first encode level 2,
    249              * then encode level 1, and finally encode level 0.
    250              */
    251             int i;
    252 
    253             ctx += num_enc - 1;
    254             if (img) img += num_enc - 1;
    255 
    256             for (i = num_enc-1; i >= 0; i--)
    257             {
    258                 if ((res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts,
    259                                                   duration, flags, deadline)))
    260                     break;
    261 
    262                 ctx--;
    263                 if (img) img--;
    264             }
    265             ctx++;
    266         }
    267 
    268         FLOATING_POINT_RESTORE();
    269     }
    270 
    271     return SAVE_STATUS(ctx, res);
    272 }
    273 
    274 
    275 const vpx_codec_cx_pkt_t *vpx_codec_get_cx_data(vpx_codec_ctx_t   *ctx,
    276         vpx_codec_iter_t  *iter)
    277 {
    278     const vpx_codec_cx_pkt_t *pkt = NULL;
    279 
    280     if (ctx)
    281     {
    282         if (!iter)
    283             ctx->err = VPX_CODEC_INVALID_PARAM;
    284         else if (!ctx->iface || !ctx->priv)
    285             ctx->err = VPX_CODEC_ERROR;
    286         else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
    287             ctx->err = VPX_CODEC_INCAPABLE;
    288         else
    289             pkt = ctx->iface->enc.get_cx_data(ctx->priv->alg_priv, iter);
    290     }
    291 
    292     if (pkt && pkt->kind == VPX_CODEC_CX_FRAME_PKT)
    293     {
    294         /* If the application has specified a destination area for the
    295          * compressed data, and the codec has not placed the data there,
    296          * and it fits, copy it.
    297          */
    298         char *dst_buf = ctx->priv->enc.cx_data_dst_buf.buf;
    299 
    300         if (dst_buf
    301             && pkt->data.raw.buf != dst_buf
    302             && pkt->data.raw.sz
    303             + ctx->priv->enc.cx_data_pad_before
    304             + ctx->priv->enc.cx_data_pad_after
    305             <= ctx->priv->enc.cx_data_dst_buf.sz)
    306         {
    307             vpx_codec_cx_pkt_t *modified_pkt = &ctx->priv->enc.cx_data_pkt;
    308 
    309             memcpy(dst_buf + ctx->priv->enc.cx_data_pad_before,
    310                    pkt->data.raw.buf, pkt->data.raw.sz);
    311             *modified_pkt = *pkt;
    312             modified_pkt->data.raw.buf = dst_buf;
    313             modified_pkt->data.raw.sz += ctx->priv->enc.cx_data_pad_before
    314                                          + ctx->priv->enc.cx_data_pad_after;
    315             pkt = modified_pkt;
    316         }
    317 
    318         if (dst_buf == pkt->data.raw.buf)
    319         {
    320             ctx->priv->enc.cx_data_dst_buf.buf = dst_buf + pkt->data.raw.sz;
    321             ctx->priv->enc.cx_data_dst_buf.sz -= pkt->data.raw.sz;
    322         }
    323     }
    324 
    325     return pkt;
    326 }
    327 
    328 
    329 vpx_codec_err_t vpx_codec_set_cx_data_buf(vpx_codec_ctx_t       *ctx,
    330         const vpx_fixed_buf_t *buf,
    331         unsigned int           pad_before,
    332         unsigned int           pad_after)
    333 {
    334     if (!ctx || !ctx->priv)
    335         return VPX_CODEC_INVALID_PARAM;
    336 
    337     if (buf)
    338     {
    339         ctx->priv->enc.cx_data_dst_buf = *buf;
    340         ctx->priv->enc.cx_data_pad_before = pad_before;
    341         ctx->priv->enc.cx_data_pad_after = pad_after;
    342     }
    343     else
    344     {
    345         ctx->priv->enc.cx_data_dst_buf.buf = NULL;
    346         ctx->priv->enc.cx_data_dst_buf.sz = 0;
    347         ctx->priv->enc.cx_data_pad_before = 0;
    348         ctx->priv->enc.cx_data_pad_after = 0;
    349     }
    350 
    351     return VPX_CODEC_OK;
    352 }
    353 
    354 
    355 const vpx_image_t *vpx_codec_get_preview_frame(vpx_codec_ctx_t   *ctx)
    356 {
    357     vpx_image_t *img = NULL;
    358 
    359     if (ctx)
    360     {
    361         if (!ctx->iface || !ctx->priv)
    362             ctx->err = VPX_CODEC_ERROR;
    363         else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
    364             ctx->err = VPX_CODEC_INCAPABLE;
    365         else if (!ctx->iface->enc.get_preview)
    366             ctx->err = VPX_CODEC_INCAPABLE;
    367         else
    368             img = ctx->iface->enc.get_preview(ctx->priv->alg_priv);
    369     }
    370 
    371     return img;
    372 }
    373 
    374 
    375 vpx_fixed_buf_t *vpx_codec_get_global_headers(vpx_codec_ctx_t   *ctx)
    376 {
    377     vpx_fixed_buf_t *buf = NULL;
    378 
    379     if (ctx)
    380     {
    381         if (!ctx->iface || !ctx->priv)
    382             ctx->err = VPX_CODEC_ERROR;
    383         else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
    384             ctx->err = VPX_CODEC_INCAPABLE;
    385         else if (!ctx->iface->enc.get_glob_hdrs)
    386             ctx->err = VPX_CODEC_INCAPABLE;
    387         else
    388             buf = ctx->iface->enc.get_glob_hdrs(ctx->priv->alg_priv);
    389     }
    390 
    391     return buf;
    392 }
    393 
    394 
    395 vpx_codec_err_t  vpx_codec_enc_config_set(vpx_codec_ctx_t            *ctx,
    396         const vpx_codec_enc_cfg_t  *cfg)
    397 {
    398     vpx_codec_err_t res;
    399 
    400     if (!ctx || !ctx->iface || !ctx->priv || !cfg)
    401         res = VPX_CODEC_INVALID_PARAM;
    402     else if (!(ctx->iface->caps & VPX_CODEC_CAP_ENCODER))
    403         res = VPX_CODEC_INCAPABLE;
    404     else
    405         res = ctx->iface->enc.cfg_set(ctx->priv->alg_priv, cfg);
    406 
    407     return SAVE_STATUS(ctx, res);
    408 }
    409 
    410 
    411 int vpx_codec_pkt_list_add(struct vpx_codec_pkt_list *list,
    412                            const struct vpx_codec_cx_pkt *pkt)
    413 {
    414     if (list->cnt < list->max)
    415     {
    416         list->pkts[list->cnt++] = *pkt;
    417         return 0;
    418     }
    419 
    420     return 1;
    421 }
    422 
    423 
    424 const vpx_codec_cx_pkt_t *vpx_codec_pkt_list_get(struct vpx_codec_pkt_list *list,
    425         vpx_codec_iter_t           *iter)
    426 {
    427     const vpx_codec_cx_pkt_t *pkt;
    428 
    429     if (!(*iter))
    430     {
    431         *iter = list->pkts;
    432     }
    433 
    434     pkt = (const void *) * iter;
    435 
    436     if ((size_t)(pkt - list->pkts) < list->cnt)
    437         *iter = pkt + 1;
    438     else
    439         pkt = NULL;
    440 
    441     return pkt;
    442 }
    443