Extend the external fb interface to allocate individual planes.
Change-Id: I73e1b9ea6f4c76ae539e2b3292ee4c751d9c7de4
This commit is contained in:
Родитель
034031d4aa
Коммит
6dd7f2b50a
|
@ -23,9 +23,16 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const int kVideoNameParam = 1;
|
const int kCodedFrameBufferTypeParam = 1;
|
||||||
|
const int kVideoNameParam = 2;
|
||||||
|
|
||||||
struct ExternalFrameBuffer {
|
struct ExternalFrameBuffer {
|
||||||
|
// The first two fields are used when fb->type is equal to
|
||||||
|
// VPX_CODEC_FRAME_BUFFER_TYPE_PLANES
|
||||||
|
uint8_t *plane[VP9_MAXIMUM_EXTERNAL_PLANES];
|
||||||
|
int stride[VP9_MAXIMUM_EXTERNAL_PLANES];
|
||||||
|
// The following two fields are used when fb->type is equal to
|
||||||
|
// VPX_CODEC_FRAME_BUFFER_TYPE_SIZE
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
int in_use;
|
int in_use;
|
||||||
|
@ -34,12 +41,17 @@ struct ExternalFrameBuffer {
|
||||||
// Class to manipulate a list of external frame buffers.
|
// Class to manipulate a list of external frame buffers.
|
||||||
class ExternalFrameBufferList {
|
class ExternalFrameBufferList {
|
||||||
public:
|
public:
|
||||||
ExternalFrameBufferList()
|
explicit ExternalFrameBufferList(vpx_codec_frame_buffer_type_t type)
|
||||||
: num_buffers_(0),
|
: num_buffers_(0),
|
||||||
ext_fb_list_(NULL) {}
|
ext_fb_list_(NULL),
|
||||||
|
type_(type),
|
||||||
|
alignment_(32) {}
|
||||||
|
|
||||||
virtual ~ExternalFrameBufferList() {
|
virtual ~ExternalFrameBufferList() {
|
||||||
for (int i = 0; i < num_buffers_; ++i) {
|
for (int i = 0; i < num_buffers_; ++i) {
|
||||||
|
for (int plane = 0; plane < VP9_MAXIMUM_EXTERNAL_PLANES; ++plane) {
|
||||||
|
delete [] ext_fb_list_[i].plane[plane];
|
||||||
|
}
|
||||||
delete [] ext_fb_list_[i].data;
|
delete [] ext_fb_list_[i].data;
|
||||||
}
|
}
|
||||||
delete [] ext_fb_list_;
|
delete [] ext_fb_list_;
|
||||||
|
@ -63,17 +75,44 @@ class ExternalFrameBufferList {
|
||||||
// external frame buffer. Returns < 0 on an error.
|
// external frame buffer. Returns < 0 on an error.
|
||||||
int GetFreeFrameBuffer(size_t min_size, vpx_codec_frame_buffer_t *fb) {
|
int GetFreeFrameBuffer(size_t min_size, vpx_codec_frame_buffer_t *fb) {
|
||||||
EXPECT_TRUE(fb != NULL);
|
EXPECT_TRUE(fb != NULL);
|
||||||
|
EXPECT_TRUE(fb->fmt == VPX_IMG_FMT_I420 || fb->fmt == VPX_IMG_FMT_I444 ||
|
||||||
|
fb->fmt == VPX_IMG_FMT_I422 || fb->fmt == VPX_IMG_FMT_I440)
|
||||||
|
<< " fmt is: " << fb->fmt;
|
||||||
|
|
||||||
const int idx = FindFreeBufferIndex();
|
const int idx = FindFreeBufferIndex();
|
||||||
if (idx == num_buffers_)
|
if (idx == num_buffers_)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (ext_fb_list_[idx].size < min_size) {
|
if (type_ == VPX_CODEC_FRAME_BUFFER_TYPE_SIZE) {
|
||||||
delete [] ext_fb_list_[idx].data;
|
if (ext_fb_list_[idx].size < min_size) {
|
||||||
ext_fb_list_[idx].data = new uint8_t[min_size];
|
delete [] ext_fb_list_[idx].data;
|
||||||
memset(ext_fb_list_[idx].data, 0, min_size);
|
ext_fb_list_[idx].data = new uint8_t[min_size];
|
||||||
ext_fb_list_[idx].size = min_size;
|
memset(ext_fb_list_[idx].data, 0, min_size);
|
||||||
|
ext_fb_list_[idx].size = min_size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EXPECT_EQ(VPX_CODEC_FRAME_BUFFER_TYPE_PLANES, type_);
|
||||||
|
for (int plane = 0; plane < 3; ++plane) {
|
||||||
|
size_t plane_stride = fb->width;
|
||||||
|
size_t plane_height = fb->height;
|
||||||
|
|
||||||
|
if (plane > 0 && fb->fmt != VPX_IMG_FMT_I444) {
|
||||||
|
if (fb->fmt != VPX_IMG_FMT_I440)
|
||||||
|
plane_stride /= 2;
|
||||||
|
if (fb->fmt == VPX_IMG_FMT_I420 || fb->fmt == VPX_IMG_FMT_I440)
|
||||||
|
plane_height /= 2;
|
||||||
|
}
|
||||||
|
plane_stride += alignment_ - plane_stride % alignment_;
|
||||||
|
|
||||||
|
delete [] ext_fb_list_[idx].plane[plane];
|
||||||
|
ext_fb_list_[idx].plane[plane] =
|
||||||
|
new uint8_t[plane_height * plane_stride];
|
||||||
|
memset(ext_fb_list_[idx].plane[plane], 0, plane_height * plane_stride);
|
||||||
|
ext_fb_list_[idx].stride[plane] = plane_stride;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fb->type = type_;
|
||||||
SetFrameBuffer(idx, fb);
|
SetFrameBuffer(idx, fb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -86,12 +125,27 @@ class ExternalFrameBufferList {
|
||||||
if (idx == num_buffers_)
|
if (idx == num_buffers_)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (ext_fb_list_[idx].size < min_size) {
|
if (type_ == VPX_CODEC_FRAME_BUFFER_TYPE_SIZE) {
|
||||||
delete [] ext_fb_list_[idx].data;
|
delete [] ext_fb_list_[idx].data;
|
||||||
ext_fb_list_[idx].data = NULL;
|
ext_fb_list_[idx].data = NULL;
|
||||||
ext_fb_list_[idx].size = min_size;
|
ext_fb_list_[idx].size = min_size;
|
||||||
|
} else {
|
||||||
|
EXPECT_EQ(VPX_CODEC_FRAME_BUFFER_TYPE_PLANES, type_);
|
||||||
|
for (int plane = 0; plane < 3; ++plane) {
|
||||||
|
size_t plane_stride = fb->width;
|
||||||
|
if (plane > 0 && fb->fmt != VPX_IMG_FMT_I444) {
|
||||||
|
if (fb->fmt != VPX_IMG_FMT_I440)
|
||||||
|
plane_stride /= 2;
|
||||||
|
}
|
||||||
|
plane_stride += alignment_ - plane_stride % alignment_;
|
||||||
|
|
||||||
|
delete [] ext_fb_list_[idx].plane[plane];
|
||||||
|
ext_fb_list_[idx].plane[plane] = NULL;
|
||||||
|
ext_fb_list_[idx].stride[plane] = plane_stride;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fb->type = type_;
|
||||||
SetFrameBuffer(idx, fb);
|
SetFrameBuffer(idx, fb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -120,12 +174,24 @@ class ExternalFrameBufferList {
|
||||||
if (img->fb_priv != NULL) {
|
if (img->fb_priv != NULL) {
|
||||||
const struct ExternalFrameBuffer *const ext_fb =
|
const struct ExternalFrameBuffer *const ext_fb =
|
||||||
reinterpret_cast<ExternalFrameBuffer*>(img->fb_priv);
|
reinterpret_cast<ExternalFrameBuffer*>(img->fb_priv);
|
||||||
|
if (ext_fb->data != NULL) {
|
||||||
ASSERT_TRUE(img->planes[0] >= ext_fb->data &&
|
ASSERT_TRUE(img->planes[0] >= ext_fb->data &&
|
||||||
img->planes[0] < (ext_fb->data + ext_fb->size));
|
img->planes[0] < (ext_fb->data + ext_fb->size));
|
||||||
|
} else {
|
||||||
|
for (int plane = 0; plane < VP9_MAXIMUM_EXTERNAL_PLANES; ++plane) {
|
||||||
|
if (ext_fb->stride[plane]) {
|
||||||
|
EXPECT_EQ(img->planes[plane], ext_fb->plane[plane]);
|
||||||
|
EXPECT_EQ(img->stride[plane], ext_fb->stride[plane]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_alignment(int alignment) {
|
||||||
|
alignment_ = alignment;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Returns the index of the first free frame buffer. Returns |num_buffers_|
|
// Returns the index of the first free frame buffer. Returns |num_buffers_|
|
||||||
// if there are no free frame buffers.
|
// if there are no free frame buffers.
|
||||||
|
@ -145,6 +211,10 @@ class ExternalFrameBufferList {
|
||||||
ASSERT_TRUE(fb != NULL);
|
ASSERT_TRUE(fb != NULL);
|
||||||
fb->data = ext_fb_list_[idx].data;
|
fb->data = ext_fb_list_[idx].data;
|
||||||
fb->size = ext_fb_list_[idx].size;
|
fb->size = ext_fb_list_[idx].size;
|
||||||
|
for (int plane = 0; plane < VP9_MAXIMUM_EXTERNAL_PLANES; ++plane) {
|
||||||
|
fb->plane[plane] = ext_fb_list_[idx].plane[plane];
|
||||||
|
fb->stride[plane] = ext_fb_list_[idx].stride[plane];
|
||||||
|
}
|
||||||
ASSERT_EQ(0, ext_fb_list_[idx].in_use);
|
ASSERT_EQ(0, ext_fb_list_[idx].in_use);
|
||||||
ext_fb_list_[idx].in_use = 1;
|
ext_fb_list_[idx].in_use = 1;
|
||||||
fb->priv = &ext_fb_list_[idx];
|
fb->priv = &ext_fb_list_[idx];
|
||||||
|
@ -152,6 +222,8 @@ class ExternalFrameBufferList {
|
||||||
|
|
||||||
int num_buffers_;
|
int num_buffers_;
|
||||||
ExternalFrameBuffer *ext_fb_list_;
|
ExternalFrameBuffer *ext_fb_list_;
|
||||||
|
vpx_codec_frame_buffer_type_t type_;
|
||||||
|
int alignment_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if CONFIG_WEBM_IO
|
#if CONFIG_WEBM_IO
|
||||||
|
@ -203,12 +275,14 @@ int do_not_release_vp9_frame_buffer(void *user_priv,
|
||||||
// Class for testing passing in external frame buffers to libvpx.
|
// Class for testing passing in external frame buffers to libvpx.
|
||||||
class ExternalFrameBufferMD5Test
|
class ExternalFrameBufferMD5Test
|
||||||
: public ::libvpx_test::DecoderTest,
|
: public ::libvpx_test::DecoderTest,
|
||||||
public ::libvpx_test::CodecTestWithParam<const char*> {
|
public ::libvpx_test::CodecTestWith2Params<vpx_codec_frame_buffer_type_t,
|
||||||
|
const char*> {
|
||||||
protected:
|
protected:
|
||||||
ExternalFrameBufferMD5Test()
|
ExternalFrameBufferMD5Test()
|
||||||
: DecoderTest(GET_PARAM(::libvpx_test::kCodecFactoryParam)),
|
: DecoderTest(GET_PARAM(::libvpx_test::kCodecFactoryParam)),
|
||||||
md5_file_(NULL),
|
md5_file_(NULL),
|
||||||
num_buffers_(0) {}
|
num_buffers_(0),
|
||||||
|
fb_list_(GET_PARAM(kCodedFrameBufferTypeParam)) {}
|
||||||
|
|
||||||
virtual ~ExternalFrameBufferMD5Test() {
|
virtual ~ExternalFrameBufferMD5Test() {
|
||||||
if (md5_file_ != NULL)
|
if (md5_file_ != NULL)
|
||||||
|
@ -284,12 +358,15 @@ class ExternalFrameBufferMD5Test
|
||||||
const char kVP9TestFile[] = "vp90-2-02-size-lf-1920x1080.webm";
|
const char kVP9TestFile[] = "vp90-2-02-size-lf-1920x1080.webm";
|
||||||
|
|
||||||
// Class for testing passing in external frame buffers to libvpx.
|
// Class for testing passing in external frame buffers to libvpx.
|
||||||
class ExternalFrameBufferTest : public ::testing::Test {
|
class ExternalFrameBufferTest
|
||||||
|
: public ::libvpx_test::CodecTestWithParam<vpx_codec_frame_buffer_type_t> {
|
||||||
protected:
|
protected:
|
||||||
ExternalFrameBufferTest()
|
ExternalFrameBufferTest()
|
||||||
: video_(NULL),
|
: video_(NULL),
|
||||||
decoder_(NULL),
|
decoder_(NULL),
|
||||||
num_buffers_(0) {}
|
num_buffers_(0),
|
||||||
|
frame_buffer_functions_set_(false),
|
||||||
|
fb_list_(GET_PARAM(kCodedFrameBufferTypeParam)) {}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
video_ = new libvpx_test::WebMVideoSource(kVP9TestFile);
|
video_ = new libvpx_test::WebMVideoSource(kVP9TestFile);
|
||||||
|
@ -312,6 +389,7 @@ class ExternalFrameBufferTest : public ::testing::Test {
|
||||||
int num_buffers,
|
int num_buffers,
|
||||||
vpx_get_frame_buffer_cb_fn_t cb_get,
|
vpx_get_frame_buffer_cb_fn_t cb_get,
|
||||||
vpx_release_frame_buffer_cb_fn_t cb_release) {
|
vpx_release_frame_buffer_cb_fn_t cb_release) {
|
||||||
|
frame_buffer_functions_set_ = true;
|
||||||
if (num_buffers > 0) {
|
if (num_buffers > 0) {
|
||||||
num_buffers_ = num_buffers;
|
num_buffers_ = num_buffers;
|
||||||
EXPECT_TRUE(fb_list_.CreateBufferList(num_buffers_));
|
EXPECT_TRUE(fb_list_.CreateBufferList(num_buffers_));
|
||||||
|
@ -320,6 +398,10 @@ class ExternalFrameBufferTest : public ::testing::Test {
|
||||||
return decoder_->SetFrameBufferFunctions(cb_get, cb_release, &fb_list_);
|
return decoder_->SetFrameBufferFunctions(cb_get, cb_release, &fb_list_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetBufferAlignment(int alignment) {
|
||||||
|
fb_list_.set_alignment(alignment);
|
||||||
|
}
|
||||||
|
|
||||||
vpx_codec_err_t DecodeOneFrame() {
|
vpx_codec_err_t DecodeOneFrame() {
|
||||||
const vpx_codec_err_t res =
|
const vpx_codec_err_t res =
|
||||||
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
|
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
|
||||||
|
@ -347,13 +429,15 @@ class ExternalFrameBufferTest : public ::testing::Test {
|
||||||
|
|
||||||
// Get decompressed data
|
// Get decompressed data
|
||||||
while ((img = dec_iter.Next()) != NULL) {
|
while ((img = dec_iter.Next()) != NULL) {
|
||||||
fb_list_.CheckXImageFrameBuffer(img);
|
if (frame_buffer_functions_set_)
|
||||||
|
fb_list_.CheckXImageFrameBuffer(img);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
libvpx_test::WebMVideoSource *video_;
|
libvpx_test::WebMVideoSource *video_;
|
||||||
libvpx_test::VP9Decoder *decoder_;
|
libvpx_test::VP9Decoder *decoder_;
|
||||||
int num_buffers_;
|
int num_buffers_;
|
||||||
|
bool frame_buffer_functions_set_;
|
||||||
ExternalFrameBufferList fb_list_;
|
ExternalFrameBufferList fb_list_;
|
||||||
};
|
};
|
||||||
#endif // CONFIG_WEBM_IO
|
#endif // CONFIG_WEBM_IO
|
||||||
|
@ -404,7 +488,7 @@ TEST_P(ExternalFrameBufferMD5Test, ExtFBMD5Match) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_WEBM_IO
|
#if CONFIG_WEBM_IO
|
||||||
TEST_F(ExternalFrameBufferTest, MinFrameBuffers) {
|
TEST_P(ExternalFrameBufferTest, MinFrameBuffers) {
|
||||||
// Minimum number of external frame buffers for VP9 is
|
// Minimum number of external frame buffers for VP9 is
|
||||||
// #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS.
|
// #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS.
|
||||||
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||||
|
@ -414,7 +498,7 @@ TEST_F(ExternalFrameBufferTest, MinFrameBuffers) {
|
||||||
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames());
|
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ExternalFrameBufferTest, EightJitterBuffers) {
|
TEST_P(ExternalFrameBufferTest, EightJitterBuffers) {
|
||||||
// Number of buffers equals #VP9_MAXIMUM_REF_BUFFERS +
|
// Number of buffers equals #VP9_MAXIMUM_REF_BUFFERS +
|
||||||
// #VPX_MAXIMUM_WORK_BUFFERS + eight jitter buffers.
|
// #VPX_MAXIMUM_WORK_BUFFERS + eight jitter buffers.
|
||||||
const int jitter_buffers = 8;
|
const int jitter_buffers = 8;
|
||||||
|
@ -426,7 +510,7 @@ TEST_F(ExternalFrameBufferTest, EightJitterBuffers) {
|
||||||
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames());
|
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ExternalFrameBufferTest, NotEnoughBuffers) {
|
TEST_P(ExternalFrameBufferTest, NotEnoughBuffers) {
|
||||||
// Minimum number of external frame buffers for VP9 is
|
// Minimum number of external frame buffers for VP9 is
|
||||||
// #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS. Most files will
|
// #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS. Most files will
|
||||||
// only use 5 frame buffers at one time.
|
// only use 5 frame buffers at one time.
|
||||||
|
@ -438,7 +522,7 @@ TEST_F(ExternalFrameBufferTest, NotEnoughBuffers) {
|
||||||
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames());
|
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ExternalFrameBufferTest, NoRelease) {
|
TEST_P(ExternalFrameBufferTest, NoRelease) {
|
||||||
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||||
ASSERT_EQ(VPX_CODEC_OK,
|
ASSERT_EQ(VPX_CODEC_OK,
|
||||||
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer,
|
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer,
|
||||||
|
@ -447,7 +531,7 @@ TEST_F(ExternalFrameBufferTest, NoRelease) {
|
||||||
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames());
|
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ExternalFrameBufferTest, NullRealloc) {
|
TEST_P(ExternalFrameBufferTest, NullRealloc) {
|
||||||
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||||
ASSERT_EQ(VPX_CODEC_OK,
|
ASSERT_EQ(VPX_CODEC_OK,
|
||||||
SetFrameBufferFunctions(num_buffers, get_vp9_zero_frame_buffer,
|
SetFrameBufferFunctions(num_buffers, get_vp9_zero_frame_buffer,
|
||||||
|
@ -455,7 +539,11 @@ TEST_F(ExternalFrameBufferTest, NullRealloc) {
|
||||||
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeOneFrame());
|
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeOneFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ExternalFrameBufferTest, ReallocOneLessByte) {
|
TEST_P(ExternalFrameBufferTest, ReallocOneLessByte) {
|
||||||
|
if (GET_PARAM(kCodedFrameBufferTypeParam) ==
|
||||||
|
VPX_CODEC_FRAME_BUFFER_TYPE_PLANES)
|
||||||
|
return;
|
||||||
|
|
||||||
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||||
ASSERT_EQ(VPX_CODEC_OK,
|
ASSERT_EQ(VPX_CODEC_OK,
|
||||||
SetFrameBufferFunctions(
|
SetFrameBufferFunctions(
|
||||||
|
@ -464,29 +552,50 @@ TEST_F(ExternalFrameBufferTest, ReallocOneLessByte) {
|
||||||
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeOneFrame());
|
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeOneFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ExternalFrameBufferTest, NullGetFunction) {
|
TEST_P(ExternalFrameBufferTest, NullGetFunction) {
|
||||||
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||||
ASSERT_EQ(VPX_CODEC_INVALID_PARAM,
|
ASSERT_EQ(VPX_CODEC_INVALID_PARAM,
|
||||||
SetFrameBufferFunctions(num_buffers, NULL,
|
SetFrameBufferFunctions(num_buffers, NULL,
|
||||||
release_vp9_frame_buffer));
|
release_vp9_frame_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ExternalFrameBufferTest, NullReleaseFunction) {
|
TEST_P(ExternalFrameBufferTest, NullReleaseFunction) {
|
||||||
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||||
ASSERT_EQ(VPX_CODEC_INVALID_PARAM,
|
ASSERT_EQ(VPX_CODEC_INVALID_PARAM,
|
||||||
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer, NULL));
|
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ExternalFrameBufferTest, SetAfterDecode) {
|
TEST_P(ExternalFrameBufferTest, SetAfterDecode) {
|
||||||
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||||
ASSERT_EQ(VPX_CODEC_OK, DecodeOneFrame());
|
ASSERT_EQ(VPX_CODEC_OK, DecodeOneFrame());
|
||||||
ASSERT_EQ(VPX_CODEC_ERROR,
|
ASSERT_EQ(VPX_CODEC_ERROR,
|
||||||
SetFrameBufferFunctions(
|
SetFrameBufferFunctions(
|
||||||
num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
|
num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(ExternalFrameBufferTest, InvalidAlignement) {
|
||||||
|
if (GET_PARAM(kCodedFrameBufferTypeParam) ==
|
||||||
|
VPX_CODEC_FRAME_BUFFER_TYPE_SIZE)
|
||||||
|
return;
|
||||||
|
const int num_buffers =
|
||||||
|
VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
|
||||||
|
ASSERT_EQ(VPX_CODEC_OK,
|
||||||
|
SetFrameBufferFunctions(
|
||||||
|
num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
|
||||||
|
SetBufferAlignment(15);
|
||||||
|
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames());
|
||||||
|
}
|
||||||
|
|
||||||
|
VP9_INSTANTIATE_TEST_CASE(ExternalFrameBufferTest,
|
||||||
|
::testing::Values(
|
||||||
|
VPX_CODEC_FRAME_BUFFER_TYPE_SIZE,
|
||||||
|
VPX_CODEC_FRAME_BUFFER_TYPE_PLANES));
|
||||||
|
|
||||||
#endif // CONFIG_WEBM_IO
|
#endif // CONFIG_WEBM_IO
|
||||||
|
|
||||||
VP9_INSTANTIATE_TEST_CASE(ExternalFrameBufferMD5Test,
|
VP9_INSTANTIATE_TEST_CASE(ExternalFrameBufferMD5Test,
|
||||||
|
::testing::Values(VPX_CODEC_FRAME_BUFFER_TYPE_SIZE,
|
||||||
|
VPX_CODEC_FRAME_BUFFER_TYPE_PLANES),
|
||||||
::testing::ValuesIn(libvpx_test::kVP9TestVectors,
|
::testing::ValuesIn(libvpx_test::kVP9TestVectors,
|
||||||
libvpx_test::kVP9TestVectors +
|
libvpx_test::kVP9TestVectors +
|
||||||
libvpx_test::kNumVP9TestVectors));
|
libvpx_test::kNumVP9TestVectors));
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "./vpx_image.h"
|
||||||
#include "./vpx_integer.h"
|
#include "./vpx_integer.h"
|
||||||
|
|
||||||
/*!\brief The maximum number of work buffers used by libvpx.
|
/*!\brief The maximum number of work buffers used by libvpx.
|
||||||
|
@ -32,24 +33,60 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
#define VP9_MAXIMUM_REF_BUFFERS 8
|
#define VP9_MAXIMUM_REF_BUFFERS 8
|
||||||
|
|
||||||
|
/*!\brief The maximum number of planes that can be allocated by an external
|
||||||
|
* frame buffer.
|
||||||
|
*/
|
||||||
|
#define VP9_MAXIMUM_EXTERNAL_PLANES 3
|
||||||
|
|
||||||
|
/*!\brief External frame buffer allocation type.
|
||||||
|
* This enum defines if the external frame buffer contains one allocation for
|
||||||
|
* all the planes contained in the frame buffer, or one allocation per plane.
|
||||||
|
*/
|
||||||
|
typedef enum vpx_codec_frame_buffer_type {
|
||||||
|
VPX_CODEC_FRAME_BUFFER_TYPE_SIZE = 1,
|
||||||
|
VPX_CODEC_FRAME_BUFFER_TYPE_PLANES = 2
|
||||||
|
} vpx_codec_frame_buffer_type_t;
|
||||||
|
|
||||||
/*!\brief External frame buffer
|
/*!\brief External frame buffer
|
||||||
*
|
*
|
||||||
* This structure holds allocated frame buffers used by the decoder.
|
* This structure holds allocated frame buffers used by the decoder.
|
||||||
*/
|
*/
|
||||||
typedef struct vpx_codec_frame_buffer {
|
typedef struct vpx_codec_frame_buffer {
|
||||||
|
vpx_img_fmt_t fmt; /**< Requested framebuffer format. */
|
||||||
|
size_t width; /**< Logical width of the frame. */
|
||||||
|
size_t height; /**< Logical height of the frame. */
|
||||||
|
|
||||||
|
/*! Whether data and size, or plane and stride should be used. */
|
||||||
|
vpx_codec_frame_buffer_type_t type;
|
||||||
|
|
||||||
uint8_t *data; /**< Pointer to the data buffer */
|
uint8_t *data; /**< Pointer to the data buffer */
|
||||||
size_t size; /**< Size of data in bytes */
|
size_t size; /**< Size of data in bytes */
|
||||||
|
|
||||||
|
/*! Pointers for each plane buffer */
|
||||||
|
uint8_t *plane[VP9_MAXIMUM_EXTERNAL_PLANES];
|
||||||
|
int stride[VP9_MAXIMUM_EXTERNAL_PLANES]; /**< Strides for each plane */
|
||||||
|
|
||||||
void *priv; /**< Frame's private data */
|
void *priv; /**< Frame's private data */
|
||||||
} vpx_codec_frame_buffer_t;
|
} vpx_codec_frame_buffer_t;
|
||||||
|
|
||||||
/*!\brief get frame buffer callback prototype
|
/*!\brief get frame buffer callback prototype
|
||||||
*
|
*
|
||||||
* This callback is invoked by the decoder to retrieve data for the frame
|
* This callback is invoked by the decoder to allocate storage for the frame
|
||||||
* buffer in order for the decode call to complete. The callback must
|
* buffer in order for the decode call to complete.
|
||||||
* allocate at least min_size in bytes and assign it to fb->data. The callback
|
* The callback can allocate one buffer for all the frame buffers, or one buffer
|
||||||
* must zero out all the data allocated. Then the callback must set fb->size
|
* per plane with the number and size of planes determined by fb->fmt.
|
||||||
* to the allocated size. The application does not need to align the allocated
|
* If the application decides to allocate only one buffer, fb->type must be set
|
||||||
* data. The callback is triggered when the decoder needs a frame buffer to
|
* to #VPX_CODEC_FRAME_BUFFER_SIZE, the buffer size must be at least |min_size|
|
||||||
|
* in bytes and the pointer to the buffer must be assigned to fb->data.
|
||||||
|
* Then the callback must set fb->size to the allocated size.
|
||||||
|
* The application does not need to align the allocated data.
|
||||||
|
* If the application decides to allocate one buffer per plane, fb->type must be
|
||||||
|
* set to #VPX_CODEC_FRAME_BUFFER_PLANES, the buffer pointers must be assigned
|
||||||
|
* to fb->plane, and their strides to fb->stride.
|
||||||
|
* The application provided buffers and strides must be aligned to 32 bytes.
|
||||||
|
* The callback must zero out all the buffers allocated.
|
||||||
|
*
|
||||||
|
* The callback is triggered when the decoder needs a frame buffer to
|
||||||
* decode a compressed image into. This function may be called more than once
|
* decode a compressed image into. This function may be called more than once
|
||||||
* for every call to vpx_codec_decode. The application may set fb->priv to
|
* for every call to vpx_codec_decode. The application may set fb->priv to
|
||||||
* some data which will be passed back in the ximage and the release function
|
* some data which will be passed back in the ximage and the release function
|
||||||
|
|
|
@ -178,23 +178,51 @@ int vpx_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
|
||||||
if (external_frame_size != (size_t)external_frame_size)
|
if (external_frame_size != (size_t)external_frame_size)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
fb->type = VPX_CODEC_FRAME_BUFFER_TYPE_SIZE;
|
||||||
|
if (ybf->subsampling_y) {
|
||||||
|
fb->fmt = ybf->subsampling_x ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_I440;
|
||||||
|
} else {
|
||||||
|
fb->fmt = ybf->subsampling_x ? VPX_IMG_FMT_I422 : VPX_IMG_FMT_I444;
|
||||||
|
}
|
||||||
|
fb->width = aligned_width + border * 2;
|
||||||
|
fb->height = aligned_height + border * 2;
|
||||||
|
|
||||||
// Allocation to hold larger frame, or first allocation.
|
// Allocation to hold larger frame, or first allocation.
|
||||||
if (cb(cb_priv, (size_t)external_frame_size, fb) < 0)
|
if (cb(cb_priv, (size_t)external_frame_size, fb) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (fb->data == NULL || fb->size < external_frame_size)
|
if (fb->type == VPX_CODEC_FRAME_BUFFER_TYPE_SIZE) {
|
||||||
return -1;
|
if (fb->data == NULL || fb->size < external_frame_size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
ybf->buffer_alloc = (uint8_t *)yv12_align_addr(fb->data, 32);
|
ybf->buffer_alloc = (uint8_t *)yv12_align_addr(fb->data, 32);
|
||||||
|
|
||||||
#if defined(__has_feature)
|
#if defined(__has_feature)
|
||||||
#if __has_feature(memory_sanitizer)
|
#if __has_feature(memory_sanitizer)
|
||||||
// This memset is needed for fixing the issue of using uninitialized
|
// This memset is needed for fixing the issue of using uninitialized
|
||||||
// value in msan test. It will cause a perf loss, so only do this for
|
// value in msan test. It will cause a perf loss, so only do this for
|
||||||
// msan test.
|
// msan test.
|
||||||
memset(ybf->buffer_alloc, 0, (int)frame_size);
|
memset(ybf->buffer_alloc, 0, (int)frame_size);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
} else { // VPX_CODEC_FRAME_BUFFER_TYPE_PLANES
|
||||||
|
if (fb->plane[0] == NULL || fb->plane[1] == NULL ||
|
||||||
|
fb->plane[2] == NULL || !fb->stride[0] || !fb->stride[1] ||
|
||||||
|
!fb->stride[2])
|
||||||
|
return -1;
|
||||||
|
// buffers should be 32 bytes aligned.
|
||||||
|
if ((fb->stride[0] & 0x1f) || (fb->stride[1] & 0x1f))
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
if (fb->stride[1] != fb->stride[2])
|
||||||
|
return -3;
|
||||||
|
ybf->y_stride = fb->stride[0];
|
||||||
|
ybf->uv_stride = fb->stride[1];
|
||||||
|
|
||||||
|
ybf->y_buffer = fb->plane[0];
|
||||||
|
ybf->u_buffer = fb->plane[1];
|
||||||
|
ybf->v_buffer = fb->plane[2];
|
||||||
|
}
|
||||||
} else if (frame_size > (size_t)ybf->buffer_alloc_sz) {
|
} else if (frame_size > (size_t)ybf->buffer_alloc_sz) {
|
||||||
// Allocation to hold larger frame, or first allocation.
|
// Allocation to hold larger frame, or first allocation.
|
||||||
vpx_free(ybf->buffer_alloc);
|
vpx_free(ybf->buffer_alloc);
|
||||||
|
@ -227,13 +255,11 @@ int vpx_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
|
||||||
ybf->y_crop_height = height;
|
ybf->y_crop_height = height;
|
||||||
ybf->y_width = aligned_width;
|
ybf->y_width = aligned_width;
|
||||||
ybf->y_height = aligned_height;
|
ybf->y_height = aligned_height;
|
||||||
ybf->y_stride = y_stride;
|
|
||||||
|
|
||||||
ybf->uv_crop_width = (width + ss_x) >> ss_x;
|
ybf->uv_crop_width = (width + ss_x) >> ss_x;
|
||||||
ybf->uv_crop_height = (height + ss_y) >> ss_y;
|
ybf->uv_crop_height = (height + ss_y) >> ss_y;
|
||||||
ybf->uv_width = uv_width;
|
ybf->uv_width = uv_width;
|
||||||
ybf->uv_height = uv_height;
|
ybf->uv_height = uv_height;
|
||||||
ybf->uv_stride = uv_stride;
|
|
||||||
|
|
||||||
ybf->border = border;
|
ybf->border = border;
|
||||||
ybf->frame_size = (int)frame_size;
|
ybf->frame_size = (int)frame_size;
|
||||||
|
@ -241,24 +267,28 @@ int vpx_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
|
||||||
ybf->subsampling_y = ss_y;
|
ybf->subsampling_y = ss_y;
|
||||||
|
|
||||||
buf = ybf->buffer_alloc;
|
buf = ybf->buffer_alloc;
|
||||||
|
if (buf != NULL) {
|
||||||
|
ybf->y_stride = y_stride;
|
||||||
|
ybf->uv_stride = uv_stride;
|
||||||
#if CONFIG_VP9_HIGHBITDEPTH
|
#if CONFIG_VP9_HIGHBITDEPTH
|
||||||
if (use_highbitdepth) {
|
if (use_highbitdepth) {
|
||||||
// Store uint16 addresses when using 16bit framebuffers
|
// Store uint16 addresses when using 16bit framebuffers
|
||||||
buf = CONVERT_TO_BYTEPTR(ybf->buffer_alloc);
|
buf = CONVERT_TO_BYTEPTR(ybf->buffer_alloc);
|
||||||
ybf->flags = YV12_FLAG_HIGHBITDEPTH;
|
ybf->flags = YV12_FLAG_HIGHBITDEPTH;
|
||||||
} else {
|
} else {
|
||||||
ybf->flags = 0;
|
ybf->flags = 0;
|
||||||
}
|
}
|
||||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||||
|
|
||||||
ybf->y_buffer = (uint8_t *)yv12_align_addr(
|
ybf->y_buffer = (uint8_t *)yv12_align_addr(
|
||||||
buf + (border * y_stride) + border, vp9_byte_align);
|
buf + (border * y_stride) + border, vp9_byte_align);
|
||||||
ybf->u_buffer = (uint8_t *)yv12_align_addr(
|
ybf->u_buffer = (uint8_t *)yv12_align_addr(
|
||||||
buf + yplane_size + (uv_border_h * uv_stride) + uv_border_w,
|
buf + yplane_size + (uv_border_h * uv_stride) + uv_border_w,
|
||||||
vp9_byte_align);
|
vp9_byte_align);
|
||||||
ybf->v_buffer = (uint8_t *)yv12_align_addr(
|
ybf->v_buffer = (uint8_t *)yv12_align_addr(
|
||||||
buf + yplane_size + uvplane_size + (uv_border_h * uv_stride) +
|
buf + yplane_size + uvplane_size + (uv_border_h * uv_stride) +
|
||||||
uv_border_w, vp9_byte_align);
|
uv_border_w, vp9_byte_align);
|
||||||
|
}
|
||||||
|
|
||||||
ybf->corrupted = 0; /* assume not corrupted by errors */
|
ybf->corrupted = 0; /* assume not corrupted by errors */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче