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