Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(440)

Side by Side Diff: media/gpu/video_encode_accelerator_unittest.cc

Issue 2108053003: Fix memory alignment of VEA (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 <inttypes.h> 5 #include <inttypes.h>
6 #include <stddef.h> 6 #include <stddef.h>
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <memory> 10 #include <memory>
11 #include <queue> 11 #include <queue>
12 #include <string> 12 #include <string>
13 #include <utility> 13 #include <utility>
14 14
15 #include "base/at_exit.h" 15 #include "base/at_exit.h"
16 #include "base/bind.h" 16 #include "base/bind.h"
17 #include "base/command_line.h" 17 #include "base/command_line.h"
18 #include "base/files/file_util.h" 18 #include "base/files/file_util.h"
19 #include "base/files/memory_mapped_file.h"
20 #include "base/macros.h" 19 #include "base/macros.h"
20 #include "base/memory/aligned_memory.h"
21 #include "base/memory/scoped_vector.h" 21 #include "base/memory/scoped_vector.h"
22 #include "base/message_loop/message_loop.h" 22 #include "base/message_loop/message_loop.h"
23 #include "base/numerics/safe_conversions.h" 23 #include "base/numerics/safe_conversions.h"
24 #include "base/process/process_handle.h" 24 #include "base/process/process_handle.h"
25 #include "base/single_thread_task_runner.h" 25 #include "base/single_thread_task_runner.h"
26 #include "base/strings/string_number_conversions.h" 26 #include "base/strings/string_number_conversions.h"
27 #include "base/strings/string_split.h" 27 #include "base/strings/string_split.h"
28 #include "base/strings/stringprintf.h" 28 #include "base/strings/stringprintf.h"
29 #include "base/threading/thread.h" 29 #include "base/threading/thread.h"
30 #include "base/threading/thread_checker.h" 30 #include "base/threading/thread_checker.h"
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 ~TestStream() {} 158 ~TestStream() {}
159 159
160 gfx::Size visible_size; 160 gfx::Size visible_size;
161 gfx::Size coded_size; 161 gfx::Size coded_size;
162 unsigned int num_frames; 162 unsigned int num_frames;
163 163
164 // Original unaligned input file name provided as an argument to the test. 164 // Original unaligned input file name provided as an argument to the test.
165 // And the file must be an I420 (YUV planar) raw stream. 165 // And the file must be an I420 (YUV planar) raw stream.
166 std::string in_filename; 166 std::string in_filename;
167 167
168 // A vector used to prepare aligned input buffers of |in_filename|. This 168 // An aligned memory used to prepare aligned input buffers of |in_filename|.
169 // makes sure starting address of YUV planes are 64 bytes-aligned. 169 // This makes sure starting address of YUV planes are 64 bytes-aligned.
170 std::vector<char> aligned_in_file_data; 170 char* aligned_in_file_data;
171 171
172 // Byte size of a frame of |aligned_in_file_data|. 172 // Byte size of a frame of |aligned_in_file_data|.
173 size_t aligned_buffer_size; 173 size_t aligned_buffer_size;
174 174
175 // Byte size for each aligned plane of a frame. 175 // Byte size for each aligned plane of a frame.
176 std::vector<size_t> aligned_plane_size; 176 std::vector<size_t> aligned_plane_size;
177 177
178 std::string out_filename; 178 std::string out_filename;
179 VideoCodecProfile requested_profile; 179 VideoCodecProfile requested_profile;
180 unsigned int requested_bitrate; 180 unsigned int requested_bitrate;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 // Otherwise newer kernels will refuse to accept them, and on older kernels 213 // Otherwise newer kernels will refuse to accept them, and on older kernels
214 // we'll be treating ourselves to random corruption. 214 // we'll be treating ourselves to random corruption.
215 // Since we are just mapping and passing chunks of the input file directly to 215 // Since we are just mapping and passing chunks of the input file directly to
216 // the VEA as input frames to avoid copying large chunks of raw data on each 216 // the VEA as input frames to avoid copying large chunks of raw data on each
217 // frame and thus affecting performance measurements, we have to prepare a 217 // frame and thus affecting performance measurements, we have to prepare a
218 // temporary file with all planes aligned to 64-byte boundaries beforehand. 218 // temporary file with all planes aligned to 64-byte boundaries beforehand.
219 static void CreateAlignedInputStreamFile(const gfx::Size& coded_size, 219 static void CreateAlignedInputStreamFile(const gfx::Size& coded_size,
220 TestStream* test_stream) { 220 TestStream* test_stream) {
221 // Test case may have many encoders and memory should be prepared once. 221 // Test case may have many encoders and memory should be prepared once.
222 if (test_stream->coded_size == coded_size && 222 if (test_stream->coded_size == coded_size &&
223 !test_stream->aligned_in_file_data.empty()) 223 test_stream->aligned_in_file_data)
224 return; 224 return;
225 225
226 // All encoders in multiple encoder test reuse the same test_stream, make 226 // All encoders in multiple encoder test reuse the same test_stream, make
227 // sure they requested the same coded_size 227 // sure they requested the same coded_size
228 ASSERT_TRUE(test_stream->aligned_in_file_data.empty() || 228 ASSERT_TRUE(!test_stream->aligned_in_file_data ||
229 coded_size == test_stream->coded_size); 229 coded_size == test_stream->coded_size);
230 test_stream->coded_size = coded_size; 230 test_stream->coded_size = coded_size;
231 231
232 size_t num_planes = VideoFrame::NumPlanes(kInputFormat); 232 size_t num_planes = VideoFrame::NumPlanes(kInputFormat);
233 std::vector<size_t> padding_sizes(num_planes); 233 std::vector<size_t> padding_sizes(num_planes);
234 std::vector<size_t> coded_bpl(num_planes); 234 std::vector<size_t> coded_bpl(num_planes);
235 std::vector<size_t> visible_bpl(num_planes); 235 std::vector<size_t> visible_bpl(num_planes);
236 std::vector<size_t> visible_plane_rows(num_planes); 236 std::vector<size_t> visible_plane_rows(num_planes);
237 237
238 // Calculate padding in bytes to be added after each plane required to keep 238 // Calculate padding in bytes to be added after each plane required to keep
(...skipping 24 matching lines...) Expand all
263 LOG_ASSERT(base::GetFileSize(src_file, &src_file_size)); 263 LOG_ASSERT(base::GetFileSize(src_file, &src_file_size));
264 264
265 size_t visible_buffer_size = 265 size_t visible_buffer_size =
266 VideoFrame::AllocationSize(kInputFormat, test_stream->visible_size); 266 VideoFrame::AllocationSize(kInputFormat, test_stream->visible_size);
267 LOG_ASSERT(src_file_size % visible_buffer_size == 0U) 267 LOG_ASSERT(src_file_size % visible_buffer_size == 0U)
268 << "Stream byte size is not a product of calculated frame byte size"; 268 << "Stream byte size is not a product of calculated frame byte size";
269 269
270 test_stream->num_frames = src_file_size / visible_buffer_size; 270 test_stream->num_frames = src_file_size / visible_buffer_size;
271 271
272 LOG_ASSERT(test_stream->aligned_buffer_size > 0UL); 272 LOG_ASSERT(test_stream->aligned_buffer_size > 0UL);
273 test_stream->aligned_in_file_data.resize(test_stream->aligned_buffer_size * 273 test_stream->aligned_in_file_data = reinterpret_cast<char*>(
274 test_stream->num_frames); 274 base::AlignedAlloc(
275 test_stream->aligned_buffer_size * test_stream->num_frames, 64));
275 276
276 base::File src(src_file, base::File::FLAG_OPEN | base::File::FLAG_READ); 277 base::File src(src_file, base::File::FLAG_OPEN | base::File::FLAG_READ);
277 std::vector<char> src_data(visible_buffer_size); 278 std::vector<char> src_data(visible_buffer_size);
278 off_t src_offset = 0, dest_offset = 0; 279 off_t src_offset = 0, dest_offset = 0;
279 for (size_t frame = 0; frame < test_stream->num_frames; frame++) { 280 for (size_t frame = 0; frame < test_stream->num_frames; frame++) {
280 LOG_ASSERT(src.Read(src_offset, &src_data[0], visible_buffer_size) == 281 LOG_ASSERT(src.Read(src_offset, &src_data[0], visible_buffer_size) ==
281 static_cast<int>(visible_buffer_size)); 282 static_cast<int>(visible_buffer_size));
282 const char* src_ptr = &src_data[0]; 283 const char* src_ptr = &src_data[0];
283 for (size_t i = 0; i < num_planes; i++) { 284 for (size_t i = 0; i < num_planes; i++) {
284 // Assert that each plane of frame starts at 64 byte boundary. 285 // Assert that each plane of frame starts at 64 byte boundary.
285 ASSERT_EQ(dest_offset & 63, 0) 286 ASSERT_EQ(dest_offset & 63, 0)
286 << "Planes of frame should be mapped at a 64 byte boundary"; 287 << "Planes of frame should be mapped at a 64 byte boundary";
287 for (size_t j = 0; j < visible_plane_rows[i]; j++) { 288 for (size_t j = 0; j < visible_plane_rows[i]; j++) {
288 memcpy(&test_stream->aligned_in_file_data[dest_offset], src_ptr, 289 memcpy(&test_stream->aligned_in_file_data[dest_offset], src_ptr,
289 visible_bpl[i]); 290 visible_bpl[i]);
290 src_ptr += visible_bpl[i]; 291 src_ptr += visible_bpl[i];
291 dest_offset += coded_bpl[i]; 292 dest_offset += coded_bpl[i];
292 } 293 }
293 dest_offset += padding_sizes[i]; 294 dest_offset += padding_sizes[i];
294 } 295 }
295 src_offset += visible_buffer_size; 296 src_offset += visible_buffer_size;
296 } 297 }
297 src.Close(); 298 src.Close();
298 299
299 // Assert that memory mapped of file starts at 64 byte boundary. So each 300 // Assert that memory mapped of file starts at 64 byte boundary. So each
300 // plane of frames also start at 64 byte boundary. 301 // plane of frames also start at 64 byte boundary.
301 ASSERT_EQ(reinterpret_cast<off_t>(&test_stream->aligned_in_file_data[0]) & 63, 302 ASSERT_EQ(reinterpret_cast<off_t>(test_stream->aligned_in_file_data) & 63, 0)
302 0)
303 << "File should be mapped at a 64 byte boundary"; 303 << "File should be mapped at a 64 byte boundary";
304 304
305 LOG_ASSERT(test_stream->num_frames > 0UL); 305 LOG_ASSERT(test_stream->num_frames > 0UL);
306 } 306 }
307 307
308 // Parse |data| into its constituent parts, set the various output fields 308 // Parse |data| into its constituent parts, set the various output fields
309 // accordingly, read in video stream, and store them to |test_streams|. 309 // accordingly, read in video stream, and store them to |test_streams|.
310 static void ParseAndReadTestStreamData(const base::FilePath::StringType& data, 310 static void ParseAndReadTestStreamData(const base::FilePath::StringType& data,
311 ScopedVector<TestStream>* test_streams) { 311 ScopedVector<TestStream>* test_streams) {
312 // Split the string to individual test stream data. 312 // Split the string to individual test stream data.
(...skipping 18 matching lines...) Expand all
331 result = base::StringToInt(fields[2], &height); 331 result = base::StringToInt(fields[2], &height);
332 LOG_ASSERT(result); 332 LOG_ASSERT(result);
333 test_stream->visible_size = gfx::Size(width, height); 333 test_stream->visible_size = gfx::Size(width, height);
334 LOG_ASSERT(!test_stream->visible_size.IsEmpty()); 334 LOG_ASSERT(!test_stream->visible_size.IsEmpty());
335 int profile; 335 int profile;
336 result = base::StringToInt(fields[3], &profile); 336 result = base::StringToInt(fields[3], &profile);
337 LOG_ASSERT(result); 337 LOG_ASSERT(result);
338 LOG_ASSERT(profile > VIDEO_CODEC_PROFILE_UNKNOWN); 338 LOG_ASSERT(profile > VIDEO_CODEC_PROFILE_UNKNOWN);
339 LOG_ASSERT(profile <= VIDEO_CODEC_PROFILE_MAX); 339 LOG_ASSERT(profile <= VIDEO_CODEC_PROFILE_MAX);
340 test_stream->requested_profile = static_cast<VideoCodecProfile>(profile); 340 test_stream->requested_profile = static_cast<VideoCodecProfile>(profile);
341 test_stream->aligned_in_file_data = NULL;
341 342
342 if (fields.size() >= 5 && !fields[4].empty()) 343 if (fields.size() >= 5 && !fields[4].empty())
343 test_stream->out_filename = fields[4]; 344 test_stream->out_filename = fields[4];
344 345
345 if (fields.size() >= 6 && !fields[5].empty()) 346 if (fields.size() >= 6 && !fields[5].empty())
346 LOG_ASSERT( 347 LOG_ASSERT(
347 base::StringToUint(fields[5], &test_stream->requested_bitrate)); 348 base::StringToUint(fields[5], &test_stream->requested_bitrate));
348 349
349 if (fields.size() >= 7 && !fields[6].empty()) 350 if (fields.size() >= 7 && !fields[6].empty())
350 LOG_ASSERT( 351 LOG_ASSERT(
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 virtual void SetUp() { 387 virtual void SetUp() {
387 if (!log_path_.empty()) { 388 if (!log_path_.empty()) {
388 log_file_.reset(new base::File( 389 log_file_.reset(new base::File(
389 log_path_, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE)); 390 log_path_, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
390 LOG_ASSERT(log_file_->IsValid()); 391 LOG_ASSERT(log_file_->IsValid());
391 } 392 }
392 ParseAndReadTestStreamData(*test_stream_data_, &test_streams_); 393 ParseAndReadTestStreamData(*test_stream_data_, &test_streams_);
393 } 394 }
394 395
395 virtual void TearDown() { 396 virtual void TearDown() {
397 for (size_t i = 0; i < test_streams_.size(); i++) {
398 base::AlignedFree(test_streams_[i]->aligned_in_file_data);
399 }
396 log_file_.reset(); 400 log_file_.reset();
397 } 401 }
398 402
399 // Log one entry of machine-readable data to file and LOG(INFO). 403 // Log one entry of machine-readable data to file and LOG(INFO).
400 // The log has one data entry per line in the format of "<key>: <value>". 404 // The log has one data entry per line in the format of "<key>: <value>".
401 // Note that Chrome OS video_VEAPerf autotest parses the output key and value 405 // Note that Chrome OS video_VEAPerf autotest parses the output key and value
402 // pairs. Be sure to keep the autotest in sync. 406 // pairs. Be sure to keep the autotest in sync.
403 void LogToFile(const std::string& key, const std::string& value) { 407 void LogToFile(const std::string& key, const std::string& value) {
404 std::string s = base::StringPrintf("%s: %s\n", key.c_str(), value.c_str()); 408 std::string s = base::StringPrintf("%s: %s\n", key.c_str(), value.c_str());
405 LOG(INFO) << s; 409 LOG(INFO) << s;
(...skipping 884 matching lines...) Expand 10 before | Expand all | Expand 10 after
1290 void VEAClient::InputNoLongerNeededCallback(int32_t input_id) { 1294 void VEAClient::InputNoLongerNeededCallback(int32_t input_id) {
1291 std::set<int32_t>::iterator it = inputs_at_client_.find(input_id); 1295 std::set<int32_t>::iterator it = inputs_at_client_.find(input_id);
1292 ASSERT_NE(it, inputs_at_client_.end()); 1296 ASSERT_NE(it, inputs_at_client_.end());
1293 inputs_at_client_.erase(it); 1297 inputs_at_client_.erase(it);
1294 if (!g_env->run_at_fps()) 1298 if (!g_env->run_at_fps())
1295 FeedEncoderWithOneInput(); 1299 FeedEncoderWithOneInput();
1296 } 1300 }
1297 1301
1298 scoped_refptr<VideoFrame> VEAClient::CreateFrame(off_t position) { 1302 scoped_refptr<VideoFrame> VEAClient::CreateFrame(off_t position) {
1299 uint8_t* frame_data_y = 1303 uint8_t* frame_data_y =
1300 reinterpret_cast<uint8_t*>(&test_stream_->aligned_in_file_data[0]) + 1304 reinterpret_cast<uint8_t*>(test_stream_->aligned_in_file_data) +
1301 position; 1305 position;
1302 uint8_t* frame_data_u = frame_data_y + test_stream_->aligned_plane_size[0]; 1306 uint8_t* frame_data_u = frame_data_y + test_stream_->aligned_plane_size[0];
1303 uint8_t* frame_data_v = frame_data_u + test_stream_->aligned_plane_size[1]; 1307 uint8_t* frame_data_v = frame_data_u + test_stream_->aligned_plane_size[1];
1304 CHECK_GT(current_framerate_, 0U); 1308 CHECK_GT(current_framerate_, 0U);
1305 1309
1306 scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalYuvData( 1310 scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalYuvData(
1307 kInputFormat, input_coded_size_, gfx::Rect(test_stream_->visible_size), 1311 kInputFormat, input_coded_size_, gfx::Rect(test_stream_->visible_size),
1308 test_stream_->visible_size, input_coded_size_.width(), 1312 test_stream_->visible_size, input_coded_size_.width(),
1309 input_coded_size_.width() / 2, input_coded_size_.width() / 2, 1313 input_coded_size_.width() / 2, input_coded_size_.width() / 2,
1310 frame_data_y, frame_data_u, frame_data_v, 1314 frame_data_y, frame_data_u, frame_data_v,
1311 base::TimeDelta().FromMilliseconds(next_input_id_ * 1315 base::TimeDelta().FromMilliseconds(next_input_id_ *
1312 base::Time::kMillisecondsPerSecond / 1316 base::Time::kMillisecondsPerSecond /
1313 current_framerate_)); 1317 current_framerate_));
1314 EXPECT_NE(nullptr, video_frame.get()); 1318 EXPECT_NE(nullptr, video_frame.get());
1315 return video_frame; 1319 return video_frame;
1316 } 1320 }
1317 1321
1318 scoped_refptr<VideoFrame> VEAClient::PrepareInputFrame(off_t position, 1322 scoped_refptr<VideoFrame> VEAClient::PrepareInputFrame(off_t position,
1319 int32_t* input_id) { 1323 int32_t* input_id) {
1320 CHECK_LE(position + test_stream_->aligned_buffer_size, 1324 CHECK_LE(position + test_stream_->aligned_buffer_size,
1321 test_stream_->aligned_in_file_data.size()); 1325 test_stream_->aligned_buffer_size * test_stream_->num_frames);
1322 1326
1323 scoped_refptr<VideoFrame> frame = CreateFrame(position); 1327 scoped_refptr<VideoFrame> frame = CreateFrame(position);
1324 EXPECT_TRUE(frame); 1328 EXPECT_TRUE(frame);
1325 frame->AddDestructionObserver( 1329 frame->AddDestructionObserver(
1326 BindToCurrentLoop(base::Bind(&VEAClient::InputNoLongerNeededCallback, 1330 BindToCurrentLoop(base::Bind(&VEAClient::InputNoLongerNeededCallback,
1327 base::Unretained(this), next_input_id_))); 1331 base::Unretained(this), next_input_id_)));
1328 1332
1329 LOG_ASSERT(inputs_at_client_.insert(next_input_id_).second); 1333 LOG_ASSERT(inputs_at_client_.insert(next_input_id_).second);
1330 1334
1331 *input_id = next_input_id_++; 1335 *input_id = next_input_id_++;
1332 return frame; 1336 return frame;
1333 } 1337 }
1334 1338
1335 void VEAClient::OnInputTimer() { 1339 void VEAClient::OnInputTimer() {
1336 if (!has_encoder() || state_ != CS_ENCODING) 1340 if (!has_encoder() || state_ != CS_ENCODING)
1337 input_timer_.reset(); 1341 input_timer_.reset();
1338 else if (inputs_at_client_.size() < 1342 else if (inputs_at_client_.size() <
1339 num_required_input_buffers_ + kNumExtraInputFrames) 1343 num_required_input_buffers_ + kNumExtraInputFrames)
1340 FeedEncoderWithOneInput(); 1344 FeedEncoderWithOneInput();
1341 else 1345 else
1342 DVLOG(1) << "Dropping input frame"; 1346 DVLOG(1) << "Dropping input frame";
1343 } 1347 }
1344 1348
1345 void VEAClient::FeedEncoderWithOneInput() { 1349 void VEAClient::FeedEncoderWithOneInput() {
1346 if (!has_encoder() || state_ != CS_ENCODING) 1350 if (!has_encoder() || state_ != CS_ENCODING)
1347 return; 1351 return;
1348 1352
1349 size_t bytes_left = 1353 size_t bytes_left =
1350 test_stream_->aligned_in_file_data.size() - pos_in_input_stream_; 1354 test_stream_->aligned_buffer_size * test_stream_->num_frames -
1355 pos_in_input_stream_;
1351 if (bytes_left < test_stream_->aligned_buffer_size) { 1356 if (bytes_left < test_stream_->aligned_buffer_size) {
1352 DCHECK_EQ(bytes_left, 0UL); 1357 DCHECK_EQ(bytes_left, 0UL);
1353 // Rewind if at the end of stream and we are still encoding. 1358 // Rewind if at the end of stream and we are still encoding.
1354 // This is to flush the encoder with additional frames from the beginning 1359 // This is to flush the encoder with additional frames from the beginning
1355 // of the stream, or if the stream is shorter that the number of frames 1360 // of the stream, or if the stream is shorter that the number of frames
1356 // we require for bitrate tests. 1361 // we require for bitrate tests.
1357 pos_in_input_stream_ = 0; 1362 pos_in_input_stream_ = 0;
1358 } 1363 }
1359 1364
1360 if (quality_validator_) 1365 if (quality_validator_)
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after
1778 1783
1779 media::g_env = 1784 media::g_env =
1780 reinterpret_cast<media::VideoEncodeAcceleratorTestEnvironment*>( 1785 reinterpret_cast<media::VideoEncodeAcceleratorTestEnvironment*>(
1781 testing::AddGlobalTestEnvironment( 1786 testing::AddGlobalTestEnvironment(
1782 new media::VideoEncodeAcceleratorTestEnvironment( 1787 new media::VideoEncodeAcceleratorTestEnvironment(
1783 std::move(test_stream_data), log_path, run_at_fps, 1788 std::move(test_stream_data), log_path, run_at_fps,
1784 needs_encode_latency, verify_all_output))); 1789 needs_encode_latency, verify_all_output)));
1785 1790
1786 return RUN_ALL_TESTS(); 1791 return RUN_ALL_TESTS();
1787 } 1792 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698