media/libvpx/vp9/decoder/vp9_onyxd_if.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 #include <assert.h>
michael@0 12 #include <limits.h>
michael@0 13 #include <stdio.h>
michael@0 14
michael@0 15 #include "vp9/common/vp9_onyxc_int.h"
michael@0 16 #if CONFIG_VP9_POSTPROC
michael@0 17 #include "vp9/common/vp9_postproc.h"
michael@0 18 #endif
michael@0 19 #include "vp9/decoder/vp9_onyxd.h"
michael@0 20 #include "vp9/decoder/vp9_onyxd_int.h"
michael@0 21 #include "vpx_mem/vpx_mem.h"
michael@0 22 #include "vp9/common/vp9_alloccommon.h"
michael@0 23 #include "vp9/common/vp9_loopfilter.h"
michael@0 24 #include "vp9/common/vp9_quant_common.h"
michael@0 25 #include "vpx_scale/vpx_scale.h"
michael@0 26 #include "vp9/common/vp9_systemdependent.h"
michael@0 27 #include "vpx_ports/vpx_timer.h"
michael@0 28 #include "vp9/decoder/vp9_decodframe.h"
michael@0 29 #include "vp9/decoder/vp9_detokenize.h"
michael@0 30 #include "./vpx_scale_rtcd.h"
michael@0 31
michael@0 32 #define WRITE_RECON_BUFFER 0
michael@0 33 #if WRITE_RECON_BUFFER == 1
michael@0 34 static void recon_write_yuv_frame(const char *name,
michael@0 35 const YV12_BUFFER_CONFIG *s,
michael@0 36 int w, int _h) {
michael@0 37 FILE *yuv_file = fopen(name, "ab");
michael@0 38 const uint8_t *src = s->y_buffer;
michael@0 39 int h = _h;
michael@0 40
michael@0 41 do {
michael@0 42 fwrite(src, w, 1, yuv_file);
michael@0 43 src += s->y_stride;
michael@0 44 } while (--h);
michael@0 45
michael@0 46 src = s->u_buffer;
michael@0 47 h = (_h + 1) >> 1;
michael@0 48 w = (w + 1) >> 1;
michael@0 49
michael@0 50 do {
michael@0 51 fwrite(src, w, 1, yuv_file);
michael@0 52 src += s->uv_stride;
michael@0 53 } while (--h);
michael@0 54
michael@0 55 src = s->v_buffer;
michael@0 56 h = (_h + 1) >> 1;
michael@0 57
michael@0 58 do {
michael@0 59 fwrite(src, w, 1, yuv_file);
michael@0 60 src += s->uv_stride;
michael@0 61 } while (--h);
michael@0 62
michael@0 63 fclose(yuv_file);
michael@0 64 }
michael@0 65 #endif
michael@0 66 #if WRITE_RECON_BUFFER == 2
michael@0 67 void write_dx_frame_to_file(YV12_BUFFER_CONFIG *frame, int this_frame) {
michael@0 68 // write the frame
michael@0 69 FILE *yframe;
michael@0 70 int i;
michael@0 71 char filename[255];
michael@0 72
michael@0 73 snprintf(filename, sizeof(filename)-1, "dx\\y%04d.raw", this_frame);
michael@0 74 yframe = fopen(filename, "wb");
michael@0 75
michael@0 76 for (i = 0; i < frame->y_height; i++)
michael@0 77 fwrite(frame->y_buffer + i * frame->y_stride,
michael@0 78 frame->y_width, 1, yframe);
michael@0 79
michael@0 80 fclose(yframe);
michael@0 81 snprintf(filename, sizeof(filename)-1, "dx\\u%04d.raw", this_frame);
michael@0 82 yframe = fopen(filename, "wb");
michael@0 83
michael@0 84 for (i = 0; i < frame->uv_height; i++)
michael@0 85 fwrite(frame->u_buffer + i * frame->uv_stride,
michael@0 86 frame->uv_width, 1, yframe);
michael@0 87
michael@0 88 fclose(yframe);
michael@0 89 snprintf(filename, sizeof(filename)-1, "dx\\v%04d.raw", this_frame);
michael@0 90 yframe = fopen(filename, "wb");
michael@0 91
michael@0 92 for (i = 0; i < frame->uv_height; i++)
michael@0 93 fwrite(frame->v_buffer + i * frame->uv_stride,
michael@0 94 frame->uv_width, 1, yframe);
michael@0 95
michael@0 96 fclose(yframe);
michael@0 97 }
michael@0 98 #endif
michael@0 99
michael@0 100 void vp9_initialize_dec() {
michael@0 101 static int init_done = 0;
michael@0 102
michael@0 103 if (!init_done) {
michael@0 104 vp9_initialize_common();
michael@0 105 vp9_init_quant_tables();
michael@0 106 init_done = 1;
michael@0 107 }
michael@0 108 }
michael@0 109
michael@0 110 static void init_macroblockd(VP9D_COMP *const pbi) {
michael@0 111 MACROBLOCKD *xd = &pbi->mb;
michael@0 112 struct macroblockd_plane *const pd = xd->plane;
michael@0 113 int i;
michael@0 114
michael@0 115 for (i = 0; i < MAX_MB_PLANE; ++i) {
michael@0 116 pd[i].qcoeff = pbi->qcoeff[i];
michael@0 117 pd[i].dqcoeff = pbi->dqcoeff[i];
michael@0 118 pd[i].eobs = pbi->eobs[i];
michael@0 119 }
michael@0 120 }
michael@0 121
michael@0 122 VP9D_PTR vp9_create_decompressor(VP9D_CONFIG *oxcf) {
michael@0 123 VP9D_COMP *const pbi = vpx_memalign(32, sizeof(VP9D_COMP));
michael@0 124 VP9_COMMON *const cm = pbi ? &pbi->common : NULL;
michael@0 125
michael@0 126 if (!cm)
michael@0 127 return NULL;
michael@0 128
michael@0 129 vp9_zero(*pbi);
michael@0 130
michael@0 131 if (setjmp(cm->error.jmp)) {
michael@0 132 cm->error.setjmp = 0;
michael@0 133 vp9_remove_decompressor(pbi);
michael@0 134 return NULL;
michael@0 135 }
michael@0 136
michael@0 137 cm->error.setjmp = 1;
michael@0 138 vp9_initialize_dec();
michael@0 139
michael@0 140 vp9_create_common(cm);
michael@0 141
michael@0 142 pbi->oxcf = *oxcf;
michael@0 143 pbi->ready_for_new_data = 1;
michael@0 144 cm->current_video_frame = 0;
michael@0 145
michael@0 146 // vp9_init_dequantizer() is first called here. Add check in
michael@0 147 // frame_init_dequantizer() to avoid unnecessary calling of
michael@0 148 // vp9_init_dequantizer() for every frame.
michael@0 149 vp9_init_dequantizer(cm);
michael@0 150
michael@0 151 vp9_loop_filter_init(cm);
michael@0 152
michael@0 153 cm->error.setjmp = 0;
michael@0 154 pbi->decoded_key_frame = 0;
michael@0 155
michael@0 156 init_macroblockd(pbi);
michael@0 157
michael@0 158 vp9_worker_init(&pbi->lf_worker);
michael@0 159
michael@0 160 return pbi;
michael@0 161 }
michael@0 162
michael@0 163 void vp9_remove_decompressor(VP9D_PTR ptr) {
michael@0 164 int i;
michael@0 165 VP9D_COMP *const pbi = (VP9D_COMP *)ptr;
michael@0 166
michael@0 167 if (!pbi)
michael@0 168 return;
michael@0 169
michael@0 170 vp9_remove_common(&pbi->common);
michael@0 171 vp9_worker_end(&pbi->lf_worker);
michael@0 172 vpx_free(pbi->lf_worker.data1);
michael@0 173 for (i = 0; i < pbi->num_tile_workers; ++i) {
michael@0 174 VP9Worker *const worker = &pbi->tile_workers[i];
michael@0 175 vp9_worker_end(worker);
michael@0 176 vpx_free(worker->data1);
michael@0 177 vpx_free(worker->data2);
michael@0 178 }
michael@0 179 vpx_free(pbi->tile_workers);
michael@0 180 vpx_free(pbi->mi_streams);
michael@0 181 vpx_free(pbi->above_context[0]);
michael@0 182 vpx_free(pbi->above_seg_context);
michael@0 183 vpx_free(pbi);
michael@0 184 }
michael@0 185
michael@0 186 static int equal_dimensions(YV12_BUFFER_CONFIG *a, YV12_BUFFER_CONFIG *b) {
michael@0 187 return a->y_height == b->y_height && a->y_width == b->y_width &&
michael@0 188 a->uv_height == b->uv_height && a->uv_width == b->uv_width;
michael@0 189 }
michael@0 190
michael@0 191 vpx_codec_err_t vp9_copy_reference_dec(VP9D_PTR ptr,
michael@0 192 VP9_REFFRAME ref_frame_flag,
michael@0 193 YV12_BUFFER_CONFIG *sd) {
michael@0 194 VP9D_COMP *pbi = (VP9D_COMP *) ptr;
michael@0 195 VP9_COMMON *cm = &pbi->common;
michael@0 196
michael@0 197 /* TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
michael@0 198 * encoder is using the frame buffers for. This is just a stub to keep the
michael@0 199 * vpxenc --test-decode functionality working, and will be replaced in a
michael@0 200 * later commit that adds VP9-specific controls for this functionality.
michael@0 201 */
michael@0 202 if (ref_frame_flag == VP9_LAST_FLAG) {
michael@0 203 YV12_BUFFER_CONFIG *cfg = &cm->yv12_fb[cm->ref_frame_map[0]];
michael@0 204 if (!equal_dimensions(cfg, sd))
michael@0 205 vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
michael@0 206 "Incorrect buffer dimensions");
michael@0 207 else
michael@0 208 vp8_yv12_copy_frame(cfg, sd);
michael@0 209 } else {
michael@0 210 vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
michael@0 211 "Invalid reference frame");
michael@0 212 }
michael@0 213
michael@0 214 return cm->error.error_code;
michael@0 215 }
michael@0 216
michael@0 217
michael@0 218 vpx_codec_err_t vp9_set_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag,
michael@0 219 YV12_BUFFER_CONFIG *sd) {
michael@0 220 VP9D_COMP *pbi = (VP9D_COMP *) ptr;
michael@0 221 VP9_COMMON *cm = &pbi->common;
michael@0 222 int *ref_fb_ptr = NULL;
michael@0 223
michael@0 224 /* TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
michael@0 225 * encoder is using the frame buffers for. This is just a stub to keep the
michael@0 226 * vpxenc --test-decode functionality working, and will be replaced in a
michael@0 227 * later commit that adds VP9-specific controls for this functionality.
michael@0 228 */
michael@0 229 if (ref_frame_flag == VP9_LAST_FLAG) {
michael@0 230 ref_fb_ptr = &pbi->common.active_ref_idx[0];
michael@0 231 } else if (ref_frame_flag == VP9_GOLD_FLAG) {
michael@0 232 ref_fb_ptr = &pbi->common.active_ref_idx[1];
michael@0 233 } else if (ref_frame_flag == VP9_ALT_FLAG) {
michael@0 234 ref_fb_ptr = &pbi->common.active_ref_idx[2];
michael@0 235 } else {
michael@0 236 vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR,
michael@0 237 "Invalid reference frame");
michael@0 238 return pbi->common.error.error_code;
michael@0 239 }
michael@0 240
michael@0 241 if (!equal_dimensions(&cm->yv12_fb[*ref_fb_ptr], sd)) {
michael@0 242 vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR,
michael@0 243 "Incorrect buffer dimensions");
michael@0 244 } else {
michael@0 245 // Find an empty frame buffer.
michael@0 246 const int free_fb = get_free_fb(cm);
michael@0 247 // Decrease fb_idx_ref_cnt since it will be increased again in
michael@0 248 // ref_cnt_fb() below.
michael@0 249 cm->fb_idx_ref_cnt[free_fb]--;
michael@0 250
michael@0 251 // Manage the reference counters and copy image.
michael@0 252 ref_cnt_fb(cm->fb_idx_ref_cnt, ref_fb_ptr, free_fb);
michael@0 253 vp8_yv12_copy_frame(sd, &cm->yv12_fb[*ref_fb_ptr]);
michael@0 254 }
michael@0 255
michael@0 256 return pbi->common.error.error_code;
michael@0 257 }
michael@0 258
michael@0 259
michael@0 260 int vp9_get_reference_dec(VP9D_PTR ptr, int index, YV12_BUFFER_CONFIG **fb) {
michael@0 261 VP9D_COMP *pbi = (VP9D_COMP *) ptr;
michael@0 262 VP9_COMMON *cm = &pbi->common;
michael@0 263
michael@0 264 if (index < 0 || index >= NUM_REF_FRAMES)
michael@0 265 return -1;
michael@0 266
michael@0 267 *fb = &cm->yv12_fb[cm->ref_frame_map[index]];
michael@0 268 return 0;
michael@0 269 }
michael@0 270
michael@0 271 /* If any buffer updating is signaled it should be done here. */
michael@0 272 static void swap_frame_buffers(VP9D_COMP *pbi) {
michael@0 273 int ref_index = 0, mask;
michael@0 274 VP9_COMMON *const cm = &pbi->common;
michael@0 275
michael@0 276 for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
michael@0 277 if (mask & 1)
michael@0 278 ref_cnt_fb(cm->fb_idx_ref_cnt, &cm->ref_frame_map[ref_index],
michael@0 279 cm->new_fb_idx);
michael@0 280 ++ref_index;
michael@0 281 }
michael@0 282
michael@0 283 cm->frame_to_show = get_frame_new_buffer(cm);
michael@0 284 cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
michael@0 285
michael@0 286 // Invalidate these references until the next frame starts.
michael@0 287 for (ref_index = 0; ref_index < 3; ref_index++)
michael@0 288 cm->active_ref_idx[ref_index] = INT_MAX;
michael@0 289 }
michael@0 290
michael@0 291 int vp9_receive_compressed_data(VP9D_PTR ptr,
michael@0 292 size_t size, const uint8_t **psource,
michael@0 293 int64_t time_stamp) {
michael@0 294 VP9D_COMP *pbi = (VP9D_COMP *) ptr;
michael@0 295 VP9_COMMON *cm = &pbi->common;
michael@0 296 const uint8_t *source = *psource;
michael@0 297 int retcode = 0;
michael@0 298
michael@0 299 /*if(pbi->ready_for_new_data == 0)
michael@0 300 return -1;*/
michael@0 301
michael@0 302 if (ptr == 0)
michael@0 303 return -1;
michael@0 304
michael@0 305 cm->error.error_code = VPX_CODEC_OK;
michael@0 306
michael@0 307 pbi->source = source;
michael@0 308 pbi->source_sz = size;
michael@0 309
michael@0 310 if (pbi->source_sz == 0) {
michael@0 311 /* This is used to signal that we are missing frames.
michael@0 312 * We do not know if the missing frame(s) was supposed to update
michael@0 313 * any of the reference buffers, but we act conservative and
michael@0 314 * mark only the last buffer as corrupted.
michael@0 315 *
michael@0 316 * TODO(jkoleszar): Error concealment is undefined and non-normative
michael@0 317 * at this point, but if it becomes so, [0] may not always be the correct
michael@0 318 * thing to do here.
michael@0 319 */
michael@0 320 if (cm->active_ref_idx[0] != INT_MAX)
michael@0 321 get_frame_ref_buffer(cm, 0)->corrupted = 1;
michael@0 322 }
michael@0 323
michael@0 324 cm->new_fb_idx = get_free_fb(cm);
michael@0 325
michael@0 326 if (setjmp(cm->error.jmp)) {
michael@0 327 cm->error.setjmp = 0;
michael@0 328
michael@0 329 /* We do not know if the missing frame(s) was supposed to update
michael@0 330 * any of the reference buffers, but we act conservative and
michael@0 331 * mark only the last buffer as corrupted.
michael@0 332 *
michael@0 333 * TODO(jkoleszar): Error concealment is undefined and non-normative
michael@0 334 * at this point, but if it becomes so, [0] may not always be the correct
michael@0 335 * thing to do here.
michael@0 336 */
michael@0 337 if (cm->active_ref_idx[0] != INT_MAX)
michael@0 338 get_frame_ref_buffer(cm, 0)->corrupted = 1;
michael@0 339
michael@0 340 if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
michael@0 341 cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
michael@0 342
michael@0 343 return -1;
michael@0 344 }
michael@0 345
michael@0 346 cm->error.setjmp = 1;
michael@0 347
michael@0 348 retcode = vp9_decode_frame(pbi, psource);
michael@0 349
michael@0 350 if (retcode < 0) {
michael@0 351 cm->error.error_code = VPX_CODEC_ERROR;
michael@0 352 cm->error.setjmp = 0;
michael@0 353 if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
michael@0 354 cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
michael@0 355 return retcode;
michael@0 356 }
michael@0 357
michael@0 358 swap_frame_buffers(pbi);
michael@0 359
michael@0 360 #if WRITE_RECON_BUFFER == 2
michael@0 361 if (cm->show_frame)
michael@0 362 write_dx_frame_to_file(cm->frame_to_show,
michael@0 363 cm->current_video_frame);
michael@0 364 else
michael@0 365 write_dx_frame_to_file(cm->frame_to_show,
michael@0 366 cm->current_video_frame + 1000);
michael@0 367 #endif
michael@0 368
michael@0 369 if (!pbi->do_loopfilter_inline) {
michael@0 370 vp9_loop_filter_frame(cm, &pbi->mb, pbi->common.lf.filter_level, 0, 0);
michael@0 371 }
michael@0 372
michael@0 373 #if WRITE_RECON_BUFFER == 2
michael@0 374 if (cm->show_frame)
michael@0 375 write_dx_frame_to_file(cm->frame_to_show,
michael@0 376 cm->current_video_frame + 2000);
michael@0 377 else
michael@0 378 write_dx_frame_to_file(cm->frame_to_show,
michael@0 379 cm->current_video_frame + 3000);
michael@0 380 #endif
michael@0 381
michael@0 382 vp9_extend_frame_inner_borders(cm->frame_to_show,
michael@0 383 cm->subsampling_x,
michael@0 384 cm->subsampling_y);
michael@0 385
michael@0 386 #if WRITE_RECON_BUFFER == 1
michael@0 387 if (cm->show_frame)
michael@0 388 recon_write_yuv_frame("recon.yuv", cm->frame_to_show,
michael@0 389 cm->width, cm->height);
michael@0 390 #endif
michael@0 391
michael@0 392 vp9_clear_system_state();
michael@0 393
michael@0 394 cm->last_show_frame = cm->show_frame;
michael@0 395 if (cm->show_frame) {
michael@0 396 // current mip will be the prev_mip for the next frame
michael@0 397 MODE_INFO *temp = cm->prev_mip;
michael@0 398 MODE_INFO **temp2 = cm->prev_mi_grid_base;
michael@0 399 cm->prev_mip = cm->mip;
michael@0 400 cm->mip = temp;
michael@0 401 cm->prev_mi_grid_base = cm->mi_grid_base;
michael@0 402 cm->mi_grid_base = temp2;
michael@0 403
michael@0 404 // update the upper left visible macroblock ptrs
michael@0 405 cm->mi = cm->mip + cm->mode_info_stride + 1;
michael@0 406 cm->prev_mi = cm->prev_mip + cm->mode_info_stride + 1;
michael@0 407 cm->mi_grid_visible = cm->mi_grid_base + cm->mode_info_stride + 1;
michael@0 408 cm->prev_mi_grid_visible = cm->prev_mi_grid_base + cm->mode_info_stride + 1;
michael@0 409
michael@0 410 pbi->mb.mi_8x8 = cm->mi_grid_visible;
michael@0 411 pbi->mb.mi_8x8[0] = cm->mi;
michael@0 412
michael@0 413 cm->current_video_frame++;
michael@0 414 }
michael@0 415
michael@0 416 pbi->ready_for_new_data = 0;
michael@0 417 pbi->last_time_stamp = time_stamp;
michael@0 418 pbi->source_sz = 0;
michael@0 419
michael@0 420 cm->error.setjmp = 0;
michael@0 421 return retcode;
michael@0 422 }
michael@0 423
michael@0 424 int vp9_get_raw_frame(VP9D_PTR ptr, YV12_BUFFER_CONFIG *sd,
michael@0 425 int64_t *time_stamp, int64_t *time_end_stamp,
michael@0 426 vp9_ppflags_t *flags) {
michael@0 427 int ret = -1;
michael@0 428 VP9D_COMP *pbi = (VP9D_COMP *) ptr;
michael@0 429
michael@0 430 if (pbi->ready_for_new_data == 1)
michael@0 431 return ret;
michael@0 432
michael@0 433 /* ie no raw frame to show!!! */
michael@0 434 if (pbi->common.show_frame == 0)
michael@0 435 return ret;
michael@0 436
michael@0 437 pbi->ready_for_new_data = 1;
michael@0 438 *time_stamp = pbi->last_time_stamp;
michael@0 439 *time_end_stamp = 0;
michael@0 440
michael@0 441 #if CONFIG_VP9_POSTPROC
michael@0 442 ret = vp9_post_proc_frame(&pbi->common, sd, flags);
michael@0 443 #else
michael@0 444
michael@0 445 if (pbi->common.frame_to_show) {
michael@0 446 *sd = *pbi->common.frame_to_show;
michael@0 447 sd->y_width = pbi->common.width;
michael@0 448 sd->y_height = pbi->common.height;
michael@0 449 sd->uv_width = sd->y_width >> pbi->common.subsampling_x;
michael@0 450 sd->uv_height = sd->y_height >> pbi->common.subsampling_y;
michael@0 451
michael@0 452 ret = 0;
michael@0 453 } else {
michael@0 454 ret = -1;
michael@0 455 }
michael@0 456
michael@0 457 #endif /*!CONFIG_POSTPROC*/
michael@0 458 vp9_clear_system_state();
michael@0 459 return ret;
michael@0 460 }

mercurial