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 int alloc_mi(VP9_COMMON *cm, int mi_size) { int i; for (i = 0; i < 2; ++i) { cm->mip_array[i] = (MODE_INFO *)vpx_calloc(mi_size, sizeof(MODE_INFO)); if (cm->mip_array[i] == NULL) return 1; cm->mi_grid_base_array[i] = (MODE_INFO **)vpx_calloc(mi_size, sizeof(MODE_INFO*)); if (cm->mi_grid_base_array[i] == NULL) return 1; } cm->mi_alloc_size = mi_size; // Init the index. cm->mi_idx = 0; cm->prev_mi_idx = 1; cm->mip = cm->mip_array[cm->mi_idx]; cm->prev_mip = cm->mip_array[cm->prev_mi_idx]; cm->mi_grid_base = cm->mi_grid_base_array[cm->mi_idx]; cm->prev_mi_grid_base = cm->mi_grid_base_array[cm->prev_mi_idx]; return 0; }
int vp9_alloc_context_buffers(VP9_COMMON *cm, int width, int height) { vp9_free_context_buffers(cm); vp9_set_mb_mi(cm, width, height); if (cm->alloc_mi(cm, cm->mi_stride * calc_mi_size(cm->mi_rows))) goto fail; // Create the segmentation map structure and set to 0. free_seg_map(cm); if (alloc_seg_map(cm, cm->mi_rows * cm->mi_cols)) goto fail; cm->above_context = (ENTROPY_CONTEXT *)vpx_calloc( 2 * mi_cols_aligned_to_sb(cm->mi_cols) * MAX_MB_PLANE, sizeof(*cm->above_context)); if (!cm->above_context) goto fail; cm->above_seg_context = (PARTITION_CONTEXT *)vpx_calloc( mi_cols_aligned_to_sb(cm->mi_cols), sizeof(*cm->above_seg_context)); if (!cm->above_seg_context) goto fail; return 0; fail: vp9_free_context_buffers(cm); return 1; }
CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols) { size_t last_coded_q_map_size; size_t consec_zero_mv_size; CYCLIC_REFRESH *const cr = vpx_calloc(1, sizeof(*cr)); if (cr == NULL) return NULL; cr->map = vpx_calloc(mi_rows * mi_cols, sizeof(*cr->map)); if (cr->map == NULL) { vpx_free(cr); return NULL; } last_coded_q_map_size = mi_rows * mi_cols * sizeof(*cr->last_coded_q_map); cr->last_coded_q_map = vpx_malloc(last_coded_q_map_size); if (cr->last_coded_q_map == NULL) { vpx_free(cr); return NULL; } assert(MAXQ <= 255); memset(cr->last_coded_q_map, MAXQ, last_coded_q_map_size); consec_zero_mv_size = mi_rows * mi_cols * sizeof(*cr->consec_zero_mv); cr->consec_zero_mv = vpx_malloc(consec_zero_mv_size); if (cr->consec_zero_mv == NULL) { vpx_free(cr); return NULL; } memset(cr->consec_zero_mv, 0, consec_zero_mv_size); return cr; }
int vp9_alloc_context_buffers(VP9_COMMON *cm, int width, int height) { vp9_free_context_buffers(cm); vp9_set_mb_mi(cm, width, height); if (alloc_mi(cm, cm->mi_stride * calc_mi_size(cm->mi_rows))) goto fail; if (cm->use_gpu) { if (vp9_alloc_gpu_interface_buffers(cm)) goto fail; cm->is_background_map = (uint8_t *)vpx_calloc( cm->sb_rows * cm->sb_cols, sizeof(*cm->is_background_map)); if (!cm->is_background_map) goto fail; } cm->last_frame_seg_map = (uint8_t *)vpx_calloc(cm->mi_rows * cm->mi_cols, 1); if (!cm->last_frame_seg_map) goto fail; cm->above_context = (ENTROPY_CONTEXT *)vpx_calloc( 2 * mi_cols_aligned_to_sb(cm->mi_cols) * MAX_MB_PLANE, sizeof(*cm->above_context)); if (!cm->above_context) goto fail; cm->above_seg_context = (PARTITION_CONTEXT *)vpx_calloc( mi_cols_aligned_to_sb(cm->mi_cols), sizeof(*cm->above_seg_context)); if (!cm->above_seg_context) goto fail; return 0; fail: vp9_free_context_buffers(cm); return 1; }
static int vp9_dec_alloc_mi(VP9_COMMON *cm, int mi_size) { cm->mip = vpx_calloc(mi_size, sizeof(*cm->mip)); if (!cm->mip) return 1; cm->mi_alloc_size = mi_size; cm->mi_grid_base = (MODE_INFO **)vpx_calloc(mi_size, sizeof(MODE_INFO *)); if (!cm->mi_grid_base) return 1; return 0; }
void vp9_dec_alloc_row_mt_mem(RowMTWorkerData *row_mt_worker_data, VP9_COMMON *cm, int num_sbs, int max_threads, int num_jobs) { int plane; const size_t dqcoeff_size = (num_sbs << DQCOEFFS_PER_SB_LOG2) * sizeof(*row_mt_worker_data->dqcoeff[0]); row_mt_worker_data->num_jobs = num_jobs; #if CONFIG_MULTITHREAD { int i; CHECK_MEM_ERROR( cm, row_mt_worker_data->recon_sync_mutex, vpx_malloc(sizeof(*row_mt_worker_data->recon_sync_mutex) * num_jobs)); if (row_mt_worker_data->recon_sync_mutex) { for (i = 0; i < num_jobs; ++i) { pthread_mutex_init(&row_mt_worker_data->recon_sync_mutex[i], NULL); } } CHECK_MEM_ERROR( cm, row_mt_worker_data->recon_sync_cond, vpx_malloc(sizeof(*row_mt_worker_data->recon_sync_cond) * num_jobs)); if (row_mt_worker_data->recon_sync_cond) { for (i = 0; i < num_jobs; ++i) { pthread_cond_init(&row_mt_worker_data->recon_sync_cond[i], NULL); } } } #endif row_mt_worker_data->num_sbs = num_sbs; for (plane = 0; plane < 3; ++plane) { CHECK_MEM_ERROR(cm, row_mt_worker_data->dqcoeff[plane], vpx_memalign(16, dqcoeff_size)); memset(row_mt_worker_data->dqcoeff[plane], 0, dqcoeff_size); CHECK_MEM_ERROR(cm, row_mt_worker_data->eob[plane], vpx_calloc(num_sbs << EOBS_PER_SB_LOG2, sizeof(*row_mt_worker_data->eob[plane]))); } CHECK_MEM_ERROR(cm, row_mt_worker_data->partition, vpx_calloc(num_sbs * PARTITIONS_PER_SB, sizeof(*row_mt_worker_data->partition))); CHECK_MEM_ERROR(cm, row_mt_worker_data->recon_map, vpx_calloc(num_sbs, sizeof(*row_mt_worker_data->recon_map))); // allocate memory for thread_data if (row_mt_worker_data->thread_data == NULL) { const size_t thread_size = max_threads * sizeof(*row_mt_worker_data->thread_data); CHECK_MEM_ERROR(cm, row_mt_worker_data->thread_data, vpx_memalign(32, thread_size)); } }
CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols) { CYCLIC_REFRESH *const cr = vpx_calloc(1, sizeof(*cr)); if (cr == NULL) return NULL; cr->map = vpx_calloc(mi_rows * mi_cols, sizeof(*cr->map)); if (cr->map == NULL) { vpx_free(cr); return NULL; } return cr; }
// This function sets up a tree of contexts such that at each square // partition level. There are contexts for none, horizontal, vertical, and // split. Along with a block_size value and a selected block_size which // represents the state of our search. void vp10_setup_pc_tree(VP10_COMMON *cm, ThreadData *td) { int i, j; const int leaf_nodes = 64; const int tree_nodes = 64 + 16 + 4 + 1; int pc_tree_index = 0; PC_TREE *this_pc; PICK_MODE_CONTEXT *this_leaf; int square_index = 1; int nodes; vpx_free(td->leaf_tree); CHECK_MEM_ERROR(cm, td->leaf_tree, vpx_calloc(leaf_nodes, sizeof(*td->leaf_tree))); vpx_free(td->pc_tree); CHECK_MEM_ERROR(cm, td->pc_tree, vpx_calloc(tree_nodes, sizeof(*td->pc_tree))); this_pc = &td->pc_tree[0]; this_leaf = &td->leaf_tree[0]; // 4x4 blocks smaller than 8x8 but in the same 8x8 block share the same // context so we only need to allocate 1 for each 8x8 block. for (i = 0; i < leaf_nodes; ++i) alloc_mode_context(cm, 1, &td->leaf_tree[i]); // Sets up all the leaf nodes in the tree. for (pc_tree_index = 0; pc_tree_index < leaf_nodes; ++pc_tree_index) { PC_TREE *const tree = &td->pc_tree[pc_tree_index]; tree->block_size = square[0]; alloc_tree_contexts(cm, tree, 4); tree->leaf_split[0] = this_leaf++; for (j = 1; j < 4; j++) tree->leaf_split[j] = tree->leaf_split[0]; } // Each node has 4 leaf nodes, fill each block_size level of the tree // from leafs to the root. for (nodes = 16; nodes > 0; nodes >>= 2) { for (i = 0; i < nodes; ++i) { PC_TREE *const tree = &td->pc_tree[pc_tree_index]; alloc_tree_contexts(cm, tree, 4 << (2 * square_index)); tree->block_size = square[square_index]; for (j = 0; j < 4; j++) tree->split[j] = this_pc++; ++pc_tree_index; } ++square_index; } td->pc_root = &td->pc_tree[tree_nodes - 1]; td->pc_root[0].none.best_mode_index = 2; }
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; }
VP10Decoder *vp10_decoder_create(BufferPool *const pool) { VP10Decoder *volatile const pbi = vpx_memalign(32, sizeof(*pbi)); VP10_COMMON *volatile const cm = pbi ? &pbi->common : NULL; if (!cm) return NULL; vp10_zero(*pbi); if (setjmp(cm->error.jmp)) { cm->error.setjmp = 0; vp10_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 = vp10_dec_alloc_mi; cm->free_mi = vp10_dec_free_mi; cm->setup_mi = vp10_dec_setup_mi; vp10_loop_filter_init(cm); cm->error.setjmp = 0; vpx_get_worker_interface()->init(&pbi->lf_worker); return pbi; }
int vp9_get_frame_buffer(void *cb_priv, size_t min_size, vpx_codec_frame_buffer_t *fb) { int i; InternalFrameBufferList *const int_fb_list = (InternalFrameBufferList *)cb_priv; if (int_fb_list == NULL) return -1; // Find a free frame buffer. for (i = 0; i < int_fb_list->num_internal_frame_buffers; ++i) { if (!int_fb_list->int_fb[i].in_use) break; } if (i == int_fb_list->num_internal_frame_buffers) return -1; if (int_fb_list->int_fb[i].size < min_size) { vpx_free(int_fb_list->int_fb[i].data); // The data must be zeroed to fix a valgrind error from the C loop filter // due to access uninitialized memory in frame border. It could be // skipped if border were totally removed. int_fb_list->int_fb[i].data = (uint8_t *)vpx_calloc(1, min_size); if (!int_fb_list->int_fb[i].data) return -1; int_fb_list->int_fb[i].size = min_size; } fb->data = int_fb_list->int_fb[i].data; fb->size = int_fb_list->int_fb[i].size; int_fb_list->int_fb[i].in_use = 1; // Set the frame buffer's private data to point at the internal frame buffer. fb->priv = &int_fb_list->int_fb[i]; return 0; }
static void alloc_mode_context(VP9_COMMON *cm, int num_4x4_blk, PICK_MODE_CONTEXT *ctx) { const int num_blk = (num_4x4_blk < 4 ? 4 : num_4x4_blk); const int num_pix = num_blk << 4; int i, k; ctx->num_4x4_blk = num_blk; CHECK_MEM_ERROR(cm, ctx->zcoeff_blk, vpx_calloc(num_4x4_blk, sizeof(uint8_t))); for (i = 0; i < MAX_MB_PLANE; ++i) { for (k = 0; k < 3; ++k) { CHECK_MEM_ERROR(cm, ctx->coeff[i][k], vpx_memalign(16, num_pix * sizeof(int16_t))); CHECK_MEM_ERROR(cm, ctx->qcoeff[i][k], vpx_memalign(16, num_pix * sizeof(int16_t))); CHECK_MEM_ERROR(cm, ctx->dqcoeff[i][k], vpx_memalign(16, num_pix * sizeof(int16_t))); CHECK_MEM_ERROR(cm, ctx->eobs[i][k], vpx_memalign(16, num_pix * sizeof(uint16_t))); ctx->coeff_pbuf[i][k] = ctx->coeff[i][k]; ctx->qcoeff_pbuf[i][k] = ctx->qcoeff[i][k]; ctx->dqcoeff_pbuf[i][k] = ctx->dqcoeff[i][k]; ctx->eobs_pbuf[i][k] = ctx->eobs[i][k]; } } }
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. (void)data; if (!ctx->priv) { vpx_codec_alg_priv_t *const priv = (vpx_codec_alg_priv_t *)vpx_calloc(1, sizeof(*priv)); if (priv == NULL) return VPX_CODEC_MEM_ERROR; ctx->priv = (vpx_codec_priv_t *)priv; ctx->priv->init_flags = ctx->init_flags; priv->si.sz = sizeof(priv->si); priv->flushed = 0; // Only do frame parallel decode when threads > 1. priv->frame_parallel_decode = (ctx->config.dec && (ctx->config.dec->threads > 1) && (ctx->init_flags & VPX_CODEC_USE_FRAME_THREADING)) ? 1 : 0; if (ctx->config.dec) { priv->cfg = *ctx->config.dec; ctx->config.dec = &priv->cfg; } } return VPX_CODEC_OK; }
static int vp9_dec_alloc_mi(VP9_COMMON *cm, int mi_size) { cm->mip = vpx_calloc(mi_size, sizeof(*cm->mip)); if (!cm->mip) return 1; cm->mi_alloc_size = mi_size; return 0; }
int vp10_alloc_internal_frame_buffers(InternalFrameBufferList *list) { assert(list != NULL); vp10_free_internal_frame_buffers(list); list->num_internal_frame_buffers = VPX_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS; list->int_fb = (InternalFrameBuffer *)vpx_calloc( list->num_internal_frame_buffers, sizeof(*list->int_fb)); return (list->int_fb == NULL); }
int vp9_alloc_ref_frame_buffers(VP9_COMMON *cm, int width, int height) { int i; const int ss_x = cm->subsampling_x; const int ss_y = cm->subsampling_y; vp9_free_ref_frame_buffers(cm); for (i = 0; i < FRAME_BUFFERS; ++i) { BufferPool *const pool = cm->buffer_pool; pool->frame_bufs[i].ref_count = 0; if (vp9_alloc_frame_buffer(&pool->frame_bufs[i].buf, width, height, ss_x, ss_y, #if CONFIG_VP9_HIGHBITDEPTH cm->use_highbitdepth, #endif VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment) < 0) goto fail; if (pool->frame_bufs[i].mvs == NULL) { pool->frame_bufs[i].mvs = (MV_REF *)vpx_calloc(cm->mi_rows * cm->mi_cols, sizeof(*pool->frame_bufs[i].mvs)); if (pool->frame_bufs[i].mvs == NULL) goto fail; pool->frame_bufs[i].mi_rows = cm->mi_rows; pool->frame_bufs[i].mi_cols = cm->mi_cols; } } init_frame_bufs(cm); #if CONFIG_VP9_POSTPROC if (vp9_alloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y, #if CONFIG_VP9_HIGHBITDEPTH cm->use_highbitdepth, #endif VP9_ENC_BORDER_IN_PIXELS, cm->byte_alignment) < 0) goto fail; #endif return 0; fail: vp9_free_ref_frame_buffers(cm); return 1; }
static int reset(VP9Worker *const worker) { int ok = 1; worker->had_error = 0; if (worker->status_ < OK) { #if CONFIG_MULTITHREAD worker->impl_ = (VP9WorkerImpl*)vpx_calloc(1, sizeof(*worker->impl_)); if (worker->impl_ == NULL) { return 0; } if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) { goto Error; } if (pthread_cond_init(&worker->impl_->condition_, NULL)) { pthread_mutex_destroy(&worker->impl_->mutex_); goto Error; } pthread_mutex_lock(&worker->impl_->mutex_); #if defined (__LB_PS4__) // Use a larger thread stack on PS4. Some functions use // > 64KB of stack in debug. pthread_attr_t thread_attr; pthread_attr_init(&thread_attr); pthread_attr_setstacksize(&thread_attr, 128 * 1024); ok = !pthread_create( &worker->impl_->thread_, &thread_attr, thread_loop, worker); #else ok = !pthread_create(&worker->impl_->thread_, NULL, thread_loop, worker); #endif if (ok) worker->status_ = OK; pthread_mutex_unlock(&worker->impl_->mutex_); if (!ok) { pthread_mutex_destroy(&worker->impl_->mutex_); pthread_cond_destroy(&worker->impl_->condition_); Error: vpx_free(worker->impl_); worker->impl_ = NULL; return 0; } #else worker->status_ = OK; #endif } else if (worker->status_ > OK) { ok = sync(worker); } assert(!ok || (worker->status_ == OK)); return ok; }
static int vp9_alloc_gpu_interface_buffers(VP9_COMMON *cm) { BLOCK_SIZE bsize; // Allocate memory for GPU output buffers // TODO(ram-ittiam): Do not allocate memory for block sizes that are not // analysed by the GPU for (bsize = BLOCK_8X8; bsize < BLOCK_SIZES; bsize++) { const int blocks_in_row = (cm->sb_cols * num_mxn_blocks_wide_lookup[bsize]); const int blocks_in_col = (cm->sb_rows * num_mxn_blocks_high_lookup[bsize]); cm->gpu_mvinfo_base_array[bsize] = (GPU_MV_INFO *)vpx_calloc( blocks_in_row * blocks_in_col, sizeof(*cm->gpu_mvinfo_base_array[bsize])); if (cm->gpu_mvinfo_base_array[bsize] == NULL) return 1; } return 0; }
static int alloc_seg_map(VP9_COMMON *cm, int seg_map_size) { int i; for (i = 0; i < NUM_PING_PONG_BUFFERS; ++i) { cm->seg_map_array[i] = (uint8_t *)vpx_calloc(seg_map_size, 1); if (cm->seg_map_array[i] == NULL) return 1; } // Init the index. cm->seg_map_idx = 0; cm->prev_seg_map_idx = 1; cm->current_frame_seg_map = cm->seg_map_array[cm->seg_map_idx]; if (!cm->frame_parallel_decode) cm->last_frame_seg_map = cm->seg_map_array[cm->prev_seg_map_idx]; return 0; }
static void vp8_init_ctx(vpx_codec_ctx_t *ctx) { vpx_codec_alg_priv_t *priv = (vpx_codec_alg_priv_t *)vpx_calloc(1, sizeof(*priv)); ctx->priv = (vpx_codec_priv_t *)priv; ctx->priv->init_flags = ctx->init_flags; priv->si.sz = sizeof(priv->si); priv->decrypt_cb = NULL; priv->decrypt_state = NULL; if (ctx->config.dec) { /* Update the reference to the config structure to an internal copy. */ priv->cfg = *ctx->config.dec; ctx->config.dec = &priv->cfg; } }
static vpx_codec_err_t init_decoder(vpx_codec_alg_priv_t *ctx) { int i; const VPxWorkerInterface *const winterface = vpx_get_worker_interface(); ctx->last_show_frame = -1; ctx->next_submit_worker_id = 0; ctx->last_submit_worker_id = 0; ctx->next_output_worker_id = 0; ctx->frame_cache_read = 0; ctx->frame_cache_write = 0; ctx->num_cache_frames = 0; ctx->need_resync = 1; ctx->num_frame_workers = (ctx->frame_parallel_decode == 1) ? ctx->cfg.threads: 1; if (ctx->num_frame_workers > MAX_DECODE_THREADS) ctx->num_frame_workers = MAX_DECODE_THREADS; ctx->available_threads = ctx->num_frame_workers; ctx->flushed = 0; ctx->buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(BufferPool)); if (ctx->buffer_pool == NULL) return VPX_CODEC_MEM_ERROR; #if CONFIG_MULTITHREAD if (pthread_mutex_init(&ctx->buffer_pool->pool_mutex, NULL)) { set_error_detail(ctx, "Failed to allocate buffer pool mutex"); return VPX_CODEC_MEM_ERROR; } #endif ctx->frame_workers = (VPxWorker *) vpx_malloc(ctx->num_frame_workers * sizeof(*ctx->frame_workers)); if (ctx->frame_workers == NULL) { set_error_detail(ctx, "Failed to allocate frame_workers"); return VPX_CODEC_MEM_ERROR; } for (i = 0; i < ctx->num_frame_workers; ++i) { VPxWorker *const worker = &ctx->frame_workers[i]; FrameWorkerData *frame_worker_data = NULL; winterface->init(worker); worker->data1 = vpx_memalign(32, sizeof(FrameWorkerData)); if (worker->data1 == NULL) { set_error_detail(ctx, "Failed to allocate frame_worker_data"); return VPX_CODEC_MEM_ERROR; } frame_worker_data = (FrameWorkerData *)worker->data1; frame_worker_data->pbi = vp9_decoder_create(ctx->buffer_pool); if (frame_worker_data->pbi == NULL) { set_error_detail(ctx, "Failed to allocate frame_worker_data"); return VPX_CODEC_MEM_ERROR; } frame_worker_data->pbi->frame_worker_owner = worker; frame_worker_data->worker_id = i; frame_worker_data->scratch_buffer = NULL; frame_worker_data->scratch_buffer_size = 0; frame_worker_data->frame_context_ready = 0; frame_worker_data->received_frame = 0; #if CONFIG_MULTITHREAD if (pthread_mutex_init(&frame_worker_data->stats_mutex, NULL)) { set_error_detail(ctx, "Failed to allocate frame_worker_data mutex"); return VPX_CODEC_MEM_ERROR; } if (pthread_cond_init(&frame_worker_data->stats_cond, NULL)) { set_error_detail(ctx, "Failed to allocate frame_worker_data cond"); return VPX_CODEC_MEM_ERROR; } #endif // If decoding in serial mode, FrameWorker thread could create tile worker // thread or loopfilter thread. frame_worker_data->pbi->max_threads = (ctx->frame_parallel_decode == 0) ? ctx->cfg.threads : 0; frame_worker_data->pbi->inv_tile_order = ctx->invert_tile_order; frame_worker_data->pbi->frame_parallel_decode = ctx->frame_parallel_decode; frame_worker_data->pbi->common.frame_parallel_decode = ctx->frame_parallel_decode; worker->hook = (VPxWorkerHook)frame_worker_hook; if (!winterface->reset(worker)) { set_error_detail(ctx, "Frame Worker thread creation failed"); return VPX_CODEC_MEM_ERROR; } } // 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)) set_default_ppflags(&ctx->postproc_cfg); init_buffer_callbacks(ctx); return VPX_CODEC_OK; }
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); } } }
int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) { int i; vp8_de_alloc_frame_buffers(oci); /* our internal buffers are always multiples of 16 */ if ((width & 0xf) != 0) width += 16 - (width & 0xf); if ((height & 0xf) != 0) height += 16 - (height & 0xf); for (i = 0; i < NUM_YV12_BUFFERS; i++) { oci->fb_idx_ref_cnt[0] = 0; if (vp8_yv12_alloc_frame_buffer(&oci->yv12_fb[i], width, height, VP8BORDERINPIXELS) < 0) { vp8_de_alloc_frame_buffers(oci); return ALLOC_FAILURE; } } oci->new_fb_idx = 0; oci->lst_fb_idx = 1; oci->gld_fb_idx = 2; oci->alt_fb_idx = 3; oci->fb_idx_ref_cnt[0] = 1; oci->fb_idx_ref_cnt[1] = 1; oci->fb_idx_ref_cnt[2] = 1; oci->fb_idx_ref_cnt[3] = 1; if (vp8_yv12_alloc_frame_buffer(&oci->temp_scale_frame, width, 16, VP8BORDERINPIXELS) < 0) { vp8_de_alloc_frame_buffers(oci); return ALLOC_FAILURE; } if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer, width, height, VP8BORDERINPIXELS) < 0) { vp8_de_alloc_frame_buffers(oci); return ALLOC_FAILURE; } oci->mb_rows = height >> 4; oci->mb_cols = width >> 4; oci->MBs = oci->mb_rows * oci->mb_cols; oci->mode_info_stride = oci->mb_cols + 1; oci->mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO)); if (!oci->mip) { vp8_de_alloc_frame_buffers(oci); return ALLOC_FAILURE; } oci->mi = oci->mip + oci->mode_info_stride + 1; oci->above_context = vpx_calloc(sizeof(ENTROPY_CONTEXT_PLANES) * oci->mb_cols, 1); if (!oci->above_context) { vp8_de_alloc_frame_buffers(oci); return ALLOC_FAILURE; } vp8_update_mode_info_border(oci->mi, oci->mb_rows, oci->mb_cols); return 0; }
// void separate_arf_mbs_byzz static void separate_arf_mbs(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; int mb_col, mb_row, offset, i; int mi_row, mi_col; int ncnt[4] = { 0 }; int n_frames = cpi->mbgraph_n_frames; int *arf_not_zz; CHECK_MEM_ERROR(cm, arf_not_zz, vpx_calloc(cm->mb_rows * cm->mb_cols * sizeof(*arf_not_zz), 1)); // We are not interested in results beyond the alt ref itself. if (n_frames > cpi->rc.frames_till_gf_update_due) n_frames = cpi->rc.frames_till_gf_update_due; // defer cost to reference frames for (i = n_frames - 1; i >= 0; i--) { MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i]; for (offset = 0, mb_row = 0; mb_row < cm->mb_rows; offset += cm->mb_cols, mb_row++) { for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) { MBGRAPH_MB_STATS *mb_stats = &frame_stats->mb_stats[offset + mb_col]; int altref_err = mb_stats->ref[ALTREF_FRAME].err; int intra_err = mb_stats->ref[INTRA_FRAME ].err; int golden_err = mb_stats->ref[GOLDEN_FRAME].err; // Test for altref vs intra and gf and that its mv was 0,0. if (altref_err > 1000 || altref_err > intra_err || altref_err > golden_err) { arf_not_zz[offset + mb_col]++; } } } } // arf_not_zz is indexed by MB, but this loop is indexed by MI to avoid out // of bound access in segmentation_map for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) { for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) { // If any of the blocks in the sequence failed then the MB // goes in segment 0 if (arf_not_zz[mi_row / 2 * cm->mb_cols + mi_col / 2]) { ncnt[0]++; cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 0; } else { cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 1; ncnt[1]++; } } } // Only bother with segmentation if over 10% of the MBs in static segment // if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) ) if (1) { // Note % of blocks that are marked as static if (cm->MBs) cpi->static_mb_pct = (ncnt[1] * 100) / (cm->mi_rows * cm->mi_cols); // This error case should not be reachable as this function should // never be called with the common data structure uninitialized. else cpi->static_mb_pct = 0; vp9_enable_segmentation(&cm->seg); } else { cpi->static_mb_pct = 0; vp9_disable_segmentation(&cm->seg); } // Free localy allocated storage vpx_free(arf_not_zz); }
void vp10_encode_tiles_mt(VP10_COMP *cpi) { VP10_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; vp10_init_tile_data(cpi); // Only run once to create threads and allocate thread data. if (cpi->num_workers == 0) { int allocated_workers = num_workers; 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))); vp10_zero(*thread_data->td); // Set up pc_tree. thread_data->td->leaf_tree = NULL; thread_data->td->pc_tree = NULL; vp10_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)); } } // 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) { vp10_accumulate_frame_counts(cm, thread_data->td->counts, 0); accumulate_rd_opt(&cpi->td, thread_data->td); } } }
int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) { int i; int aligned_width, aligned_height; vp9_de_alloc_frame_buffers(oci); /* our internal buffers are always multiples of 16 */ aligned_width = (width + 15) & ~15; aligned_height = (height + 15) & ~15; for (i = 0; i < NUM_YV12_BUFFERS; i++) { oci->fb_idx_ref_cnt[i] = 0; if (vp8_yv12_alloc_frame_buffer(&oci->yv12_fb[i], width, height, VP9BORDERINPIXELS) < 0) { vp9_de_alloc_frame_buffers(oci); return 1; } } oci->new_fb_idx = NUM_YV12_BUFFERS - 1; oci->fb_idx_ref_cnt[oci->new_fb_idx] = 1; for (i = 0; i < 3; i++) oci->active_ref_idx[i] = i; for (i = 0; i < NUM_REF_FRAMES; i++) { oci->ref_frame_map[i] = i; oci->fb_idx_ref_cnt[i] = 1; } if (vp8_yv12_alloc_frame_buffer(&oci->temp_scale_frame, width, 16, VP9BORDERINPIXELS) < 0) { vp9_de_alloc_frame_buffers(oci); return 1; } if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer, width, height, VP9BORDERINPIXELS) < 0) { vp9_de_alloc_frame_buffers(oci); return 1; } oci->mb_rows = aligned_height >> 4; oci->mb_cols = aligned_width >> 4; oci->MBs = oci->mb_rows * oci->mb_cols; oci->mode_info_stride = oci->mb_cols + 1; oci->mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO)); if (!oci->mip) { vp9_de_alloc_frame_buffers(oci); return 1; } oci->mi = oci->mip + oci->mode_info_stride + 1; /* allocate memory for last frame MODE_INFO array */ oci->prev_mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO)); if (!oci->prev_mip) { vp9_de_alloc_frame_buffers(oci); return 1; } oci->prev_mi = oci->prev_mip + oci->mode_info_stride + 1; oci->above_context = vpx_calloc(sizeof(ENTROPY_CONTEXT_PLANES) * (3 + oci->mb_cols), 1); if (!oci->above_context) { vp9_de_alloc_frame_buffers(oci); return 1; } vp9_update_mode_info_border(oci, oci->mip); vp9_update_mode_info_in_image(oci, oci->mi); return 0; }
static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, const uint8_t *data, unsigned int data_sz, void *user_priv, long deadline) { vpx_codec_err_t res = VPX_CODEC_OK; unsigned int resolution_change = 0; unsigned int w, h; if (!ctx->fragments.enabled && (data == NULL && data_sz == 0)) { return 0; } /* Update the input fragment data */ if(update_fragments(ctx, data, data_sz, &res) <= 0) return res; /* 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. */ w = ctx->si.w; h = ctx->si.h; res = vp8_peek_si_internal(ctx->fragments.ptrs[0], ctx->fragments.sizes[0], &ctx->si, ctx->decrypt_cb, ctx->decrypt_state); if((res == VPX_CODEC_UNSUP_BITSTREAM) && !ctx->si.is_kf) { /* the peek function returns an error for non keyframes, however for * this case, it is not an error */ res = VPX_CODEC_OK; } if(!ctx->decoder_init && !ctx->si.is_kf) res = VPX_CODEC_UNSUP_BITSTREAM; if ((ctx->si.h != h) || (ctx->si.w != w)) resolution_change = 1; /* Initialize the decoder instance on the first frame*/ if (!res && !ctx->decoder_init) { VP8D_CONFIG oxcf; oxcf.Width = ctx->si.w; oxcf.Height = ctx->si.h; oxcf.Version = 9; oxcf.postprocess = 0; oxcf.max_threads = ctx->cfg.threads; oxcf.error_concealment = (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT); /* 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 | VP8_MFQE; ctx->postproc_cfg.deblocking_level = 4; ctx->postproc_cfg.noise_level = 0; } res = vp8_create_decoder_instances(&ctx->yv12_frame_buffers, &oxcf); ctx->decoder_init = 1; } /* Set these even if already initialized. The caller may have changed the * decrypt config between frames. */ if (ctx->decoder_init) { ctx->yv12_frame_buffers.pbi[0]->decrypt_cb = ctx->decrypt_cb; ctx->yv12_frame_buffers.pbi[0]->decrypt_state = ctx->decrypt_state; } if (!res) { VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0]; if (resolution_change) { VP8_COMMON *const pc = & pbi->common; MACROBLOCKD *const xd = & pbi->mb; #if CONFIG_MULTITHREAD int i; #endif pc->Width = ctx->si.w; pc->Height = ctx->si.h; { int prev_mb_rows = pc->mb_rows; if (setjmp(pbi->common.error.jmp)) { pbi->common.error.setjmp = 0; vp8_clear_system_state(); /* same return value as used in vp8dx_receive_compressed_data */ return -1; } pbi->common.error.setjmp = 1; if (pc->Width <= 0) { pc->Width = w; vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Invalid frame width"); } if (pc->Height <= 0) { pc->Height = h; vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Invalid frame height"); } if (vp8_alloc_frame_buffers(pc, pc->Width, pc->Height)) vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, "Failed to allocate frame buffers"); xd->pre = pc->yv12_fb[pc->lst_fb_idx]; xd->dst = pc->yv12_fb[pc->new_fb_idx]; #if CONFIG_MULTITHREAD for (i = 0; i < pbi->allocated_decoding_thread_count; i++) { pbi->mb_row_di[i].mbd.dst = pc->yv12_fb[pc->new_fb_idx]; vp8_build_block_doffsets(&pbi->mb_row_di[i].mbd); } #endif vp8_build_block_doffsets(&pbi->mb); /* allocate memory for last frame MODE_INFO array */ #if CONFIG_ERROR_CONCEALMENT if (pbi->ec_enabled) { /* old prev_mip was released by vp8_de_alloc_frame_buffers() * called in vp8_alloc_frame_buffers() */ pc->prev_mip = vpx_calloc( (pc->mb_cols + 1) * (pc->mb_rows + 1), sizeof(MODE_INFO)); if (!pc->prev_mip) { vp8_de_alloc_frame_buffers(pc); vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, "Failed to allocate" "last frame MODE_INFO array"); } pc->prev_mi = pc->prev_mip + pc->mode_info_stride + 1; if (vp8_alloc_overlap_lists(pbi)) vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, "Failed to allocate overlap lists " "for error concealment"); } #endif #if CONFIG_MULTITHREAD if (pbi->b_multithreaded_rd) vp8mt_alloc_temp_buffers(pbi, pc->Width, prev_mb_rows); #else (void)prev_mb_rows; #endif } pbi->common.error.setjmp = 0; /* required to get past the first get_free_fb() call */ pbi->common.fb_idx_ref_cnt[0] = 0; } /* update the pbi fragment data */ pbi->fragments = ctx->fragments; ctx->user_priv = user_priv; if (vp8dx_receive_compressed_data(pbi, data_sz, data, deadline)) { res = update_error_state(ctx, &pbi->common.error); } /* get ready for the next series of fragments */ ctx->fragments.count = 0; } return res; }
static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, const uint8_t *data, unsigned int data_sz, void *user_priv, long deadline) { vpx_codec_err_t res = VPX_CODEC_OK; unsigned int resolution_change = 0; unsigned int w, h; /* 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. */ w = ctx->si.w; h = ctx->si.h; res = ctx->base.iface->dec.peek_si(data, data_sz, &ctx->si); if((res == VPX_CODEC_UNSUP_BITSTREAM) && !ctx->si.is_kf) { /* the peek function returns an error for non keyframes, however for * this case, it is not an error */ res = VPX_CODEC_OK; } if(!ctx->decoder_init && !ctx->si.is_kf) res = VPX_CODEC_UNSUP_BITSTREAM; if ((ctx->si.h != h) || (ctx->si.w != w)) resolution_change = 1; /* 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 = vp8_mem_req_segs[i].id; ctx->mmaps[i].sz = vp8_mem_req_segs[i].sz; ctx->mmaps[i].align = vp8_mem_req_segs[i].align; ctx->mmaps[i].flags = vp8_mem_req_segs[i].flags; if (!ctx->mmaps[i].sz) ctx->mmaps[i].sz = vp8_mem_req_segs[i].calc_sz(&cfg, ctx->base.init_flags); res = vp8_mmap_alloc(&ctx->mmaps[i]); } if (!res) vp8_finalize_mmaps(ctx); ctx->defer_alloc = 0; } /* Initialize the decoder instance on the first frame*/ if (!res && !ctx->decoder_init) { res = vp8_validate_mmaps(&ctx->si, ctx->mmaps, ctx->base.init_flags); if (!res) { VP8D_CONFIG oxcf; struct VP8D_COMP* optr; oxcf.Width = ctx->si.w; oxcf.Height = ctx->si.h; oxcf.Version = 9; oxcf.postprocess = 0; oxcf.max_threads = ctx->cfg.threads; oxcf.error_concealment = (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT); oxcf.input_fragments = (ctx->base.init_flags & VPX_CODEC_USE_INPUT_FRAGMENTS); optr = vp8dx_create_decompressor(&oxcf); /* 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 | VP8_MFQE; ctx->postproc_cfg.deblocking_level = 4; ctx->postproc_cfg.noise_level = 0; } if (!optr) res = VPX_CODEC_ERROR; else ctx->pbi = optr; } ctx->decoder_init = 1; } if (!res && ctx->pbi) { if(resolution_change) { VP8D_COMP *pbi = ctx->pbi; VP8_COMMON *const pc = & pbi->common; MACROBLOCKD *const xd = & pbi->mb; #if CONFIG_MULTITHREAD int i; #endif pc->Width = ctx->si.w; pc->Height = ctx->si.h; { int prev_mb_rows = pc->mb_rows; if (setjmp(pbi->common.error.jmp)) { pbi->common.error.setjmp = 0; /* same return value as used in vp8dx_receive_compressed_data */ return -1; } pbi->common.error.setjmp = 1; if (pc->Width <= 0) { pc->Width = w; vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Invalid frame width"); } if (pc->Height <= 0) { pc->Height = h; vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Invalid frame height"); } if (vp8_alloc_frame_buffers(pc, pc->Width, pc->Height)) vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, "Failed to allocate frame buffers"); xd->pre = pc->yv12_fb[pc->lst_fb_idx]; xd->dst = pc->yv12_fb[pc->new_fb_idx]; #if CONFIG_MULTITHREAD for (i = 0; i < pbi->allocated_decoding_thread_count; i++) { pbi->mb_row_di[i].mbd.dst = pc->yv12_fb[pc->new_fb_idx]; vp8_build_block_doffsets(&pbi->mb_row_di[i].mbd); } #endif vp8_build_block_doffsets(&pbi->mb); /* allocate memory for last frame MODE_INFO array */ #if CONFIG_ERROR_CONCEALMENT if (pbi->ec_enabled) { /* old prev_mip was released by vp8_de_alloc_frame_buffers() * called in vp8_alloc_frame_buffers() */ pc->prev_mip = vpx_calloc( (pc->mb_cols + 1) * (pc->mb_rows + 1), sizeof(MODE_INFO)); if (!pc->prev_mip) { vp8_de_alloc_frame_buffers(pc); vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, "Failed to allocate" "last frame MODE_INFO array"); } pc->prev_mi = pc->prev_mip + pc->mode_info_stride + 1; if (vp8_alloc_overlap_lists(pbi)) vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, "Failed to allocate overlap lists " "for error concealment"); } #endif #if CONFIG_MULTITHREAD if (pbi->b_multithreaded_rd) vp8mt_alloc_temp_buffers(pbi, pc->Width, prev_mb_rows); #else (void)prev_mb_rows; #endif } pbi->common.error.setjmp = 0; /* required to get past the first get_free_fb() call */ ctx->pbi->common.fb_idx_ref_cnt[0] = 0; } ctx->user_priv = user_priv; if (vp8dx_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) { VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi; res = update_error_state(ctx, &pbi->common.error); } } return res; }
int vp8_alloc_frame_buffers(VP8_COMMON *oci, int width, int height) { int i; vp8_de_alloc_frame_buffers(oci); if ((width & 0xf) != 0) width += 16 - (width & 0xf); if ((height & 0xf) != 0) height += 16 - (height & 0xf); for (i = 0; i < NUM_YV12_BUFFERS; i++) { oci->fb_idx_ref_cnt[i] = 0; oci->yv12_fb[i].flags = 0; if (vp8_yv12_alloc_frame_buffer(&oci->yv12_fb[i], width, height, VP8BORDERINPIXELS) < 0) goto allocation_fail; } oci->new_fb_idx = 0; oci->lst_fb_idx = 1; oci->gld_fb_idx = 2; oci->alt_fb_idx = 3; oci->fb_idx_ref_cnt[0] = 1; oci->fb_idx_ref_cnt[1] = 1; oci->fb_idx_ref_cnt[2] = 1; oci->fb_idx_ref_cnt[3] = 1; if (vp8_yv12_alloc_frame_buffer(&oci->temp_scale_frame, width, 16, VP8BORDERINPIXELS) < 0) goto allocation_fail; oci->mb_rows = height >> 4; oci->mb_cols = width >> 4; oci->MBs = oci->mb_rows * oci->mb_cols; oci->mode_info_stride = oci->mb_cols + 1; oci->mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO)); if (!oci->mip) goto allocation_fail; oci->mi = oci->mip + oci->mode_info_stride + 1; oci->above_context = vpx_calloc(sizeof(ENTROPY_CONTEXT_PLANES) * oci->mb_cols, 1); if (!oci->above_context) goto allocation_fail; #if CONFIG_POSTPROC if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer, width, height, VP8BORDERINPIXELS) < 0) goto allocation_fail; oci->post_proc_buffer_int_used = 0; vpx_memset(&oci->postproc_state, 0, sizeof(oci->postproc_state)); vpx_memset(oci->post_proc_buffer.buffer_alloc, 128, oci->post_proc_buffer.frame_size); oci->pp_limits_buffer = vpx_memalign(16, 24 * ((oci->mb_cols + 1) & ~1)); if (!oci->pp_limits_buffer) goto allocation_fail; #endif return 0; allocation_fail: vp8_de_alloc_frame_buffers(oci); return 1; }