paint_canvas_video_renderer_unittest.cc 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418
  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 <GLES3/gl3.h>
  5. #include <stdint.h>
  6. #include "base/bind.h"
  7. #include "base/logging.h"
  8. #include "base/memory/aligned_memory.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/sys_byteorder.h"
  11. #include "base/test/task_environment.h"
  12. #include "build/build_config.h"
  13. #include "cc/paint/paint_flags.h"
  14. #include "cc/paint/skia_paint_canvas.h"
  15. #include "components/viz/common/gpu/context_provider.h"
  16. #include "components/viz/test/test_context_provider.h"
  17. #include "components/viz/test/test_gpu_service_holder.h"
  18. #include "components/viz/test/test_in_process_context_provider.h"
  19. #include "gpu/GLES2/gl2extchromium.h"
  20. #include "gpu/command_buffer/client/gles2_interface_stub.h"
  21. #include "gpu/command_buffer/common/capabilities.h"
  22. #include "gpu/command_buffer/common/shared_image_usage.h"
  23. #include "gpu/config/gpu_feature_info.h"
  24. #include "media/base/timestamp_constants.h"
  25. #include "media/base/video_frame.h"
  26. #include "media/base/video_util.h"
  27. #include "media/renderers/paint_canvas_video_renderer.h"
  28. #include "media/renderers/shared_image_video_frame_test_utils.h"
  29. #include "testing/gtest/include/gtest/gtest.h"
  30. #include "third_party/libyuv/include/libyuv/convert.h"
  31. #include "third_party/libyuv/include/libyuv/scale.h"
  32. #include "third_party/skia/include/core/SkColorPriv.h"
  33. #include "third_party/skia/include/core/SkImage.h"
  34. #include "third_party/skia/include/core/SkRefCnt.h"
  35. #include "third_party/skia/include/core/SkSurface.h"
  36. #include "third_party/skia/include/gpu/GrDirectContext.h"
  37. #include "ui/gfx/color_space.h"
  38. #include "ui/gfx/geometry/rect_f.h"
  39. #include "ui/gl/gl_implementation.h"
  40. #include "ui/gl/test/gl_surface_test_support.h"
  41. using media::VideoFrame;
  42. namespace media {
  43. static const int kWidth = 320;
  44. static const int kHeight = 240;
  45. static const gfx::RectF kNaturalRect(kWidth, kHeight);
  46. // Generate frame pixels to provided |external_memory| and wrap it as frame.
  47. scoped_refptr<VideoFrame> CreateTestY16Frame(const gfx::Size& coded_size,
  48. const gfx::Rect& visible_rect,
  49. void* external_memory,
  50. base::TimeDelta timestamp) {
  51. const int offset_x = visible_rect.x();
  52. const int offset_y = visible_rect.y();
  53. const int stride = coded_size.width();
  54. const size_t byte_size = stride * coded_size.height() * 2;
  55. // In the visible rect, fill upper byte with [0-255] and lower with [255-0].
  56. uint16_t* data = static_cast<uint16_t*>(external_memory);
  57. for (int j = 0; j < visible_rect.height(); j++) {
  58. for (int i = 0; i < visible_rect.width(); i++) {
  59. const int value = i + j * visible_rect.width();
  60. data[(stride * (j + offset_y)) + i + offset_x] =
  61. ((value & 0xFF) << 8) | (~value & 0xFF);
  62. }
  63. }
  64. return media::VideoFrame::WrapExternalData(
  65. media::PIXEL_FORMAT_Y16, coded_size, visible_rect, visible_rect.size(),
  66. static_cast<uint8_t*>(external_memory), byte_size, timestamp);
  67. }
  68. // Readback the contents of a RGBA texture into an array of RGBA values.
  69. static std::unique_ptr<uint8_t[]> ReadbackTexture(
  70. gpu::gles2::GLES2Interface* gl,
  71. GLuint texture,
  72. const gfx::Size& size) {
  73. size_t pixel_count = size.width() * size.height();
  74. GLuint fbo = 0;
  75. gl->GenFramebuffers(1, &fbo);
  76. gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
  77. gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
  78. texture, 0);
  79. auto pixels = std::make_unique<uint8_t[]>(pixel_count * 4);
  80. uint8_t* raw_pixels = pixels.get();
  81. gl->ReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE,
  82. raw_pixels);
  83. gl->DeleteFramebuffers(1, &fbo);
  84. return pixels;
  85. }
  86. // Returns a functor that retrieves a SkColor for a given pixel, from raw RGBA
  87. // data.
  88. static auto ColorGetter(uint8_t* pixels, const gfx::Size& size) {
  89. return [pixels, size](size_t x, size_t y) {
  90. uint8_t* p = pixels + (size.width() * y + x) * 4;
  91. return SkColorSetARGB(p[3], p[0], p[1], p[2]);
  92. };
  93. }
  94. class PaintCanvasVideoRendererTest : public testing::Test {
  95. public:
  96. enum Color {
  97. kNone,
  98. kRed,
  99. kGreen,
  100. kBlue,
  101. };
  102. PaintCanvasVideoRendererTest();
  103. PaintCanvasVideoRendererTest(const PaintCanvasVideoRendererTest&) = delete;
  104. PaintCanvasVideoRendererTest& operator=(const PaintCanvasVideoRendererTest&) =
  105. delete;
  106. ~PaintCanvasVideoRendererTest() override;
  107. // Paints to |canvas| using |renderer_| without any frame data.
  108. void PaintWithoutFrame(cc::PaintCanvas* canvas);
  109. // Paints the |video_frame| to the |canvas| using |renderer_|, setting the
  110. // color of |video_frame| to |color| first.
  111. void Paint(scoped_refptr<VideoFrame> video_frame,
  112. cc::PaintCanvas* canvas,
  113. Color color);
  114. void PaintRotated(scoped_refptr<VideoFrame> video_frame,
  115. cc::PaintCanvas* canvas,
  116. const gfx::RectF& dest_rect,
  117. Color color,
  118. SkBlendMode mode,
  119. VideoTransformation video_transformation);
  120. void Copy(scoped_refptr<VideoFrame> video_frame, cc::PaintCanvas* canvas);
  121. // Getters for various frame sizes.
  122. scoped_refptr<VideoFrame> natural_frame() { return natural_frame_; }
  123. scoped_refptr<VideoFrame> larger_frame() { return larger_frame_; }
  124. scoped_refptr<VideoFrame> smaller_frame() { return smaller_frame_; }
  125. scoped_refptr<VideoFrame> cropped_frame() { return cropped_frame_; }
  126. // Standard canvas.
  127. cc::PaintCanvas* target_canvas() { return &target_canvas_; }
  128. SkBitmap* bitmap() { return &bitmap_; }
  129. protected:
  130. PaintCanvasVideoRenderer renderer_;
  131. scoped_refptr<VideoFrame> natural_frame_;
  132. scoped_refptr<VideoFrame> larger_frame_;
  133. scoped_refptr<VideoFrame> smaller_frame_;
  134. scoped_refptr<VideoFrame> cropped_frame_;
  135. SkBitmap bitmap_;
  136. cc::SkiaPaintCanvas target_canvas_;
  137. base::test::TaskEnvironment task_environment_;
  138. };
  139. static SkBitmap AllocBitmap(int width, int height) {
  140. SkBitmap bitmap;
  141. bitmap.allocPixels(SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType));
  142. bitmap.eraseColor(0);
  143. return bitmap;
  144. }
  145. static scoped_refptr<VideoFrame> CreateCroppedFrame() {
  146. scoped_refptr<VideoFrame> cropped_frame = VideoFrame::CreateFrame(
  147. PIXEL_FORMAT_I420, gfx::Size(16, 16), gfx::Rect(6, 6, 8, 6),
  148. gfx::Size(8, 6), base::Milliseconds(4));
  149. // Make sure the cropped video frame's aspect ratio matches the output device.
  150. // Update cropped_frame_'s crop dimensions if this is not the case.
  151. EXPECT_EQ(cropped_frame->visible_rect().width() * kHeight,
  152. cropped_frame->visible_rect().height() * kWidth);
  153. // Fill in the cropped frame's entire data with colors:
  154. //
  155. // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
  156. // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
  157. // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
  158. // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
  159. // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
  160. // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
  161. // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
  162. // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
  163. // G G G G G G G G B B B B B B B B
  164. // G G G G G G G G B B B B B B B B
  165. // G G G G G G G G B B B B B B B B
  166. // G G G G G G G G B B B B B B B B
  167. // G G G G G G G G B B B B B B B B
  168. // G G G G G G G G B B B B B B B B
  169. // G G G G G G G G B B B B B B B B
  170. // G G G G G G G G B B B B B B B B
  171. //
  172. // The visible crop of the frame (as set by its visible_rect_) has contents:
  173. //
  174. // Bl Bl R R R R R R
  175. // Bl Bl R R R R R R
  176. // G G B B B B B B
  177. // G G B B B B B B
  178. // G G B B B B B B
  179. // G G B B B B B B
  180. //
  181. // Each color region in the cropped frame is on a 2x2 block granularity, to
  182. // avoid sharing UV samples between regions.
  183. static const uint8_t cropped_y_plane[] = {
  184. 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
  185. 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
  186. 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
  187. 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
  188. 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
  189. 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
  190. 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
  191. 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
  192. 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
  193. 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
  194. 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
  195. 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
  196. 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
  197. 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
  198. 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
  199. 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
  200. };
  201. static const uint8_t cropped_u_plane[] = {
  202. 128, 128, 128, 128, 84, 84, 84, 84, 128, 128, 128, 128, 84,
  203. 84, 84, 84, 128, 128, 128, 128, 84, 84, 84, 84, 128, 128,
  204. 128, 128, 84, 84, 84, 84, 43, 43, 43, 43, 255, 255, 255,
  205. 255, 43, 43, 43, 43, 255, 255, 255, 255, 43, 43, 43, 43,
  206. 255, 255, 255, 255, 43, 43, 43, 43, 255, 255, 255, 255,
  207. };
  208. static const uint8_t cropped_v_plane[] = {
  209. 128, 128, 128, 128, 255, 255, 255, 255, 128, 128, 128, 128, 255,
  210. 255, 255, 255, 128, 128, 128, 128, 255, 255, 255, 255, 128, 128,
  211. 128, 128, 255, 255, 255, 255, 21, 21, 21, 21, 107, 107, 107,
  212. 107, 21, 21, 21, 21, 107, 107, 107, 107, 21, 21, 21, 21,
  213. 107, 107, 107, 107, 21, 21, 21, 21, 107, 107, 107, 107,
  214. };
  215. libyuv::I420Copy(cropped_y_plane, 16, cropped_u_plane, 8, cropped_v_plane, 8,
  216. cropped_frame->data(VideoFrame::kYPlane),
  217. cropped_frame->stride(VideoFrame::kYPlane),
  218. cropped_frame->data(VideoFrame::kUPlane),
  219. cropped_frame->stride(VideoFrame::kUPlane),
  220. cropped_frame->data(VideoFrame::kVPlane),
  221. cropped_frame->stride(VideoFrame::kVPlane), 16, 16);
  222. return cropped_frame;
  223. }
  224. PaintCanvasVideoRendererTest::PaintCanvasVideoRendererTest()
  225. : natural_frame_(VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight))),
  226. larger_frame_(
  227. VideoFrame::CreateBlackFrame(gfx::Size(kWidth * 2, kHeight * 2))),
  228. smaller_frame_(
  229. VideoFrame::CreateBlackFrame(gfx::Size(kWidth / 2, kHeight / 2))),
  230. cropped_frame_(CreateCroppedFrame()),
  231. bitmap_(AllocBitmap(kWidth, kHeight)),
  232. target_canvas_(bitmap_) {
  233. // Give each frame a unique timestamp.
  234. natural_frame_->set_timestamp(base::Milliseconds(1));
  235. larger_frame_->set_timestamp(base::Milliseconds(2));
  236. smaller_frame_->set_timestamp(base::Milliseconds(3));
  237. }
  238. PaintCanvasVideoRendererTest::~PaintCanvasVideoRendererTest() = default;
  239. void PaintCanvasVideoRendererTest::PaintWithoutFrame(cc::PaintCanvas* canvas) {
  240. cc::PaintFlags flags;
  241. flags.setFilterQuality(cc::PaintFlags::FilterQuality::kLow);
  242. renderer_.Paint(nullptr, canvas, kNaturalRect, flags, kNoTransformation,
  243. nullptr);
  244. }
  245. void PaintCanvasVideoRendererTest::Paint(scoped_refptr<VideoFrame> video_frame,
  246. cc::PaintCanvas* canvas,
  247. Color color) {
  248. PaintRotated(std::move(video_frame), canvas, kNaturalRect, color,
  249. SkBlendMode::kSrcOver, kNoTransformation);
  250. }
  251. void PaintCanvasVideoRendererTest::PaintRotated(
  252. scoped_refptr<VideoFrame> video_frame,
  253. cc::PaintCanvas* canvas,
  254. const gfx::RectF& dest_rect,
  255. Color color,
  256. SkBlendMode mode,
  257. VideoTransformation video_transformation) {
  258. switch (color) {
  259. case kNone:
  260. break;
  261. case kRed:
  262. media::FillYUV(video_frame.get(), 76, 84, 255);
  263. break;
  264. case kGreen:
  265. media::FillYUV(video_frame.get(), 149, 43, 21);
  266. break;
  267. case kBlue:
  268. media::FillYUV(video_frame.get(), 29, 255, 107);
  269. break;
  270. }
  271. cc::PaintFlags flags;
  272. flags.setBlendMode(mode);
  273. flags.setFilterQuality(cc::PaintFlags::FilterQuality::kLow);
  274. renderer_.Paint(std::move(video_frame), canvas, dest_rect, flags,
  275. video_transformation, nullptr);
  276. }
  277. void PaintCanvasVideoRendererTest::Copy(scoped_refptr<VideoFrame> video_frame,
  278. cc::PaintCanvas* canvas) {
  279. renderer_.Copy(std::move(video_frame), canvas, nullptr);
  280. }
  281. TEST_F(PaintCanvasVideoRendererTest, NoFrame) {
  282. // Test that black gets painted over canvas.
  283. target_canvas()->clear(SkColors::kRed);
  284. PaintWithoutFrame(target_canvas());
  285. EXPECT_EQ(SK_ColorBLACK, bitmap()->getColor(0, 0));
  286. }
  287. TEST_F(PaintCanvasVideoRendererTest, TransparentFrame) {
  288. target_canvas()->clear(SkColors::kRed);
  289. PaintRotated(
  290. VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)).get(),
  291. target_canvas(), kNaturalRect, kNone, SkBlendMode::kSrcOver,
  292. kNoTransformation);
  293. EXPECT_EQ(static_cast<SkColor>(SK_ColorRED), bitmap()->getColor(0, 0));
  294. }
  295. TEST_F(PaintCanvasVideoRendererTest, TransparentFrameSrcMode) {
  296. target_canvas()->clear(SkColors::kRed);
  297. // SRC mode completely overwrites the buffer.
  298. PaintRotated(
  299. VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)).get(),
  300. target_canvas(), kNaturalRect, kNone, SkBlendMode::kSrc,
  301. kNoTransformation);
  302. EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
  303. bitmap()->getColor(0, 0));
  304. }
  305. TEST_F(PaintCanvasVideoRendererTest, TransparentFrameSrcMode1x1) {
  306. target_canvas()->clear(SkColors::kRed);
  307. // SRC mode completely overwrites the buffer.
  308. auto frame = VideoFrame::CreateTransparentFrame(gfx::Size(1, 1));
  309. PaintRotated(frame.get(), target_canvas(), gfx::RectF(1, 1), kNone,
  310. SkBlendMode::kSrc, kNoTransformation);
  311. EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
  312. bitmap()->getColor(0, 0));
  313. }
  314. TEST_F(PaintCanvasVideoRendererTest, CopyTransparentFrame) {
  315. target_canvas()->clear(SkColors::kRed);
  316. Copy(VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)).get(),
  317. target_canvas());
  318. EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
  319. bitmap()->getColor(0, 0));
  320. }
  321. TEST_F(PaintCanvasVideoRendererTest, Natural) {
  322. Paint(natural_frame(), target_canvas(), kRed);
  323. EXPECT_EQ(SK_ColorRED, bitmap()->getColor(0, 0));
  324. }
  325. TEST_F(PaintCanvasVideoRendererTest, Larger) {
  326. Paint(natural_frame(), target_canvas(), kRed);
  327. EXPECT_EQ(SK_ColorRED, bitmap()->getColor(0, 0));
  328. Paint(larger_frame(), target_canvas(), kBlue);
  329. EXPECT_EQ(SK_ColorBLUE, bitmap()->getColor(0, 0));
  330. }
  331. TEST_F(PaintCanvasVideoRendererTest, Smaller) {
  332. Paint(natural_frame(), target_canvas(), kRed);
  333. EXPECT_EQ(SK_ColorRED, bitmap()->getColor(0, 0));
  334. Paint(smaller_frame(), target_canvas(), kBlue);
  335. EXPECT_EQ(SK_ColorBLUE, bitmap()->getColor(0, 0));
  336. }
  337. TEST_F(PaintCanvasVideoRendererTest, NoTimestamp) {
  338. VideoFrame* video_frame = natural_frame().get();
  339. video_frame->set_timestamp(media::kNoTimestamp);
  340. Paint(video_frame, target_canvas(), kRed);
  341. EXPECT_EQ(SK_ColorRED, bitmap()->getColor(0, 0));
  342. }
  343. TEST_F(PaintCanvasVideoRendererTest, CroppedFrame) {
  344. Paint(cropped_frame(), target_canvas(), kNone);
  345. // Check the corners.
  346. EXPECT_EQ(SK_ColorBLACK, bitmap()->getColor(0, 0));
  347. EXPECT_EQ(SK_ColorRED, bitmap()->getColor(kWidth - 1, 0));
  348. EXPECT_EQ(SK_ColorGREEN, bitmap()->getColor(0, kHeight - 1));
  349. EXPECT_EQ(SK_ColorBLUE, bitmap()->getColor(kWidth - 1, kHeight - 1));
  350. // Check the interior along the border between color regions. Note that we're
  351. // bilinearly upscaling, so we'll need to take care to pick sample points that
  352. // are just outside the "zone of resampling".
  353. EXPECT_EQ(SK_ColorBLACK,
  354. bitmap()->getColor(kWidth * 1 / 8 - 1, kHeight * 1 / 6 - 1));
  355. EXPECT_EQ(SK_ColorRED,
  356. bitmap()->getColor(kWidth * 3 / 8, kHeight * 1 / 6 - 1));
  357. EXPECT_EQ(SK_ColorGREEN,
  358. bitmap()->getColor(kWidth * 1 / 8 - 1, kHeight * 3 / 6));
  359. EXPECT_EQ(SK_ColorBLUE, bitmap()->getColor(kWidth * 3 / 8, kHeight * 3 / 6));
  360. }
  361. uint32_t MaybeConvertABGRToARGB(uint32_t abgr) {
  362. #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
  363. SK_A32_SHIFT == 24
  364. return abgr;
  365. #else
  366. return (base::ByteSwap(abgr & 0x00FFFFFF) >> 8) | (abgr & 0xFF000000);
  367. #endif
  368. }
  369. TEST_F(PaintCanvasVideoRendererTest, CroppedFrameToRGBParallel) {
  370. // We need a test frame large enough to trigger parallel conversion. So we use
  371. // cropped_frame() as a base and scale it up. Note: Visible rect and natural
  372. // size must be even.
  373. auto test_frame = VideoFrame::CreateFrame(
  374. PIXEL_FORMAT_I420, gfx::Size(3840, 2160), gfx::Rect(1440, 810, 1920, 810),
  375. gfx::Size(1920, 810), base::TimeDelta());
  376. // Fill in the frame with the same data as the cropped frame.
  377. libyuv::I420Scale(cropped_frame()->data(0), cropped_frame()->stride(0),
  378. cropped_frame()->data(1), cropped_frame()->stride(1),
  379. cropped_frame()->data(2), cropped_frame()->stride(2),
  380. cropped_frame()->coded_size().width(),
  381. cropped_frame()->coded_size().height(), test_frame->data(0),
  382. test_frame->stride(0), test_frame->data(1),
  383. test_frame->stride(1), test_frame->data(2),
  384. test_frame->stride(2), test_frame->coded_size().width(),
  385. test_frame->coded_size().height(), libyuv::kFilterNone);
  386. const gfx::Size visible_size = test_frame->visible_rect().size();
  387. const size_t row_bytes = visible_size.width() * sizeof(SkColor);
  388. const size_t allocation_size = row_bytes * visible_size.height();
  389. std::unique_ptr<uint8_t, base::AlignedFreeDeleter> memory(
  390. static_cast<uint8_t*>(base::AlignedAlloc(
  391. allocation_size, media::VideoFrame::kFrameAddressAlignment)));
  392. memset(memory.get(), 0, allocation_size);
  393. PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
  394. test_frame.get(), memory.get(), row_bytes);
  395. const uint32_t* rgb_pixels = reinterpret_cast<uint32_t*>(memory.get());
  396. // Check the corners; this is sufficient to reveal https://crbug.com/1027442.
  397. EXPECT_EQ(SK_ColorBLACK, rgb_pixels[0]);
  398. EXPECT_EQ(MaybeConvertABGRToARGB(SK_ColorRED),
  399. rgb_pixels[visible_size.width() - 1]);
  400. EXPECT_EQ(SK_ColorGREEN,
  401. rgb_pixels[visible_size.width() * (visible_size.height() - 1)]);
  402. EXPECT_EQ(MaybeConvertABGRToARGB(SK_ColorBLUE),
  403. rgb_pixels[(visible_size.width() - 1) * visible_size.height()]);
  404. }
  405. TEST_F(PaintCanvasVideoRendererTest, CroppedFrame_NoScaling) {
  406. SkBitmap bitmap = AllocBitmap(kWidth, kHeight);
  407. cc::SkiaPaintCanvas canvas(bitmap);
  408. const gfx::Rect crop_rect = cropped_frame()->visible_rect();
  409. // Force painting to a non-zero position on the destination bitmap, to check
  410. // if the coordinates are calculated properly.
  411. const int offset_x = 10;
  412. const int offset_y = 15;
  413. canvas.translate(offset_x, offset_y);
  414. // Create a destination canvas with dimensions and scale which would not
  415. // cause scaling.
  416. canvas.scale(static_cast<SkScalar>(crop_rect.width()) / kWidth,
  417. static_cast<SkScalar>(crop_rect.height()) / kHeight);
  418. Paint(cropped_frame(), &canvas, kNone);
  419. // Check the corners.
  420. EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(offset_x, offset_y));
  421. EXPECT_EQ(SK_ColorRED,
  422. bitmap.getColor(offset_x + crop_rect.width() - 1, offset_y));
  423. EXPECT_EQ(SK_ColorGREEN,
  424. bitmap.getColor(offset_x, offset_y + crop_rect.height() - 1));
  425. EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(offset_x + crop_rect.width() - 1,
  426. offset_y + crop_rect.height() - 1));
  427. }
  428. TEST_F(PaintCanvasVideoRendererTest, Video_Rotation_90) {
  429. SkBitmap bitmap = AllocBitmap(kWidth, kHeight);
  430. cc::SkiaPaintCanvas canvas(bitmap);
  431. PaintRotated(cropped_frame(), &canvas, kNaturalRect, kNone,
  432. SkBlendMode::kSrcOver, VideoTransformation(VIDEO_ROTATION_90));
  433. // Check the corners.
  434. EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(0, 0));
  435. EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(kWidth - 1, 0));
  436. EXPECT_EQ(SK_ColorRED, bitmap.getColor(kWidth - 1, kHeight - 1));
  437. EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(0, kHeight - 1));
  438. }
  439. TEST_F(PaintCanvasVideoRendererTest, Video_Rotation_180) {
  440. SkBitmap bitmap = AllocBitmap(kWidth, kHeight);
  441. cc::SkiaPaintCanvas canvas(bitmap);
  442. PaintRotated(cropped_frame(), &canvas, kNaturalRect, kNone,
  443. SkBlendMode::kSrcOver, VideoTransformation(VIDEO_ROTATION_180));
  444. // Check the corners.
  445. EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(0, 0));
  446. EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(kWidth - 1, 0));
  447. EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(kWidth - 1, kHeight - 1));
  448. EXPECT_EQ(SK_ColorRED, bitmap.getColor(0, kHeight - 1));
  449. }
  450. TEST_F(PaintCanvasVideoRendererTest, Video_Rotation_270) {
  451. SkBitmap bitmap = AllocBitmap(kWidth, kHeight);
  452. cc::SkiaPaintCanvas canvas(bitmap);
  453. PaintRotated(cropped_frame(), &canvas, kNaturalRect, kNone,
  454. SkBlendMode::kSrcOver, VideoTransformation(VIDEO_ROTATION_270));
  455. // Check the corners.
  456. EXPECT_EQ(SK_ColorRED, bitmap.getColor(0, 0));
  457. EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(kWidth - 1, 0));
  458. EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(kWidth - 1, kHeight - 1));
  459. EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(0, kHeight - 1));
  460. }
  461. TEST_F(PaintCanvasVideoRendererTest, Video_Translate) {
  462. SkBitmap bitmap = AllocBitmap(kWidth, kHeight);
  463. cc::SkiaPaintCanvas canvas(bitmap);
  464. canvas.clear(SkColors::kMagenta);
  465. PaintRotated(cropped_frame(), &canvas,
  466. gfx::RectF(kWidth / 2, kHeight / 2, kWidth / 2, kHeight / 2),
  467. kNone, SkBlendMode::kSrcOver, kNoTransformation);
  468. // Check the corners of quadrant 2 and 4.
  469. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor(0, 0));
  470. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor((kWidth / 2) - 1, 0));
  471. EXPECT_EQ(SK_ColorMAGENTA,
  472. bitmap.getColor((kWidth / 2) - 1, (kHeight / 2) - 1));
  473. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor(0, (kHeight / 2) - 1));
  474. EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(kWidth / 2, kHeight / 2));
  475. EXPECT_EQ(SK_ColorRED, bitmap.getColor(kWidth - 1, kHeight / 2));
  476. EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(kWidth - 1, kHeight - 1));
  477. EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(kWidth / 2, kHeight - 1));
  478. }
  479. TEST_F(PaintCanvasVideoRendererTest, Video_Translate_Rotation_90) {
  480. SkBitmap bitmap = AllocBitmap(kWidth, kHeight);
  481. cc::SkiaPaintCanvas canvas(bitmap);
  482. canvas.clear(SkColors::kMagenta);
  483. PaintRotated(cropped_frame(), &canvas,
  484. gfx::RectF(kWidth / 2, kHeight / 2, kWidth / 2, kHeight / 2),
  485. kNone, SkBlendMode::kSrcOver,
  486. VideoTransformation(VIDEO_ROTATION_90));
  487. // Check the corners of quadrant 2 and 4.
  488. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor(0, 0));
  489. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor((kWidth / 2) - 1, 0));
  490. EXPECT_EQ(SK_ColorMAGENTA,
  491. bitmap.getColor((kWidth / 2) - 1, (kHeight / 2) - 1));
  492. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor(0, (kHeight / 2) - 1));
  493. EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(kWidth / 2, kHeight / 2));
  494. EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(kWidth - 1, kHeight / 2));
  495. EXPECT_EQ(SK_ColorRED, bitmap.getColor(kWidth - 1, kHeight - 1));
  496. EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(kWidth / 2, kHeight - 1));
  497. }
  498. TEST_F(PaintCanvasVideoRendererTest, Video_Translate_Rotation_180) {
  499. SkBitmap bitmap = AllocBitmap(kWidth, kHeight);
  500. cc::SkiaPaintCanvas canvas(bitmap);
  501. canvas.clear(SkColors::kMagenta);
  502. PaintRotated(cropped_frame(), &canvas,
  503. gfx::RectF(kWidth / 2, kHeight / 2, kWidth / 2, kHeight / 2),
  504. kNone, SkBlendMode::kSrcOver,
  505. VideoTransformation(VIDEO_ROTATION_180));
  506. // Check the corners of quadrant 2 and 4.
  507. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor(0, 0));
  508. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor((kWidth / 2) - 1, 0));
  509. EXPECT_EQ(SK_ColorMAGENTA,
  510. bitmap.getColor((kWidth / 2) - 1, (kHeight / 2) - 1));
  511. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor(0, (kHeight / 2) - 1));
  512. EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(kWidth / 2, kHeight / 2));
  513. EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(kWidth - 1, kHeight / 2));
  514. EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(kWidth - 1, kHeight - 1));
  515. EXPECT_EQ(SK_ColorRED, bitmap.getColor(kWidth / 2, kHeight - 1));
  516. }
  517. TEST_F(PaintCanvasVideoRendererTest, Video_Translate_Rotation_270) {
  518. SkBitmap bitmap = AllocBitmap(kWidth, kHeight);
  519. cc::SkiaPaintCanvas canvas(bitmap);
  520. canvas.clear(SkColors::kMagenta);
  521. PaintRotated(cropped_frame(), &canvas,
  522. gfx::RectF(kWidth / 2, kHeight / 2, kWidth / 2, kHeight / 2),
  523. kNone, SkBlendMode::kSrcOver,
  524. VideoTransformation(VIDEO_ROTATION_270));
  525. // Check the corners of quadrant 2 and 4.
  526. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor(0, 0));
  527. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor((kWidth / 2) - 1, 0));
  528. EXPECT_EQ(SK_ColorMAGENTA,
  529. bitmap.getColor((kWidth / 2) - 1, (kHeight / 2) - 1));
  530. EXPECT_EQ(SK_ColorMAGENTA, bitmap.getColor(0, (kHeight / 2) - 1));
  531. EXPECT_EQ(SK_ColorRED, bitmap.getColor(kWidth / 2, kHeight / 2));
  532. EXPECT_EQ(SK_ColorBLUE, bitmap.getColor(kWidth - 1, kHeight / 2));
  533. EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(kWidth - 1, kHeight - 1));
  534. EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(kWidth / 2, kHeight - 1));
  535. }
  536. TEST_F(PaintCanvasVideoRendererTest, HighBitDepth) {
  537. struct params {
  538. int bit_depth;
  539. VideoPixelFormat format;
  540. } kBitDepthAndFormats[] = {{9, PIXEL_FORMAT_YUV420P9},
  541. {10, PIXEL_FORMAT_YUV420P10},
  542. {12, PIXEL_FORMAT_YUV420P12}};
  543. for (const auto param : kBitDepthAndFormats) {
  544. // Copy cropped_frame into a highbit frame.
  545. scoped_refptr<VideoFrame> frame(VideoFrame::CreateFrame(
  546. param.format, cropped_frame()->coded_size(),
  547. cropped_frame()->visible_rect(), cropped_frame()->natural_size(),
  548. cropped_frame()->timestamp()));
  549. for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane;
  550. ++plane) {
  551. int width = cropped_frame()->row_bytes(plane);
  552. uint16_t* dst = reinterpret_cast<uint16_t*>(frame->data(plane));
  553. uint8_t* src = cropped_frame()->data(plane);
  554. for (int row = 0; row < cropped_frame()->rows(plane); row++) {
  555. for (int col = 0; col < width; col++) {
  556. dst[col] = src[col] << (param.bit_depth - 8);
  557. }
  558. src += cropped_frame()->stride(plane);
  559. dst += frame->stride(plane) / 2;
  560. }
  561. }
  562. Paint(frame, target_canvas(), kNone);
  563. // Check the corners.
  564. EXPECT_EQ(SK_ColorBLACK, bitmap()->getColor(0, 0));
  565. EXPECT_EQ(SK_ColorRED, bitmap()->getColor(kWidth - 1, 0));
  566. EXPECT_EQ(SK_ColorGREEN, bitmap()->getColor(0, kHeight - 1));
  567. EXPECT_EQ(SK_ColorBLUE, bitmap()->getColor(kWidth - 1, kHeight - 1));
  568. // Check the interior along the border between color regions. Note that
  569. // we're bilinearly upscaling, so we'll need to take care to pick sample
  570. // points that are just outside the "zone of resampling".
  571. EXPECT_EQ(SK_ColorBLACK,
  572. bitmap()->getColor(kWidth * 1 / 8 - 1, kHeight * 1 / 6 - 1));
  573. EXPECT_EQ(SK_ColorRED,
  574. bitmap()->getColor(kWidth * 3 / 8, kHeight * 1 / 6 - 1));
  575. EXPECT_EQ(SK_ColorGREEN,
  576. bitmap()->getColor(kWidth * 1 / 8 - 1, kHeight * 3 / 6));
  577. EXPECT_EQ(SK_ColorBLUE,
  578. bitmap()->getColor(kWidth * 3 / 8, kHeight * 3 / 6));
  579. }
  580. }
  581. TEST_F(PaintCanvasVideoRendererTest, Y16) {
  582. SkBitmap bitmap;
  583. bitmap.allocPixels(SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType));
  584. // |offset_x| and |offset_y| define visible rect's offset to coded rect.
  585. const int offset_x = 3;
  586. const int offset_y = 5;
  587. const int stride = bitmap.width() + offset_x;
  588. const size_t byte_size = stride * (bitmap.height() + offset_y) * 2;
  589. std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory(
  590. static_cast<unsigned char*>(base::AlignedAlloc(
  591. byte_size, media::VideoFrame::kFrameAddressAlignment)));
  592. const gfx::Rect rect(offset_x, offset_y, bitmap.width(), bitmap.height());
  593. auto video_frame =
  594. CreateTestY16Frame(gfx::Size(stride, offset_y + bitmap.height()), rect,
  595. memory.get(), cropped_frame()->timestamp());
  596. cc::SkiaPaintCanvas canvas(bitmap);
  597. cc::PaintFlags flags;
  598. flags.setFilterQuality(cc::PaintFlags::FilterQuality::kNone);
  599. renderer_.Paint(std::move(video_frame), &canvas,
  600. gfx::RectF(bitmap.width(), bitmap.height()), flags,
  601. kNoTransformation, nullptr);
  602. for (int j = 0; j < bitmap.height(); j++) {
  603. for (int i = 0; i < bitmap.width(); i++) {
  604. const int value = i + j * bitmap.width();
  605. EXPECT_EQ(SkColorSetRGB(value, value, value), bitmap.getColor(i, j));
  606. }
  607. }
  608. }
  609. // A reproducer test case for crbug.com/1230409 if run with ASAN enabled.
  610. TEST_F(PaintCanvasVideoRendererTest, Yuv420P12OddWidth) {
  611. // Allocate the Y, U, V planes for a 3x3 12-bit YUV 4:2:0 image. Note that
  612. // there are no padding bytes after each row.
  613. constexpr int kImgWidth = 3;
  614. constexpr int kImgHeight = 3;
  615. constexpr int kUvWidth = (kImgWidth + 1) / 2;
  616. constexpr int kUvHeight = (kImgHeight + 1) / 2;
  617. std::unique_ptr<uint16_t[]> y_plane =
  618. std::make_unique<uint16_t[]>(kImgWidth * kImgHeight);
  619. std::unique_ptr<uint16_t[]> u_plane =
  620. std::make_unique<uint16_t[]>(kUvWidth * kUvHeight);
  621. std::unique_ptr<uint16_t[]> v_plane =
  622. std::make_unique<uint16_t[]>(kUvWidth * kUvHeight);
  623. // Set all pixels to white.
  624. for (int i = 0; i < kImgHeight; ++i) {
  625. for (int j = 0; j < kImgWidth; ++j) {
  626. y_plane[i * kImgWidth + j] = 4095;
  627. }
  628. }
  629. for (int i = 0; i < kUvHeight; ++i) {
  630. for (int j = 0; j < kUvWidth; ++j) {
  631. u_plane[i * kUvWidth + j] = 2048;
  632. v_plane[i * kUvWidth + j] = 2048;
  633. }
  634. }
  635. const int32_t y_stride = sizeof(uint16_t) * kImgWidth;
  636. const int32_t uv_stride = sizeof(uint16_t) * kUvWidth;
  637. uint8_t* const y_data = reinterpret_cast<uint8_t*>(y_plane.get());
  638. uint8_t* const u_data = reinterpret_cast<uint8_t*>(u_plane.get());
  639. uint8_t* const v_data = reinterpret_cast<uint8_t*>(v_plane.get());
  640. auto size = gfx::Size(kImgWidth, kImgHeight);
  641. scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalYuvData(
  642. PIXEL_FORMAT_YUV420P12, size, gfx::Rect(size), size, y_stride, uv_stride,
  643. uv_stride, y_data, u_data, v_data, base::TimeDelta());
  644. std::unique_ptr<uint32_t[]> rgba =
  645. std::make_unique<uint32_t[]>(kImgWidth * kImgHeight);
  646. PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
  647. frame.get(), rgba.get(), frame->visible_rect().width() * 4,
  648. /*premultiply_alpha=*/true);
  649. for (int i = 0; i < kImgHeight; ++i) {
  650. for (int j = 0; j < kImgWidth; ++j) {
  651. EXPECT_EQ(rgba[i * kImgWidth + j], 0xffffffff);
  652. }
  653. }
  654. }
  655. TEST_F(PaintCanvasVideoRendererTest, I420WithFilters) {
  656. // Allocate the Y, U, V planes for a 4x4 8-bit YUV 4:2:0 image. Note that
  657. // there are no padding bytes after each row.
  658. constexpr int kImgWidth = 4;
  659. constexpr int kImgHeight = 4;
  660. constexpr int kUvWidth = (kImgWidth + 1) / 2;
  661. constexpr int kUvHeight = (kImgHeight + 1) / 2;
  662. std::unique_ptr<uint8_t[]> y_plane =
  663. std::make_unique<uint8_t[]>(kImgWidth * kImgHeight);
  664. std::unique_ptr<uint8_t[]> u_plane =
  665. std::make_unique<uint8_t[]>(kUvWidth * kUvHeight);
  666. std::unique_ptr<uint8_t[]> v_plane =
  667. std::make_unique<uint8_t[]>(kUvWidth * kUvHeight);
  668. // In the JPEG color space (K_R = 0.299, K_B = 0.114, full range), red
  669. // (R = 255, G = 0, B = 0) is Y = 76, U = 85, V = 255.
  670. //
  671. // Set Y to 76 for all pixels.
  672. memset(y_plane.get(), 76, kImgWidth * kImgHeight);
  673. // Set U = 85 and V = 255 for the upperleft pixel. Then vary U and V with a
  674. // linear, diagonal slope over the UV planes with a step size of 4 and -4,
  675. // respectively.
  676. //
  677. // The full U plane is
  678. // 85 89 93 97
  679. // 89 93 97 101
  680. // 93 97 101 105
  681. // 97 101 105 109
  682. // The subsampled U plane is
  683. // 89 97
  684. // 97 105
  685. //
  686. // The full V plane is
  687. // 255 251 247 243
  688. // 251 247 243 239
  689. // 247 243 239 235
  690. // 243 239 235 231
  691. // The subsampled V plane is
  692. // 251 243
  693. // 243 235
  694. for (int i = 0; i < kUvHeight; ++i) {
  695. for (int j = 0; j < kUvWidth; ++j) {
  696. u_plane[i * kUvWidth + j] = 89 + 8 * i + 8 * j;
  697. v_plane[i * kUvWidth + j] = 251 - 8 * i - 8 * j;
  698. }
  699. }
  700. auto size = gfx::Size(kImgWidth, kImgHeight);
  701. scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalYuvData(
  702. PIXEL_FORMAT_I420, size, gfx::Rect(size), size, kImgWidth, kUvWidth,
  703. kUvWidth, y_plane.get(), u_plane.get(), v_plane.get(), base::TimeDelta());
  704. frame->set_color_space(gfx::ColorSpace::CreateJpeg());
  705. std::unique_ptr<uint32_t[]> rgba =
  706. std::make_unique<uint32_t[]>(kImgWidth * kImgHeight);
  707. // First convert with kFilterNone (nearest neighbor).
  708. PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
  709. frame.get(), rgba.get(), frame->visible_rect().width() * 4,
  710. /*premultiply_alpha=*/true);
  711. // The pixel at coordinates (1, 1) will have U = 89 and V = 251 if nearest
  712. // neighbor is used. (The correct values are U = 93 and V = 247.)
  713. int i = 1;
  714. int j = 1;
  715. uint32_t color = rgba[i * kImgWidth + j];
  716. EXPECT_EQ(SkGetPackedA32(color), 255u);
  717. EXPECT_EQ(SkGetPackedR32(color), 249u);
  718. EXPECT_EQ(SkGetPackedG32(color), 1u);
  719. EXPECT_EQ(SkGetPackedB32(color), 7u);
  720. // The pixel at coordinates (2, 2) will have U = 105 and V = 235 if nearest
  721. // neighbor is used. (The correct values are U = 101 and V = 239.)
  722. i = 2;
  723. j = 2;
  724. color = rgba[i * kImgWidth + j];
  725. EXPECT_EQ(SkGetPackedA32(color), 255u);
  726. EXPECT_EQ(SkGetPackedR32(color), 226u);
  727. EXPECT_EQ(SkGetPackedG32(color), 7u);
  728. EXPECT_EQ(SkGetPackedB32(color), 35u);
  729. // Then convert with kFilterBilinear (bilinear interpolation).
  730. PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
  731. frame.get(), rgba.get(), frame->visible_rect().width() * 4,
  732. /*premultiply_alpha=*/true, PaintCanvasVideoRenderer::kFilterBilinear);
  733. // The pixel at coordinates (1, 1) will have the correct values U = 93 and
  734. // V = 247 if bilinear interpolation is used.
  735. i = 1;
  736. j = 1;
  737. color = rgba[i * kImgWidth + j];
  738. EXPECT_EQ(SkGetPackedA32(color), 255u);
  739. EXPECT_EQ(SkGetPackedR32(color), 243u);
  740. EXPECT_EQ(SkGetPackedG32(color), 2u);
  741. EXPECT_EQ(SkGetPackedB32(color), 14u);
  742. // The pixel at coordinates (2, 2) will have the correct values U = 101 and
  743. // V = 239 if bilinear interpolation is used.
  744. i = 2;
  745. j = 2;
  746. color = rgba[i * kImgWidth + j];
  747. EXPECT_EQ(SkGetPackedA32(color), 255u);
  748. EXPECT_EQ(SkGetPackedR32(color), 232u);
  749. EXPECT_EQ(SkGetPackedG32(color), 5u);
  750. EXPECT_EQ(SkGetPackedB32(color), 28u);
  751. }
  752. namespace {
  753. class TestGLES2Interface : public gpu::gles2::GLES2InterfaceStub {
  754. public:
  755. void GenTextures(GLsizei n, GLuint* textures) override {
  756. DCHECK_EQ(1, n);
  757. *textures = 1;
  758. }
  759. void TexImage2D(GLenum target,
  760. GLint level,
  761. GLint internalformat,
  762. GLsizei width,
  763. GLsizei height,
  764. GLint border,
  765. GLenum format,
  766. GLenum type,
  767. const void* pixels) override {
  768. if (!teximage2d_callback_.is_null()) {
  769. teximage2d_callback_.Run(target, level, internalformat, width, height,
  770. border, format, type, pixels);
  771. }
  772. }
  773. void TexSubImage2D(GLenum target,
  774. GLint level,
  775. GLint xoffset,
  776. GLint yoffset,
  777. GLsizei width,
  778. GLsizei height,
  779. GLenum format,
  780. GLenum type,
  781. const void* pixels) override {
  782. if (!texsubimage2d_callback_.is_null()) {
  783. texsubimage2d_callback_.Run(target, level, xoffset, yoffset, width,
  784. height, format, type, pixels);
  785. }
  786. }
  787. base::RepeatingCallback<void(GLenum target,
  788. GLint level,
  789. GLint internalformat,
  790. GLsizei width,
  791. GLsizei height,
  792. GLint border,
  793. GLenum format,
  794. GLenum type,
  795. const void* pixels)>
  796. teximage2d_callback_;
  797. base::RepeatingCallback<void(GLenum target,
  798. GLint level,
  799. GLint xoffset,
  800. GLint yoffset,
  801. GLsizei width,
  802. GLsizei height,
  803. GLenum format,
  804. GLenum type,
  805. const void* pixels)>
  806. texsubimage2d_callback_;
  807. };
  808. void MailboxHoldersReleased(const gpu::SyncToken& sync_token) {}
  809. } // namespace
  810. // Test that PaintCanvasVideoRenderer::Paint doesn't crash when GrContext is
  811. // unable to wrap a video frame texture (eg due to being abandoned).
  812. TEST_F(PaintCanvasVideoRendererTest, ContextLost) {
  813. auto context_provider = viz::TestContextProvider::Create();
  814. context_provider->BindToCurrentThread();
  815. context_provider->GrContext()->abandonContext();
  816. cc::SkiaPaintCanvas canvas(AllocBitmap(kWidth, kHeight));
  817. gfx::Size size(kWidth, kHeight);
  818. gpu::MailboxHolder holders[VideoFrame::kMaxPlanes] = {gpu::MailboxHolder(
  819. gpu::Mailbox::Generate(), gpu::SyncToken(), GL_TEXTURE_RECTANGLE_ARB)};
  820. auto video_frame = VideoFrame::WrapNativeTextures(
  821. PIXEL_FORMAT_NV12, holders, base::BindOnce(MailboxHoldersReleased), size,
  822. gfx::Rect(size), size, kNoTimestamp);
  823. cc::PaintFlags flags;
  824. flags.setFilterQuality(cc::PaintFlags::FilterQuality::kLow);
  825. renderer_.Paint(std::move(video_frame), &canvas, kNaturalRect, flags,
  826. kNoTransformation, context_provider.get());
  827. }
  828. void EmptyCallback(const gpu::SyncToken& sync_token) {}
  829. TEST_F(PaintCanvasVideoRendererTest, CorrectFrameSizeToVisibleRect) {
  830. constexpr int fWidth{16}, fHeight{16};
  831. SkImageInfo imInfo =
  832. SkImageInfo::MakeN32(fWidth, fHeight, kOpaque_SkAlphaType);
  833. cc::SkiaPaintCanvas canvas(AllocBitmap(kWidth, kHeight));
  834. gfx::Size coded_size(fWidth, fHeight);
  835. gfx::Size visible_size(fWidth / 2, fHeight / 2);
  836. uint8_t memory[fWidth * fHeight * 2] = {0};
  837. auto video_frame = media::VideoFrame::WrapExternalData(
  838. media::PIXEL_FORMAT_Y16, coded_size, gfx::Rect(visible_size),
  839. visible_size, &memory[0], fWidth * fHeight * 2, base::Milliseconds(4));
  840. gfx::RectF visible_rect(visible_size.width(), visible_size.height());
  841. cc::PaintFlags flags;
  842. renderer_.Paint(std::move(video_frame), &canvas, visible_rect, flags,
  843. kNoTransformation, nullptr);
  844. EXPECT_EQ(fWidth / 2, renderer_.LastImageDimensionsForTesting().width());
  845. EXPECT_EQ(fWidth / 2, renderer_.LastImageDimensionsForTesting().height());
  846. }
  847. TEST_F(PaintCanvasVideoRendererTest, TexImage2D_Y16_RGBA32F) {
  848. // Create test frame.
  849. // |offset_x| and |offset_y| define visible rect's offset to coded rect.
  850. const int offset_x = 3;
  851. const int offset_y = 5;
  852. const int width = 16;
  853. const int height = 16;
  854. const int stride = width + offset_x;
  855. const size_t byte_size = stride * (height + offset_y) * 2;
  856. std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory(
  857. static_cast<unsigned char*>(base::AlignedAlloc(
  858. byte_size, media::VideoFrame::kFrameAddressAlignment)));
  859. const gfx::Rect rect(offset_x, offset_y, width, height);
  860. auto video_frame =
  861. CreateTestY16Frame(gfx::Size(stride, offset_y + height), rect,
  862. memory.get(), cropped_frame()->timestamp());
  863. TestGLES2Interface gles2;
  864. // Bind the texImage2D callback to verify the uint16 to float32 conversion.
  865. gles2.teximage2d_callback_ =
  866. base::BindRepeating([](GLenum target, GLint level, GLint internalformat,
  867. GLsizei width, GLsizei height, GLint border,
  868. GLenum format, GLenum type, const void* pixels) {
  869. EXPECT_EQ(static_cast<unsigned>(GL_FLOAT), type);
  870. EXPECT_EQ(static_cast<unsigned>(GL_RGBA), format);
  871. EXPECT_EQ(GL_RGBA, internalformat);
  872. EXPECT_EQ(0, border);
  873. EXPECT_EQ(16, width);
  874. EXPECT_EQ(16, height);
  875. EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
  876. const float* data = static_cast<const float*>(pixels);
  877. for (int j = 0; j < height; j++) {
  878. for (int i = 0; i < width; i++) {
  879. const int value = i + (height - j - 1) * width; // flip_y is true.
  880. float expected_value =
  881. (((value & 0xFF) << 8) | (~value & 0xFF)) / 65535.f;
  882. EXPECT_EQ(expected_value, data[(i + j * width) * 4]);
  883. EXPECT_EQ(expected_value, data[(i + j * width) * 4 + 1]);
  884. EXPECT_EQ(expected_value, data[(i + j * width) * 4 + 2]);
  885. EXPECT_EQ(1.0f, data[(i + j * width) * 4 + 3]);
  886. }
  887. }
  888. });
  889. PaintCanvasVideoRenderer::TexImage2D(
  890. GL_TEXTURE_2D, 0, &gles2, gpu::Capabilities(), video_frame.get(), 0,
  891. GL_RGBA, GL_RGBA, GL_FLOAT, true /*flip_y*/, true);
  892. }
  893. TEST_F(PaintCanvasVideoRendererTest, TexSubImage2D_Y16_R32F) {
  894. // Create test frame.
  895. // |offset_x| and |offset_y| define visible rect's offset to coded rect.
  896. const int offset_x = 3;
  897. const int offset_y = 5;
  898. const int width = 16;
  899. const int height = 16;
  900. const int stride = width + offset_x;
  901. const size_t byte_size = stride * (height + offset_y) * 2;
  902. std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory(
  903. static_cast<unsigned char*>(base::AlignedAlloc(
  904. byte_size, media::VideoFrame::kFrameAddressAlignment)));
  905. const gfx::Rect rect(offset_x, offset_y, width, height);
  906. auto video_frame =
  907. CreateTestY16Frame(gfx::Size(stride, offset_y + height), rect,
  908. memory.get(), cropped_frame()->timestamp());
  909. TestGLES2Interface gles2;
  910. // Bind the texImage2D callback to verify the uint16 to float32 conversion.
  911. gles2.texsubimage2d_callback_ =
  912. base::BindRepeating([](GLenum target, GLint level, GLint xoffset,
  913. GLint yoffset, GLsizei width, GLsizei height,
  914. GLenum format, GLenum type, const void* pixels) {
  915. EXPECT_EQ(static_cast<unsigned>(GL_FLOAT), type);
  916. EXPECT_EQ(static_cast<unsigned>(GL_RED), format);
  917. EXPECT_EQ(2, xoffset);
  918. EXPECT_EQ(1, yoffset);
  919. EXPECT_EQ(16, width);
  920. EXPECT_EQ(16, height);
  921. EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
  922. const float* data = static_cast<const float*>(pixels);
  923. for (int j = 0; j < height; j++) {
  924. for (int i = 0; i < width; i++) {
  925. const int value = i + j * width; // flip_y is false.
  926. float expected_value =
  927. (((value & 0xFF) << 8) | (~value & 0xFF)) / 65535.f;
  928. EXPECT_EQ(expected_value, data[(i + j * width)]);
  929. }
  930. }
  931. });
  932. PaintCanvasVideoRenderer::TexSubImage2D(
  933. GL_TEXTURE_2D, &gles2, video_frame.get(), 0, GL_RED, GL_FLOAT,
  934. 2 /*xoffset*/, 1 /*yoffset*/, false /*flip_y*/, true);
  935. }
  936. // Fixture for tests that require a GL context.
  937. class PaintCanvasVideoRendererWithGLTest : public testing::Test {
  938. public:
  939. using GetColorCallback = base::RepeatingCallback<SkColor(int, int)>;
  940. void SetUp() override {
  941. display_ = gl::GLSurfaceTestSupport::InitializeOneOff();
  942. enable_pixels_.emplace();
  943. media_context_ = base::MakeRefCounted<viz::TestInProcessContextProvider>(
  944. viz::TestContextType::kGpuRaster, /*support_locking=*/false);
  945. gpu::ContextResult result = media_context_->BindToCurrentThread();
  946. ASSERT_EQ(result, gpu::ContextResult::kSuccess);
  947. gles2_context_ = base::MakeRefCounted<viz::TestInProcessContextProvider>(
  948. viz::TestContextType::kGLES2, /*support_locking=*/false);
  949. result = gles2_context_->BindToCurrentThread();
  950. ASSERT_EQ(result, gpu::ContextResult::kSuccess);
  951. destination_context_ =
  952. base::MakeRefCounted<viz::TestInProcessContextProvider>(
  953. viz::TestContextType::kGLES2, /*support_locking=*/false);
  954. result = destination_context_->BindToCurrentThread();
  955. ASSERT_EQ(result, gpu::ContextResult::kSuccess);
  956. cropped_frame_ = CreateCroppedFrame();
  957. }
  958. void TearDown() override {
  959. renderer_.ResetCache();
  960. destination_context_.reset();
  961. gles2_context_.reset();
  962. media_context_.reset();
  963. enable_pixels_.reset();
  964. viz::TestGpuServiceHolder::ResetInstance();
  965. gl::GLSurfaceTestSupport::ShutdownGL(display_);
  966. }
  967. // Uses CopyVideoFrameTexturesToGLTexture to copy |frame| into a GL texture,
  968. // reads back its contents, and runs |check_pixels| to validate it.
  969. template <class CheckPixels>
  970. void CopyVideoFrameTexturesAndCheckPixels(scoped_refptr<VideoFrame> frame,
  971. CheckPixels check_pixels) {
  972. auto* destination_gl = destination_context_->ContextGL();
  973. DCHECK(destination_gl);
  974. GLenum target = GL_TEXTURE_2D;
  975. GLuint texture = 0;
  976. destination_gl->GenTextures(1, &texture);
  977. destination_gl->BindTexture(target, texture);
  978. renderer_.CopyVideoFrameTexturesToGLTexture(
  979. media_context_.get(), destination_gl, frame, target, texture, GL_RGBA,
  980. GL_RGBA, GL_UNSIGNED_BYTE, 0, false /* premultiply_alpha */,
  981. false /* flip_y */);
  982. gfx::Size expected_size = frame->visible_rect().size();
  983. std::unique_ptr<uint8_t[]> pixels =
  984. ReadbackTexture(destination_gl, texture, expected_size);
  985. destination_gl->DeleteTextures(1, &texture);
  986. auto get_color = base::BindRepeating(
  987. [](uint8_t* pixels, const gfx::Size& size, int x, int y) {
  988. uint8_t* p = pixels + (size.width() * y + x) * 4;
  989. return SkColorSetARGB(p[3], p[0], p[1], p[2]);
  990. },
  991. pixels.get(), expected_size);
  992. check_pixels(get_color);
  993. }
  994. // Uses Copy to paint |frame| into a bitmap-backed canvas, then
  995. // runs |check_pixels| to validate the contents of the canvas.
  996. template <class CheckPixels>
  997. void PaintVideoFrameAndCheckPixels(scoped_refptr<VideoFrame> frame,
  998. CheckPixels check_pixels) {
  999. gfx::Size expected_size = frame->visible_rect().size();
  1000. SkBitmap bitmap =
  1001. AllocBitmap(expected_size.width(), expected_size.height());
  1002. cc::SkiaPaintCanvas canvas(bitmap);
  1003. canvas.clear(SkColors::kGray);
  1004. renderer_.Copy(frame, &canvas, media_context_.get());
  1005. auto get_color = base::BindRepeating(
  1006. [](SkBitmap* bitmap, int x, int y) { return bitmap->getColor(x, y); },
  1007. &bitmap);
  1008. check_pixels(get_color);
  1009. }
  1010. // Creates a cropped RGBA VideoFrame. |closure| is run once the shared images
  1011. // backing the VideoFrame have been destroyed.
  1012. scoped_refptr<VideoFrame> CreateTestRGBAFrame(base::OnceClosure closure) {
  1013. return CreateSharedImageRGBAFrame(gles2_context_, gfx::Size(16, 8),
  1014. gfx::Rect(3, 3, 12, 4),
  1015. std::move(closure));
  1016. }
  1017. // Checks that the contents of a texture/canvas match the expectations for the
  1018. // cropped RGBA frame above. |get_color| is a callback that returns the actual
  1019. // color at a given pixel location.
  1020. static void CheckRGBAFramePixels(GetColorCallback get_color) {
  1021. EXPECT_EQ(SK_ColorBLACK, get_color.Run(0, 0));
  1022. EXPECT_EQ(SK_ColorRED, get_color.Run(1, 0));
  1023. EXPECT_EQ(SK_ColorRED, get_color.Run(4, 0));
  1024. EXPECT_EQ(SK_ColorGREEN, get_color.Run(5, 0));
  1025. EXPECT_EQ(SK_ColorYELLOW, get_color.Run(9, 0));
  1026. EXPECT_EQ(SK_ColorYELLOW, get_color.Run(11, 0));
  1027. EXPECT_EQ(SK_ColorBLUE, get_color.Run(0, 1));
  1028. EXPECT_EQ(SK_ColorBLUE, get_color.Run(0, 3));
  1029. EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(1, 1));
  1030. EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(4, 1));
  1031. EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(1, 3));
  1032. EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(4, 3));
  1033. EXPECT_EQ(SK_ColorCYAN, get_color.Run(5, 1));
  1034. EXPECT_EQ(SK_ColorCYAN, get_color.Run(5, 3));
  1035. EXPECT_EQ(SK_ColorWHITE, get_color.Run(9, 1));
  1036. EXPECT_EQ(SK_ColorWHITE, get_color.Run(11, 1));
  1037. EXPECT_EQ(SK_ColorWHITE, get_color.Run(9, 3));
  1038. EXPECT_EQ(SK_ColorWHITE, get_color.Run(11, 3));
  1039. }
  1040. // Creates a cropped I420 VideoFrame. |closure| is run once the shared images
  1041. // backing the VideoFrame have been destroyed.
  1042. scoped_refptr<VideoFrame> CreateTestI420Frame(base::OnceClosure closure) {
  1043. return CreateSharedImageI420Frame(gles2_context_, gfx::Size(16, 8),
  1044. gfx::Rect(2, 2, 12, 4),
  1045. std::move(closure));
  1046. }
  1047. // Creates a cropped I420 VideoFrame. |closure| is run once the shared images
  1048. // backing the VideoFrame have been destroyed.
  1049. scoped_refptr<VideoFrame> CreateTestI420FrameNotSubset(
  1050. base::OnceClosure closure) {
  1051. return CreateSharedImageI420Frame(gles2_context_, gfx::Size(16, 8),
  1052. gfx::Rect(0, 0, 16, 8),
  1053. std::move(closure));
  1054. }
  1055. // Checks that the contents of a texture/canvas match the expectations for the
  1056. // cropped I420 frame above. |get_color| is a callback that returns the actual
  1057. // color at a given pixel location.
  1058. static void CheckI420FramePixels(GetColorCallback get_color) {
  1059. // Avoid checking around the "seams" where subsamples may be interpolated.
  1060. EXPECT_EQ(SK_ColorBLACK, get_color.Run(0, 0));
  1061. EXPECT_EQ(SK_ColorRED, get_color.Run(3, 0));
  1062. EXPECT_EQ(SK_ColorRED, get_color.Run(4, 0));
  1063. EXPECT_EQ(SK_ColorGREEN, get_color.Run(7, 0));
  1064. EXPECT_EQ(SK_ColorGREEN, get_color.Run(8, 0));
  1065. EXPECT_EQ(SK_ColorYELLOW, get_color.Run(11, 0));
  1066. EXPECT_EQ(SK_ColorBLUE, get_color.Run(0, 3));
  1067. EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(3, 3));
  1068. EXPECT_EQ(SK_ColorCYAN, get_color.Run(7, 3));
  1069. EXPECT_EQ(SK_ColorWHITE, get_color.Run(11, 3));
  1070. }
  1071. // Checks that the contents of a texture/canvas match the expectations for the
  1072. // cropped I420 frame above. |get_color| is a callback that returns the actual
  1073. // color at a given pixel location.
  1074. static void CheckI420FramePixelsNotSubset(GetColorCallback get_color) {
  1075. // Avoid checking around the "seams" where subsamples may be interpolated.
  1076. EXPECT_EQ(SK_ColorBLACK, get_color.Run(2, 2));
  1077. EXPECT_EQ(SK_ColorRED, get_color.Run(5, 2));
  1078. EXPECT_EQ(SK_ColorRED, get_color.Run(6, 2));
  1079. EXPECT_EQ(SK_ColorGREEN, get_color.Run(9, 2));
  1080. EXPECT_EQ(SK_ColorGREEN, get_color.Run(10, 2));
  1081. EXPECT_EQ(SK_ColorYELLOW, get_color.Run(13, 2));
  1082. EXPECT_EQ(SK_ColorBLUE, get_color.Run(2, 5));
  1083. EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(5, 5));
  1084. EXPECT_EQ(SK_ColorCYAN, get_color.Run(9, 5));
  1085. EXPECT_EQ(SK_ColorWHITE, get_color.Run(13, 5));
  1086. }
  1087. // Creates a cropped NV12 VideoFrame, or nullptr if the needed extension is
  1088. // not available. |closure| is run once the shared images backing the
  1089. // VideoFrame have been destroyed.
  1090. scoped_refptr<VideoFrame> CreateTestNV12Frame(base::OnceClosure closure) {
  1091. return CreateSharedImageNV12Frame(gles2_context_, gfx::Size(16, 8),
  1092. gfx::Rect(2, 2, 12, 4),
  1093. std::move(closure));
  1094. }
  1095. // Checks that the contents of a texture/canvas match the expectations for the
  1096. // cropped NV12 frame above. |get_color| is a callback that returns the actual
  1097. // color at a given pixel location. Note that the expectations are the same as
  1098. // for the I420 frame.
  1099. static void CheckNV12FramePixels(GetColorCallback get_color) {
  1100. CheckI420FramePixels(std::move(get_color));
  1101. }
  1102. scoped_refptr<VideoFrame> cropped_frame() { return cropped_frame_; }
  1103. protected:
  1104. absl::optional<gl::DisableNullDrawGLBindings> enable_pixels_;
  1105. scoped_refptr<viz::TestInProcessContextProvider> media_context_;
  1106. scoped_refptr<viz::TestInProcessContextProvider> gles2_context_;
  1107. scoped_refptr<viz::TestInProcessContextProvider> destination_context_;
  1108. PaintCanvasVideoRenderer renderer_;
  1109. scoped_refptr<VideoFrame> cropped_frame_;
  1110. base::test::TaskEnvironment task_environment_;
  1111. raw_ptr<gl::GLDisplay> display_ = nullptr;
  1112. };
  1113. TEST_F(PaintCanvasVideoRendererWithGLTest, CopyVideoFrameYUVDataToGLTexture) {
  1114. auto* destination_gl = destination_context_->ContextGL();
  1115. DCHECK(destination_gl);
  1116. GLenum target = GL_TEXTURE_2D;
  1117. GLuint texture = 0;
  1118. destination_gl->GenTextures(1, &texture);
  1119. destination_gl->BindTexture(target, texture);
  1120. renderer_.CopyVideoFrameYUVDataToGLTexture(
  1121. media_context_.get(), destination_gl, cropped_frame(), target, texture,
  1122. GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 0, false /* premultiply_alpha */,
  1123. false /* flip_y */);
  1124. gfx::Size expected_size = cropped_frame()->visible_rect().size();
  1125. std::unique_ptr<uint8_t[]> pixels =
  1126. ReadbackTexture(destination_gl, texture, expected_size);
  1127. auto get_color = ColorGetter(pixels.get(), expected_size);
  1128. // Avoid checking around the seams.
  1129. EXPECT_EQ(SK_ColorBLACK, get_color(0, 0));
  1130. EXPECT_EQ(SK_ColorRED, get_color(3, 0));
  1131. EXPECT_EQ(SK_ColorRED, get_color(7, 0));
  1132. EXPECT_EQ(SK_ColorGREEN, get_color(0, 3));
  1133. EXPECT_EQ(SK_ColorGREEN, get_color(0, 5));
  1134. EXPECT_EQ(SK_ColorBLUE, get_color(3, 3));
  1135. EXPECT_EQ(SK_ColorBLUE, get_color(7, 5));
  1136. destination_gl->DeleteTextures(1, &texture);
  1137. }
  1138. TEST_F(PaintCanvasVideoRendererWithGLTest,
  1139. CopyVideoFrameYUVDataToGLTexture_FlipY) {
  1140. auto* destination_gl = destination_context_->ContextGL();
  1141. DCHECK(destination_gl);
  1142. GLenum target = GL_TEXTURE_2D;
  1143. GLuint texture = 0;
  1144. destination_gl->GenTextures(1, &texture);
  1145. destination_gl->BindTexture(target, texture);
  1146. renderer_.CopyVideoFrameYUVDataToGLTexture(
  1147. media_context_.get(), destination_gl, cropped_frame(), target, texture,
  1148. GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 0, false /* premultiply_alpha */,
  1149. true /* flip_y */);
  1150. gfx::Size expected_size = cropped_frame()->visible_rect().size();
  1151. std::unique_ptr<uint8_t[]> pixels =
  1152. ReadbackTexture(destination_gl, texture, expected_size);
  1153. auto get_color = ColorGetter(pixels.get(), expected_size);
  1154. // Avoid checking around the seams.
  1155. EXPECT_EQ(SK_ColorBLACK, get_color(0, 5));
  1156. EXPECT_EQ(SK_ColorRED, get_color(3, 5));
  1157. EXPECT_EQ(SK_ColorRED, get_color(7, 5));
  1158. EXPECT_EQ(SK_ColorGREEN, get_color(0, 2));
  1159. EXPECT_EQ(SK_ColorGREEN, get_color(0, 0));
  1160. EXPECT_EQ(SK_ColorBLUE, get_color(3, 2));
  1161. EXPECT_EQ(SK_ColorBLUE, get_color(7, 0));
  1162. destination_gl->DeleteTextures(1, &texture);
  1163. }
  1164. // Checks that we correctly copy a RGBA shared image VideoFrame when using
  1165. // CopyVideoFrameYUVDataToGLTexture, including correct cropping.
  1166. TEST_F(PaintCanvasVideoRendererWithGLTest,
  1167. CopyVideoFrameTexturesToGLTextureRGBA) {
  1168. base::RunLoop run_loop;
  1169. scoped_refptr<VideoFrame> frame = CreateTestRGBAFrame(run_loop.QuitClosure());
  1170. CopyVideoFrameTexturesAndCheckPixels(frame, &CheckRGBAFramePixels);
  1171. frame.reset();
  1172. run_loop.Run();
  1173. }
  1174. // Checks that we correctly copy a RGBA shared image VideoFrame that needs read
  1175. // lock fences, when using CopyVideoFrameYUVDataToGLTexture, including correct
  1176. // cropping.
  1177. TEST_F(PaintCanvasVideoRendererWithGLTest,
  1178. CopyVideoFrameTexturesToGLTextureRGBA_ReadLockFence) {
  1179. base::RunLoop run_loop;
  1180. scoped_refptr<VideoFrame> frame = CreateTestRGBAFrame(run_loop.QuitClosure());
  1181. frame->metadata().read_lock_fences_enabled = true;
  1182. CopyVideoFrameTexturesAndCheckPixels(frame, &CheckRGBAFramePixels);
  1183. frame.reset();
  1184. run_loop.Run();
  1185. }
  1186. // Checks that we correctly paint a RGBA shared image VideoFrame, including
  1187. // correct cropping.
  1188. TEST_F(PaintCanvasVideoRendererWithGLTest, PaintRGBA) {
  1189. base::RunLoop run_loop;
  1190. scoped_refptr<VideoFrame> frame = CreateTestRGBAFrame(run_loop.QuitClosure());
  1191. PaintVideoFrameAndCheckPixels(frame, &CheckRGBAFramePixels);
  1192. frame.reset();
  1193. run_loop.Run();
  1194. }
  1195. // Checks that we correctly copy an I420 shared image VideoFrame when using
  1196. // CopyVideoFrameYUVDataToGLTexture, including correct cropping.
  1197. TEST_F(PaintCanvasVideoRendererWithGLTest,
  1198. CopyVideoFrameTexturesToGLTextureI420) {
  1199. base::RunLoop run_loop;
  1200. scoped_refptr<VideoFrame> frame = CreateTestI420Frame(run_loop.QuitClosure());
  1201. CopyVideoFrameTexturesAndCheckPixels(frame, &CheckI420FramePixels);
  1202. frame.reset();
  1203. run_loop.Run();
  1204. }
  1205. // Checks that we correctly paint a I420 shared image VideoFrame, including
  1206. // correct cropping.
  1207. TEST_F(PaintCanvasVideoRendererWithGLTest, PaintI420) {
  1208. base::RunLoop run_loop;
  1209. scoped_refptr<VideoFrame> frame = CreateTestI420Frame(run_loop.QuitClosure());
  1210. PaintVideoFrameAndCheckPixels(frame, &CheckI420FramePixels);
  1211. frame.reset();
  1212. run_loop.Run();
  1213. }
  1214. // Checks that we correctly paint a I420 shared image VideoFrame, including
  1215. // correct cropping.
  1216. TEST_F(PaintCanvasVideoRendererWithGLTest, PaintI420NotSubset) {
  1217. base::RunLoop run_loop;
  1218. scoped_refptr<VideoFrame> frame =
  1219. CreateTestI420FrameNotSubset(run_loop.QuitClosure());
  1220. PaintVideoFrameAndCheckPixels(frame, &CheckI420FramePixelsNotSubset);
  1221. frame.reset();
  1222. run_loop.Run();
  1223. }
  1224. // Checks that we correctly copy a NV12 shared image VideoFrame when using
  1225. // CopyVideoFrameYUVDataToGLTexture, including correct cropping.
  1226. TEST_F(PaintCanvasVideoRendererWithGLTest,
  1227. CopyVideoFrameTexturesToGLTextureNV12) {
  1228. base::RunLoop run_loop;
  1229. scoped_refptr<VideoFrame> frame = CreateTestNV12Frame(run_loop.QuitClosure());
  1230. if (!frame) {
  1231. LOG(ERROR) << "GL_EXT_texture_rg not supported, skipping NV12 test";
  1232. return;
  1233. }
  1234. CopyVideoFrameTexturesAndCheckPixels(frame, &CheckNV12FramePixels);
  1235. frame.reset();
  1236. run_loop.Run();
  1237. }
  1238. // Checks that we correctly paint a NV12 shared image VideoFrame, including
  1239. // correct cropping.
  1240. TEST_F(PaintCanvasVideoRendererWithGLTest, PaintNV12) {
  1241. base::RunLoop run_loop;
  1242. scoped_refptr<VideoFrame> frame = CreateTestNV12Frame(run_loop.QuitClosure());
  1243. if (!frame) {
  1244. LOG(ERROR) << "GL_EXT_texture_rg not supported, skipping NV12 test";
  1245. return;
  1246. }
  1247. PaintVideoFrameAndCheckPixels(frame, &CheckNV12FramePixels);
  1248. frame.reset();
  1249. run_loop.Run();
  1250. }
  1251. } // namespace media