vpx_codec_err_t vp9_copy_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) { VP9D_COMP *pbi = (VP9D_COMP *) ptr; VP9_COMMON *cm = &pbi->common; /* TODO(jkoleszar): The decoder doesn't have any real knowledge of what the * encoder is using the frame buffers for. This is just a stub to keep the * vpxenc --test-decode functionality working, and will be replaced in a * later commit that adds VP9-specific controls for this functionality. */ if (ref_frame_flag == VP9_LAST_FLAG) { YV12_BUFFER_CONFIG *cfg = &cm->yv12_fb[cm->ref_frame_map[0]]; if (!equal_dimensions(cfg, sd)) vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Incorrect buffer dimensions"); else vp8_yv12_copy_frame(cfg, sd); } else { vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Invalid reference frame"); } return cm->error.error_code; }
vpx_codec_err_t vp8dx_get_reference(VP8D_COMP *pbi, enum vpx_ref_frame_type ref_frame_flag, YV12_BUFFER_CONFIG *sd) { VP8_COMMON *cm = &pbi->common; int ref_fb_idx; if (ref_frame_flag == VP8_LAST_FRAME) ref_fb_idx = cm->lst_fb_idx; else if (ref_frame_flag == VP8_GOLD_FRAME) ref_fb_idx = cm->gld_fb_idx; else if (ref_frame_flag == VP8_ALTR_FRAME) ref_fb_idx = cm->alt_fb_idx; else{ vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, "Invalid reference frame"); return pbi->common.error.error_code; } if(cm->yv12_fb[ref_fb_idx].y_height != sd->y_height || cm->yv12_fb[ref_fb_idx].y_width != sd->y_width || cm->yv12_fb[ref_fb_idx].uv_height != sd->uv_height || cm->yv12_fb[ref_fb_idx].uv_width != sd->uv_width){ vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, "Incorrect buffer dimensions"); } else vp8_yv12_copy_frame(&cm->yv12_fb[ref_fb_idx], sd); return pbi->common.error.error_code; }
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 void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) { int i; for (i = 0; i < ctx->num_frame_workers; ++i) { VPxWorker *const worker = &ctx->frame_workers[i]; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; VP9_COMMON *const cm = &frame_worker_data->pbi->common; BufferPool *const pool = cm->buffer_pool; cm->new_fb_idx = INVALID_IDX; cm->byte_alignment = ctx->byte_alignment; cm->skip_loop_filter = ctx->skip_loop_filter; if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) { pool->get_fb_cb = ctx->get_ext_fb_cb; pool->release_fb_cb = ctx->release_ext_fb_cb; pool->cb_priv = ctx->ext_priv; } else { pool->get_fb_cb = vp9_get_frame_buffer; pool->release_fb_cb = vp9_release_frame_buffer; if (vp9_alloc_internal_frame_buffers(&pool->int_frame_buffers)) vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, "Failed to initialize internal frame buffers"); pool->cb_priv = &pool->int_frame_buffers; } } }
void vp9_create_encoding_threads(VP9_COMP *cpi) { VP9_COMMON * const cm = &cpi->common; const VP9WorkerInterface * const winterface = vp9_get_worker_interface(); int i; CHECK_MEM_ERROR(cm, cpi->enc_thread_hndl, vpx_malloc(sizeof(*cpi->enc_thread_hndl) * cpi->max_threads)); for (i = 0; i < cpi->max_threads; ++i) { VP9Worker * const worker = &cpi->enc_thread_hndl[i]; winterface->init(worker); CHECK_MEM_ERROR(cm, worker->data1, vpx_memalign(32, sizeof(thread_context))); worker->data2 = NULL; if (i < cpi->max_threads - 1 && !winterface->reset(worker)) { vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Tile decoder thread creation failed"); } } // set row encoding hook for (i = 0; i < cpi->max_threads; ++i) { winterface->sync(&cpi->enc_thread_hndl[i]); cpi->enc_thread_hndl[i].hook = (VP9WorkerHook) encoding_thread_process; } CHECK_MEM_ERROR(cm, cpi->cur_sb_col, vpx_malloc(sizeof(*cpi->cur_sb_col) * cm->sb_rows)); // init cur sb col vpx_memset(cpi->cur_sb_col, -1, (sizeof(*cpi->cur_sb_col) * cm->sb_rows)); // set up nsync (currently unused). cpi->sync_range = get_sync_range(cpi->oxcf.width); }
static unsigned int read_available_partition_size( VP8D_COMP *pbi, const unsigned char *token_part_sizes, const unsigned char *fragment_start, const unsigned char *first_fragment_end, const unsigned char *fragment_end, int i, int num_part) { VP8_COMMON* pc = &pbi->common; const unsigned char *partition_size_ptr = token_part_sizes + i * 3; unsigned int partition_size = 0; ptrdiff_t bytes_left = fragment_end - fragment_start; /* Calculate the length of this partition. The last partition * size is implicit. If the partition size can't be read, then * either use the remaining data in the buffer (for EC mode) * or throw an error. */ if (i < num_part - 1) { if (read_is_valid(partition_size_ptr, 3, first_fragment_end)) partition_size = read_partition_size(pbi, partition_size_ptr); else if (pbi->ec_active) partition_size = (unsigned int)bytes_left; else vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Truncated partition size data"); } else partition_size = (unsigned int)bytes_left; /* Validate the calculated partition length. If the buffer * described by the partition can't be fully read, then restrict * it to the portion that can be (for EC mode) or throw an error. */ if (!read_is_valid(fragment_start, partition_size, fragment_end)) { if (pbi->ec_active) partition_size = (unsigned int)bytes_left; else vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet or corrupt partition " "%d length", i + 1); } return partition_size; }
vpx_codec_err_t vp10_set_reference_dec(VP10_COMMON *cm, VP9_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) { RefBuffer *ref_buf = NULL; RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; // TODO(jkoleszar): The decoder doesn't have any real knowledge of what the // encoder is using the frame buffers for. This is just a stub to keep the // vpxenc --test-decode functionality working, and will be replaced in a // later commit that adds VP9-specific controls for this functionality. if (ref_frame_flag == VP9_LAST_FLAG) { ref_buf = &cm->frame_refs[0]; } else if (ref_frame_flag == VP9_GOLD_FLAG) { ref_buf = &cm->frame_refs[1]; } else if (ref_frame_flag == VP9_ALT_FLAG) { ref_buf = &cm->frame_refs[2]; } else { vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Invalid reference frame"); return cm->error.error_code; } if (!equal_dimensions(ref_buf->buf, sd)) { vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Incorrect buffer dimensions"); } else { int *ref_fb_ptr = &ref_buf->idx; // Find an empty frame buffer. const int free_fb = get_free_fb(cm); if (cm->new_fb_idx == INVALID_IDX) return VPX_CODEC_MEM_ERROR; // Decrease ref_count since it will be increased again in // ref_cnt_fb() below. --frame_bufs[free_fb].ref_count; // Manage the reference counters and copy image. ref_cnt_fb(frame_bufs, ref_fb_ptr, free_fb); ref_buf->buf = &frame_bufs[*ref_fb_ptr].buf; vp8_yv12_copy_frame(sd, ref_buf->buf); } return cm->error.error_code; }
vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm, VP9_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) { int idx; YV12_BUFFER_CONFIG *ref_buf = NULL; // TODO(jkoleszar): The decoder doesn't have any real knowledge of what the // encoder is using the frame buffers for. This is just a stub to keep the // vpxenc --test-decode functionality working, and will be replaced in a // later commit that adds VP9-specific controls for this functionality. // (Yunqing) The set_reference control depends on the following setting in // encoder. // cpi->lst_fb_idx = 0; // cpi->gld_fb_idx = 1; // cpi->alt_fb_idx = 2; if (ref_frame_flag == VP9_LAST_FLAG) { idx = cm->ref_frame_map[0]; } else if (ref_frame_flag == VP9_GOLD_FLAG) { idx = cm->ref_frame_map[1]; } else if (ref_frame_flag == VP9_ALT_FLAG) { idx = cm->ref_frame_map[2]; } else { vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Invalid reference frame"); return cm->error.error_code; } if (idx < 0 || idx >= FRAME_BUFFERS) { vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Invalid reference frame map"); return cm->error.error_code; } // Get the destination reference buffer. ref_buf = &cm->buffer_pool->frame_bufs[idx].buf; if (!equal_dimensions(ref_buf, sd)) { vpx_internal_error(&cm->error, VPX_CODEC_ERROR, "Incorrect buffer dimensions"); } else { // Overwrite the reference frame buffer. vpx_yv12_copy_frame(sd, ref_buf); } return cm->error.error_code; }
vpx_codec_err_t vp9_set_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag, YV12_BUFFER_CONFIG *sd) { VP9D_COMP *pbi = (VP9D_COMP *) ptr; VP9_COMMON *cm = &pbi->common; int *ref_fb_ptr = NULL; /* TODO(jkoleszar): The decoder doesn't have any real knowledge of what the * encoder is using the frame buffers for. This is just a stub to keep the * vpxenc --test-decode functionality working, and will be replaced in a * later commit that adds VP9-specific controls for this functionality. */ if (ref_frame_flag == VP9_LAST_FLAG) { ref_fb_ptr = &pbi->common.active_ref_idx[0]; } else if (ref_frame_flag == VP9_GOLD_FLAG) { ref_fb_ptr = &pbi->common.active_ref_idx[1]; } else if (ref_frame_flag == VP9_ALT_FLAG) { ref_fb_ptr = &pbi->common.active_ref_idx[2]; } else { vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, "Invalid reference frame"); return pbi->common.error.error_code; } if (!equal_dimensions(&cm->yv12_fb[*ref_fb_ptr], sd)) { vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, "Incorrect buffer dimensions"); } else { // Find an empty frame buffer. const int free_fb = get_free_fb(cm); // Decrease fb_idx_ref_cnt since it will be increased again in // ref_cnt_fb() below. cm->fb_idx_ref_cnt[free_fb]--; // Manage the reference counters and copy image. ref_cnt_fb(cm->fb_idx_ref_cnt, ref_fb_ptr, free_fb); vp8_yv12_copy_frame(sd, &cm->yv12_fb[*ref_fb_ptr]); } return pbi->common.error.error_code; }
vpx_codec_err_t vp8dx_set_reference(VP8D_COMP *pbi, enum vpx_ref_frame_type ref_frame_flag, YV12_BUFFER_CONFIG *sd) { VP8_COMMON *cm = &pbi->common; int *ref_fb_ptr = NULL; int free_fb; if (ref_frame_flag == VP8_LAST_FRAME) ref_fb_ptr = &cm->lst_fb_idx; else if (ref_frame_flag == VP8_GOLD_FRAME) ref_fb_ptr = &cm->gld_fb_idx; else if (ref_frame_flag == VP8_ALTR_FRAME) ref_fb_ptr = &cm->alt_fb_idx; else{ vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, "Invalid reference frame"); return pbi->common.error.error_code; } if(cm->yv12_fb[*ref_fb_ptr].y_height != sd->y_height || cm->yv12_fb[*ref_fb_ptr].y_width != sd->y_width || cm->yv12_fb[*ref_fb_ptr].uv_height != sd->uv_height || cm->yv12_fb[*ref_fb_ptr].uv_width != sd->uv_width){ vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR, "Incorrect buffer dimensions"); } else{ /* Find an empty frame buffer. */ free_fb = get_free_fb(cm); /* Decrease fb_idx_ref_cnt since it will be increased again in * ref_cnt_fb() below. */ cm->fb_idx_ref_cnt[free_fb]--; /* Manage the reference counters and copy image. */ ref_cnt_fb (cm->fb_idx_ref_cnt, ref_fb_ptr, free_fb); vp8_yv12_copy_frame(sd, &cm->yv12_fb[*ref_fb_ptr]); } return pbi->common.error.error_code; }
// TODO(hkuang): Remove worker parameter as it is only used in debug code. void vp10_frameworker_wait(VPxWorker *const worker, RefCntBuffer *const ref_buf, int row) { #if CONFIG_MULTITHREAD if (!ref_buf) return; #ifndef BUILDING_WITH_TSAN // The following line of code will get harmless tsan error but it is the key // to get best performance. if (ref_buf->row >= row && ref_buf->buf.corrupted != 1) return; #endif { // Find the worker thread that owns the reference frame. If the reference // frame has been fully decoded, it may not have owner. VPxWorker *const ref_worker = ref_buf->frame_worker_owner; FrameWorkerData *const ref_worker_data = (FrameWorkerData *)ref_worker->data1; const VP10Decoder *const pbi = ref_worker_data->pbi; #ifdef DEBUG_THREAD { FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1; printf("%d %p worker is waiting for %d %p worker (%d) ref %d \r\n", worker_data->worker_id, worker, ref_worker_data->worker_id, ref_buf->frame_worker_owner, row, ref_buf->row); } #endif vp10_frameworker_lock_stats(ref_worker); while (ref_buf->row < row && pbi->cur_buf == ref_buf && ref_buf->buf.corrupted != 1) { pthread_cond_wait(&ref_worker_data->stats_cond, &ref_worker_data->stats_mutex); } if (ref_buf->buf.corrupted == 1) { FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1; vp10_frameworker_unlock_stats(ref_worker); vpx_internal_error(&worker_data->pbi->common.error, VPX_CODEC_CORRUPT_FRAME, "Worker %p failed to decode frame", worker); } vp10_frameworker_unlock_stats(ref_worker); } #else (void)worker; (void)ref_buf; (void)row; (void)ref_buf; #endif // CONFIG_MULTITHREAD }
static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) { VP9_COMMON *const cm = &ctx->pbi->common; cm->new_fb_idx = -1; if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) { cm->get_fb_cb = ctx->get_ext_fb_cb; cm->release_fb_cb = ctx->release_ext_fb_cb; cm->cb_priv = ctx->ext_priv; } else { cm->get_fb_cb = vp9_get_frame_buffer; cm->release_fb_cb = vp9_release_frame_buffer; if (vp9_alloc_internal_frame_buffers(&cm->int_frame_buffers)) vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, "Failed to initialize internal frame buffers"); cm->cb_priv = &cm->int_frame_buffers; } }
void vp9_setup_version(VP9_COMMON *cm) { if (cm->version & 0x4) { if (!CONFIG_EXPERIMENTAL) vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, "Bitstream was created by an experimental " "encoder"); cm->experimental = 1; } switch (cm->version & 0x3) { case 0: cm->no_lpf = 0; cm->filter_type = NORMAL_LOOPFILTER; cm->use_bilinear_mc_filter = 0; cm->full_pixel = 0; break; case 1: cm->no_lpf = 0; cm->filter_type = SIMPLE_LOOPFILTER; cm->use_bilinear_mc_filter = 1; cm->full_pixel = 0; break; case 2: case 3: cm->no_lpf = 1; cm->filter_type = NORMAL_LOOPFILTER; cm->use_bilinear_mc_filter = 1; cm->full_pixel = 0; break; // Full pel only code deprecated in experimental code base // case 3: // cm->no_lpf = 1; // cm->filter_type = SIMPLE_LOOPFILTER; // cm->use_bilinear_mc_filter = 1; // cm->full_pixel = 1; // break; } }
static void read_inter_block_mode_info(VP9_COMMON *const cm, MACROBLOCKD *const xd, const TileInfo *const tile, MODE_INFO *const mi, int mi_row, int mi_col, vp9_reader *r) { MB_MODE_INFO *const mbmi = &mi->mbmi; const BLOCK_SIZE bsize = mbmi->sb_type; const int allow_hp = cm->allow_high_precision_mv; int_mv nearest[2], nearmv[2], best[2]; int inter_mode_ctx, ref, is_compound; read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame); is_compound = has_second_ref(mbmi); for (ref = 0; ref < 1 + is_compound; ++ref) { const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; vp9_find_mv_refs(cm, xd, tile, mi, xd->last_mi, frame, mbmi->ref_mvs[frame], mi_row, mi_col); } inter_mode_ctx = mbmi->mode_context[mbmi->ref_frame[0]]; if (vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { mbmi->mode = ZEROMV; if (bsize < BLOCK_8X8) { vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, "Invalid usage of segement feature on small blocks"); return; } } else { if (bsize >= BLOCK_8X8) mbmi->mode = read_inter_mode(cm, r, inter_mode_ctx); } if (bsize < BLOCK_8X8 || mbmi->mode != ZEROMV) { for (ref = 0; ref < 1 + is_compound; ++ref) { vp9_find_best_ref_mvs(xd, allow_hp, mbmi->ref_mvs[mbmi->ref_frame[ref]], &nearest[ref], &nearmv[ref]); best[ref].as_int = nearest[ref].as_int; } } mbmi->interp_filter = (cm->mcomp_filter_type == SWITCHABLE) ? read_switchable_filter_type(cm, xd, r) : cm->mcomp_filter_type; if (bsize < BLOCK_8X8) { const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; // 1 or 2 const int num_4x4_h = num_4x4_blocks_high_lookup[bsize]; // 1 or 2 int idx, idy; int b_mode; for (idy = 0; idy < 2; idy += num_4x4_h) { for (idx = 0; idx < 2; idx += num_4x4_w) { int_mv block[2]; const int j = idy * 2 + idx; b_mode = read_inter_mode(cm, r, inter_mode_ctx); if (b_mode == NEARESTMV || b_mode == NEARMV) for (ref = 0; ref < 1 + is_compound; ++ref) vp9_append_sub8x8_mvs_for_idx(cm, xd, tile, j, ref, mi_row, mi_col, &nearest[ref], &nearmv[ref]); if (!assign_mv(cm, b_mode, block, best, nearest, nearmv, is_compound, allow_hp, r)) { xd->corrupted |= 1; break; }; mi->bmi[j].as_mv[0].as_int = block[0].as_int; if (is_compound) mi->bmi[j].as_mv[1].as_int = block[1].as_int; if (num_4x4_h == 2) mi->bmi[j + 2] = mi->bmi[j]; if (num_4x4_w == 2) mi->bmi[j + 1] = mi->bmi[j]; } } mi->mbmi.mode = b_mode; mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int; mbmi->mv[1].as_int = mi->bmi[3].as_mv[1].as_int; } else { xd->corrupted |= !assign_mv(cm, mbmi->mode, mbmi->mv, best, nearest, nearmv, is_compound, allow_hp, r); } }
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); } } }
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; }
static void read_inter_block_mode_info(VP9Decoder *const pbi, MACROBLOCKD *const xd, const TileInfo *const tile, MODE_INFO *const mi, int mi_row, int mi_col, vp9_reader *r) { VP9_COMMON *const cm = &pbi->common; MB_MODE_INFO *const mbmi = &mi->mbmi; const BLOCK_SIZE bsize = mbmi->sb_type; const int allow_hp = cm->allow_high_precision_mv; int_mv nearestmv[2], nearmv[2]; int inter_mode_ctx, ref, is_compound; read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame); is_compound = has_second_ref(mbmi); for (ref = 0; ref < 1 + is_compound; ++ref) { const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; RefBuffer *ref_buf = &cm->frame_refs[frame - LAST_FRAME]; xd->block_refs[ref] = ref_buf; if ((!vp9_is_valid_scale(&ref_buf->sf))) vpx_internal_error(xd->error_info, VPX_CODEC_UNSUP_BITSTREAM, "Reference frame has invalid dimensions"); vp9_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, &ref_buf->sf); vp9_find_mv_refs(cm, xd, tile, mi, frame, mbmi->ref_mvs[frame], mi_row, mi_col, fpm_sync, (void *)pbi); } inter_mode_ctx = mbmi->mode_context[mbmi->ref_frame[0]]; if (vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { mbmi->mode = ZEROMV; if (bsize < BLOCK_8X8) { vpx_internal_error(xd->error_info, VPX_CODEC_UNSUP_BITSTREAM, "Invalid usage of segement feature on small blocks"); return; } } else { if (bsize >= BLOCK_8X8) mbmi->mode = read_inter_mode(cm, xd, r, inter_mode_ctx); } if (bsize < BLOCK_8X8 || mbmi->mode != ZEROMV) { for (ref = 0; ref < 1 + is_compound; ++ref) { vp9_find_best_ref_mvs(xd, allow_hp, mbmi->ref_mvs[mbmi->ref_frame[ref]], &nearestmv[ref], &nearmv[ref]); } } mbmi->interp_filter = (cm->interp_filter == SWITCHABLE) ? read_switchable_interp_filter(cm, xd, r) : cm->interp_filter; if (bsize < BLOCK_8X8) { const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; // 1 or 2 const int num_4x4_h = num_4x4_blocks_high_lookup[bsize]; // 1 or 2 int idx, idy; PREDICTION_MODE b_mode; int_mv nearest_sub8x8[2], near_sub8x8[2]; for (idy = 0; idy < 2; idy += num_4x4_h) { for (idx = 0; idx < 2; idx += num_4x4_w) { int_mv block[2]; const int j = idy * 2 + idx; b_mode = read_inter_mode(cm, xd, r, inter_mode_ctx); if (b_mode == NEARESTMV || b_mode == NEARMV) for (ref = 0; ref < 1 + is_compound; ++ref) vp9_append_sub8x8_mvs_for_idx(cm, xd, tile, j, ref, mi_row, mi_col, &nearest_sub8x8[ref], &near_sub8x8[ref]); if (!assign_mv(cm, xd, b_mode, block, nearestmv, nearest_sub8x8, near_sub8x8, is_compound, allow_hp, r)) { xd->corrupted |= 1; break; }; mi->bmi[j].as_mv[0].as_int = block[0].as_int; if (is_compound) mi->bmi[j].as_mv[1].as_int = block[1].as_int; if (num_4x4_h == 2) mi->bmi[j + 2] = mi->bmi[j]; if (num_4x4_w == 2) mi->bmi[j + 1] = mi->bmi[j]; } } mi->mbmi.mode = b_mode; mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int; mbmi->mv[1].as_int = mi->bmi[3].as_mv[1].as_int; } else { xd->corrupted |= !assign_mv(cm, xd, mbmi->mode, mbmi->mv, nearestmv, nearestmv, nearmv, is_compound, allow_hp, r); } }
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; }
int vp8_decode_frame(VP8D_COMP *pbi) { vp8_reader *const bc = & pbi->bc; VP8_COMMON *const pc = & pbi->common; MACROBLOCKD *const xd = & pbi->mb; const unsigned char *data = pbi->fragments[0]; const unsigned char *data_end = data + pbi->fragment_sizes[0]; ptrdiff_t first_partition_length_in_bytes; int mb_row; int i, j, k, l; const int *const mb_feature_data_bits = vp8_mb_feature_data_bits; int corrupt_tokens = 0; int prev_independent_partitions = pbi->independent_partitions; /* start with no corruption of current frame */ xd->corrupted = 0; pc->yv12_fb[pc->new_fb_idx].corrupted = 0; if (data_end - data < 3) { if (!pbi->ec_active) { vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet"); } /* Declare the missing frame as an inter frame since it will be handled as an inter frame when we have estimated its motion vectors. */ pc->frame_type = INTER_FRAME; pc->version = 0; pc->show_frame = 1; first_partition_length_in_bytes = 0; } else { pc->frame_type = (FRAME_TYPE)(data[0] & 1); pc->version = (data[0] >> 1) & 7; pc->show_frame = (data[0] >> 4) & 1; first_partition_length_in_bytes = (data[0] | (data[1] << 8) | (data[2] << 16)) >> 5; if (!pbi->ec_active && (data + first_partition_length_in_bytes > data_end || data + first_partition_length_in_bytes < data)) vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet or corrupt partition 0 length"); data += 3; vp8_setup_version(pc); if (pc->frame_type == KEY_FRAME) { const int Width = pc->Width; const int Height = pc->Height; /* vet via sync code */ /* When error concealment is enabled we should only check the sync * code if we have enough bits available */ if (!pbi->ec_active || data + 3 < data_end) { if (data[0] != 0x9d || data[1] != 0x01 || data[2] != 0x2a) vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM, "Invalid frame sync code"); } /* If error concealment is enabled we should only parse the new size * if we have enough data. Otherwise we will end up with the wrong * size. */ if (!pbi->ec_active || data + 6 < data_end) { pc->Width = (data[3] | (data[4] << 8)) & 0x3fff; pc->horiz_scale = data[4] >> 6; pc->Height = (data[5] | (data[6] << 8)) & 0x3fff; pc->vert_scale = data[6] >> 6; } data += 7; if (Width != pc->Width || Height != pc->Height) { int prev_mb_rows = pc->mb_rows; if (pc->Width <= 0) { pc->Width = Width; vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Invalid frame width"); } if (pc->Height <= 0) { pc->Height = Height; 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"); #if CONFIG_ERROR_CONCEALMENT pbi->overlaps = NULL; if (pbi->ec_enabled) { 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); #endif } } }
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 vp8_decode_frame(VP8D_COMP *pbi) { vp8_reader *const bc = &pbi->mbc[8]; VP8_COMMON *const pc = &pbi->common; MACROBLOCKD *const xd = &pbi->mb; const unsigned char *data = pbi->fragments.ptrs[0]; const unsigned char *data_end = data + pbi->fragments.sizes[0]; ptrdiff_t first_partition_length_in_bytes; int i, j, k, l; const int *const mb_feature_data_bits = vp8_mb_feature_data_bits; int corrupt_tokens = 0; int prev_independent_partitions = pbi->independent_partitions; YV12_BUFFER_CONFIG *yv12_fb_new = pbi->dec_fb_ref[INTRA_FRAME]; /* start with no corruption of current frame */ xd->corrupted = 0; yv12_fb_new->corrupted = 0; if (data_end - data < 3) { if (!pbi->ec_active) { vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet"); } /* Declare the missing frame as an inter frame since it will be handled as an inter frame when we have estimated its motion vectors. */ pc->frame_type = INTER_FRAME; pc->version = 0; pc->show_frame = 1; first_partition_length_in_bytes = 0; } else { unsigned char clear_buffer[10]; const unsigned char *clear = data; if (pbi->decrypt_cb) { int n = (int)MIN(sizeof(clear_buffer), data_end - data); pbi->decrypt_cb(pbi->decrypt_state, data, clear_buffer, n); clear = clear_buffer; } pc->frame_type = (FRAME_TYPE)(clear[0] & 1); pc->version = (clear[0] >> 1) & 7; pc->show_frame = (clear[0] >> 4) & 1; first_partition_length_in_bytes = (clear[0] | (clear[1] << 8) | (clear[2] << 16)) >> 5; if (!pbi->ec_active && (data + first_partition_length_in_bytes > data_end || data + first_partition_length_in_bytes < data)) vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet or corrupt partition 0 length"); data += 3; clear += 3; vp8_setup_version(pc); if (pc->frame_type == KEY_FRAME) { /* vet via sync code */ /* When error concealment is enabled we should only check the sync * code if we have enough bits available */ if (!pbi->ec_active || data + 3 < data_end) { if (clear[0] != 0x9d || clear[1] != 0x01 || clear[2] != 0x2a) vpx_internal_error(&pc->error, VPX_CODEC_UNSUP_BITSTREAM, "Invalid frame sync code"); } /* If error concealment is enabled we should only parse the new size * if we have enough data. Otherwise we will end up with the wrong * size. */ if (!pbi->ec_active || data + 6 < data_end) { pc->Width = (clear[3] | (clear[4] << 8)) & 0x3fff; pc->horiz_scale = clear[4] >> 6; pc->Height = (clear[5] | (clear[6] << 8)) & 0x3fff; pc->vert_scale = clear[6] >> 6; } data += 7; clear += 7; } else {
static void setup_token_decoder(VP8D_COMP *pbi, const unsigned char* token_part_sizes) { vp8_reader *bool_decoder = &pbi->mbc[0]; unsigned int partition_idx; unsigned int fragment_idx; unsigned int num_token_partitions; const unsigned char *first_fragment_end = pbi->fragments.ptrs[0] + pbi->fragments.sizes[0]; TOKEN_PARTITION multi_token_partition = (TOKEN_PARTITION)vp8_read_literal(&pbi->mbc[8], 2); if (!vp8dx_bool_error(&pbi->mbc[8])) pbi->common.multi_token_partition = multi_token_partition; num_token_partitions = 1 << pbi->common.multi_token_partition; /* Check for partitions within the fragments and unpack the fragments * so that each fragment pointer points to its corresponding partition. */ for (fragment_idx = 0; fragment_idx < pbi->fragments.count; ++fragment_idx) { unsigned int fragment_size = pbi->fragments.sizes[fragment_idx]; const unsigned char *fragment_end = pbi->fragments.ptrs[fragment_idx] + fragment_size; /* Special case for handling the first partition since we have already * read its size. */ if (fragment_idx == 0) { /* Size of first partition + token partition sizes element */ ptrdiff_t ext_first_part_size = token_part_sizes - pbi->fragments.ptrs[0] + 3 * (num_token_partitions - 1); fragment_size -= (unsigned int)ext_first_part_size; if (fragment_size > 0) { pbi->fragments.sizes[0] = (unsigned int)ext_first_part_size; /* The fragment contains an additional partition. Move to * next. */ fragment_idx++; pbi->fragments.ptrs[fragment_idx] = pbi->fragments.ptrs[0] + pbi->fragments.sizes[0]; } } /* Split the chunk into partitions read from the bitstream */ while (fragment_size > 0) { ptrdiff_t partition_size = read_available_partition_size( pbi, token_part_sizes, pbi->fragments.ptrs[fragment_idx], first_fragment_end, fragment_end, fragment_idx - 1, num_token_partitions); pbi->fragments.sizes[fragment_idx] = (unsigned int)partition_size; fragment_size -= (unsigned int)partition_size; assert(fragment_idx <= num_token_partitions); if (fragment_size > 0) { /* The fragment contains an additional partition. * Move to next. */ fragment_idx++; pbi->fragments.ptrs[fragment_idx] = pbi->fragments.ptrs[fragment_idx - 1] + partition_size; } } } pbi->fragments.count = num_token_partitions + 1; for (partition_idx = 1; partition_idx < pbi->fragments.count; ++partition_idx) { if (vp8dx_start_decode(bool_decoder, pbi->fragments.ptrs[partition_idx], pbi->fragments.sizes[partition_idx], pbi->decrypt_cb, pbi->decrypt_state)) vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate bool decoder %d", partition_idx); bool_decoder++; } #if CONFIG_MULTITHREAD /* Clamp number of decoder threads */ if (pbi->decoding_thread_count > num_token_partitions - 1) pbi->decoding_thread_count = num_token_partitions - 1; #endif }
static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx, const uint8_t **data, unsigned int data_sz, void *user_priv, int64_t deadline) { vpx_codec_err_t res = VPX_CODEC_OK; ctx->img_avail = 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); /* Initialize the decoder instance on the first frame*/ if (!res && !ctx->decoder_init) { VP9D_CONFIG oxcf; struct VP9Decompressor *optr; vp9_initialize_dec(); oxcf.width = ctx->si.w; oxcf.height = ctx->si.h; oxcf.version = 9; oxcf.max_threads = ctx->cfg.threads; oxcf.inv_tile_order = ctx->invert_tile_order; optr = vp9_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; 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; // Set index to not initialized. cm->new_fb_idx = -1; if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) { cm->get_fb_cb = ctx->get_ext_fb_cb; cm->release_fb_cb = ctx->release_ext_fb_cb; cm->cb_priv = ctx->ext_priv; } else { cm->get_fb_cb = vp9_get_frame_buffer; cm->release_fb_cb = vp9_release_frame_buffer; if (vp9_alloc_internal_frame_buffers(&cm->int_frame_buffers)) vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, "Failed to initialize internal frame buffers"); cm->cb_priv = &cm->int_frame_buffers; } ctx->pbi = optr; } ctx->decoder_init = 1; } if (!res && ctx->pbi) { VP9D_COMP *const pbi = ctx->pbi; VP9_COMMON *const cm = &pbi->common; 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 (vp9_receive_compressed_data(pbi, data_sz, data, deadline)) res = update_error_state(ctx, &cm->error); if (!res && 0 == vp9_get_raw_frame(pbi, &sd, &time_stamp, &time_end_stamp, &flags)) { yuvconfig2image(&ctx->img, &sd, user_priv); ctx->img.fb_priv = cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv; ctx->img_avail = 1; } } return res; }
void vp9_init_layer_context(VP9_COMP *const cpi) { SVC *const svc = &cpi->svc; const VP9EncoderConfig *const oxcf = &cpi->oxcf; int layer; int layer_end; int alt_ref_idx = svc->number_spatial_layers; svc->spatial_layer_id = 0; svc->temporal_layer_id = 0; if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) { layer_end = svc->number_temporal_layers; } else { layer_end = svc->number_spatial_layers; if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) { if (vp9_realloc_frame_buffer(&cpi->svc.empty_frame.img, cpi->common.width, cpi->common.height, cpi->common.subsampling_x, cpi->common.subsampling_y, #if CONFIG_VP9_HIGHBITDEPTH cpi->common.use_highbitdepth, #endif VP9_ENC_BORDER_IN_PIXELS, cpi->common.byte_alignment, NULL, NULL, NULL)) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate empty frame for multiple frame " "contexts"); vpx_memset(cpi->svc.empty_frame.img.buffer_alloc, 0x80, cpi->svc.empty_frame.img.buffer_alloc_sz); cpi->svc.empty_frame_width = cpi->common.width; cpi->svc.empty_frame_height = cpi->common.height; } } for (layer = 0; layer < layer_end; ++layer) { LAYER_CONTEXT *const lc = &svc->layer_context[layer]; RATE_CONTROL *const lrc = &lc->rc; int i; lc->current_video_frame_in_layer = 0; lc->layer_size = 0; lc->frames_from_key_frame = 0; lc->last_frame_type = FRAME_TYPES; lrc->ni_av_qi = oxcf->worst_allowed_q; lrc->total_actual_bits = 0; lrc->total_target_vs_actual = 0; lrc->ni_tot_qi = 0; lrc->tot_q = 0.0; lrc->avg_q = 0.0; lrc->ni_frames = 0; lrc->decimation_count = 0; lrc->decimation_factor = 0; for (i = 0; i < RATE_FACTOR_LEVELS; ++i) { lrc->rate_correction_factors[i] = 1.0; } if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) { lc->target_bandwidth = oxcf->ts_target_bitrate[layer]; lrc->last_q[INTER_FRAME] = oxcf->worst_allowed_q; lrc->avg_frame_qindex[INTER_FRAME] = oxcf->worst_allowed_q; lrc->avg_frame_qindex[KEY_FRAME] = oxcf->worst_allowed_q; } else { lc->target_bandwidth = oxcf->ss_target_bitrate[layer]; lrc->last_q[KEY_FRAME] = oxcf->best_allowed_q; lrc->last_q[INTER_FRAME] = oxcf->best_allowed_q; lrc->avg_frame_qindex[KEY_FRAME] = (oxcf->worst_allowed_q + oxcf->best_allowed_q) / 2; lrc->avg_frame_qindex[INTER_FRAME] = (oxcf->worst_allowed_q + oxcf->best_allowed_q) / 2; if (oxcf->ss_enable_auto_arf[layer]) lc->alt_ref_idx = alt_ref_idx++; else lc->alt_ref_idx = INVALID_IDX; lc->gold_ref_idx = INVALID_IDX; } lrc->buffer_level = oxcf->starting_buffer_level_ms * lc->target_bandwidth / 1000; lrc->bits_off_target = lrc->buffer_level; } // Still have extra buffer for base layer golden frame if (!(svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) && alt_ref_idx < REF_FRAMES) svc->layer_context[0].gold_ref_idx = alt_ref_idx; }
void vp9_init_layer_context(VP9_COMP *const cpi) { SVC *const svc = &cpi->svc; const VP9EncoderConfig *const oxcf = &cpi->oxcf; int mi_rows = cpi->common.mi_rows; int mi_cols = cpi->common.mi_cols; int sl, tl, i; int alt_ref_idx = svc->number_spatial_layers; svc->spatial_layer_id = 0; svc->temporal_layer_id = 0; svc->first_spatial_layer_to_encode = 0; svc->rc_drop_superframe = 0; svc->force_zero_mode_spatial_ref = 0; svc->use_base_mv = 0; svc->scaled_temp_is_alloc = 0; svc->scaled_one_half = 0; svc->current_superframe = 0; for (i = 0; i < REF_FRAMES; ++i) svc->ref_frame_index[i] = -1; for (sl = 0; sl < oxcf->ss_number_layers; ++sl) { cpi->svc.ext_frame_flags[sl] = 0; cpi->svc.ext_lst_fb_idx[sl] = 0; cpi->svc.ext_gld_fb_idx[sl] = 1; cpi->svc.ext_alt_fb_idx[sl] = 2; } if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) { if (vpx_realloc_frame_buffer(&cpi->svc.empty_frame.img, SMALL_FRAME_WIDTH, SMALL_FRAME_HEIGHT, cpi->common.subsampling_x, cpi->common.subsampling_y, #if CONFIG_VP9_HIGHBITDEPTH cpi->common.use_highbitdepth, #endif VP9_ENC_BORDER_IN_PIXELS, cpi->common.byte_alignment, NULL, NULL, NULL)) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate empty frame for multiple frame " "contexts"); memset(cpi->svc.empty_frame.img.buffer_alloc, 0x80, cpi->svc.empty_frame.img.buffer_alloc_sz); } for (sl = 0; sl < oxcf->ss_number_layers; ++sl) { for (tl = 0; tl < oxcf->ts_number_layers; ++tl) { int layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers); LAYER_CONTEXT *const lc = &svc->layer_context[layer]; RATE_CONTROL *const lrc = &lc->rc; int i; lc->current_video_frame_in_layer = 0; lc->layer_size = 0; lc->frames_from_key_frame = 0; lc->last_frame_type = FRAME_TYPES; lrc->ni_av_qi = oxcf->worst_allowed_q; lrc->total_actual_bits = 0; lrc->total_target_vs_actual = 0; lrc->ni_tot_qi = 0; lrc->tot_q = 0.0; lrc->avg_q = 0.0; lrc->ni_frames = 0; lrc->decimation_count = 0; lrc->decimation_factor = 0; for (i = 0; i < RATE_FACTOR_LEVELS; ++i) { lrc->rate_correction_factors[i] = 1.0; } if (cpi->oxcf.rc_mode == VPX_CBR) { lc->target_bandwidth = oxcf->layer_target_bitrate[layer]; lrc->last_q[INTER_FRAME] = oxcf->worst_allowed_q; lrc->avg_frame_qindex[INTER_FRAME] = oxcf->worst_allowed_q; lrc->avg_frame_qindex[KEY_FRAME] = oxcf->worst_allowed_q; } else { lc->target_bandwidth = oxcf->layer_target_bitrate[layer]; lrc->last_q[KEY_FRAME] = oxcf->best_allowed_q; lrc->last_q[INTER_FRAME] = oxcf->best_allowed_q; lrc->avg_frame_qindex[KEY_FRAME] = (oxcf->worst_allowed_q + oxcf->best_allowed_q) / 2; lrc->avg_frame_qindex[INTER_FRAME] = (oxcf->worst_allowed_q + oxcf->best_allowed_q) / 2; if (oxcf->ss_enable_auto_arf[sl]) lc->alt_ref_idx = alt_ref_idx++; else lc->alt_ref_idx = INVALID_IDX; lc->gold_ref_idx = INVALID_IDX; } lrc->buffer_level = oxcf->starting_buffer_level_ms * lc->target_bandwidth / 1000; lrc->bits_off_target = lrc->buffer_level; // Initialize the cyclic refresh parameters. If spatial layers are used // (i.e., ss_number_layers > 1), these need to be updated per spatial // layer. // Cyclic refresh is only applied on base temporal layer. if (oxcf->ss_number_layers > 1 && tl == 0) { size_t last_coded_q_map_size; size_t consec_zero_mv_size; VP9_COMMON *const cm = &cpi->common; lc->sb_index = 0; CHECK_MEM_ERROR(cm, lc->map, vpx_malloc(mi_rows * mi_cols * sizeof(*lc->map))); memset(lc->map, 0, mi_rows * mi_cols); last_coded_q_map_size = mi_rows * mi_cols * sizeof(*lc->last_coded_q_map); CHECK_MEM_ERROR(cm, lc->last_coded_q_map, vpx_malloc(last_coded_q_map_size)); assert(MAXQ <= 255); memset(lc->last_coded_q_map, MAXQ, last_coded_q_map_size); consec_zero_mv_size = mi_rows * mi_cols * sizeof(*lc->consec_zero_mv); CHECK_MEM_ERROR(cm, lc->consec_zero_mv, vpx_malloc(consec_zero_mv_size)); memset(lc->consec_zero_mv, 0, consec_zero_mv_size); } } } // Still have extra buffer for base layer golden frame if (!(svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) && alt_ref_idx < REF_FRAMES) svc->layer_context[0].gold_ref_idx = alt_ref_idx; }