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 #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
     37 static 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
     70 void 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 
    103 void 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 
    113 VP9D_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 
    155 void 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 
    179 static 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 
    185 vpx_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 
    212 vpx_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 
    255 int 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. */
    266 static 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 
    290 int 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 
    406 int 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