diff --git a/media/gpu/av1_decoder_unittest.cc b/media/gpu/av1_decoder_unittest.cc index e4d977ae4d620..72f12670ecf13 100644 --- a/media/gpu/av1_decoder_unittest.cc +++ b/media/gpu/av1_decoder_unittest.cc @@ -1133,6 +1133,97 @@ FUZZ_TEST(AV1DecoderFuzz, DecodeDoesNotCrash) .WithMaxSize(3)) .WithSeeds(GetAV1Seeds); +MATCHER_P4(SeqInfoFieldsAre, sb128, cdef, restoration, film_grain, "") { + return arg.use_128x128_superblock == sb128 && arg.enable_cdef == cdef && + arg.enable_restoration == restoration && + arg.film_grain_params_present == film_grain; +} + +// Demonstrates that AV1Decoder adopts a new ObuSequenceHeader whose +// non-dimensional flags (use_128x128_superblock / enable_cdef / +// enable_restoration / film_grain_params_present) flip mid-stream WITHOUT +// returning kConfigChange, so the same accelerator context receives +// SubmitDecode() with the new seq_info_fields. +// +// av1-seqhdr-flip.ivf: two 256x256 8-bit 4:2:0 lossless key frames whose +// sequence headers are identical except for {sb128, cdef, restoration, +// film_grain} = {0,0,0,0} -> {1,1,1,1}. +TEST_F(AV1DecoderTest, SeqHeaderFlagsFlipWithoutConfigChange) { + const std::string kStream("av1-seqhdr-flip.ivf"); + std::vector> buffers = ReadIVF(kStream); + ASSERT_EQ(buffers.size(), 2u); + + constexpr gfx::Size kFrameSize(256, 256); + + // ---- Temporal Unit 1: SeqHdr A ---- + { + ::testing::InSequence s; + auto pic = base::MakeRefCounted(); + EXPECT_CALL(*mock_accelerator_, CreateAV1Picture(/*apply_grain=*/false)) + .WillOnce(Return(pic)); + EXPECT_CALL(*mock_accelerator_, + SubmitDecode(_, + AllOf(MatchesYUV420SequenceHeader( + libgav1::kProfile0, /*bitdepth=*/8, + kFrameSize, + /*film_grain_params_present=*/false), + SeqInfoFieldsAre(/*sb128=*/false, + /*cdef=*/false, + /*restoration=*/false, + /*film_grain=*/false)), + _, NonEmptyTileBuffers(), _)) + .WillOnce(Return(AV1Decoder::AV1Accelerator::Status::kOk)); + EXPECT_CALL(*mock_accelerator_, OutputPicture(_)).WillOnce(Return(true)); + + std::vector results = Decode(buffers[0]); + std::vector expected = {DecodeResult::kConfigChange, + DecodeResult::kRanOutOfStreamData}; + EXPECT_EQ(results, expected); + testing::Mock::VerifyAndClearExpectations(mock_accelerator_); + } + + // The backend now has a context sized for SeqHdr A (no film grain -> + // GetRequiredNumOfPictures() does not double the pool). + const size_t pics_after_a = decoder_->GetRequiredNumOfPictures(); + + // ---- Temporal Unit 2: SeqHdr B (only seq-level flags differ) ---- + { + ::testing::InSequence s; + auto pic = base::MakeRefCounted(); + EXPECT_CALL(*mock_accelerator_, CreateAV1Picture(_)).WillOnce(Return(pic)); + // SubmitDecode is called with the *new* sequence header even though no + // kConfigChange was emitted: the same VA/D3D11/V4L2 decode object would + // receive seq_info_fields with {sb128=1, cdef=1, restoration=1, + // film_grain=1} mid-context. + EXPECT_CALL(*mock_accelerator_, + SubmitDecode(_, + AllOf(MatchesYUV420SequenceHeader( + libgav1::kProfile0, /*bitdepth=*/8, + kFrameSize, + /*film_grain_params_present=*/true), + SeqInfoFieldsAre(/*sb128=*/true, + /*cdef=*/true, + /*restoration=*/true, + /*film_grain=*/true)), + _, NonEmptyTileBuffers(), _)) + .WillOnce(Return(AV1Decoder::AV1Accelerator::Status::kOk)); + EXPECT_CALL(*mock_accelerator_, OutputPicture(_)).WillOnce(Return(true)); + + std::vector results = Decode(buffers[1]); + // *** No kConfigChange. *** The kConfigChange gate at av1_decoder.cc only + // compares {frame_size, visible_rect, profile, bit_depth, color_space}, + // none of which changed. + std::vector expected = {DecodeResult::kRanOutOfStreamData}; + EXPECT_EQ(results, expected); + testing::Mock::VerifyAndClearExpectations(mock_accelerator_); + } + + // GetRequiredNumOfPictures() now reflects film_grain_params_present=1 (x2), + // but the backend was never told to re-create the context / surface pool. + const size_t pics_after_b = decoder_->GetRequiredNumOfPictures(); + EXPECT_EQ(pics_after_b, 2 * pics_after_a); +} + // TODO(hiroh): Add more tests: reference frame tracking, render size change, // profile change, bit depth change, render size different than the frame size, // visible rectangle change in the middle of video sequence, reset while waiting