Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "base/at_exit.h" | 5 #include "base/at_exit.h" |
| 6 #include "base/bind.h" | 6 #include "base/bind.h" |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/files/memory_mapped_file.h" | 9 #include "base/files/memory_mapped_file.h" |
| 10 #include "base/memory/scoped_vector.h" | 10 #include "base/memory/scoped_vector.h" |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 #endif | 26 #endif |
| 27 | 27 |
| 28 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) | 28 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) |
| 29 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" | 29 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" |
| 30 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) | 30 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) |
| 31 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h" | 31 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h" |
| 32 #else | 32 #else |
| 33 #error The VideoEncodeAcceleratorUnittest is not supported on this platform. | 33 #error The VideoEncodeAcceleratorUnittest is not supported on this platform. |
| 34 #endif | 34 #endif |
| 35 | 35 |
| 36 #define ALIGN_64_BYTES(x) (((x) + 63) & ~63) | |
| 37 | |
| 36 using media::VideoEncodeAccelerator; | 38 using media::VideoEncodeAccelerator; |
| 37 | 39 |
| 38 namespace content { | 40 namespace content { |
| 39 namespace { | 41 namespace { |
| 40 | 42 |
| 41 const media::VideoFrame::Format kInputFormat = media::VideoFrame::I420; | 43 const media::VideoFrame::Format kInputFormat = media::VideoFrame::I420; |
| 42 | 44 |
| 43 // Arbitrarily chosen to add some depth to the pipeline. | 45 // Arbitrarily chosen to add some depth to the pipeline. |
| 44 const unsigned int kNumOutputBuffers = 4; | 46 const unsigned int kNumOutputBuffers = 4; |
| 45 const unsigned int kNumExtraInputFrames = 4; | 47 const unsigned int kNumExtraInputFrames = 4; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 72 | 74 |
| 73 // The syntax of multiple test streams is: | 75 // The syntax of multiple test streams is: |
| 74 // test-stream1;test-stream2;test-stream3 | 76 // test-stream1;test-stream2;test-stream3 |
| 75 // The syntax of each test stream is: | 77 // The syntax of each test stream is: |
| 76 // "in_filename:width:height:out_filename:requested_bitrate:requested_framerate | 78 // "in_filename:width:height:out_filename:requested_bitrate:requested_framerate |
| 77 // :requested_subsequent_bitrate:requested_subsequent_framerate" | 79 // :requested_subsequent_bitrate:requested_subsequent_framerate" |
| 78 // - |in_filename| must be an I420 (YUV planar) raw stream | 80 // - |in_filename| must be an I420 (YUV planar) raw stream |
| 79 // (see http://www.fourcc.org/yuv.php#IYUV). | 81 // (see http://www.fourcc.org/yuv.php#IYUV). |
| 80 // - |width| and |height| are in pixels. | 82 // - |width| and |height| are in pixels. |
| 81 // - |profile| to encode into (values of media::VideoCodecProfile). | 83 // - |profile| to encode into (values of media::VideoCodecProfile). |
| 84 // - |temp_file| is used to prepare input buffers. | |
|
wuchengli
2014/08/29 10:03:11
This should go to struct TestStream. Right?
henryhsu
2014/09/01 05:53:45
Done.
| |
| 82 // - |out_filename| filename to save the encoded stream to (optional). | 85 // - |out_filename| filename to save the encoded stream to (optional). |
| 83 // Output stream is saved for the simple encode test only. | 86 // Output stream is saved for the simple encode test only. |
| 84 // Further parameters are optional (need to provide preceding positional | 87 // Further parameters are optional (need to provide preceding positional |
| 85 // parameters if a specific subsequent parameter is required): | 88 // parameters if a specific subsequent parameter is required): |
| 86 // - |requested_bitrate| requested bitrate in bits per second. | 89 // - |requested_bitrate| requested bitrate in bits per second. |
| 87 // - |requested_framerate| requested initial framerate. | 90 // - |requested_framerate| requested initial framerate. |
| 88 // - |requested_subsequent_bitrate| bitrate to switch to in the middle of the | 91 // - |requested_subsequent_bitrate| bitrate to switch to in the middle of the |
| 89 // stream. | 92 // stream. |
| 90 // - |requested_subsequent_framerate| framerate to switch to in the middle | 93 // - |requested_subsequent_framerate| framerate to switch to in the middle |
| 91 // of the stream. | 94 // of the stream. |
| 92 // Bitrate is only forced for tests that test bitrate. | 95 // Bitrate is only forced for tests that test bitrate. |
| 93 const char* g_default_in_filename = "bear_320x192_40frames.yuv"; | 96 const char* g_default_in_filename = "bear_320x192_40frames.yuv"; |
| 94 const char* g_default_in_parameters = ":320:192:1:out.h264:200000"; | 97 const char* g_default_in_parameters = ":320:192:1:out.h264:200000"; |
| 95 base::FilePath::StringType* g_test_stream_data; | 98 base::FilePath::StringType* g_test_stream_data; |
| 96 | 99 |
| 97 struct TestStream { | 100 struct TestStream { |
| 98 TestStream() | 101 TestStream() |
| 99 : requested_bitrate(0), | 102 : requested_bitrate(0), |
| 100 requested_framerate(0), | 103 requested_framerate(0), |
| 101 requested_subsequent_bitrate(0), | 104 requested_subsequent_bitrate(0), |
| 102 requested_subsequent_framerate(0) {} | 105 requested_subsequent_framerate(0) {} |
| 103 ~TestStream() {} | 106 ~TestStream() {} |
| 104 | 107 |
| 105 gfx::Size size; | 108 gfx::Size size; |
| 109 std::string in_filename; | |
| 106 base::MemoryMappedFile input_file; | 110 base::MemoryMappedFile input_file; |
|
wuchengli
2014/08/29 10:03:11
in_filename, input_file, and temp_file are similar
henryhsu
2014/09/01 05:53:45
Done.
| |
| 107 media::VideoCodecProfile requested_profile; | 111 media::VideoCodecProfile requested_profile; |
| 112 base::FilePath temp_file; | |
|
wuchengli
2014/08/29 10:03:11
Move this after |input_file|.
henryhsu
2014/09/01 05:53:45
Done.
| |
| 108 std::string out_filename; | 113 std::string out_filename; |
|
wuchengli
2014/08/29 10:03:11
Move this before requested_profile. Better to keep
henryhsu
2014/09/01 05:53:45
Done.
| |
| 109 unsigned int requested_bitrate; | 114 unsigned int requested_bitrate; |
| 110 unsigned int requested_framerate; | 115 unsigned int requested_framerate; |
| 111 unsigned int requested_subsequent_bitrate; | 116 unsigned int requested_subsequent_bitrate; |
| 112 unsigned int requested_subsequent_framerate; | 117 unsigned int requested_subsequent_framerate; |
| 113 }; | 118 }; |
| 114 | 119 |
| 120 // ARM performs CPU cache management with CPU cache line granularity. We thus | |
| 121 // need to ensure our buffers are CPU cache line-aligned (64 byte-aligned). | |
| 122 // Otherwise newer kernels will refuse to accept them, and on older kernels | |
| 123 // we'll be treating ourselves to random corruption. | |
| 124 // Since we are just mmapping and passing chunks of the input file, to ensure | |
| 125 // alignment, if the starting virtual addresses of YUV planes of the frames | |
| 126 // in it were not 64 byte-aligned, we'd have to prepare a memory with 64 | |
| 127 // byte-aligned starting address and make sure the addresses of YUV planes of | |
| 128 // each frame are 64 byte-aligned before sending to the encoder. | |
| 129 // Now we test resolutions different from coded size and prepare chunks before | |
| 130 // encoding to avoid performance impact. | |
| 131 // Use |visible_size| and |coded_size| to copy YUV data into memory from | |
| 132 // |in_filename|. The copied result will be saved in |input_file|. Also | |
| 133 // calculate the byte size of an input frame and set it to |coded_buffer_size|. | |
| 134 // |temp_file| is used to prepare input buffers and will be deleted after test | |
| 135 // finished. | |
| 136 static void PrepareInputBuffers(const gfx::Size& visible_size, | |
| 137 const gfx::Size& coded_size, | |
| 138 const std::string in_filename, | |
| 139 base::MemoryMappedFile* input_file, | |
| 140 base::FilePath* temp_file, | |
| 141 size_t* coded_buffer_size) { | |
| 142 size_t input_num_planes = media::VideoFrame::NumPlanes(kInputFormat); | |
| 143 std::vector<size_t> padding_sizes(input_num_planes); | |
| 144 std::vector<size_t> coded_bpl(input_num_planes); | |
| 145 std::vector<size_t> visible_bpl(input_num_planes); | |
| 146 std::vector<size_t> visible_plane_rows(input_num_planes); | |
| 147 | |
| 148 // YUV plane starting address should be 64 bytes alignment. Calculate padding | |
| 149 // size for each plane, and frame allocation size for coded size. Also store | |
| 150 // bytes per line information of coded size and visible size. | |
| 151 *coded_buffer_size = 0; | |
| 152 for (off_t i = 0; i < input_num_planes; i++) { | |
| 153 size_t size = | |
| 154 media::VideoFrame::PlaneAllocationSize(kInputFormat, i, coded_size); | |
| 155 size_t padding_bytes = ALIGN_64_BYTES(size) - size; | |
| 156 *coded_buffer_size += ALIGN_64_BYTES(size); | |
| 157 | |
| 158 coded_bpl[i] = | |
| 159 media::VideoFrame::RowBytes(i, kInputFormat, coded_size.width()); | |
| 160 visible_bpl[i] = | |
| 161 media::VideoFrame::RowBytes(i, kInputFormat, visible_size.width()); | |
| 162 visible_plane_rows[i] = | |
| 163 media::VideoFrame::Rows(i, kInputFormat, visible_size.height()); | |
| 164 size_t padding_rows = | |
| 165 media::VideoFrame::Rows(i, kInputFormat, coded_size.height()) - | |
| 166 visible_plane_rows[i]; | |
| 167 padding_sizes[i] = padding_rows * coded_bpl[i] + padding_bytes; | |
| 168 } | |
| 169 | |
| 170 // Test case may have many encoders and memory should be prepared once. | |
| 171 if (input_file->IsValid()) | |
| 172 return; | |
| 173 | |
| 174 base::MemoryMappedFile src_file; | |
| 175 CHECK(base::CreateTemporaryFile(temp_file)); | |
| 176 CHECK(src_file.Initialize(base::FilePath(in_filename))); | |
| 177 | |
| 178 size_t visible_buffer_size = | |
| 179 media::VideoFrame::AllocationSize(kInputFormat, visible_size); | |
| 180 size_t num_frames = src_file.length() / visible_buffer_size; | |
| 181 uint32 flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | | |
| 182 base::File::FLAG_READ; | |
| 183 | |
| 184 // Create a temporary file with coded_size length. | |
| 185 base::File file(base::FilePath(*temp_file), flags); | |
|
wuchengli
2014/08/29 10:03:11
|temp_file| is a FilePath. Do we need base::FilePa
henryhsu
2014/09/01 05:53:45
Done.
| |
| 186 file.SetLength(*coded_buffer_size * num_frames); | |
| 187 CHECK(input_file->Initialize(file.Pass(), true)); | |
| 188 | |
| 189 off_t src_offset = 0, dest_offset = 0; | |
| 190 while (src_offset < static_cast<off_t>(src_file.length())) { | |
| 191 for (off_t i = 0; i < input_num_planes; i++) { | |
| 192 #if defined(ARCH_CPU_ARMEL) | |
| 193 // Assert that each plane of frame starts at 64-byte boundary. | |
| 194 const uint8* ptr = input_file->data() + dest_offset; | |
| 195 ASSERT_EQ(reinterpret_cast<off_t>(ptr) & 63, 0) | |
| 196 << "Planes of frame should be mapped at a 64 byte boundary"; | |
| 197 #endif | |
| 198 for (off_t j = 0; j < visible_plane_rows[i]; j++) { | |
| 199 const uint8* src = src_file.data() + src_offset; | |
| 200 uint8* dest = input_file->data() + dest_offset; | |
| 201 memcpy(dest, src, visible_bpl[i]); | |
| 202 src_offset += visible_bpl[i]; | |
| 203 dest_offset += coded_bpl[i]; | |
| 204 } | |
| 205 dest_offset += padding_sizes[i]; | |
| 206 } | |
| 207 } | |
| 208 } | |
| 209 | |
| 115 // Parse |data| into its constituent parts, set the various output fields | 210 // Parse |data| into its constituent parts, set the various output fields |
| 116 // accordingly, read in video stream, and store them to |test_streams|. | 211 // accordingly, read in video stream, and store them to |test_streams|. |
| 117 static void ParseAndReadTestStreamData(const base::FilePath::StringType& data, | 212 static void ParseAndReadTestStreamData(const base::FilePath::StringType& data, |
| 118 ScopedVector<TestStream>* test_streams) { | 213 ScopedVector<TestStream>* test_streams) { |
| 119 // Split the string to individual test stream data. | 214 // Split the string to individual test stream data. |
| 120 std::vector<base::FilePath::StringType> test_streams_data; | 215 std::vector<base::FilePath::StringType> test_streams_data; |
| 121 base::SplitString(data, ';', &test_streams_data); | 216 base::SplitString(data, ';', &test_streams_data); |
| 122 CHECK_GE(test_streams_data.size(), 1U) << data; | 217 CHECK_GE(test_streams_data.size(), 1U) << data; |
| 123 | 218 |
| 124 // Parse each test stream data and read the input file. | 219 // Parse each test stream data and read the input file. |
| 125 for (size_t index = 0; index < test_streams_data.size(); ++index) { | 220 for (size_t index = 0; index < test_streams_data.size(); ++index) { |
| 126 std::vector<base::FilePath::StringType> fields; | 221 std::vector<base::FilePath::StringType> fields; |
| 127 base::SplitString(test_streams_data[index], ':', &fields); | 222 base::SplitString(test_streams_data[index], ':', &fields); |
| 128 CHECK_GE(fields.size(), 4U) << data; | 223 CHECK_GE(fields.size(), 4U) << data; |
| 129 CHECK_LE(fields.size(), 9U) << data; | 224 CHECK_LE(fields.size(), 9U) << data; |
| 130 TestStream* test_stream = new TestStream(); | 225 TestStream* test_stream = new TestStream(); |
| 131 | 226 |
| 132 base::FilePath::StringType filename = fields[0]; | 227 test_stream->in_filename = fields[0]; |
| 133 int width, height; | 228 int width, height; |
| 134 CHECK(base::StringToInt(fields[1], &width)); | 229 CHECK(base::StringToInt(fields[1], &width)); |
| 135 CHECK(base::StringToInt(fields[2], &height)); | 230 CHECK(base::StringToInt(fields[2], &height)); |
| 136 test_stream->size = gfx::Size(width, height); | 231 test_stream->size = gfx::Size(width, height); |
| 137 CHECK(!test_stream->size.IsEmpty()); | 232 CHECK(!test_stream->size.IsEmpty()); |
| 138 int profile; | 233 int profile; |
| 139 CHECK(base::StringToInt(fields[3], &profile)); | 234 CHECK(base::StringToInt(fields[3], &profile)); |
| 140 CHECK_GT(profile, media::VIDEO_CODEC_PROFILE_UNKNOWN); | 235 CHECK_GT(profile, media::VIDEO_CODEC_PROFILE_UNKNOWN); |
| 141 CHECK_LE(profile, media::VIDEO_CODEC_PROFILE_MAX); | 236 CHECK_LE(profile, media::VIDEO_CODEC_PROFILE_MAX); |
| 142 test_stream->requested_profile = | 237 test_stream->requested_profile = |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 154 if (fields.size() >= 8 && !fields[7].empty()) { | 249 if (fields.size() >= 8 && !fields[7].empty()) { |
| 155 CHECK(base::StringToUint(fields[7], | 250 CHECK(base::StringToUint(fields[7], |
| 156 &test_stream->requested_subsequent_bitrate)); | 251 &test_stream->requested_subsequent_bitrate)); |
| 157 } | 252 } |
| 158 | 253 |
| 159 if (fields.size() >= 9 && !fields[8].empty()) { | 254 if (fields.size() >= 9 && !fields[8].empty()) { |
| 160 CHECK(base::StringToUint(fields[8], | 255 CHECK(base::StringToUint(fields[8], |
| 161 &test_stream->requested_subsequent_framerate)); | 256 &test_stream->requested_subsequent_framerate)); |
| 162 } | 257 } |
| 163 | 258 |
| 164 CHECK(test_stream->input_file.Initialize(base::FilePath(filename))); | |
| 165 test_streams->push_back(test_stream); | 259 test_streams->push_back(test_stream); |
| 166 } | 260 } |
| 167 } | 261 } |
| 168 | 262 |
| 169 // Set default parameters of |test_streams| and update the parameters according | 263 // Set default parameters of |test_streams| and update the parameters according |
| 170 // to |mid_stream_bitrate_switch| and |mid_stream_framerate_switch|. | 264 // to |mid_stream_bitrate_switch| and |mid_stream_framerate_switch|. |
| 171 static void UpdateTestStreamData(bool mid_stream_bitrate_switch, | 265 static void UpdateTestStreamData(bool mid_stream_bitrate_switch, |
| 172 bool mid_stream_framerate_switch, | 266 bool mid_stream_framerate_switch, |
| 173 ScopedVector<TestStream>* test_streams) { | 267 ScopedVector<TestStream>* test_streams) { |
| 174 for (size_t i = 0; i < test_streams->size(); i++) { | 268 for (size_t i = 0; i < test_streams->size(); i++) { |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 361 validator.reset(new VP8Validator(frame_cb)); | 455 validator.reset(new VP8Validator(frame_cb)); |
| 362 } else { | 456 } else { |
| 363 LOG(FATAL) << "Unsupported profile: " << profile; | 457 LOG(FATAL) << "Unsupported profile: " << profile; |
| 364 } | 458 } |
| 365 | 459 |
| 366 return validator.Pass(); | 460 return validator.Pass(); |
| 367 } | 461 } |
| 368 | 462 |
| 369 class VEAClient : public VideoEncodeAccelerator::Client { | 463 class VEAClient : public VideoEncodeAccelerator::Client { |
| 370 public: | 464 public: |
| 371 VEAClient(const TestStream& test_stream, | 465 VEAClient(TestStream& test_stream, |
| 372 ClientStateNotification<ClientState>* note, | 466 ClientStateNotification<ClientState>* note, |
| 373 bool save_to_file, | 467 bool save_to_file, |
| 374 unsigned int keyframe_period, | 468 unsigned int keyframe_period, |
| 375 bool force_bitrate, | 469 bool force_bitrate, |
| 376 bool test_perf); | 470 bool test_perf); |
| 377 virtual ~VEAClient(); | 471 virtual ~VEAClient(); |
| 378 void CreateEncoder(); | 472 void CreateEncoder(); |
| 379 void DestroyEncoder(); | 473 void DestroyEncoder(); |
| 380 | 474 |
| 381 // Return the number of encoded frames per second. | 475 // Return the number of encoded frames per second. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 // the performance test. | 517 // the performance test. |
| 424 void VerifyPerf(); | 518 void VerifyPerf(); |
| 425 | 519 |
| 426 // Prepare and return a frame wrapping the data at |position| bytes in | 520 // Prepare and return a frame wrapping the data at |position| bytes in |
| 427 // the input stream, ready to be sent to encoder. | 521 // the input stream, ready to be sent to encoder. |
| 428 scoped_refptr<media::VideoFrame> PrepareInputFrame(off_t position); | 522 scoped_refptr<media::VideoFrame> PrepareInputFrame(off_t position); |
| 429 | 523 |
| 430 ClientState state_; | 524 ClientState state_; |
| 431 scoped_ptr<VideoEncodeAccelerator> encoder_; | 525 scoped_ptr<VideoEncodeAccelerator> encoder_; |
| 432 | 526 |
| 433 const TestStream& test_stream_; | 527 TestStream& test_stream_; |
| 434 // Used to notify another thread about the state. VEAClient does not own this. | 528 // Used to notify another thread about the state. VEAClient does not own this. |
| 435 ClientStateNotification<ClientState>* note_; | 529 ClientStateNotification<ClientState>* note_; |
| 436 | 530 |
| 437 // Ids assigned to VideoFrames (start at 1 for easy comparison with | 531 // Ids assigned to VideoFrames (start at 1 for easy comparison with |
| 438 // num_encoded_frames_). | 532 // num_encoded_frames_). |
| 439 std::set<int32> inputs_at_client_; | 533 std::set<int32> inputs_at_client_; |
| 440 int32 next_input_id_; | 534 int32 next_input_id_; |
| 441 | 535 |
| 442 // Ids for output BitstreamBuffers. | 536 // Ids for output BitstreamBuffers. |
| 443 typedef std::map<int32, base::SharedMemory*> IdToSHM; | 537 typedef std::map<int32, base::SharedMemory*> IdToSHM; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 500 // The time when the encoding started. | 594 // The time when the encoding started. |
| 501 base::TimeTicks encode_start_time_; | 595 base::TimeTicks encode_start_time_; |
| 502 | 596 |
| 503 // The time when the last encoded frame is ready. | 597 // The time when the last encoded frame is ready. |
| 504 base::TimeTicks last_frame_ready_time_; | 598 base::TimeTicks last_frame_ready_time_; |
| 505 | 599 |
| 506 // All methods of this class should be run on the same thread. | 600 // All methods of this class should be run on the same thread. |
| 507 base::ThreadChecker thread_checker_; | 601 base::ThreadChecker thread_checker_; |
| 508 }; | 602 }; |
| 509 | 603 |
| 510 VEAClient::VEAClient(const TestStream& test_stream, | 604 VEAClient::VEAClient(TestStream& test_stream, |
| 511 ClientStateNotification<ClientState>* note, | 605 ClientStateNotification<ClientState>* note, |
| 512 bool save_to_file, | 606 bool save_to_file, |
| 513 unsigned int keyframe_period, | 607 unsigned int keyframe_period, |
| 514 bool force_bitrate, | 608 bool force_bitrate, |
| 515 bool test_perf) | 609 bool test_perf) |
| 516 : state_(CS_CREATED), | 610 : state_(CS_CREATED), |
| 517 test_stream_(test_stream), | 611 test_stream_(test_stream), |
| 518 note_(note), | 612 note_(note), |
| 519 next_input_id_(1), | 613 next_input_id_(1), |
| 520 next_output_buffer_id_(0), | 614 next_output_buffer_id_(0), |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 545 CHECK(validator_.get()); | 639 CHECK(validator_.get()); |
| 546 | 640 |
| 547 if (save_to_file_) { | 641 if (save_to_file_) { |
| 548 CHECK(!test_stream_.out_filename.empty()); | 642 CHECK(!test_stream_.out_filename.empty()); |
| 549 base::FilePath out_filename(test_stream_.out_filename); | 643 base::FilePath out_filename(test_stream_.out_filename); |
| 550 // This creates or truncates out_filename. | 644 // This creates or truncates out_filename. |
| 551 // Without it, AppendToFile() will not work. | 645 // Without it, AppendToFile() will not work. |
| 552 EXPECT_EQ(0, base::WriteFile(out_filename, NULL, 0)); | 646 EXPECT_EQ(0, base::WriteFile(out_filename, NULL, 0)); |
| 553 } | 647 } |
| 554 | 648 |
| 555 input_buffer_size_ = | |
| 556 media::VideoFrame::AllocationSize(kInputFormat, test_stream.size); | |
| 557 CHECK_GT(input_buffer_size_, 0UL); | |
| 558 | |
| 559 // Calculate the number of frames in the input stream by dividing its length | |
| 560 // in bytes by frame size in bytes. | |
| 561 CHECK_EQ(test_stream_.input_file.length() % input_buffer_size_, 0U) | |
| 562 << "Stream byte size is not a product of calculated frame byte size"; | |
| 563 num_frames_in_stream_ = test_stream_.input_file.length() / input_buffer_size_; | |
| 564 CHECK_GT(num_frames_in_stream_, 0UL); | |
| 565 CHECK_LE(num_frames_in_stream_, kMaxFrameNum); | |
| 566 | |
| 567 // We may need to loop over the stream more than once if more frames than | |
| 568 // provided is required for bitrate tests. | |
| 569 if (force_bitrate_ && num_frames_in_stream_ < kMinFramesForBitrateTests) { | |
| 570 DVLOG(1) << "Stream too short for bitrate test (" << num_frames_in_stream_ | |
| 571 << " frames), will loop it to reach " << kMinFramesForBitrateTests | |
| 572 << " frames"; | |
| 573 num_frames_to_encode_ = kMinFramesForBitrateTests; | |
| 574 } else { | |
| 575 num_frames_to_encode_ = num_frames_in_stream_; | |
| 576 } | |
| 577 | |
| 578 thread_checker_.DetachFromThread(); | 649 thread_checker_.DetachFromThread(); |
| 579 } | 650 } |
| 580 | 651 |
| 581 VEAClient::~VEAClient() { CHECK(!has_encoder()); } | 652 VEAClient::~VEAClient() { CHECK(!has_encoder()); } |
| 582 | 653 |
| 583 void VEAClient::CreateEncoder() { | 654 void VEAClient::CreateEncoder() { |
| 584 DCHECK(thread_checker_.CalledOnValidThread()); | 655 DCHECK(thread_checker_.CalledOnValidThread()); |
| 585 CHECK(!has_encoder()); | 656 CHECK(!has_encoder()); |
| 586 | 657 |
| 587 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) | 658 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 622 return num_encoded_frames_ / duration.InSecondsF(); | 693 return num_encoded_frames_ / duration.InSecondsF(); |
| 623 } | 694 } |
| 624 | 695 |
| 625 void VEAClient::RequireBitstreamBuffers(unsigned int input_count, | 696 void VEAClient::RequireBitstreamBuffers(unsigned int input_count, |
| 626 const gfx::Size& input_coded_size, | 697 const gfx::Size& input_coded_size, |
| 627 size_t output_size) { | 698 size_t output_size) { |
| 628 DCHECK(thread_checker_.CalledOnValidThread()); | 699 DCHECK(thread_checker_.CalledOnValidThread()); |
| 629 ASSERT_EQ(state_, CS_INITIALIZED); | 700 ASSERT_EQ(state_, CS_INITIALIZED); |
| 630 SetState(CS_ENCODING); | 701 SetState(CS_ENCODING); |
| 631 | 702 |
| 632 // TODO(posciak): For now we only support input streams that meet encoder | 703 PrepareInputBuffers( |
| 633 // size requirements exactly (i.e. coded size == visible size), so that we | 704 test_stream_.size, |
| 634 // can simply mmap the stream file and feed the encoder directly with chunks | 705 input_coded_size, |
| 635 // of that, instead of memcpying from mmapped file into a separate set of | 706 test_stream_.in_filename, |
| 636 // input buffers that would meet the coded size and alignment requirements. | 707 &test_stream_.input_file, |
| 637 // If/when this is changed, the ARM-specific alignment check below should be | 708 &test_stream_.temp_file, |
| 638 // redone as well. | 709 &input_buffer_size_); |
| 710 CHECK_GT(input_buffer_size_, 0UL); | |
| 711 | |
| 712 // Calculate the number of frames in the input stream by dividing its length | |
| 713 // in bytes by frame size in bytes. | |
| 714 CHECK_EQ(test_stream_.input_file.length() % input_buffer_size_, 0U) | |
| 715 << "Stream byte size is not a product of calculated frame byte size"; | |
| 716 num_frames_in_stream_ = test_stream_.input_file.length() / input_buffer_size_; | |
| 717 CHECK_GT(num_frames_in_stream_, 0UL); | |
| 718 CHECK_LE(num_frames_in_stream_, kMaxFrameNum); | |
| 719 | |
| 720 // We may need to loop over the stream more than once if more frames than | |
| 721 // provided is required for bitrate tests. | |
| 722 if (force_bitrate_ && num_frames_in_stream_ < kMinFramesForBitrateTests) { | |
| 723 DVLOG(1) << "Stream too short for bitrate test (" << num_frames_in_stream_ | |
| 724 << " frames), will loop it to reach " << kMinFramesForBitrateTests | |
| 725 << " frames"; | |
| 726 num_frames_to_encode_ = kMinFramesForBitrateTests; | |
| 727 } else { | |
| 728 num_frames_to_encode_ = num_frames_in_stream_; | |
| 729 } | |
| 730 | |
| 639 input_coded_size_ = input_coded_size; | 731 input_coded_size_ = input_coded_size; |
| 640 ASSERT_EQ(input_coded_size_, test_stream_.size); | |
| 641 #if defined(ARCH_CPU_ARMEL) | |
| 642 // ARM performs CPU cache management with CPU cache line granularity. We thus | |
| 643 // need to ensure our buffers are CPU cache line-aligned (64 byte-aligned). | |
| 644 // Otherwise newer kernels will refuse to accept them, and on older kernels | |
| 645 // we'll be treating ourselves to random corruption. | |
| 646 // Since we are just mmapping and passing chunks of the input file, to ensure | |
| 647 // alignment, if the starting virtual addresses of the frames in it were not | |
| 648 // 64 byte-aligned, we'd have to use a separate set of input buffers and copy | |
| 649 // the frames into them before sending to the encoder. It would have been an | |
| 650 // overkill here though, because, for now at least, we only test resolutions | |
| 651 // that result in proper alignment, and it would have also interfered with | |
| 652 // performance testing. So just assert that the frame size is a multiple of | |
| 653 // 64 bytes. This ensures all frames start at 64-byte boundary, because | |
| 654 // MemoryMappedFile should be mmapp()ed at virtual page start as well. | |
| 655 ASSERT_EQ(input_buffer_size_ & 63, 0u) | |
| 656 << "Frame size has to be a multiple of 64 bytes"; | |
| 657 ASSERT_EQ(reinterpret_cast<off_t>(test_stream_.input_file.data()) & 63, 0) | |
| 658 << "Mapped file should be mapped at a 64 byte boundary"; | |
| 659 #endif | |
| 660 | |
| 661 num_required_input_buffers_ = input_count; | 732 num_required_input_buffers_ = input_count; |
| 662 ASSERT_GT(num_required_input_buffers_, 0UL); | 733 ASSERT_GT(num_required_input_buffers_, 0UL); |
| 663 | 734 |
| 664 output_buffer_size_ = output_size; | 735 output_buffer_size_ = output_size; |
| 665 ASSERT_GT(output_buffer_size_, 0UL); | 736 ASSERT_GT(output_buffer_size_, 0UL); |
| 666 | 737 |
| 667 for (unsigned int i = 0; i < kNumOutputBuffers; ++i) { | 738 for (unsigned int i = 0; i < kNumOutputBuffers; ++i) { |
| 668 base::SharedMemory* shm = new base::SharedMemory(); | 739 base::SharedMemory* shm = new base::SharedMemory(); |
| 669 CHECK(shm->CreateAndMapAnonymous(output_buffer_size_)); | 740 CHECK(shm->CreateAndMapAnonymous(output_buffer_size_)); |
| 670 output_shms_.push_back(shm); | 741 output_shms_.push_back(shm); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 736 void VEAClient::InputNoLongerNeededCallback(int32 input_id) { | 807 void VEAClient::InputNoLongerNeededCallback(int32 input_id) { |
| 737 std::set<int32>::iterator it = inputs_at_client_.find(input_id); | 808 std::set<int32>::iterator it = inputs_at_client_.find(input_id); |
| 738 ASSERT_NE(it, inputs_at_client_.end()); | 809 ASSERT_NE(it, inputs_at_client_.end()); |
| 739 inputs_at_client_.erase(it); | 810 inputs_at_client_.erase(it); |
| 740 FeedEncoderWithInputs(); | 811 FeedEncoderWithInputs(); |
| 741 } | 812 } |
| 742 | 813 |
| 743 scoped_refptr<media::VideoFrame> VEAClient::PrepareInputFrame(off_t position) { | 814 scoped_refptr<media::VideoFrame> VEAClient::PrepareInputFrame(off_t position) { |
| 744 CHECK_LE(position + input_buffer_size_, test_stream_.input_file.length()); | 815 CHECK_LE(position + input_buffer_size_, test_stream_.input_file.length()); |
| 745 | 816 |
| 746 uint8* frame_data = | 817 uint8* frame_data_y = |
| 747 const_cast<uint8*>(test_stream_.input_file.data() + position); | 818 const_cast<uint8*>(test_stream_.input_file.data() + position); |
| 819 uint8* frame_data_u = | |
| 820 frame_data_y + ALIGN_64_BYTES(media::VideoFrame::PlaneAllocationSize( | |
| 821 kInputFormat, 0, input_coded_size_)); | |
| 822 uint8* frame_data_v = | |
| 823 frame_data_u + ALIGN_64_BYTES(media::VideoFrame::PlaneAllocationSize( | |
| 824 kInputFormat, 1, input_coded_size_)); | |
| 748 | 825 |
| 749 CHECK_GT(current_framerate_, 0U); | 826 CHECK_GT(current_framerate_, 0U); |
| 750 scoped_refptr<media::VideoFrame> frame = | 827 scoped_refptr<media::VideoFrame> frame = |
| 751 media::VideoFrame::WrapExternalYuvData( | 828 media::VideoFrame::WrapExternalYuvData( |
| 752 kInputFormat, | 829 kInputFormat, |
| 753 input_coded_size_, | 830 input_coded_size_, |
| 754 gfx::Rect(test_stream_.size), | 831 gfx::Rect(test_stream_.size), |
| 755 test_stream_.size, | 832 test_stream_.size, |
| 756 input_coded_size_.width(), | 833 input_coded_size_.width(), |
| 757 input_coded_size_.width() / 2, | 834 input_coded_size_.width() / 2, |
| 758 input_coded_size_.width() / 2, | 835 input_coded_size_.width() / 2, |
| 759 frame_data, | 836 frame_data_y, |
| 760 frame_data + input_coded_size_.GetArea(), | 837 frame_data_u, |
| 761 frame_data + (input_coded_size_.GetArea() * 5 / 4), | 838 frame_data_v, |
| 762 base::TimeDelta().FromMilliseconds( | 839 base::TimeDelta().FromMilliseconds( |
| 763 next_input_id_ * base::Time::kMillisecondsPerSecond / | 840 next_input_id_ * base::Time::kMillisecondsPerSecond / |
| 764 current_framerate_), | 841 current_framerate_), |
| 765 media::BindToCurrentLoop( | 842 media::BindToCurrentLoop( |
| 766 base::Bind(&VEAClient::InputNoLongerNeededCallback, | 843 base::Bind(&VEAClient::InputNoLongerNeededCallback, |
| 767 base::Unretained(this), | 844 base::Unretained(this), |
| 768 next_input_id_))); | 845 next_input_id_))); |
| 769 | 846 |
| 770 CHECK(inputs_at_client_.insert(next_input_id_).second); | 847 CHECK(inputs_at_client_.insert(next_input_id_).second); |
| 771 ++next_input_id_; | 848 ++next_input_id_; |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 966 for (size_t state_no = 0; state_no < arraysize(state_transitions); ++state_no) | 1043 for (size_t state_no = 0; state_no < arraysize(state_transitions); ++state_no) |
| 967 for (size_t i = 0; i < num_concurrent_encoders; i++) | 1044 for (size_t i = 0; i < num_concurrent_encoders; i++) |
| 968 ASSERT_EQ(notes[i]->Wait(), state_transitions[state_no]); | 1045 ASSERT_EQ(notes[i]->Wait(), state_transitions[state_no]); |
| 969 | 1046 |
| 970 for (size_t i = 0; i < num_concurrent_encoders; ++i) { | 1047 for (size_t i = 0; i < num_concurrent_encoders; ++i) { |
| 971 encoder_thread.message_loop()->PostTask( | 1048 encoder_thread.message_loop()->PostTask( |
| 972 FROM_HERE, | 1049 FROM_HERE, |
| 973 base::Bind(&VEAClient::DestroyEncoder, base::Unretained(clients[i]))); | 1050 base::Bind(&VEAClient::DestroyEncoder, base::Unretained(clients[i]))); |
| 974 } | 1051 } |
| 975 | 1052 |
| 1053 for (size_t i = 0; i < test_streams.size(); i++) | |
|
wuchengli
2014/08/29 10:03:11
We should close the memory mapped files before del
henryhsu
2014/09/01 05:53:45
Done.
| |
| 1054 base::DeleteFile(test_streams[i]->temp_file, false); | |
| 1055 | |
| 976 // This ensures all tasks have finished. | 1056 // This ensures all tasks have finished. |
| 977 encoder_thread.Stop(); | 1057 encoder_thread.Stop(); |
| 978 } | 1058 } |
| 979 | 1059 |
| 980 INSTANTIATE_TEST_CASE_P( | 1060 INSTANTIATE_TEST_CASE_P( |
| 981 SimpleEncode, | 1061 SimpleEncode, |
| 982 VideoEncodeAcceleratorTest, | 1062 VideoEncodeAcceleratorTest, |
| 983 ::testing::Values(MakeTuple(1, true, 0, false, false, false, false))); | 1063 ::testing::Values(MakeTuple(1, true, 0, false, false, false, false))); |
| 984 | 1064 |
| 985 INSTANTIATE_TEST_CASE_P( | 1065 INSTANTIATE_TEST_CASE_P( |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1054 test_stream_data->assign(it->second.c_str()); | 1134 test_stream_data->assign(it->second.c_str()); |
| 1055 continue; | 1135 continue; |
| 1056 } | 1136 } |
| 1057 if (it->first == "v" || it->first == "vmodule") | 1137 if (it->first == "v" || it->first == "vmodule") |
| 1058 continue; | 1138 continue; |
| 1059 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; | 1139 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; |
| 1060 } | 1140 } |
| 1061 | 1141 |
| 1062 return RUN_ALL_TESTS(); | 1142 return RUN_ALL_TESTS(); |
| 1063 } | 1143 } |
| OLD | NEW |