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