/* If any buffer updating is signaled it should be done here. */ static void swap_frame_buffers(AV1Decoder *pbi) { int ref_index = 0, mask; AV1_COMMON *const cm = &pbi->common; BufferPool *const pool = cm->buffer_pool; RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; lock_buffer_pool(pool); 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 holding in the reference map for the decoding // of the next frame. if (mask & 1) decrease_ref_count(old_idx, frame_bufs, pool); cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index]; ++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); 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); // TODO(zoeliu): To fix the ref frame buffer update for the scenario of // cm->frame_parellel_decode == 1 if (!cm->frame_parallel_decode || !cm->show_frame) { lock_buffer_pool(pool); --frame_bufs[cm->new_fb_idx].ref_count; unlock_buffer_pool(pool); } // Invalidate these references until the next frame starts. for (ref_index = 0; ref_index < INTER_REFS_PER_FRAME; ref_index++) { cm->frame_refs[ref_index].idx = INVALID_IDX; cm->frame_refs[ref_index].buf = NULL; } }
static void release_last_output_frame(vpx_codec_alg_priv_t *ctx) { RefCntBuffer *const frame_bufs = ctx->buffer_pool->frame_bufs; // Decrease reference count of last output frame in frame parallel mode. if (ctx->frame_parallel_decode && ctx->last_show_frame >= 0) { BufferPool *const pool = ctx->buffer_pool; lock_buffer_pool(pool); decrease_ref_count(ctx->last_show_frame, frame_bufs, pool); unlock_buffer_pool(pool); } }
/* If any buffer updating is signaled it should be done here. */ static void swap_frame_buffers(VP10Decoder *pbi) { int ref_index = 0, mask; VP10_COMMON *const cm = &pbi->common; BufferPool *const pool = cm->buffer_pool; RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; lock_buffer_pool(pool); 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); } cm->ref_frame_map[ref_index] = cm->next_ref_frame_map[ref_index]; ++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); 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) { lock_buffer_pool(pool); --frame_bufs[cm->new_fb_idx].ref_count; unlock_buffer_pool(pool); } // Invalidate these references until the next frame starts. for (ref_index = 0; ref_index < 3; ref_index++) cm->frame_refs[ref_index].idx = -1; }
static int frame_worker_hook(void *arg1, void *arg2) { FrameWorkerData *const frame_worker_data = (FrameWorkerData *)arg1; const uint8_t *data = frame_worker_data->data; (void)arg2; frame_worker_data->result = vp9_receive_compressed_data(frame_worker_data->pbi, frame_worker_data->data_size, &data); frame_worker_data->data_end = data; if (frame_worker_data->pbi->frame_parallel_decode) { // In frame parallel decoding, a worker thread must successfully decode all // the compressed data. if (frame_worker_data->result != 0 || frame_worker_data->data + frame_worker_data->data_size - 1 > data) { VPxWorker *const worker = frame_worker_data->pbi->frame_worker_owner; BufferPool *const pool = frame_worker_data->pbi->common.buffer_pool; // Signal all the other threads that are waiting for this frame. vp9_frameworker_lock_stats(worker); frame_worker_data->frame_context_ready = 1; lock_buffer_pool(pool); frame_worker_data->pbi->cur_buf->buf.corrupted = 1; unlock_buffer_pool(pool); frame_worker_data->pbi->need_resync = 1; vp9_frameworker_signal_stats(worker); vp9_frameworker_unlock_stats(worker); return 0; } } else if (frame_worker_data->result != 0) { // Check decode result in serial decode. frame_worker_data->pbi->cur_buf->buf.corrupted = 1; frame_worker_data->pbi->need_resync = 1; } return !frame_worker_data->result; }
int vp10_receive_compressed_data(VP10Decoder *pbi, size_t size, const uint8_t **psource) { VP10_COMMON *volatile const cm = &pbi->common; BufferPool *volatile const pool = cm->buffer_pool; RefCntBuffer *volatile 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) { // This is used to signal that we are missing frames. // 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 > 0) { assert(cm->frame_refs[0].buf != NULL); cm->frame_refs[0].buf->corrupted = 1; } } pbi->ready_for_new_data = 0; // Check if the previous frame was a frame without any references to it. // Release frame buffer if not decoding in frame parallel mode. if (!pbi->frame_parallel_decode && cm->new_fb_idx >= 0 && frame_bufs[cm->new_fb_idx].ref_count == 0) pool->release_fb_cb(pool->cb_priv, &frame_bufs[cm->new_fb_idx].raw_frame_buffer); // Find a free frame buffer. Return error if can not find any. cm->new_fb_idx = get_free_fb(cm); if (cm->new_fb_idx == INVALID_IDX) return VPX_CODEC_MEM_ERROR; // Assign a MV array to the frame buffer. cm->cur_frame = &pool->frame_bufs[cm->new_fb_idx]; pbi->hold_ref_buf = 0; if (pbi->frame_parallel_decode) { VPxWorker *const worker = pbi->frame_worker_owner; vp10_frameworker_lock_stats(worker); frame_bufs[cm->new_fb_idx].frame_worker_owner = worker; // Reset decoding progress. pbi->cur_buf = &frame_bufs[cm->new_fb_idx]; pbi->cur_buf->row = -1; pbi->cur_buf->col = -1; vp10_frameworker_unlock_stats(worker); } else { pbi->cur_buf = &frame_bufs[cm->new_fb_idx]; } if (setjmp(cm->error.jmp)) { const VPxWorkerInterface *const winterface = vpx_get_worker_interface(); int i; cm->error.setjmp = 0; pbi->ready_for_new_data = 1; // Synchronize all threads immediately as a subsequent decode call may // cause a resize invalidating some allocations. winterface->sync(&pbi->lf_worker); for (i = 0; i < pbi->num_tile_workers; ++i) { winterface->sync(&pbi->tile_workers[i]); } 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; 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); vpx_clear_system_state(); return -1; }