Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unittest: pass Non IDR frame to decode after flush #6

Open
wants to merge 3 commits into
base: zero_copy
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 99 additions & 30 deletions decoder/DecoderApi_unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ static FrameData g_vp8data[] = {
g_EOF,
};


static FrameData g_mpeg2data[] = {
g_mpeg2_8x8I1,
g_mpeg2_8x8P,
g_mpeg2_8x8I2,
g_mpeg2_8x8I1,
g_mpeg2_8x8P,
g_mpeg2_8x8I2,
g_EOF,
};

class TestDecodeFrames {
public:
typedef SharedPtr<TestDecodeFrames> Shared;
Expand Down Expand Up @@ -264,6 +275,42 @@ TEST_P(DecodeApiTest, Format_Change)
EXPECT_EQ(inFrames, outFrames);
}

void decodeAndOutput(SharedPtr<IVideoDecoder> decoder, DecodeSurfaceAllocator *allocator, TestDecodeFrames& frames,
int begin, int end, int64_t& timeBeforeFlush, int64_t& timeCurrent, bool isFlushed, int& inFrames, int& outFrames)
{
VideoDecodeBuffer buffer;
FrameInfo info;
SharedPtr<VideoFrame> output;

for (int j = begin; j < end; j++) {
if (!frames.getFrame(buffer, info))
break;

buffer.timeStamp = timeCurrent;
timeCurrent++;
YamiStatus status = decoder->decode(&buffer);
while ((output = decoder->getOutput())) {
outFrames ++;
if (isFlushed) {
EXPECT_TRUE(output->timeStamp > timeBeforeFlush);
}
}

if (status == YAMI_DECODE_FORMAT_CHANGE) {
//check format
const VideoFormatInfo* format = decoder->getFormatInfo();
allocator->onFormatChange(format);

//send buffer again
EXPECT_EQ(YAMI_SUCCESS, decoder->decode(&buffer));
} else {
EXPECT_TRUE((YAMI_SUCCESS == status) || (YAMI_DECODE_INVALID_DATA == status));
}
inFrames++;
}
return;
}

TEST_P(DecodeApiTest, Flush)
{
NativeDisplay nativeDisplay;
Expand All @@ -282,43 +329,18 @@ TEST_P(DecodeApiTest, Flush)
memset(&config, 0, sizeof(config));
ASSERT_EQ(YAMI_SUCCESS, decoder->start(&config));

VideoDecodeBuffer buffer;
FrameInfo info;
int64_t timeBeforeFlush = 0;
int64_t timeCurrent = 0;
SharedPtr<VideoFrame> output;
int32_t size = frames.getFrameCount();
int32_t inFrames = 0;
int32_t outFrames = 0;

for (int i = 0; i < size; i++) {
inFrames = 0;
outFrames = 0;
frames.seekToStart();
for (int j = 0; j <= i; j++) {
if (!frames.getFrame(buffer, info))
break;

buffer.timeStamp = timeCurrent;
timeCurrent++;
YamiStatus status = decoder->decode(&buffer);
while ((output = decoder->getOutput())) {
EXPECT_TRUE(output->timeStamp > timeBeforeFlush);
outFrames++;
}

if (status == YAMI_DECODE_FORMAT_CHANGE) {
//check format
const VideoFormatInfo* format = decoder->getFormatInfo();
allocator->onFormatChange(format);

//send buffer again
EXPECT_EQ(YAMI_SUCCESS, decoder->decode(&buffer));
}
else {
EXPECT_EQ(YAMI_SUCCESS, status);
}
}
timeBeforeFlush = buffer.timeStamp;

decodeAndOutput(decoder, allocator, frames, 0, i, timeBeforeFlush, timeCurrent, false, inFrames, outFrames);
timeBeforeFlush = timeCurrent - 1;
// No flush at last round, it has EOS at the end
if (i < (size - 1))
decoder->flush();
Expand All @@ -328,7 +350,53 @@ TEST_P(DecodeApiTest, Flush)
while (decoder->getOutput()) {
outFrames++;
}
EXPECT_EQ(outFrames, size);
EXPECT_EQ(outFrames, inFrames);
}


TEST_P(DecodeApiTest, Flush_NonIDR)
{
NativeDisplay nativeDisplay;
memset(&nativeDisplay, 0, sizeof(nativeDisplay));
DisplayPtr display = VaapiDisplay::create(nativeDisplay);
DecodeSurfaceAllocator* allocator = new DecodeSurfaceAllocator(display);

SharedPtr<IVideoDecoder> decoder;
TestDecodeFrames frames = *GetParam();
decoder.reset(createVideoDecoder(frames.getMime()), releaseVideoDecoder);
ASSERT_TRUE(bool(decoder));

decoder->setAllocator(allocator);

VideoConfigBuffer config;
memset(&config, 0, sizeof(config));
ASSERT_EQ(YAMI_SUCCESS, decoder->start(&config));

int64_t timeBeforeFlush = 0;
int64_t timeCurrent = 0;
int32_t size = frames.getFrameCount();
int inFrames = 0;
int outFrames = 0;

for (int i = 1; i < size; i++) {
frames.seekToStart();
// decode 0 -> i frames, and get possible output
decodeAndOutput(decoder, allocator, frames, 0, i, timeBeforeFlush, timeCurrent, false, inFrames, outFrames);
timeBeforeFlush = timeCurrent - 1;
// flush
EXPECT_TRUE(inFrames > outFrames);
decoder->flush();
inFrames = 0;
outFrames = 0;
// decode i -> size frames, and get possible output
decodeAndOutput(decoder, allocator, frames, i, size, timeBeforeFlush, timeCurrent, true, inFrames, outFrames);
}
//drain the decoder
EXPECT_EQ(YAMI_SUCCESS, decoder->decode(NULL));
while (decoder->getOutput()) {
outFrames ++;
}
EXPECT_TRUE(inFrames > outFrames);
}

/** Teach Google Test how to print a TestDecodeFrames::Shared object */
Expand All @@ -341,6 +409,7 @@ INSTANTIATE_TEST_CASE_P(
VaapiDecoder, DecodeApiTest,
::testing::Values(
TestDecodeFrames::create(g_h264data, YAMI_MIME_H264),
TestDecodeFrames::create(g_mpeg2data, YAMI_MIME_MPEG2),
TestDecodeFrames::create(g_h265data, YAMI_MIME_H265),
TestDecodeFrames::create(g_vp8data, YAMI_MIME_VP8)));
}
36 changes: 36 additions & 0 deletions decoder/FrameData.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,38 @@ static const uint8_t s_hevc16x16[] = {
0x3e, 0xfe, 0xc3, 0x05, 0xd2, 0x1a, 0xc9, 0x78
};


static const uint8_t s_mpeg2_8x8I1[] = {
0x00, 0x00, 0x01, 0xb3, 0x00, 0x80, 0x08, 0x13, 0xff, 0xff, 0xe0, 0x18,
0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x01, 0xb8, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f,
0xff, 0xf8, 0x00, 0x00, 0x01, 0xb5, 0x8f, 0xff, 0xf3, 0x41, 0x80, 0x00,
0x00, 0x01, 0x01, 0x13, 0xfb, 0x55, 0x29, 0x49, 0x4a
};

static const uint8_t s_mpeg2_8x8P[] = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x57, 0xff, 0xfb, 0x80, 0x00, 0x00, 0x01,
0xb5, 0x81, 0x1f, 0xf3, 0x41, 0x80, 0x00, 0x00, 0x01, 0x01, 0x12, 0x88,
0x02, 0x07, 0xe4, 0x00, 0x6a, 0x08, 0x60, 0x7a, 0x00, 0xb8, 0x11, 0xff,
0xb5, 0x20, 0x97, 0xff, 0xa0, 0x0d, 0x60, 0x40, 0xfc, 0x80, 0x0d, 0x41,
0x0c, 0x0f, 0x40, 0x17, 0x02, 0x3f, 0xf6, 0xa4, 0x12, 0xff, 0xf4, 0x01,
0xac, 0x02, 0x70, 0x2a, 0x08, 0x80, 0x0c, 0x08, 0xe0, 0x10, 0x18, 0x45,
0x80, 0x14, 0x00, 0x2e, 0x09, 0x04, 0x1f, 0xeb, 0x03, 0xc3, 0x00, 0x15,
0x80, 0x5e, 0x80, 0x2c, 0xa7, 0x59, 0x49, 0x74, 0x8f, 0x48, 0x4b, 0x38,
0x12, 0xdb, 0x19, 0x00
};

static const uint8_t s_mpeg2_8x8I2[] = {
0x00, 0x00, 0x01, 0xb3, 0x00, 0x80, 0x08, 0x13, 0xff, 0xff, 0xe0, 0x18,
0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x01, 0xb8, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f,
0xff, 0xf8, 0x00, 0x00, 0x01, 0xb5, 0x8f, 0xff, 0xf3, 0x41, 0x80, 0x00,
0x00, 0x01, 0x01, 0x13, 0xfb, 0x30, 0x21, 0x00, 0x40, 0x13, 0x4a, 0x28,
0xc0, 0x3a, 0x04, 0x5f, 0xfc, 0x2c, 0x9f, 0x5c, 0x98, 0xdc, 0xa0, 0x83,
0xfd, 0x65, 0x1a, 0x00, 0xf8, 0x01, 0xf7, 0xe3, 0xc0, 0xc1, 0x0d, 0x04,
0xe2, 0x80, 0xaa, 0x10, 0x4e, 0xad, 0xa0
};

struct FrameInfo {
uint32_t m_width;
uint32_t m_height;
Expand Down Expand Up @@ -363,6 +395,10 @@ const static FrameData g_vp8_8x8P1(s_vp8_8x8P1, N_ELEMENTS(s_vp8_8x8P1), 8, 8);
const static FrameData g_vp8_8x8P2(s_vp8_8x8P2, N_ELEMENTS(s_vp8_8x8P2), 8, 8);
const static FrameData g_vp8_16x16(s_vp8_16x16, N_ELEMENTS(s_vp8_16x16), 16, 16);

const static FrameData g_mpeg2_8x8I1(s_mpeg2_8x8I1, N_ELEMENTS(s_mpeg2_8x8I1), 8, 8);
const static FrameData g_mpeg2_8x8P(s_mpeg2_8x8P, N_ELEMENTS(s_mpeg2_8x8P), 8, 8);
const static FrameData g_mpeg2_8x8I2(s_mpeg2_8x8I2, N_ELEMENTS(s_mpeg2_8x8I2), 8, 8);

const static FrameData g_EOF(NULL, 0, 0, 0);
};
#endif
2 changes: 1 addition & 1 deletion decoder/vaapidecoder_h265.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ YamiStatus VaapiDecoderH265::decodeSlice(NalUnit* nalu)
return status;
if (m_noRaslOutputFlag && isRasl(nalu))
return YAMI_SUCCESS;
if (!m_current || !m_dpb.init(m_current, slice, nalu, m_newStream))
if (!m_current || (!isIdr(nalu) && m_newStream) || !m_dpb.init(m_current, slice, nalu, m_newStream))
return YAMI_DECODE_INVALID_DATA;
if (!fillPicture(m_current, slice) || !fillIqMatrix(m_current, slice))
return YAMI_FAIL;
Expand Down