| 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_frame.h" | 5 #include "media/base/video_frame.h" |
| 6 | 6 |
| 7 #include "base/format_macros.h" | 7 #include "base/format_macros.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/stringprintf.h" | 9 #include "base/stringprintf.h" |
| 10 #include "media/base/buffers.h" | 10 #include "media/base/buffers.h" |
| 11 #include "media/base/yuv_convert.h" | 11 #include "media/base/yuv_convert.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 13 |
| 14 namespace media { | 14 namespace media { |
| 15 | 15 |
| 16 using base::MD5DigestToBase16; | 16 using base::MD5DigestToBase16; |
| 17 | 17 |
| 18 // Helper function that initializes a YV12 frame with white and black scan | 18 // Helper function that initializes a YV12 frame with white and black scan |
| 19 // lines based on the |white_to_black| parameter. If 0, then the entire | 19 // lines based on the |white_to_black| parameter. If 0, then the entire |
| 20 // frame will be black, if 1 then the entire frame will be white. | 20 // frame will be black, if 1 then the entire frame will be white. |
| 21 void InitializeYV12Frame(VideoFrame* frame, double white_to_black) { | 21 void InitializeYV12Frame(VideoFrame* frame, double white_to_black) { |
| 22 EXPECT_EQ(VideoFrame::YV12, frame->format()); | 22 EXPECT_EQ(VideoFrame::YV12, frame->format()); |
| 23 size_t first_black_row = static_cast<size_t>(frame->height() * | 23 int first_black_row = static_cast<int>(frame->data_size().height() * |
| 24 white_to_black); | 24 white_to_black); |
| 25 uint8* y_plane = frame->data(VideoFrame::kYPlane); | 25 uint8* y_plane = frame->data(VideoFrame::kYPlane); |
| 26 for (size_t row = 0; row < frame->height(); ++row) { | 26 for (int row = 0; row < frame->data_size().height(); ++row) { |
| 27 int color = (row < first_black_row) ? 0xFF : 0x00; | 27 int color = (row < first_black_row) ? 0xFF : 0x00; |
| 28 memset(y_plane, color, frame->width()); | 28 memset(y_plane, color, frame->data_size().width()); |
| 29 y_plane += frame->stride(VideoFrame::kYPlane); | 29 y_plane += frame->stride(VideoFrame::kYPlane); |
| 30 } | 30 } |
| 31 uint8* u_plane = frame->data(VideoFrame::kUPlane); | 31 uint8* u_plane = frame->data(VideoFrame::kUPlane); |
| 32 uint8* v_plane = frame->data(VideoFrame::kVPlane); | 32 uint8* v_plane = frame->data(VideoFrame::kVPlane); |
| 33 for (size_t row = 0; row < frame->height(); row += 2) { | 33 for (int row = 0; row < frame->data_size().height(); row += 2) { |
| 34 memset(u_plane, 0x80, frame->width() / 2); | 34 memset(u_plane, 0x80, frame->data_size().width() / 2); |
| 35 memset(v_plane, 0x80, frame->width() / 2); | 35 memset(v_plane, 0x80, frame->data_size().width() / 2); |
| 36 u_plane += frame->stride(VideoFrame::kUPlane); | 36 u_plane += frame->stride(VideoFrame::kUPlane); |
| 37 v_plane += frame->stride(VideoFrame::kVPlane); | 37 v_plane += frame->stride(VideoFrame::kVPlane); |
| 38 } | 38 } |
| 39 } | 39 } |
| 40 | 40 |
| 41 // Given a |yv12_frame| this method converts the YV12 frame to RGBA and | 41 // Given a |yv12_frame| this method converts the YV12 frame to RGBA and |
| 42 // makes sure that all the pixels of the RBG frame equal |expect_rgb_color|. | 42 // makes sure that all the pixels of the RBG frame equal |expect_rgb_color|. |
| 43 void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) { | 43 void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) { |
| 44 ASSERT_EQ(VideoFrame::YV12, yv12_frame->format()); | 44 ASSERT_EQ(VideoFrame::YV12, yv12_frame->format()); |
| 45 ASSERT_EQ(yv12_frame->stride(VideoFrame::kUPlane), | 45 ASSERT_EQ(yv12_frame->stride(VideoFrame::kUPlane), |
| 46 yv12_frame->stride(VideoFrame::kVPlane)); | 46 yv12_frame->stride(VideoFrame::kVPlane)); |
| 47 | 47 |
| 48 scoped_refptr<media::VideoFrame> rgb_frame; | 48 scoped_refptr<media::VideoFrame> rgb_frame; |
| 49 rgb_frame = media::VideoFrame::CreateFrame(VideoFrame::RGB32, | 49 rgb_frame = media::VideoFrame::CreateFrame(VideoFrame::RGB32, |
| 50 yv12_frame->width(), | 50 yv12_frame->data_size(), |
| 51 yv12_frame->height(), | 51 yv12_frame->natural_size(), |
| 52 yv12_frame->GetTimestamp()); | 52 yv12_frame->GetTimestamp()); |
| 53 | 53 |
| 54 ASSERT_EQ(yv12_frame->width(), rgb_frame->width()); | 54 ASSERT_EQ(yv12_frame->data_size().width(), rgb_frame->data_size().width()); |
| 55 ASSERT_EQ(yv12_frame->height(), rgb_frame->height()); | 55 ASSERT_EQ(yv12_frame->data_size().height(), rgb_frame->data_size().height()); |
| 56 | 56 |
| 57 media::ConvertYUVToRGB32(yv12_frame->data(VideoFrame::kYPlane), | 57 media::ConvertYUVToRGB32(yv12_frame->data(VideoFrame::kYPlane), |
| 58 yv12_frame->data(VideoFrame::kUPlane), | 58 yv12_frame->data(VideoFrame::kUPlane), |
| 59 yv12_frame->data(VideoFrame::kVPlane), | 59 yv12_frame->data(VideoFrame::kVPlane), |
| 60 rgb_frame->data(VideoFrame::kRGBPlane), | 60 rgb_frame->data(VideoFrame::kRGBPlane), |
| 61 rgb_frame->width(), | 61 rgb_frame->data_size().width(), |
| 62 rgb_frame->height(), | 62 rgb_frame->data_size().height(), |
| 63 yv12_frame->stride(VideoFrame::kYPlane), | 63 yv12_frame->stride(VideoFrame::kYPlane), |
| 64 yv12_frame->stride(VideoFrame::kUPlane), | 64 yv12_frame->stride(VideoFrame::kUPlane), |
| 65 rgb_frame->stride(VideoFrame::kRGBPlane), | 65 rgb_frame->stride(VideoFrame::kRGBPlane), |
| 66 media::YV12); | 66 media::YV12); |
| 67 | 67 |
| 68 for (size_t row = 0; row < rgb_frame->height(); ++row) { | 68 for (int row = 0; row < rgb_frame->data_size().height(); ++row) { |
| 69 uint32* rgb_row_data = reinterpret_cast<uint32*>( | 69 uint32* rgb_row_data = reinterpret_cast<uint32*>( |
| 70 rgb_frame->data(VideoFrame::kRGBPlane) + | 70 rgb_frame->data(VideoFrame::kRGBPlane) + |
| 71 (rgb_frame->stride(VideoFrame::kRGBPlane) * row)); | 71 (rgb_frame->stride(VideoFrame::kRGBPlane) * row)); |
| 72 for (size_t col = 0; col < rgb_frame->width(); ++col) { | 72 for (int col = 0; col < rgb_frame->data_size().width(); ++col) { |
| 73 SCOPED_TRACE( | 73 SCOPED_TRACE( |
| 74 base::StringPrintf("Checking (%" PRIuS ", %" PRIuS ")", row, col)); | 74 base::StringPrintf("Checking (%d, %d)", row, col)); |
| 75 EXPECT_EQ(expect_rgb_color, rgb_row_data[col]); | 75 EXPECT_EQ(expect_rgb_color, rgb_row_data[col]); |
| 76 } | 76 } |
| 77 } | 77 } |
| 78 } | 78 } |
| 79 | 79 |
| 80 // Fill each plane to its reported extents and verify accessors report non | 80 // Fill each plane to its reported extents and verify accessors report non |
| 81 // zero values. Additionally, for the first plane verify the rows and | 81 // zero values. Additionally, for the first plane verify the rows and |
| 82 // row_bytes values are correct. | 82 // row_bytes values are correct. |
| 83 void ExpectFrameExtents(VideoFrame::Format format, int planes, | 83 void ExpectFrameExtents(VideoFrame::Format format, int planes, |
| 84 int bytes_per_pixel, const char* expected_hash) { | 84 int bytes_per_pixel, const char* expected_hash) { |
| 85 const unsigned char kFillByte = 0x80; | 85 const unsigned char kFillByte = 0x80; |
| 86 const size_t kWidth = 61; | 86 const int kWidth = 61; |
| 87 const size_t kHeight = 31; | 87 const int kHeight = 31; |
| 88 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337); | 88 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337); |
| 89 | 89 |
| 90 gfx::Size size(kWidth, kHeight); |
| 90 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( | 91 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( |
| 91 format, kWidth, kHeight, kTimestamp); | 92 format, size, size, kTimestamp); |
| 92 ASSERT_TRUE(frame); | 93 ASSERT_TRUE(frame); |
| 93 | 94 |
| 94 for(int plane = 0; plane < planes; plane++) { | 95 for(int plane = 0; plane < planes; plane++) { |
| 95 SCOPED_TRACE(base::StringPrintf("Checking plane %d", plane)); | 96 SCOPED_TRACE(base::StringPrintf("Checking plane %d", plane)); |
| 96 EXPECT_TRUE(frame->data(plane)); | 97 EXPECT_TRUE(frame->data(plane)); |
| 97 EXPECT_TRUE(frame->stride(plane)); | 98 EXPECT_TRUE(frame->stride(plane)); |
| 98 EXPECT_TRUE(frame->rows(plane)); | 99 EXPECT_TRUE(frame->rows(plane)); |
| 99 EXPECT_TRUE(frame->row_bytes(plane)); | 100 EXPECT_TRUE(frame->row_bytes(plane)); |
| 100 | 101 |
| 101 if (plane == 0) { | 102 if (plane == 0) { |
| 102 EXPECT_EQ((size_t)frame->rows(plane), kHeight); | 103 EXPECT_EQ(frame->rows(plane), kHeight); |
| 103 EXPECT_EQ((size_t)frame->row_bytes(plane), kWidth * bytes_per_pixel); | 104 EXPECT_EQ(frame->row_bytes(plane), kWidth * bytes_per_pixel); |
| 104 } | 105 } |
| 105 | 106 |
| 106 memset(frame->data(plane), kFillByte, | 107 memset(frame->data(plane), kFillByte, |
| 107 frame->stride(plane) * frame->rows(plane)); | 108 frame->stride(plane) * frame->rows(plane)); |
| 108 } | 109 } |
| 109 | 110 |
| 110 base::MD5Context context; | 111 base::MD5Context context; |
| 111 base::MD5Init(&context); | 112 base::MD5Init(&context); |
| 112 frame->HashFrameForTesting(&context); | 113 frame->HashFrameForTesting(&context); |
| 113 base::MD5Digest digest; | 114 base::MD5Digest digest; |
| 114 base::MD5Final(&digest, &context); | 115 base::MD5Final(&digest, &context); |
| 115 EXPECT_EQ(MD5DigestToBase16(digest), expected_hash); | 116 EXPECT_EQ(MD5DigestToBase16(digest), expected_hash); |
| 116 } | 117 } |
| 117 | 118 |
| 118 TEST(VideoFrame, CreateFrame) { | 119 TEST(VideoFrame, CreateFrame) { |
| 119 const size_t kWidth = 64; | 120 const int kWidth = 64; |
| 120 const size_t kHeight = 48; | 121 const int kHeight = 48; |
| 121 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337); | 122 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337); |
| 122 | 123 |
| 123 // Create a YV12 Video Frame. | 124 // Create a YV12 Video Frame. |
| 125 gfx::Size size(kWidth, kHeight); |
| 124 scoped_refptr<media::VideoFrame> frame = | 126 scoped_refptr<media::VideoFrame> frame = |
| 125 VideoFrame::CreateFrame(media::VideoFrame::YV12, kWidth, kHeight, | 127 VideoFrame::CreateFrame(media::VideoFrame::YV12, size, size, kTimestamp); |
| 126 kTimestamp); | |
| 127 ASSERT_TRUE(frame); | 128 ASSERT_TRUE(frame); |
| 128 | 129 |
| 129 // Test VideoFrame implementation. | 130 // Test VideoFrame implementation. |
| 130 EXPECT_EQ(media::VideoFrame::YV12, frame->format()); | 131 EXPECT_EQ(media::VideoFrame::YV12, frame->format()); |
| 131 { | 132 { |
| 132 SCOPED_TRACE(""); | 133 SCOPED_TRACE(""); |
| 133 InitializeYV12Frame(frame, 0.0f); | 134 InitializeYV12Frame(frame, 0.0f); |
| 134 ExpectFrameColor(frame, 0xFF000000); | 135 ExpectFrameColor(frame, 0xFF000000); |
| 135 } | 136 } |
| 136 base::MD5Digest digest; | 137 base::MD5Digest digest; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 148 frame->HashFrameForTesting(&context); | 149 frame->HashFrameForTesting(&context); |
| 149 base::MD5Final(&digest, &context); | 150 base::MD5Final(&digest, &context); |
| 150 EXPECT_EQ(MD5DigestToBase16(digest), "911991d51438ad2e1a40ed5f6fc7c796"); | 151 EXPECT_EQ(MD5DigestToBase16(digest), "911991d51438ad2e1a40ed5f6fc7c796"); |
| 151 | 152 |
| 152 // Test an empty frame. | 153 // Test an empty frame. |
| 153 frame = VideoFrame::CreateEmptyFrame(); | 154 frame = VideoFrame::CreateEmptyFrame(); |
| 154 EXPECT_TRUE(frame->IsEndOfStream()); | 155 EXPECT_TRUE(frame->IsEndOfStream()); |
| 155 } | 156 } |
| 156 | 157 |
| 157 TEST(VideoFrame, CreateBlackFrame) { | 158 TEST(VideoFrame, CreateBlackFrame) { |
| 158 const size_t kWidth = 2; | 159 const int kWidth = 2; |
| 159 const size_t kHeight = 2; | 160 const int kHeight = 2; |
| 160 const uint8 kExpectedYRow[] = { 0, 0 }; | 161 const uint8 kExpectedYRow[] = { 0, 0 }; |
| 161 const uint8 kExpectedUVRow[] = { 128 }; | 162 const uint8 kExpectedUVRow[] = { 128 }; |
| 162 | 163 |
| 163 scoped_refptr<media::VideoFrame> frame = | 164 scoped_refptr<media::VideoFrame> frame = |
| 164 VideoFrame::CreateBlackFrame(kWidth, kHeight); | 165 VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight)); |
| 165 ASSERT_TRUE(frame); | 166 ASSERT_TRUE(frame); |
| 166 | 167 |
| 167 // Test basic properties. | 168 // Test basic properties. |
| 168 EXPECT_EQ(0, frame->GetTimestamp().InMicroseconds()); | 169 EXPECT_EQ(0, frame->GetTimestamp().InMicroseconds()); |
| 169 EXPECT_FALSE(frame->IsEndOfStream()); | 170 EXPECT_FALSE(frame->IsEndOfStream()); |
| 170 | 171 |
| 171 // Test |frame| properties. | 172 // Test |frame| properties. |
| 172 EXPECT_EQ(VideoFrame::YV12, frame->format()); | 173 EXPECT_EQ(VideoFrame::YV12, frame->format()); |
| 173 EXPECT_EQ(kWidth, frame->width()); | 174 EXPECT_EQ(kWidth, frame->data_size().width()); |
| 174 EXPECT_EQ(kHeight, frame->height()); | 175 EXPECT_EQ(kHeight, frame->data_size().height()); |
| 175 | 176 |
| 176 // Test frames themselves. | 177 // Test frames themselves. |
| 177 uint8* y_plane = frame->data(VideoFrame::kYPlane); | 178 uint8* y_plane = frame->data(VideoFrame::kYPlane); |
| 178 for (size_t y = 0; y < frame->height(); ++y) { | 179 for (int y = 0; y < frame->data_size().height(); ++y) { |
| 179 EXPECT_EQ(0, memcmp(kExpectedYRow, y_plane, arraysize(kExpectedYRow))); | 180 EXPECT_EQ(0, memcmp(kExpectedYRow, y_plane, arraysize(kExpectedYRow))); |
| 180 y_plane += frame->stride(VideoFrame::kYPlane); | 181 y_plane += frame->stride(VideoFrame::kYPlane); |
| 181 } | 182 } |
| 182 | 183 |
| 183 uint8* u_plane = frame->data(VideoFrame::kUPlane); | 184 uint8* u_plane = frame->data(VideoFrame::kUPlane); |
| 184 uint8* v_plane = frame->data(VideoFrame::kVPlane); | 185 uint8* v_plane = frame->data(VideoFrame::kVPlane); |
| 185 for (size_t y = 0; y < frame->height() / 2; ++y) { | 186 for (int y = 0; y < frame->data_size().height() / 2; ++y) { |
| 186 EXPECT_EQ(0, memcmp(kExpectedUVRow, u_plane, arraysize(kExpectedUVRow))); | 187 EXPECT_EQ(0, memcmp(kExpectedUVRow, u_plane, arraysize(kExpectedUVRow))); |
| 187 EXPECT_EQ(0, memcmp(kExpectedUVRow, v_plane, arraysize(kExpectedUVRow))); | 188 EXPECT_EQ(0, memcmp(kExpectedUVRow, v_plane, arraysize(kExpectedUVRow))); |
| 188 u_plane += frame->stride(VideoFrame::kUPlane); | 189 u_plane += frame->stride(VideoFrame::kUPlane); |
| 189 v_plane += frame->stride(VideoFrame::kVPlane); | 190 v_plane += frame->stride(VideoFrame::kVPlane); |
| 190 } | 191 } |
| 191 } | 192 } |
| 192 | 193 |
| 193 // Ensure each frame is properly sized and allocated. Will trigger OOB reads | 194 // Ensure each frame is properly sized and allocated. Will trigger OOB reads |
| 194 // and writes as well as incorrect frame hashes otherwise. | 195 // and writes as well as incorrect frame hashes otherwise. |
| 195 TEST(VideoFrame, CheckFrameExtents) { | 196 TEST(VideoFrame, CheckFrameExtents) { |
| 196 // Each call consists of a VideoFrame::Format, # of planes, bytes per pixel, | 197 // Each call consists of a VideoFrame::Format, # of planes, bytes per pixel, |
| 197 // and the expected hash of all planes if filled with kFillByte (defined in | 198 // and the expected hash of all planes if filled with kFillByte (defined in |
| 198 // ExpectFrameExtents). | 199 // ExpectFrameExtents). |
| 199 ExpectFrameExtents( | 200 ExpectFrameExtents( |
| 200 VideoFrame::RGB32, 1, 4, "de6d3d567e282f6a38d478f04fc81fb0"); | 201 VideoFrame::RGB32, 1, 4, "de6d3d567e282f6a38d478f04fc81fb0"); |
| 201 ExpectFrameExtents( | 202 ExpectFrameExtents( |
| 202 VideoFrame::YV12, 3, 1, "71113bdfd4c0de6cf62f48fb74f7a0b1"); | 203 VideoFrame::YV12, 3, 1, "71113bdfd4c0de6cf62f48fb74f7a0b1"); |
| 203 ExpectFrameExtents( | 204 ExpectFrameExtents( |
| 204 VideoFrame::YV16, 3, 1, "9bb99ac3ff350644ebff4d28dc01b461"); | 205 VideoFrame::YV16, 3, 1, "9bb99ac3ff350644ebff4d28dc01b461"); |
| 205 } | 206 } |
| 206 | 207 |
| 207 } // namespace media | 208 } // namespace media |
| OLD | NEW |