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