Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / formats / mp2t / es_parser_h264_unittest.cc
blob65f9a37be96b388674ea181860b80a62bb947150
1 // Copyright 2014 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.
5 #include <sstream>
6 #include <string>
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/time/time.h"
13 #include "media/base/stream_parser_buffer.h"
14 #include "media/filters/h264_parser.h"
15 #include "media/formats/mp2t/es_parser_h264.h"
16 #include "media/formats/mp2t/es_parser_test_base.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 namespace media {
20 class VideoDecoderConfig;
22 namespace mp2t {
24 class EsParserH264Test : public EsParserTestBase,
25 public testing::Test {
26 public:
27 EsParserH264Test() {}
29 protected:
30 void LoadH264Stream(const char* filename);
31 void GetPesTimestamps(std::vector<Packet>* pes_packets);
32 bool Process(const std::vector<Packet>& pes_packets, bool force_timing);
33 void CheckAccessUnits();
35 // Access units of the stream with AUD NALUs.
36 std::vector<Packet> access_units_;
38 private:
39 // Get the offset of the start of each access unit of |stream_|.
40 // This function assumes there is only one slice per access unit.
41 // This is a very simplified access unit segmenter that is good
42 // enough for unit tests.
43 void GetAccessUnits();
45 // Insert an AUD before each access unit.
46 // Update |stream_| and |access_units_| accordingly.
47 void InsertAUD();
49 DISALLOW_COPY_AND_ASSIGN(EsParserH264Test);
52 void EsParserH264Test::LoadH264Stream(const char* filename) {
53 // Load the input H264 file and segment it into access units.
54 LoadStream(filename);
55 GetAccessUnits();
56 ASSERT_GT(access_units_.size(), 0u);
58 // Insert AUDs into the stream.
59 InsertAUD();
61 // Generate some timestamps based on a 25fps stream.
62 for (size_t k = 0; k < access_units_.size(); k++)
63 access_units_[k].pts = base::TimeDelta::FromMilliseconds(k * 40u);
66 void EsParserH264Test::GetAccessUnits() {
67 access_units_.resize(0);
68 bool start_access_unit = true;
70 // In a first pass, retrieve the offsets of all access units.
71 size_t offset = 0;
72 while (true) {
73 // Find the next start code.
74 off_t relative_offset = 0;
75 off_t start_code_size = 0;
76 bool success = H264Parser::FindStartCode(
77 &stream_[offset], stream_.size() - offset,
78 &relative_offset, &start_code_size);
79 if (!success)
80 break;
81 offset += relative_offset;
83 if (start_access_unit) {
84 Packet cur_access_unit;
85 cur_access_unit.offset = offset;
86 access_units_.push_back(cur_access_unit);
87 start_access_unit = false;
90 // Get the NALU type.
91 offset += start_code_size;
92 if (offset >= stream_.size())
93 break;
94 int nal_unit_type = stream_[offset] & 0x1f;
96 // We assume there is only one slice per access unit.
97 if (nal_unit_type == H264NALU::kIDRSlice ||
98 nal_unit_type == H264NALU::kNonIDRSlice) {
99 start_access_unit = true;
103 ComputePacketSize(&access_units_);
106 void EsParserH264Test::InsertAUD() {
107 uint8 aud[] = { 0x00, 0x00, 0x01, 0x09 };
109 std::vector<uint8> stream_with_aud(
110 stream_.size() + access_units_.size() * sizeof(aud));
111 std::vector<EsParserTestBase::Packet> access_units_with_aud(
112 access_units_.size());
114 size_t offset = 0;
115 for (size_t k = 0; k < access_units_.size(); k++) {
116 access_units_with_aud[k].offset = offset;
117 access_units_with_aud[k].size = access_units_[k].size + sizeof(aud);
119 memcpy(&stream_with_aud[offset], aud, sizeof(aud));
120 offset += sizeof(aud);
122 memcpy(&stream_with_aud[offset],
123 &stream_[access_units_[k].offset], access_units_[k].size);
124 offset += access_units_[k].size;
127 // Update the stream and access units used for the test.
128 stream_ = stream_with_aud;
129 access_units_ = access_units_with_aud;
132 void EsParserH264Test::GetPesTimestamps(std::vector<Packet>* pes_packets_ptr) {
133 DCHECK(pes_packets_ptr);
134 const std::vector<Packet>& pes_packets = *pes_packets_ptr;
136 // Default: set to a negative timestamp to be able to differentiate from
137 // real timestamps.
138 // Note: we don't use kNoTimestamp() here since this one has already
139 // a special meaning in EsParserH264. The negative timestamps should be
140 // ultimately discarded by the H264 parser since not relevant.
141 for (size_t k = 0; k < pes_packets.size(); k++) {
142 (*pes_packets_ptr)[k].pts = base::TimeDelta::FromMilliseconds(-1);
145 // Set a valid timestamp for PES packets which include the start
146 // of an H264 access unit.
147 size_t pes_idx = 0;
148 for (size_t k = 0; k < access_units_.size(); k++) {
149 for (; pes_idx < pes_packets.size(); pes_idx++) {
150 size_t pes_start = pes_packets[pes_idx].offset;
151 size_t pes_end = pes_packets[pes_idx].offset + pes_packets[pes_idx].size;
152 if (pes_start <= access_units_[k].offset &&
153 pes_end > access_units_[k].offset) {
154 (*pes_packets_ptr)[pes_idx].pts = access_units_[k].pts;
155 break;
161 bool EsParserH264Test::Process(
162 const std::vector<Packet>& pes_packets,
163 bool force_timing) {
164 EsParserH264 es_parser(
165 base::Bind(&EsParserH264Test::NewVideoConfig, base::Unretained(this)),
166 base::Bind(&EsParserH264Test::EmitBuffer, base::Unretained(this)));
167 return ProcessPesPackets(&es_parser, pes_packets, force_timing);
170 void EsParserH264Test::CheckAccessUnits() {
171 EXPECT_EQ(buffer_count_, access_units_.size());
173 std::stringstream buffer_timestamps_stream;
174 for (size_t k = 0; k < access_units_.size(); k++) {
175 buffer_timestamps_stream << "("
176 << access_units_[k].pts.InMilliseconds()
177 << ") ";
179 std::string buffer_timestamps = buffer_timestamps_stream.str();
180 base::TrimWhitespaceASCII(
181 buffer_timestamps, base::TRIM_ALL, &buffer_timestamps);
182 EXPECT_EQ(buffer_timestamps_, buffer_timestamps);
185 TEST_F(EsParserH264Test, OneAccessUnitPerPes) {
186 LoadH264Stream("bear.h264");
188 // One to one equivalence between PES packets and access units.
189 std::vector<Packet> pes_packets(access_units_);
190 GetPesTimestamps(&pes_packets);
192 // Process each PES packet.
193 EXPECT_TRUE(Process(pes_packets, false));
194 CheckAccessUnits();
197 TEST_F(EsParserH264Test, NonAlignedPesPacket) {
198 LoadH264Stream("bear.h264");
200 // Generate the PES packets.
201 std::vector<Packet> pes_packets;
202 Packet cur_pes_packet;
203 cur_pes_packet.offset = 0;
204 for (size_t k = 0; k < access_units_.size(); k++) {
205 pes_packets.push_back(cur_pes_packet);
207 // The current PES packet includes the remaining bytes of the previous
208 // access unit and some bytes of the current access unit
209 // (487 bytes in this unit test but no more than the current access unit
210 // size).
211 cur_pes_packet.offset = access_units_[k].offset +
212 std::min<size_t>(487u, access_units_[k].size);
214 ComputePacketSize(&pes_packets);
215 GetPesTimestamps(&pes_packets);
217 // Process each PES packet.
218 EXPECT_TRUE(Process(pes_packets, false));
219 CheckAccessUnits();
222 TEST_F(EsParserH264Test, SeveralPesPerAccessUnit) {
223 LoadH264Stream("bear.h264");
225 // Get the minimum size of an access unit.
226 size_t min_access_unit_size = stream_.size();
227 for (size_t k = 0; k < access_units_.size(); k++) {
228 if (min_access_unit_size >= access_units_[k].size)
229 min_access_unit_size = access_units_[k].size;
232 // Use a small PES packet size or the minimum access unit size
233 // if it is even smaller.
234 size_t pes_size = 512;
235 if (min_access_unit_size < pes_size)
236 pes_size = min_access_unit_size;
238 std::vector<Packet> pes_packets;
239 Packet cur_pes_packet;
240 cur_pes_packet.offset = 0;
241 while (cur_pes_packet.offset < stream_.size()) {
242 pes_packets.push_back(cur_pes_packet);
243 cur_pes_packet.offset += pes_size;
245 ComputePacketSize(&pes_packets);
246 GetPesTimestamps(&pes_packets);
248 // Process each PES packet.
249 EXPECT_TRUE(Process(pes_packets, false));
250 CheckAccessUnits();
252 // Process PES packets forcing timings for each PES packet.
253 EXPECT_TRUE(Process(pes_packets, true));
254 CheckAccessUnits();
257 } // namespace mp2t
258 } // namespace media