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) { YV12_BUFFER_CONFIG sd = { 0 }; int64_t time_stamp = 0, time_end_stamp = 0; vp9_ppflags_t flags = {0}; VP9_COMMON *cm = NULL; 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) { const vpx_codec_err_t res = ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si); if (res != VPX_CODEC_OK) return res; } // Initialize the decoder instance on the first frame if (!ctx->decoder_init) { init_decoder(ctx); if (ctx->pbi == NULL) return VPX_CODEC_ERROR; ctx->decoder_init = 1; } cm = &ctx->pbi->common; if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline)) return update_error_state(ctx, &cm->error); if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) set_ppflags(ctx, &flags); if (vp9_get_raw_frame(ctx->pbi, &sd, &time_stamp, &time_end_stamp, &flags)) return update_error_state(ctx, &cm->error); 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 VPX_CODEC_OK; }
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) { vp9_ppflags_t flags = {0}; VP9_COMMON *cm = NULL; (void)deadline; // 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) { const vpx_codec_err_t res = decoder_peek_si_internal(*data, data_sz, &ctx->si, ctx->decrypt_cb, ctx->decrypt_state); if (res != VPX_CODEC_OK) return res; if (!ctx->si.is_kf) return VPX_CODEC_ERROR; } // Initialize the decoder instance on the first frame if (ctx->pbi == NULL) { init_decoder(ctx); if (ctx->pbi == NULL) return VPX_CODEC_ERROR; } // Set these even if already initialized. The caller may have changed the // decrypt config between frames. ctx->pbi->decrypt_cb = ctx->decrypt_cb; ctx->pbi->decrypt_state = ctx->decrypt_state; cm = &ctx->pbi->common; if (vp9_receive_compressed_data(ctx->pbi, data_sz, data)) return update_error_state(ctx, &cm->error); if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) set_ppflags(ctx, &flags); return VPX_CODEC_OK; }
static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx, vpx_codec_iter_t *iter) { vpx_image_t *img = NULL; // Only return frame when all the cpu are busy or // application fluhsed the decoder in frame parallel decode. if (ctx->frame_parallel_decode && ctx->available_threads > 0 && !ctx->flushed) { return NULL; } // Output the frames in the cache first. if (ctx->num_cache_frames > 0) { release_last_output_frame(ctx); ctx->last_show_frame = ctx->frame_cache[ctx->frame_cache_read].fb_idx; if (ctx->need_resync) return NULL; img = &ctx->frame_cache[ctx->frame_cache_read].img; ctx->frame_cache_read = (ctx->frame_cache_read + 1) % FRAME_CACHE_SIZE; --ctx->num_cache_frames; return img; } // iter acts as a flip flop, so an image is only returned on the first // call to get_frame. if (*iter == NULL && ctx->frame_workers != NULL) { do { YV12_BUFFER_CONFIG sd; vp9_ppflags_t flags = {0, 0, 0}; const VPxWorkerInterface *const winterface = vpx_get_worker_interface(); VPxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id]; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; ctx->next_output_worker_id = (ctx->next_output_worker_id + 1) % ctx->num_frame_workers; if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) set_ppflags(ctx, &flags); // Wait for the frame from worker thread. if (winterface->sync(worker)) { // Check if worker has received any frames. if (frame_worker_data->received_frame == 1) { ++ctx->available_threads; frame_worker_data->received_frame = 0; check_resync(ctx, frame_worker_data->pbi); } if (vp9_get_raw_frame(frame_worker_data->pbi, &sd, &flags) == 0) { VP9_COMMON *const cm = &frame_worker_data->pbi->common; RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; release_last_output_frame(ctx); ctx->last_show_frame = frame_worker_data->pbi->common.new_fb_idx; if (ctx->need_resync) return NULL; yuvconfig2image(&ctx->img, &sd, frame_worker_data->user_priv); ctx->img.fb_priv = frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv; img = &ctx->img; return img; } } else { // Decoding failed. Release the worker thread. frame_worker_data->received_frame = 0; ++ctx->available_threads; ctx->need_resync = 1; if (ctx->flushed != 1) return NULL; } } while (ctx->next_output_worker_id != ctx->next_submit_worker_id); } return NULL; }
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) { vp9_ppflags_t flags = {0, 0, 0}; const VP9WorkerInterface *const winterface = vp9_get_worker_interface(); (void)deadline; // 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) { int is_intra_only = 0; const vpx_codec_err_t res = decoder_peek_si_internal(*data, data_sz, &ctx->si, &is_intra_only, ctx->decrypt_cb, ctx->decrypt_state); if (res != VPX_CODEC_OK) return res; if (!ctx->si.is_kf && !is_intra_only) return VPX_CODEC_ERROR; } if (!ctx->frame_parallel_decode) { VP9Worker *const worker = ctx->frame_workers; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; frame_worker_data->data = *data; frame_worker_data->data_size = data_sz; frame_worker_data->user_priv = user_priv; frame_worker_data->received_frame = 1; // Set these even if already initialized. The caller may have changed the // decrypt config between frames. frame_worker_data->pbi->decrypt_cb = ctx->decrypt_cb; frame_worker_data->pbi->decrypt_state = ctx->decrypt_state; worker->had_error = 0; winterface->execute(worker); // Update data pointer after decode. *data = frame_worker_data->data_end; if (worker->had_error) return update_error_state(ctx, &frame_worker_data->pbi->common.error); check_resync(ctx, frame_worker_data->pbi); } else { VP9Worker *const worker = &ctx->frame_workers[ctx->next_submit_worker_id]; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; // Copy context from last worker thread to next worker thread. if (ctx->next_submit_worker_id != ctx->last_submit_worker_id) vp9_frameworker_copy_context( &ctx->frame_workers[ctx->next_submit_worker_id], &ctx->frame_workers[ctx->last_submit_worker_id]); frame_worker_data->pbi->ready_for_new_data = 0; // Copy the compressed data into worker's internal buffer. // TODO(hkuang): Will all the workers allocate the same size // as the size of the first intra frame be better? This will // avoid too many deallocate and allocate. if (frame_worker_data->scratch_buffer_size < data_sz) { frame_worker_data->scratch_buffer = (uint8_t *)vpx_realloc(frame_worker_data->scratch_buffer, data_sz); if (frame_worker_data->scratch_buffer == NULL) { set_error_detail(ctx, "Failed to reallocate scratch buffer"); return VPX_CODEC_MEM_ERROR; } frame_worker_data->scratch_buffer_size = data_sz; } frame_worker_data->data_size = data_sz; vpx_memcpy(frame_worker_data->scratch_buffer, *data, data_sz); frame_worker_data->frame_decoded = 0; frame_worker_data->frame_context_ready = 0; frame_worker_data->received_frame = 1; frame_worker_data->data = frame_worker_data->scratch_buffer; frame_worker_data->user_priv = user_priv; if (ctx->next_submit_worker_id != ctx->last_submit_worker_id) ctx->last_submit_worker_id = (ctx->last_submit_worker_id + 1) % ctx->num_frame_workers; ctx->next_submit_worker_id = (ctx->next_submit_worker_id + 1) % ctx->num_frame_workers; --ctx->available_threads; worker->had_error = 0; winterface->launch(worker); } if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC) set_ppflags(ctx, &flags); return VPX_CODEC_OK; }