Beispiel #1
0
static void create_enc_workers(VP9_COMP *cpi, int num_workers) {
  VP9_COMMON *const cm = &cpi->common;
  const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
  int i;

  // Only run once to create threads and allocate thread data.
  if (cpi->num_workers == 0) {
    int allocated_workers = num_workers;

    // While using SVC, we need to allocate threads according to the highest
    // resolution. When row based multithreading is enabled, it is OK to
    // allocate more threads than the number of max tile columns.
    if (cpi->use_svc && !cpi->row_mt) {
      int max_tile_cols = get_max_tile_cols(cpi);
      allocated_workers = VPXMIN(cpi->oxcf.max_threads, max_tile_cols);
    }

    CHECK_MEM_ERROR(cm, cpi->workers,
                    vpx_malloc(allocated_workers * sizeof(*cpi->workers)));

    CHECK_MEM_ERROR(cm, cpi->tile_thr_data,
                    vpx_calloc(allocated_workers, sizeof(*cpi->tile_thr_data)));

    for (i = 0; i < allocated_workers; i++) {
      VPxWorker *const worker = &cpi->workers[i];
      EncWorkerData *thread_data = &cpi->tile_thr_data[i];

      ++cpi->num_workers;
      winterface->init(worker);

      if (i < allocated_workers - 1) {
        thread_data->cpi = cpi;

        // Allocate thread data.
        CHECK_MEM_ERROR(cm, thread_data->td,
                        vpx_memalign(32, sizeof(*thread_data->td)));
        vp9_zero(*thread_data->td);

        // Set up pc_tree.
        thread_data->td->leaf_tree = NULL;
        thread_data->td->pc_tree = NULL;
        vp9_setup_pc_tree(cm, thread_data->td);

        // Allocate frame counters in thread data.
        CHECK_MEM_ERROR(cm, thread_data->td->counts,
                        vpx_calloc(1, sizeof(*thread_data->td->counts)));

        // Create threads
        if (!winterface->reset(worker))
          vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
                             "Tile encoder thread creation failed");
      } else {
        // Main thread acts as a worker and uses the thread data in cpi.
        thread_data->cpi = cpi;
        thread_data->td = &cpi->td;
      }
      winterface->sync(worker);
    }
  }
}
static vpx_codec_err_t decoder_init(vpx_codec_ctx_t *ctx,
                            vpx_codec_priv_enc_mr_cfg_t *data) {
  // This function only allocates space for the vpx_codec_alg_priv_t
  // structure. More memory may be required at the time the stream
  // information becomes known.
  if (!ctx->priv) {
    vpx_codec_alg_priv_t *alg_priv = vpx_memalign(32, sizeof(*alg_priv));
    if (alg_priv == NULL)
      return VPX_CODEC_MEM_ERROR;

    vp9_zero(*alg_priv);

    ctx->priv = (vpx_codec_priv_t *)alg_priv;
    ctx->priv->sz = sizeof(*ctx->priv);
    ctx->priv->iface = ctx->iface;
    ctx->priv->alg_priv = alg_priv;
    ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
    ctx->priv->init_flags = ctx->init_flags;

    if (ctx->config.dec) {
      // Update the reference to the config structure to an internal copy.
      ctx->priv->alg_priv->cfg = *ctx->config.dec;
      ctx->config.dec = &ctx->priv->alg_priv->cfg;
    }
  }

  return VPX_CODEC_OK;
}
// Deallocate lf synchronization related mutex and data
void vp9_loop_filter_dealloc(VP9LfSync *lf_sync, int rows) {
#if !CONFIG_MULTITHREAD
  (void)rows;
#endif  // !CONFIG_MULTITHREAD

  if (lf_sync != NULL) {
#if CONFIG_MULTITHREAD
    int i;

    if (lf_sync->mutex_ != NULL) {
      for (i = 0; i < rows; ++i) {
        pthread_mutex_destroy(&lf_sync->mutex_[i]);
      }
      vpx_free(lf_sync->mutex_);
    }
    if (lf_sync->cond_ != NULL) {
      for (i = 0; i < rows; ++i) {
        pthread_cond_destroy(&lf_sync->cond_[i]);
      }
      vpx_free(lf_sync->cond_);
    }
#endif  // CONFIG_MULTITHREAD
    vpx_free(lf_sync->cur_sb_col);
    // clear the structure as the source of this call may be a resize in which
    // case this call will be followed by an _alloc() which may fail.
    vp9_zero(*lf_sync);
  }
}
Beispiel #4
0
// Deallocate row based multi-threading synchronization related mutex and data
void vp9_row_mt_sync_mem_dealloc(VP9RowMTSync *row_mt_sync) {
  if (row_mt_sync != NULL) {
#if CONFIG_MULTITHREAD
    int i;

    if (row_mt_sync->mutex_ != NULL) {
      for (i = 0; i < row_mt_sync->rows; ++i) {
        pthread_mutex_destroy(&row_mt_sync->mutex_[i]);
      }
      vpx_free(row_mt_sync->mutex_);
    }
    if (row_mt_sync->cond_ != NULL) {
      for (i = 0; i < row_mt_sync->rows; ++i) {
        pthread_cond_destroy(&row_mt_sync->cond_[i]);
      }
      vpx_free(row_mt_sync->cond_);
    }
#endif  // CONFIG_MULTITHREAD
    vpx_free(row_mt_sync->cur_col);
    // clear the structure as the source of this call may be dynamic change
    // in tiles in which case this call will be followed by an _alloc()
    // which may fail.
    vp9_zero(*row_mt_sync);
  }
}
Beispiel #5
0
void vp9_setup_past_independence(VP9_COMMON *cm) {
  // Reset the segment feature data to the default stats:
  // Features disabled, 0, with delta coding (Default state).
  struct loopfilter *const lf = &cm->lf;

  int i;
  vp9_clearall_segfeatures(&cm->seg);
  cm->seg.abs_delta = SEGMENT_DELTADATA;

  if (cm->last_frame_seg_map && !cm->frame_parallel_decode)
    memset(cm->last_frame_seg_map, 0, (cm->mi_rows * cm->mi_cols));

  if (cm->current_frame_seg_map)
    memset(cm->current_frame_seg_map, 0, (cm->mi_rows * cm->mi_cols));

  // Reset the mode ref deltas for loop filter
  vp9_zero(lf->last_ref_deltas);
  vp9_zero(lf->last_mode_deltas);
  set_default_lf_deltas(lf);

  // To force update of the sharpness
  lf->last_sharpness_level = -1;

  vp9_default_coef_probs(cm);
  init_mode_probs(cm->fc);
  vp9_init_mv_probs(cm);
  cm->fc->initialized = 1;

  if (cm->frame_type == KEY_FRAME ||
      cm->error_resilient_mode || cm->reset_frame_context == 3) {
    // Reset all frame contexts.
    for (i = 0; i < FRAME_CONTEXTS; ++i)
      cm->frame_contexts[i] = *cm->fc;
  } else if (cm->reset_frame_context == 2) {
    // Reset only the frame context specified in the frame header.
    cm->frame_contexts[cm->frame_context_idx] = *cm->fc;
  }

  // prev_mip will only be allocated in encoder.
  if (frame_is_intra_only(cm) && cm->prev_mip && !cm->frame_parallel_decode)
    memset(cm->prev_mip, 0,
           cm->mi_stride * (cm->mi_rows + 1) * sizeof(*cm->prev_mip));

  vp9_zero(cm->ref_frame_sign_bias);

  cm->frame_context_idx = 0;
}
void vp9_setup_past_independence(VP9_COMMON *cm) {
  // Reset the segment feature data to the default stats:
  // Features disabled, 0, with delta coding (Default state).
  struct loopfilter *const lf = &cm->lf;

  int i;
  vp9_clearall_segfeatures(&cm->seg);
  cm->seg.abs_delta = SEGMENT_DELTADATA;
  if (cm->last_frame_seg_map)
    vpx_memset(cm->last_frame_seg_map, 0, (cm->mi_rows * cm->mi_cols));

  // Reset the mode ref deltas for loop filter
  vp9_zero(lf->last_ref_deltas);
  vp9_zero(lf->last_mode_deltas);
  set_default_lf_deltas(lf);

  // To force update of the sharpness
  lf->last_sharpness_level = -1;

  vp9_default_coef_probs(cm);
  vp9_init_mbmode_probs(cm);
  vp9_init_mv_probs(cm);
  vp9_copy(cm->fc.inter_mode_probs, default_inter_mode_probs);

  if (cm->frame_type == KEY_FRAME ||
      cm->error_resilient_mode || cm->reset_frame_context == 3) {
    // Reset all frame contexts.
    for (i = 0; i < NUM_FRAME_CONTEXTS; ++i)
      cm->frame_contexts[i] = cm->fc;
  } else if (cm->reset_frame_context == 2) {
    // Reset only the frame context specified in the frame header.
    cm->frame_contexts[cm->frame_context_idx] = cm->fc;
  }

  vpx_memset(cm->prev_mip, 0,
             cm->mode_info_stride * (cm->mi_rows + 1) * sizeof(MODE_INFO));
  vpx_memset(cm->mip, 0,
             cm->mode_info_stride * (cm->mi_rows + 1) * sizeof(MODE_INFO));

  vp9_update_mode_info_border(cm, cm->mip);
  vp9_update_mode_info_border(cm, cm->prev_mip);

  vp9_zero(cm->ref_frame_sign_bias);

  cm->frame_context_idx = 0;
}
Beispiel #7
0
VP9Decoder *vp9_decoder_create() {
  VP9Decoder *const pbi = vpx_memalign(32, sizeof(*pbi));
  VP9_COMMON *const cm = pbi ? &pbi->common : NULL;

  if (!cm)
    return NULL;

  vp9_zero(*pbi);

  if (setjmp(cm->error.jmp)) {
    cm->error.setjmp = 0;
    vp9_decoder_remove(pbi);
    return NULL;
  }

  cm->error.setjmp = 1;

  CHECK_MEM_ERROR(cm, cm->fc,
                  (FRAME_CONTEXT *)vpx_calloc(1, sizeof(*cm->fc)));
  CHECK_MEM_ERROR(cm, cm->frame_contexts,
                  (FRAME_CONTEXT *)vpx_calloc(FRAME_CONTEXTS,
                  sizeof(*cm->frame_contexts)));

  pbi->need_resync = 1;
  initialize_dec();

  // Initialize the references to not point to any frame buffers.
  vpx_memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));

  cm->current_video_frame = 0;
  pbi->ready_for_new_data = 1;
  cm->bit_depth = VPX_BITS_8;
  cm->dequant_bit_depth = VPX_BITS_8;

  cm->alloc_mi = vp9_dec_alloc_mi;
  cm->free_mi = vp9_dec_free_mi;
  cm->setup_mi = vp9_dec_setup_mi;

  // vp9_init_dequantizer() is first called here. Add check in
  // frame_init_dequantizer() to avoid unnecessary calling of
  // vp9_init_dequantizer() for every frame.
  vp9_init_dequantizer(cm);

  vp9_loop_filter_init(cm);

  cm->error.setjmp = 0;

  vp9_get_worker_interface()->init(&pbi->lf_worker);

  return pbi;
}
VP9Decoder *vp9_decoder_create(BufferPool *const pool) {
  VP9Decoder *volatile const pbi = vpx_memalign(32, sizeof(*pbi));
  VP9_COMMON *volatile const cm = pbi ? &pbi->common : NULL;

  if (!cm)
    return NULL;

  vp9_zero(*pbi);

  if (setjmp(cm->error.jmp)) {
    cm->error.setjmp = 0;
    vp9_decoder_remove(pbi);
    return NULL;
  }

  cm->error.setjmp = 1;

  CHECK_MEM_ERROR(cm, cm->fc,
                  (FRAME_CONTEXT *)vpx_calloc(1, sizeof(*cm->fc)));
  CHECK_MEM_ERROR(cm, cm->frame_contexts,
                  (FRAME_CONTEXT *)vpx_calloc(FRAME_CONTEXTS,
                  sizeof(*cm->frame_contexts)));

  pbi->need_resync = 1;
  once(initialize_dec);

  // Initialize the references to not point to any frame buffers.
  memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));
  memset(&cm->next_ref_frame_map, -1, sizeof(cm->next_ref_frame_map));

  cm->current_video_frame = 0;
  pbi->ready_for_new_data = 1;
  pbi->common.buffer_pool = pool;

  cm->bit_depth = VPX_BITS_8;
  cm->dequant_bit_depth = VPX_BITS_8;

  cm->alloc_mi = vp9_dec_alloc_mi;
  cm->free_mi = vp9_dec_free_mi;
  cm->setup_mi = vp9_dec_setup_mi;

  vp9_loop_filter_init(cm);

  cm->error.setjmp = 0;

  vpx_get_worker_interface()->init(&pbi->lf_worker);

  return pbi;
}
Beispiel #9
0
void init_context_counters(void) {
  FILE *f = fopen("context.bin", "rb");
  if (!f) {
    vp9_zero(context_counters);
  } else {
    fread(context_counters, sizeof(context_counters), 1, f);
    fclose(f);
  }

  f = fopen("treeupdate.bin", "rb");
  if (!f) {
    vpx_memset(tree_update_hist, 0, sizeof(tree_update_hist));
  } else {
    fread(tree_update_hist, sizeof(tree_update_hist), 1, f);
    fclose(f);
  }
}
static void write_modes(VP9_COMP *cpi,
                        const TileInfo *const tile, vpx_writer *w,
                        TOKENEXTRA **tok, const TOKENEXTRA *const tok_end) {
  const VP9_COMMON *const cm = &cpi->common;
  MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
  int mi_row, mi_col;

  set_partition_probs(cm, xd);

  for (mi_row = tile->mi_row_start; mi_row < tile->mi_row_end;
       mi_row += MI_BLOCK_SIZE) {
    vp9_zero(xd->left_seg_context);
    for (mi_col = tile->mi_col_start; mi_col < tile->mi_col_end;
         mi_col += MI_BLOCK_SIZE)
      write_modes_sb(cpi, tile, w, tok, tok_end, mi_row, mi_col,
                     BLOCK_64X64);
  }
}
Beispiel #11
0
static int first_pass_worker_hook(void *arg1, void *arg2) {
  EncWorkerData *const thread_data = (EncWorkerData *)arg1;
  MultiThreadHandle *multi_thread_ctxt = (MultiThreadHandle *)arg2;
  VP9_COMP *const cpi = thread_data->cpi;
  const VP9_COMMON *const cm = &cpi->common;
  const int tile_cols = 1 << cm->log2_tile_cols;
  int tile_row, tile_col;
  TileDataEnc *this_tile;
  int end_of_frame;
  int thread_id = thread_data->thread_id;
  int cur_tile_id = multi_thread_ctxt->thread_id_to_tile_id[thread_id];
  JobNode *proc_job = NULL;
  FIRSTPASS_DATA fp_acc_data;
  MV zero_mv = { 0, 0 };
  MV best_ref_mv;
  int mb_row;

  end_of_frame = 0;
  while (0 == end_of_frame) {
    // Get the next job in the queue
    proc_job =
        (JobNode *)vp9_enc_grp_get_next_job(multi_thread_ctxt, cur_tile_id);
    if (NULL == proc_job) {
      // Query for the status of other tiles
      end_of_frame = vp9_get_tiles_proc_status(
          multi_thread_ctxt, thread_data->tile_completion_status, &cur_tile_id,
          tile_cols);
    } else {
      tile_col = proc_job->tile_col_id;
      tile_row = proc_job->tile_row_id;

      this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
      mb_row = proc_job->vert_unit_row_num;

      best_ref_mv = zero_mv;
      vp9_zero(fp_acc_data);
      fp_acc_data.image_data_start_row = INVALID_ROW;
      vp9_first_pass_encode_tile_mb_row(cpi, thread_data->td, &fp_acc_data,
                                        this_tile, &best_ref_mv, mb_row);
    }
  }
  return 0;
}
Beispiel #12
0
VP9D_PTR vp9_create_decompressor(VP9D_CONFIG *oxcf) {
  VP9D_COMP *const pbi = vpx_memalign(32, sizeof(VP9D_COMP));
  VP9_COMMON *const cm = pbi ? &pbi->common : NULL;

  if (!cm)
    return NULL;

  vp9_zero(*pbi);

  // Initialize the references to not point to any frame buffers.
  memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));

  if (setjmp(cm->error.jmp)) {
    cm->error.setjmp = 0;
    vp9_remove_decompressor(pbi);
    return NULL;
  }

  cm->error.setjmp = 1;
  vp9_initialize_dec();

  vp9_create_common(cm);

  pbi->oxcf = *oxcf;
  pbi->ready_for_new_data = 1;
  cm->current_video_frame = 0;

  // vp9_init_dequantizer() is first called here. Add check in
  // frame_init_dequantizer() to avoid unnecessary calling of
  // vp9_init_dequantizer() for every frame.
  vp9_init_dequantizer(cm);

  vp9_loop_filter_init(cm);

  cm->error.setjmp = 0;
  pbi->decoded_key_frame = 0;

  init_macroblockd(pbi);

  vp9_worker_init(&pbi->lf_worker);

  return pbi;
}
VP9Decoder *vp9_decoder_create() {
  VP9Decoder *const pbi = vpx_memalign(32, sizeof(*pbi));
  VP9_COMMON *const cm = pbi ? &pbi->common : NULL;

  if (!cm)
    return NULL;

  vp9_zero(*pbi);

  if (setjmp(cm->error.jmp)) {
    cm->error.setjmp = 0;
    vp9_decoder_remove(pbi);
    return NULL;
  }

  cm->error.setjmp = 1;
  initialize_dec();

  vp9_rtcd();

  // Initialize the references to not point to any frame buffers.
  vpx_memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));

  cm->current_video_frame = 0;
  pbi->ready_for_new_data = 1;

  // vp9_init_dequantizer() is first called here. Add check in
  // frame_init_dequantizer() to avoid unnecessary calling of
  // vp9_init_dequantizer() for every frame.
  vp9_init_dequantizer(cm);

  vp9_loop_filter_init(cm);

  cm->error.setjmp = 0;

  vp9_get_worker_interface()->init(&pbi->lf_worker);

  return pbi;
}
static vpx_codec_err_t decode_one_recon_ex(vpx_codec_alg_priv_t *ctx,
                                  const uint8_t **data, unsigned int data_sz,
                                  void *user_priv, int64_t deadline, void *texture) {
  vpx_codec_err_t res = VPX_CODEC_OK;

  VP9D_COMP *pbi;
  VP9D_COMP *pbi_storage;
  VP9D_COMP *my_pbi;
  static int flag = 0;
  int i_is_last_frame = 0;
  int ret = -1;

  struct vpx_usec_timer timer;
  unsigned long yuv2rgb_time = 0;
  unsigned long decode_time = 0;

  // ctx->img_avail = 0;
  vpx_usec_timer_start(&timer);
  if (data_sz == 0) {
    pbi = (VP9D_COMP *)ctx->pbi;
    if (!pbi->l_bufpool_flag_output) {
      return 0;
    }
  }

  /* Determine the stream parameters. Note that we rely on peek_si to
   * validate that we have a buffer that does not wrap around the top
   * of the heap.
   */
  if (!ctx->si.h)
    res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);


  /* Perform deferred allocations, if required */
  if (!res && ctx->defer_alloc) {
    int i;

    for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++) {
      vpx_codec_dec_cfg_t cfg;

      cfg.w = ctx->si.w;
      cfg.h = ctx->si.h;
      ctx->mmaps[i].id = vp9_mem_req_segs[i].id;
      ctx->mmaps[i].sz = vp9_mem_req_segs[i].sz;
      ctx->mmaps[i].align = vp9_mem_req_segs[i].align;
      ctx->mmaps[i].flags = vp9_mem_req_segs[i].flags;

      if (!ctx->mmaps[i].sz)
        ctx->mmaps[i].sz = vp9_mem_req_segs[i].calc_sz(&cfg,
                                                       ctx->base.init_flags);

      res = vpx_mmap_alloc(&ctx->mmaps[i]);
    }

    if (!res)
      vp9_finalize_mmaps(ctx);

    ctx->defer_alloc = 0;
  }

  /* Initialize the decoder instance on the first frame*/
  if (!res && !ctx->decoder_init) {
    res = vpx_validate_mmaps(&ctx->si, ctx->mmaps,
                             vp9_mem_req_segs, NELEMENTS(vp9_mem_req_segs),
                             ctx->base.init_flags);

    if (!res) {
      VP9D_CONFIG oxcf;
      VP9D_PTR optr;

      VP9D_COMP *const new_pbi = vpx_memalign(32, sizeof(VP9D_COMP));
      VP9D_COMP *const new_pbi_two = vpx_memalign(32, sizeof(VP9D_COMP));

      vp9_initialize_dec();

      oxcf.width = ctx->si.w;
      oxcf.height = ctx->si.h;
      oxcf.version = 9;
      oxcf.postprocess = 0;
      oxcf.max_threads = ctx->cfg.threads;
      oxcf.inv_tile_order = ctx->invert_tile_order;
      optr = vp9_create_decompressor_recon(&oxcf);

      vp9_zero(*new_pbi);
      vp9_zero(*new_pbi_two);

      // If postprocessing was enabled by the application and a
      // configuration has not been provided, default it.
      if (!ctx->postproc_cfg_set &&
          (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
        ctx->postproc_cfg.post_proc_flag = VP8_DEBLOCK | VP8_DEMACROBLOCK;
        ctx->postproc_cfg.deblocking_level = 4;
        ctx->postproc_cfg.noise_level = 0;
      }

      if (!optr) {
        res = VPX_CODEC_ERROR;
      } else {
        VP9D_COMP *const pbi = (VP9D_COMP*)optr;
        VP9_COMMON *const cm = &pbi->common;

        VP9_COMMON *const cm0 = &new_pbi->common;
        VP9_COMMON *const cm1 = &new_pbi_two->common;

        if (ctx->fb_list != NULL && ctx->realloc_fb_cb != NULL &&
            ctx->fb_count > 0) {
          cm->fb_list = ctx->fb_list;
          cm->fb_count = ctx->fb_count;
          cm->realloc_fb_cb = ctx->realloc_fb_cb;
          cm->user_priv = ctx->user_priv;
          CpuFlag = 1;
        } else {
          CpuFlag = 0;
          cm->fb_count = FRAME_BUFFERS;
        }
        cm->fb_lru = ctx->fb_lru;
        CHECK_MEM_ERROR(cm, cm->yv12_fb,
                        vpx_calloc(cm->fb_count, sizeof(*cm->yv12_fb)));
        CHECK_MEM_ERROR(cm, cm->fb_idx_ref_cnt,
                        vpx_calloc(cm->fb_count, sizeof(*cm->fb_idx_ref_cnt)));
        if (cm->fb_lru) {
          CHECK_MEM_ERROR(cm, cm->fb_idx_ref_lru,
                          vpx_calloc(cm->fb_count,
                                     sizeof(*cm->fb_idx_ref_lru)));
        }
        ctx->pbi = optr;

        ctx->storage_pbi[0] = new_pbi;
        ctx->storage_pbi[1] = new_pbi_two;

        // cm 0
        if (ctx->fb_list != NULL && ctx->realloc_fb_cb != NULL &&
            ctx->fb_count > 0) {
          cm0->fb_list = ctx->fb_list;
          cm0->fb_count = ctx->fb_count;
          cm0->realloc_fb_cb = ctx->realloc_fb_cb;
          cm0->user_priv = ctx->user_priv;
        } else {
          cm0->fb_count = FRAME_BUFFERS;
        }
        cm0->fb_lru = ctx->fb_lru;
        // CHECK_MEM_ERROR(cm, cm->yv12_fb,
                        // vpx_calloc(cm->fb_count, sizeof(*cm->yv12_fb)));
        CHECK_MEM_ERROR(cm0, cm0->fb_idx_ref_cnt,
                        vpx_calloc(cm0->fb_count, sizeof(*cm0->fb_idx_ref_cnt)));
        if (cm0->fb_lru) {
          CHECK_MEM_ERROR(cm0, cm0->fb_idx_ref_lru,
                          vpx_calloc(cm0->fb_count,
                                     sizeof(*cm0->fb_idx_ref_lru)));
        }

        // cm 1
        if (ctx->fb_list != NULL && ctx->realloc_fb_cb != NULL &&
            ctx->fb_count > 0) {
          cm1->fb_list = ctx->fb_list;
          cm1->fb_count = ctx->fb_count;
          cm1->realloc_fb_cb = ctx->realloc_fb_cb;
          cm1->user_priv = ctx->user_priv;
        } else {
          cm1->fb_count = FRAME_BUFFERS;
        }
        cm1->fb_lru = ctx->fb_lru;
        // CHECK_MEM_ERROR(cm, cm->yv12_fb,
                        // vpx_calloc(cm->fb_count, sizeof(*cm->yv12_fb)));
        CHECK_MEM_ERROR(cm1, cm1->fb_idx_ref_cnt,
                        vpx_calloc(cm1->fb_count, sizeof(*cm1->fb_idx_ref_cnt)));
        if (cm1->fb_lru) {
          CHECK_MEM_ERROR(cm1, cm1->fb_idx_ref_lru,
                          vpx_calloc(cm1->fb_count,
                                     sizeof(*cm1->fb_idx_ref_lru)));
        }

      }
    }

    ctx->decoder_init = 1;
  }

  if (!res && ctx->pbi) {
    YV12_BUFFER_CONFIG sd;
    int64_t time_stamp = 0, time_end_stamp = 0;
    vp9_ppflags_t flags = {0};

    if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) {
      flags.post_proc_flag =
#if CONFIG_POSTPROC_VISUALIZER
          (ctx->dbg_color_ref_frame_flag ? VP9D_DEBUG_CLR_FRM_REF_BLKS : 0) |
          (ctx->dbg_color_mb_modes_flag ? VP9D_DEBUG_CLR_BLK_MODES : 0) |
          (ctx->dbg_color_b_modes_flag ? VP9D_DEBUG_CLR_BLK_MODES : 0) |
          (ctx->dbg_display_mv_flag ? VP9D_DEBUG_DRAW_MV : 0) |
#endif
          ctx->postproc_cfg.post_proc_flag;

      flags.deblocking_level = ctx->postproc_cfg.deblocking_level;
      flags.noise_level = ctx->postproc_cfg.noise_level;
#if CONFIG_POSTPROC_VISUALIZER
      flags.display_ref_frame_flag = ctx->dbg_color_ref_frame_flag;
      flags.display_mb_modes_flag = ctx->dbg_color_mb_modes_flag;
      flags.display_b_modes_flag = ctx->dbg_color_b_modes_flag;
      flags.display_mv_flag = ctx->dbg_display_mv_flag;
#endif
    }

#if 0
    if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) {
      VP9D_COMP *pbi = (VP9D_COMP*)ctx->pbi;
      res = update_error_state(ctx, &pbi->common.error);
    }

    if (!res && 0 == vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp,
                                       &time_end_stamp, &flags)) {
      yuvconfig2image(&ctx->img, &sd, user_priv);
      ctx->img_avail = 1;
    }
#endif
    
    if (data_sz == 0) {
      i_is_last_frame = 1;
    }
    
    if (vp9_receive_compressed_data_recon(ctx->pbi, ctx->storage_pbi, data_sz, data,
      deadline, i_is_last_frame)) {
      pbi = (VP9D_COMP *)ctx->pbi;
      if (pbi->l_bufpool_flag_output == 0)
        pbi_storage = (VP9D_COMP *)ctx->storage_pbi[1];
      else
        pbi_storage = (VP9D_COMP *)ctx->storage_pbi[pbi->l_bufpool_flag_output & 1];
      res = update_error_state(ctx, &pbi_storage->common.error);
    }
	vpx_usec_timer_mark(&timer);
    decode_time = (unsigned int)vpx_usec_timer_elapsed(&timer);
    if (ctx->pbi) {
      pbi = (VP9D_COMP *)ctx->pbi;
      if (pbi->l_bufpool_flag_output) {
        ret = vp9_get_raw_frame(ctx->storage_pbi[pbi->l_bufpool_flag_output & 1],
              &sd, &time_stamp, &time_end_stamp, &flags);
        if (!pbi->res && 0 == ret ) {
          //for render
          my_pbi = (VP9D_COMP *)(ctx->storage_pbi[pbi->l_bufpool_flag_output & 1]);
          yuv2rgba_ocl_obj.y_plane_offset = my_pbi->common.frame_to_show->y_buffer - 
                                                inter_ocl_obj.buffer_pool_map_ptr;
          yuv2rgba_ocl_obj.u_plane_offset = my_pbi->common.frame_to_show->u_buffer - 
                                                inter_ocl_obj.buffer_pool_map_ptr;
          yuv2rgba_ocl_obj.v_plane_offset = my_pbi->common.frame_to_show->v_buffer - 
                                                inter_ocl_obj.buffer_pool_map_ptr;
 
          yuv2rgba_ocl_obj.Y_stride =  my_pbi->common.frame_to_show->y_stride;
          yuv2rgba_ocl_obj.UV_stride =  my_pbi->common.frame_to_show->uv_stride;
          yuv2rgba_ocl_obj.globalThreads[0] =  my_pbi->common.width >> 1;
          yuv2rgba_ocl_obj.globalThreads[1] =  my_pbi->common.height >> 1;
 
		  vpx_usec_timer_start(&timer);
          vp9_yuv2rgba(&yuv2rgba_ocl_obj, texture);
		  vpx_usec_timer_mark(&timer);
          yuv2rgb_time = (unsigned int)vpx_usec_timer_elapsed(&timer);
	      fprintf(pLog, "decode one frame time(without YUV to RGB): %lu us\n"
			            "the whole time of YUV to RGB:  %lu us\n", decode_time, yuv2rgb_time);
          // for render end
          yuvconfig2image(&ctx->img, &sd, user_priv);
          ctx->img_avail = 1;
        }
void init_tx_count_stats() {
  vp9_zero(tx_count_32x32p_stats);
  vp9_zero(tx_count_16x16p_stats);
  vp9_zero(tx_count_8x8p_stats);
}
void init_switchable_interp_stats() {
  vp9_zero(switchable_interp_stats);
}
Beispiel #17
0
static void update_mbgraph_frame_stats(VP9_COMP *cpi,
                                       MBGRAPH_FRAME_STATS *stats,
                                       YV12_BUFFER_CONFIG *buf,
                                       YV12_BUFFER_CONFIG *golden_ref,
                                       YV12_BUFFER_CONFIG *alt_ref) {
  MACROBLOCK *const x = &cpi->td.mb;
  MACROBLOCKD *const xd = &x->e_mbd;
  VP9_COMMON *const cm = &cpi->common;

  int mb_col, mb_row, offset = 0;
  int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0;
  MV gld_top_mv = {0, 0};
  MODE_INFO mi_local;

  vp9_zero(mi_local);
  // Set up limit values for motion vectors to prevent them extending outside
  // the UMV borders.
  x->mv_row_min     = -BORDER_MV_PIXELS_B16;
  x->mv_row_max     = (cm->mb_rows - 1) * 8 + BORDER_MV_PIXELS_B16;
  xd->up_available  = 0;
  xd->plane[0].dst.stride  = buf->y_stride;
  xd->plane[0].pre[0].stride  = buf->y_stride;
  xd->plane[1].dst.stride = buf->uv_stride;
  xd->mi[0] = &mi_local;
  mi_local.mbmi.sb_type = BLOCK_16X16;
  mi_local.mbmi.ref_frame[0] = LAST_FRAME;
  mi_local.mbmi.ref_frame[1] = NONE;

  for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
    MV gld_left_mv = gld_top_mv;
    int mb_y_in_offset  = mb_y_offset;
    int arf_y_in_offset = arf_y_offset;
    int gld_y_in_offset = gld_y_offset;

    // Set up limit values for motion vectors to prevent them extending outside
    // the UMV borders.
    x->mv_col_min      = -BORDER_MV_PIXELS_B16;
    x->mv_col_max      = (cm->mb_cols - 1) * 8 + BORDER_MV_PIXELS_B16;
    xd->left_available = 0;

    for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
      MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col];

      update_mbgraph_mb_stats(cpi, mb_stats, buf, mb_y_in_offset,
                              golden_ref, &gld_left_mv, alt_ref,
                              mb_row, mb_col);
      gld_left_mv = mb_stats->ref[GOLDEN_FRAME].m.mv.as_mv;
      if (mb_col == 0) {
        gld_top_mv = gld_left_mv;
      }
      xd->left_available = 1;
      mb_y_in_offset    += 16;
      gld_y_in_offset   += 16;
      arf_y_in_offset   += 16;
      x->mv_col_min     -= 16;
      x->mv_col_max     -= 16;
    }
    xd->up_available = 1;
    mb_y_offset     += buf->y_stride * 16;
    gld_y_offset    += golden_ref->y_stride * 16;
    if (alt_ref)
      arf_y_offset    += alt_ref->y_stride * 16;
    x->mv_row_min   -= 16;
    x->mv_row_max   -= 16;
    offset          += cm->mb_cols;
  }
}
Beispiel #18
0
void vp9_encode_tiles_mt(VP9_COMP *cpi) {
  VP9_COMMON *const cm = &cpi->common;
  const int tile_cols = 1 << cm->log2_tile_cols;
  const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
  const int num_workers = VPXMIN(cpi->oxcf.max_threads, tile_cols);
  int i;

  vp9_init_tile_data(cpi);

  // Only run once to create threads and allocate thread data.
  if (cpi->num_workers == 0) {
    int allocated_workers = num_workers;

    // While using SVC, we need to allocate threads according to the highest
    // resolution.
    if (cpi->use_svc) {
      int max_tile_cols = get_max_tile_cols(cpi);
      allocated_workers = VPXMIN(cpi->oxcf.max_threads, max_tile_cols);
    }

    CHECK_MEM_ERROR(cm, cpi->workers,
                    vpx_malloc(allocated_workers * sizeof(*cpi->workers)));

    CHECK_MEM_ERROR(cm, cpi->tile_thr_data,
                    vpx_calloc(allocated_workers,
                    sizeof(*cpi->tile_thr_data)));

    for (i = 0; i < allocated_workers; i++) {
      VPxWorker *const worker = &cpi->workers[i];
      EncWorkerData *thread_data = &cpi->tile_thr_data[i];

      ++cpi->num_workers;
      winterface->init(worker);

      if (i < allocated_workers - 1) {
        thread_data->cpi = cpi;

        // Allocate thread data.
        CHECK_MEM_ERROR(cm, thread_data->td,
                        vpx_memalign(32, sizeof(*thread_data->td)));
        vp9_zero(*thread_data->td);

        // Set up pc_tree.
        thread_data->td->leaf_tree = NULL;
        thread_data->td->pc_tree = NULL;
        vp9_setup_pc_tree(cm, thread_data->td);

        // Allocate frame counters in thread data.
        CHECK_MEM_ERROR(cm, thread_data->td->counts,
                        vpx_calloc(1, sizeof(*thread_data->td->counts)));

        // Create threads
        if (!winterface->reset(worker))
          vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
                             "Tile encoder thread creation failed");
      } else {
        // Main thread acts as a worker and uses the thread data in cpi.
        thread_data->cpi = cpi;
        thread_data->td = &cpi->td;
      }

      winterface->sync(worker);
    }
  }

  for (i = 0; i < num_workers; i++) {
    VPxWorker *const worker = &cpi->workers[i];
    EncWorkerData *thread_data;

    worker->hook = (VPxWorkerHook)enc_worker_hook;
    worker->data1 = &cpi->tile_thr_data[i];
    worker->data2 = NULL;
    thread_data = (EncWorkerData*)worker->data1;

    // Before encoding a frame, copy the thread data from cpi.
    if (thread_data->td != &cpi->td) {
      thread_data->td->mb = cpi->td.mb;
      thread_data->td->rd_counts = cpi->td.rd_counts;
    }
    if (thread_data->td->counts != &cpi->common.counts) {
      memcpy(thread_data->td->counts, &cpi->common.counts,
             sizeof(cpi->common.counts));
    }

    // Handle use_nonrd_pick_mode case.
    if (cpi->sf.use_nonrd_pick_mode) {
      MACROBLOCK *const x = &thread_data->td->mb;
      MACROBLOCKD *const xd = &x->e_mbd;
      struct macroblock_plane *const p = x->plane;
      struct macroblockd_plane *const pd = xd->plane;
      PICK_MODE_CONTEXT *ctx = &thread_data->td->pc_root->none;
      int j;

      for (j = 0; j < MAX_MB_PLANE; ++j) {
        p[j].coeff = ctx->coeff_pbuf[j][0];
        p[j].qcoeff = ctx->qcoeff_pbuf[j][0];
        pd[j].dqcoeff = ctx->dqcoeff_pbuf[j][0];
        p[j].eobs = ctx->eobs_pbuf[j][0];
      }
    }
  }

  // Encode a frame
  for (i = 0; i < num_workers; i++) {
    VPxWorker *const worker = &cpi->workers[i];
    EncWorkerData *const thread_data = (EncWorkerData*)worker->data1;

    // Set the starting tile for each thread.
    thread_data->start = i;

    if (i == cpi->num_workers - 1)
      winterface->execute(worker);
    else
      winterface->launch(worker);
  }

  // Encoding ends.
  for (i = 0; i < num_workers; i++) {
    VPxWorker *const worker = &cpi->workers[i];
    winterface->sync(worker);
  }

  for (i = 0; i < num_workers; i++) {
    VPxWorker *const worker = &cpi->workers[i];
    EncWorkerData *const thread_data = (EncWorkerData*)worker->data1;

    // Accumulate counters.
    if (i < cpi->num_workers - 1) {
      vp9_accumulate_frame_counts(cm, thread_data->td->counts, 0);
      accumulate_rd_opt(&cpi->td, thread_data->td);
    }
  }
}
Beispiel #19
0
void vp9_mb_copy(VP9_COMP *cpi, MACROBLOCK *x_dst, MACROBLOCK *x_src) {
  VP9_COMMON *cm = &cpi->common;
  MACROBLOCKD *const xd_dst = &x_dst->e_mbd;
  MACROBLOCKD *const xd_src = &x_src->e_mbd;
  int i;

  for (i = 0; i < MAX_MB_PLANE; ++i) {
    x_dst->plane[i] = x_src->plane[i];
    xd_dst->plane[i] = xd_src->plane[i];
  }
  xd_dst->mi_stride = xd_src->mi_stride;
  xd_dst->mi = xd_src->mi;
  xd_dst->mi[0] = xd_src->mi[0];
  xd_dst->block_refs[0] = xd_src->block_refs[0];
  xd_dst->block_refs[1] = xd_src->block_refs[1];
  xd_dst->cur_buf = xd_src->cur_buf;
#if CONFIG_VP9_HIGHBITDEPTH
  xd_dst->bd = xd_src->bd;
#endif
  xd_dst->lossless = xd_src->lossless;
  xd_dst->corrupted = 0;
  for (i = 0; i < MAX_MB_PLANE; i++) {
    xd_dst->above_context[i] = xd_src->above_context[i];
  }
  xd_dst->above_seg_context = xd_src->above_seg_context;

  x_dst->skip_block = x_src->skip_block;
  x_dst->select_tx_size = x_src->select_tx_size;
  x_dst->skip_recode = x_src->skip_recode;
  x_dst->skip_optimize = x_src->skip_optimize;
  x_dst->q_index = x_src->q_index;

  x_dst->errorperbit = x_src->errorperbit;
  x_dst->sadperbit16 = x_src->sadperbit16;
  x_dst->sadperbit4 = x_src->sadperbit4;
  x_dst->rddiv = x_src->rddiv;
  x_dst->rdmult = x_src->rdmult;
  x_dst->mb_energy = x_src->mb_energy;

  for (i = 0; i < MV_JOINTS; i++) {
    x_dst->nmvjointcost[i] = x_src->nmvjointcost[i];
    x_dst->nmvjointsadcost[i] = x_src->nmvjointsadcost[i];
  }
  x_dst->nmvcost[0] = x_src->nmvcost[0];
  x_dst->nmvcost[1] = x_src->nmvcost[1];
  x_dst->nmvcost_hp[0] = x_src->nmvcost_hp[0];
  x_dst->nmvcost_hp[1] = x_src->nmvcost_hp[1];
  x_dst->mvcost = x_src->mvcost;
  x_dst->nmvsadcost[0] = x_src->nmvsadcost[0];
  x_dst->nmvsadcost[1] = x_src->nmvsadcost[1];
  x_dst->nmvsadcost_hp[0] = x_src->nmvsadcost_hp[0];
  x_dst->nmvsadcost_hp[1] = x_src->nmvsadcost_hp[1];
  x_dst->mvsadcost = x_src->mvsadcost;

  x_dst->min_partition_size = x_src->min_partition_size;
  x_dst->max_partition_size = x_src->max_partition_size;

  vpx_memcpy(x_dst->token_costs, x_src->token_costs,
             sizeof(x_src->token_costs));

  vp9_zero(x_dst->counts);
  vp9_zero(x_dst->coef_counts);
  vpx_memcpy(x_dst->rd.threshes, cpi->rd.threshes, sizeof(cpi->rd.threshes));
  // freq scaling factors initialization has to happen only for video frame 1.
  // For all other frames, It self corrects itself while encoding.
  if (cm->current_video_frame == 0)
    vpx_memcpy(x_dst->rd.thresh_freq_fact, cpi->rd.thresh_freq_fact,
               sizeof(cpi->rd.thresh_freq_fact));
  vp9_zero(x_dst->rd.comp_pred_diff);
  vp9_zero(x_dst->rd.tx_select_diff);
  vp9_zero(x_dst->rd.tx_select_threshes);
  vp9_zero(x_dst->rd.filter_diff);
  x_dst->rd.RDMULT = cpi->rd.RDMULT;
  x_dst->rd.RDDIV = cpi->rd.RDDIV;

  x_dst->data_parallel_processing = 0;

  x_dst->optimize = x_src->optimize;
  x_dst->quant_fp = x_src->quant_fp;
  vp9_zero(x_dst->skip_txfm);
  vp9_zero(x_dst->bsse);

  x_dst->fwd_txm4x4 = x_src->fwd_txm4x4;
  x_dst->itxm_add = x_src->itxm_add;
#if CONFIG_VP9_HIGHBITDEPTH
  x_dst->itxm_add = x_src->itxm_add;
#endif
}
Beispiel #20
0
int main(int argc, char **argv) {
  FILE *infile = NULL;
  // Encoder
  vpx_codec_ctx_t ecodec;
  vpx_codec_enc_cfg_t cfg;
  unsigned int frame_in = 0;
  vpx_image_t raw;
  vpx_codec_err_t res;
  VpxVideoInfo info;
  VpxVideoWriter *writer = NULL;
  const VpxInterface *encoder = NULL;

  // Test encoder/decoder mismatch.
  int test_decode = 1;
  // Decoder
  vpx_codec_ctx_t dcodec;
  unsigned int frame_out = 0;

  // The frame number to set reference frame on
  unsigned int update_frame_num = 0;
  int mismatch_seen = 0;

  const int fps = 30;
  const int bitrate = 500;

  const char *width_arg = NULL;
  const char *height_arg = NULL;
  const char *infile_arg = NULL;
  const char *outfile_arg = NULL;
  const char *update_frame_num_arg = NULL;
  unsigned int limit = 0;

  vp9_zero(ecodec);
  vp9_zero(cfg);
  vp9_zero(info);

  exec_name = argv[0];

  if (argc < 6) die("Invalid number of arguments");

  width_arg = argv[1];
  height_arg = argv[2];
  infile_arg = argv[3];
  outfile_arg = argv[4];
  update_frame_num_arg = argv[5];

  encoder = get_vpx_encoder_by_name("vp9");
  if (!encoder) die("Unsupported codec.");

  update_frame_num = (unsigned int)strtoul(update_frame_num_arg, NULL, 0);
  // In VP9, the reference buffers (cm->buffer_pool->frame_bufs[i].buf) are
  // allocated while calling vpx_codec_encode(), thus, setting reference for
  // 1st frame isn't supported.
  if (update_frame_num <= 1) {
    die("Couldn't parse frame number '%s'\n", update_frame_num_arg);
  }

  if (argc > 6) {
    limit = (unsigned int)strtoul(argv[6], NULL, 0);
    if (update_frame_num > limit)
      die("Update frame number couldn't larger than limit\n");
  }

  info.codec_fourcc = encoder->fourcc;
  info.frame_width = (int)strtol(width_arg, NULL, 0);
  info.frame_height = (int)strtol(height_arg, NULL, 0);
  info.time_base.numerator = 1;
  info.time_base.denominator = fps;

  if (info.frame_width <= 0 || info.frame_height <= 0 ||
      (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
    die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
  }

  if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
                     info.frame_height, 1)) {
    die("Failed to allocate image.");
  }

  printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));

  res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
  if (res) die_codec(&ecodec, "Failed to get default codec config.");

  cfg.g_w = info.frame_width;
  cfg.g_h = info.frame_height;
  cfg.g_timebase.num = info.time_base.numerator;
  cfg.g_timebase.den = info.time_base.denominator;
  cfg.rc_target_bitrate = bitrate;
  cfg.g_lag_in_frames = 3;

  writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info);
  if (!writer) die("Failed to open %s for writing.", outfile_arg);

  if (!(infile = fopen(infile_arg, "rb")))
    die("Failed to open %s for reading.", infile_arg);

  if (vpx_codec_enc_init(&ecodec, encoder->codec_interface(), &cfg, 0))
    die_codec(&ecodec, "Failed to initialize encoder");

  // Disable alt_ref.
  if (vpx_codec_control(&ecodec, VP8E_SET_ENABLEAUTOALTREF, 0))
    die_codec(&ecodec, "Failed to set enable auto alt ref");

  if (test_decode) {
    const VpxInterface *decoder = get_vpx_decoder_by_name("vp9");
    if (vpx_codec_dec_init(&dcodec, decoder->codec_interface(), NULL, 0))
      die_codec(&dcodec, "Failed to initialize decoder.");
  }

  // Encode frames.
  while (vpx_img_read(&raw, infile)) {
    if (limit && frame_in >= limit) break;
    if (update_frame_num > 1 && frame_out + 1 == update_frame_num) {
      vpx_ref_frame_t ref;
      ref.frame_type = VP8_LAST_FRAME;
      ref.img = raw;
      // Set reference frame in encoder.
      if (vpx_codec_control(&ecodec, VP8_SET_REFERENCE, &ref))
        die_codec(&ecodec, "Failed to set reference frame");
      printf(" <SET_REF>");

      // If set_reference in decoder is commented out, the enc/dec mismatch
      // would be seen.
      if (test_decode) {
        if (vpx_codec_control(&dcodec, VP8_SET_REFERENCE, &ref))
          die_codec(&dcodec, "Failed to set reference frame");
      }
    }

    encode_frame(&ecodec, &raw, frame_in, writer, test_decode, &dcodec,
                 &frame_out, &mismatch_seen);
    frame_in++;
    if (mismatch_seen) break;
  }

  // Flush encoder.
  if (!mismatch_seen)
    while (encode_frame(&ecodec, NULL, frame_in, writer, test_decode, &dcodec,
                        &frame_out, &mismatch_seen)) {
    }

  printf("\n");
  fclose(infile);
  printf("Processed %d frames.\n", frame_out);

  if (test_decode) {
    if (!mismatch_seen)
      printf("Encoder/decoder results are matching.\n");
    else
      printf("Encoder/decoder results are NOT matching.\n");
  }

  if (test_decode)
    if (vpx_codec_destroy(&dcodec))
      die_codec(&dcodec, "Failed to destroy decoder");

  vpx_img_free(&raw);
  if (vpx_codec_destroy(&ecodec))
    die_codec(&ecodec, "Failed to destroy encoder.");

  vpx_video_writer_close(writer);

  return EXIT_SUCCESS;
}