diff options
author | hkuang <hkuang@google.com> | 2014-11-18 16:18:20 -0800 |
---|---|---|
committer | hkuang <hkuang@google.com> | 2014-12-08 12:30:19 -0800 |
commit | d05cf10fe718ebb09394d9c183ed046d05a8e6a2 (patch) | |
tree | 2756e868bce262ebf87aec5652a0fd9e8e161d8d /vp9/decoder | |
parent | a9a20a104018589de1efb58c61aeb84b327b54b7 (diff) | |
download | libvpx-d05cf10fe718ebb09394d9c183ed046d05a8e6a2.tar libvpx-d05cf10fe718ebb09394d9c183ed046d05a8e6a2.tar.gz libvpx-d05cf10fe718ebb09394d9c183ed046d05a8e6a2.tar.bz2 libvpx-d05cf10fe718ebb09394d9c183ed046d05a8e6a2.zip |
Add error handling for frame parallel decode and unit test for that.
Change-Id: I6e309e11f1641618d2424b7a2c0fe744b8974dec
Diffstat (limited to 'vp9/decoder')
-rw-r--r-- | vp9/decoder/vp9_decodeframe.c | 23 | ||||
-rw-r--r-- | vp9/decoder/vp9_decoder.c | 57 | ||||
-rw-r--r-- | vp9/decoder/vp9_decoder.h | 17 | ||||
-rw-r--r-- | vp9/decoder/vp9_dthread.c | 22 |
4 files changed, 86 insertions, 33 deletions
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index da973c3c8..b93eed8f4 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -648,6 +648,7 @@ static void apply_frame_size(VP9_COMMON *cm, int width, int height) { cm->subsampling_x, cm->subsampling_y, VP9_DEC_BORDER_IN_PIXELS, &pool->frame_bufs[cm->new_fb_idx].raw_frame_buffer, pool->get_fb_cb, pool->cb_priv)) { + unlock_buffer_pool(pool); vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, "Failed to allocate frame buffer"); } @@ -1165,6 +1166,10 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, } setup_frame_size(cm, rb); + if (pbi->need_resync) { + vpx_memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map)); + pbi->need_resync = 0; + } } else { cm->intra_only = cm->show_frame ? 0 : vp9_rb_read_bit(rb); @@ -1176,6 +1181,10 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, pbi->refresh_frame_flags = vp9_rb_read_literal(rb, REF_FRAMES); setup_frame_size(cm, rb); + if (pbi->need_resync) { + vpx_memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map)); + pbi->need_resync = 0; + } } else { pbi->refresh_frame_flags = vp9_rb_read_literal(rb, REF_FRAMES); for (i = 0; i < REFS_PER_FRAME; ++i) { @@ -1203,6 +1212,12 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, } } + if (pbi->need_resync) { + vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME, + "Keyframe / intra-only frame required to reset decoder" + " state"); + } + if (!cm->error_resilient_mode) { cm->coding_use_prev_mi = 1; cm->refresh_frame_context = vp9_rb_read_bit(rb); @@ -1239,6 +1254,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, ++frame_bufs[cm->ref_frame_map[ref_index]].ref_count; } unlock_buffer_pool(pool); + pbi->hold_ref_buf = 1; if (frame_is_intra_only(cm) || cm->error_resilient_mode) vp9_setup_past_independence(cm); @@ -1457,9 +1473,7 @@ void vp9_decode_frame(VP9Decoder *pbi, *p_data_end = decode_tiles(pbi, data + first_partition_size, data_end); } - new_fb->corrupted |= xd->corrupted; - - if (!new_fb->corrupted) { + if (!xd->corrupted) { if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode) { vp9_adapt_coef_probs(cm); @@ -1470,6 +1484,9 @@ void vp9_decode_frame(VP9Decoder *pbi, } else { debug_check_frame_counts(cm); } + } else { + vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME, + "Decode failed. Frame data is corrupted."); } // Non frame parallel update frame context here. diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c index b5f3b1448..85d454203 100644 --- a/vp9/decoder/vp9_decoder.c +++ b/vp9/decoder/vp9_decoder.c @@ -58,6 +58,7 @@ VP9Decoder *vp9_decoder_create(BufferPool *const pool) { } cm->error.setjmp = 1; + pbi->need_resync = 1; initialize_dec(); vp9_rtcd(); @@ -197,16 +198,6 @@ int vp9_get_reference_dec(VP9Decoder *pbi, int index, YV12_BUFFER_CONFIG **fb) { return 0; } -static INLINE void decrease_ref_count(int idx, RefCntBuffer *const frame_bufs, - BufferPool *const pool) { - if (idx >= 0) { - --frame_bufs[idx].ref_count; - if (frame_bufs[idx].ref_count == 0) { - pool->release_fb_cb(pool->cb_priv, &frame_bufs[idx].raw_frame_buffer); - } - } -} - /* If any buffer updating is signaled it should be done here. */ static void swap_frame_buffers(VP9Decoder *pbi) { int ref_index = 0, mask; @@ -235,7 +226,7 @@ static void swap_frame_buffers(VP9Decoder *pbi) { cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index]; } unlock_buffer_pool(pool); - + pbi->hold_ref_buf = 0; cm->frame_to_show = get_frame_new_buffer(cm); if (!pbi->frame_parallel_decode || !cm->show_frame) { @@ -256,7 +247,6 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; const uint8_t *source = *psource; int retcode = 0; - cm->error.error_code = VPX_CODEC_OK; if (size == 0) { @@ -282,7 +272,7 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, &frame_bufs[cm->new_fb_idx].raw_frame_buffer); cm->new_fb_idx = get_free_fb(cm); - + pbi->hold_ref_buf = 0; if (pbi->frame_parallel_decode) { VP9Worker *const worker = pbi->frame_worker_owner; vp9_frameworker_lock_stats(worker); @@ -300,18 +290,35 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, cm->error.setjmp = 0; pbi->ready_for_new_data = 1; - // We do not know if the missing frame(s) was supposed to update - // any of the reference buffers, but we act conservative and - // mark only the last buffer as corrupted. - // - // TODO(jkoleszar): Error concealment is undefined and non-normative - // at this point, but if it becomes so, [0] may not always be the correct - // thing to do here. - if (cm->frame_refs[0].idx != INT_MAX && cm->frame_refs[0].buf != NULL) - cm->frame_refs[0].buf->corrupted = 1; - - if (frame_bufs[cm->new_fb_idx].ref_count > 0) - --frame_bufs[cm->new_fb_idx].ref_count; + lock_buffer_pool(pool); + // Release all the reference buffers if worker thread is holding them. + if (pbi->hold_ref_buf == 1) { + int ref_index = 0, mask; + VP9_COMMON *const cm = &pbi->common; + BufferPool *const pool = cm->buffer_pool; + RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; + for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) { + const int old_idx = cm->ref_frame_map[ref_index]; + // Current thread releases the holding of reference frame. + decrease_ref_count(old_idx, frame_bufs, pool); + + // Release the reference frame in reference map. + if ((mask & 1) && old_idx >= 0) { + decrease_ref_count(old_idx, frame_bufs, pool); + } + ++ref_index; + } + + // Current thread releases the holding of reference frame. + for (; ref_index < REF_FRAMES && !cm->show_existing_frame; ++ref_index) { + const int old_idx = cm->ref_frame_map[ref_index]; + decrease_ref_count(old_idx, frame_bufs, pool); + } + pbi->hold_ref_buf = 0; + } + // Release current frame. + decrease_ref_count(cm->new_fb_idx, frame_bufs, pool); + unlock_buffer_pool(pool); return -1; } diff --git a/vp9/decoder/vp9_decoder.h b/vp9/decoder/vp9_decoder.h index 9844e2031..aa4217103 100644 --- a/vp9/decoder/vp9_decoder.h +++ b/vp9/decoder/vp9_decoder.h @@ -65,6 +65,8 @@ typedef struct VP9Decoder { int max_threads; int inv_tile_order; + int need_resync; // wait for key/intra-only frame. + int hold_ref_buf; // hold the reference buffer. } VP9Decoder; int vp9_receive_compressed_data(struct VP9Decoder *pbi, @@ -88,6 +90,21 @@ struct VP9Decoder *vp9_decoder_create(BufferPool *const pool); void vp9_decoder_remove(struct VP9Decoder *pbi); +static INLINE void decrease_ref_count(int idx, RefCntBuffer *const frame_bufs, + BufferPool *const pool) { + if (idx >= 0) { + --frame_bufs[idx].ref_count; + // A worker may only get a free framebuffer index when calling get_free_fb. + // But the private buffer is not set up until finish decoding header. + // So any error happens during decoding header, the frame_bufs will not + // have valid priv buffer. + if (frame_bufs[idx].ref_count == 0 && + frame_bufs[idx].raw_frame_buffer.priv) { + pool->release_fb_cb(pool->cb_priv, &frame_bufs[idx].raw_frame_buffer); + } + } +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/decoder/vp9_dthread.c b/vp9/decoder/vp9_dthread.c index f599c2a8b..d0be882df 100644 --- a/vp9/decoder/vp9_dthread.c +++ b/vp9/decoder/vp9_dthread.c @@ -320,7 +320,7 @@ void vp9_frameworker_wait(VP9Worker *const worker, RefCntBuffer *const ref_buf, // Enabling the following line of code will get harmless tsan error but // will get best performance. - // if (ref_buf->row >= row) return; + // if (ref_buf->row >= row && ref_buf->buf.corrupted != 1) return; { // Find the worker thread that owns the reference frame. If the reference @@ -340,10 +340,19 @@ void vp9_frameworker_wait(VP9Worker *const worker, RefCntBuffer *const ref_buf, #endif vp9_frameworker_lock_stats(ref_worker); - while (ref_buf->row < row && pbi->cur_buf == ref_buf) { + 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; + vp9_frameworker_unlock_stats(ref_worker); + vpx_internal_error(&worker_data->pbi->common.error, + VPX_CODEC_CORRUPT_FRAME, + "Worker %p failed to decode frame", worker); + } vp9_frameworker_unlock_stats(ref_worker); } #else @@ -358,8 +367,11 @@ void vp9_frameworker_broadcast(RefCntBuffer *const buf, int row) { VP9Worker *worker = buf->frame_worker_owner; #ifdef DEBUG_THREAD - printf("%d %p worker decode to (%d) \r\n", worker_data->worker_id, - buf->frame_worker_owner, row); + { + FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1; + printf("%d %p worker decode to (%d) \r\n", worker_data->worker_id, + buf->frame_worker_owner, row); + } #endif vp9_frameworker_lock_stats(worker); @@ -403,7 +415,7 @@ void vp9_frameworker_copy_context(VP9Worker *const dst_worker, dst_cm->prev_mi_grid_visible = src_cm->mi_grid_visible; dst_cm->last_frame_seg_map = src_cm->current_frame_seg_map; } - + dst_worker_data->pbi->need_resync = src_worker_data->pbi->need_resync; vp9_frameworker_unlock_stats(src_worker); dst_worker_data->pbi->prev_buf = |