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