Add JPEG encode tests that encode raw I420 and NV12 data at quality 100 and then decodes them to verify proper encoding.
Currently, the 7680x4320 I420 test fails because ~40-60 Y-values (i.e. plane 0) in each line from the decoded bitstream are off by more than 2 of the original raw I420 values. It is not clear why only this resolution exhibits this problem. Signed-off-by: U. Artie Eoff <ullysses.a.e...@intel.com> --- test/Makefile.am | 1 + test/i965_jpeg_encode_test.cpp | 694 +++++++++++++++++++++++++++++++++++++++++ test/i965_jpeg_test_data.h | 198 +++++++++++- test/i965_test_fixture.h | 1 + 4 files changed, 890 insertions(+), 4 deletions(-) create mode 100644 test/i965_jpeg_encode_test.cpp diff --git a/test/Makefile.am b/test/Makefile.am index 2e9edda648a4..99560f8d8a54 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -57,6 +57,7 @@ test_i965_drv_video_SOURCES = \ i965_jpeg_test_data.cpp \ i965_test_fixture.cpp \ i965_jpeg_decode_test.cpp \ + i965_jpeg_encode_test.cpp \ object_heap_test.cpp \ test_main.cpp \ $(NULL) diff --git a/test/i965_jpeg_encode_test.cpp b/test/i965_jpeg_encode_test.cpp new file mode 100644 index 000000000000..b10c8ef74ec7 --- /dev/null +++ b/test/i965_jpeg_encode_test.cpp @@ -0,0 +1,694 @@ +/* + * Copyright (C) 2016 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "i965_jpeg_test_data.h" +#include "test_utils.h" + +#include <algorithm> +#include <cstring> +#include <fstream> +#include <memory> +#include <sstream> +#include <tuple> + +namespace JPEG { +namespace Encode { + +class JPEGEncodeTest + : public I965TestFixture +{ +public: + JPEGEncodeTest() + : I965TestFixture() + , config(VA_INVALID_ID) // invalid + , context(VA_INVALID_ID) // invalid + { } + +protected: + virtual void TearDown() + { + if (context != VA_INVALID_ID) { + destroyContext(context); + context = VA_INVALID_ID; + } + + if (config != VA_INVALID_ID) { + destroyConfig(config); + config = VA_INVALID_ID; + } + + I965TestFixture::TearDown(); + } + + VAConfigID config; + VAContextID context; +}; + +TEST_F(JPEGEncodeTest, Entrypoint) +{ + ConfigAttribs attributes; + struct i965_driver_data *i965(*this); + + ASSERT_PTR(i965); + + if (HAS_JPEG_ENCODING(i965)) { + config = createConfig(profile, entrypoint, attributes); + } else { + VAStatus status = i965_CreateConfig( + *this, profile, entrypoint, attributes.data(), attributes.size(), + &config); + EXPECT_STATUS_EQ(VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT, status); + EXPECT_INVALID_ID(config); + } +} + +class TestInputCreator +{ +public: + typedef std::shared_ptr<TestInputCreator> Shared; + typedef std::shared_ptr<const TestInputCreator> SharedConst; + + TestInput::Shared create(const unsigned fourcc) const + { + const std::array<unsigned, 2> res = getResolution(); + + TestInput::Shared input(new TestInput(fourcc, res[0], res[1])); + ByteData& bytes = input->bytes; + + RandomValueGenerator<uint8_t> rg(0x00, 0xff); + for (size_t i(0); i < input->planes; ++i) + std::generate_n( + std::back_inserter(bytes), input->sizes[i], + [&rg]{ return rg(); }); + return input; + } + + friend ::std::ostream& operator<<( + ::std::ostream& os, const TestInputCreator& t) + { + t.repr(os); + return os; + } + + friend ::std::ostream& operator<<( + ::std::ostream& os, const TestInputCreator::Shared& t) + { + return os << *t; + } + + friend ::std::ostream& operator<<( + ::std::ostream& os, const TestInputCreator::SharedConst& t) + { + return os << *t; + } + +protected: + virtual std::array<unsigned, 2> getResolution() const = 0; + virtual void repr(std::ostream& os) const = 0; +}; + +template <typename T> +const std::string toString(const T& t) +{ + std::ostringstream os; + os << t; + return os.str(); +} + +const TestInput::Shared NV12toI420(const TestInput::SharedConst& nv12) +{ + TestInput::Shared i420( + new TestInput(VA_FOURCC_I420, nv12->width(), nv12->height())); + + i420->bytes = nv12->bytes; + + size_t i(0); + auto predicate = [&i](const ByteData::value_type&) { + bool isu = ((i % 2) == 0) or (i == 0); + ++i; + return isu; + }; + + std::stable_partition( + i420->bytes.begin() + i420->offsets[1], + i420->bytes.end(), predicate); + + return i420; +} + +#define ASSERT_NO_FAILURE(statement) \ + statement; \ + ASSERT_FALSE(HasFailure()); + +class JPEGEncodeInputTest + : public JPEGEncodeTest + , public ::testing::WithParamInterface< + std::tuple<TestInputCreator::SharedConst, const char*> > +{ +public: + JPEGEncodeInputTest() + : JPEGEncodeTest::JPEGEncodeTest() + , surfaces() // empty + , coded(VA_INVALID_ID) // invalid + , renderBuffers() // empty + , input() // invalid + , output() // empty + { } + +protected: + virtual void SetUp() + { + JPEGEncodeTest::SetUp(); + + TestInputCreator::SharedConst creator; + std::string sFourcc; + std::tie(creator, sFourcc) = GetParam(); + + ASSERT_PTR(creator.get()) << "Invalid test input creator parameter"; + + ASSERT_EQ(4u, sFourcc.size()) + << "Invalid fourcc parameter '" << sFourcc << "'"; + + unsigned fourcc = VA_FOURCC( + sFourcc[0], sFourcc[1], sFourcc[2], sFourcc[3]); + + input = creator->create(fourcc); + + ASSERT_PTR(input.get()) + << "Unhandled fourcc parameter '" << sFourcc << "'" + << " = 0x" << std::hex << fourcc << std::dec; + + ASSERT_EQ(fourcc, input->fourcc); + + RecordProperty("test_input", toString(*input)); + } + + virtual void TearDown() + { + for (auto id : renderBuffers) { + if (id != VA_INVALID_ID) { + destroyBuffer(id); + } + } + renderBuffers.clear(); + + if (coded != VA_INVALID_ID) { + destroyBuffer(coded); + coded = VA_INVALID_ID; + } + + if (not surfaces.empty()) { + destroySurfaces(surfaces); + surfaces.clear(); + } + + if (std::get<0>(GetParam()).get()) + std::cout << "Creator: " << std::get<0>(GetParam()) << std::endl; + if (input.get()) + std::cout << "Input : " << input << std::endl; + + JPEGEncodeTest::TearDown(); + } + + void Encode() + { + ASSERT_FALSE(surfaces.empty()); + + ASSERT_NO_FAILURE( + beginPicture(context, surfaces.front())); + ASSERT_NO_FAILURE( + renderPicture(context, renderBuffers.data(), renderBuffers.size())); + ASSERT_NO_FAILURE( + endPicture(context)); + ASSERT_NO_FAILURE( + syncSurface(surfaces.front())); + ASSERT_NO_FAILURE( + VACodedBufferSegment *segment = + mapBuffer<VACodedBufferSegment>(coded)); + + EXPECT_FALSE(segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) + << "segment->size = " << segment->size; + EXPECT_PTR_NULL(segment->next); + + // copy segment buffer to output while stripping the packed header data + const size_t headerSize(1); + output.resize(segment->size - headerSize, 0x0); + std::memcpy( + output.data(), + reinterpret_cast<uint8_t *>(segment->buf) + headerSize, + segment->size - headerSize); + + unmapBuffer(coded); + + // EOI JPEG Marker + ASSERT_GE(output.size(), 2u); + EXPECT_TRUE( + unsigned(0xff) == unsigned(*(output.end() - 2)) and + unsigned(0xd9) == unsigned(output.back())) + << "Invalid JPEG EOI Marker"; + } + + void SetUpSurfaces() + { + SurfaceAttribs attributes(1); + attributes.front().flags = VA_SURFACE_ATTRIB_SETTABLE; + attributes.front().type = VASurfaceAttribPixelFormat; + attributes.front().value.type = VAGenericValueTypeInteger; + attributes.front().value.value.i = input->fourcc; + surfaces = createSurfaces(input->width(), input->height(), + input->format, 1, attributes); + } + + void CopyInputToSurface() + { + ASSERT_FALSE(surfaces.empty()); + + VAImage image; + deriveImage(surfaces.front(), image); + if (HasFailure()) + return; + + SCOPED_TRACE(::testing::Message() << std::endl << image); + + RecordProperty("input_image", toString(image)); + + EXPECT_EQ(input->planes, image.num_planes); + EXPECT_GT(image.data_size, 0u); + EXPECT_EQ(input->width(), image.width); + EXPECT_EQ(input->height(), image.height); + if (HasFailure()) { + unmapBuffer(image.buf); + destroyImage(image); + return; + } + + uint8_t *data = mapBuffer<uint8_t>(image.buf); + if (HasFailure()) { + destroyImage(image); + return; + } + + std::memset(data, 0, image.data_size); + + for (size_t i(0); i < image.num_planes; ++i) { + size_t w = input->widths[i]; + size_t h = input->heights[i]; + + EXPECT_GE(image.pitches[i], w); + if (HasFailure()) + break; + + const ByteData::value_type *source = input->plane(i); + uint8_t *dest = data + image.offsets[i]; + for (size_t r(0); r < h; ++r) { + std::memcpy(dest, source, w); + source += w; + dest += image.pitches[i]; + } + } + + unmapBuffer(image.buf); + destroyImage(image); + } + + void SetUpConfig() + { + ASSERT_INVALID_ID(config); + ConfigAttribs attributes( + 1, {type:VAConfigAttribRTFormat, value:input->format}); + config = createConfig(profile, entrypoint, attributes); + } + + void SetUpContext() + { + ASSERT_INVALID_ID(context); + context = createContext(config, input->width(), + input->height(), 0, surfaces); + } + + void SetUpCodedBuffer() + { + ASSERT_INVALID_ID(coded); + unsigned size = + std::accumulate(input->sizes.begin(), input->sizes.end(), 8192u); + size *= input->planes; + coded = createBuffer(context, VAEncCodedBufferType, size); + } + + void SetUpPicture() + { + input->picture.coded_buf = coded; + renderBuffers.push_back( + createBuffer(context, VAEncPictureParameterBufferType, + sizeof(PictureParameter), 1, &input->picture)); + } + + void SetUpIQMatrix() + { + renderBuffers.push_back( + createBuffer(context, VAQMatrixBufferType, sizeof(IQMatrix), + 1, &input->matrix)); + } + + void SetUpHuffmanTables() + { + renderBuffers.push_back( + createBuffer(context, VAHuffmanTableBufferType, + sizeof(HuffmanTable), 1, &input->huffman)); + } + + void SetUpSlice() + { + renderBuffers.push_back( + createBuffer(context, VAEncSliceParameterBufferType, + sizeof(SliceParameter), 1, &input->slice)); + } + + void SetUpHeader() + { + /* + * The driver expects a packed JPEG header which it prepends to the + * coded buffer segment output. The driver does not appear to inspect + * this header, however. So we'll just create a 1-byte packed header + * since we really don't care if it contains a "valid" JPEG header. + */ + renderBuffers.push_back( + createBuffer(context, VAEncPackedHeaderParameterBufferType, + sizeof(VAEncPackedHeaderParameterBuffer))); + if (HasFailure()) + return; + + VAEncPackedHeaderParameterBuffer *packed = + mapBuffer<VAEncPackedHeaderParameterBuffer>(renderBuffers.back()); + if (HasFailure()) + return; + + std::memset(packed, 0, sizeof(*packed)); + packed->type = VAEncPackedHeaderRawData; + packed->bit_length = 8; + packed->has_emulation_bytes = 0; + + unmapBuffer(renderBuffers.back()); + + renderBuffers.push_back( + createBuffer(context, VAEncPackedHeaderDataBufferType, 1)); + } + + Surfaces surfaces; + VABufferID coded; + Buffers renderBuffers; + TestInput::Shared input; + ByteData output; + + void VerifyOutput() + { + // VerifyOutput only supports VA_FOURCC_IMC3 output, currently + ASSERT_EQ(unsigned(VA_FOURCC_IMC3), input->fourcc_output); + TestInput::SharedConst expect = input; + if (input->fourcc == VA_FOURCC_NV12) + expect = NV12toI420(input); + + ::JPEG::Decode::PictureData::SharedConst pd = + ::JPEG::Decode::PictureData::make( + input->fourcc_output, output, input->width(), input->height()); + + ASSERT_NO_FAILURE( + Surfaces osurfaces = createSurfaces( + pd->pparam.picture_width, pd->pparam.picture_height, + pd->format));; + + ConfigAttribs attribs( + 1, {type:VAConfigAttribRTFormat, value:pd->format}); + ASSERT_NO_FAILURE( + VAConfigID oconfig = createConfig( + ::JPEG::profile, ::JPEG::Decode::entrypoint, attribs)); + + ASSERT_NO_FAILURE( + VAContextID ocontext = createContext( + oconfig, pd->pparam.picture_width, pd->pparam.picture_height, + 0, osurfaces)); + + Buffers buffers; + + ASSERT_NO_FAILURE( + buffers.push_back( + createBuffer( + ocontext, VASliceDataBufferType, pd->sparam.slice_data_size, + 1, pd->slice.data()))); + + ASSERT_NO_FAILURE( + buffers.push_back( + createBuffer( + ocontext, VASliceParameterBufferType, sizeof(pd->sparam), + 1, &pd->sparam))); + + ASSERT_NO_FAILURE( + buffers.push_back( + createBuffer( + ocontext,VAPictureParameterBufferType, sizeof(pd->pparam), + 1, &pd->pparam))); + + ASSERT_NO_FAILURE( + buffers.push_back( + createBuffer( + ocontext, VAIQMatrixBufferType, sizeof(pd->iqmatrix), + 1, &pd->iqmatrix))); + + ASSERT_NO_FAILURE( + buffers.push_back( + createBuffer( + ocontext, VAHuffmanTableBufferType, sizeof(pd->huffman), + 1, &pd->huffman))); + + ASSERT_NO_FAILURE(beginPicture(ocontext, osurfaces.front())); + ASSERT_NO_FAILURE( + renderPicture(ocontext, buffers.data(), buffers.size())); + ASSERT_NO_FAILURE(endPicture(ocontext)); + ASSERT_NO_FAILURE(syncSurface(osurfaces.front())); + + VAImage image; + ASSERT_NO_FAILURE(deriveImage(osurfaces.front(), image)); + ASSERT_NO_FAILURE(uint8_t *data = mapBuffer<uint8_t>(image.buf)); + + auto isClose = [](const uint8_t& a, const uint8_t& b) { + return std::abs(int(a)-int(b)) <= 2; + }; + + for (size_t i(0); i < image.num_planes; ++i) { + size_t w = expect->widths[i]; + size_t h = expect->heights[i]; + + const ByteData::value_type *source = expect->plane(i); + const uint8_t *result = data + image.offsets[i]; + ASSERT_GE(image.pitches[i], w); + for (size_t r(0); r < h; ++r) { + EXPECT_TRUE(std::equal(result, result + w, source, isClose)) + << "Byte(s) mismatch in plane " << i << " row " << r; + source += w; + result += image.pitches[i]; + } + } + + unmapBuffer(image.buf); + + for (auto id : buffers) + destroyBuffer(id); + + destroyImage(image); + destroyContext(ocontext); + destroyConfig(oconfig); + destroySurfaces(osurfaces); + } +}; + +TEST_P(JPEGEncodeInputTest, Full) +{ + struct i965_driver_data *i965(*this); + ASSERT_PTR(i965); + if (not HAS_JPEG_ENCODING(i965)) { + RecordProperty("skipped", true); + std::cout << "[ SKIPPED ] " << getFullTestName() + << " is unsupported on this hardware" << std::endl; + return; + } + + ASSERT_NO_FAILURE(SetUpSurfaces()); + ASSERT_NO_FAILURE(SetUpConfig()); + ASSERT_NO_FAILURE(SetUpContext()); + ASSERT_NO_FAILURE(SetUpCodedBuffer()); + ASSERT_NO_FAILURE(SetUpPicture()); + ASSERT_NO_FAILURE(SetUpIQMatrix()); + ASSERT_NO_FAILURE(SetUpHuffmanTables()); + ASSERT_NO_FAILURE(SetUpSlice()); + ASSERT_NO_FAILURE(SetUpHeader()); + ASSERT_NO_FAILURE(CopyInputToSurface()); + ASSERT_NO_FAILURE(Encode()); + + VerifyOutput(); +} + +class RandomSizeCreator + : public TestInputCreator +{ +protected: + std::array<unsigned, 2> getResolution() const + { + static RandomValueGenerator<unsigned> rg(1, 769); + return {rg(), rg()}; + } + void repr(std::ostream& os) const { os << "Random Size"; } +}; + +INSTANTIATE_TEST_CASE_P( + Random, JPEGEncodeInputTest, + ::testing::Combine( + ::testing::ValuesIn( + std::vector<TestInputCreator::SharedConst>( + 5, TestInputCreator::SharedConst(new RandomSizeCreator))), + ::testing::Values("I420", "NV12") + ) +); + +class FixedSizeCreator + : public TestInputCreator +{ +public: + FixedSizeCreator(const std::array<unsigned, 2>& resolution) + : res(resolution) + { } + +protected: + std::array<unsigned, 2> getResolution() const { return res; } + void repr(std::ostream& os) const + { + os << "Fixed Size " << res[0] << "x" << res[1]; + } + +private: + const std::array<unsigned, 2> res; +}; + +typedef std::vector<TestInputCreator::SharedConst> InputCreators; + +InputCreators generateCommonInputs() +{ + return { + TestInputCreator::Shared(new FixedSizeCreator({800, 600})), /* SVGA */ + TestInputCreator::Shared(new FixedSizeCreator({1024, 600})), /* WSVGA */ + TestInputCreator::Shared(new FixedSizeCreator({1024, 768})), /* XGA */ + TestInputCreator::Shared(new FixedSizeCreator({1152, 864})), /* XGA+ */ + TestInputCreator::Shared(new FixedSizeCreator({1280, 720})), /* WXGA */ + TestInputCreator::Shared(new FixedSizeCreator({1280, 768})), /* WXGA */ + TestInputCreator::Shared(new FixedSizeCreator({1280, 800})), /* WXGA */ + TestInputCreator::Shared(new FixedSizeCreator({1280, 1024})), /* SXGA */ + TestInputCreator::Shared(new FixedSizeCreator({1360, 768})), /* HD */ + TestInputCreator::Shared(new FixedSizeCreator({1366, 768})), /* HD */ + TestInputCreator::Shared(new FixedSizeCreator({1440, 900})), /* WXGA+ */ + TestInputCreator::Shared(new FixedSizeCreator({1600, 900})), /* HD+ */ + TestInputCreator::Shared(new FixedSizeCreator({1600, 1200})), /* UXGA */ + TestInputCreator::Shared(new FixedSizeCreator({1680, 1050})), /* WSXGA+ */ + TestInputCreator::Shared(new FixedSizeCreator({1920, 1080})), /* FHD */ + TestInputCreator::Shared(new FixedSizeCreator({1920, 1200})), /* WUXGA */ + TestInputCreator::Shared(new FixedSizeCreator({2560, 1440})), /* WQHD */ + TestInputCreator::Shared(new FixedSizeCreator({2560, 1600})), /* WQXGA */ + TestInputCreator::Shared(new FixedSizeCreator({3640, 2160})), /* UHD (4K) */ + TestInputCreator::Shared(new FixedSizeCreator({7680, 4320})), /* UHD (8K) */ + }; +} + +INSTANTIATE_TEST_CASE_P( + Common, JPEGEncodeInputTest, + ::testing::Combine( + ::testing::ValuesIn(generateCommonInputs()), + ::testing::Values("I420", "NV12") + ) +); + +INSTANTIATE_TEST_CASE_P( + Big, JPEGEncodeInputTest, + ::testing::Combine( + ::testing::Values( + TestInputCreator::Shared(new FixedSizeCreator({8192, 8192})) + ), + ::testing::Values("I420", "NV12") + ) +); + +InputCreators generateEdgeCaseInputs() +{ + std::vector<TestInputCreator::SharedConst> result; + for (unsigned i(64); i <= 512; i += 64) { + result.push_back( + TestInputCreator::Shared(new FixedSizeCreator({i, i}))); + result.push_back( + TestInputCreator::Shared(new FixedSizeCreator({i+1, i}))); + result.push_back( + TestInputCreator::Shared(new FixedSizeCreator({i, i+1}))); + result.push_back( + TestInputCreator::Shared(new FixedSizeCreator({i+1, i+1}))); + result.push_back( + TestInputCreator::Shared(new FixedSizeCreator({i-1, i}))); + result.push_back( + TestInputCreator::Shared(new FixedSizeCreator({i, i-1}))); + result.push_back( + TestInputCreator::Shared(new FixedSizeCreator({i-1, i-1}))); + } + + result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 1}))); + result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 2}))); + result.push_back(TestInputCreator::Shared(new FixedSizeCreator({2, 1}))); + result.push_back(TestInputCreator::Shared(new FixedSizeCreator({2, 2}))); + result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 462}))); + + return result; +} + +INSTANTIATE_TEST_CASE_P( + Edge, JPEGEncodeInputTest, + ::testing::Combine( + ::testing::ValuesIn(generateEdgeCaseInputs()), + ::testing::Values("I420", "NV12") + ) +); + +InputCreators generateMiscInputs() +{ + return { + TestInputCreator::Shared(new FixedSizeCreator({150, 75})), + TestInputCreator::Shared(new FixedSizeCreator({10, 10})), + TestInputCreator::Shared(new FixedSizeCreator({385, 610})), + TestInputCreator::Shared(new FixedSizeCreator({1245, 1281})), + }; +} + +INSTANTIATE_TEST_CASE_P( + Misc, JPEGEncodeInputTest, + ::testing::Combine( + ::testing::ValuesIn(generateMiscInputs()), + ::testing::Values("I420", "NV12") + ) +); + +} // namespace Encode +} // namespace JPEG diff --git a/test/i965_jpeg_test_data.h b/test/i965_jpeg_test_data.h index d52f58233cc5..490ec941feb5 100644 --- a/test/i965_jpeg_test_data.h +++ b/test/i965_jpeg_test_data.h @@ -25,6 +25,8 @@ #ifndef I965_JPEG_TEST_DATA_H #define I965_JPEG_TEST_DATA_H +#include "i965_test_fixture.h" + #include <array> #include <iostream> #include <map> @@ -183,6 +185,18 @@ namespace Decode { const HuffmanTable& huffman = defaultHuffmanTable, const IQMatrix& iqmatrix = defaultIQMatrix) { + return make(fourcc, slice, W, H, sparam, pparam, huffman, iqmatrix); + } + + static SharedConst make( + const unsigned fourcc, + const ByteData& slice, + const unsigned w, const unsigned h, + const SliceParameter& sparam = defaultSliceParameter, + const PictureParameter& pparam = defaultPictureParameter, + const HuffmanTable& huffman = defaultHuffmanTable, + const IQMatrix& iqmatrix = defaultIQMatrix) + { Shared pd( new PictureData { slice: slice, @@ -196,8 +210,8 @@ namespace Decode { ); pd->sparam.slice_data_size = slice.size(); - pd->pparam.picture_width = W; - pd->pparam.picture_height = H; + pd->pparam.picture_width = w; + pd->pparam.picture_height = h; switch(fourcc) { @@ -232,8 +246,8 @@ namespace Decode { /* Calculate num_mcus */ int hfactor = pd->pparam.components[0].h_sampling_factor << 3; int vfactor = pd->pparam.components[0].v_sampling_factor << 3; - int wmcu = (W + hfactor - 1) / hfactor; - int hmcu = (H + vfactor - 1) / vfactor; + int wmcu = (w + hfactor - 1) / hfactor; + int hmcu = (h + vfactor - 1) / vfactor; pd->sparam.num_mcus = wmcu * hmcu; return pd; @@ -321,4 +335,180 @@ namespace Decode { } // namespace Decode } // namespace JPEG +namespace JPEG { +namespace Encode { + typedef VAQMatrixBufferJPEG IQMatrix; + typedef VAHuffmanTableBufferJPEGBaseline HuffmanTable; + typedef VAEncPictureParameterBufferJPEG PictureParameter; + typedef VAEncSliceParameterBufferJPEG SliceParameter; + + static const VAEntrypoint entrypoint = VAEntrypointEncPicture; + + static const IQMatrix defaultIQMatrix = { /* Quality 50 */ + load_lum_quantiser_matrix: 1, + load_chroma_quantiser_matrix: 1, + lum_quantiser_matrix: { + 0x10,0x0b,0x0c,0x0e,0x0c,0x0a,0x10,0x0e, + 0x0d,0x0e,0x12,0x11,0x10,0x13,0x18,0x28, + 0x1a,0x18,0x16,0x16,0x18,0x31,0x23,0x25, + 0x1d,0x28,0x3a,0x33,0x3d,0x3c,0x39,0x33, + 0x38,0x37,0x40,0x48,0x5c,0x4e,0x40,0x44, + 0x57,0x45,0x37,0x38,0x50,0x6d,0x51,0x57, + 0x5f,0x62,0x67,0x68,0x67,0x3e,0x4d,0x71, + 0x79,0x70,0x64,0x78,0x5c,0x65,0x67,0x63, + }, + chroma_quantiser_matrix: { + 0x11,0x12,0x12,0x18,0x15,0x18,0x2f,0x1a, + 0x1a,0x2f,0x63,0x42,0x38,0x42,0x63,0x63, + 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, + 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, + 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, + 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, + 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, + 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, + }, + }; + + static const HuffmanTable defaultHuffmanTable = + ::JPEG::Decode::defaultHuffmanTable; + + static const PictureParameter defaultPictureParameter = { + reconstructed_picture: VA_INVALID_ID, + picture_width: 10, + picture_height: 10, + coded_buf: VA_INVALID_ID, + pic_flags: {value: 0x00100}, + sample_bit_depth: 8, + num_scan: 1, + num_components: 3, + component_id: {0, 1, 2, 0}, + quantiser_table_selector: {0, 1, 1, 0}, + quality: 100, + }; + + static const SliceParameter defaultSliceParameter = { + restart_interval: 0, + num_components: 3, + /* component_selector, dc_table_selector, ac_table_selector */ + components: {{1,0,0},{2,1,1},{3,1,1}}, + }; + + class TestInput + { + public: + typedef std::shared_ptr<TestInput> Shared; + typedef std::shared_ptr<TestInput> SharedConst; + + TestInput(const unsigned fourcc, const unsigned w, const unsigned h) + : bytes() // caller must fill this in after instantiation + , picture(defaultPictureParameter) + , matrix(defaultIQMatrix) + , huffman(defaultHuffmanTable) + , slice(defaultSliceParameter) + , fourcc(fourcc) + , fourcc_output(fourcc) + , format(0) + , planes(0) + , widths{0,0,0} + , heights{0,0,0} + , offsets{0,0,0} + , sizes{0,0,0} + { + picture.picture_width = ALIGN(w,2); + picture.picture_height = ALIGN(h,2); + + switch(fourcc) { + case VA_FOURCC('I', '4', '2', '0'): + planes = 3; + widths = { + w +( w & 1), + (w + 1) >> 1, + (w + 1) >> 1 + }; + heights = { + h + (h & 1), + (h + 1) >> 1, + (h + 1) >> 1 + }; + format = VA_RT_FORMAT_YUV420; + fourcc_output = VA_FOURCC_IMC3; + break; + case VA_FOURCC_NV12: + planes = 2; + widths = { + w + (w & 1), + w + (w & 1), + 0 + }; + heights = { + h + (h & 1), + (h + 1) >> 1, + 0 + }; + format = VA_RT_FORMAT_YUV420; + fourcc_output = VA_FOURCC_IMC3; + break; + default: + return; + } + + for (size_t i(0); i < planes; ++i) { + sizes[i] = widths[i] * heights[i]; + } + + for (size_t i(1); i < planes; ++i) { + offsets[i] = sizes[i - 1]; + offsets[i] += offsets[i - 1]; + } + } + + const unsigned width() const + { + return picture.picture_width; + } + + const unsigned height() const + { + return picture.picture_height; + } + + const uint8_t* plane(const size_t i) const + { + return bytes.data() + offsets[i]; + } + + friend ::std::ostream& operator<<(::std::ostream& os, const TestInput& t) + { + return os + << std::string((char*)(&t.fourcc), 4) + << " " << t.width() << "x" << t.height() + << " " << t.widths << " " << t.heights + << " " << t.sizes << " " << t.offsets + ; + } + + friend ::std::ostream& operator<<(::std::ostream& os, const Shared& t) + { + return os << *t; + } + + ByteData bytes; + PictureParameter picture; + IQMatrix matrix; + HuffmanTable huffman; + SliceParameter slice; + unsigned fourcc; + unsigned fourcc_output; + unsigned format; + size_t planes; + std::array<size_t, 3> widths; + std::array<size_t, 3> heights; + std::array<size_t, 3> offsets; + std::array<size_t, 3> sizes; + }; + + +} // namespace Encode +} // namespace JPEG + #endif diff --git a/test/i965_test_fixture.h b/test/i965_test_fixture.h index 54d85d223789..c805b359e19f 100644 --- a/test/i965_test_fixture.h +++ b/test/i965_test_fixture.h @@ -35,6 +35,7 @@ typedef std::vector<VASurfaceID> Surfaces; typedef std::vector<VASurfaceAttrib> SurfaceAttribs; typedef std::vector<VAConfigAttrib> ConfigAttribs; +typedef std::vector<VABufferID> Buffers; /** * This test fixture handles initialization and termination of the i965 driver -- 2.4.11 _______________________________________________ Libva mailing list Libva@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libva