Thu, 15 Jan 2015 15:59:08 +0100
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 | #include <stdlib.h> |
michael@0 | 13 | #include <string.h> |
michael@0 | 14 | #include "vpx/vpx_decoder.h" |
michael@0 | 15 | #include "vpx/vp8dx.h" |
michael@0 | 16 | #include "vpx/internal/vpx_codec_internal.h" |
michael@0 | 17 | #include "./vpx_version.h" |
michael@0 | 18 | #include "vp9/decoder/vp9_onyxd.h" |
michael@0 | 19 | #include "vp9/decoder/vp9_onyxd_int.h" |
michael@0 | 20 | #include "vp9/decoder/vp9_read_bit_buffer.h" |
michael@0 | 21 | #include "vp9/vp9_iface_common.h" |
michael@0 | 22 | |
michael@0 | 23 | #define VP9_CAP_POSTPROC (CONFIG_VP9_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0) |
michael@0 | 24 | typedef vpx_codec_stream_info_t vp9_stream_info_t; |
michael@0 | 25 | |
michael@0 | 26 | /* Structures for handling memory allocations */ |
michael@0 | 27 | typedef enum { |
michael@0 | 28 | VP9_SEG_ALG_PRIV = 256, |
michael@0 | 29 | VP9_SEG_MAX |
michael@0 | 30 | } mem_seg_id_t; |
michael@0 | 31 | #define NELEMENTS(x) ((int)(sizeof(x)/sizeof(x[0]))) |
michael@0 | 32 | |
michael@0 | 33 | static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si, |
michael@0 | 34 | vpx_codec_flags_t flags); |
michael@0 | 35 | |
michael@0 | 36 | static const mem_req_t vp9_mem_req_segs[] = { |
michael@0 | 37 | {VP9_SEG_ALG_PRIV, 0, 8, VPX_CODEC_MEM_ZERO, priv_sz}, |
michael@0 | 38 | {VP9_SEG_MAX, 0, 0, 0, NULL} |
michael@0 | 39 | }; |
michael@0 | 40 | |
michael@0 | 41 | struct vpx_codec_alg_priv { |
michael@0 | 42 | vpx_codec_priv_t base; |
michael@0 | 43 | vpx_codec_mmap_t mmaps[NELEMENTS(vp9_mem_req_segs) - 1]; |
michael@0 | 44 | vpx_codec_dec_cfg_t cfg; |
michael@0 | 45 | vp9_stream_info_t si; |
michael@0 | 46 | int defer_alloc; |
michael@0 | 47 | int decoder_init; |
michael@0 | 48 | VP9D_PTR pbi; |
michael@0 | 49 | int postproc_cfg_set; |
michael@0 | 50 | vp8_postproc_cfg_t postproc_cfg; |
michael@0 | 51 | #if CONFIG_POSTPROC_VISUALIZER |
michael@0 | 52 | unsigned int dbg_postproc_flag; |
michael@0 | 53 | int dbg_color_ref_frame_flag; |
michael@0 | 54 | int dbg_color_mb_modes_flag; |
michael@0 | 55 | int dbg_color_b_modes_flag; |
michael@0 | 56 | int dbg_display_mv_flag; |
michael@0 | 57 | #endif |
michael@0 | 58 | vpx_image_t img; |
michael@0 | 59 | int img_setup; |
michael@0 | 60 | int img_avail; |
michael@0 | 61 | int invert_tile_order; |
michael@0 | 62 | }; |
michael@0 | 63 | |
michael@0 | 64 | static unsigned long priv_sz(const vpx_codec_dec_cfg_t *si, |
michael@0 | 65 | vpx_codec_flags_t flags) { |
michael@0 | 66 | /* Although this declaration is constant, we can't use it in the requested |
michael@0 | 67 | * segments list because we want to define the requested segments list |
michael@0 | 68 | * before defining the private type (so that the number of memory maps is |
michael@0 | 69 | * known) |
michael@0 | 70 | */ |
michael@0 | 71 | (void)si; |
michael@0 | 72 | return sizeof(vpx_codec_alg_priv_t); |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | static void vp9_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap) { |
michael@0 | 76 | int i; |
michael@0 | 77 | |
michael@0 | 78 | ctx->priv = mmap->base; |
michael@0 | 79 | ctx->priv->sz = sizeof(*ctx->priv); |
michael@0 | 80 | ctx->priv->iface = ctx->iface; |
michael@0 | 81 | ctx->priv->alg_priv = mmap->base; |
michael@0 | 82 | |
michael@0 | 83 | for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) |
michael@0 | 84 | ctx->priv->alg_priv->mmaps[i].id = vp9_mem_req_segs[i].id; |
michael@0 | 85 | |
michael@0 | 86 | ctx->priv->alg_priv->mmaps[0] = *mmap; |
michael@0 | 87 | ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si); |
michael@0 | 88 | ctx->priv->init_flags = ctx->init_flags; |
michael@0 | 89 | |
michael@0 | 90 | if (ctx->config.dec) { |
michael@0 | 91 | /* Update the reference to the config structure to an internal copy. */ |
michael@0 | 92 | ctx->priv->alg_priv->cfg = *ctx->config.dec; |
michael@0 | 93 | ctx->config.dec = &ctx->priv->alg_priv->cfg; |
michael@0 | 94 | } |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | static void vp9_finalize_mmaps(vpx_codec_alg_priv_t *ctx) { |
michael@0 | 98 | /* nothing to clean up */ |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | static vpx_codec_err_t vp9_init(vpx_codec_ctx_t *ctx, |
michael@0 | 102 | vpx_codec_priv_enc_mr_cfg_t *data) { |
michael@0 | 103 | vpx_codec_err_t res = VPX_CODEC_OK; |
michael@0 | 104 | |
michael@0 | 105 | /* This function only allocates space for the vpx_codec_alg_priv_t |
michael@0 | 106 | * structure. More memory may be required at the time the stream |
michael@0 | 107 | * information becomes known. |
michael@0 | 108 | */ |
michael@0 | 109 | if (!ctx->priv) { |
michael@0 | 110 | vpx_codec_mmap_t mmap; |
michael@0 | 111 | |
michael@0 | 112 | mmap.id = vp9_mem_req_segs[0].id; |
michael@0 | 113 | mmap.sz = sizeof(vpx_codec_alg_priv_t); |
michael@0 | 114 | mmap.align = vp9_mem_req_segs[0].align; |
michael@0 | 115 | mmap.flags = vp9_mem_req_segs[0].flags; |
michael@0 | 116 | |
michael@0 | 117 | res = vpx_mmap_alloc(&mmap); |
michael@0 | 118 | |
michael@0 | 119 | if (!res) { |
michael@0 | 120 | vp9_init_ctx(ctx, &mmap); |
michael@0 | 121 | |
michael@0 | 122 | ctx->priv->alg_priv->defer_alloc = 1; |
michael@0 | 123 | /*post processing level initialized to do nothing */ |
michael@0 | 124 | } |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | return res; |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | static vpx_codec_err_t vp9_destroy(vpx_codec_alg_priv_t *ctx) { |
michael@0 | 131 | int i; |
michael@0 | 132 | |
michael@0 | 133 | vp9_remove_decompressor(ctx->pbi); |
michael@0 | 134 | |
michael@0 | 135 | for (i = NELEMENTS(ctx->mmaps) - 1; i >= 0; i--) { |
michael@0 | 136 | if (ctx->mmaps[i].dtor) |
michael@0 | 137 | ctx->mmaps[i].dtor(&ctx->mmaps[i]); |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | return VPX_CODEC_OK; |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | static vpx_codec_err_t vp9_peek_si(const uint8_t *data, |
michael@0 | 144 | unsigned int data_sz, |
michael@0 | 145 | vpx_codec_stream_info_t *si) { |
michael@0 | 146 | if (data_sz <= 8) return VPX_CODEC_UNSUP_BITSTREAM; |
michael@0 | 147 | if (data + data_sz <= data) return VPX_CODEC_INVALID_PARAM; |
michael@0 | 148 | |
michael@0 | 149 | si->is_kf = 0; |
michael@0 | 150 | si->w = si->h = 0; |
michael@0 | 151 | |
michael@0 | 152 | { |
michael@0 | 153 | struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL }; |
michael@0 | 154 | const int frame_marker = vp9_rb_read_literal(&rb, 2); |
michael@0 | 155 | const int version = vp9_rb_read_bit(&rb) | (vp9_rb_read_bit(&rb) << 1); |
michael@0 | 156 | if (frame_marker != 0x2) return VPX_CODEC_UNSUP_BITSTREAM; |
michael@0 | 157 | #if CONFIG_NON420 |
michael@0 | 158 | if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM; |
michael@0 | 159 | #else |
michael@0 | 160 | if (version != 0) return VPX_CODEC_UNSUP_BITSTREAM; |
michael@0 | 161 | #endif |
michael@0 | 162 | |
michael@0 | 163 | if (vp9_rb_read_bit(&rb)) { // show an existing frame |
michael@0 | 164 | return VPX_CODEC_OK; |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | si->is_kf = !vp9_rb_read_bit(&rb); |
michael@0 | 168 | if (si->is_kf) { |
michael@0 | 169 | const int sRGB = 7; |
michael@0 | 170 | int colorspace; |
michael@0 | 171 | |
michael@0 | 172 | rb.bit_offset += 1; // show frame |
michael@0 | 173 | rb.bit_offset += 1; // error resilient |
michael@0 | 174 | |
michael@0 | 175 | if (vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_0 || |
michael@0 | 176 | vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_1 || |
michael@0 | 177 | vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) { |
michael@0 | 178 | return VPX_CODEC_UNSUP_BITSTREAM; |
michael@0 | 179 | } |
michael@0 | 180 | |
michael@0 | 181 | colorspace = vp9_rb_read_literal(&rb, 3); |
michael@0 | 182 | if (colorspace != sRGB) { |
michael@0 | 183 | rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range |
michael@0 | 184 | if (version == 1) { |
michael@0 | 185 | rb.bit_offset += 2; // subsampling x/y |
michael@0 | 186 | rb.bit_offset += 1; // has extra plane |
michael@0 | 187 | } |
michael@0 | 188 | } else { |
michael@0 | 189 | if (version == 1) { |
michael@0 | 190 | rb.bit_offset += 1; // has extra plane |
michael@0 | 191 | } else { |
michael@0 | 192 | // RGB is only available in version 1 |
michael@0 | 193 | return VPX_CODEC_UNSUP_BITSTREAM; |
michael@0 | 194 | } |
michael@0 | 195 | } |
michael@0 | 196 | |
michael@0 | 197 | // TODO(jzern): these are available on non-keyframes in intra only mode. |
michael@0 | 198 | si->w = vp9_rb_read_literal(&rb, 16) + 1; |
michael@0 | 199 | si->h = vp9_rb_read_literal(&rb, 16) + 1; |
michael@0 | 200 | } |
michael@0 | 201 | } |
michael@0 | 202 | |
michael@0 | 203 | return VPX_CODEC_OK; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | static vpx_codec_err_t vp9_get_si(vpx_codec_alg_priv_t *ctx, |
michael@0 | 207 | vpx_codec_stream_info_t *si) { |
michael@0 | 208 | unsigned int sz; |
michael@0 | 209 | |
michael@0 | 210 | if (si->sz >= sizeof(vp9_stream_info_t)) |
michael@0 | 211 | sz = sizeof(vp9_stream_info_t); |
michael@0 | 212 | else |
michael@0 | 213 | sz = sizeof(vpx_codec_stream_info_t); |
michael@0 | 214 | |
michael@0 | 215 | memcpy(si, &ctx->si, sz); |
michael@0 | 216 | si->sz = sz; |
michael@0 | 217 | |
michael@0 | 218 | return VPX_CODEC_OK; |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | |
michael@0 | 222 | static vpx_codec_err_t |
michael@0 | 223 | update_error_state(vpx_codec_alg_priv_t *ctx, |
michael@0 | 224 | const struct vpx_internal_error_info *error) { |
michael@0 | 225 | vpx_codec_err_t res; |
michael@0 | 226 | |
michael@0 | 227 | if ((res = error->error_code)) |
michael@0 | 228 | ctx->base.err_detail = error->has_detail |
michael@0 | 229 | ? error->detail |
michael@0 | 230 | : NULL; |
michael@0 | 231 | |
michael@0 | 232 | return res; |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx, |
michael@0 | 236 | const uint8_t **data, |
michael@0 | 237 | unsigned int data_sz, |
michael@0 | 238 | void *user_priv, |
michael@0 | 239 | long deadline) { |
michael@0 | 240 | vpx_codec_err_t res = VPX_CODEC_OK; |
michael@0 | 241 | |
michael@0 | 242 | ctx->img_avail = 0; |
michael@0 | 243 | |
michael@0 | 244 | /* Determine the stream parameters. Note that we rely on peek_si to |
michael@0 | 245 | * validate that we have a buffer that does not wrap around the top |
michael@0 | 246 | * of the heap. |
michael@0 | 247 | */ |
michael@0 | 248 | if (!ctx->si.h) |
michael@0 | 249 | res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si); |
michael@0 | 250 | |
michael@0 | 251 | |
michael@0 | 252 | /* Perform deferred allocations, if required */ |
michael@0 | 253 | if (!res && ctx->defer_alloc) { |
michael@0 | 254 | int i; |
michael@0 | 255 | |
michael@0 | 256 | for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++) { |
michael@0 | 257 | vpx_codec_dec_cfg_t cfg; |
michael@0 | 258 | |
michael@0 | 259 | cfg.w = ctx->si.w; |
michael@0 | 260 | cfg.h = ctx->si.h; |
michael@0 | 261 | ctx->mmaps[i].id = vp9_mem_req_segs[i].id; |
michael@0 | 262 | ctx->mmaps[i].sz = vp9_mem_req_segs[i].sz; |
michael@0 | 263 | ctx->mmaps[i].align = vp9_mem_req_segs[i].align; |
michael@0 | 264 | ctx->mmaps[i].flags = vp9_mem_req_segs[i].flags; |
michael@0 | 265 | |
michael@0 | 266 | if (!ctx->mmaps[i].sz) |
michael@0 | 267 | ctx->mmaps[i].sz = vp9_mem_req_segs[i].calc_sz(&cfg, |
michael@0 | 268 | ctx->base.init_flags); |
michael@0 | 269 | |
michael@0 | 270 | res = vpx_mmap_alloc(&ctx->mmaps[i]); |
michael@0 | 271 | } |
michael@0 | 272 | |
michael@0 | 273 | if (!res) |
michael@0 | 274 | vp9_finalize_mmaps(ctx); |
michael@0 | 275 | |
michael@0 | 276 | ctx->defer_alloc = 0; |
michael@0 | 277 | } |
michael@0 | 278 | |
michael@0 | 279 | /* Initialize the decoder instance on the first frame*/ |
michael@0 | 280 | if (!res && !ctx->decoder_init) { |
michael@0 | 281 | res = vpx_validate_mmaps(&ctx->si, ctx->mmaps, |
michael@0 | 282 | vp9_mem_req_segs, NELEMENTS(vp9_mem_req_segs), |
michael@0 | 283 | ctx->base.init_flags); |
michael@0 | 284 | |
michael@0 | 285 | if (!res) { |
michael@0 | 286 | VP9D_CONFIG oxcf; |
michael@0 | 287 | VP9D_PTR optr; |
michael@0 | 288 | |
michael@0 | 289 | vp9_initialize_dec(); |
michael@0 | 290 | |
michael@0 | 291 | oxcf.width = ctx->si.w; |
michael@0 | 292 | oxcf.height = ctx->si.h; |
michael@0 | 293 | oxcf.version = 9; |
michael@0 | 294 | oxcf.postprocess = 0; |
michael@0 | 295 | oxcf.max_threads = ctx->cfg.threads; |
michael@0 | 296 | oxcf.inv_tile_order = ctx->invert_tile_order; |
michael@0 | 297 | optr = vp9_create_decompressor(&oxcf); |
michael@0 | 298 | |
michael@0 | 299 | /* If postprocessing was enabled by the application and a |
michael@0 | 300 | * configuration has not been provided, default it. |
michael@0 | 301 | */ |
michael@0 | 302 | if (!ctx->postproc_cfg_set |
michael@0 | 303 | && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) { |
michael@0 | 304 | ctx->postproc_cfg.post_proc_flag = |
michael@0 | 305 | VP8_DEBLOCK | VP8_DEMACROBLOCK; |
michael@0 | 306 | ctx->postproc_cfg.deblocking_level = 4; |
michael@0 | 307 | ctx->postproc_cfg.noise_level = 0; |
michael@0 | 308 | } |
michael@0 | 309 | |
michael@0 | 310 | if (!optr) |
michael@0 | 311 | res = VPX_CODEC_ERROR; |
michael@0 | 312 | else |
michael@0 | 313 | ctx->pbi = optr; |
michael@0 | 314 | } |
michael@0 | 315 | |
michael@0 | 316 | ctx->decoder_init = 1; |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | if (!res && ctx->pbi) { |
michael@0 | 320 | YV12_BUFFER_CONFIG sd; |
michael@0 | 321 | int64_t time_stamp = 0, time_end_stamp = 0; |
michael@0 | 322 | vp9_ppflags_t flags = {0}; |
michael@0 | 323 | |
michael@0 | 324 | if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) { |
michael@0 | 325 | flags.post_proc_flag = |
michael@0 | 326 | #if CONFIG_POSTPROC_VISUALIZER |
michael@0 | 327 | ((ctx->dbg_color_ref_frame_flag != 0) ? |
michael@0 | 328 | VP9D_DEBUG_CLR_FRM_REF_BLKS : 0) |
michael@0 | 329 | | ((ctx->dbg_color_mb_modes_flag != 0) ? |
michael@0 | 330 | VP9D_DEBUG_CLR_BLK_MODES : 0) |
michael@0 | 331 | | ((ctx->dbg_color_b_modes_flag != 0) ? |
michael@0 | 332 | VP9D_DEBUG_CLR_BLK_MODES : 0) |
michael@0 | 333 | | ((ctx->dbg_display_mv_flag != 0) ? |
michael@0 | 334 | VP9D_DEBUG_DRAW_MV : 0) |
michael@0 | 335 | | |
michael@0 | 336 | #endif |
michael@0 | 337 | ctx->postproc_cfg.post_proc_flag; |
michael@0 | 338 | |
michael@0 | 339 | flags.deblocking_level = ctx->postproc_cfg.deblocking_level; |
michael@0 | 340 | flags.noise_level = ctx->postproc_cfg.noise_level; |
michael@0 | 341 | #if CONFIG_POSTPROC_VISUALIZER |
michael@0 | 342 | flags.display_ref_frame_flag = ctx->dbg_color_ref_frame_flag; |
michael@0 | 343 | flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag; |
michael@0 | 344 | flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag; |
michael@0 | 345 | flags.display_mv_flag = ctx->dbg_display_mv_flag; |
michael@0 | 346 | #endif |
michael@0 | 347 | } |
michael@0 | 348 | |
michael@0 | 349 | if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) { |
michael@0 | 350 | VP9D_COMP *pbi = (VP9D_COMP *)ctx->pbi; |
michael@0 | 351 | res = update_error_state(ctx, &pbi->common.error); |
michael@0 | 352 | } |
michael@0 | 353 | |
michael@0 | 354 | if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp, |
michael@0 | 355 | &time_end_stamp, &flags)) { |
michael@0 | 356 | yuvconfig2image(&ctx->img, &sd, user_priv); |
michael@0 | 357 | ctx->img_avail = 1; |
michael@0 | 358 | } |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | return res; |
michael@0 | 362 | } |
michael@0 | 363 | |
michael@0 | 364 | static void parse_superframe_index(const uint8_t *data, |
michael@0 | 365 | size_t data_sz, |
michael@0 | 366 | uint32_t sizes[8], |
michael@0 | 367 | int *count) { |
michael@0 | 368 | uint8_t marker; |
michael@0 | 369 | |
michael@0 | 370 | assert(data_sz); |
michael@0 | 371 | marker = data[data_sz - 1]; |
michael@0 | 372 | *count = 0; |
michael@0 | 373 | |
michael@0 | 374 | if ((marker & 0xe0) == 0xc0) { |
michael@0 | 375 | const uint32_t frames = (marker & 0x7) + 1; |
michael@0 | 376 | const uint32_t mag = ((marker >> 3) & 0x3) + 1; |
michael@0 | 377 | const size_t index_sz = 2 + mag * frames; |
michael@0 | 378 | |
michael@0 | 379 | if (data_sz >= index_sz && data[data_sz - index_sz] == marker) { |
michael@0 | 380 | // found a valid superframe index |
michael@0 | 381 | uint32_t i, j; |
michael@0 | 382 | const uint8_t *x = data + data_sz - index_sz + 1; |
michael@0 | 383 | |
michael@0 | 384 | for (i = 0; i < frames; i++) { |
michael@0 | 385 | uint32_t this_sz = 0; |
michael@0 | 386 | |
michael@0 | 387 | for (j = 0; j < mag; j++) |
michael@0 | 388 | this_sz |= (*x++) << (j * 8); |
michael@0 | 389 | sizes[i] = this_sz; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | *count = frames; |
michael@0 | 393 | } |
michael@0 | 394 | } |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | static vpx_codec_err_t vp9_decode(vpx_codec_alg_priv_t *ctx, |
michael@0 | 398 | const uint8_t *data, |
michael@0 | 399 | unsigned int data_sz, |
michael@0 | 400 | void *user_priv, |
michael@0 | 401 | long deadline) { |
michael@0 | 402 | const uint8_t *data_start = data; |
michael@0 | 403 | const uint8_t *data_end = data + data_sz; |
michael@0 | 404 | vpx_codec_err_t res = 0; |
michael@0 | 405 | uint32_t sizes[8]; |
michael@0 | 406 | int frames_this_pts, frame_count = 0; |
michael@0 | 407 | |
michael@0 | 408 | if (data == NULL || data_sz == 0) return VPX_CODEC_INVALID_PARAM; |
michael@0 | 409 | |
michael@0 | 410 | parse_superframe_index(data, data_sz, sizes, &frames_this_pts); |
michael@0 | 411 | |
michael@0 | 412 | do { |
michael@0 | 413 | // Skip over the superframe index, if present |
michael@0 | 414 | if (data_sz && (*data_start & 0xe0) == 0xc0) { |
michael@0 | 415 | const uint8_t marker = *data_start; |
michael@0 | 416 | const uint32_t frames = (marker & 0x7) + 1; |
michael@0 | 417 | const uint32_t mag = ((marker >> 3) & 0x3) + 1; |
michael@0 | 418 | const uint32_t index_sz = 2 + mag * frames; |
michael@0 | 419 | |
michael@0 | 420 | if (data_sz >= index_sz && data_start[index_sz - 1] == marker) { |
michael@0 | 421 | data_start += index_sz; |
michael@0 | 422 | data_sz -= index_sz; |
michael@0 | 423 | if (data_start < data_end) |
michael@0 | 424 | continue; |
michael@0 | 425 | else |
michael@0 | 426 | break; |
michael@0 | 427 | } |
michael@0 | 428 | } |
michael@0 | 429 | |
michael@0 | 430 | // Use the correct size for this frame, if an index is present. |
michael@0 | 431 | if (frames_this_pts) { |
michael@0 | 432 | uint32_t this_sz = sizes[frame_count]; |
michael@0 | 433 | |
michael@0 | 434 | if (data_sz < this_sz) { |
michael@0 | 435 | ctx->base.err_detail = "Invalid frame size in index"; |
michael@0 | 436 | return VPX_CODEC_CORRUPT_FRAME; |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | data_sz = this_sz; |
michael@0 | 440 | frame_count++; |
michael@0 | 441 | } |
michael@0 | 442 | |
michael@0 | 443 | res = decode_one(ctx, &data_start, data_sz, user_priv, deadline); |
michael@0 | 444 | assert(data_start >= data); |
michael@0 | 445 | assert(data_start <= data_end); |
michael@0 | 446 | |
michael@0 | 447 | /* Early exit if there was a decode error */ |
michael@0 | 448 | if (res) |
michael@0 | 449 | break; |
michael@0 | 450 | |
michael@0 | 451 | /* Account for suboptimal termination by the encoder. */ |
michael@0 | 452 | while (data_start < data_end && *data_start == 0) |
michael@0 | 453 | data_start++; |
michael@0 | 454 | |
michael@0 | 455 | data_sz = data_end - data_start; |
michael@0 | 456 | } while (data_start < data_end); |
michael@0 | 457 | return res; |
michael@0 | 458 | } |
michael@0 | 459 | |
michael@0 | 460 | static vpx_image_t *vp9_get_frame(vpx_codec_alg_priv_t *ctx, |
michael@0 | 461 | vpx_codec_iter_t *iter) { |
michael@0 | 462 | vpx_image_t *img = NULL; |
michael@0 | 463 | |
michael@0 | 464 | if (ctx->img_avail) { |
michael@0 | 465 | /* iter acts as a flip flop, so an image is only returned on the first |
michael@0 | 466 | * call to get_frame. |
michael@0 | 467 | */ |
michael@0 | 468 | if (!(*iter)) { |
michael@0 | 469 | img = &ctx->img; |
michael@0 | 470 | *iter = img; |
michael@0 | 471 | } |
michael@0 | 472 | } |
michael@0 | 473 | ctx->img_avail = 0; |
michael@0 | 474 | |
michael@0 | 475 | return img; |
michael@0 | 476 | } |
michael@0 | 477 | |
michael@0 | 478 | static vpx_codec_err_t vp9_xma_get_mmap(const vpx_codec_ctx_t *ctx, |
michael@0 | 479 | vpx_codec_mmap_t *mmap, |
michael@0 | 480 | vpx_codec_iter_t *iter) { |
michael@0 | 481 | vpx_codec_err_t res; |
michael@0 | 482 | const mem_req_t *seg_iter = *iter; |
michael@0 | 483 | |
michael@0 | 484 | /* Get address of next segment request */ |
michael@0 | 485 | do { |
michael@0 | 486 | if (!seg_iter) |
michael@0 | 487 | seg_iter = vp9_mem_req_segs; |
michael@0 | 488 | else if (seg_iter->id != VP9_SEG_MAX) |
michael@0 | 489 | seg_iter++; |
michael@0 | 490 | |
michael@0 | 491 | *iter = (vpx_codec_iter_t)seg_iter; |
michael@0 | 492 | |
michael@0 | 493 | if (seg_iter->id != VP9_SEG_MAX) { |
michael@0 | 494 | mmap->id = seg_iter->id; |
michael@0 | 495 | mmap->sz = seg_iter->sz; |
michael@0 | 496 | mmap->align = seg_iter->align; |
michael@0 | 497 | mmap->flags = seg_iter->flags; |
michael@0 | 498 | |
michael@0 | 499 | if (!seg_iter->sz) |
michael@0 | 500 | mmap->sz = seg_iter->calc_sz(ctx->config.dec, ctx->init_flags); |
michael@0 | 501 | |
michael@0 | 502 | res = VPX_CODEC_OK; |
michael@0 | 503 | } else { |
michael@0 | 504 | res = VPX_CODEC_LIST_END; |
michael@0 | 505 | } |
michael@0 | 506 | } while (!mmap->sz && res != VPX_CODEC_LIST_END); |
michael@0 | 507 | |
michael@0 | 508 | return res; |
michael@0 | 509 | } |
michael@0 | 510 | |
michael@0 | 511 | static vpx_codec_err_t vp9_xma_set_mmap(vpx_codec_ctx_t *ctx, |
michael@0 | 512 | const vpx_codec_mmap_t *mmap) { |
michael@0 | 513 | vpx_codec_err_t res = VPX_CODEC_MEM_ERROR; |
michael@0 | 514 | int i, done; |
michael@0 | 515 | |
michael@0 | 516 | if (!ctx->priv) { |
michael@0 | 517 | if (mmap->id == VP9_SEG_ALG_PRIV) { |
michael@0 | 518 | if (!ctx->priv) { |
michael@0 | 519 | vp9_init_ctx(ctx, mmap); |
michael@0 | 520 | res = VPX_CODEC_OK; |
michael@0 | 521 | } |
michael@0 | 522 | } |
michael@0 | 523 | } |
michael@0 | 524 | |
michael@0 | 525 | done = 1; |
michael@0 | 526 | |
michael@0 | 527 | if (!res && ctx->priv->alg_priv) { |
michael@0 | 528 | for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++) { |
michael@0 | 529 | if (ctx->priv->alg_priv->mmaps[i].id == mmap->id) |
michael@0 | 530 | if (!ctx->priv->alg_priv->mmaps[i].base) { |
michael@0 | 531 | ctx->priv->alg_priv->mmaps[i] = *mmap; |
michael@0 | 532 | res = VPX_CODEC_OK; |
michael@0 | 533 | } |
michael@0 | 534 | |
michael@0 | 535 | done &= (ctx->priv->alg_priv->mmaps[i].base != NULL); |
michael@0 | 536 | } |
michael@0 | 537 | } |
michael@0 | 538 | |
michael@0 | 539 | if (done && !res) { |
michael@0 | 540 | vp9_finalize_mmaps(ctx->priv->alg_priv); |
michael@0 | 541 | res = ctx->iface->init(ctx, NULL); |
michael@0 | 542 | } |
michael@0 | 543 | |
michael@0 | 544 | return res; |
michael@0 | 545 | } |
michael@0 | 546 | |
michael@0 | 547 | static vpx_codec_err_t set_reference(vpx_codec_alg_priv_t *ctx, |
michael@0 | 548 | int ctr_id, |
michael@0 | 549 | va_list args) { |
michael@0 | 550 | vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); |
michael@0 | 551 | |
michael@0 | 552 | if (data) { |
michael@0 | 553 | vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; |
michael@0 | 554 | YV12_BUFFER_CONFIG sd; |
michael@0 | 555 | |
michael@0 | 556 | image2yuvconfig(&frame->img, &sd); |
michael@0 | 557 | |
michael@0 | 558 | return vp9_set_reference_dec(ctx->pbi, |
michael@0 | 559 | (VP9_REFFRAME)frame->frame_type, &sd); |
michael@0 | 560 | } else { |
michael@0 | 561 | return VPX_CODEC_INVALID_PARAM; |
michael@0 | 562 | } |
michael@0 | 563 | } |
michael@0 | 564 | |
michael@0 | 565 | static vpx_codec_err_t copy_reference(vpx_codec_alg_priv_t *ctx, |
michael@0 | 566 | int ctr_id, |
michael@0 | 567 | va_list args) { |
michael@0 | 568 | vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); |
michael@0 | 569 | |
michael@0 | 570 | if (data) { |
michael@0 | 571 | vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data; |
michael@0 | 572 | YV12_BUFFER_CONFIG sd; |
michael@0 | 573 | |
michael@0 | 574 | image2yuvconfig(&frame->img, &sd); |
michael@0 | 575 | |
michael@0 | 576 | return vp9_copy_reference_dec(ctx->pbi, |
michael@0 | 577 | (VP9_REFFRAME)frame->frame_type, &sd); |
michael@0 | 578 | } else { |
michael@0 | 579 | return VPX_CODEC_INVALID_PARAM; |
michael@0 | 580 | } |
michael@0 | 581 | } |
michael@0 | 582 | |
michael@0 | 583 | static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx, |
michael@0 | 584 | int ctr_id, |
michael@0 | 585 | va_list args) { |
michael@0 | 586 | vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *); |
michael@0 | 587 | |
michael@0 | 588 | if (data) { |
michael@0 | 589 | YV12_BUFFER_CONFIG* fb; |
michael@0 | 590 | |
michael@0 | 591 | vp9_get_reference_dec(ctx->pbi, data->idx, &fb); |
michael@0 | 592 | yuvconfig2image(&data->img, fb, NULL); |
michael@0 | 593 | return VPX_CODEC_OK; |
michael@0 | 594 | } else { |
michael@0 | 595 | return VPX_CODEC_INVALID_PARAM; |
michael@0 | 596 | } |
michael@0 | 597 | } |
michael@0 | 598 | |
michael@0 | 599 | static vpx_codec_err_t set_postproc(vpx_codec_alg_priv_t *ctx, |
michael@0 | 600 | int ctr_id, |
michael@0 | 601 | va_list args) { |
michael@0 | 602 | #if CONFIG_VP9_POSTPROC |
michael@0 | 603 | vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *); |
michael@0 | 604 | |
michael@0 | 605 | if (data) { |
michael@0 | 606 | ctx->postproc_cfg_set = 1; |
michael@0 | 607 | ctx->postproc_cfg = *((vp8_postproc_cfg_t *)data); |
michael@0 | 608 | return VPX_CODEC_OK; |
michael@0 | 609 | } else { |
michael@0 | 610 | return VPX_CODEC_INVALID_PARAM; |
michael@0 | 611 | } |
michael@0 | 612 | #else |
michael@0 | 613 | return VPX_CODEC_INCAPABLE; |
michael@0 | 614 | #endif |
michael@0 | 615 | } |
michael@0 | 616 | |
michael@0 | 617 | static vpx_codec_err_t set_dbg_options(vpx_codec_alg_priv_t *ctx, |
michael@0 | 618 | int ctrl_id, |
michael@0 | 619 | va_list args) { |
michael@0 | 620 | #if CONFIG_POSTPROC_VISUALIZER && CONFIG_POSTPROC |
michael@0 | 621 | int data = va_arg(args, int); |
michael@0 | 622 | |
michael@0 | 623 | #define MAP(id, var) case id: var = data; break; |
michael@0 | 624 | |
michael@0 | 625 | switch (ctrl_id) { |
michael@0 | 626 | MAP(VP8_SET_DBG_COLOR_REF_FRAME, ctx->dbg_color_ref_frame_flag); |
michael@0 | 627 | MAP(VP8_SET_DBG_COLOR_MB_MODES, ctx->dbg_color_mb_modes_flag); |
michael@0 | 628 | MAP(VP8_SET_DBG_COLOR_B_MODES, ctx->dbg_color_b_modes_flag); |
michael@0 | 629 | MAP(VP8_SET_DBG_DISPLAY_MV, ctx->dbg_display_mv_flag); |
michael@0 | 630 | } |
michael@0 | 631 | |
michael@0 | 632 | return VPX_CODEC_OK; |
michael@0 | 633 | #else |
michael@0 | 634 | return VPX_CODEC_INCAPABLE; |
michael@0 | 635 | #endif |
michael@0 | 636 | } |
michael@0 | 637 | |
michael@0 | 638 | static vpx_codec_err_t get_last_ref_updates(vpx_codec_alg_priv_t *ctx, |
michael@0 | 639 | int ctrl_id, |
michael@0 | 640 | va_list args) { |
michael@0 | 641 | int *update_info = va_arg(args, int *); |
michael@0 | 642 | VP9D_COMP *pbi = (VP9D_COMP *)ctx->pbi; |
michael@0 | 643 | |
michael@0 | 644 | if (update_info) { |
michael@0 | 645 | *update_info = pbi->refresh_frame_flags; |
michael@0 | 646 | |
michael@0 | 647 | return VPX_CODEC_OK; |
michael@0 | 648 | } else { |
michael@0 | 649 | return VPX_CODEC_INVALID_PARAM; |
michael@0 | 650 | } |
michael@0 | 651 | } |
michael@0 | 652 | |
michael@0 | 653 | |
michael@0 | 654 | static vpx_codec_err_t get_frame_corrupted(vpx_codec_alg_priv_t *ctx, |
michael@0 | 655 | int ctrl_id, |
michael@0 | 656 | va_list args) { |
michael@0 | 657 | int *corrupted = va_arg(args, int *); |
michael@0 | 658 | |
michael@0 | 659 | if (corrupted) { |
michael@0 | 660 | VP9D_COMP *pbi = (VP9D_COMP *)ctx->pbi; |
michael@0 | 661 | if (pbi) |
michael@0 | 662 | *corrupted = pbi->common.frame_to_show->corrupted; |
michael@0 | 663 | else |
michael@0 | 664 | return VPX_CODEC_ERROR; |
michael@0 | 665 | return VPX_CODEC_OK; |
michael@0 | 666 | } else { |
michael@0 | 667 | return VPX_CODEC_INVALID_PARAM; |
michael@0 | 668 | } |
michael@0 | 669 | } |
michael@0 | 670 | |
michael@0 | 671 | static vpx_codec_err_t set_invert_tile_order(vpx_codec_alg_priv_t *ctx, |
michael@0 | 672 | int ctr_id, |
michael@0 | 673 | va_list args) { |
michael@0 | 674 | ctx->invert_tile_order = va_arg(args, int); |
michael@0 | 675 | return VPX_CODEC_OK; |
michael@0 | 676 | } |
michael@0 | 677 | |
michael@0 | 678 | static vpx_codec_ctrl_fn_map_t ctf_maps[] = { |
michael@0 | 679 | {VP8_SET_REFERENCE, set_reference}, |
michael@0 | 680 | {VP8_COPY_REFERENCE, copy_reference}, |
michael@0 | 681 | {VP8_SET_POSTPROC, set_postproc}, |
michael@0 | 682 | {VP8_SET_DBG_COLOR_REF_FRAME, set_dbg_options}, |
michael@0 | 683 | {VP8_SET_DBG_COLOR_MB_MODES, set_dbg_options}, |
michael@0 | 684 | {VP8_SET_DBG_COLOR_B_MODES, set_dbg_options}, |
michael@0 | 685 | {VP8_SET_DBG_DISPLAY_MV, set_dbg_options}, |
michael@0 | 686 | {VP8D_GET_LAST_REF_UPDATES, get_last_ref_updates}, |
michael@0 | 687 | {VP8D_GET_FRAME_CORRUPTED, get_frame_corrupted}, |
michael@0 | 688 | {VP9_GET_REFERENCE, get_reference}, |
michael@0 | 689 | {VP9_INVERT_TILE_DECODE_ORDER, set_invert_tile_order}, |
michael@0 | 690 | { -1, NULL}, |
michael@0 | 691 | }; |
michael@0 | 692 | |
michael@0 | 693 | |
michael@0 | 694 | #ifndef VERSION_STRING |
michael@0 | 695 | #define VERSION_STRING |
michael@0 | 696 | #endif |
michael@0 | 697 | CODEC_INTERFACE(vpx_codec_vp9_dx) = { |
michael@0 | 698 | "WebM Project VP9 Decoder" VERSION_STRING, |
michael@0 | 699 | VPX_CODEC_INTERNAL_ABI_VERSION, |
michael@0 | 700 | VPX_CODEC_CAP_DECODER | VP9_CAP_POSTPROC, |
michael@0 | 701 | /* vpx_codec_caps_t caps; */ |
michael@0 | 702 | vp9_init, /* vpx_codec_init_fn_t init; */ |
michael@0 | 703 | vp9_destroy, /* vpx_codec_destroy_fn_t destroy; */ |
michael@0 | 704 | ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */ |
michael@0 | 705 | vp9_xma_get_mmap, /* vpx_codec_get_mmap_fn_t get_mmap; */ |
michael@0 | 706 | vp9_xma_set_mmap, /* vpx_codec_set_mmap_fn_t set_mmap; */ |
michael@0 | 707 | { // NOLINT |
michael@0 | 708 | vp9_peek_si, /* vpx_codec_peek_si_fn_t peek_si; */ |
michael@0 | 709 | vp9_get_si, /* vpx_codec_get_si_fn_t get_si; */ |
michael@0 | 710 | vp9_decode, /* vpx_codec_decode_fn_t decode; */ |
michael@0 | 711 | vp9_get_frame, /* vpx_codec_frame_get_fn_t frame_get; */ |
michael@0 | 712 | }, |
michael@0 | 713 | { // NOLINT |
michael@0 | 714 | /* encoder functions */ |
michael@0 | 715 | NOT_IMPLEMENTED, |
michael@0 | 716 | NOT_IMPLEMENTED, |
michael@0 | 717 | NOT_IMPLEMENTED, |
michael@0 | 718 | NOT_IMPLEMENTED, |
michael@0 | 719 | NOT_IMPLEMENTED, |
michael@0 | 720 | NOT_IMPLEMENTED |
michael@0 | 721 | } |
michael@0 | 722 | }; |