video_util_unittest.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. // Copyright (c) 2012 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. #include "media/base/video_util.h"
  5. #include <stdint.h>
  6. #include <cmath>
  7. #include <memory>
  8. #include "media/base/limits.h"
  9. #include "media/base/video_frame.h"
  10. #include "testing/gtest/include/gtest/gtest.h"
  11. #include "ui/gfx/geometry/rect.h"
  12. namespace {
  13. // Initialize a plane's visible rect with value circularly from 0 to 255.
  14. void FillPlaneWithPattern(uint8_t* data,
  15. int stride,
  16. const gfx::Size& visible_size) {
  17. DCHECK(data && visible_size.width() <= stride);
  18. uint32_t val = 0;
  19. uint8_t* src = data;
  20. for (int i = 0; i < visible_size.height(); ++i, src += stride) {
  21. for (int j = 0; j < visible_size.width(); ++j, ++val)
  22. src[j] = val & 0xff;
  23. }
  24. }
  25. // Create a VideoFrame and initialize the visible rect using
  26. // |FillPlaneWithPattern()|. For testing purpose, the VideoFrame should be
  27. // filled with varying values, which is different from
  28. // |VideoFrame::CreateColorFrame()| where the entrire VideoFrame is filled
  29. // with a given color.
  30. scoped_refptr<media::VideoFrame> CreateFrameWithPatternFilled(
  31. media::VideoPixelFormat format,
  32. const gfx::Size& coded_size,
  33. const gfx::Rect& visible_rect,
  34. const gfx::Size& natural_size,
  35. base::TimeDelta timestamp) {
  36. scoped_refptr<media::VideoFrame> frame(media::VideoFrame::CreateFrame(
  37. format, coded_size, visible_rect, natural_size, timestamp));
  38. FillPlaneWithPattern(frame->data(media::VideoFrame::kYPlane),
  39. frame->stride(media::VideoFrame::kYPlane),
  40. frame->visible_rect().size());
  41. FillPlaneWithPattern(
  42. frame->data(media::VideoFrame::kUPlane),
  43. frame->stride(media::VideoFrame::kUPlane),
  44. media::VideoFrame::PlaneSize(format, media::VideoFrame::kUPlane,
  45. frame->visible_rect().size()));
  46. FillPlaneWithPattern(
  47. frame->data(media::VideoFrame::kVPlane),
  48. frame->stride(media::VideoFrame::kVPlane),
  49. media::VideoFrame::PlaneSize(format, media::VideoFrame::kVPlane,
  50. frame->visible_rect().size()));
  51. return frame;
  52. }
  53. // Helper function used to verify the data in the coded region after copying the
  54. // visible region and padding the remaining area.
  55. bool VerifyPlanCopyWithPadding(const uint8_t* src,
  56. size_t src_stride,
  57. // Size of visible region.
  58. const gfx::Size& src_size,
  59. const uint8_t* dst,
  60. size_t dst_stride,
  61. // Coded size of |dst|.
  62. const gfx::Size& dst_size) {
  63. if (!src || !dst)
  64. return false;
  65. const size_t src_width = src_size.width();
  66. const size_t src_height = src_size.height();
  67. const size_t dst_width = dst_size.width();
  68. const size_t dst_height = dst_size.height();
  69. if (src_width > dst_width || src_width > src_stride ||
  70. src_height > dst_height || src_size.IsEmpty() || dst_size.IsEmpty())
  71. return false;
  72. const uint8_t *src_ptr = src, *dst_ptr = dst;
  73. for (size_t i = 0; i < src_height;
  74. ++i, src_ptr += src_stride, dst_ptr += dst_stride) {
  75. if (memcmp(src_ptr, dst_ptr, src_width))
  76. return false;
  77. for (size_t j = src_width; j < dst_width; ++j) {
  78. if (src_ptr[src_width - 1] != dst_ptr[j])
  79. return false;
  80. }
  81. }
  82. if (src_height < dst_height) {
  83. src_ptr = dst + (src_height - 1) * dst_stride;
  84. if (memcmp(src_ptr, dst_ptr, dst_width))
  85. return false;
  86. }
  87. return true;
  88. }
  89. bool VerifyCopyWithPadding(const media::VideoFrame& src_frame,
  90. const media::VideoFrame& dst_frame) {
  91. if (!src_frame.IsMappable() || !dst_frame.IsMappable() ||
  92. src_frame.visible_rect().size() != dst_frame.visible_rect().size())
  93. return false;
  94. if (!VerifyPlanCopyWithPadding(
  95. src_frame.visible_data(media::VideoFrame::kYPlane),
  96. src_frame.stride(media::VideoFrame::kYPlane),
  97. src_frame.visible_rect().size(),
  98. dst_frame.data(media::VideoFrame::kYPlane),
  99. dst_frame.stride(media::VideoFrame::kYPlane), dst_frame.coded_size()))
  100. return false;
  101. if (!VerifyPlanCopyWithPadding(
  102. src_frame.visible_data(media::VideoFrame::kUPlane),
  103. src_frame.stride(media::VideoFrame::kUPlane),
  104. media::VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420,
  105. media::VideoFrame::kUPlane,
  106. src_frame.visible_rect().size()),
  107. dst_frame.data(media::VideoFrame::kUPlane),
  108. dst_frame.stride(media::VideoFrame::kUPlane),
  109. media::VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420,
  110. media::VideoFrame::kUPlane,
  111. dst_frame.coded_size())))
  112. return false;
  113. if (!VerifyPlanCopyWithPadding(
  114. src_frame.visible_data(media::VideoFrame::kVPlane),
  115. src_frame.stride(media::VideoFrame::kVPlane),
  116. media::VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420,
  117. media::VideoFrame::kVPlane,
  118. src_frame.visible_rect().size()),
  119. dst_frame.data(media::VideoFrame::kVPlane),
  120. dst_frame.stride(media::VideoFrame::kVPlane),
  121. media::VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420,
  122. media::VideoFrame::kVPlane,
  123. dst_frame.coded_size())))
  124. return false;
  125. return true;
  126. }
  127. } // namespace
  128. namespace media {
  129. class VideoUtilTest : public testing::Test {
  130. public:
  131. VideoUtilTest()
  132. : height_(0),
  133. y_stride_(0),
  134. u_stride_(0),
  135. v_stride_(0) {
  136. }
  137. VideoUtilTest(const VideoUtilTest&) = delete;
  138. VideoUtilTest& operator=(const VideoUtilTest&) = delete;
  139. ~VideoUtilTest() override = default;
  140. void CreateSourceFrame(int width, int height,
  141. int y_stride, int u_stride, int v_stride) {
  142. EXPECT_GE(y_stride, width);
  143. EXPECT_GE(u_stride, width / 2);
  144. EXPECT_GE(v_stride, width / 2);
  145. height_ = height;
  146. y_stride_ = y_stride;
  147. u_stride_ = u_stride;
  148. v_stride_ = v_stride;
  149. y_plane_ = std::make_unique<uint8_t[]>(y_stride * height);
  150. u_plane_ = std::make_unique<uint8_t[]>(u_stride * height / 2);
  151. v_plane_ = std::make_unique<uint8_t[]>(v_stride * height / 2);
  152. }
  153. void CreateDestinationFrame(int width, int height) {
  154. gfx::Size size(width, height);
  155. destination_frame_ = VideoFrame::CreateFrame(
  156. PIXEL_FORMAT_I420, size, gfx::Rect(size), size, base::TimeDelta());
  157. }
  158. private:
  159. std::unique_ptr<uint8_t[]> y_plane_;
  160. std::unique_ptr<uint8_t[]> u_plane_;
  161. std::unique_ptr<uint8_t[]> v_plane_;
  162. int height_;
  163. int y_stride_;
  164. int u_stride_;
  165. int v_stride_;
  166. scoped_refptr<VideoFrame> destination_frame_;
  167. };
  168. namespace {
  169. uint8_t src6x4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
  170. 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
  171. // Target images, name pattern target_rotation_flipV_flipH.
  172. uint8_t* target6x4_0_n_n = src6x4;
  173. uint8_t target6x4_0_n_y[] = {5, 4, 3, 2, 1, 0, 11, 10, 9, 8, 7, 6,
  174. 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18};
  175. uint8_t target6x4_0_y_n[] = {18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17,
  176. 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5};
  177. uint8_t target6x4_0_y_y[] = {23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12,
  178. 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
  179. uint8_t target6x4_90_n_n[] = {255, 19, 13, 7, 1, 255, 255, 20, 14, 8, 2, 255,
  180. 255, 21, 15, 9, 3, 255, 255, 22, 16, 10, 4, 255};
  181. uint8_t target6x4_90_n_y[] = {255, 1, 7, 13, 19, 255, 255, 2, 8, 14, 20, 255,
  182. 255, 3, 9, 15, 21, 255, 255, 4, 10, 16, 22, 255};
  183. uint8_t target6x4_90_y_n[] = {255, 22, 16, 10, 4, 255, 255, 21, 15, 9, 3, 255,
  184. 255, 20, 14, 8, 2, 255, 255, 19, 13, 7, 1, 255};
  185. uint8_t target6x4_90_y_y[] = {255, 4, 10, 16, 22, 255, 255, 3, 9, 15, 21, 255,
  186. 255, 2, 8, 14, 20, 255, 255, 1, 7, 13, 19, 255};
  187. uint8_t* target6x4_180_n_n = target6x4_0_y_y;
  188. uint8_t* target6x4_180_n_y = target6x4_0_y_n;
  189. uint8_t* target6x4_180_y_n = target6x4_0_n_y;
  190. uint8_t* target6x4_180_y_y = target6x4_0_n_n;
  191. uint8_t* target6x4_270_n_n = target6x4_90_y_y;
  192. uint8_t* target6x4_270_n_y = target6x4_90_y_n;
  193. uint8_t* target6x4_270_y_n = target6x4_90_n_y;
  194. uint8_t* target6x4_270_y_y = target6x4_90_n_n;
  195. uint8_t src4x6[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
  196. 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
  197. uint8_t* target4x6_0_n_n = src4x6;
  198. uint8_t target4x6_0_n_y[] = {3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8,
  199. 15, 14, 13, 12, 19, 18, 17, 16, 23, 22, 21, 20};
  200. uint8_t target4x6_0_y_n[] = {20, 21, 22, 23, 16, 17, 18, 19, 12, 13, 14, 15,
  201. 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3};
  202. uint8_t target4x6_0_y_y[] = {23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12,
  203. 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
  204. uint8_t target4x6_90_n_n[] = {255, 255, 255, 255, 16, 12, 8, 4,
  205. 17, 13, 9, 5, 18, 14, 10, 6,
  206. 19, 15, 11, 7, 255, 255, 255, 255};
  207. uint8_t target4x6_90_n_y[] = {255, 255, 255, 255, 4, 8, 12, 16,
  208. 5, 9, 13, 17, 6, 10, 14, 18,
  209. 7, 11, 15, 19, 255, 255, 255, 255};
  210. uint8_t target4x6_90_y_n[] = {255, 255, 255, 255, 19, 15, 11, 7,
  211. 18, 14, 10, 6, 17, 13, 9, 5,
  212. 16, 12, 8, 4, 255, 255, 255, 255};
  213. uint8_t target4x6_90_y_y[] = {255, 255, 255, 255, 7, 11, 15, 19,
  214. 6, 10, 14, 18, 5, 9, 13, 17,
  215. 4, 8, 12, 16, 255, 255, 255, 255};
  216. uint8_t* target4x6_180_n_n = target4x6_0_y_y;
  217. uint8_t* target4x6_180_n_y = target4x6_0_y_n;
  218. uint8_t* target4x6_180_y_n = target4x6_0_n_y;
  219. uint8_t* target4x6_180_y_y = target4x6_0_n_n;
  220. uint8_t* target4x6_270_n_n = target4x6_90_y_y;
  221. uint8_t* target4x6_270_n_y = target4x6_90_y_n;
  222. uint8_t* target4x6_270_y_n = target4x6_90_n_y;
  223. uint8_t* target4x6_270_y_y = target4x6_90_n_n;
  224. struct VideoRotationTestData {
  225. uint8_t* src;
  226. uint8_t* target;
  227. int width;
  228. int height;
  229. int rotation;
  230. bool flip_vert;
  231. bool flip_horiz;
  232. };
  233. const VideoRotationTestData kVideoRotationTestData[] = {
  234. { src6x4, target6x4_0_n_n, 6, 4, 0, false, false },
  235. { src6x4, target6x4_0_n_y, 6, 4, 0, false, true },
  236. { src6x4, target6x4_0_y_n, 6, 4, 0, true, false },
  237. { src6x4, target6x4_0_y_y, 6, 4, 0, true, true },
  238. { src6x4, target6x4_90_n_n, 6, 4, 90, false, false },
  239. { src6x4, target6x4_90_n_y, 6, 4, 90, false, true },
  240. { src6x4, target6x4_90_y_n, 6, 4, 90, true, false },
  241. { src6x4, target6x4_90_y_y, 6, 4, 90, true, true },
  242. { src6x4, target6x4_180_n_n, 6, 4, 180, false, false },
  243. { src6x4, target6x4_180_n_y, 6, 4, 180, false, true },
  244. { src6x4, target6x4_180_y_n, 6, 4, 180, true, false },
  245. { src6x4, target6x4_180_y_y, 6, 4, 180, true, true },
  246. { src6x4, target6x4_270_n_n, 6, 4, 270, false, false },
  247. { src6x4, target6x4_270_n_y, 6, 4, 270, false, true },
  248. { src6x4, target6x4_270_y_n, 6, 4, 270, true, false },
  249. { src6x4, target6x4_270_y_y, 6, 4, 270, true, true },
  250. { src4x6, target4x6_0_n_n, 4, 6, 0, false, false },
  251. { src4x6, target4x6_0_n_y, 4, 6, 0, false, true },
  252. { src4x6, target4x6_0_y_n, 4, 6, 0, true, false },
  253. { src4x6, target4x6_0_y_y, 4, 6, 0, true, true },
  254. { src4x6, target4x6_90_n_n, 4, 6, 90, false, false },
  255. { src4x6, target4x6_90_n_y, 4, 6, 90, false, true },
  256. { src4x6, target4x6_90_y_n, 4, 6, 90, true, false },
  257. { src4x6, target4x6_90_y_y, 4, 6, 90, true, true },
  258. { src4x6, target4x6_180_n_n, 4, 6, 180, false, false },
  259. { src4x6, target4x6_180_n_y, 4, 6, 180, false, true },
  260. { src4x6, target4x6_180_y_n, 4, 6, 180, true, false },
  261. { src4x6, target4x6_180_y_y, 4, 6, 180, true, true },
  262. { src4x6, target4x6_270_n_n, 4, 6, 270, false, false },
  263. { src4x6, target4x6_270_n_y, 4, 6, 270, false, true },
  264. { src4x6, target4x6_270_y_n, 4, 6, 270, true, false },
  265. { src4x6, target4x6_270_y_y, 4, 6, 270, true, true }
  266. };
  267. } // namespace
  268. class VideoUtilRotationTest
  269. : public testing::TestWithParam<VideoRotationTestData> {
  270. public:
  271. VideoUtilRotationTest() {
  272. dest_ = std::make_unique<uint8_t[]>(GetParam().width * GetParam().height);
  273. }
  274. VideoUtilRotationTest(const VideoUtilRotationTest&) = delete;
  275. VideoUtilRotationTest& operator=(const VideoUtilRotationTest&) = delete;
  276. ~VideoUtilRotationTest() override = default;
  277. uint8_t* dest_plane() { return dest_.get(); }
  278. private:
  279. std::unique_ptr<uint8_t[]> dest_;
  280. };
  281. TEST_P(VideoUtilRotationTest, Rotate) {
  282. int rotation = GetParam().rotation;
  283. EXPECT_TRUE((rotation >= 0) && (rotation < 360) && (rotation % 90 == 0));
  284. int size = GetParam().width * GetParam().height;
  285. uint8_t* dest = dest_plane();
  286. memset(dest, 255, size);
  287. RotatePlaneByPixels(GetParam().src, dest, GetParam().width,
  288. GetParam().height, rotation,
  289. GetParam().flip_vert, GetParam().flip_horiz);
  290. EXPECT_EQ(memcmp(dest, GetParam().target, size), 0);
  291. }
  292. INSTANTIATE_TEST_SUITE_P(All,
  293. VideoUtilRotationTest,
  294. testing::ValuesIn(kVideoRotationTestData));
  295. // Tests the ComputeLetterboxRegion function. Also, because of shared code
  296. // internally, this also tests ScaleSizeToFitWithinTarget().
  297. TEST_F(VideoUtilTest, ComputeLetterboxRegion) {
  298. EXPECT_EQ(gfx::Rect(166, 0, 667, 500),
  299. ComputeLetterboxRegion(gfx::Rect(0, 0, 1000, 500),
  300. gfx::Size(640, 480)));
  301. EXPECT_EQ(gfx::Rect(0, 312, 500, 375),
  302. ComputeLetterboxRegion(gfx::Rect(0, 0, 500, 1000),
  303. gfx::Size(640, 480)));
  304. EXPECT_EQ(gfx::Rect(55, 0, 889, 500),
  305. ComputeLetterboxRegion(gfx::Rect(0, 0, 1000, 500),
  306. gfx::Size(1920, 1080)));
  307. EXPECT_EQ(gfx::Rect(0, 12, 100, 75),
  308. ComputeLetterboxRegion(gfx::Rect(0, 0, 100, 100),
  309. gfx::Size(400, 300)));
  310. EXPECT_EQ(gfx::Rect(0, 250000000, 2000000000, 1500000000),
  311. ComputeLetterboxRegion(gfx::Rect(0, 0, 2000000000, 2000000000),
  312. gfx::Size(40000, 30000)));
  313. EXPECT_TRUE(ComputeLetterboxRegion(gfx::Rect(0, 0, 2000000000, 2000000000),
  314. gfx::Size(0, 0)).IsEmpty());
  315. // Some operations in the internal ScaleSizeToTarget() use rounded division
  316. // and might lose some precision, this expectation codifies that.
  317. EXPECT_EQ(
  318. gfx::Rect(0, 0, 1279, 720),
  319. ComputeLetterboxRegion(gfx::Rect(0, 0, 1280, 720), gfx::Size(1057, 595)));
  320. }
  321. // Tests the ComputeLetterboxRegionForI420 function.
  322. TEST_F(VideoUtilTest, ComputeLetterboxRegionForI420) {
  323. // Note: These are the same trials as in VideoUtilTest.ComputeLetterboxRegion
  324. // above, except that Rect coordinates are nudged into even-numbered values.
  325. EXPECT_EQ(gfx::Rect(166, 0, 666, 500),
  326. ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 1000, 500),
  327. gfx::Size(640, 480)));
  328. EXPECT_EQ(gfx::Rect(0, 312, 500, 374),
  329. ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 500, 1000),
  330. gfx::Size(640, 480)));
  331. EXPECT_EQ(gfx::Rect(54, 0, 890, 500),
  332. ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 1000, 500),
  333. gfx::Size(1920, 1080)));
  334. EXPECT_EQ(gfx::Rect(0, 12, 100, 74),
  335. ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 100, 100),
  336. gfx::Size(400, 300)));
  337. EXPECT_EQ(
  338. gfx::Rect(0, 250000000, 2000000000, 1500000000),
  339. ComputeLetterboxRegionForI420(gfx::Rect(0, 0, 2000000000, 2000000000),
  340. gfx::Size(40000, 30000)));
  341. EXPECT_TRUE(ComputeLetterboxRegionForI420(
  342. gfx::Rect(0, 0, 2000000000, 2000000000), gfx::Size(0, 0))
  343. .IsEmpty());
  344. }
  345. // Tests the MinimallyShrinkRectForI420 function.
  346. TEST_F(VideoUtilTest, MinimallyShrinkRectForI420) {
  347. // A few no-ops:
  348. EXPECT_EQ(gfx::Rect(2, 2, 100, 100),
  349. MinimallyShrinkRectForI420(gfx::Rect(2, 2, 100, 100)));
  350. EXPECT_EQ(gfx::Rect(2, -2, 100, 100),
  351. MinimallyShrinkRectForI420(gfx::Rect(2, -2, 100, 100)));
  352. EXPECT_EQ(gfx::Rect(-2, 2, 100, 100),
  353. MinimallyShrinkRectForI420(gfx::Rect(-2, 2, 100, 100)));
  354. // Origin has odd coordinates:
  355. EXPECT_EQ(gfx::Rect(2, 2, 98, 98),
  356. MinimallyShrinkRectForI420(gfx::Rect(1, 1, 100, 100)));
  357. EXPECT_EQ(gfx::Rect(0, 2, 98, 98),
  358. MinimallyShrinkRectForI420(gfx::Rect(-1, 1, 100, 100)));
  359. EXPECT_EQ(gfx::Rect(2, 0, 98, 98),
  360. MinimallyShrinkRectForI420(gfx::Rect(1, -1, 100, 100)));
  361. // Size is odd:
  362. EXPECT_EQ(gfx::Rect(2, 2, 98, 98),
  363. MinimallyShrinkRectForI420(gfx::Rect(2, 2, 99, 99)));
  364. EXPECT_EQ(gfx::Rect(-2, 2, 98, 98),
  365. MinimallyShrinkRectForI420(gfx::Rect(-2, 2, 99, 99)));
  366. EXPECT_EQ(gfx::Rect(2, -2, 98, 98),
  367. MinimallyShrinkRectForI420(gfx::Rect(2, -2, 99, 99)));
  368. // Both are odd:
  369. EXPECT_EQ(gfx::Rect(2, 2, 98, 98),
  370. MinimallyShrinkRectForI420(gfx::Rect(1, 1, 99, 99)));
  371. EXPECT_EQ(gfx::Rect(0, 2, 98, 98),
  372. MinimallyShrinkRectForI420(gfx::Rect(-1, 1, 99, 99)));
  373. EXPECT_EQ(gfx::Rect(2, 0, 98, 98),
  374. MinimallyShrinkRectForI420(gfx::Rect(1, -1, 99, 99)));
  375. // Check the biggest rectangle that the function will accept:
  376. constexpr int kMinDimension = -1 * limits::kMaxDimension;
  377. if (limits::kMaxDimension % 2 == 0) {
  378. EXPECT_EQ(gfx::Rect(kMinDimension, kMinDimension, 2 * limits::kMaxDimension,
  379. 2 * limits::kMaxDimension),
  380. MinimallyShrinkRectForI420(gfx::Rect(kMinDimension, kMinDimension,
  381. 2 * limits::kMaxDimension,
  382. 2 * limits::kMaxDimension)));
  383. } else {
  384. EXPECT_EQ(
  385. gfx::Rect(kMinDimension + 1, kMinDimension + 1,
  386. 2 * limits::kMaxDimension - 2, 2 * limits::kMaxDimension - 2),
  387. MinimallyShrinkRectForI420(gfx::Rect(kMinDimension, kMinDimension,
  388. 2 * limits::kMaxDimension,
  389. 2 * limits::kMaxDimension)));
  390. }
  391. }
  392. TEST_F(VideoUtilTest, ScaleSizeToEncompassTarget) {
  393. EXPECT_EQ(gfx::Size(1000, 750),
  394. ScaleSizeToEncompassTarget(gfx::Size(640, 480),
  395. gfx::Size(1000, 500)));
  396. EXPECT_EQ(gfx::Size(1333, 1000),
  397. ScaleSizeToEncompassTarget(gfx::Size(640, 480),
  398. gfx::Size(500, 1000)));
  399. EXPECT_EQ(gfx::Size(1000, 563),
  400. ScaleSizeToEncompassTarget(gfx::Size(1920, 1080),
  401. gfx::Size(1000, 500)));
  402. EXPECT_EQ(gfx::Size(133, 100),
  403. ScaleSizeToEncompassTarget(gfx::Size(400, 300),
  404. gfx::Size(100, 100)));
  405. EXPECT_EQ(gfx::Size(266666667, 200000000),
  406. ScaleSizeToEncompassTarget(gfx::Size(40000, 30000),
  407. gfx::Size(200000000, 200000000)));
  408. EXPECT_TRUE(ScaleSizeToEncompassTarget(
  409. gfx::Size(0, 0), gfx::Size(2000000000, 2000000000)).IsEmpty());
  410. }
  411. TEST_F(VideoUtilTest, CropSizeForScalingToTarget) {
  412. // Test same aspect ratios.
  413. EXPECT_EQ(gfx::Rect(0, 0, 640, 360),
  414. CropSizeForScalingToTarget(gfx::Size(640, 360), gfx::Size(16, 9)));
  415. EXPECT_EQ(gfx::Rect(0, 0, 320, 240),
  416. CropSizeForScalingToTarget(gfx::Size(320, 240), gfx::Size(4, 3)));
  417. EXPECT_EQ(
  418. gfx::Rect(0, 0, 320, 240),
  419. CropSizeForScalingToTarget(gfx::Size(321, 241), gfx::Size(4, 3), 2));
  420. // Test cropping 4:3 from 16:9.
  421. EXPECT_EQ(gfx::Rect(80, 0, 480, 360),
  422. CropSizeForScalingToTarget(gfx::Size(640, 360), gfx::Size(4, 3)));
  423. EXPECT_EQ(gfx::Rect(53, 0, 320, 240),
  424. CropSizeForScalingToTarget(gfx::Size(426, 240), gfx::Size(4, 3)));
  425. EXPECT_EQ(
  426. gfx::Rect(52, 0, 320, 240),
  427. CropSizeForScalingToTarget(gfx::Size(426, 240), gfx::Size(4, 3), 2));
  428. // Test cropping 16:9 from 4:3.
  429. EXPECT_EQ(gfx::Rect(0, 30, 320, 180),
  430. CropSizeForScalingToTarget(gfx::Size(320, 240), gfx::Size(16, 9)));
  431. EXPECT_EQ(gfx::Rect(0, 9, 96, 54),
  432. CropSizeForScalingToTarget(gfx::Size(96, 72), gfx::Size(16, 9)));
  433. EXPECT_EQ(gfx::Rect(0, 8, 96, 54),
  434. CropSizeForScalingToTarget(gfx::Size(96, 72), gfx::Size(16, 9), 2));
  435. // Test abnormal inputs.
  436. EXPECT_EQ(gfx::Rect(),
  437. CropSizeForScalingToTarget(gfx::Size(0, 1), gfx::Size(1, 1)));
  438. EXPECT_EQ(gfx::Rect(),
  439. CropSizeForScalingToTarget(gfx::Size(1, 0), gfx::Size(1, 1)));
  440. EXPECT_EQ(gfx::Rect(),
  441. CropSizeForScalingToTarget(gfx::Size(1, 1), gfx::Size(0, 1)));
  442. EXPECT_EQ(gfx::Rect(),
  443. CropSizeForScalingToTarget(gfx::Size(1, 1), gfx::Size(1, 0)));
  444. }
  445. TEST_F(VideoUtilTest, PadToMatchAspectRatio) {
  446. EXPECT_EQ(gfx::Size(640, 480),
  447. PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(640, 480)));
  448. EXPECT_EQ(gfx::Size(640, 480),
  449. PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(4, 3)));
  450. EXPECT_EQ(gfx::Size(960, 480),
  451. PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(1000, 500)));
  452. EXPECT_EQ(gfx::Size(640, 1280),
  453. PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(500, 1000)));
  454. EXPECT_EQ(gfx::Size(2160, 1080),
  455. PadToMatchAspectRatio(gfx::Size(1920, 1080), gfx::Size(1000, 500)));
  456. EXPECT_EQ(gfx::Size(400, 400),
  457. PadToMatchAspectRatio(gfx::Size(400, 300), gfx::Size(100, 100)));
  458. EXPECT_EQ(gfx::Size(400, 400),
  459. PadToMatchAspectRatio(gfx::Size(300, 400), gfx::Size(100, 100)));
  460. EXPECT_EQ(gfx::Size(40000, 40000),
  461. PadToMatchAspectRatio(gfx::Size(40000, 30000),
  462. gfx::Size(2000000000, 2000000000)));
  463. EXPECT_TRUE(PadToMatchAspectRatio(
  464. gfx::Size(40000, 30000), gfx::Size(0, 0)).IsEmpty());
  465. }
  466. TEST_F(VideoUtilTest, LetterboxVideoFrame) {
  467. int width = 40;
  468. int height = 30;
  469. gfx::Size size(width, height);
  470. scoped_refptr<VideoFrame> frame(VideoFrame::CreateFrame(
  471. PIXEL_FORMAT_I420, size, gfx::Rect(size), size, base::TimeDelta()));
  472. for (int left_margin = 0; left_margin <= 10; left_margin += 10) {
  473. for (int right_margin = 0; right_margin <= 10; right_margin += 10) {
  474. for (int top_margin = 0; top_margin <= 10; top_margin += 10) {
  475. for (int bottom_margin = 0; bottom_margin <= 10; bottom_margin += 10) {
  476. gfx::Rect view_area(left_margin, top_margin,
  477. width - left_margin - right_margin,
  478. height - top_margin - bottom_margin);
  479. FillYUV(frame.get(), 0x1, 0x2, 0x3);
  480. LetterboxVideoFrame(frame.get(), view_area);
  481. for (int x = 0; x < width; x++) {
  482. for (int y = 0; y < height; y++) {
  483. bool inside = x >= view_area.x() &&
  484. x < view_area.x() + view_area.width() &&
  485. y >= view_area.y() &&
  486. y < view_area.y() + view_area.height();
  487. EXPECT_EQ(frame->data(VideoFrame::kYPlane)[
  488. y * frame->stride(VideoFrame::kYPlane) + x],
  489. inside ? 0x01 : 0x00);
  490. EXPECT_EQ(frame->data(VideoFrame::kUPlane)[
  491. (y / 2) * frame->stride(VideoFrame::kUPlane) + (x / 2)],
  492. inside ? 0x02 : 0x80);
  493. EXPECT_EQ(frame->data(VideoFrame::kVPlane)[
  494. (y / 2) * frame->stride(VideoFrame::kVPlane) + (x / 2)],
  495. inside ? 0x03 : 0x80);
  496. }
  497. }
  498. }
  499. }
  500. }
  501. }
  502. }
  503. TEST_F(VideoUtilTest, I420CopyWithPadding) {
  504. gfx::Size visible_size(40, 30);
  505. scoped_refptr<VideoFrame> src_frame = CreateFrameWithPatternFilled(
  506. PIXEL_FORMAT_I420, visible_size, gfx::Rect(visible_size), visible_size,
  507. base::TimeDelta());
  508. // Expect to return false when copying to an empty buffer.
  509. EXPECT_FALSE(I420CopyWithPadding(*src_frame, nullptr));
  510. scoped_refptr<VideoFrame> dst_frame = CreateFrameWithPatternFilled(
  511. PIXEL_FORMAT_I420, visible_size, gfx::Rect(visible_size), visible_size,
  512. base::TimeDelta());
  513. EXPECT_TRUE(I420CopyWithPadding(*src_frame, dst_frame.get()));
  514. EXPECT_TRUE(VerifyCopyWithPadding(*src_frame, *dst_frame));
  515. gfx::Size coded_size(60, 40);
  516. dst_frame = CreateFrameWithPatternFilled(PIXEL_FORMAT_I420, coded_size,
  517. gfx::Rect(visible_size), coded_size,
  518. base::TimeDelta());
  519. EXPECT_TRUE(I420CopyWithPadding(*src_frame, dst_frame.get()));
  520. EXPECT_TRUE(VerifyCopyWithPadding(*src_frame, *dst_frame));
  521. gfx::Size odd_size(39, 31);
  522. src_frame = CreateFrameWithPatternFilled(PIXEL_FORMAT_I420, odd_size,
  523. gfx::Rect(odd_size), odd_size,
  524. base::TimeDelta());
  525. dst_frame = CreateFrameWithPatternFilled(PIXEL_FORMAT_I420, coded_size,
  526. gfx::Rect(odd_size), coded_size,
  527. base::TimeDelta());
  528. EXPECT_TRUE(I420CopyWithPadding(*src_frame, dst_frame.get()));
  529. EXPECT_TRUE(VerifyCopyWithPadding(*src_frame, *dst_frame));
  530. }
  531. TEST_F(VideoUtilTest, WrapAsI420VideoFrame) {
  532. gfx::Size size(640, 480);
  533. scoped_refptr<VideoFrame> src_frame = VideoFrame::CreateFrame(
  534. PIXEL_FORMAT_I420A, size, gfx::Rect(size), size, base::Days(1));
  535. scoped_refptr<VideoFrame> dst_frame = WrapAsI420VideoFrame(src_frame);
  536. EXPECT_EQ(dst_frame->format(), PIXEL_FORMAT_I420);
  537. EXPECT_EQ(dst_frame->timestamp(), src_frame->timestamp());
  538. EXPECT_EQ(dst_frame->coded_size(), src_frame->coded_size());
  539. EXPECT_EQ(dst_frame->visible_rect(), src_frame->visible_rect());
  540. EXPECT_EQ(dst_frame->natural_size(), src_frame->natural_size());
  541. std::vector<size_t> planes = {VideoFrame::kYPlane, VideoFrame::kUPlane,
  542. VideoFrame::kVPlane};
  543. for (auto plane : planes)
  544. EXPECT_EQ(dst_frame->data(plane), src_frame->data(plane));
  545. // Check that memory for planes is not released upon destruction of the
  546. // original frame pointer (new frame holds a reference). This check relies on
  547. // ASAN.
  548. src_frame.reset();
  549. for (auto plane : planes)
  550. memset(dst_frame->data(plane), 1, dst_frame->stride(plane));
  551. }
  552. } // namespace media