Compare commits

...

5 Commits

Author SHA1 Message Date
hkuang
21e9f79d25 Remove unnecessary check for frame parallel decode.
The check will make the code break out from the loop earlier.
But without the check. it works the same in non frame-parallel decode.
In frame parallel decode, this check is wrong as there may be left
frames inside the decoder even if there are no more frames to read.
So the loop should continue until got_data = 0.

Change-Id: I42937cec5d80d1d921a008d78dafce0928c727e0
2014-07-08 15:43:51 -07:00
hkuang
ffd20828d0 Add more functions for FrameWorker.
Change-Id: Ia0a549aaa3e83b5a17b31d8299aa496ea4f21e3e
2014-07-08 11:50:57 -07:00
hkuang
10aa23f751 ctrl_get_reference does not need user_priv.
The relationship of the user private data at runtime
is not preserved from decode() to this call which may
occur at an unknown point in the future

Change-Id: Ia7eb25365c805147614574c3af87aedbe0305fc6
2014-07-02 19:28:38 -07:00
hkuang
28a794f680 Seperate the frame buffers from VP9 encoder/decoder structure.
Prepare for frame parallel decoding, the frame buffers must be
separated from the encoder and decoder structure, while the encoder
and decoder will hold the pointer of the BufferPool.

Change-Id: I172c78f876e41fb5aea11be5f632adadf2a6f466
2014-07-02 15:34:20 -07:00
hkuang
bf58d1725c Revert "Revert "Revert "Revert 3 patches from Hangyu to get Chrome to build:"""
This reverts commit 749e0c7b28.

Change-Id: I0c63a152baf94d38496dd925a40040366153bf4f
2014-07-02 14:57:39 -07:00
13 changed files with 542 additions and 152 deletions

View File

@@ -97,14 +97,15 @@ static void free_mi(VP9_COMMON *cm) {
void vp9_free_frame_buffers(VP9_COMMON *cm) { void vp9_free_frame_buffers(VP9_COMMON *cm) {
int i; int i;
BufferPool *const pool = cm->buffer_pool;
for (i = 0; i < FRAME_BUFFERS; ++i) { 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 && if (pool->frame_bufs[i].ref_count > 0 &&
cm->frame_bufs[i].raw_frame_buffer.data != NULL) { pool->frame_bufs[i].raw_frame_buffer.data != NULL) {
cm->release_fb_cb(cm->cb_priv, &cm->frame_bufs[i].raw_frame_buffer); pool->release_fb_cb(pool->cb_priv, &pool->frame_bufs[i].raw_frame_buffer);
cm->frame_bufs[i].ref_count = 0; 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) { static void init_frame_bufs(VP9_COMMON *cm) {
int i; int i;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
cm->new_fb_idx = FRAME_BUFFERS - 1; 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) { for (i = 0; i < REF_FRAMES; ++i) {
cm->ref_frame_map[i] = 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; int i;
const int ss_x = cm->subsampling_x; const int ss_x = cm->subsampling_x;
const int ss_y = cm->subsampling_y; const int ss_y = cm->subsampling_y;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
vp9_free_frame_buffers(cm); vp9_free_frame_buffers(cm);
for (i = 0; i < FRAME_BUFFERS; ++i) { for (i = 0; i < FRAME_BUFFERS; ++i) {
cm->frame_bufs[i].ref_count = 0; frame_bufs[i].ref_count = 0;
if (vp9_alloc_frame_buffer(&cm->frame_bufs[i].buf, width, height, if (vp9_alloc_frame_buffer(&frame_bufs[i].buf, width, height,
ss_x, ss_y, VP9_ENC_BORDER_IN_PIXELS) < 0) ss_x, ss_y, VP9_ENC_BORDER_IN_PIXELS) < 0)
goto fail; 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) { void vp9_remove_common(VP9_COMMON *cm) {
vp9_free_frame_buffers(cm); vp9_free_frame_buffers(cm);
vp9_free_context_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) { void vp9_update_frame_size(VP9_COMMON *cm) {

View File

@@ -11,6 +11,7 @@
#ifndef VP9_COMMON_VP9_ONYXC_INT_H_ #ifndef VP9_COMMON_VP9_ONYXC_INT_H_
#define VP9_COMMON_VP9_ONYXC_INT_H_ #define VP9_COMMON_VP9_ONYXC_INT_H_
#include <pthread.h>
#include "./vpx_config.h" #include "./vpx_config.h"
#include "vpx/internal/vpx_codec_internal.h" #include "vpx/internal/vpx_codec_internal.h"
#include "./vp9_rtcd.h" #include "./vp9_rtcd.h"
@@ -61,8 +62,40 @@ typedef struct {
int ref_count; int ref_count;
vpx_codec_frame_buffer_t raw_frame_buffer; vpx_codec_frame_buffer_t raw_frame_buffer;
YV12_BUFFER_CONFIG buf; 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; } 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 { typedef struct VP9Common {
struct vpx_internal_error_info error; struct vpx_internal_error_info error;
@@ -89,10 +122,11 @@ typedef struct VP9Common {
YV12_BUFFER_CONFIG *frame_to_show; YV12_BUFFER_CONFIG *frame_to_show;
RefCntBuffer frame_bufs[FRAME_BUFFERS];
int ref_frame_map[REF_FRAMES]; /* maps fb_idx to reference slot */ 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 // TODO(jkoleszar): could expand active_ref_idx to 4, with 0 as intra, and
// roll new_fb_idx into it. // roll new_fb_idx into it.
@@ -202,30 +236,33 @@ typedef struct VP9Common {
int log2_tile_cols, log2_tile_rows; int log2_tile_cols, log2_tile_rows;
// Private data associated with the frame buffer callbacks. // External BufferPool passed from outside.
void *cb_priv; BufferPool *buffer_pool;
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;
PARTITION_CONTEXT *above_seg_context; PARTITION_CONTEXT *above_seg_context;
ENTROPY_CONTEXT *above_context; ENTROPY_CONTEXT *above_context;
} VP9_COMMON; } VP9_COMMON;
static INLINE YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) { 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) { static INLINE int get_free_fb(VP9_COMMON *cm) {
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
int i; int i;
#if CONFIG_MULTITHREAD
pthread_mutex_lock(&cm->buffer_pool->pool_mutex);
#endif
for (i = 0; i < FRAME_BUFFERS; i++) for (i = 0; i < FRAME_BUFFERS; i++)
if (cm->frame_bufs[i].ref_count == 0) if (frame_bufs[i].ref_count == 0)
break; break;
assert(i < FRAME_BUFFERS); 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; return i;
} }

View File

@@ -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) { 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) { if (cm->width != width || cm->height != height) {
// Change in frame size. // Change in frame size.
// TODO(agrange) Don't test width/height, check overall 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( if (vp9_realloc_frame_buffer(
get_frame_new_buffer(cm), cm->width, cm->height, get_frame_new_buffer(cm), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y, VP9_DEC_BORDER_IN_PIXELS, 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, &pool->frame_bufs[cm->new_fb_idx].raw_frame_buffer, pool->get_fb_cb,
cm->cb_priv)) { pool->cb_priv)) {
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate frame buffer"); "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, static size_t read_uncompressed_header(VP9Decoder *pbi,
struct vp9_read_bit_buffer *rb) { struct vp9_read_bit_buffer *rb) {
VP9_COMMON *const cm = &pbi->common; VP9_COMMON *const cm = &pbi->common;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
int mask, i, ref_index = 0;
size_t sz; size_t sz;
int i;
cm->last_frame_type = cm->frame_type; cm->last_frame_type = cm->frame_type;
@@ -1095,12 +1097,18 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
// Show an existing frame directly. // Show an existing frame directly.
const int frame_to_show = cm->ref_frame_map[vp9_rb_read_literal(rb, 3)]; 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, vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
"Buffer %d does not contain a decoded frame", "Buffer %d does not contain a decoded frame",
frame_to_show); 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; pbi->refresh_frame_flags = 0;
cm->lf.filter_level = 0; cm->lf.filter_level = 0;
cm->show_frame = 1; cm->show_frame = 1;
@@ -1161,7 +1169,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
const int idx = cm->ref_frame_map[ref]; const int idx = cm->ref_frame_map[ref];
RefBuffer *const ref_frame = &cm->frame_refs[i]; RefBuffer *const ref_frame = &cm->frame_refs[i];
ref_frame->idx = idx; 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); 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. // below, forcing the use of context 0 for those frame types.
cm->frame_context_idx = vp9_rb_read_literal(rb, FRAME_CONTEXTS_LOG2); 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) if (frame_is_intra_only(cm) || cm->error_resilient_mode)
vp9_setup_past_independence(cm); vp9_setup_past_independence(cm);
@@ -1392,6 +1422,17 @@ void vp9_decode_frame(VP9Decoder *pbi,
new_fb->corrupted |= xd->corrupted; 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 (!new_fb->corrupted) {
if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode) { if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode) {
vp9_adapt_coef_probs(cm); vp9_adapt_coef_probs(cm);

View File

@@ -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)); VP9Decoder *const pbi = vpx_memalign(32, sizeof(*pbi));
VP9_COMMON *const cm = pbi ? &pbi->common : NULL; 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. // 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->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; cm->current_video_frame = 0;
pbi->ready_for_new_data = 1; pbi->ready_for_new_data = 1;
pbi->common.buffer_pool = pool;
// vp9_init_dequantizer() is first called here. Add check in // vp9_init_dequantizer() is first called here. Add check in
// frame_init_dequantizer() to avoid unnecessary calling of // 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) { if (ref_frame_flag == VP9_LAST_FLAG) {
const YV12_BUFFER_CONFIG *const cfg = 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)) if (!equal_dimensions(cfg, sd))
vpx_internal_error(&cm->error, VPX_CODEC_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
"Incorrect buffer dimensions"); "Incorrect buffer dimensions");
@@ -143,6 +145,7 @@ vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
VP9_REFFRAME ref_frame_flag, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) { YV12_BUFFER_CONFIG *sd) {
RefBuffer *ref_buf = NULL; 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 // 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 // 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); const int free_fb = get_free_fb(cm);
// Decrease ref_count since it will be increased again in // Decrease ref_count since it will be increased again in
// ref_cnt_fb() below. // ref_cnt_fb() below.
cm->frame_bufs[free_fb].ref_count--; --frame_bufs[free_fb].ref_count;
// Manage the reference counters and copy image. // Manage the reference counters and copy image.
ref_cnt_fb(cm->frame_bufs, ref_fb_ptr, free_fb); ref_cnt_fb(frame_bufs, ref_fb_ptr, free_fb);
ref_buf->buf = &cm->frame_bufs[*ref_fb_ptr].buf; ref_buf->buf = &frame_bufs[*ref_fb_ptr].buf;
vp8_yv12_copy_frame(sd, ref_buf->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) { int vp9_get_reference_dec(VP9Decoder *pbi, int index, YV12_BUFFER_CONFIG **fb) {
VP9_COMMON *cm = &pbi->common; VP9_COMMON *cm = &pbi->common;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
if (index < 0 || index >= REF_FRAMES) if (index < 0 || index >= REF_FRAMES)
return -1; return -1;
*fb = &cm->frame_bufs[cm->ref_frame_map[index]].buf; *fb = &frame_bufs[cm->ref_frame_map[index]].buf;
return 0; return 0;
} }
/* If any buffer updating is signaled it should be done here. */ /* If any buffer updating is signaled it should be done here. */
static void swap_frame_buffers(VP9Decoder *pbi) { static void swap_frame_buffers(VP9Decoder *pbi) {
int ref_index = 0, mask; 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) { for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
if (mask & 1) { if (mask & 1) {
const int old_idx = cm->ref_frame_map[ref_index]; 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); cm->new_fb_idx);
if (old_idx >= 0 && cm->frame_bufs[old_idx].ref_count == 0) if (old_idx >= 0 && frame_bufs[old_idx].ref_count == 0)
cm->release_fb_cb(cm->cb_priv, pool->release_fb_cb(pool->cb_priv,
&cm->frame_bufs[old_idx].raw_frame_buffer); &frame_bufs[old_idx].raw_frame_buffer);
} }
#if CONFIG_MULTITHREAD
pthread_mutex_unlock(&cm->buffer_pool->pool_mutex);
#endif
++ref_index; ++ref_index;
} }
cm->frame_to_show = get_frame_new_buffer(cm); 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. // Invalidate these references until the next frame starts.
for (ref_index = 0; ref_index < 3; ref_index++) 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, int vp9_receive_compressed_data(VP9Decoder *pbi,
size_t size, const uint8_t **psource) { size_t size, const uint8_t **psource) {
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;
const uint8_t *source = *psource; const uint8_t *source = *psource;
int retcode = 0; 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. // 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) // Release frame buffer if not decoding in frame parallel mode.
cm->release_fb_cb(cm->cb_priv, if (!pbi->frame_parallel_decode && cm->new_fb_idx >= 0
&cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer); && 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); 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)) { if (setjmp(cm->error.jmp)) {
cm->error.setjmp = 0; 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) if (cm->frame_refs[0].idx != INT_MAX && cm->frame_refs[0].buf != NULL)
cm->frame_refs[0].buf->corrupted = 1; cm->frame_refs[0].buf->corrupted = 1;
if (cm->new_fb_idx > 0 && cm->frame_bufs[cm->new_fb_idx].ref_count > 0) if (frame_bufs[cm->new_fb_idx].ref_count > 0)
cm->frame_bufs[cm->new_fb_idx].ref_count--; --frame_bufs[cm->new_fb_idx].ref_count;
return -1; return -1;
} }

View File

@@ -45,8 +45,14 @@ typedef struct VP9Decoder {
int frame_parallel_decode; // frame-based threading. 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 lf_worker;
VP9Worker *tile_workers; VP9Worker *tile_workers;
VP9Worker *owner_frame_worker; // frame_worker that owns this pbi;
int num_tile_workers; int num_tile_workers;
TileData *tile_data; 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 vp9_get_reference_dec(struct VP9Decoder *pbi,
int index, YV12_BUFFER_CONFIG **fb); 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); void vp9_decoder_remove(struct VP9Decoder *pbi);

View File

@@ -279,3 +279,78 @@ void vp9_loop_filter_dealloc(VP9LfSync *lf_sync, int rows) {
vp9_zero(*lf_sync); 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];
}

View File

@@ -40,6 +40,28 @@ typedef struct VP9LfSyncData {
int sync_range; int sync_range;
} VP9LfSync; } 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. // Allocate memory for loopfilter row synchronization.
void vp9_loop_filter_alloc(struct VP9Common *cm, VP9LfSync *lf_sync, void vp9_loop_filter_alloc(struct VP9Common *cm, VP9LfSync *lf_sync,
int rows, int width); int rows, int width);
@@ -54,4 +76,19 @@ void vp9_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame,
int frame_filter_level, int frame_filter_level,
int y_only); 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_ #endif // VP9_DECODER_VP9_DTHREAD_H_

View File

@@ -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; unsigned int i, j;
VP9_COMP *const cpi = vpx_memalign(32, sizeof(VP9_COMP)); VP9_COMP *const cpi = vpx_memalign(32, sizeof(VP9_COMP));
VP9_COMMON *const cm = cpi != NULL ? &cpi->common : NULL; VP9_COMMON *const cm = cpi != NULL ? &cpi->common : NULL;
@@ -734,6 +735,7 @@ VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) {
vp9_rtcd(); vp9_rtcd();
cpi->use_svc = 0; cpi->use_svc = 0;
cpi->common.buffer_pool = pool;
init_config(cpi, oxcf); init_config(cpi, oxcf);
vp9_rc_init(&cpi->oxcf, cpi->pass, &cpi->rc); 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) if (index < 0 || index >= REF_FRAMES)
return -1; 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; return 0;
} }
@@ -1542,14 +1544,13 @@ static int recode_loop_test(const VP9_COMP *cpi,
void vp9_update_reference_frames(VP9_COMP *cpi) { void vp9_update_reference_frames(VP9_COMP *cpi) {
VP9_COMMON * const cm = &cpi->common; VP9_COMMON * const cm = &cpi->common;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
// At this point the new frame has been encoded. // At this point the new frame has been encoded.
// If any buffer copy / swapping is signaled it should be done here. // If any buffer copy / swapping is signaled it should be done here.
if (cm->frame_type == KEY_FRAME) { if (cm->frame_type == KEY_FRAME) {
ref_cnt_fb(cm->frame_bufs, ref_cnt_fb(frame_bufs, &cm->ref_frame_map[cpi->gld_fb_idx], cm->new_fb_idx);
&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);
ref_cnt_fb(cm->frame_bufs,
&cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx);
} else if (!cpi->multi_arf_allowed && cpi->refresh_golden_frame && } else if (!cpi->multi_arf_allowed && cpi->refresh_golden_frame &&
cpi->rc.is_src_frame_alt_ref && !cpi->use_svc) { cpi->rc.is_src_frame_alt_ref && !cpi->use_svc) {
/* Preserve the previously existing golden frame and update the frame in /* 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; int tmp;
ref_cnt_fb(cm->frame_bufs, ref_cnt_fb(frame_bufs, &cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx);
&cm->ref_frame_map[cpi->alt_fb_idx], cm->new_fb_idx);
tmp = cpi->alt_fb_idx; tmp = cpi->alt_fb_idx;
cpi->alt_fb_idx = cpi->gld_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]; arf_idx = gf_group->arf_update_idx[gf_group->index];
} }
ref_cnt_fb(cm->frame_bufs, ref_cnt_fb(frame_bufs, &cm->ref_frame_map[arf_idx], cm->new_fb_idx);
&cm->ref_frame_map[arf_idx], cm->new_fb_idx);
} }
if (cpi->refresh_golden_frame) { 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); &cm->ref_frame_map[cpi->gld_fb_idx], cm->new_fb_idx);
} }
} }
if (cpi->refresh_last_frame) { if (cpi->refresh_last_frame) {
ref_cnt_fb(cm->frame_bufs, ref_cnt_fb(frame_bufs, &cm->ref_frame_map[cpi->lst_fb_idx], cm->new_fb_idx);
&cm->ref_frame_map[cpi->lst_fb_idx], cm->new_fb_idx);
} }
#if CONFIG_DENOISING #if CONFIG_DENOISING
vp9_denoiser_update_frame_info(&cpi->denoiser, vp9_denoiser_update_frame_info(&cpi->denoiser,
@@ -1630,34 +1628,36 @@ void vp9_scale_references(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common; VP9_COMMON *cm = &cpi->common;
MV_REFERENCE_FRAME ref_frame; MV_REFERENCE_FRAME ref_frame;
const VP9_REFFRAME ref_mask[3] = {VP9_LAST_FLAG, VP9_GOLD_FLAG, VP9_ALT_FLAG}; 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) { 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 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). // Need to convert from VP9_REFFRAME to index into ref_mask (subtract 1).
if ((cpi->ref_frame_flags & ref_mask[ref_frame - 1]) && if ((cpi->ref_frame_flags & ref_mask[ref_frame - 1]) &&
(ref->y_crop_width != cm->width || ref->y_crop_height != cm->height)) { (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height)) {
const int new_fb = get_free_fb(cm); 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->width, cm->height,
cm->subsampling_x, cm->subsampling_y, cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL); 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; cpi->scaled_ref_idx[ref_frame - 1] = new_fb;
} else { } else {
cpi->scaled_ref_idx[ref_frame - 1] = idx; 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) { static void release_scaled_references(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common; VP9_COMMON *cm = &cpi->common;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
int i; int i;
for (i = 0; i < 3; i++) for (i = 0; i < 3; ++i)
cm->frame_bufs[cpi->scaled_ref_idx[i]].ref_count--; --frame_bufs[cpi->scaled_ref_idx[i]].ref_count;
} }
static void full_to_model_count(unsigned int *model_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 && const int is_spatial_svc = cpi->use_svc &&
(cpi->svc.number_temporal_layers == 1) && (cpi->svc.number_temporal_layers == 1) &&
(cpi->svc.number_spatial_layers > 1); (cpi->svc.number_spatial_layers > 1);
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
if (!cpi) if (!cpi)
return -1; return -1;
@@ -2602,7 +2603,8 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
cm->show_frame = 1; cm->show_frame = 1;
cm->intra_only = 0; 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); 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 /* find a free buffer for the new frame, releasing the reference previously
* held. * 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); cm->new_fb_idx = get_free_fb(cm);
if (!cpi->use_svc && cpi->multi_arf_allowed) { 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) { 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 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]; RefBuffer *const ref_buf = &cm->frame_refs[ref_frame - 1];
ref_buf->buf = buf; ref_buf->buf = buf;
ref_buf->idx = idx; ref_buf->idx = idx;

View File

@@ -436,7 +436,8 @@ typedef struct VP9_COMP {
void vp9_initialize_enc(); 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_remove_compressor(VP9_COMP *cpi);
void vp9_change_config(VP9_COMP *cpi, const VP9EncoderConfig *oxcf); 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( static INLINE YV12_BUFFER_CONFIG *get_ref_frame_buffer(
VP9_COMP *cpi, MV_REFERENCE_FRAME ref_frame) { VP9_COMP *cpi, MV_REFERENCE_FRAME ref_frame) {
VP9_COMMON * const cm = &cpi->common; VP9_COMMON *const cm = &cpi->common;
return &cm->frame_bufs[cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]] BufferPool *const pool = cm->buffer_pool;
return &pool->frame_bufs[cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]]
.buf; .buf;
} }

View File

@@ -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, const YV12_BUFFER_CONFIG *vp9_get_scaled_ref_frame(const VP9_COMP *cpi,
int ref_frame) { int ref_frame) {
const VP9_COMMON *const cm = &cpi->common; 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 ref_idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
const int scaled_idx = cpi->scaled_ref_idx[ref_frame - 1]; 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) { int vp9_get_switchable_rate(const VP9_COMP *cpi) {

View File

@@ -90,6 +90,8 @@ struct vpx_codec_alg_priv {
vp8_postproc_cfg_t preview_ppcfg; vp8_postproc_cfg_t preview_ppcfg;
vpx_codec_pkt_list_decl(128) pkt_list; vpx_codec_pkt_list_decl(128) pkt_list;
unsigned int fixed_kf_cntr; 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) { 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->alg_priv = priv;
ctx->priv->init_flags = ctx->init_flags; ctx->priv->init_flags = ctx->init_flags;
ctx->priv->enc.total_encoders = 1; 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) { if (ctx->config.enc) {
// Update the reference to the config structure to an internal copy. // 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, set_encoder_config(&ctx->priv->alg_priv->oxcf,
&ctx->priv->alg_priv->cfg, &ctx->priv->alg_priv->cfg,
&ctx->priv->alg_priv->extra_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) if (cpi == NULL)
res = VPX_CODEC_MEM_ERROR; res = VPX_CODEC_MEM_ERROR;
else 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) { static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
free(ctx->cx_data); free(ctx->cx_data);
vp9_remove_compressor(ctx->cpi); vp9_remove_compressor(ctx->cpi);
vpx_free(ctx->buffer_pool);
free(ctx); free(ctx);
return VPX_CODEC_OK; return VPX_CODEC_OK;
} }

View File

@@ -32,15 +32,22 @@ struct vpx_codec_alg_priv {
vpx_codec_priv_t base; vpx_codec_priv_t base;
vpx_codec_dec_cfg_t cfg; vpx_codec_dec_cfg_t cfg;
vp9_stream_info_t si; vp9_stream_info_t si;
struct VP9Decoder *pbi;
int postproc_cfg_set; int postproc_cfg_set;
vp8_postproc_cfg_t postproc_cfg; vp8_postproc_cfg_t postproc_cfg;
vpx_decrypt_cb decrypt_cb; vpx_decrypt_cb decrypt_cb;
void *decrypt_state; void *decrypt_state;
vpx_image_t img; vpx_image_t img;
int img_avail;
int invert_tile_order; int invert_tile_order;
int frame_parallel_decode; // frame-based threading. 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. // External frame buffer info to save for VP9 common.
void *ext_priv; // Private data associated with the external frame buffers. 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) { static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) {
if (ctx->pbi) { if (ctx->frame_workers != NULL) {
vp9_decoder_remove(ctx->pbi); int i;
ctx->pbi = NULL; 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); vpx_free(ctx);
return VPX_CODEC_OK; 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; 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, static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx,
const struct vpx_internal_error_info *error) { const struct vpx_internal_error_info *error) {
if (error->error_code) 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; return error->error_code;
} }
static void init_buffer_callbacks(vpx_codec_alg_priv_t *ctx) { 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->new_fb_idx = -1;
cm->get_fb_cb = ctx->get_ext_fb_cb; if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) {
cm->release_fb_cb = ctx->release_ext_fb_cb; pool->get_fb_cb = ctx->get_ext_fb_cb;
cm->cb_priv = ctx->ext_priv; pool->release_fb_cb = ctx->release_ext_fb_cb;
} else { pool->cb_priv = ctx->ext_priv;
cm->get_fb_cb = vp9_get_frame_buffer; } else {
cm->release_fb_cb = vp9_release_frame_buffer; 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)) if (vp9_alloc_internal_frame_buffers(&pool->int_frame_buffers))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to initialize internal frame buffers"); "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; flags->noise_level = ctx->postproc_cfg.noise_level;
} }
static void init_decoder(vpx_codec_alg_priv_t *ctx) { static int frame_worker_hook(void *arg1, void *arg2) {
ctx->pbi = vp9_decoder_create(); FrameWorkerData *const worker_data = (FrameWorkerData *)arg1;
if (ctx->pbi == NULL) const uint8_t *data = worker_data->data;
return; (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; static vpx_codec_err_t init_decoder(vpx_codec_alg_priv_t *ctx) {
ctx->pbi->inv_tile_order = ctx->invert_tile_order; int i;
ctx->pbi->frame_parallel_decode = ctx->frame_parallel_decode; 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 // If postprocessing was enabled by the application and a
// configuration has not been provided, default it. // 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); set_default_ppflags(&ctx->postproc_cfg);
init_buffer_callbacks(ctx); init_buffer_callbacks(ctx);
return VPX_CODEC_OK;
} }
static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx, static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
const uint8_t **data, unsigned int data_sz, const uint8_t **data, unsigned int data_sz,
void *user_priv, int64_t deadline) { void *user_priv, int64_t deadline) {
YV12_BUFFER_CONFIG sd; vp9_ppflags_t flags = {0};
vp9_ppflags_t flags = {0, 0, 0}; const VP9WorkerInterface *const winterface = vp9_get_worker_interface();
VP9_COMMON *cm = NULL;
(void)deadline; (void)deadline;
vp9_zero(sd);
ctx->img_avail = 0;
// Determine the stream parameters. Note that we rely on peek_si to // 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 // validate that we have a buffer that does not wrap around the top
// of the heap. // of the heap.
@@ -276,33 +348,41 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
return VPX_CODEC_ERROR; return VPX_CODEC_ERROR;
} }
// Initialize the decoder instance on the first frame // Initialize the decoder workers on the first frame
if (ctx->pbi == NULL) { if (ctx->frame_workers == NULL) {
init_decoder(ctx); const vpx_codec_err_t res = init_decoder(ctx);
if (ctx->pbi == NULL) if (res != VPX_CODEC_OK)
return VPX_CODEC_ERROR; return res;
} }
// Set these even if already initialized. The caller may have changed the if (!ctx->frame_parallel_decode) {
// decrypt config between frames. VP9Worker *const worker = ctx->frame_workers;
ctx->pbi->decrypt_cb = ctx->decrypt_cb; FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
ctx->pbi->decrypt_state = ctx->decrypt_state; 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)) worker->had_error = 0;
return update_error_state(ctx, &cm->error); 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) if (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)
set_ppflags(ctx, &flags); 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; 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; vpx_codec_err_t res;
if (data_start < data if (data_start < data
|| frame_size > (uint32_t) (data_end - data_start)) { || 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; 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. // Extra data detected after the frame.
if (data_start < data_end - 1) { 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; 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; vpx_codec_err_t res;
if (data_start < data if (data_start < data
|| frame_size > (uint32_t) (data_end - data_start)) { || 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; 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_codec_iter_t *iter) {
vpx_image_t *img = NULL; vpx_image_t *img = NULL;
if (ctx->img_avail) { // iter acts as a flip flop, so an image is only returned on the first
// iter acts as a flip flop, so an image is only returned on the first // call to get_frame.
// call to get_frame. if (*iter == NULL && ctx->frame_workers != NULL) {
if (!(*iter)) { 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; img = &ctx->img;
*iter = 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; 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) { vpx_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) {
if (cb_get == NULL || cb_release == NULL) { if (cb_get == NULL || cb_release == NULL) {
return VPX_CODEC_INVALID_PARAM; 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 // If the decoder has already been initialized, do not accept changes to
// the frame buffer functions. // the frame buffer functions.
ctx->get_ext_fb_cb = cb_get; 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) { va_list args) {
vpx_ref_frame_t *const data = va_arg(args, vpx_ref_frame_t *); 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) { if (data) {
vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data; vpx_ref_frame_t *const frame = (vpx_ref_frame_t *)data;
YV12_BUFFER_CONFIG sd; YV12_BUFFER_CONFIG sd;
VP9Worker *const worker = ctx->frame_workers;
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
image2yuvconfig(&frame->img, &sd); 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); (VP9_REFFRAME)frame->frame_type, &sd);
} else { } else {
return VPX_CODEC_INVALID_PARAM; 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) { va_list args) {
vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *); 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) { 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; YV12_BUFFER_CONFIG sd;
VP9Worker *const worker = ctx->frame_workers;
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
image2yuvconfig(&frame->img, &sd); image2yuvconfig(&frame->img, &sd);
return vp9_copy_reference_dec(worker_data->pbi,
return vp9_copy_reference_dec(ctx->pbi,
(VP9_REFFRAME)frame->frame_type, &sd); (VP9_REFFRAME)frame->frame_type, &sd);
} else { } else {
return VPX_CODEC_INVALID_PARAM; 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) { va_list args) {
vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *); 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) { if (data) {
YV12_BUFFER_CONFIG* fb; YV12_BUFFER_CONFIG* fb;
VP9Worker *const worker = ctx->frame_workers;
vp9_get_reference_dec(ctx->pbi, data->idx, &fb); FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
vp9_get_reference_dec(worker_data->pbi, data->idx, &fb);
yuvconfig2image(&data->img, fb, NULL); yuvconfig2image(&data->img, fb, NULL);
return VPX_CODEC_OK; return VPX_CODEC_OK;
} else { } else {
@@ -592,11 +716,20 @@ static vpx_codec_err_t ctrl_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
va_list args) { va_list args) {
int *const update_info = va_arg(args, int *); 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 (update_info) {
if (ctx->pbi) if (ctx->frame_workers) {
*update_info = ctx->pbi->refresh_frame_flags; VP9Worker *const worker = ctx->frame_workers;
else FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
*update_info = worker_data->pbi->refresh_frame_flags;
} else {
return VPX_CODEC_ERROR; return VPX_CODEC_ERROR;
}
return VPX_CODEC_OK; return VPX_CODEC_OK;
} else { } else {
return VPX_CODEC_INVALID_PARAM; 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) { va_list args) {
int *corrupted = va_arg(args, int *); 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 (corrupted) {
if (ctx->pbi) if (ctx->frame_workers) {
*corrupted = ctx->pbi->common.frame_to_show->corrupted; VP9Worker *const worker = ctx->frame_workers;
else FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
*corrupted = worker_data->pbi->common.frame_to_show->corrupted;
} else {
return VPX_CODEC_ERROR; return VPX_CODEC_ERROR;
}
return VPX_CODEC_OK; return VPX_CODEC_OK;
} else { } else {
return VPX_CODEC_INVALID_PARAM; 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) { va_list args) {
int *const display_size = va_arg(args, int *); 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 (display_size) {
if (ctx->pbi) { if (ctx->frame_workers) {
const VP9_COMMON *const cm = &ctx->pbi->common; 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[0] = cm->display_width;
display_size[1] = cm->display_height; display_size[1] = cm->display_height;
} else { } else {

View File

@@ -934,8 +934,6 @@ int main_loop(int argc, const char **argv_) {
} }
} }
if (stop_after && frame_in >= stop_after)
break;
} }
if (summary || progress) { if (summary || progress) {