Fix a bug in frame parallel decode and add a unit test for that.
A flush bug is discovered during putting frame parallel decoder into Android. This test will expose that bug. Change-Id: Ia047f27972f4da0471649f79f1f91e7695297473
This commit is contained in:
@@ -665,3 +665,5 @@ f97088c7359fc8d3d5aa5eafe57bc7308b3ee124 vp90-2-20-big_superframe-01.webm
|
|||||||
47d7d409785afa33b123376de0c907336e6c7bd7 vp90-2-20-big_superframe-01.webm.md5
|
47d7d409785afa33b123376de0c907336e6c7bd7 vp90-2-20-big_superframe-01.webm.md5
|
||||||
65ade6d2786209582c50d34cfe22b3cdb033abaf vp90-2-20-big_superframe-02.webm
|
65ade6d2786209582c50d34cfe22b3cdb033abaf vp90-2-20-big_superframe-02.webm
|
||||||
7c0ed8d04c4d06c5411dd2e5de2411d37f092db5 vp90-2-20-big_superframe-02.webm.md5
|
7c0ed8d04c4d06c5411dd2e5de2411d37f092db5 vp90-2-20-big_superframe-02.webm.md5
|
||||||
|
667ec8718c982aef6be07eb94f083c2efb9d2d16 vp90-2-07-frame_parallel-1.webm
|
||||||
|
bfc82bf848e9c05020d61e3ffc1e62f25df81d19 vp90-2-07-frame_parallel-1.webm.md5
|
||||||
|
@@ -31,6 +31,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += keyframe_test.cc
|
|||||||
|
|
||||||
LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += external_frame_buffer_test.cc
|
LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += external_frame_buffer_test.cc
|
||||||
LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += user_priv_test.cc
|
LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += user_priv_test.cc
|
||||||
|
LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += vp9_frame_parallel_test.cc
|
||||||
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += active_map_test.cc
|
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += active_map_test.cc
|
||||||
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += borders_test.cc
|
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += borders_test.cc
|
||||||
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += cpu_speed_test.cc
|
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += cpu_speed_test.cc
|
||||||
@@ -683,6 +684,8 @@ LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-06-bilinear.webm
|
|||||||
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-06-bilinear.webm.md5
|
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-06-bilinear.webm.md5
|
||||||
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-07-frame_parallel.webm
|
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-07-frame_parallel.webm
|
||||||
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-07-frame_parallel.webm.md5
|
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-07-frame_parallel.webm.md5
|
||||||
|
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-07-frame_parallel-1.webm
|
||||||
|
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-07-frame_parallel-1.webm.md5
|
||||||
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-08-tile-4x1.webm
|
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-08-tile-4x1.webm
|
||||||
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-08-tile-4x1.webm.md5
|
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-08-tile-4x1.webm.md5
|
||||||
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-08-tile-4x4.webm
|
LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-08-tile-4x4.webm
|
||||||
|
@@ -154,7 +154,8 @@ const char *const kVP9TestVectors[] = {
|
|||||||
"vp90-2-03-size-226x210.webm", "vp90-2-03-size-226x224.webm",
|
"vp90-2-03-size-226x210.webm", "vp90-2-03-size-226x224.webm",
|
||||||
"vp90-2-03-size-226x226.webm", "vp90-2-03-deltaq.webm",
|
"vp90-2-03-size-226x226.webm", "vp90-2-03-deltaq.webm",
|
||||||
"vp90-2-05-resize.ivf", "vp90-2-06-bilinear.webm",
|
"vp90-2-05-resize.ivf", "vp90-2-06-bilinear.webm",
|
||||||
"vp90-2-07-frame_parallel.webm", "vp90-2-08-tile_1x2_frame_parallel.webm",
|
"vp90-2-07-frame_parallel.webm", "vp90-2-07-frame_parallel-1.webm",
|
||||||
|
"vp90-2-08-tile_1x2_frame_parallel.webm",
|
||||||
"vp90-2-08-tile_1x2.webm", "vp90-2-08-tile_1x4_frame_parallel.webm",
|
"vp90-2-08-tile_1x2.webm", "vp90-2-08-tile_1x4_frame_parallel.webm",
|
||||||
"vp90-2-08-tile_1x4.webm", "vp90-2-08-tile_1x8_frame_parallel.webm",
|
"vp90-2-08-tile_1x4.webm", "vp90-2-08-tile_1x8_frame_parallel.webm",
|
||||||
"vp90-2-08-tile_1x8.webm", "vp90-2-08-tile-4x4.webm",
|
"vp90-2-08-tile_1x8.webm", "vp90-2-08-tile-4x4.webm",
|
||||||
|
122
test/vp9_frame_parallel_test.cc
Normal file
122
test/vp9_frame_parallel_test.cc
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
#include "third_party/googletest/src/include/gtest/gtest.h"
|
||||||
|
#include "./vpx_config.h"
|
||||||
|
#include "test/codec_factory.h"
|
||||||
|
#include "test/decode_test_driver.h"
|
||||||
|
#include "test/ivf_video_source.h"
|
||||||
|
#include "test/md5_helper.h"
|
||||||
|
#include "test/util.h"
|
||||||
|
#if CONFIG_WEBM_IO
|
||||||
|
#include "test/webm_video_source.h"
|
||||||
|
#endif
|
||||||
|
#include "vpx_mem/vpx_mem.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
#if CONFIG_WEBM_IO
|
||||||
|
|
||||||
|
struct FileList {
|
||||||
|
const char *name;
|
||||||
|
// md5 sum for decoded frames which does not include skipped frames.
|
||||||
|
const char *expected_md5;
|
||||||
|
const int pause_frame_num;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decodes |filename| with |num_threads|. Pause at the specified frame_num,
|
||||||
|
// seek to next key frame and then continue decoding until the end. Return
|
||||||
|
// the md5 of the decoded frames which does not include skipped frames.
|
||||||
|
string DecodeFile(const string &filename, int num_threads, int pause_num) {
|
||||||
|
libvpx_test::WebMVideoSource video(filename);
|
||||||
|
video.Init();
|
||||||
|
int in_frames = 0;
|
||||||
|
int out_frames = 0;
|
||||||
|
|
||||||
|
vpx_codec_dec_cfg_t cfg = {0};
|
||||||
|
cfg.threads = num_threads;
|
||||||
|
vpx_codec_flags_t flags = 0;
|
||||||
|
flags |= VPX_CODEC_USE_FRAME_THREADING;
|
||||||
|
libvpx_test::VP9Decoder decoder(cfg, flags, 0);
|
||||||
|
|
||||||
|
libvpx_test::MD5 md5;
|
||||||
|
video.Begin();
|
||||||
|
|
||||||
|
do {
|
||||||
|
++in_frames;
|
||||||
|
const vpx_codec_err_t res =
|
||||||
|
decoder.DecodeFrame(video.cxdata(), video.frame_size());
|
||||||
|
if (res != VPX_CODEC_OK) {
|
||||||
|
EXPECT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause at specified frame number.
|
||||||
|
if (in_frames == pause_num) {
|
||||||
|
// Flush the decoder and then seek to next key frame.
|
||||||
|
decoder.DecodeFrame(NULL, 0);
|
||||||
|
video.SeekToNextKeyFrame();
|
||||||
|
} else {
|
||||||
|
video.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the decoder at the end of the video.
|
||||||
|
if (!video.cxdata())
|
||||||
|
decoder.DecodeFrame(NULL, 0);
|
||||||
|
|
||||||
|
libvpx_test::DxDataIterator dec_iter = decoder.GetDxData();
|
||||||
|
const vpx_image_t *img;
|
||||||
|
|
||||||
|
// Get decompressed data
|
||||||
|
while ((img = dec_iter.Next())) {
|
||||||
|
++out_frames;
|
||||||
|
md5.Add(img);
|
||||||
|
}
|
||||||
|
} while (video.cxdata() != NULL);
|
||||||
|
|
||||||
|
EXPECT_EQ(in_frames, out_frames) <<
|
||||||
|
"Input frame count does not match output frame count";
|
||||||
|
|
||||||
|
return string(md5.Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecodeFiles(const FileList files[]) {
|
||||||
|
for (const FileList *iter = files; iter->name != NULL; ++iter) {
|
||||||
|
SCOPED_TRACE(iter->name);
|
||||||
|
for (int t = 2; t <= 8; ++t) {
|
||||||
|
EXPECT_EQ(iter->expected_md5,
|
||||||
|
DecodeFile(iter->name, t, iter->pause_frame_num))
|
||||||
|
<< "threads = " << t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VP9MultiThreadedFrameParallel, PauseSeekResume) {
|
||||||
|
// vp90-2-07-frame_parallel-1.webm is a 40 frame video file with
|
||||||
|
// one key frame for every ten frames.
|
||||||
|
static const FileList files[] = {
|
||||||
|
{ "vp90-2-07-frame_parallel-1.webm",
|
||||||
|
"6ea7c3875d67252e7caf2bc6e75b36b1", 6},
|
||||||
|
{ "vp90-2-07-frame_parallel-1.webm",
|
||||||
|
"4bb634160c7356a8d7d4299b6dc83a45", 12},
|
||||||
|
{ "vp90-2-07-frame_parallel-1.webm",
|
||||||
|
"89772591e6ef461f9fa754f916c78ed8", 26},
|
||||||
|
{ NULL, NULL, 0},
|
||||||
|
};
|
||||||
|
DecodeFiles(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CONFIG_WEBM_IO
|
||||||
|
} // namespace
|
@@ -272,6 +272,8 @@ int vp9_receive_compressed_data(VP9Decoder *pbi,
|
|||||||
cm->frame_refs[0].buf->corrupted = 1;
|
cm->frame_refs[0].buf->corrupted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pbi->ready_for_new_data = 0;
|
||||||
|
|
||||||
// Check if the previous frame was a frame without any references to it.
|
// Check if the previous frame was a frame without any references to it.
|
||||||
// Release frame buffer if not decoding in frame parallel mode.
|
// Release frame buffer if not decoding in frame parallel mode.
|
||||||
if (!pbi->frame_parallel_decode && cm->new_fb_idx >= 0
|
if (!pbi->frame_parallel_decode && cm->new_fb_idx >= 0
|
||||||
@@ -296,6 +298,7 @@ int vp9_receive_compressed_data(VP9Decoder *pbi,
|
|||||||
|
|
||||||
if (setjmp(cm->error.jmp)) {
|
if (setjmp(cm->error.jmp)) {
|
||||||
cm->error.setjmp = 0;
|
cm->error.setjmp = 0;
|
||||||
|
pbi->ready_for_new_data = 1;
|
||||||
|
|
||||||
// We do not know if the missing frame(s) was supposed to update
|
// We do not know if the missing frame(s) was supposed to update
|
||||||
// any of the reference buffers, but we act conservative and
|
// any of the reference buffers, but we act conservative and
|
||||||
@@ -354,8 +357,6 @@ int vp9_receive_compressed_data(VP9Decoder *pbi,
|
|||||||
vp9_swap_current_and_last_seg_map(cm);
|
vp9_swap_current_and_last_seg_map(cm);
|
||||||
}
|
}
|
||||||
|
|
||||||
pbi->ready_for_new_data = 0;
|
|
||||||
|
|
||||||
cm->error.setjmp = 0;
|
cm->error.setjmp = 0;
|
||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
@@ -370,12 +371,12 @@ int vp9_get_raw_frame(VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd,
|
|||||||
if (pbi->ready_for_new_data == 1)
|
if (pbi->ready_for_new_data == 1)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
pbi->ready_for_new_data = 1;
|
||||||
|
|
||||||
/* no raw frame to show!!! */
|
/* no raw frame to show!!! */
|
||||||
if (pbi->common.show_frame == 0)
|
if (pbi->common.show_frame == 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
pbi->ready_for_new_data = 1;
|
|
||||||
|
|
||||||
#if CONFIG_VP9_POSTPROC
|
#if CONFIG_VP9_POSTPROC
|
||||||
ret = vp9_post_proc_frame(&pbi->common, sd, flags);
|
ret = vp9_post_proc_frame(&pbi->common, sd, flags);
|
||||||
#else
|
#else
|
||||||
|
@@ -443,6 +443,8 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
|
|||||||
&ctx->frame_workers[ctx->next_submit_worker_id],
|
&ctx->frame_workers[ctx->next_submit_worker_id],
|
||||||
&ctx->frame_workers[ctx->last_submit_worker_id]);
|
&ctx->frame_workers[ctx->last_submit_worker_id]);
|
||||||
|
|
||||||
|
frame_worker_data->pbi->ready_for_new_data = 0;
|
||||||
|
|
||||||
// Copy the compressed data into worker's internal buffer.
|
// Copy the compressed data into worker's internal buffer.
|
||||||
// TODO(hkuang): Will all the workers allocate the same size
|
// TODO(hkuang): Will all the workers allocate the same size
|
||||||
// as the size of the first intra frame be better? This will
|
// as the size of the first intra frame be better? This will
|
||||||
@@ -757,10 +759,10 @@ static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx,
|
|||||||
(ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
|
(ctx->next_output_worker_id + 1) % ctx->num_frame_workers;
|
||||||
// Wait for the frame from worker thread.
|
// Wait for the frame from worker thread.
|
||||||
winterface->sync(worker);
|
winterface->sync(worker);
|
||||||
++ctx->available_threads;
|
|
||||||
if (vp9_get_raw_frame(frame_worker_data->pbi, &sd, &flags) == 0) {
|
if (vp9_get_raw_frame(frame_worker_data->pbi, &sd, &flags) == 0) {
|
||||||
VP9_COMMON *const cm = &frame_worker_data->pbi->common;
|
VP9_COMMON *const cm = &frame_worker_data->pbi->common;
|
||||||
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
|
||||||
|
++ctx->available_threads;
|
||||||
release_last_output_frame(ctx);
|
release_last_output_frame(ctx);
|
||||||
ctx->last_show_frame = frame_worker_data->pbi->common.new_fb_idx;
|
ctx->last_show_frame = frame_worker_data->pbi->common.new_fb_idx;
|
||||||
yuvconfig2image(&ctx->img, &sd, frame_worker_data->user_priv);
|
yuvconfig2image(&ctx->img, &sd, frame_worker_data->user_priv);
|
||||||
|
Reference in New Issue
Block a user