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