| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/video_util.h" | 5 #include "media/base/video_util.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "media/base/video_frame.h" | 12 #include "media/base/video_frame.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 14 | 14 |
| 15 namespace { |
| 16 |
| 17 // Initialize a plane's visible rect with value circularly from 0 to 255. |
| 18 void FillPlaneWithPattern(uint8_t* data, |
| 19 int stride, |
| 20 const gfx::Size& visible_size) { |
| 21 DCHECK(data && visible_size.width() <= stride); |
| 22 |
| 23 uint32_t val = 0; |
| 24 uint8_t* src = data; |
| 25 for (int i = 0; i < visible_size.height(); ++i, src += stride) { |
| 26 for (int j = 0; j < visible_size.width(); ++j, ++val) |
| 27 src[j] = val & 0xff; |
| 28 } |
| 29 } |
| 30 |
| 31 // Create a VideoFrame and initialize the visible rect using |
| 32 // |FillPlaneWithPattern()|. For testing purpose, the VideoFrame should be |
| 33 // filled with varying values, which is different from |
| 34 // |VideoFrame::CreateColorFrame()| where the entrire VideoFrame is filled |
| 35 // with a given color. |
| 36 scoped_refptr<media::VideoFrame> CreateFrameWithPatternFilled( |
| 37 media::VideoPixelFormat format, |
| 38 const gfx::Size& coded_size, |
| 39 const gfx::Rect& visible_rect, |
| 40 const gfx::Size& natural_size, |
| 41 base::TimeDelta timestamp) { |
| 42 scoped_refptr<media::VideoFrame> frame(media::VideoFrame::CreateFrame( |
| 43 format, coded_size, visible_rect, natural_size, timestamp)); |
| 44 |
| 45 FillPlaneWithPattern(frame->data(media::VideoFrame::kYPlane), |
| 46 frame->stride(media::VideoFrame::kYPlane), |
| 47 frame->visible_rect().size()); |
| 48 FillPlaneWithPattern( |
| 49 frame->data(media::VideoFrame::kUPlane), |
| 50 frame->stride(media::VideoFrame::kUPlane), |
| 51 media::VideoFrame::PlaneSize(format, media::VideoFrame::kUPlane, |
| 52 frame->visible_rect().size())); |
| 53 FillPlaneWithPattern( |
| 54 frame->data(media::VideoFrame::kVPlane), |
| 55 frame->stride(media::VideoFrame::kVPlane), |
| 56 media::VideoFrame::PlaneSize(format, media::VideoFrame::kVPlane, |
| 57 frame->visible_rect().size())); |
| 58 return frame; |
| 59 } |
| 60 |
| 61 // Helper function used to verify the data in the coded region after copying the |
| 62 // visible region and padding the remaining area. |
| 63 bool VerifyPlanCopyWithPadding(const uint8_t* src, |
| 64 size_t src_stride, |
| 65 // Size of visible region. |
| 66 const gfx::Size& src_size, |
| 67 const uint8_t* dst, |
| 68 size_t dst_stride, |
| 69 // Coded size of |dst|. |
| 70 const gfx::Size& dst_size) { |
| 71 if (!src || !dst) |
| 72 return false; |
| 73 |
| 74 const size_t src_width = src_size.width(); |
| 75 const size_t src_height = src_size.height(); |
| 76 const size_t dst_width = dst_size.width(); |
| 77 const size_t dst_height = dst_size.height(); |
| 78 if (src_width > dst_width || src_width > src_stride || |
| 79 src_height > dst_height || src_size.IsEmpty() || dst_size.IsEmpty()) |
| 80 return false; |
| 81 |
| 82 const uint8_t *src_ptr = src, *dst_ptr = dst; |
| 83 for (size_t i = 0; i < src_height; |
| 84 ++i, src_ptr += src_stride, dst_ptr += dst_stride) { |
| 85 if (memcmp(src_ptr, dst_ptr, src_width)) |
| 86 return false; |
| 87 for (size_t j = src_width; j < dst_width; ++j) { |
| 88 if (src_ptr[src_width - 1] != dst_ptr[j]) |
| 89 return false; |
| 90 } |
| 91 } |
| 92 if (src_height < dst_height) { |
| 93 src_ptr = dst + (src_height - 1) * dst_stride; |
| 94 if (memcmp(src_ptr, dst_ptr, dst_width)) |
| 95 return false; |
| 96 } |
| 97 return true; |
| 98 } |
| 99 |
| 100 bool VerifyCopyWithPadding(const media::VideoFrame& src_frame, |
| 101 const media::VideoFrame& dst_frame) { |
| 102 if (!src_frame.IsMappable() || !dst_frame.IsMappable() || |
| 103 src_frame.visible_rect().size() != dst_frame.visible_rect().size()) |
| 104 return false; |
| 105 |
| 106 if (!VerifyPlanCopyWithPadding( |
| 107 src_frame.visible_data(media::VideoFrame::kYPlane), |
| 108 src_frame.stride(media::VideoFrame::kYPlane), |
| 109 src_frame.visible_rect().size(), |
| 110 dst_frame.data(media::VideoFrame::kYPlane), |
| 111 dst_frame.stride(media::VideoFrame::kYPlane), dst_frame.coded_size())) |
| 112 return false; |
| 113 if (!VerifyPlanCopyWithPadding( |
| 114 src_frame.visible_data(media::VideoFrame::kUPlane), |
| 115 src_frame.stride(media::VideoFrame::kUPlane), |
| 116 media::VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420, |
| 117 media::VideoFrame::kUPlane, |
| 118 src_frame.visible_rect().size()), |
| 119 dst_frame.data(media::VideoFrame::kUPlane), |
| 120 dst_frame.stride(media::VideoFrame::kUPlane), |
| 121 media::VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420, |
| 122 media::VideoFrame::kUPlane, |
| 123 dst_frame.coded_size()))) |
| 124 return false; |
| 125 if (!VerifyPlanCopyWithPadding( |
| 126 src_frame.visible_data(media::VideoFrame::kVPlane), |
| 127 src_frame.stride(media::VideoFrame::kVPlane), |
| 128 media::VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420, |
| 129 media::VideoFrame::kVPlane, |
| 130 src_frame.visible_rect().size()), |
| 131 dst_frame.data(media::VideoFrame::kVPlane), |
| 132 dst_frame.stride(media::VideoFrame::kVPlane), |
| 133 media::VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420, |
| 134 media::VideoFrame::kVPlane, |
| 135 dst_frame.coded_size()))) |
| 136 return false; |
| 137 |
| 138 return true; |
| 139 } |
| 140 |
| 141 } // namespace |
| 142 |
| 15 namespace media { | 143 namespace media { |
| 16 | 144 |
| 17 class VideoUtilTest : public testing::Test { | 145 class VideoUtilTest : public testing::Test { |
| 18 public: | 146 public: |
| 19 VideoUtilTest() | 147 VideoUtilTest() |
| 20 : height_(0), | 148 : height_(0), |
| 21 y_stride_(0), | 149 y_stride_(0), |
| 22 u_stride_(0), | 150 u_stride_(0), |
| 23 v_stride_(0) { | 151 v_stride_(0) { |
| 24 } | 152 } |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 (y / 2) * frame->stride(VideoFrame::kVPlane) + (x / 2)], | 483 (y / 2) * frame->stride(VideoFrame::kVPlane) + (x / 2)], |
| 356 inside ? 0x03 : 0x80); | 484 inside ? 0x03 : 0x80); |
| 357 } | 485 } |
| 358 } | 486 } |
| 359 } | 487 } |
| 360 } | 488 } |
| 361 } | 489 } |
| 362 } | 490 } |
| 363 } | 491 } |
| 364 | 492 |
| 493 TEST_F(VideoUtilTest, I420CopyWithPadding) { |
| 494 gfx::Size visible_size(40, 30); |
| 495 scoped_refptr<VideoFrame> src_frame = CreateFrameWithPatternFilled( |
| 496 PIXEL_FORMAT_I420, visible_size, gfx::Rect(visible_size), visible_size, |
| 497 base::TimeDelta()); |
| 498 // Expect to return false when copying to an empty buffer. |
| 499 EXPECT_FALSE(I420CopyWithPadding(*src_frame, nullptr)); |
| 500 |
| 501 scoped_refptr<VideoFrame> dst_frame = CreateFrameWithPatternFilled( |
| 502 PIXEL_FORMAT_I420, visible_size, gfx::Rect(visible_size), visible_size, |
| 503 base::TimeDelta()); |
| 504 EXPECT_TRUE(I420CopyWithPadding(*src_frame, dst_frame.get())); |
| 505 EXPECT_TRUE(VerifyCopyWithPadding(*src_frame, *dst_frame)); |
| 506 |
| 507 gfx::Size coded_size(60, 40); |
| 508 dst_frame = CreateFrameWithPatternFilled(PIXEL_FORMAT_I420, coded_size, |
| 509 gfx::Rect(visible_size), coded_size, |
| 510 base::TimeDelta()); |
| 511 EXPECT_TRUE(I420CopyWithPadding(*src_frame, dst_frame.get())); |
| 512 EXPECT_TRUE(VerifyCopyWithPadding(*src_frame, *dst_frame)); |
| 513 |
| 514 gfx::Size odd_size(39, 31); |
| 515 src_frame = CreateFrameWithPatternFilled(PIXEL_FORMAT_I420, odd_size, |
| 516 gfx::Rect(odd_size), odd_size, |
| 517 base::TimeDelta()); |
| 518 dst_frame = CreateFrameWithPatternFilled(PIXEL_FORMAT_I420, coded_size, |
| 519 gfx::Rect(odd_size), coded_size, |
| 520 base::TimeDelta()); |
| 521 EXPECT_TRUE(I420CopyWithPadding(*src_frame, dst_frame.get())); |
| 522 EXPECT_TRUE(VerifyCopyWithPadding(*src_frame, *dst_frame)); |
| 523 } |
| 524 |
| 365 } // namespace media | 525 } // namespace media |
| OLD | NEW |