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