/* * Copyright (c) 2010 The WebM project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree.
*/
if (xd->mode_info_context->mbmi.mb_skip_coeff) {
vp8_reset_mb_tokens_context(xd);
} elseif (!vp8dx_bool_error(xd->current_bc)) { int eobtotal;
eobtotal = vp8_decode_mb_tokens(pbi, xd);
/* Special case: Force the loopfilter to skip when eobtotal is zero */
xd->mode_info_context->mbmi.mb_skip_coeff = (eobtotal == 0);
}
mode = xd->mode_info_context->mbmi.mode;
if (xd->segmentation_enabled) vp8_mb_init_dequantizer(pbi, xd);
#if CONFIG_ERROR_CONCEALMENT
if (pbi->ec_active) { int throw_residual; /* When we have independent partitions we can apply residual even * though other partitions within the frame are corrupt.
*/
throw_residual =
(!pbi->independent_partitions && pbi->frame_corrupt_residual);
throw_residual = (throw_residual || vp8dx_bool_error(xd->current_bc));
if ((mb_idx >= pbi->mvs_corrupt_from_mb || throw_residual)) { /* MB with corrupt residuals or corrupt mode/motion vectors. * Better to use the predictor as reconstruction.
*/
pbi->frame_corrupt_residual = 1;
memset(xd->qcoeff, 0, sizeof(xd->qcoeff));
corruption_detected = 1;
/* force idct to be skipped for B_PRED and use the * prediction only for reconstruction
* */
memset(xd->eobs, 0, 25);
}
} #endif
/* do prediction */ if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) {
vp8_build_intra_predictors_mbuv_s(
xd, xd->recon_above[1], xd->recon_above[2], xd->recon_left[1],
xd->recon_left[2], xd->recon_left_stride[1], xd->dst.u_buffer,
xd->dst.v_buffer, xd->dst.uv_stride);
if (mode != B_PRED) {
vp8_build_intra_predictors_mby_s(
xd, xd->recon_above[0], xd->recon_left[0], xd->recon_left_stride[0],
xd->dst.y_buffer, xd->dst.y_stride);
} else { short *DQC = xd->dequant_y1; int dst_stride = xd->dst.y_stride;
/* clear out residual eob info */ if (xd->mode_info_context->mbmi.mb_skip_coeff) memset(xd->eobs, 0, 25);
for (mb_row = start_mb_row; mb_row < pc->mb_rows;
mb_row += (pbi->decoding_thread_count + 1)) { int recon_yoffset, recon_uvoffset; int mb_col; int filter_level;
loop_filter_info_n *lfi_n = &pc->lf_info;
/* save last row processed by this thread */
last_mb_row = mb_row; /* select bool coder for current partition */
xd->current_bc = &pbi->mbc[mb_row % num_part];
/* Distance of MB to the various image edges. * These are specified to 8th pel as they are always * compared to values that are in 1/8th pel units.
*/
xd->mb_to_left_edge = -((mb_col * 16) << 3);
xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
#if CONFIG_ERROR_CONCEALMENT
{ int corrupt_residual =
(!pbi->independent_partitions && pbi->frame_corrupt_residual) ||
vp8dx_bool_error(xd->current_bc); if (pbi->ec_active &&
(xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
corrupt_residual) { /* We have an intra block with corrupt * coefficients, better to conceal with an inter * block. * Interpolate MVs from neighboring MBs * * Note that for the first mb with corrupt * residual in a frame, we might not discover * that before decoding the residual. That * happens after this check, and therefore no * inter concealment will be done.
*/
vp8_interpolate_motion(xd, mb_row, mb_col, pc->mb_rows, pc->mb_cols);
}
} #endif
/* propagate errors from reference frames */
xd->corrupted |= ref_fb_corrupted[xd->mode_info_context->mbmi.ref_frame];
if (xd->corrupted) { // Move current decoding marcoblock to the end of row for all rows // assigned to this thread, such that other threads won't be waiting. for (; mb_row < pc->mb_rows;
mb_row += (pbi->decoding_thread_count + 1)) {
current_mb_col = &pbi->mt_current_mb_col[mb_row];
vpx_atomic_store_release(current_mb_col, pc->mb_cols + nsync);
}
vpx_internal_error(&xd->error_info, VPX_CODEC_CORRUPT_FRAME, "Corrupted reference frame");
}
if (xd->mode_info_context->mbmi.ref_frame >= LAST_FRAME) { const MV_REFERENCE_FRAME ref = xd->mode_info_context->mbmi.ref_frame;
xd->pre.y_buffer = ref_buffer[ref][0] + recon_yoffset;
xd->pre.u_buffer = ref_buffer[ref][1] + recon_uvoffset;
xd->pre.v_buffer = ref_buffer[ref][2] + recon_uvoffset;
} else { // ref_frame is INTRA_FRAME, pre buffer should not be used.
xd->pre.y_buffer = 0;
xd->pre.u_buffer = 0;
xd->pre.v_buffer = 0;
}
mt_decode_macroblock(pbi, xd, 0);
xd->left_available = 1;
/* check if the boolean decoder has suffered an error */
xd->corrupted |= vp8dx_bool_error(xd->current_bc);
/* save left_col for next MB decoding */ if (mb_col != pc->mb_cols - 1) {
MODE_INFO *next = xd->mode_info_context + 1;
if (next->mbmi.ref_frame == INTRA_FRAME) { for (i = 0; i < 16; ++i) {
pbi->mt_yleft_col[mb_row][i] =
xd->dst.y_buffer[i * recon_y_stride + 15];
} for (i = 0; i < 8; ++i) {
pbi->mt_uleft_col[mb_row][i] =
xd->dst.u_buffer[i * recon_uv_stride + 7];
pbi->mt_vleft_col[mb_row][i] =
xd->dst.v_buffer[i * recon_uv_stride + 7];
}
}
}
/* loopfilter on this macroblock. */ if (filter_level) { if (pc->filter_type == NORMAL_LOOPFILTER) {
loop_filter_info lfi;
FRAME_TYPE frame_type = pc->frame_type; constint hev_index = lfi_n->hev_thr_lut[frame_type][filter_level];
lfi.mblim = lfi_n->mblim[filter_level];
lfi.blim = lfi_n->blim[filter_level];
lfi.lim = lfi_n->lim[filter_level];
lfi.hev_thr = lfi_n->hev_thr[hev_index];
if (mb_col > 0)
vp8_loop_filter_mbv(xd->dst.y_buffer, xd->dst.u_buffer,
xd->dst.v_buffer, recon_y_stride,
recon_uv_stride, &lfi);
if (!skip_lf)
vp8_loop_filter_bv(xd->dst.y_buffer, xd->dst.u_buffer,
xd->dst.v_buffer, recon_y_stride,
recon_uv_stride, &lfi);
/* don't apply across umv border */ if (mb_row > 0)
vp8_loop_filter_mbh(xd->dst.y_buffer, xd->dst.u_buffer,
xd->dst.v_buffer, recon_y_stride,
recon_uv_stride, &lfi);
if (!skip_lf)
vp8_loop_filter_bh(xd->dst.y_buffer, xd->dst.u_buffer,
xd->dst.v_buffer, recon_y_stride,
recon_uv_stride, &lfi);
} else { if (mb_col > 0)
vp8_loop_filter_simple_mbv(xd->dst.y_buffer, recon_y_stride,
lfi_n->mblim[filter_level]);
if (!skip_lf)
vp8_loop_filter_simple_bv(xd->dst.y_buffer, recon_y_stride,
lfi_n->blim[filter_level]);
/* don't apply across umv border */ if (mb_row > 0)
vp8_loop_filter_simple_mbh(xd->dst.y_buffer, recon_y_stride,
lfi_n->mblim[filter_level]);
if (!skip_lf)
vp8_loop_filter_simple_bh(xd->dst.y_buffer, recon_y_stride,
lfi_n->blim[filter_level]);
}
}
}
recon_yoffset += 16;
recon_uvoffset += 8;
++xd->mode_info_context; /* next mb */
xd->above_context++;
}
/* adjust to the next row of mbs */ if (pbi->common.filter_level) { if (mb_row != pc->mb_rows - 1) { int lasty = yv12_fb_lst->y_width + VP8BORDERINPIXELS; int lastuv = (yv12_fb_lst->y_width >> 1) + (VP8BORDERINPIXELS >> 1);
/* since we have multithread */
xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count;
}
/* signal end of decoding of current thread for current frame */ if (last_mb_row + (int)pbi->decoding_thread_count + 1 >= pc->mb_rows)
vp8_sem_post(&pbi->h_event_end_decoding);
}
/* limit decoding threads to the max number of token partitions */
core_count = (pbi->max_threads > 8) ? 8 : pbi->max_threads;
/* limit decoding threads to the available cores */ if (core_count > pbi->common.processor_core_count) {
core_count = pbi->common.processor_core_count;
}
if (pthread_create(&pbi->h_decoding_thread[ithread], 0,
thread_decoding_proc, &pbi->de_thread_data[ithread])) {
vp8_sem_destroy(&pbi->h_event_start_decoding[ithread]); break;
}
}
pbi->allocated_decoding_thread_count = ithread; if (pbi->allocated_decoding_thread_count !=
(int)pbi->decoding_thread_count) { /* the remainder of cleanup cases will be handled in
* vp8_decoder_remove_threads(). */ if (pbi->allocated_decoding_thread_count == 0) {
vp8_sem_destroy(&pbi->h_event_end_decoding);
}
vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR, "Failed to create threads");
}
}
}
void vp8mt_de_alloc_temp_buffers(VP8D_COMP *pbi, int mb_rows) { int i;
/* Allocate a vpx_atomic_int for each mb row. */
CHECK_MEM_ERROR(&pc->error, pbi->mt_current_mb_col,
vpx_malloc(sizeof(*pbi->mt_current_mb_col) * pc->mb_rows)); for (i = 0; i < pc->mb_rows; ++i)
vpx_atomic_init(&pbi->mt_current_mb_col[i], 0);
/* Allocate memory for above_row buffers. */
CALLOC_ARRAY(pbi->mt_yabove_row, pc->mb_rows); for (i = 0; i < pc->mb_rows; ++i) {
CHECK_MEM_ERROR(&pc->error, pbi->mt_yabove_row[i],
vpx_memalign(16, sizeof(unsignedchar) *
(width + (VP8BORDERINPIXELS << 1))));
vp8_zero_array(pbi->mt_yabove_row[i], width + (VP8BORDERINPIXELS << 1));
}
CALLOC_ARRAY(pbi->mt_uabove_row, pc->mb_rows); for (i = 0; i < pc->mb_rows; ++i) {
CHECK_MEM_ERROR(&pc->error, pbi->mt_uabove_row[i],
vpx_memalign(16, sizeof(unsignedchar) *
(uv_width + VP8BORDERINPIXELS)));
vp8_zero_array(pbi->mt_uabove_row[i], uv_width + VP8BORDERINPIXELS);
}
CALLOC_ARRAY(pbi->mt_vabove_row, pc->mb_rows); for (i = 0; i < pc->mb_rows; ++i) {
CHECK_MEM_ERROR(&pc->error, pbi->mt_vabove_row[i],
vpx_memalign(16, sizeof(unsignedchar) *
(uv_width + VP8BORDERINPIXELS)));
vp8_zero_array(pbi->mt_vabove_row[i], uv_width + VP8BORDERINPIXELS);
}
/* Allocate memory for left_col buffers. */
CALLOC_ARRAY(pbi->mt_yleft_col, pc->mb_rows); for (i = 0; i < pc->mb_rows; ++i)
CHECK_MEM_ERROR(&pc->error, pbi->mt_yleft_col[i],
vpx_calloc(sizeof(unsignedchar) * 16, 1));
CALLOC_ARRAY(pbi->mt_uleft_col, pc->mb_rows); for (i = 0; i < pc->mb_rows; ++i)
CHECK_MEM_ERROR(&pc->error, pbi->mt_uleft_col[i],
vpx_calloc(sizeof(unsignedchar) * 8, 1));
CALLOC_ARRAY(pbi->mt_vleft_col, pc->mb_rows); for (i = 0; i < pc->mb_rows; ++i)
CHECK_MEM_ERROR(&pc->error, pbi->mt_vleft_col[i],
vpx_calloc(sizeof(unsignedchar) * 8, 1));
}
}
void vp8_decoder_remove_threads(VP8D_COMP *pbi) { /* shutdown MB Decoding thread; */ if (vpx_atomic_load_acquire(&pbi->b_multithreaded_rd)) { int i;
vpx_atomic_store_release(&pbi->b_multithreaded_rd, 0);
/* allow all threads to exit */ for (i = 0; i < pbi->allocated_decoding_thread_count; ++i) {
vp8_sem_post(&pbi->h_event_start_decoding[i]);
pthread_join(pbi->h_decoding_thread[i], NULL);
}
for (i = 0; i < pbi->allocated_decoding_thread_count; ++i) {
vp8_sem_destroy(&pbi->h_event_start_decoding[i]);
}
if (pbi->allocated_decoding_thread_count) {
vp8_sem_destroy(&pbi->h_event_end_decoding);
}
for (i = 0; i < pbi->decoding_thread_count; ++i) {
vp8_sem_post(&pbi->h_event_start_decoding[i]);
}
if (setjmp(xd->error_info.jmp)) {
xd->error_info.setjmp = 0;
xd->corrupted = 1; // Wait for other threads to finish. This prevents other threads decoding // the current frame while the main thread starts decoding the next frame, // which causes a data race. for (i = 0; i < pbi->decoding_thread_count; ++i)
vp8_sem_wait(&pbi->h_event_end_decoding); return -1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.