h264_encoder_test.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  */
19 
21 #include <gtest/gtest.h>
23 #include <math.h>
24 
25 #include <array>
26 #include <map>
27 
28 constexpr int kDefaultSrcWidth = 410;
29 constexpr int kDefaultSrcHeight = 308;
30 constexpr AVPixelFormat kDefaultSrcEncoding = AV_PIX_FMT_RGB24;
31 constexpr int kBytesPerPixel = 3; // 3 color channels (red, green, blue)
32 constexpr int kDefaultDstWidth = 1230;
33 constexpr int kDefaultDstHeight = 924;
34 constexpr int kDefaultFpsNumerator = 30;
35 constexpr int kDefaultFpsDenominator = 1;
36 constexpr int kDefaultBitrate = 2048000;
37 constexpr char kDefaultCodec[] = "libx264";
38 
39 using namespace Aws;
40 using namespace Aws::Client;
41 using namespace Aws::Utils::Encoding;
42 
47 {
48 public:
50 
51  TestParameterReader(int output_width, int output_height, int fps_num, int fps_denom, int bitrate,
52  const std::string & codec)
53  {
54  int_map_ = {{"output_width", output_width},
55  {"output_height", output_height},
56  {"fps_numerator", fps_num},
57  {"fps_denominator", fps_denom},
58  {"bitrate", bitrate}};
59  string_map_ = {{"codec", codec}};
60  }
61 
62  AwsError ReadParam(const ParameterPath & param_path, int & out) const
63  {
64  AwsError result = AWS_ERR_NOT_FOUND;
65  std::string name = FormatParameterPath(param_path);
66  if (int_map_.count(name) > 0) {
67  out = int_map_.at(name);
68  result = AWS_ERR_OK;
69  }
70  return result;
71  }
72 
73  AwsError ReadParam(const ParameterPath & param_path, bool & out) const
74  {
75  return AWS_ERR_NOT_FOUND;
76  }
77 
78  AwsError ReadParam(const ParameterPath & param_path, std::string & out) const
79  {
80  AwsError result = AWS_ERR_NOT_FOUND;
81  std::string name = FormatParameterPath(param_path);
82  if (string_map_.count(name) > 0) {
83  out = string_map_.at(name);
84  result = AWS_ERR_OK;
85  }
86  return result;
87  }
88 
89  AwsError ReadParam(const ParameterPath & param_path, Aws::String & out) const
90  {
91  AwsError result = AWS_ERR_NOT_FOUND;
92  std::string name = FormatParameterPath(param_path);
93  if (string_map_.count(name) > 0) {
94  out = string_map_.at(name).c_str();
95  result = AWS_ERR_OK;
96  }
97  return result;
98  }
99 
100  AwsError ReadParam(const ParameterPath & param_path, std::map<std::string, std::string> & out) const
101  {
102  return AWS_ERR_NOT_FOUND;
103  }
104 
105  AwsError ReadParam(const ParameterPath & param_path, std::vector<std::string> & out) const
106  {
107  return AWS_ERR_NOT_FOUND;
108  }
109 
110  AwsError ReadParam(const ParameterPath & param_path, double & out) const {
111  return AWS_ERR_NOT_FOUND;
112  }
113 
114 private:
115  std::string FormatParameterPath(const ParameterPath & param_path) const
116  {
117  return param_path.get_resolved_path('/', '/');
118  }
119 
120  std::map<std::string, int> int_map_;
121  std::map<std::string, std::string> string_map_;
122 };
123 
128 TEST(H264EncoderCoreSuite, InitWithEmptyParamServer)
129 {
130  TestParameterReader param_reader;
131 
132  auto encoder = std::unique_ptr<H264Encoder>(new H264Encoder());
133 
134  AwsError result =
135  encoder->Initialize(kDefaultSrcWidth, kDefaultSrcHeight, kDefaultSrcEncoding, param_reader);
136 
137  EXPECT_EQ(result, AWS_ERR_OK);
138  EXPECT_FALSE(encoder->GetExtraData().empty());
139 }
140 
144 TEST(H264EncoderCoreSuite, InitWithFullParamServer)
145 {
148 
149  auto encoder = std::unique_ptr<H264Encoder>(new H264Encoder());
150 
151  AwsError result =
152  encoder->Initialize(kDefaultSrcWidth, kDefaultSrcHeight, kDefaultSrcEncoding, param_reader);
153 
154  EXPECT_EQ(result, AWS_ERR_OK);
155  EXPECT_FALSE(encoder->GetExtraData().empty());
156 }
157 
161 TEST(H264EncoderCoreSuite, InitWithInvalidParamServer)
162 {
163  struct TestParamCollection
164  {
165  int src_width;
166  int src_height;
167  AVPixelFormat src_enc;
168  int dst_width;
169  int dst_height;
170  int fps_num;
171  int fps_denom;
172  int bitrate;
173  const char * codec;
174  };
175 
176  const std::array<TestParamCollection, 9> params_sweep = {
177  {{
178  -1, // SrcWidth set to some invalid value
179  kDefaultSrcHeight, // SrcHeight
180  kDefaultSrcEncoding, // SrcEncoding
181  kDefaultDstWidth, // DstWidth
182  kDefaultDstHeight, // DstHeight
183  kDefaultFpsNumerator, // FpsNumerator
184  kDefaultFpsDenominator, // FpsDenominator
185  kDefaultBitrate, // Bitrate
186  kDefaultCodec // Codec
187  },
188  {
189  kDefaultSrcWidth, // SrcWidth
190  -1, // SrcHeight set to some invalid value
191  kDefaultSrcEncoding, // SrcEncoding
192  kDefaultDstWidth, // DstWidth
193  kDefaultDstHeight, // DstHeight
194  kDefaultFpsNumerator, // FpsNumerator
195  kDefaultFpsDenominator, // FpsDenominator
196  kDefaultBitrate, // Bitrate
197  kDefaultCodec // Codec
198  },
199  {
200  kDefaultSrcWidth, // SrcWidth
201  kDefaultSrcHeight, // SrcHeight
202  static_cast<AVPixelFormat>(-1), // SrcEncoding set to some invalid value
203  kDefaultDstWidth, // DstWidth
204  kDefaultDstHeight, // DstHeight
205  kDefaultFpsNumerator, // FpsNumerator
206  kDefaultFpsDenominator, // FpsDenominator
207  kDefaultBitrate, // Bitrate
208  kDefaultCodec // Codec
209  },
210  {
211  kDefaultSrcWidth, // SrcWidth
212  kDefaultSrcHeight, // SrcHeight
213  kDefaultSrcEncoding, // SrcEncoding
214  -1, // DstWidth set to some invalid value
215  kDefaultDstHeight, // DstHeight
216  kDefaultFpsNumerator, // FpsNumerator
217  kDefaultFpsDenominator, // FpsDenominator
218  kDefaultBitrate, // Bitrate
219  kDefaultCodec // Codec
220  },
221  {
222  kDefaultSrcWidth, // SrcWidth
223  kDefaultSrcHeight, // SrcHeight
224  kDefaultSrcEncoding, // SrcEncoding
225  kDefaultDstWidth, // DstWidth
226  -1, // DstHeight set to some invalid value
227  kDefaultFpsNumerator, // FpsNumerator
228  kDefaultFpsDenominator, // FpsDenominator
229  kDefaultBitrate, // Bitrate
230  kDefaultCodec // Codec
231  },
232  {
233  kDefaultSrcWidth, // SrcWidth
234  kDefaultSrcHeight, // SrcHeight
235  kDefaultSrcEncoding, // SrcEncoding
236  kDefaultDstWidth, // DstWidth
237  kDefaultDstHeight, // DstHeight
238  -1, // FpsNumerator set to some invalid value
239  kDefaultFpsDenominator, // FpsDenominator
240  kDefaultBitrate, // Bitrate
241  kDefaultCodec // Codec
242  },
243  {
244  kDefaultSrcWidth, // SrcWidth
245  kDefaultSrcHeight, // SrcHeight
246  kDefaultSrcEncoding, // SrcEncoding
247  kDefaultDstWidth, // DstWidth
248  kDefaultDstHeight, // DstHeight
249  kDefaultFpsNumerator, // FpsNumerator
250  -1, // FpsDenominator set to some invalid value
251  kDefaultBitrate, // Bitrate
252  kDefaultCodec // Codec
253  },
254  {
255  kDefaultSrcWidth, // SrcWidth
256  kDefaultSrcHeight, // SrcHeight
257  kDefaultSrcEncoding, // SrcEncoding
258  kDefaultDstWidth, // DstWidth
259  kDefaultDstHeight, // DstHeight
260  kDefaultFpsNumerator, // FpsNumerator
261  kDefaultFpsDenominator, // FpsDenominator
262  -1, // Bitrate set to some invalid value
263  kDefaultCodec // Codec
264  },
265  {
266  kDefaultSrcWidth, // SrcWidth
267  kDefaultSrcHeight, // SrcHeight
268  kDefaultSrcEncoding, // SrcEncoding
269  kDefaultDstWidth, // DstWidth
270  kDefaultDstHeight, // DstHeight
271  kDefaultFpsNumerator, // FpsNumerator
272  kDefaultFpsDenominator, // FpsDenominator
273  kDefaultBitrate, // Bitrate
274  "fake codec name" // Codec set to some invalid value
275  }}};
276 
277  for (const auto & p : params_sweep) {
278  TestParameterReader param_reader(p.dst_width, p.dst_height, p.fps_num, p.fps_denom, p.bitrate,
279  p.codec);
280 
281  auto encoder = std::unique_ptr<H264Encoder>(new H264Encoder());
282 
283  AwsError result = encoder->Initialize(p.src_width, p.src_height, p.src_enc, param_reader);
284 
285  EXPECT_TRUE(AWS_ERR_PARAM == result || AWS_ERR_NOT_FOUND == result);
286  }
287 }
288 
289 static void RainbowColor(const float h, uint8_t & r_out, uint8_t & g_out, uint8_t & b_out)
290 {
291  int i = 6.0f * h;
292  float f = 6.0f * h - i;
293  float t = f;
294  float q = 1.0f - f;
295 
296  float r, g, b;
297  switch (i % 6) {
298  case 0:
299  r = 1.0f;
300  g = t;
301  b = 0.0f;
302  break;
303  case 1:
304  r = q;
305  g = 1.0f;
306  b = 0.0f;
307  break;
308  case 2:
309  r = 0.0f;
310  g = 1.0f;
311  b = t;
312  break;
313  case 3:
314  r = 0.0f;
315  g = q;
316  b = 1.0f;
317  break;
318  case 4:
319  r = t;
320  g = 0.0f;
321  b = 1.0f;
322  break;
323  case 5:
324  r = 1.0f;
325  g = 0.0f;
326  b = q;
327  break;
328  }
329 
330  r_out = std::lround(255.0f * r);
331  g_out = std::lround(255.0f * g);
332  b_out = std::lround(255.0f * b);
333 }
334 
338 TEST(H264EncoderCoreSuite, Encode)
339 {
342 
343  auto encoder = std::unique_ptr<H264Encoder>(new H264Encoder());
344 
345  AwsError result =
346  encoder->Initialize(kDefaultSrcWidth, kDefaultSrcHeight, kDefaultSrcEncoding, param_reader);
347  ASSERT_EQ(result, AWS_ERR_OK);
348 
349  uint8_t * img_buffer = new uint8_t[kBytesPerPixel * kDefaultSrcWidth * kDefaultSrcHeight];
350  FILE * debug_file = fopen("frames.bin", "wb");
351 
352  // encode (1 / kDefaultFpsDenominator) seconds of video
353  for (int i = 0; i < kDefaultFpsNumerator; ++i) {
354  // prepare a dummy image
355  int shift = static_cast<float>(i) / (kDefaultFpsNumerator - 1) * kDefaultSrcWidth;
356  for (int y = 0; y < kDefaultSrcHeight; ++y) {
357  for (int x = 0; x < kDefaultSrcWidth; ++x) {
358  uint8_t r, g, b;
359  RainbowColor(static_cast<float>((x + shift) % kDefaultSrcWidth) / kDefaultSrcWidth, r, g,
360  b);
361  img_buffer[kBytesPerPixel * y * kDefaultSrcWidth + kBytesPerPixel * x + 0] = r;
362  img_buffer[kBytesPerPixel * y * kDefaultSrcWidth + kBytesPerPixel * x + 1] = g;
363  img_buffer[kBytesPerPixel * y * kDefaultSrcWidth + kBytesPerPixel * x + 2] = b;
364  }
365  }
366 
367  H264EncoderResult encoder_output;
368  AwsError result = encoder->Encode(img_buffer, encoder_output);
369 
370  EXPECT_TRUE(AWS_ERR_OK == result || AWS_ERR_EMPTY == result);
371  if (AWS_ERR_OK == result) {
372  EXPECT_EQ(encoder_output.frame_dts % encoder_output.frame_duration, 0);
373  EXPECT_EQ(encoder_output.frame_pts % encoder_output.frame_duration, 0);
374  EXPECT_EQ(static_cast<uint64_t>(1.0e6 * kDefaultFpsDenominator / kDefaultFpsNumerator),
375  encoder_output.frame_duration);
376  }
377 
378  if (0 == i) {
379  fwrite(encoder->GetExtraData().data(), 1, encoder->GetExtraData().size(), debug_file);
380  }
381  fwrite(encoder_output.frame_data.data(), 1, encoder_output.frame_data.size(), debug_file);
382  }
383 
384  fclose(debug_file);
385  // you can dump the debug frames by executing: ffmpeg -i frames.bin -frames:v 10 -f image2
386  // frame%03d.png
387 }
388 
389 int main(int argc, char ** argv)
390 {
391  testing::InitGoogleTest(&argc, argv);
392  return RUN_ALL_TESTS();
393 }
int main(int argc, char **argv)
TEST(H264EncoderCoreSuite, InitWithEmptyParamServer)
constexpr int kDefaultFpsNumerator
constexpr char kDefaultCodec[]
constexpr AVPixelFormat kDefaultSrcEncoding
AWS_ERR_PARAM
constexpr int kDefaultFpsDenominator
std::map< std::string, std::string > string_map_
AwsError ReadParam(const ParameterPath &param_path, std::map< std::string, std::string > &out) const
constexpr int kDefaultSrcWidth
AwsError
std::string get_resolved_path(char node_namespace_separator, char parameter_namespace_separator) const
constexpr int kBytesPerPixel
AWS_ERR_EMPTY
constexpr int kDefaultDstWidth
AwsError ReadParam(const ParameterPath &param_path, std::vector< std::string > &out) const
constexpr int kDefaultBitrate
AWS_ERR_NOT_FOUND
constexpr int kDefaultDstHeight
constexpr int kDefaultSrcHeight
std::string FormatParameterPath(const ParameterPath &param_path) const
AwsError ReadParam(const ParameterPath &param_path, double &out) const
std::map< std::string, int > int_map_
TestParameterReader(int output_width, int output_height, int fps_num, int fps_denom, int bitrate, const std::string &codec)
AwsError ReadParam(const ParameterPath &param_path, int &out) const
AWS_ERR_OK
AwsError ReadParam(const ParameterPath &param_path, Aws::String &out) const
AwsError ReadParam(const ParameterPath &param_path, std::string &out) const
static void RainbowColor(const float h, uint8_t &r_out, uint8_t &g_out, uint8_t &b_out)
AwsError ReadParam(const ParameterPath &param_path, bool &out) const


h264_encoder_core
Author(s): AWS RoboMaker
autogenerated on Fri Mar 5 2021 03:31:35