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 12#include "onyxc_int.h" 13#if CONFIG_POSTPROC 14#include "postproc.h" 15#endif 16#include "onyxd.h" 17#include "onyxd_int.h" 18#include "vpx_mem/vpx_mem.h" 19#include "alloccommon.h" 20#include "vpx_scale/yv12extend.h" 21#include "loopfilter.h" 22#include "swapyv12buffer.h" 23#include "g_common.h" 24#include "threading.h" 25#include "decoderthreading.h" 26#include <stdio.h> 27 28#include "quant_common.h" 29#include "vpx_scale/vpxscale.h" 30#include "systemdependent.h" 31#include "vpx_ports/vpx_timer.h" 32#include "detokenize.h" 33#if ARCH_ARM 34#include "vpx_ports/arm.h" 35#endif 36 37extern void vp8_init_loop_filter(VP8_COMMON *cm); 38extern void vp8cx_init_de_quantizer(VP8D_COMP *pbi); 39 40#if CONFIG_DEBUG 41void vp8_recon_write_yuv_frame(unsigned char *name, YV12_BUFFER_CONFIG *s) 42{ 43 FILE *yuv_file = fopen((char *)name, "ab"); 44 unsigned char *src = s->y_buffer; 45 int h = s->y_height; 46 47 do 48 { 49 fwrite(src, s->y_width, 1, yuv_file); 50 src += s->y_stride; 51 } 52 while (--h); 53 54 src = s->u_buffer; 55 h = s->uv_height; 56 57 do 58 { 59 fwrite(src, s->uv_width, 1, yuv_file); 60 src += s->uv_stride; 61 } 62 while (--h); 63 64 src = s->v_buffer; 65 h = s->uv_height; 66 67 do 68 { 69 fwrite(src, s->uv_width, 1, yuv_file); 70 src += s->uv_stride; 71 } 72 while (--h); 73 74 fclose(yuv_file); 75} 76#endif 77 78void vp8dx_initialize() 79{ 80 static int init_done = 0; 81 82 if (!init_done) 83 { 84 vp8_initialize_common(); 85 vp8_scale_machine_specific_config(); 86 init_done = 1; 87 } 88} 89 90 91VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf) 92{ 93 VP8D_COMP *pbi = vpx_memalign(32, sizeof(VP8D_COMP)); 94 95 if (!pbi) 96 return NULL; 97 98 vpx_memset(pbi, 0, sizeof(VP8D_COMP)); 99 100 if (setjmp(pbi->common.error.jmp)) 101 { 102 pbi->common.error.setjmp = 0; 103 vp8dx_remove_decompressor(pbi); 104 return 0; 105 } 106 107 pbi->common.error.setjmp = 1; 108 vp8dx_initialize(); 109 110 vp8_create_common(&pbi->common); 111 vp8_dmachine_specific_config(pbi); 112 113 pbi->common.current_video_frame = 0; 114 pbi->ready_for_new_data = 1; 115 116 pbi->CPUFreq = 0; /*vp8_get_processor_freq();*/ 117 pbi->max_threads = oxcf->max_threads; 118 vp8_decoder_create_threads(pbi); 119 120 /* vp8cx_init_de_quantizer() is first called here. Add check in frame_init_dequantizer() to avoid 121 * unnecessary calling of vp8cx_init_de_quantizer() for every frame. 122 */ 123 vp8cx_init_de_quantizer(pbi); 124 125 { 126 VP8_COMMON *cm = &pbi->common; 127 128 vp8_init_loop_filter(cm); 129 cm->last_frame_type = KEY_FRAME; 130 cm->last_filter_type = cm->filter_type; 131 cm->last_sharpness_level = cm->sharpness_level; 132 } 133 134#if CONFIG_ARM_ASM_DETOK 135 vp8_init_detokenizer(pbi); 136#endif 137 pbi->common.error.setjmp = 0; 138 return (VP8D_PTR) pbi; 139} 140 141 142void vp8dx_remove_decompressor(VP8D_PTR ptr) 143{ 144 VP8D_COMP *pbi = (VP8D_COMP *) ptr; 145 146 if (!pbi) 147 return; 148 149#if CONFIG_MULTITHREAD 150 if (pbi->b_multithreaded_rd) 151 vp8mt_de_alloc_temp_buffers(pbi, pbi->common.mb_rows); 152#endif 153 vp8_decoder_remove_threads(pbi); 154 vp8_remove_common(&pbi->common); 155 vpx_free(pbi); 156} 157 158 159void vp8dx_set_setting(VP8D_PTR comp, VP8D_SETTING oxst, int x) 160{ 161 VP8D_COMP *pbi = (VP8D_COMP *) comp; 162 163 (void) pbi; 164 (void) x; 165 166 switch (oxst) 167 { 168 case VP8D_OK: 169 break; 170 } 171} 172 173int vp8dx_get_setting(VP8D_PTR comp, VP8D_SETTING oxst) 174{ 175 VP8D_COMP *pbi = (VP8D_COMP *) comp; 176 177 (void) pbi; 178 179 switch (oxst) 180 { 181 case VP8D_OK: 182 break; 183 } 184 185 return -1; 186} 187 188int vp8dx_get_reference(VP8D_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) 189{ 190 VP8D_COMP *pbi = (VP8D_COMP *) ptr; 191 VP8_COMMON *cm = &pbi->common; 192 int ref_fb_idx; 193 194 if (ref_frame_flag == VP8_LAST_FLAG) 195 ref_fb_idx = cm->lst_fb_idx; 196 else if (ref_frame_flag == VP8_GOLD_FLAG) 197 ref_fb_idx = cm->gld_fb_idx; 198 else if (ref_frame_flag == VP8_ALT_FLAG) 199 ref_fb_idx = cm->alt_fb_idx; 200 else 201 return -1; 202 203 vp8_yv12_copy_frame_ptr(&cm->yv12_fb[ref_fb_idx], sd); 204 205 return 0; 206} 207int vp8dx_set_reference(VP8D_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) 208{ 209 VP8D_COMP *pbi = (VP8D_COMP *) ptr; 210 VP8_COMMON *cm = &pbi->common; 211 int ref_fb_idx; 212 213 if (ref_frame_flag == VP8_LAST_FLAG) 214 ref_fb_idx = cm->lst_fb_idx; 215 else if (ref_frame_flag == VP8_GOLD_FLAG) 216 ref_fb_idx = cm->gld_fb_idx; 217 else if (ref_frame_flag == VP8_ALT_FLAG) 218 ref_fb_idx = cm->alt_fb_idx; 219 else 220 return -1; 221 222 vp8_yv12_copy_frame_ptr(sd, &cm->yv12_fb[ref_fb_idx]); 223 224 return 0; 225} 226 227/*For ARM NEON, d8-d15 are callee-saved registers, and need to be saved by us.*/ 228#if HAVE_ARMV7 229extern void vp8_push_neon(INT64 *store); 230extern void vp8_pop_neon(INT64 *store); 231#endif 232 233static int get_free_fb (VP8_COMMON *cm) 234{ 235 int i; 236 for (i = 0; i < NUM_YV12_BUFFERS; i++) 237 if (cm->fb_idx_ref_cnt[i] == 0) 238 break; 239 240 cm->fb_idx_ref_cnt[i] = 1; 241 return i; 242} 243 244static void ref_cnt_fb (int *buf, int *idx, int new_idx) 245{ 246 if (buf[*idx] > 0) 247 buf[*idx]--; 248 249 *idx = new_idx; 250 251 buf[new_idx]++; 252} 253 254/* If any buffer copy / swapping is signalled it should be done here. */ 255static int swap_frame_buffers (VP8_COMMON *cm) 256{ 257 int fb_to_update_with, err = 0; 258 259 if (cm->refresh_last_frame) 260 fb_to_update_with = cm->lst_fb_idx; 261 else 262 fb_to_update_with = cm->new_fb_idx; 263 264 /* The alternate reference frame or golden frame can be updated 265 * using the new, last, or golden/alt ref frame. If it 266 * is updated using the newly decoded frame it is a refresh. 267 * An update using the last or golden/alt ref frame is a copy. 268 */ 269 if (cm->copy_buffer_to_arf) 270 { 271 int new_fb = 0; 272 273 if (cm->copy_buffer_to_arf == 1) 274 new_fb = fb_to_update_with; 275 else if (cm->copy_buffer_to_arf == 2) 276 new_fb = cm->gld_fb_idx; 277 else 278 err = -1; 279 280 ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->alt_fb_idx, new_fb); 281 } 282 283 if (cm->copy_buffer_to_gf) 284 { 285 int new_fb = 0; 286 287 if (cm->copy_buffer_to_gf == 1) 288 new_fb = fb_to_update_with; 289 else if (cm->copy_buffer_to_gf == 2) 290 new_fb = cm->alt_fb_idx; 291 else 292 err = -1; 293 294 ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->gld_fb_idx, new_fb); 295 } 296 297 if (cm->refresh_golden_frame) 298 ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->gld_fb_idx, cm->new_fb_idx); 299 300 if (cm->refresh_alt_ref_frame) 301 ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->alt_fb_idx, cm->new_fb_idx); 302 303 if (cm->refresh_last_frame) 304 { 305 ref_cnt_fb (cm->fb_idx_ref_cnt, &cm->lst_fb_idx, cm->new_fb_idx); 306 307 cm->frame_to_show = &cm->yv12_fb[cm->lst_fb_idx]; 308 } 309 else 310 cm->frame_to_show = &cm->yv12_fb[cm->new_fb_idx]; 311 312 cm->fb_idx_ref_cnt[cm->new_fb_idx]--; 313 314 return err; 315} 316 317int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsigned char *source, INT64 time_stamp) 318{ 319#if HAVE_ARMV7 320 INT64 dx_store_reg[8]; 321#endif 322 VP8D_COMP *pbi = (VP8D_COMP *) ptr; 323 VP8_COMMON *cm = &pbi->common; 324 int retcode = 0; 325 struct vpx_usec_timer timer; 326 327 /*if(pbi->ready_for_new_data == 0) 328 return -1;*/ 329 330 if (ptr == 0) 331 { 332 return -1; 333 } 334 335 pbi->common.error.error_code = VPX_CODEC_OK; 336 337#if HAVE_ARMV7 338#if CONFIG_RUNTIME_CPU_DETECT 339 if (cm->rtcd.flags & HAS_NEON) 340#endif 341 { 342 vp8_push_neon(dx_store_reg); 343 } 344#endif 345 346 cm->new_fb_idx = get_free_fb (cm); 347 348 if (setjmp(pbi->common.error.jmp)) 349 { 350#if HAVE_ARMV7 351#if CONFIG_RUNTIME_CPU_DETECT 352 if (cm->rtcd.flags & HAS_NEON) 353#endif 354 { 355 vp8_pop_neon(dx_store_reg); 356 } 357#endif 358 pbi->common.error.setjmp = 0; 359 if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0) 360 cm->fb_idx_ref_cnt[cm->new_fb_idx]--; 361 return -1; 362 } 363 364 pbi->common.error.setjmp = 1; 365 366 vpx_usec_timer_start(&timer); 367 368 /*cm->current_video_frame++;*/ 369 pbi->Source = source; 370 pbi->source_sz = size; 371 372 retcode = vp8_decode_frame(pbi); 373 374 if (retcode < 0) 375 { 376#if HAVE_ARMV7 377#if CONFIG_RUNTIME_CPU_DETECT 378 if (cm->rtcd.flags & HAS_NEON) 379#endif 380 { 381 vp8_pop_neon(dx_store_reg); 382 } 383#endif 384 pbi->common.error.error_code = VPX_CODEC_ERROR; 385 pbi->common.error.setjmp = 0; 386 if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0) 387 cm->fb_idx_ref_cnt[cm->new_fb_idx]--; 388 return retcode; 389 } 390 391 if (pbi->b_multithreaded_rd && cm->multi_token_partition != ONE_PARTITION) 392 { 393 if (swap_frame_buffers (cm)) 394 { 395#if HAVE_ARMV7 396#if CONFIG_RUNTIME_CPU_DETECT 397 if (cm->rtcd.flags & HAS_NEON) 398#endif 399 { 400 vp8_pop_neon(dx_store_reg); 401 } 402#endif 403 pbi->common.error.error_code = VPX_CODEC_ERROR; 404 pbi->common.error.setjmp = 0; 405 return -1; 406 } 407 } else 408 { 409 if (swap_frame_buffers (cm)) 410 { 411#if HAVE_ARMV7 412#if CONFIG_RUNTIME_CPU_DETECT 413 if (cm->rtcd.flags & HAS_NEON) 414#endif 415 { 416 vp8_pop_neon(dx_store_reg); 417 } 418#endif 419 pbi->common.error.error_code = VPX_CODEC_ERROR; 420 pbi->common.error.setjmp = 0; 421 return -1; 422 } 423 424 if(pbi->common.filter_level) 425 { 426 struct vpx_usec_timer lpftimer; 427 vpx_usec_timer_start(&lpftimer); 428 /* Apply the loop filter if appropriate. */ 429 430 vp8_loop_filter_frame(cm, &pbi->mb, cm->filter_level); 431 432 vpx_usec_timer_mark(&lpftimer); 433 pbi->time_loop_filtering += vpx_usec_timer_elapsed(&lpftimer); 434 435 cm->last_frame_type = cm->frame_type; 436 cm->last_filter_type = cm->filter_type; 437 cm->last_sharpness_level = cm->sharpness_level; 438 } 439 vp8_yv12_extend_frame_borders_ptr(cm->frame_to_show); 440 } 441 442#if 0 443 /* DEBUG code */ 444 /*vp8_recon_write_yuv_frame("recon.yuv", cm->frame_to_show);*/ 445 if (cm->current_video_frame <= 5) 446 write_dx_frame_to_file(cm->frame_to_show, cm->current_video_frame); 447#endif 448 449 vp8_clear_system_state(); 450 451 vpx_usec_timer_mark(&timer); 452 pbi->decode_microseconds = vpx_usec_timer_elapsed(&timer); 453 454 pbi->time_decoding += pbi->decode_microseconds; 455 456 /*vp8_print_modes_and_motion_vectors( cm->mi, cm->mb_rows,cm->mb_cols, cm->current_video_frame);*/ 457 458 if (cm->show_frame) 459 cm->current_video_frame++; 460 461 pbi->ready_for_new_data = 0; 462 pbi->last_time_stamp = time_stamp; 463 464#if 0 465 { 466 int i; 467 INT64 earliest_time = pbi->dr[0].time_stamp; 468 INT64 latest_time = pbi->dr[0].time_stamp; 469 INT64 time_diff = 0; 470 int bytes = 0; 471 472 pbi->dr[pbi->common.current_video_frame&0xf].size = pbi->bc.pos + pbi->bc2.pos + 4;; 473 pbi->dr[pbi->common.current_video_frame&0xf].time_stamp = time_stamp; 474 475 for (i = 0; i < 16; i++) 476 { 477 478 bytes += pbi->dr[i].size; 479 480 if (pbi->dr[i].time_stamp < earliest_time) 481 earliest_time = pbi->dr[i].time_stamp; 482 483 if (pbi->dr[i].time_stamp > latest_time) 484 latest_time = pbi->dr[i].time_stamp; 485 } 486 487 time_diff = latest_time - earliest_time; 488 489 if (time_diff > 0) 490 { 491 pbi->common.bitrate = 80000.00 * bytes / time_diff ; 492 pbi->common.framerate = 160000000.00 / time_diff ; 493 } 494 495 } 496#endif 497 498#if HAVE_ARMV7 499#if CONFIG_RUNTIME_CPU_DETECT 500 if (cm->rtcd.flags & HAS_NEON) 501#endif 502 { 503 vp8_pop_neon(dx_store_reg); 504 } 505#endif 506 pbi->common.error.setjmp = 0; 507 return retcode; 508} 509int vp8dx_get_raw_frame(VP8D_PTR ptr, YV12_BUFFER_CONFIG *sd, INT64 *time_stamp, INT64 *time_end_stamp, int deblock_level, int noise_level, int flags) 510{ 511 int ret = -1; 512 VP8D_COMP *pbi = (VP8D_COMP *) ptr; 513 514 if (pbi->ready_for_new_data == 1) 515 return ret; 516 517 /* ie no raw frame to show!!! */ 518 if (pbi->common.show_frame == 0) 519 return ret; 520 521 pbi->ready_for_new_data = 1; 522 *time_stamp = pbi->last_time_stamp; 523 *time_end_stamp = 0; 524 525 sd->clrtype = pbi->common.clr_type; 526#if CONFIG_POSTPROC 527 ret = vp8_post_proc_frame(&pbi->common, sd, deblock_level, noise_level, flags); 528#else 529 530 if (pbi->common.frame_to_show) 531 { 532 *sd = *pbi->common.frame_to_show; 533 sd->y_width = pbi->common.Width; 534 sd->y_height = pbi->common.Height; 535 sd->uv_height = pbi->common.Height / 2; 536 ret = 0; 537 } 538 else 539 { 540 ret = -1; 541 } 542 543#endif /*!CONFIG_POSTPROC*/ 544 vp8_clear_system_state(); 545 return ret; 546} 547