| /* |
| * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| |
| #include "onyxc_int.h" |
| #include "postproc.h" |
| #include "onyxd.h" |
| #include "onyxd_int.h" |
| #include "vpx_mem/vpx_mem.h" |
| #include "alloccommon.h" |
| #include "vpx_scale/yv12extend.h" |
| #include "loopfilter.h" |
| #include "swapyv12buffer.h" |
| #include "g_common.h" |
| #include "threading.h" |
| #include "decoderthreading.h" |
| #include <stdio.h> |
| #include "segmentation_common.h" |
| #include "quant_common.h" |
| #include "vpx_scale/vpxscale.h" |
| #include "systemdependent.h" |
| #include "vpx_ports/vpx_timer.h" |
| |
| |
| #ifndef VPX_NO_GLOBALS |
| static int init_ct = 0; |
| #else |
| # include "vpx_global_handling.h" |
| # define init_ct ((int)vpxglobalm(onyxd,init_ct)) |
| #endif |
| |
| extern void vp8_init_loop_filter(VP8_COMMON *cm); |
| |
| extern void vp8cx_init_de_quantizer(VP8D_COMP *pbi); |
| extern void init_detokenizer(VP8D_COMP *dx); |
| |
| // DEBUG code |
| void vp8_recon_write_yuv_frame(unsigned char *name, YV12_BUFFER_CONFIG *s) |
| { |
| FILE *yuv_file = fopen((char *)name, "ab"); |
| unsigned char *src = s->y_buffer; |
| int h = s->y_height; |
| |
| do |
| { |
| fwrite(src, s->y_width, 1, yuv_file); |
| src += s->y_stride; |
| } |
| while (--h); |
| |
| src = s->u_buffer; |
| h = s->uv_height; |
| |
| do |
| { |
| fwrite(src, s->uv_width, 1, yuv_file); |
| src += s->uv_stride; |
| } |
| while (--h); |
| |
| src = s->v_buffer; |
| h = s->uv_height; |
| |
| do |
| { |
| fwrite(src, s->uv_width, 1, yuv_file); |
| src += s->uv_stride; |
| } |
| while (--h); |
| |
| fclose(yuv_file); |
| } |
| |
| void vp8dx_initialize() |
| { |
| if (!init_ct++) |
| { |
| vp8_initialize_common(); |
| vp8_scale_machine_specific_config(); |
| } |
| } |
| |
| void vp8dx_shutdown() |
| { |
| if (!--init_ct) |
| { |
| vp8_shutdown_common(); |
| } |
| } |
| |
| |
| VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf) |
| { |
| VP8D_COMP *pbi = vpx_memalign(32, sizeof(VP8D_COMP)); |
| |
| if (!pbi) |
| return NULL; |
| |
| vpx_memset(pbi, 0, sizeof(VP8D_COMP)); |
| |
| vp8dx_initialize(); |
| |
| vp8_create_common(&pbi->common); |
| vp8_dmachine_specific_config(pbi); |
| |
| pbi->common.current_video_frame = 0; |
| pbi->ready_for_new_data = 1; |
| |
| pbi->CPUFreq = 0; //vp8_get_processor_freq(); |
| pbi->max_threads = oxcf->max_threads; |
| vp8_decoder_create_threads(pbi); |
| |
| //vp8cx_init_de_quantizer() is first called here. Add check in frame_init_dequantizer() to avoid |
| // unnecessary calling of vp8cx_init_de_quantizer() for every frame. |
| vp8cx_init_de_quantizer(pbi); |
| |
| { |
| VP8_COMMON *cm = &pbi->common; |
| |
| vp8_init_loop_filter(cm); |
| cm->last_frame_type = KEY_FRAME; |
| cm->last_filter_type = cm->filter_type; |
| cm->last_sharpness_level = cm->sharpness_level; |
| } |
| |
| init_detokenizer(pbi); |
| |
| return (VP8D_PTR) pbi; |
| } |
| void vp8dx_remove_decompressor(VP8D_PTR ptr) |
| { |
| VP8D_COMP *pbi = (VP8D_COMP *) ptr; |
| |
| if (!pbi) |
| return; |
| |
| vp8_decoder_remove_threads(pbi); |
| vp8_remove_common(&pbi->common); |
| vpx_free(pbi); |
| vp8dx_shutdown(); |
| |
| } |
| |
| void vp8dx_set_setting(VP8D_PTR comp, VP8D_SETTING oxst, int x) |
| { |
| VP8D_COMP *pbi = (VP8D_COMP *) comp; |
| |
| (void) pbi; |
| (void) x; |
| |
| switch (oxst) |
| { |
| case VP8D_OK: |
| break; |
| } |
| } |
| |
| int vp8dx_get_setting(VP8D_PTR comp, VP8D_SETTING oxst) |
| { |
| VP8D_COMP *pbi = (VP8D_COMP *) comp; |
| |
| (void) pbi; |
| |
| switch (oxst) |
| { |
| case VP8D_OK: |
| break; |
| } |
| |
| return -1; |
| } |
| |
| int vp8dx_get_reference(VP8D_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) |
| { |
| VP8D_COMP *pbi = (VP8D_COMP *) ptr; |
| VP8_COMMON *cm = &pbi->common; |
| |
| if (ref_frame_flag == VP8_LAST_FLAG) |
| vp8_yv12_copy_frame_ptr(&cm->last_frame, sd); |
| |
| else if (ref_frame_flag == VP8_GOLD_FLAG) |
| vp8_yv12_copy_frame_ptr(&cm->golden_frame, sd); |
| |
| else if (ref_frame_flag == VP8_ALT_FLAG) |
| vp8_yv12_copy_frame_ptr(&cm->alt_ref_frame, sd); |
| |
| else |
| return -1; |
| |
| return 0; |
| } |
| int vp8dx_set_reference(VP8D_PTR ptr, VP8_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) |
| { |
| VP8D_COMP *pbi = (VP8D_COMP *) ptr; |
| VP8_COMMON *cm = &pbi->common; |
| |
| if (ref_frame_flag == VP8_LAST_FLAG) |
| vp8_yv12_copy_frame_ptr(sd, &cm->last_frame); |
| |
| else if (ref_frame_flag == VP8_GOLD_FLAG) |
| vp8_yv12_copy_frame_ptr(sd, &cm->golden_frame); |
| |
| else if (ref_frame_flag == VP8_ALT_FLAG) |
| vp8_yv12_copy_frame_ptr(sd, &cm->alt_ref_frame); |
| |
| else |
| return -1; |
| |
| return 0; |
| } |
| int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, char *source, INT64 time_stamp) |
| { |
| VP8D_COMP *pbi = (VP8D_COMP *) ptr; |
| VP8_COMMON *cm = &pbi->common; |
| int retcode = 0; |
| |
| struct vpx_usec_timer timer; |
| (void) size; |
| |
| // if(pbi->ready_for_new_data == 0) |
| // return -1; |
| |
| vpx_usec_timer_start(&timer); |
| |
| if (ptr == 0) |
| { |
| return -1; |
| } |
| |
| //cm->current_video_frame++; |
| pbi->Source = source; |
| |
| retcode = vp8_decode_frame(pbi); |
| |
| if (retcode < 0) |
| return retcode; |
| |
| // Update the GF useage maps. |
| vp8_update_gf_useage_maps(cm, &pbi->mb); |
| |
| if (pbi->b_multithreaded) |
| vp8_stop_lfthread(pbi); |
| |
| if (cm->refresh_last_frame) |
| { |
| vp8_swap_yv12_buffer(&cm->last_frame, &cm->new_frame); |
| |
| cm->frame_to_show = &cm->last_frame; |
| } |
| else |
| { |
| cm->frame_to_show = &cm->new_frame; |
| } |
| |
| if (!pbi->b_multithreaded) |
| { |
| struct vpx_usec_timer lpftimer; |
| vpx_usec_timer_start(&lpftimer); |
| // Apply the loop filter if appropriate. |
| |
| if (cm->filter_level > 0) |
| { |
| vp8_loop_filter_frame(cm, &pbi->mb, cm->filter_level); |
| cm->last_frame_type = cm->frame_type; |
| cm->last_filter_type = cm->filter_type; |
| cm->last_sharpness_level = cm->sharpness_level; |
| |
| } |
| |
| vpx_usec_timer_mark(&lpftimer); |
| pbi->time_loop_filtering += vpx_usec_timer_elapsed(&lpftimer); |
| } |
| |
| vp8_yv12_extend_frame_borders_ptr(cm->frame_to_show); |
| |
| #if 0 |
| // DEBUG code |
| //vp8_recon_write_yuv_frame("recon.yuv", cm->frame_to_show); |
| if (cm->current_video_frame <= 5) |
| write_dx_frame_to_file(cm->frame_to_show, cm->current_video_frame); |
| #endif |
| |
| // If any buffer copy / swaping is signalled it should be done here. |
| if (cm->copy_buffer_to_arf) |
| { |
| if (cm->copy_buffer_to_arf == 1) |
| { |
| if (cm->refresh_last_frame) |
| vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->alt_ref_frame); |
| else |
| vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->alt_ref_frame); |
| } |
| else if (cm->copy_buffer_to_arf == 2) |
| vp8_yv12_copy_frame_ptr(&cm->golden_frame, &cm->alt_ref_frame); |
| } |
| |
| if (cm->copy_buffer_to_gf) |
| { |
| if (cm->copy_buffer_to_gf == 1) |
| { |
| if (cm->refresh_last_frame) |
| vp8_yv12_copy_frame_ptr(&cm->new_frame, &cm->golden_frame); |
| else |
| vp8_yv12_copy_frame_ptr(&cm->last_frame, &cm->golden_frame); |
| } |
| else if (cm->copy_buffer_to_gf == 2) |
| vp8_yv12_copy_frame_ptr(&cm->alt_ref_frame, &cm->golden_frame); |
| } |
| |
| // Should the golden or alternate reference frame be refreshed? |
| if (cm->refresh_golden_frame || cm->refresh_alt_ref_frame) |
| { |
| if (cm->refresh_golden_frame) |
| vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->golden_frame); |
| |
| if (cm->refresh_alt_ref_frame) |
| vp8_yv12_copy_frame_ptr(cm->frame_to_show, &cm->alt_ref_frame); |
| |
| //vpx_log("Decoder: recovery frame received \n"); |
| |
| // Update data structures that monitors GF useage |
| vpx_memset(cm->gf_active_flags, 1, (cm->mb_rows * cm->mb_cols)); |
| cm->gf_active_count = cm->mb_rows * cm->mb_cols; |
| } |
| |
| vp8_clear_system_state(); |
| |
| vpx_usec_timer_mark(&timer); |
| pbi->decode_microseconds = vpx_usec_timer_elapsed(&timer); |
| |
| pbi->time_decoding += pbi->decode_microseconds; |
| |
| // vp8_print_modes_and_motion_vectors( cm->mi, cm->mb_rows,cm->mb_cols, cm->current_video_frame); |
| |
| cm->current_video_frame++; |
| pbi->ready_for_new_data = 0; |
| pbi->last_time_stamp = time_stamp; |
| |
| { |
| int i; |
| INT64 earliest_time = pbi->dr[0].time_stamp; |
| INT64 latest_time = pbi->dr[0].time_stamp; |
| INT64 time_diff = 0; |
| int bytes = 0; |
| |
| pbi->dr[pbi->common.current_video_frame&0xf].size = pbi->bc.pos + pbi->bc2.pos + 4;; |
| pbi->dr[pbi->common.current_video_frame&0xf].time_stamp = time_stamp; |
| |
| for (i = 0; i < 16; i++) |
| { |
| |
| bytes += pbi->dr[i].size; |
| |
| if (pbi->dr[i].time_stamp < earliest_time) |
| earliest_time = pbi->dr[i].time_stamp; |
| |
| if (pbi->dr[i].time_stamp > latest_time) |
| latest_time = pbi->dr[i].time_stamp; |
| } |
| |
| time_diff = latest_time - earliest_time; |
| |
| if (time_diff > 0) |
| { |
| pbi->common.bitrate = 80000.00 * bytes / time_diff ; |
| pbi->common.framerate = 160000000.00 / time_diff ; |
| } |
| |
| } |
| return retcode; |
| } |
| int 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) |
| { |
| int ret = -1; |
| VP8D_COMP *pbi = (VP8D_COMP *) ptr; |
| |
| if (pbi->ready_for_new_data == 1) |
| return ret; |
| |
| // ie no raw frame to show!!! |
| if (pbi->common.show_frame == 0) |
| return ret; |
| |
| pbi->ready_for_new_data = 1; |
| *time_stamp = pbi->last_time_stamp; |
| *time_end_stamp = 0; |
| |
| sd->clrtype = pbi->common.clr_type; |
| ret = vp8_post_proc_frame(&pbi->common, sd, deblock_level, noise_level, flags); |
| vp8_clear_system_state(); |
| return ret; |
| } |