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