1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/gpu/mac/vp9_super_frame_bitstream_filter.h"
6
7 #include <CoreMedia/CoreMedia.h>
8
9 #include "media/base/media.h"
10 #include "media/base/test_data_util.h"
11 #include "media/ffmpeg/ffmpeg_common.h"
12 #include "media/filters/ffmpeg_glue.h"
13 #include "media/filters/in_memory_url_protocol.h"
14 #include "media/filters/vp9_parser.h"
15 #include "media/media_buildflags.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace media {
19
20 #if BUILDFLAG(ENABLE_FFMPEG)
21
22 class VP9SuperFrameBitstreamFilterTest : public testing::Test {
23 public:
VP9SuperFrameBitstreamFilterTest()24 VP9SuperFrameBitstreamFilterTest()
25 : parser_(/*parsing_compressed_header=*/false) {
26 InitializeMediaLibrary();
27 }
28
29 ~VP9SuperFrameBitstreamFilterTest() override = default;
30
LoadTestData(const char * file_name)31 void LoadTestData(const char* file_name) {
32 buffer_ = ReadTestDataFile(file_name);
33 ASSERT_TRUE(buffer_);
34
35 // Initialize ffmpeg with the file data.
36 protocol_ = std::make_unique<InMemoryUrlProtocol>(
37 buffer_->data(), buffer_->data_size(), false);
38 glue_ = std::make_unique<FFmpegGlue>(protocol_.get());
39 ASSERT_TRUE(glue_->OpenContext());
40 }
41
ReadPacket(int stream_index=0)42 scoped_refptr<DecoderBuffer> ReadPacket(int stream_index = 0) {
43 AVPacket packet = {0};
44 while (av_read_frame(glue_->format_context(), &packet) >= 0) {
45 if (packet.stream_index == stream_index) {
46 auto buffer = DecoderBuffer::CopyFrom(packet.data, packet.size);
47 av_packet_unref(&packet);
48 return buffer;
49 }
50 av_packet_unref(&packet);
51 }
52 return nullptr;
53 }
54
ParseNextFrame()55 Vp9Parser::Result ParseNextFrame() {
56 // Temporaries for the Vp9Parser.
57 Vp9FrameHeader fhdr;
58 gfx::Size coded_size;
59 std::unique_ptr<DecryptConfig> null_config;
60 return parser_.ParseNextFrame(&fhdr, &coded_size, &null_config);
61 }
62
63 protected:
64 Vp9Parser parser_;
65
66 private:
67 scoped_refptr<DecoderBuffer> buffer_;
68 std::unique_ptr<InMemoryUrlProtocol> protocol_;
69 std::unique_ptr<FFmpegGlue> glue_;
70 };
71
TEST_F(VP9SuperFrameBitstreamFilterTest,Passthrough)72 TEST_F(VP9SuperFrameBitstreamFilterTest, Passthrough) {
73 // This test file has no super frames.
74 ASSERT_NO_FATAL_FAILURE(LoadTestData("bear-vp9.webm"));
75
76 // Run through a few packets for good measure.
77 VP9SuperFrameBitstreamFilter bsf;
78 for (int i = 0; i < 16; ++i) {
79 auto buffer = ReadPacket();
80 EXPECT_TRUE(buffer->HasOneRef());
81
82 // Passthrough buffers should be zero-copy, so a ref should be added.
83 bsf.EnqueueBuffer(buffer);
84 EXPECT_FALSE(buffer->HasOneRef());
85
86 auto cm_block = bsf.take_buffer();
87 ASSERT_TRUE(cm_block);
88
89 ASSERT_EQ(buffer->data_size(), CMBlockBufferGetDataLength(cm_block));
90
91 std::unique_ptr<uint8_t> block_data(new uint8_t[buffer->data_size()]);
92 ASSERT_EQ(noErr, CMBlockBufferCopyDataBytes(
93 cm_block, 0, buffer->data_size(), block_data.get()));
94
95 // Verify that the block is valid.
96 parser_.SetStream(block_data.get(), buffer->data_size(), nullptr);
97 EXPECT_EQ(Vp9Parser::kOk, ParseNextFrame());
98 EXPECT_EQ(Vp9Parser::kEOStream, ParseNextFrame());
99
100 // Releasing the block should bring our ref count back down.
101 cm_block.reset();
102 ASSERT_TRUE(buffer->HasOneRef());
103 }
104 }
105
TEST_F(VP9SuperFrameBitstreamFilterTest,Superframe)106 TEST_F(VP9SuperFrameBitstreamFilterTest, Superframe) {
107 ASSERT_NO_FATAL_FAILURE(LoadTestData("buck-1280x720-vp9.webm"));
108
109 VP9SuperFrameBitstreamFilter bsf;
110
111 // The first packet in this file is not part of a super frame. We still need
112 // to send it to the VP9 parser so that the superframe can reference it.
113 auto buffer = ReadPacket();
114 parser_.SetStream(buffer->data(), buffer->data_size(), nullptr);
115 EXPECT_EQ(Vp9Parser::kOk, ParseNextFrame());
116 bsf.EnqueueBuffer(std::move(buffer));
117 ASSERT_TRUE(bsf.take_buffer());
118
119 // The second and third belong to a super frame.
120 buffer = ReadPacket();
121 size_t total_size = buffer->data_size();
122 bsf.EnqueueBuffer(std::move(buffer));
123 ASSERT_FALSE(bsf.take_buffer());
124 buffer = ReadPacket();
125 total_size += buffer->data_size();
126 bsf.EnqueueBuffer(std::move(buffer));
127
128 auto cm_block = bsf.take_buffer();
129 ASSERT_TRUE(cm_block);
130
131 // Two marker bytes and 2x 16-bit sizes.
132 const size_t kExpectedTotalSize = 1 + 2 + 2 + 1 + total_size;
133 EXPECT_EQ(kExpectedTotalSize, CMBlockBufferGetDataLength(cm_block));
134
135 std::unique_ptr<uint8_t> block_data(new uint8_t[kExpectedTotalSize]);
136 ASSERT_EQ(noErr, CMBlockBufferCopyDataBytes(cm_block, 0, kExpectedTotalSize,
137 block_data.get()));
138
139 parser_.SetStream(block_data.get(), kExpectedTotalSize, nullptr);
140 EXPECT_EQ(Vp9Parser::kOk, ParseNextFrame());
141 EXPECT_EQ(Vp9Parser::kOk, ParseNextFrame());
142 EXPECT_EQ(Vp9Parser::kEOStream, ParseNextFrame());
143 }
144
TEST_F(VP9SuperFrameBitstreamFilterTest,FlushPassthroughFrame)145 TEST_F(VP9SuperFrameBitstreamFilterTest, FlushPassthroughFrame) {
146 ASSERT_NO_FATAL_FAILURE(LoadTestData("buck-1280x720-vp9.webm"));
147
148 VP9SuperFrameBitstreamFilter bsf;
149
150 // The first packet in this file is not part of a super frame.
151 bsf.EnqueueBuffer(ReadPacket());
152 ASSERT_TRUE(bsf.has_buffers_for_testing());
153 bsf.Flush();
154 ASSERT_FALSE(bsf.has_buffers_for_testing());
155 ASSERT_FALSE(bsf.take_buffer());
156 }
157
TEST_F(VP9SuperFrameBitstreamFilterTest,FlushPartialSuperFrame)158 TEST_F(VP9SuperFrameBitstreamFilterTest, FlushPartialSuperFrame) {
159 ASSERT_NO_FATAL_FAILURE(LoadTestData("buck-1280x720-vp9.webm"));
160
161 VP9SuperFrameBitstreamFilter bsf;
162
163 // The first packet in this file is not part of a super frame.
164 bsf.EnqueueBuffer(ReadPacket());
165 ASSERT_TRUE(bsf.has_buffers_for_testing());
166 ASSERT_TRUE(bsf.take_buffer());
167
168 // The second and third belong to a super frame.
169 bsf.EnqueueBuffer(ReadPacket());
170 ASSERT_FALSE(bsf.take_buffer());
171 ASSERT_TRUE(bsf.has_buffers_for_testing());
172
173 bsf.Flush();
174 ASSERT_FALSE(bsf.has_buffers_for_testing());
175 ASSERT_FALSE(bsf.take_buffer());
176 }
177
178 #endif // BUILDFLAG(ENABLE_FFMPEG)
179
180 } // namespace media
181