media/libvpx/vpx/src/vpx_encoder.c

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial