Compare commits
5 Commits
highbitdep
...
sandbox/hk
Author | SHA1 | Date | |
---|---|---|---|
![]() |
21e9f79d25 | ||
![]() |
ffd20828d0 | ||
![]() |
10aa23f751 | ||
![]() |
28a794f680 | ||
![]() |
bf58d1725c |
@@ -97,14 +97,15 @@ static void free_mi(VP9_COMMON *cm) {
|
||||
|
||||
void vp9_free_frame_buffers(VP9_COMMON *cm) {
|
||||
int i;
|
||||
BufferPool *const pool = cm->buffer_pool;
|
||||
|
||||
for (i = 0; i < FRAME_BUFFERS; ++i) {
|
||||
vp9_free_frame_buffer(&cm->frame_bufs[i].buf);
|
||||
vp9_free_frame_buffer(&pool->frame_bufs[i].buf);
|
||||
|
||||
if (cm->frame_bufs[i].ref_count > 0 &&
|
||||
cm->frame_bufs[i].raw_frame_buffer.data != NULL) {
|
||||
cm->release_fb_cb(cm->cb_priv, &cm->frame_bufs[i].raw_frame_buffer);
|
||||
cm->frame_bufs[i].ref_count = 0;
|
||||
if (pool->frame_bufs[i].ref_count > 0 &&
|
||||
pool->frame_bufs[i].raw_frame_buffer.data != NULL) {
|
||||
pool->release_fb_cb(pool->cb_priv, &pool->frame_bufs[i].raw_frame_buffer);
|
||||
pool->frame_bufs[i].ref_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,13 +177,14 @@ int vp9_resize_frame_buffers(VP9_COMMON *cm, int width, int height) {
|
||||
|
||||
static void init_frame_bufs(VP9_COMMON *cm) {
|
||||
int i;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
|
||||
cm->new_fb_idx = FRAME_BUFFERS - 1;
|
||||
cm->frame_bufs[cm->new_fb_idx].ref_count = 1;
|
||||
frame_bufs[cm->new_fb_idx].ref_count = 1;
|
||||
|
||||
for (i = 0; i < REF_FRAMES; ++i) {
|
||||
cm->ref_frame_map[i] = i;
|
||||
cm->frame_bufs[i].ref_count = 1;
|
||||
frame_bufs[i].ref_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,12 +192,13 @@ int vp9_alloc_frame_buffers(VP9_COMMON *cm, int width, int height) {
|
||||
int i;
|
||||
const int ss_x = cm->subsampling_x;
|
||||
const int ss_y = cm->subsampling_y;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
|
||||
vp9_free_frame_buffers(cm);
|
||||
|
||||
for (i = 0; i < FRAME_BUFFERS; ++i) {
|
||||
cm->frame_bufs[i].ref_count = 0;
|
||||
if (vp9_alloc_frame_buffer(&cm->frame_bufs[i].buf, width, height,
|
||||
frame_bufs[i].ref_count = 0;
|
||||
if (vp9_alloc_frame_buffer(&frame_bufs[i].buf, width, height,
|
||||
ss_x, ss_y, VP9_ENC_BORDER_IN_PIXELS) < 0)
|
||||
goto fail;
|
||||
}
|
||||
@@ -256,7 +259,7 @@ int vp9_alloc_context_buffers(VP9_COMMON *cm, int width, int height) {
|
||||
void vp9_remove_common(VP9_COMMON *cm) {
|
||||
vp9_free_frame_buffers(cm);
|
||||
vp9_free_context_buffers(cm);
|
||||
vp9_free_internal_frame_buffers(&cm->int_frame_buffers);
|
||||
vp9_free_internal_frame_buffers(&cm->buffer_pool->int_frame_buffers);
|
||||
}
|
||||
|
||||
void vp9_update_frame_size(VP9_COMMON *cm) {
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#ifndef VP9_COMMON_VP9_ONYXC_INT_H_
|
||||
#define VP9_COMMON_VP9_ONYXC_INT_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include "./vpx_config.h"
|
||||
#include "vpx/internal/vpx_codec_internal.h"
|
||||
#include "./vp9_rtcd.h"
|
||||
@@ -61,8 +62,40 @@ typedef struct {
|
||||
int ref_count;
|
||||
vpx_codec_frame_buffer_t raw_frame_buffer;
|
||||
YV12_BUFFER_CONFIG buf;
|
||||
|
||||
// The Following variables will only be used in frame parallel decode.
|
||||
|
||||
// owner_thread_id indicates which FrameWorker owns this buffer. -1 means
|
||||
// that no FrameWorker owns, or is decoding, this buffer.
|
||||
int owner_worker_id;
|
||||
|
||||
// Buffer has been decoded to (row, col) position. When first start decoding,
|
||||
// they are reset to -1. If a frame has been fully decoded, row and col will
|
||||
// be set to INT_MAX.
|
||||
int row;
|
||||
int col;
|
||||
} RefCntBuffer;
|
||||
|
||||
typedef struct {
|
||||
// Protect BufferPool from being accessed by several FrameWorkers at
|
||||
// the same time during frame parallel decode.
|
||||
// TODO(hkuang): Try to use atomic variable instead of locking the whole pool.
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_t pool_mutex;
|
||||
#endif
|
||||
|
||||
// Private data associated with the frame buffer callbacks.
|
||||
void *cb_priv;
|
||||
|
||||
vpx_get_frame_buffer_cb_fn_t get_fb_cb;
|
||||
vpx_release_frame_buffer_cb_fn_t release_fb_cb;
|
||||
|
||||
RefCntBuffer frame_bufs[FRAME_BUFFERS];
|
||||
|
||||
// Handles memory for the codec.
|
||||
InternalFrameBufferList int_frame_buffers;
|
||||
} BufferPool;
|
||||
|
||||
typedef struct VP9Common {
|
||||
struct vpx_internal_error_info error;
|
||||
|
||||
@@ -89,10 +122,11 @@ typedef struct VP9Common {
|
||||
|
||||
YV12_BUFFER_CONFIG *frame_to_show;
|
||||
|
||||
RefCntBuffer frame_bufs[FRAME_BUFFERS];
|
||||
|
||||
int ref_frame_map[REF_FRAMES]; /* maps fb_idx to reference slot */
|
||||
|
||||
// Prepare ref_frame_map for next frame. Only used in frame parallel decode.
|
||||
int next_ref_frame_map[REF_FRAMES];
|
||||
|
||||
// TODO(jkoleszar): could expand active_ref_idx to 4, with 0 as intra, and
|
||||
// roll new_fb_idx into it.
|
||||
|
||||
@@ -202,30 +236,33 @@ typedef struct VP9Common {
|
||||
|
||||
int log2_tile_cols, log2_tile_rows;
|
||||
|
||||
// Private data associated with the frame buffer callbacks.
|
||||
void *cb_priv;
|
||||
vpx_get_frame_buffer_cb_fn_t get_fb_cb;
|
||||
vpx_release_frame_buffer_cb_fn_t release_fb_cb;
|
||||
|
||||
// Handles memory for the codec.
|
||||
InternalFrameBufferList int_frame_buffers;
|
||||
// External BufferPool passed from outside.
|
||||
BufferPool *buffer_pool;
|
||||
|
||||
PARTITION_CONTEXT *above_seg_context;
|
||||
ENTROPY_CONTEXT *above_context;
|
||||
} VP9_COMMON;
|
||||
|
||||
static INLINE YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) {
|
||||
return &cm->frame_bufs[cm->new_fb_idx].buf;
|
||||
return &cm->buffer_pool->frame_bufs[cm->new_fb_idx].buf;
|
||||
}
|
||||
|
||||
static INLINE int get_free_fb(VP9_COMMON *cm) {
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
int i;
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
for (i = 0; i < FRAME_BUFFERS; i++)
|
||||
if (cm->frame_bufs[i].ref_count == 0)
|
||||
if (frame_bufs[i].ref_count == 0)
|
||||
break;
|
||||
|
||||
assert(i < FRAME_BUFFERS);
|
||||
cm->frame_bufs[i].ref_count = 1;
|
||||
frame_bufs[i].ref_count = 1;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@@ -621,6 +621,7 @@ static void setup_display_size(VP9_COMMON *cm, struct vp9_read_bit_buffer *rb) {
|
||||
}
|
||||
|
||||
static void apply_frame_size(VP9_COMMON *cm, int width, int height) {
|
||||
BufferPool *const pool = cm->buffer_pool;
|
||||
if (cm->width != width || cm->height != height) {
|
||||
// Change in frame size.
|
||||
// TODO(agrange) Don't test width/height, check overall size.
|
||||
@@ -640,8 +641,8 @@ static void apply_frame_size(VP9_COMMON *cm, int width, int height) {
|
||||
if (vp9_realloc_frame_buffer(
|
||||
get_frame_new_buffer(cm), cm->width, cm->height,
|
||||
cm->subsampling_x, cm->subsampling_y, VP9_DEC_BORDER_IN_PIXELS,
|
||||
&cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer, cm->get_fb_cb,
|
||||
cm->cb_priv)) {
|
||||
&pool->frame_bufs[cm->new_fb_idx].raw_frame_buffer, pool->get_fb_cb,
|
||||
pool->cb_priv)) {
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
|
||||
"Failed to allocate frame buffer");
|
||||
}
|
||||
@@ -1076,8 +1077,9 @@ static BITSTREAM_PROFILE read_profile(struct vp9_read_bit_buffer *rb) {
|
||||
static size_t read_uncompressed_header(VP9Decoder *pbi,
|
||||
struct vp9_read_bit_buffer *rb) {
|
||||
VP9_COMMON *const cm = &pbi->common;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
int mask, i, ref_index = 0;
|
||||
size_t sz;
|
||||
int i;
|
||||
|
||||
cm->last_frame_type = cm->frame_type;
|
||||
|
||||
@@ -1095,12 +1097,18 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
|
||||
// Show an existing frame directly.
|
||||
const int frame_to_show = cm->ref_frame_map[vp9_rb_read_literal(rb, 3)];
|
||||
|
||||
if (frame_to_show < 0 || cm->frame_bufs[frame_to_show].ref_count < 1)
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
if (frame_to_show < 0 || frame_bufs[frame_to_show].ref_count < 1)
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
|
||||
"Buffer %d does not contain a decoded frame",
|
||||
frame_to_show);
|
||||
|
||||
ref_cnt_fb(cm->frame_bufs, &cm->new_fb_idx, frame_to_show);
|
||||
ref_cnt_fb(frame_bufs, &cm->new_fb_idx, frame_to_show);
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
pbi->refresh_frame_flags = 0;
|
||||
cm->lf.filter_level = 0;
|
||||
cm->show_frame = 1;
|
||||
@@ -1161,7 +1169,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
|
||||
const int idx = cm->ref_frame_map[ref];
|
||||
RefBuffer *const ref_frame = &cm->frame_refs[i];
|
||||
ref_frame->idx = idx;
|
||||
ref_frame->buf = &cm->frame_bufs[idx].buf;
|
||||
ref_frame->buf = &frame_bufs[idx].buf;
|
||||
cm->ref_frame_sign_bias[LAST_FRAME + i] = vp9_rb_read_bit(rb);
|
||||
}
|
||||
|
||||
@@ -1196,6 +1204,28 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
|
||||
// below, forcing the use of context 0 for those frame types.
|
||||
cm->frame_context_idx = vp9_rb_read_literal(rb, FRAME_CONTEXTS_LOG2);
|
||||
|
||||
// Update next_ref_frame_map in frame parallel decode.
|
||||
if (pbi->frame_parallel_decode) {
|
||||
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
|
||||
if (mask & 1) {
|
||||
cm->next_ref_frame_map[ref_index] = cm->new_fb_idx;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
++cm->buffer_pool->frame_bufs[cm->new_fb_idx].ref_count;
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
} else {
|
||||
cm->next_ref_frame_map[ref_index] = cm->ref_frame_map[ref_index];
|
||||
}
|
||||
++ref_index;
|
||||
}
|
||||
|
||||
for (; ref_index < REF_FRAMES; ++ref_index)
|
||||
cm->next_ref_frame_map[ref_index] = cm->ref_frame_map[ref_index];
|
||||
}
|
||||
|
||||
if (frame_is_intra_only(cm) || cm->error_resilient_mode)
|
||||
vp9_setup_past_independence(cm);
|
||||
|
||||
@@ -1392,6 +1422,17 @@ void vp9_decode_frame(VP9Decoder *pbi,
|
||||
|
||||
new_fb->corrupted |= xd->corrupted;
|
||||
|
||||
// Update progress in frame parallel decode.
|
||||
if (pbi->frame_parallel_decode) {
|
||||
VP9Worker *worker = pbi->owner_frame_worker;
|
||||
FrameWorkerData *const worker_data = worker->data1;
|
||||
pthread_mutex_lock(&worker_data->stats_mutex);
|
||||
pbi->cur_buf->row = INT_MAX;
|
||||
pbi->cur_buf->col = INT_MAX;
|
||||
pthread_cond_signal(&worker_data->stats_cond);
|
||||
pthread_mutex_unlock(&worker_data->stats_mutex);
|
||||
}
|
||||
|
||||
if (!new_fb->corrupted) {
|
||||
if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode) {
|
||||
vp9_adapt_coef_probs(cm);
|
||||
|
@@ -41,7 +41,7 @@ static void initialize_dec() {
|
||||
}
|
||||
}
|
||||
|
||||
VP9Decoder *vp9_decoder_create() {
|
||||
VP9Decoder *vp9_decoder_create(BufferPool *const pool) {
|
||||
VP9Decoder *const pbi = vpx_memalign(32, sizeof(*pbi));
|
||||
VP9_COMMON *const cm = pbi ? &pbi->common : NULL;
|
||||
|
||||
@@ -63,9 +63,11 @@ VP9Decoder *vp9_decoder_create() {
|
||||
|
||||
// Initialize the references to not point to any frame buffers.
|
||||
vpx_memset(&cm->ref_frame_map, -1, sizeof(cm->ref_frame_map));
|
||||
vpx_memset(&cm->next_ref_frame_map, -1, sizeof(cm->next_ref_frame_map));
|
||||
|
||||
cm->current_video_frame = 0;
|
||||
pbi->ready_for_new_data = 1;
|
||||
pbi->common.buffer_pool = pool;
|
||||
|
||||
// vp9_init_dequantizer() is first called here. Add check in
|
||||
// frame_init_dequantizer() to avoid unnecessary calling of
|
||||
@@ -124,7 +126,7 @@ vpx_codec_err_t vp9_copy_reference_dec(VP9Decoder *pbi,
|
||||
*/
|
||||
if (ref_frame_flag == VP9_LAST_FLAG) {
|
||||
const YV12_BUFFER_CONFIG *const cfg =
|
||||
&cm->frame_bufs[cm->ref_frame_map[0]].buf;
|
||||
&cm->buffer_pool->frame_bufs[cm->ref_frame_map[0]].buf;
|
||||
if (!equal_dimensions(cfg, sd))
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
|
||||
"Incorrect buffer dimensions");
|
||||
@@ -143,6 +145,7 @@ vpx_codec_err_t vp9_set_reference_dec(VP9_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
|
||||
@@ -170,11 +173,11 @@ vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
|
||||
const int free_fb = get_free_fb(cm);
|
||||
// Decrease ref_count since it will be increased again in
|
||||
// ref_cnt_fb() below.
|
||||
cm->frame_bufs[free_fb].ref_count--;
|
||||
--frame_bufs[free_fb].ref_count;
|
||||
|
||||
// Manage the reference counters and copy image.
|
||||
ref_cnt_fb(cm->frame_bufs, ref_fb_ptr, free_fb);
|
||||
ref_buf->buf = &cm->frame_bufs[*ref_fb_ptr].buf;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -184,33 +187,45 @@ vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
|
||||
|
||||
int vp9_get_reference_dec(VP9Decoder *pbi, int index, YV12_BUFFER_CONFIG **fb) {
|
||||
VP9_COMMON *cm = &pbi->common;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
|
||||
if (index < 0 || index >= REF_FRAMES)
|
||||
return -1;
|
||||
|
||||
*fb = &cm->frame_bufs[cm->ref_frame_map[index]].buf;
|
||||
*fb = &frame_bufs[cm->ref_frame_map[index]].buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If any buffer updating is signaled it should be done here. */
|
||||
static void swap_frame_buffers(VP9Decoder *pbi) {
|
||||
int ref_index = 0, mask;
|
||||
VP9_COMMON *const cm = &pbi->common;
|
||||
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) {
|
||||
if (mask & 1) {
|
||||
const int old_idx = cm->ref_frame_map[ref_index];
|
||||
ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[ref_index],
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
ref_cnt_fb(frame_bufs, &cm->ref_frame_map[ref_index],
|
||||
cm->new_fb_idx);
|
||||
if (old_idx >= 0 && cm->frame_bufs[old_idx].ref_count == 0)
|
||||
cm->release_fb_cb(cm->cb_priv,
|
||||
&cm->frame_bufs[old_idx].raw_frame_buffer);
|
||||
if (old_idx >= 0 && frame_bufs[old_idx].ref_count == 0)
|
||||
pool->release_fb_cb(pool->cb_priv,
|
||||
&frame_bufs[old_idx].raw_frame_buffer);
|
||||
}
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
++ref_index;
|
||||
}
|
||||
|
||||
cm->frame_to_show = get_frame_new_buffer(cm);
|
||||
cm->frame_bufs[cm->new_fb_idx].ref_count--;
|
||||
|
||||
if (!pbi->frame_parallel_decode || !cm->show_frame) {
|
||||
--frame_bufs[cm->new_fb_idx].ref_count;
|
||||
}
|
||||
|
||||
// Invalidate these references until the next frame starts.
|
||||
for (ref_index = 0; ref_index < 3; ref_index++)
|
||||
@@ -220,6 +235,8 @@ static void swap_frame_buffers(VP9Decoder *pbi) {
|
||||
int vp9_receive_compressed_data(VP9Decoder *pbi,
|
||||
size_t size, const uint8_t **psource) {
|
||||
VP9_COMMON *const cm = &pbi->common;
|
||||
BufferPool *const pool = cm->buffer_pool;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
const uint8_t *source = *psource;
|
||||
int retcode = 0;
|
||||
|
||||
@@ -239,11 +256,24 @@ int vp9_receive_compressed_data(VP9Decoder *pbi,
|
||||
}
|
||||
|
||||
// Check if the previous frame was a frame without any references to it.
|
||||
if (cm->new_fb_idx >= 0 && cm->frame_bufs[cm->new_fb_idx].ref_count == 0)
|
||||
cm->release_fb_cb(cm->cb_priv,
|
||||
&cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer);
|
||||
// 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);
|
||||
cm->new_fb_idx = get_free_fb(cm);
|
||||
|
||||
if (pbi->frame_parallel_decode) {
|
||||
VP9Worker *worker = pbi->owner_frame_worker;
|
||||
FrameWorkerData *const worker_data = worker->data1;
|
||||
pbi->cur_buf = &pool->frame_bufs[cm->new_fb_idx];
|
||||
pool->frame_bufs[cm->new_fb_idx].owner_worker_id = worker_data->worker_id;
|
||||
|
||||
// Reset the decoding progress.
|
||||
pbi->cur_buf->row = -1;
|
||||
pbi->cur_buf->col = -1;
|
||||
}
|
||||
|
||||
if (setjmp(cm->error.jmp)) {
|
||||
cm->error.setjmp = 0;
|
||||
|
||||
@@ -257,8 +287,8 @@ int vp9_receive_compressed_data(VP9Decoder *pbi,
|
||||
if (cm->frame_refs[0].idx != INT_MAX && cm->frame_refs[0].buf != NULL)
|
||||
cm->frame_refs[0].buf->corrupted = 1;
|
||||
|
||||
if (cm->new_fb_idx > 0 && cm->frame_bufs[cm->new_fb_idx].ref_count > 0)
|
||||
cm->frame_bufs[cm->new_fb_idx].ref_count--;
|
||||
if (frame_bufs[cm->new_fb_idx].ref_count > 0)
|
||||
--frame_bufs[cm->new_fb_idx].ref_count;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@@ -45,8 +45,14 @@ typedef struct VP9Decoder {
|
||||
|
||||
int frame_parallel_decode; // frame-based threading.
|
||||
|
||||
// TODO(hkuang): Combine this with cur_buf in macroblockd as they are
|
||||
// the same.
|
||||
RefCntBuffer *cur_buf; // current decoding reference buffer.
|
||||
|
||||
VP9Worker lf_worker;
|
||||
VP9Worker *tile_workers;
|
||||
VP9Worker *owner_frame_worker; // frame_worker that owns this pbi;
|
||||
|
||||
int num_tile_workers;
|
||||
|
||||
TileData *tile_data;
|
||||
@@ -78,7 +84,7 @@ vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
|
||||
int vp9_get_reference_dec(struct VP9Decoder *pbi,
|
||||
int index, YV12_BUFFER_CONFIG **fb);
|
||||
|
||||
struct VP9Decoder *vp9_decoder_create();
|
||||
struct VP9Decoder *vp9_decoder_create(BufferPool *const pool);
|
||||
|
||||
void vp9_decoder_remove(struct VP9Decoder *pbi);
|
||||
|
||||
|
@@ -279,3 +279,78 @@ void vp9_loop_filter_dealloc(VP9LfSync *lf_sync, int rows) {
|
||||
vp9_zero(*lf_sync);
|
||||
}
|
||||
}
|
||||
|
||||
void vp9_frameworker_wait(VP9Worker* const worker, int row, int col,
|
||||
RefCntBuffer *ref_buf) {
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
const VP9Decoder *const pbi = worker_data->pbi;
|
||||
const RefCntBuffer *const cur_buf = pbi->cur_buf;
|
||||
|
||||
// Check if worker already release the ref_buf.
|
||||
if (!worker || ref_buf->owner_worker_id == -1) return;
|
||||
|
||||
pthread_mutex_lock(&worker_data->stats_mutex);
|
||||
while (!(cur_buf->row >= row && cur_buf->col >= col)
|
||||
&& pbi->cur_buf == ref_buf && ref_buf->owner_worker_id != -1) {
|
||||
pthread_cond_wait(&worker_data->stats_cond, &worker_data->stats_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&worker_data->stats_mutex);
|
||||
}
|
||||
|
||||
void vp9_frameworker_broadcast(VP9Worker* const worker, int row, int col) {
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
const VP9Decoder *const pbi = worker_data->pbi;
|
||||
RefCntBuffer *const cur_buf = pbi->cur_buf;
|
||||
|
||||
pthread_mutex_lock(&worker_data->stats_mutex);
|
||||
cur_buf->row = row;
|
||||
cur_buf->col = col;
|
||||
pthread_cond_signal(&worker_data->stats_cond);
|
||||
pthread_mutex_unlock(&worker_data->stats_mutex);
|
||||
}
|
||||
|
||||
void vp9_frameworker_copy_context(VP9Worker *const dst_worker,
|
||||
const VP9Worker *const src_worker) {
|
||||
FrameWorkerData *const src_worker_data =
|
||||
(FrameWorkerData *)dst_worker->data1;
|
||||
FrameWorkerData *const dst_worker_data =
|
||||
(FrameWorkerData *)src_worker->data1;
|
||||
const VP9_COMMON *const src_cm = &src_worker_data->pbi->common;
|
||||
VP9_COMMON *const dst_cm = &dst_worker_data->pbi->common;
|
||||
int i;
|
||||
|
||||
// Wait until source frame's context is ready.
|
||||
pthread_mutex_lock(&src_worker_data->stats_mutex);
|
||||
while (!src_worker_data->frame_context_ready) {
|
||||
pthread_cond_wait(&src_worker_data->stats_cond,
|
||||
&src_worker_data->stats_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&src_worker_data->stats_mutex);
|
||||
|
||||
dst_cm->last_width = src_cm->width;
|
||||
dst_cm->last_height = src_cm->height;
|
||||
dst_cm->subsampling_x = src_cm->subsampling_x;
|
||||
dst_cm->subsampling_y = src_cm->subsampling_y;
|
||||
|
||||
for (i = 0; i < REF_FRAMES; ++i)
|
||||
dst_cm->ref_frame_map[i] = src_cm->next_ref_frame_map[i];
|
||||
|
||||
dst_cm->last_show_frame = src_cm->show_frame;
|
||||
|
||||
dst_cm->prev_mip = src_cm->mip;
|
||||
dst_cm->prev_mi = src_cm->mi;
|
||||
dst_cm->prev_mi_grid_base = src_cm->mi_grid_base;
|
||||
dst_cm->prev_mi_grid_visible = src_cm->mi_grid_visible;
|
||||
dst_cm->lf.last_sharpness_level = src_cm->lf.sharpness_level;
|
||||
|
||||
for (i = 0; i < MAX_REF_LF_DELTAS; ++i) {
|
||||
dst_cm->lf.last_ref_deltas[i] = src_cm->lf.ref_deltas[i];
|
||||
dst_cm->lf.ref_deltas[i] = src_cm->lf.ref_deltas[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_MODE_LF_DELTAS; ++i)
|
||||
dst_cm-> lf.last_mode_deltas[i] = src_cm->lf.mode_deltas[i];
|
||||
|
||||
for (i = 0; i < FRAME_CONTEXTS; ++i)
|
||||
dst_cm-> frame_contexts[i] = src_cm->frame_contexts[i];
|
||||
}
|
||||
|
@@ -40,6 +40,28 @@ typedef struct VP9LfSyncData {
|
||||
int sync_range;
|
||||
} VP9LfSync;
|
||||
|
||||
// WorkerData for the FrameWorker thread. It contains all the information of
|
||||
// the worker and decode structures for decoding a frame.
|
||||
typedef struct FrameWorkerData {
|
||||
struct VP9Decoder *pbi;
|
||||
const uint8_t *data;
|
||||
const uint8_t *data_end;
|
||||
size_t data_size;
|
||||
void *user_priv;
|
||||
int result;
|
||||
int worker_id;
|
||||
|
||||
// scratch_buffer is used in frame parallel mode only.
|
||||
// It is used to make a copy of the compressed data.
|
||||
uint8_t *scratch_buffer;
|
||||
size_t scratch_buffer_size;
|
||||
|
||||
pthread_mutex_t stats_mutex;
|
||||
pthread_cond_t stats_cond;
|
||||
|
||||
int frame_context_ready; // Current frame's context is ready to read.
|
||||
} FrameWorkerData;
|
||||
|
||||
// Allocate memory for loopfilter row synchronization.
|
||||
void vp9_loop_filter_alloc(struct VP9Common *cm, VP9LfSync *lf_sync,
|
||||
int rows, int width);
|
||||
@@ -54,4 +76,19 @@ void vp9_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame,
|
||||
int frame_filter_level,
|
||||
int y_only);
|
||||
|
||||
// Wait for FrameWorker to finish decoding ref_buf to (r,c) position.
|
||||
// Note: worker may already finish decoding ref_buf and release it in order to
|
||||
// start decoding next frame. So need to check whether worker is still decoding
|
||||
// ref_buf.
|
||||
void vp9_frameworker_wait(VP9Worker* const worker, int row, int col,
|
||||
RefCntBuffer *ref_buf);
|
||||
|
||||
// FrameWorker broadcasts its decoding progress so other workers that are
|
||||
// waiting it could resume decoding.
|
||||
void vp9_frameworker_broadcast(VP9Worker* const worker, int row, int col);
|
||||
|
||||
// Copy necessary decoding context from src worker to dst worker.
|
||||
void vp9_frameworker_copy_context(VP9Worker *const dst_worker,
|
||||
const VP9Worker *const src_worker);
|
||||
|
||||
#endif // VP9_DECODER_VP9_DTHREAD_H_
|
||||
|
@@ -713,7 +713,8 @@ static void cal_nmvsadcosts_hp(int *mvsadcost[2]) {
|
||||
}
|
||||
|
||||
|
||||
VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) {
|
||||
VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf,
|
||||
BufferPool *const pool) {
|
||||
unsigned int i, j;
|
||||
VP9_COMP *const cpi = vpx_memalign(32, sizeof(VP9_COMP));
|
||||
VP9_COMMON *const cm = cpi != NULL ? &cpi->common : NULL;
|
||||
@@ -734,6 +735,7 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) {
|
||||
vp9_rtcd();
|
||||
|
||||
cpi->use_svc = 0;
|
||||
cpi->common.buffer_pool = pool;
|
||||
|
||||
init_config(cpi, oxcf);
|
||||
vp9_rc_init(&cpi->oxcf, cpi->pass, &cpi->rc);
|
||||
@@ -1273,7 +1275,7 @@ int vp9_get_reference_enc(VP9_COMP *cpi, int index, YV12_BUFFER_CONFIG **fb) {
|
||||
if (index < 0 || index >= REF_FRAMES)
|
||||
return -1;
|
||||
|
||||
*fb = &cm->frame_bufs[cm->ref_frame_map[index]].buf;
|
||||
*fb = &cm->buffer_pool->frame_bufs[cm->ref_frame_map[index]].buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1542,14 +1544,13 @@ static int recode_loop_test(const VP9_COMP *cpi,
|
||||
|
||||
void vp9_update_reference_frames(VP9_COMP *cpi) {
|
||||
VP9_COMMON * const cm = &cpi->common;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
|
||||
// At this point the new frame has been encoded.
|
||||
// If any buffer copy / swapping is signaled it should be done here.
|
||||
if (cm->frame_type == KEY_FRAME) {
|
||||
ref_cnt_fb(cm->frame_bufs,
|
||||
&cm->ref_frame_map[cpi->gld_fb_idx], cm->new_fb_idx);
|
||||
ref_cnt_fb(cm->frame_bufs,
|
||||
&cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx);
|
||||
ref_cnt_fb(frame_bufs, &cm->ref_frame_map[cpi->gld_fb_idx], cm->new_fb_idx);
|
||||
ref_cnt_fb(frame_bufs, &cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx);
|
||||
} else if (!cpi->multi_arf_allowed && cpi->refresh_golden_frame &&
|
||||
cpi->rc.is_src_frame_alt_ref && !cpi->use_svc) {
|
||||
/* Preserve the previously existing golden frame and update the frame in
|
||||
@@ -1563,8 +1564,7 @@ void vp9_update_reference_frames(VP9_COMP *cpi) {
|
||||
*/
|
||||
int tmp;
|
||||
|
||||
ref_cnt_fb(cm->frame_bufs,
|
||||
&cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx);
|
||||
ref_cnt_fb(frame_bufs, &cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx);
|
||||
|
||||
tmp = cpi->alt_fb_idx;
|
||||
cpi->alt_fb_idx = cpi->gld_fb_idx;
|
||||
@@ -1577,19 +1577,17 @@ void vp9_update_reference_frames(VP9_COMP *cpi) {
|
||||
arf_idx = gf_group->arf_update_idx[gf_group->index];
|
||||
}
|
||||
|
||||
ref_cnt_fb(cm->frame_bufs,
|
||||
&cm->ref_frame_map[arf_idx], cm->new_fb_idx);
|
||||
ref_cnt_fb(frame_bufs, &cm->ref_frame_map[arf_idx], cm->new_fb_idx);
|
||||
}
|
||||
|
||||
if (cpi->refresh_golden_frame) {
|
||||
ref_cnt_fb(cm->frame_bufs,
|
||||
ref_cnt_fb(frame_bufs,
|
||||
&cm->ref_frame_map[cpi->gld_fb_idx], cm->new_fb_idx);
|
||||
}
|
||||
}
|
||||
|
||||
if (cpi->refresh_last_frame) {
|
||||
ref_cnt_fb(cm->frame_bufs,
|
||||
&cm->ref_frame_map[cpi->lst_fb_idx], cm->new_fb_idx);
|
||||
ref_cnt_fb(frame_bufs, &cm->ref_frame_map[cpi->lst_fb_idx], cm->new_fb_idx);
|
||||
}
|
||||
#if CONFIG_DENOISING
|
||||
vp9_denoiser_update_frame_info(&cpi->denoiser,
|
||||
@@ -1630,34 +1628,36 @@ void vp9_scale_references(VP9_COMP *cpi) {
|
||||
VP9_COMMON *cm = &cpi->common;
|
||||
MV_REFERENCE_FRAME ref_frame;
|
||||
const VP9_REFFRAME ref_mask[3] = {VP9_LAST_FLAG, VP9_GOLD_FLAG, VP9_ALT_FLAG};
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
|
||||
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
|
||||
const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
|
||||
const YV12_BUFFER_CONFIG *const ref = &cm->frame_bufs[idx].buf;
|
||||
const YV12_BUFFER_CONFIG *const ref = &frame_bufs[idx].buf;
|
||||
|
||||
// Need to convert from VP9_REFFRAME to index into ref_mask (subtract 1).
|
||||
if ((cpi->ref_frame_flags & ref_mask[ref_frame - 1]) &&
|
||||
(ref->y_crop_width != cm->width || ref->y_crop_height != cm->height)) {
|
||||
const int new_fb = get_free_fb(cm);
|
||||
vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf,
|
||||
vp9_realloc_frame_buffer(&frame_bufs[new_fb].buf,
|
||||
cm->width, cm->height,
|
||||
cm->subsampling_x, cm->subsampling_y,
|
||||
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
|
||||
scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf);
|
||||
scale_and_extend_frame(ref, &frame_bufs[new_fb].buf);
|
||||
cpi->scaled_ref_idx[ref_frame - 1] = new_fb;
|
||||
} else {
|
||||
cpi->scaled_ref_idx[ref_frame - 1] = idx;
|
||||
cm->frame_bufs[idx].ref_count++;
|
||||
++frame_bufs[idx].ref_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void release_scaled_references(VP9_COMP *cpi) {
|
||||
VP9_COMMON *cm = &cpi->common;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
cm->frame_bufs[cpi->scaled_ref_idx[i]].ref_count--;
|
||||
for (i = 0; i < 3; ++i)
|
||||
--frame_bufs[cpi->scaled_ref_idx[i]].ref_count;
|
||||
}
|
||||
|
||||
static void full_to_model_count(unsigned int *model_count,
|
||||
@@ -2520,6 +2520,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
|
||||
const int is_spatial_svc = cpi->use_svc &&
|
||||
(cpi->svc.number_temporal_layers == 1) &&
|
||||
(cpi->svc.number_spatial_layers > 1);
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
|
||||
if (!cpi)
|
||||
return -1;
|
||||
@@ -2602,7 +2603,8 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
|
||||
cm->show_frame = 1;
|
||||
cm->intra_only = 0;
|
||||
|
||||
// Check to see if the frame should be encoded as an arf overlay.
|
||||
// Check to see if the frame to be encoded is an overlay for a previous
|
||||
// arf frame and if so configure it as such.
|
||||
check_src_altref(cpi);
|
||||
}
|
||||
}
|
||||
@@ -2656,7 +2658,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
|
||||
/* find a free buffer for the new frame, releasing the reference previously
|
||||
* held.
|
||||
*/
|
||||
cm->frame_bufs[cm->new_fb_idx].ref_count--;
|
||||
--frame_bufs[cm->new_fb_idx].ref_count;
|
||||
cm->new_fb_idx = get_free_fb(cm);
|
||||
|
||||
if (!cpi->use_svc && cpi->multi_arf_allowed) {
|
||||
@@ -2690,7 +2692,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
|
||||
|
||||
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
|
||||
const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
|
||||
YV12_BUFFER_CONFIG *const buf = &cm->frame_bufs[idx].buf;
|
||||
YV12_BUFFER_CONFIG *const buf = &frame_bufs[idx].buf;
|
||||
RefBuffer *const ref_buf = &cm->frame_refs[ref_frame - 1];
|
||||
ref_buf->buf = buf;
|
||||
ref_buf->idx = idx;
|
||||
|
@@ -436,7 +436,8 @@ typedef struct VP9_COMP {
|
||||
|
||||
void vp9_initialize_enc();
|
||||
|
||||
struct VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf);
|
||||
struct VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf,
|
||||
BufferPool *const pool);
|
||||
void vp9_remove_compressor(VP9_COMP *cpi);
|
||||
|
||||
void vp9_change_config(VP9_COMP *cpi, const VP9EncoderConfig *oxcf);
|
||||
@@ -494,8 +495,9 @@ static INLINE int get_ref_frame_idx(const VP9_COMP *cpi,
|
||||
|
||||
static INLINE YV12_BUFFER_CONFIG *get_ref_frame_buffer(
|
||||
VP9_COMP *cpi, MV_REFERENCE_FRAME ref_frame) {
|
||||
VP9_COMMON * const cm = &cpi->common;
|
||||
return &cm->frame_bufs[cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]]
|
||||
VP9_COMMON *const cm = &cpi->common;
|
||||
BufferPool *const pool = cm->buffer_pool;
|
||||
return &pool->frame_bufs[cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]]
|
||||
.buf;
|
||||
}
|
||||
|
||||
|
@@ -2271,9 +2271,10 @@ void vp9_setup_buffer_inter(VP9_COMP *cpi, MACROBLOCK *x,
|
||||
const YV12_BUFFER_CONFIG *vp9_get_scaled_ref_frame(const VP9_COMP *cpi,
|
||||
int ref_frame) {
|
||||
const VP9_COMMON *const cm = &cpi->common;
|
||||
const RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
const int ref_idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
|
||||
const int scaled_idx = cpi->scaled_ref_idx[ref_frame - 1];
|
||||
return (scaled_idx != ref_idx) ? &cm->frame_bufs[scaled_idx].buf : NULL;
|
||||
return (scaled_idx != ref_idx) ? &frame_bufs[scaled_idx].buf : NULL;
|
||||
}
|
||||
|
||||
int vp9_get_switchable_rate(const VP9_COMP *cpi) {
|
||||
|
@@ -90,6 +90,8 @@ struct vpx_codec_alg_priv {
|
||||
vp8_postproc_cfg_t preview_ppcfg;
|
||||
vpx_codec_pkt_list_decl(128) pkt_list;
|
||||
unsigned int fixed_kf_cntr;
|
||||
// BufferPool that holds all reference frames.
|
||||
BufferPool *buffer_pool;
|
||||
};
|
||||
|
||||
static VP9_REFFRAME ref_frame_to_vp9_reframe(vpx_ref_frame_type_t frame) {
|
||||
@@ -630,6 +632,10 @@ static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
|
||||
ctx->priv->alg_priv = priv;
|
||||
ctx->priv->init_flags = ctx->init_flags;
|
||||
ctx->priv->enc.total_encoders = 1;
|
||||
ctx->priv->alg_priv->buffer_pool =
|
||||
(BufferPool *)vpx_calloc(1, sizeof(BufferPool));
|
||||
if (ctx->priv->alg_priv->buffer_pool == NULL)
|
||||
return VPX_CODEC_MEM_ERROR;
|
||||
|
||||
if (ctx->config.enc) {
|
||||
// Update the reference to the config structure to an internal copy.
|
||||
@@ -667,7 +673,8 @@ static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
|
||||
set_encoder_config(&ctx->priv->alg_priv->oxcf,
|
||||
&ctx->priv->alg_priv->cfg,
|
||||
&ctx->priv->alg_priv->extra_cfg);
|
||||
cpi = vp9_create_compressor(&ctx->priv->alg_priv->oxcf);
|
||||
cpi = vp9_create_compressor(&ctx->priv->alg_priv->oxcf,
|
||||
ctx->priv->alg_priv->buffer_pool);
|
||||
if (cpi == NULL)
|
||||
res = VPX_CODEC_MEM_ERROR;
|
||||
else
|
||||
@@ -681,6 +688,7 @@ static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
|
||||
static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
|
||||
free(ctx->cx_data);
|
||||
vp9_remove_compressor(ctx->cpi);
|
||||
vpx_free(ctx->buffer_pool);
|
||||
free(ctx);
|
||||
return VPX_CODEC_OK;
|
||||
}
|
||||
|
@@ -32,15 +32,22 @@ struct vpx_codec_alg_priv {
|
||||
vpx_codec_priv_t base;
|
||||
vpx_codec_dec_cfg_t cfg;
|
||||
vp9_stream_info_t si;
|
||||
struct VP9Decoder *pbi;
|
||||
int postproc_cfg_set;
|
||||
vp8_postproc_cfg_t postproc_cfg;
|
||||
vpx_decrypt_cb decrypt_cb;
|
||||
void *decrypt_state;
|
||||
vpx_image_t img;
|
||||
int img_avail;
|
||||
int invert_tile_order;
|
||||
int frame_parallel_decode; // frame-based threading.
|
||||
int last_show_frame; // Index of last output frame.
|
||||
|
||||
VP9Worker *frame_workers;
|
||||
int num_frame_workers;
|
||||
int next_submit_thread_id;
|
||||
int next_output_thread_id;
|
||||
|
||||
// BufferPool that holds all reference frames. Shared by all the FrameWorkers.
|
||||
BufferPool *buffer_pool;
|
||||
|
||||
// External frame buffer info to save for VP9 common.
|
||||
void *ext_priv; // Private data associated with the external frame buffers.
|
||||
@@ -85,11 +92,18 @@ static vpx_codec_err_t decoder_init(vpx_codec_ctx_t *ctx,
|
||||
}
|
||||
|
||||
static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) {
|
||||
if (ctx->pbi) {
|
||||
vp9_decoder_remove(ctx->pbi);
|
||||
ctx->pbi = NULL;
|
||||
if (ctx->frame_workers != NULL) {
|
||||
int i;
|
||||
for (i = 0; i < ctx->num_frame_workers; ++i) {
|
||||
VP9Worker *const worker = &ctx->frame_workers[i];
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
vp9_decoder_remove(worker_data->pbi);
|
||||
vpx_free(worker_data);
|
||||
}
|
||||
}
|
||||
|
||||
vpx_free(ctx->frame_workers);
|
||||
vpx_free(ctx->buffer_pool);
|
||||
vpx_free(ctx);
|
||||
|
||||
return VPX_CODEC_OK;
|
||||
@@ -188,32 +202,43 @@ static vpx_codec_err_t decoder_get_si(vpx_codec_alg_priv_t *ctx,
|
||||
return VPX_CODEC_OK;
|
||||
}
|
||||
|
||||
static void set_error_detail(vpx_codec_alg_priv_t *ctx,
|
||||
const char *const error) {
|
||||
ctx->base.err_detail = error;
|
||||
}
|
||||
|
||||
static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx,
|
||||
const struct vpx_internal_error_info *error) {
|
||||
if (error->error_code)
|
||||
ctx->base.err_detail = error->has_detail ? error->detail : NULL;
|
||||
set_error_detail(ctx, error->has_detail ? error->detail : NULL);
|
||||
|
||||
return error->error_code;
|
||||
}
|
||||
|
||||
static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) {
|
||||
VP9_COMMON *const cm = &ctx->pbi->common;
|
||||
int i;
|
||||
|
||||
cm->new_fb_idx = -1;
|
||||
for (i = 0; i < ctx->num_frame_workers; ++i) {
|
||||
VP9Worker *const worker = &ctx->frame_workers[i];
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
VP9_COMMON *const cm = &worker_data->pbi->common;
|
||||
BufferPool *const pool = cm->buffer_pool;
|
||||
|
||||
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;
|
||||
cm->new_fb_idx = -1;
|
||||
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(&cm->int_frame_buffers))
|
||||
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
|
||||
"Failed to initialize internal frame buffers");
|
||||
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");
|
||||
|
||||
cm->cb_priv = &cm->int_frame_buffers;
|
||||
pool->cb_priv = &pool->int_frame_buffers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,14 +257,64 @@ static void set_ppflags(const vpx_codec_alg_priv_t *ctx,
|
||||
flags->noise_level = ctx->postproc_cfg.noise_level;
|
||||
}
|
||||
|
||||
static void init_decoder(vpx_codec_alg_priv_t *ctx) {
|
||||
ctx->pbi = vp9_decoder_create();
|
||||
if (ctx->pbi == NULL)
|
||||
return;
|
||||
static int frame_worker_hook(void *arg1, void *arg2) {
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)arg1;
|
||||
const uint8_t *data = worker_data->data;
|
||||
(void)arg2;
|
||||
worker_data->result = vp9_receive_compressed_data(worker_data->pbi,
|
||||
worker_data->data_size,
|
||||
&data);
|
||||
worker_data->data_end = data;
|
||||
return !worker_data->result;
|
||||
}
|
||||
|
||||
ctx->pbi->max_threads = ctx->cfg.threads;
|
||||
ctx->pbi->inv_tile_order = ctx->invert_tile_order;
|
||||
ctx->pbi->frame_parallel_decode = ctx->frame_parallel_decode;
|
||||
static vpx_codec_err_t init_decoder(vpx_codec_alg_priv_t *ctx) {
|
||||
int i;
|
||||
const VP9WorkerInterface *const winterface = vp9_get_worker_interface();
|
||||
|
||||
ctx->last_show_frame = -1;
|
||||
ctx->next_submit_thread_id = 0;
|
||||
ctx->next_output_thread_id = 0;
|
||||
ctx->num_frame_workers =
|
||||
(ctx->frame_parallel_decode == 1) ? ctx->cfg.threads: 1;
|
||||
ctx->buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(BufferPool));
|
||||
if (ctx->buffer_pool == NULL)
|
||||
return VPX_CODEC_MEM_ERROR;
|
||||
|
||||
ctx->frame_workers = (VP9Worker *)
|
||||
vpx_malloc(ctx->num_frame_workers * sizeof(*ctx->frame_workers));
|
||||
if (ctx->frame_workers == NULL) {
|
||||
set_error_detail(ctx, "Failed to allocate frame_workers");
|
||||
return VPX_CODEC_MEM_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < ctx->num_frame_workers; ++i) {
|
||||
VP9Worker *const worker = &ctx->frame_workers[i];
|
||||
FrameWorkerData *worker_data = NULL;
|
||||
winterface->init(worker);
|
||||
worker->data1 = vpx_memalign(32, sizeof(FrameWorkerData));
|
||||
if (worker->data1 == NULL) {
|
||||
set_error_detail(ctx, "Failed to allocate worker_data");
|
||||
return VPX_CODEC_MEM_ERROR;
|
||||
}
|
||||
worker_data = (FrameWorkerData *)worker->data1;
|
||||
worker_data->pbi = vp9_decoder_create(ctx->buffer_pool);
|
||||
if (worker_data->pbi == NULL) {
|
||||
set_error_detail(ctx, "Failed to allocate worker_data");
|
||||
return VPX_CODEC_MEM_ERROR;
|
||||
}
|
||||
worker_data->pbi->owner_frame_worker = worker;
|
||||
worker_data->worker_id = i;
|
||||
worker_data->frame_context_ready = 0;
|
||||
// If decoding in serial mode, FrameWorker thread could create tile worker
|
||||
// thread or loopfilter thread.
|
||||
worker_data->pbi->max_threads =
|
||||
(ctx->frame_parallel_decode == 0) ? ctx->cfg.threads : 0;
|
||||
|
||||
worker_data->pbi->inv_tile_order = ctx->invert_tile_order;
|
||||
worker_data->pbi->frame_parallel_decode = ctx->frame_parallel_decode;
|
||||
worker->hook = (VP9WorkerHook)frame_worker_hook;
|
||||
}
|
||||
|
||||
// If postprocessing was enabled by the application and a
|
||||
// configuration has not been provided, default it.
|
||||
@@ -248,20 +323,17 @@ static void init_decoder(vpx_codec_alg_priv_t *ctx) {
|
||||
set_default_ppflags(&ctx->postproc_cfg);
|
||||
|
||||
init_buffer_callbacks(ctx);
|
||||
|
||||
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) {
|
||||
YV12_BUFFER_CONFIG sd;
|
||||
vp9_ppflags_t flags = {0, 0, 0};
|
||||
VP9_COMMON *cm = NULL;
|
||||
|
||||
vp9_ppflags_t flags = {0};
|
||||
const VP9WorkerInterface *const winterface = vp9_get_worker_interface();
|
||||
(void)deadline;
|
||||
|
||||
vp9_zero(sd);
|
||||
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.
|
||||
@@ -276,33 +348,41 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
|
||||
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;
|
||||
// Initialize the decoder workers on the first frame
|
||||
if (ctx->frame_workers == NULL) {
|
||||
const vpx_codec_err_t res = init_decoder(ctx);
|
||||
if (res != VPX_CODEC_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (!ctx->frame_parallel_decode) {
|
||||
VP9Worker *const worker = ctx->frame_workers;
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
worker_data->data = *data;
|
||||
worker_data->data_size = data_sz;
|
||||
worker_data->user_priv = user_priv;
|
||||
|
||||
cm = &ctx->pbi->common;
|
||||
// Set these even if already initialized. The caller may have changed the
|
||||
// decrypt config between frames.
|
||||
worker_data->pbi->decrypt_cb = ctx->decrypt_cb;
|
||||
worker_data->pbi->decrypt_state = ctx->decrypt_state;
|
||||
|
||||
if (vp9_receive_compressed_data(ctx->pbi, data_sz, data))
|
||||
return update_error_state(ctx, &cm->error);
|
||||
worker->had_error = 0;
|
||||
winterface->execute(worker);
|
||||
|
||||
// Update data pointer after decode.
|
||||
*data = worker_data->data_end;
|
||||
|
||||
if (worker->had_error)
|
||||
return update_error_state(ctx, &worker_data->pbi->common.error);
|
||||
} else {
|
||||
// TODO(hkuang): Implement frame parallel decode.
|
||||
return VPX_CODEC_INCAPABLE;
|
||||
}
|
||||
|
||||
if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
|
||||
set_ppflags(ctx, &flags);
|
||||
|
||||
if (vp9_get_raw_frame(ctx->pbi, &sd, &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;
|
||||
}
|
||||
|
||||
@@ -412,7 +492,7 @@ static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx,
|
||||
vpx_codec_err_t res;
|
||||
if (data_start < data
|
||||
|| frame_size > (uint32_t) (data_end - data_start)) {
|
||||
ctx->base.err_detail = "Invalid frame size in index";
|
||||
set_error_detail(ctx, "Invalid frame size in index");
|
||||
return VPX_CODEC_CORRUPT_FRAME;
|
||||
}
|
||||
|
||||
@@ -430,7 +510,7 @@ static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx,
|
||||
|
||||
// Extra data detected after the frame.
|
||||
if (data_start < data_end - 1) {
|
||||
ctx->base.err_detail = "Fail to decode frame in parallel mode";
|
||||
set_error_detail(ctx, "Fail to decode frame in parallel mode");
|
||||
return VPX_CODEC_INCAPABLE;
|
||||
}
|
||||
}
|
||||
@@ -445,7 +525,7 @@ static vpx_codec_err_t decoder_decode(vpx_codec_alg_priv_t *ctx,
|
||||
vpx_codec_err_t res;
|
||||
if (data_start < data
|
||||
|| frame_size > (uint32_t) (data_end - data_start)) {
|
||||
ctx->base.err_detail = "Invalid frame size in index";
|
||||
set_error_detail(ctx, "Invalid frame size in index");
|
||||
return VPX_CODEC_CORRUPT_FRAME;
|
||||
}
|
||||
|
||||
@@ -483,15 +563,39 @@ static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx,
|
||||
vpx_codec_iter_t *iter) {
|
||||
vpx_image_t *img = NULL;
|
||||
|
||||
if (ctx->img_avail) {
|
||||
// iter acts as a flip flop, so an image is only returned on the first
|
||||
// call to get_frame.
|
||||
if (!(*iter)) {
|
||||
// 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) {
|
||||
YV12_BUFFER_CONFIG sd;
|
||||
vp9_ppflags_t flags = {0, 0, 0};
|
||||
|
||||
VP9Worker *const worker = &ctx->frame_workers[ctx->next_output_thread_id];
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
if (vp9_get_raw_frame(worker_data->pbi, &sd, &flags) == 0) {
|
||||
VP9_COMMON *const cm = &worker_data->pbi->common;
|
||||
BufferPool *const pool = cm->buffer_pool;
|
||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||
yuvconfig2image(&ctx->img, &sd, worker_data->user_priv);
|
||||
ctx->img.fb_priv = frame_bufs[cm->new_fb_idx].raw_frame_buffer.priv;
|
||||
img = &ctx->img;
|
||||
*iter = img;
|
||||
// Decrease reference count of last output frame in frame parallel mode.
|
||||
if (ctx->frame_parallel_decode && ctx->last_show_frame >= 0) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_lock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
--frame_bufs[ctx->last_show_frame].ref_count;
|
||||
if (frame_bufs[ctx->last_show_frame].ref_count == 0) {
|
||||
pool->release_fb_cb(pool->cb_priv,
|
||||
&frame_bufs[ctx->last_show_frame].raw_frame_buffer);
|
||||
}
|
||||
#if CONFIG_MULTITHREAD
|
||||
pthread_mutex_unlock(&cm->buffer_pool->pool_mutex);
|
||||
#endif
|
||||
}
|
||||
ctx->last_show_frame = worker_data->pbi->common.new_fb_idx;
|
||||
}
|
||||
}
|
||||
ctx->img_avail = 0;
|
||||
|
||||
return img;
|
||||
}
|
||||
@@ -502,7 +606,7 @@ static vpx_codec_err_t decoder_set_fb_fn(
|
||||
vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) {
|
||||
if (cb_get == NULL || cb_release == NULL) {
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
} else if (ctx->pbi == NULL) {
|
||||
} else if (ctx->frame_workers == NULL) {
|
||||
// If the decoder has already been initialized, do not accept changes to
|
||||
// the frame buffer functions.
|
||||
ctx->get_ext_fb_cb = cb_get;
|
||||
@@ -518,12 +622,19 @@ static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
|
||||
va_list args) {
|
||||
vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *);
|
||||
|
||||
// Only support this function in serial decode.
|
||||
if (ctx->frame_parallel_decode) {
|
||||
set_error_detail(ctx, "Not supported in frame parallel decode");
|
||||
return VPX_CODEC_INCAPABLE;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
|
||||
YV12_BUFFER_CONFIG sd;
|
||||
|
||||
VP9Worker *const worker = ctx->frame_workers;
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
image2yuvconfig(&frame->img, &sd);
|
||||
return vp9_set_reference_dec(&ctx->pbi->common,
|
||||
return vp9_set_reference_dec(&worker_data->pbi->common,
|
||||
(VP9_REFFRAME)frame->frame_type, &sd);
|
||||
} else {
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
@@ -534,13 +645,19 @@ static vpx_codec_err_t ctrl_copy_reference(vpx_codec_alg_priv_t *ctx,
|
||||
va_list args) {
|
||||
vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
|
||||
|
||||
// Only support this function in serial decode.
|
||||
if (ctx->frame_parallel_decode) {
|
||||
set_error_detail(ctx, "Not supported in frame parallel decode");
|
||||
return VPX_CODEC_INCAPABLE;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
|
||||
vpx_ref_frame_t *frame = (vpx_ref_frame_t *) data;
|
||||
YV12_BUFFER_CONFIG sd;
|
||||
|
||||
VP9Worker *const worker = ctx->frame_workers;
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
image2yuvconfig(&frame->img, &sd);
|
||||
|
||||
return vp9_copy_reference_dec(ctx->pbi,
|
||||
return vp9_copy_reference_dec(worker_data->pbi,
|
||||
(VP9_REFFRAME)frame->frame_type, &sd);
|
||||
} else {
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
@@ -551,10 +668,17 @@ static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx,
|
||||
va_list args) {
|
||||
vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);
|
||||
|
||||
// Only support this function in serial decode.
|
||||
if (ctx->frame_parallel_decode) {
|
||||
set_error_detail(ctx, "Not supported in frame parallel decode");
|
||||
return VPX_CODEC_INCAPABLE;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
YV12_BUFFER_CONFIG* fb;
|
||||
|
||||
vp9_get_reference_dec(ctx->pbi, data->idx, &fb);
|
||||
VP9Worker *const worker = ctx->frame_workers;
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
vp9_get_reference_dec(worker_data->pbi, data->idx, &fb);
|
||||
yuvconfig2image(&data->img, fb, NULL);
|
||||
return VPX_CODEC_OK;
|
||||
} else {
|
||||
@@ -592,11 +716,20 @@ static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
|
||||
va_list args) {
|
||||
int *const update_info = va_arg(args, int *);
|
||||
|
||||
// Only support this function in serial decode.
|
||||
if (ctx->frame_parallel_decode) {
|
||||
set_error_detail(ctx, "Not supported in frame parallel decode");
|
||||
return VPX_CODEC_INCAPABLE;
|
||||
}
|
||||
|
||||
if (update_info) {
|
||||
if (ctx->pbi)
|
||||
*update_info = ctx->pbi->refresh_frame_flags;
|
||||
else
|
||||
if (ctx->frame_workers) {
|
||||
VP9Worker *const worker = ctx->frame_workers;
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
*update_info = worker_data->pbi->refresh_frame_flags;
|
||||
} else {
|
||||
return VPX_CODEC_ERROR;
|
||||
}
|
||||
return VPX_CODEC_OK;
|
||||
} else {
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
@@ -608,11 +741,20 @@ static vpx_codec_err_t ctrl_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
|
||||
va_list args) {
|
||||
int *corrupted = va_arg(args, int *);
|
||||
|
||||
// Only support this function in serial decode.
|
||||
if (ctx->frame_parallel_decode) {
|
||||
set_error_detail(ctx, "Not supported in frame parallel decode");
|
||||
return VPX_CODEC_INCAPABLE;
|
||||
}
|
||||
|
||||
if (corrupted) {
|
||||
if (ctx->pbi)
|
||||
*corrupted = ctx->pbi->common.frame_to_show->corrupted;
|
||||
else
|
||||
if (ctx->frame_workers) {
|
||||
VP9Worker *const worker = ctx->frame_workers;
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
*corrupted = worker_data->pbi->common.frame_to_show->corrupted;
|
||||
} else {
|
||||
return VPX_CODEC_ERROR;
|
||||
}
|
||||
return VPX_CODEC_OK;
|
||||
} else {
|
||||
return VPX_CODEC_INVALID_PARAM;
|
||||
@@ -623,9 +765,17 @@ static vpx_codec_err_t ctrl_get_display_size(vpx_codec_alg_priv_t *ctx,
|
||||
va_list args) {
|
||||
int *const display_size = va_arg(args, int *);
|
||||
|
||||
// Only support this function in serial decode.
|
||||
if (ctx->frame_parallel_decode) {
|
||||
set_error_detail(ctx, "Not supported in frame parallel decode");
|
||||
return VPX_CODEC_INCAPABLE;
|
||||
}
|
||||
|
||||
if (display_size) {
|
||||
if (ctx->pbi) {
|
||||
const VP9_COMMON *const cm = &ctx->pbi->common;
|
||||
if (ctx->frame_workers) {
|
||||
VP9Worker *const worker = ctx->frame_workers;
|
||||
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
|
||||
const VP9_COMMON *const cm = &worker_data->pbi->common;
|
||||
display_size[0] = cm->display_width;
|
||||
display_size[1] = cm->display_height;
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user