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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 85 // parameters if a specific subsequent parameter is required): | 85 // parameters if a specific subsequent parameter is required): |
| 86 // - |requested_bitrate| requested bitrate in bits per second. | 86 // - |requested_bitrate| requested bitrate in bits per second. |
| 87 // - |requested_framerate| requested initial framerate. | 87 // - |requested_framerate| requested initial framerate. |
| 88 // - |requested_subsequent_bitrate| bitrate to switch to in the middle of the | 88 // - |requested_subsequent_bitrate| bitrate to switch to in the middle of the |
| 89 // stream. | 89 // stream. |
| 90 // - |requested_subsequent_framerate| framerate to switch to in the middle | 90 // - |requested_subsequent_framerate| framerate to switch to in the middle |
| 91 // of the stream. | 91 // of the stream. |
| 92 // Bitrate is only forced for tests that test bitrate. | 92 // Bitrate is only forced for tests that test bitrate. |
| 93 const char* g_default_in_filename = "bear_320x192_40frames.yuv"; | 93 const char* g_default_in_filename = "bear_320x192_40frames.yuv"; |
| 94 const char* g_default_in_parameters = ":320:192:1:out.h264:200000"; | 94 const char* g_default_in_parameters = ":320:192:1:out.h264:200000"; |
| 95 base::FilePath::StringType* g_test_stream_data; | 95 // Environment to store test stream data for all test cases. |
| 96 class VideoEncodeAcceleratorTestEnvironment; | |
| 97 VideoEncodeAcceleratorTestEnvironment* g_env; | |
| 96 | 98 |
| 97 struct TestStream { | 99 struct TestStream { |
| 98 TestStream() | 100 TestStream() |
| 99 : requested_bitrate(0), | 101 : num_frames(0), |
| 102 aligned_buffer_size(0), | |
| 103 requested_bitrate(0), | |
| 100 requested_framerate(0), | 104 requested_framerate(0), |
| 101 requested_subsequent_bitrate(0), | 105 requested_subsequent_bitrate(0), |
| 102 requested_subsequent_framerate(0) {} | 106 requested_subsequent_framerate(0) {} |
| 103 ~TestStream() {} | 107 ~TestStream() {} |
| 104 | 108 |
| 105 gfx::Size size; | 109 gfx::Size visible_size; |
| 106 base::MemoryMappedFile input_file; | 110 gfx::Size coded_size; |
| 111 unsigned int num_frames; | |
| 112 | |
| 113 // Original unaligned input file name provided as an argument to the test. | |
| 114 // And the file must be an I420 (YUV planar) raw stream. | |
| 115 std::string in_filename; | |
| 116 | |
| 117 // A temporary file used to prepare aligned input buffers of |in_filename|. | |
| 118 // The file makes sure starting address of YUV planes are 64 byte-aligned. | |
| 119 base::FilePath aligned_in_file; | |
| 120 | |
| 121 // The memory mapping of |aligned_in_file| | |
| 122 base::MemoryMappedFile mapped_aligned_in_file; | |
| 123 | |
| 124 // Byte size of a frame of |aligned_in_file|. | |
| 125 size_t aligned_buffer_size; | |
| 126 | |
| 127 // Byte size for each aligned plane of a frame | |
| 128 std::vector<size_t> aligned_plane_size; | |
| 129 | |
| 130 std::string out_filename; | |
| 107 media::VideoCodecProfile requested_profile; | 131 media::VideoCodecProfile requested_profile; |
| 108 std::string out_filename; | |
| 109 unsigned int requested_bitrate; | 132 unsigned int requested_bitrate; |
| 110 unsigned int requested_framerate; | 133 unsigned int requested_framerate; |
| 111 unsigned int requested_subsequent_bitrate; | 134 unsigned int requested_subsequent_bitrate; |
| 112 unsigned int requested_subsequent_framerate; | 135 unsigned int requested_subsequent_framerate; |
| 113 }; | 136 }; |
| 114 | 137 |
| 138 inline static size_t Align64Bytes(size_t value) { | |
| 139 return (value + 63) & ~63; | |
| 140 } | |
| 141 | |
| 142 // Write |data| of |size| bytes at |offset| bytes into |file|. | |
| 143 static bool WriteFile(base::File* file, | |
| 144 const off_t offset, | |
| 145 const uint8* data, | |
| 146 size_t size) { | |
| 147 size_t written_bytes = 0; | |
| 148 while (written_bytes < size) { | |
| 149 int bytes = file->Write(offset + written_bytes, | |
| 150 reinterpret_cast<const char*>(data + written_bytes), | |
| 151 size - written_bytes); | |
| 152 if (bytes <= 0) | |
| 153 return false; | |
| 154 written_bytes += bytes; | |
| 155 } | |
| 156 return true; | |
| 157 } | |
| 158 | |
| 159 // ARM performs CPU cache management with CPU cache line granularity. We thus | |
| 160 // need to ensure our buffers are CPU cache line-aligned (64 byte-aligned). | |
| 161 // Otherwise newer kernels will refuse to accept them, and on older kernels | |
| 162 // we'll be treating ourselves to random corruption. | |
| 163 // Since we are just mapping and passing chunks of the input file directly to | |
| 164 // the VEA as input frames to avoid copying large chunks of raw data on each | |
| 165 // frame and thus affecting performance measurements, we have to prepare a | |
| 166 // temporary file with all planes aligned to 64-byte boundaries beforehand. | |
| 167 static void CreateAlignedInputStreamFile(const gfx::Size& coded_size, | |
| 168 TestStream* test_stream) { | |
| 169 // Test case may have many encoders and memory should be prepared once. | |
| 170 if (test_stream->coded_size == coded_size && | |
| 171 test_stream->mapped_aligned_in_file.IsValid()) | |
| 172 return; | |
| 173 | |
| 174 ASSERT_TRUE(!test_stream->mapped_aligned_in_file.IsValid() || | |
|
Pawel Osciak
2014/09/17 13:42:02
Please add a comment why.
henryhsu
2014/09/18 03:41:23
Done.
| |
| 175 coded_size == test_stream->coded_size); | |
| 176 test_stream->coded_size = coded_size; | |
| 177 | |
| 178 size_t num_planes = media::VideoFrame::NumPlanes(kInputFormat); | |
| 179 std::vector<size_t> padding_sizes(num_planes); | |
| 180 std::vector<size_t> coded_bpl(num_planes); | |
| 181 std::vector<size_t> visible_bpl(num_planes); | |
| 182 std::vector<size_t> visible_plane_rows(num_planes); | |
| 183 | |
| 184 // Calculate padding in bytes to be added after each plane required to keep | |
| 185 // starting addresses of all planes at a 64 byte boudnary. This padding will | |
| 186 // be added after each plane when copying to the temporary file. | |
| 187 // At the same time we also need to take into account coded_size requested by | |
| 188 // the VEA; each row of visible_bpl bytes in the original file needs to be | |
| 189 // copied into a row of coded_bpl bytes in the aligned file. | |
| 190 for (size_t i = 0; i < num_planes; i++) { | |
| 191 size_t size = | |
| 192 media::VideoFrame::PlaneAllocationSize(kInputFormat, i, coded_size); | |
| 193 test_stream->aligned_plane_size.push_back(Align64Bytes(size)); | |
| 194 test_stream->aligned_buffer_size += test_stream->aligned_plane_size.back(); | |
| 195 | |
| 196 coded_bpl[i] = | |
| 197 media::VideoFrame::RowBytes(i, kInputFormat, coded_size.width()); | |
| 198 visible_bpl[i] = media::VideoFrame::RowBytes( | |
| 199 i, kInputFormat, test_stream->visible_size.width()); | |
| 200 visible_plane_rows[i] = media::VideoFrame::Rows( | |
| 201 i, kInputFormat, test_stream->visible_size.height()); | |
| 202 size_t padding_rows = | |
| 203 media::VideoFrame::Rows(i, kInputFormat, coded_size.height()) - | |
| 204 visible_plane_rows[i]; | |
| 205 padding_sizes[i] = Align64Bytes(padding_rows * coded_bpl[i]); | |
| 206 } | |
| 207 | |
| 208 base::MemoryMappedFile src_file; | |
| 209 CHECK(src_file.Initialize(base::FilePath(test_stream->in_filename))); | |
| 210 CHECK(base::CreateTemporaryFile(&test_stream->aligned_in_file)); | |
| 211 | |
| 212 size_t visible_buffer_size = media::VideoFrame::AllocationSize( | |
| 213 kInputFormat, test_stream->visible_size); | |
| 214 CHECK_EQ(src_file.length() % visible_buffer_size, 0U) | |
| 215 << "Stream byte size is not a product of calculated frame byte size"; | |
| 216 | |
| 217 test_stream->num_frames = src_file.length() / visible_buffer_size; | |
| 218 uint32 flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | | |
| 219 base::File::FLAG_READ; | |
| 220 | |
| 221 // Create a temporary file with coded_size length. | |
| 222 base::File dest_file(test_stream->aligned_in_file, flags); | |
| 223 CHECK_GT(test_stream->aligned_buffer_size, 0UL); | |
| 224 dest_file.SetLength(test_stream->aligned_buffer_size * | |
| 225 test_stream->num_frames); | |
| 226 | |
| 227 const uint8* src = src_file.data(); | |
| 228 off_t dest_offset = 0; | |
| 229 for (size_t frame = 0; frame < test_stream->num_frames; frame++) { | |
| 230 for (size_t i = 0; i < num_planes; i++) { | |
| 231 // Assert that each plane of frame starts at 64 byte boundary. | |
| 232 ASSERT_EQ(dest_offset & 63, 0) | |
| 233 << "Planes of frame should be mapped at a 64 byte boundary"; | |
| 234 for (size_t j = 0; j < visible_plane_rows[i]; j++) { | |
| 235 CHECK(WriteFile(&dest_file, dest_offset, src, visible_bpl[i])); | |
| 236 src += visible_bpl[i]; | |
| 237 dest_offset += coded_bpl[i]; | |
| 238 } | |
| 239 dest_offset += padding_sizes[i]; | |
| 240 } | |
| 241 } | |
| 242 CHECK(test_stream->mapped_aligned_in_file.Initialize(dest_file.Pass())); | |
| 243 // Assert that memory mapped of file starts at 64 byte boundary. So each | |
| 244 // plane of frames also start at 64 byte boundary. | |
| 245 ASSERT_EQ( | |
| 246 reinterpret_cast<off_t>(test_stream->mapped_aligned_in_file.data()) & 63, | |
| 247 0) | |
| 248 << "File should be mapped at a 64 byte boundary"; | |
| 249 | |
| 250 CHECK_EQ(test_stream->mapped_aligned_in_file.length() % | |
| 251 test_stream->aligned_buffer_size, | |
| 252 0U) | |
| 253 << "Stream byte size is not a product of calculated frame byte size"; | |
| 254 CHECK_GT(test_stream->num_frames, 0UL); | |
| 255 CHECK_LE(test_stream->num_frames, kMaxFrameNum); | |
| 256 } | |
| 257 | |
| 115 // Parse |data| into its constituent parts, set the various output fields | 258 // Parse |data| into its constituent parts, set the various output fields |
| 116 // accordingly, read in video stream, and store them to |test_streams|. | 259 // accordingly, read in video stream, and store them to |test_streams|. |
| 117 static void ParseAndReadTestStreamData(const base::FilePath::StringType& data, | 260 static void ParseAndReadTestStreamData(const base::FilePath::StringType& data, |
| 118 ScopedVector<TestStream>* test_streams) { | 261 ScopedVector<TestStream>* test_streams) { |
| 119 // Split the string to individual test stream data. | 262 // Split the string to individual test stream data. |
| 120 std::vector<base::FilePath::StringType> test_streams_data; | 263 std::vector<base::FilePath::StringType> test_streams_data; |
| 121 base::SplitString(data, ';', &test_streams_data); | 264 base::SplitString(data, ';', &test_streams_data); |
| 122 CHECK_GE(test_streams_data.size(), 1U) << data; | 265 CHECK_GE(test_streams_data.size(), 1U) << data; |
| 123 | 266 |
| 124 // Parse each test stream data and read the input file. | 267 // Parse each test stream data and read the input file. |
| 125 for (size_t index = 0; index < test_streams_data.size(); ++index) { | 268 for (size_t index = 0; index < test_streams_data.size(); ++index) { |
| 126 std::vector<base::FilePath::StringType> fields; | 269 std::vector<base::FilePath::StringType> fields; |
| 127 base::SplitString(test_streams_data[index], ':', &fields); | 270 base::SplitString(test_streams_data[index], ':', &fields); |
| 128 CHECK_GE(fields.size(), 4U) << data; | 271 CHECK_GE(fields.size(), 4U) << data; |
| 129 CHECK_LE(fields.size(), 9U) << data; | 272 CHECK_LE(fields.size(), 9U) << data; |
| 130 TestStream* test_stream = new TestStream(); | 273 TestStream* test_stream = new TestStream(); |
| 131 | 274 |
| 132 base::FilePath::StringType filename = fields[0]; | 275 test_stream->in_filename = fields[0]; |
| 133 int width, height; | 276 int width, height; |
| 134 CHECK(base::StringToInt(fields[1], &width)); | 277 CHECK(base::StringToInt(fields[1], &width)); |
| 135 CHECK(base::StringToInt(fields[2], &height)); | 278 CHECK(base::StringToInt(fields[2], &height)); |
| 136 test_stream->size = gfx::Size(width, height); | 279 test_stream->visible_size = gfx::Size(width, height); |
| 137 CHECK(!test_stream->size.IsEmpty()); | 280 CHECK(!test_stream->visible_size.IsEmpty()); |
| 138 int profile; | 281 int profile; |
| 139 CHECK(base::StringToInt(fields[3], &profile)); | 282 CHECK(base::StringToInt(fields[3], &profile)); |
| 140 CHECK_GT(profile, media::VIDEO_CODEC_PROFILE_UNKNOWN); | 283 CHECK_GT(profile, media::VIDEO_CODEC_PROFILE_UNKNOWN); |
| 141 CHECK_LE(profile, media::VIDEO_CODEC_PROFILE_MAX); | 284 CHECK_LE(profile, media::VIDEO_CODEC_PROFILE_MAX); |
| 142 test_stream->requested_profile = | 285 test_stream->requested_profile = |
| 143 static_cast<media::VideoCodecProfile>(profile); | 286 static_cast<media::VideoCodecProfile>(profile); |
| 144 | 287 |
| 145 if (fields.size() >= 5 && !fields[4].empty()) | 288 if (fields.size() >= 5 && !fields[4].empty()) |
| 146 test_stream->out_filename = fields[4]; | 289 test_stream->out_filename = fields[4]; |
| 147 | 290 |
| 148 if (fields.size() >= 6 && !fields[5].empty()) | 291 if (fields.size() >= 6 && !fields[5].empty()) |
| 149 CHECK(base::StringToUint(fields[5], &test_stream->requested_bitrate)); | 292 CHECK(base::StringToUint(fields[5], &test_stream->requested_bitrate)); |
| 150 | 293 |
| 151 if (fields.size() >= 7 && !fields[6].empty()) | 294 if (fields.size() >= 7 && !fields[6].empty()) |
| 152 CHECK(base::StringToUint(fields[6], &test_stream->requested_framerate)); | 295 CHECK(base::StringToUint(fields[6], &test_stream->requested_framerate)); |
| 153 | 296 |
| 154 if (fields.size() >= 8 && !fields[7].empty()) { | 297 if (fields.size() >= 8 && !fields[7].empty()) { |
| 155 CHECK(base::StringToUint(fields[7], | 298 CHECK(base::StringToUint(fields[7], |
| 156 &test_stream->requested_subsequent_bitrate)); | 299 &test_stream->requested_subsequent_bitrate)); |
| 157 } | 300 } |
| 158 | 301 |
| 159 if (fields.size() >= 9 && !fields[8].empty()) { | 302 if (fields.size() >= 9 && !fields[8].empty()) { |
| 160 CHECK(base::StringToUint(fields[8], | 303 CHECK(base::StringToUint(fields[8], |
| 161 &test_stream->requested_subsequent_framerate)); | 304 &test_stream->requested_subsequent_framerate)); |
| 162 } | 305 } |
| 163 | |
| 164 CHECK(test_stream->input_file.Initialize(base::FilePath(filename))); | |
| 165 test_streams->push_back(test_stream); | 306 test_streams->push_back(test_stream); |
| 166 } | 307 } |
| 167 } | 308 } |
| 168 | 309 |
| 169 // Set default parameters of |test_streams| and update the parameters according | |
| 170 // to |mid_stream_bitrate_switch| and |mid_stream_framerate_switch|. | |
| 171 static void UpdateTestStreamData(bool mid_stream_bitrate_switch, | |
| 172 bool mid_stream_framerate_switch, | |
| 173 ScopedVector<TestStream>* test_streams) { | |
| 174 for (size_t i = 0; i < test_streams->size(); i++) { | |
| 175 TestStream* test_stream = (*test_streams)[i]; | |
| 176 // Use defaults for bitrate/framerate if they are not provided. | |
| 177 if (test_stream->requested_bitrate == 0) | |
| 178 test_stream->requested_bitrate = kDefaultBitrate; | |
| 179 | |
| 180 if (test_stream->requested_framerate == 0) | |
| 181 test_stream->requested_framerate = kDefaultFramerate; | |
| 182 | |
| 183 // If bitrate/framerate switch is requested, use the subsequent values if | |
| 184 // provided, or, if not, calculate them from their initial values using | |
| 185 // the default ratios. | |
| 186 // Otherwise, if a switch is not requested, keep the initial values. | |
| 187 if (mid_stream_bitrate_switch) { | |
| 188 if (test_stream->requested_subsequent_bitrate == 0) { | |
| 189 test_stream->requested_subsequent_bitrate = | |
| 190 test_stream->requested_bitrate * kDefaultSubsequentBitrateRatio; | |
| 191 } | |
| 192 } else { | |
| 193 test_stream->requested_subsequent_bitrate = | |
| 194 test_stream->requested_bitrate; | |
| 195 } | |
| 196 if (test_stream->requested_subsequent_bitrate == 0) | |
| 197 test_stream->requested_subsequent_bitrate = 1; | |
| 198 | |
| 199 if (mid_stream_framerate_switch) { | |
| 200 if (test_stream->requested_subsequent_framerate == 0) { | |
| 201 test_stream->requested_subsequent_framerate = | |
| 202 test_stream->requested_framerate * kDefaultSubsequentFramerateRatio; | |
| 203 } | |
| 204 } else { | |
| 205 test_stream->requested_subsequent_framerate = | |
| 206 test_stream->requested_framerate; | |
| 207 } | |
| 208 if (test_stream->requested_subsequent_framerate == 0) | |
| 209 test_stream->requested_subsequent_framerate = 1; | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 enum ClientState { | 310 enum ClientState { |
| 214 CS_CREATED, | 311 CS_CREATED, |
| 215 CS_ENCODER_SET, | 312 CS_ENCODER_SET, |
| 216 CS_INITIALIZED, | 313 CS_INITIALIZED, |
| 217 CS_ENCODING, | 314 CS_ENCODING, |
| 218 CS_FINISHED, | 315 CS_FINISHED, |
| 219 CS_ERROR, | 316 CS_ERROR, |
| 220 }; | 317 }; |
| 221 | 318 |
| 222 // Performs basic, codec-specific sanity checks on the stream buffers passed | 319 // Performs basic, codec-specific sanity checks on the stream buffers passed |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 361 validator.reset(new VP8Validator(frame_cb)); | 458 validator.reset(new VP8Validator(frame_cb)); |
| 362 } else { | 459 } else { |
| 363 LOG(FATAL) << "Unsupported profile: " << profile; | 460 LOG(FATAL) << "Unsupported profile: " << profile; |
| 364 } | 461 } |
| 365 | 462 |
| 366 return validator.Pass(); | 463 return validator.Pass(); |
| 367 } | 464 } |
| 368 | 465 |
| 369 class VEAClient : public VideoEncodeAccelerator::Client { | 466 class VEAClient : public VideoEncodeAccelerator::Client { |
| 370 public: | 467 public: |
| 371 VEAClient(const TestStream& test_stream, | 468 VEAClient(TestStream* test_stream, |
| 372 ClientStateNotification<ClientState>* note, | 469 ClientStateNotification<ClientState>* note, |
| 373 bool save_to_file, | 470 bool save_to_file, |
| 374 unsigned int keyframe_period, | 471 unsigned int keyframe_period, |
| 375 bool force_bitrate, | 472 bool force_bitrate, |
| 376 bool test_perf); | 473 bool test_perf, |
| 474 bool mid_stream_bitrate_switch, | |
| 475 bool mid_stream_framerate_switch); | |
| 377 virtual ~VEAClient(); | 476 virtual ~VEAClient(); |
| 378 void CreateEncoder(); | 477 void CreateEncoder(); |
| 379 void DestroyEncoder(); | 478 void DestroyEncoder(); |
| 380 | 479 |
| 381 // Return the number of encoded frames per second. | 480 // Return the number of encoded frames per second. |
| 382 double frames_per_second(); | 481 double frames_per_second(); |
| 383 | 482 |
| 384 // VideoDecodeAccelerator::Client implementation. | 483 // VideoDecodeAccelerator::Client implementation. |
| 385 virtual void RequireBitstreamBuffers(unsigned int input_count, | 484 virtual void RequireBitstreamBuffers(unsigned int input_count, |
| 386 const gfx::Size& input_coded_size, | 485 const gfx::Size& input_coded_size, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 void VerifyStreamProperties(); | 519 void VerifyStreamProperties(); |
| 421 | 520 |
| 422 // Test codec performance, failing the test if we are currently running | 521 // Test codec performance, failing the test if we are currently running |
| 423 // the performance test. | 522 // the performance test. |
| 424 void VerifyPerf(); | 523 void VerifyPerf(); |
| 425 | 524 |
| 426 // Prepare and return a frame wrapping the data at |position| bytes in | 525 // Prepare and return a frame wrapping the data at |position| bytes in |
| 427 // the input stream, ready to be sent to encoder. | 526 // the input stream, ready to be sent to encoder. |
| 428 scoped_refptr<media::VideoFrame> PrepareInputFrame(off_t position); | 527 scoped_refptr<media::VideoFrame> PrepareInputFrame(off_t position); |
| 429 | 528 |
| 529 // Update the parameters according to |mid_stream_bitrate_switch| and | |
| 530 // |mid_stream_framerate_switch|. | |
| 531 void UpdateTestStreamData(bool mid_stream_bitrate_switch, | |
| 532 bool mid_stream_framerate_switch); | |
| 533 | |
| 430 ClientState state_; | 534 ClientState state_; |
| 431 scoped_ptr<VideoEncodeAccelerator> encoder_; | 535 scoped_ptr<VideoEncodeAccelerator> encoder_; |
| 432 | 536 |
| 433 const TestStream& test_stream_; | 537 TestStream* test_stream_; |
| 434 // Used to notify another thread about the state. VEAClient does not own this. | 538 // Used to notify another thread about the state. VEAClient does not own this. |
| 435 ClientStateNotification<ClientState>* note_; | 539 ClientStateNotification<ClientState>* note_; |
| 436 | 540 |
| 437 // Ids assigned to VideoFrames (start at 1 for easy comparison with | 541 // Ids assigned to VideoFrames (start at 1 for easy comparison with |
| 438 // num_encoded_frames_). | 542 // num_encoded_frames_). |
| 439 std::set<int32> inputs_at_client_; | 543 std::set<int32> inputs_at_client_; |
| 440 int32 next_input_id_; | 544 int32 next_input_id_; |
| 441 | 545 |
| 442 // Ids for output BitstreamBuffers. | 546 // Ids for output BitstreamBuffers. |
| 443 typedef std::map<int32, base::SharedMemory*> IdToSHM; | 547 typedef std::map<int32, base::SharedMemory*> IdToSHM; |
| 444 ScopedVector<base::SharedMemory> output_shms_; | 548 ScopedVector<base::SharedMemory> output_shms_; |
| 445 IdToSHM output_buffers_at_client_; | 549 IdToSHM output_buffers_at_client_; |
| 446 int32 next_output_buffer_id_; | 550 int32 next_output_buffer_id_; |
| 447 | 551 |
| 448 // Current offset into input stream. | 552 // Current offset into input stream. |
| 449 off_t pos_in_input_stream_; | 553 off_t pos_in_input_stream_; |
| 450 // Byte size of an input frame. | |
| 451 size_t input_buffer_size_; | |
| 452 gfx::Size input_coded_size_; | 554 gfx::Size input_coded_size_; |
| 453 // Requested by encoder. | 555 // Requested by encoder. |
| 454 unsigned int num_required_input_buffers_; | 556 unsigned int num_required_input_buffers_; |
| 455 size_t output_buffer_size_; | 557 size_t output_buffer_size_; |
| 456 | 558 |
| 457 // Precalculated number of frames in the stream. | 559 // Number of frames to encode. This may differ from the number of frames in |
| 458 unsigned int num_frames_in_stream_; | 560 // stream if we need more frames for bitrate tests. |
| 459 | |
| 460 // Number of frames to encode. This may differ from num_frames_in_stream_ if | |
| 461 // we need more frames for bitrate tests. | |
| 462 unsigned int num_frames_to_encode_; | 561 unsigned int num_frames_to_encode_; |
| 463 | 562 |
| 464 // Number of encoded frames we've got from the encoder thus far. | 563 // Number of encoded frames we've got from the encoder thus far. |
| 465 unsigned int num_encoded_frames_; | 564 unsigned int num_encoded_frames_; |
| 466 | 565 |
| 467 // Frames since last bitrate verification. | 566 // Frames since last bitrate verification. |
| 468 unsigned int num_frames_since_last_check_; | 567 unsigned int num_frames_since_last_check_; |
| 469 | 568 |
| 470 // True if received a keyframe while processing current bitstream buffer. | 569 // True if received a keyframe while processing current bitstream buffer. |
| 471 bool seen_keyframe_in_this_buffer_; | 570 bool seen_keyframe_in_this_buffer_; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 498 scoped_ptr<StreamValidator> validator_; | 597 scoped_ptr<StreamValidator> validator_; |
| 499 | 598 |
| 500 // The time when the encoding started. | 599 // The time when the encoding started. |
| 501 base::TimeTicks encode_start_time_; | 600 base::TimeTicks encode_start_time_; |
| 502 | 601 |
| 503 // The time when the last encoded frame is ready. | 602 // The time when the last encoded frame is ready. |
| 504 base::TimeTicks last_frame_ready_time_; | 603 base::TimeTicks last_frame_ready_time_; |
| 505 | 604 |
| 506 // All methods of this class should be run on the same thread. | 605 // All methods of this class should be run on the same thread. |
| 507 base::ThreadChecker thread_checker_; | 606 base::ThreadChecker thread_checker_; |
| 607 | |
| 608 // Requested bitrate in bits per second. | |
| 609 unsigned int requested_bitrate_; | |
| 610 | |
| 611 // Requested initial framerate. | |
| 612 unsigned int requested_framerate_; | |
| 613 | |
| 614 // Bitrate to switch to in the middle of the stream. | |
| 615 unsigned int requested_subsequent_bitrate_; | |
| 616 | |
| 617 // Framerate to switch to in the middle of the stream. | |
| 618 unsigned int requested_subsequent_framerate_; | |
| 508 }; | 619 }; |
| 509 | 620 |
| 510 VEAClient::VEAClient(const TestStream& test_stream, | 621 VEAClient::VEAClient(TestStream* test_stream, |
| 511 ClientStateNotification<ClientState>* note, | 622 ClientStateNotification<ClientState>* note, |
| 512 bool save_to_file, | 623 bool save_to_file, |
| 513 unsigned int keyframe_period, | 624 unsigned int keyframe_period, |
| 514 bool force_bitrate, | 625 bool force_bitrate, |
| 515 bool test_perf) | 626 bool test_perf, |
| 627 bool mid_stream_bitrate_switch, | |
| 628 bool mid_stream_framerate_switch) | |
| 516 : state_(CS_CREATED), | 629 : state_(CS_CREATED), |
| 517 test_stream_(test_stream), | 630 test_stream_(test_stream), |
| 518 note_(note), | 631 note_(note), |
| 519 next_input_id_(1), | 632 next_input_id_(1), |
| 520 next_output_buffer_id_(0), | 633 next_output_buffer_id_(0), |
| 521 pos_in_input_stream_(0), | 634 pos_in_input_stream_(0), |
| 522 input_buffer_size_(0), | |
| 523 num_required_input_buffers_(0), | 635 num_required_input_buffers_(0), |
| 524 output_buffer_size_(0), | 636 output_buffer_size_(0), |
| 525 num_frames_in_stream_(0), | |
| 526 num_frames_to_encode_(0), | 637 num_frames_to_encode_(0), |
| 527 num_encoded_frames_(0), | 638 num_encoded_frames_(0), |
| 528 num_frames_since_last_check_(0), | 639 num_frames_since_last_check_(0), |
| 529 seen_keyframe_in_this_buffer_(false), | 640 seen_keyframe_in_this_buffer_(false), |
| 530 save_to_file_(save_to_file), | 641 save_to_file_(save_to_file), |
| 531 keyframe_period_(keyframe_period), | 642 keyframe_period_(keyframe_period), |
| 532 keyframe_requested_at_(kMaxFrameNum), | 643 keyframe_requested_at_(kMaxFrameNum), |
| 533 force_bitrate_(force_bitrate), | 644 force_bitrate_(force_bitrate), |
| 534 current_requested_bitrate_(0), | 645 current_requested_bitrate_(0), |
| 535 current_framerate_(0), | 646 current_framerate_(0), |
| 536 encoded_stream_size_since_last_check_(0), | 647 encoded_stream_size_since_last_check_(0), |
| 537 test_perf_(test_perf) { | 648 test_perf_(test_perf), |
| 649 requested_bitrate_(0), | |
| 650 requested_framerate_(0), | |
| 651 requested_subsequent_bitrate_(0), | |
| 652 requested_subsequent_framerate_(0) { | |
| 538 if (keyframe_period_) | 653 if (keyframe_period_) |
| 539 CHECK_LT(kMaxKeyframeDelay, keyframe_period_); | 654 CHECK_LT(kMaxKeyframeDelay, keyframe_period_); |
| 540 | 655 |
| 541 validator_ = StreamValidator::Create( | 656 validator_ = StreamValidator::Create( |
| 542 test_stream_.requested_profile, | 657 test_stream_->requested_profile, |
| 543 base::Bind(&VEAClient::HandleEncodedFrame, base::Unretained(this))); | 658 base::Bind(&VEAClient::HandleEncodedFrame, base::Unretained(this))); |
| 544 | 659 |
| 545 CHECK(validator_.get()); | 660 CHECK(validator_.get()); |
| 546 | 661 |
| 547 if (save_to_file_) { | 662 if (save_to_file_) { |
| 548 CHECK(!test_stream_.out_filename.empty()); | 663 CHECK(!test_stream_->out_filename.empty()); |
| 549 base::FilePath out_filename(test_stream_.out_filename); | 664 base::FilePath out_filename(test_stream_->out_filename); |
| 550 // This creates or truncates out_filename. | 665 // This creates or truncates out_filename. |
| 551 // Without it, AppendToFile() will not work. | 666 // Without it, AppendToFile() will not work. |
| 552 EXPECT_EQ(0, base::WriteFile(out_filename, NULL, 0)); | 667 EXPECT_EQ(0, base::WriteFile(out_filename, NULL, 0)); |
| 553 } | 668 } |
| 554 | 669 |
| 555 input_buffer_size_ = | 670 // Initialize the parameters of the test streams. |
| 556 media::VideoFrame::AllocationSize(kInputFormat, test_stream.size); | 671 UpdateTestStreamData(mid_stream_bitrate_switch, mid_stream_framerate_switch); |
| 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 | 672 |
| 578 thread_checker_.DetachFromThread(); | 673 thread_checker_.DetachFromThread(); |
| 579 } | 674 } |
| 580 | 675 |
| 581 VEAClient::~VEAClient() { CHECK(!has_encoder()); } | 676 VEAClient::~VEAClient() { CHECK(!has_encoder()); } |
| 582 | 677 |
| 583 void VEAClient::CreateEncoder() { | 678 void VEAClient::CreateEncoder() { |
| 584 DCHECK(thread_checker_.CalledOnValidThread()); | 679 DCHECK(thread_checker_.CalledOnValidThread()); |
| 585 CHECK(!has_encoder()); | 680 CHECK(!has_encoder()); |
| 586 | 681 |
| 587 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) | 682 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) |
| 588 scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder); | 683 scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder); |
| 589 encoder_.reset(new V4L2VideoEncodeAccelerator(device.Pass())); | 684 encoder_.reset(new V4L2VideoEncodeAccelerator(device.Pass())); |
| 590 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) | 685 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11) |
| 591 encoder_.reset(new VaapiVideoEncodeAccelerator(gfx::GetXDisplay())); | 686 encoder_.reset(new VaapiVideoEncodeAccelerator(gfx::GetXDisplay())); |
| 592 #endif | 687 #endif |
| 593 | 688 |
| 594 SetState(CS_ENCODER_SET); | 689 SetState(CS_ENCODER_SET); |
| 595 | 690 |
| 596 DVLOG(1) << "Profile: " << test_stream_.requested_profile | 691 DVLOG(1) << "Profile: " << test_stream_->requested_profile |
| 597 << ", initial bitrate: " << test_stream_.requested_bitrate; | 692 << ", initial bitrate: " << requested_bitrate_; |
| 598 if (!encoder_->Initialize(kInputFormat, | 693 if (!encoder_->Initialize(kInputFormat, |
| 599 test_stream_.size, | 694 test_stream_->visible_size, |
| 600 test_stream_.requested_profile, | 695 test_stream_->requested_profile, |
| 601 test_stream_.requested_bitrate, | 696 requested_bitrate_, |
| 602 this)) { | 697 this)) { |
| 603 DLOG(ERROR) << "VideoEncodeAccelerator::Initialize() failed"; | 698 DLOG(ERROR) << "VideoEncodeAccelerator::Initialize() failed"; |
| 604 SetState(CS_ERROR); | 699 SetState(CS_ERROR); |
| 605 return; | 700 return; |
| 606 } | 701 } |
| 607 | 702 |
| 608 SetStreamParameters(test_stream_.requested_bitrate, | 703 SetStreamParameters(requested_bitrate_, requested_framerate_); |
| 609 test_stream_.requested_framerate); | |
| 610 SetState(CS_INITIALIZED); | 704 SetState(CS_INITIALIZED); |
| 611 } | 705 } |
| 612 | 706 |
| 613 void VEAClient::DestroyEncoder() { | 707 void VEAClient::DestroyEncoder() { |
| 614 DCHECK(thread_checker_.CalledOnValidThread()); | 708 DCHECK(thread_checker_.CalledOnValidThread()); |
| 615 if (!has_encoder()) | 709 if (!has_encoder()) |
| 616 return; | 710 return; |
| 617 encoder_.reset(); | 711 encoder_.reset(); |
| 618 } | 712 } |
| 619 | 713 |
| 714 void VEAClient::UpdateTestStreamData(bool mid_stream_bitrate_switch, | |
| 715 bool mid_stream_framerate_switch) { | |
| 716 // Use defaults for bitrate/framerate if they are not provided. | |
| 717 if (test_stream_->requested_bitrate == 0) | |
| 718 requested_bitrate_ = kDefaultBitrate; | |
| 719 else | |
| 720 requested_bitrate_ = test_stream_->requested_bitrate; | |
| 721 | |
| 722 if (test_stream_->requested_framerate == 0) | |
| 723 requested_framerate_ = kDefaultFramerate; | |
| 724 else | |
| 725 requested_framerate_ = test_stream_->requested_framerate; | |
| 726 | |
| 727 // If bitrate/framerate switch is requested, use the subsequent values if | |
| 728 // provided, or, if not, calculate them from their initial values using | |
| 729 // the default ratios. | |
| 730 // Otherwise, if a switch is not requested, keep the initial values. | |
| 731 if (mid_stream_bitrate_switch) { | |
| 732 if (test_stream_->requested_subsequent_bitrate == 0) | |
| 733 requested_subsequent_bitrate_ = | |
| 734 requested_bitrate_ * kDefaultSubsequentBitrateRatio; | |
| 735 else | |
| 736 requested_subsequent_bitrate_ = | |
| 737 test_stream_->requested_subsequent_bitrate; | |
| 738 } else { | |
| 739 requested_subsequent_bitrate_ = requested_bitrate_; | |
| 740 } | |
| 741 if (requested_subsequent_bitrate_ == 0) | |
| 742 requested_subsequent_bitrate_ = 1; | |
| 743 | |
| 744 if (mid_stream_framerate_switch) { | |
| 745 if (test_stream_->requested_subsequent_framerate == 0) | |
| 746 requested_subsequent_framerate_ = | |
| 747 requested_framerate_ * kDefaultSubsequentFramerateRatio; | |
| 748 else | |
| 749 requested_subsequent_framerate_ = | |
| 750 test_stream_->requested_subsequent_framerate; | |
| 751 } else { | |
| 752 requested_subsequent_framerate_ = requested_framerate_; | |
| 753 } | |
| 754 if (requested_subsequent_framerate_ == 0) | |
| 755 requested_subsequent_framerate_ = 1; | |
| 756 } | |
| 757 | |
| 620 double VEAClient::frames_per_second() { | 758 double VEAClient::frames_per_second() { |
| 621 base::TimeDelta duration = last_frame_ready_time_ - encode_start_time_; | 759 base::TimeDelta duration = last_frame_ready_time_ - encode_start_time_; |
| 622 return num_encoded_frames_ / duration.InSecondsF(); | 760 return num_encoded_frames_ / duration.InSecondsF(); |
| 623 } | 761 } |
| 624 | 762 |
| 625 void VEAClient::RequireBitstreamBuffers(unsigned int input_count, | 763 void VEAClient::RequireBitstreamBuffers(unsigned int input_count, |
| 626 const gfx::Size& input_coded_size, | 764 const gfx::Size& input_coded_size, |
| 627 size_t output_size) { | 765 size_t output_size) { |
| 628 DCHECK(thread_checker_.CalledOnValidThread()); | 766 DCHECK(thread_checker_.CalledOnValidThread()); |
| 629 ASSERT_EQ(state_, CS_INITIALIZED); | 767 ASSERT_EQ(state_, CS_INITIALIZED); |
| 630 SetState(CS_ENCODING); | 768 SetState(CS_ENCODING); |
| 631 | 769 |
| 632 // TODO(posciak): For now we only support input streams that meet encoder | 770 CreateAlignedInputStreamFile(input_coded_size, test_stream_); |
| 633 // size requirements exactly (i.e. coded size == visible size), so that we | 771 |
| 634 // can simply mmap the stream file and feed the encoder directly with chunks | 772 // We may need to loop over the stream more than once if more frames than |
| 635 // of that, instead of memcpying from mmapped file into a separate set of | 773 // provided is required for bitrate tests. |
| 636 // input buffers that would meet the coded size and alignment requirements. | 774 if (force_bitrate_ && test_stream_->num_frames < kMinFramesForBitrateTests) { |
| 637 // If/when this is changed, the ARM-specific alignment check below should be | 775 DVLOG(1) << "Stream too short for bitrate test (" |
| 638 // redone as well. | 776 << test_stream_->num_frames << " frames), will loop it to reach " |
| 777 << kMinFramesForBitrateTests << " frames"; | |
| 778 num_frames_to_encode_ = kMinFramesForBitrateTests; | |
| 779 } else { | |
| 780 num_frames_to_encode_ = test_stream_->num_frames; | |
| 781 } | |
| 782 | |
| 639 input_coded_size_ = input_coded_size; | 783 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; | 784 num_required_input_buffers_ = input_count; |
| 662 ASSERT_GT(num_required_input_buffers_, 0UL); | 785 ASSERT_GT(num_required_input_buffers_, 0UL); |
| 663 | 786 |
| 664 output_buffer_size_ = output_size; | 787 output_buffer_size_ = output_size; |
| 665 ASSERT_GT(output_buffer_size_, 0UL); | 788 ASSERT_GT(output_buffer_size_, 0UL); |
| 666 | 789 |
| 667 for (unsigned int i = 0; i < kNumOutputBuffers; ++i) { | 790 for (unsigned int i = 0; i < kNumOutputBuffers; ++i) { |
| 668 base::SharedMemory* shm = new base::SharedMemory(); | 791 base::SharedMemory* shm = new base::SharedMemory(); |
| 669 CHECK(shm->CreateAndMapAnonymous(output_buffer_size_)); | 792 CHECK(shm->CreateAndMapAnonymous(output_buffer_size_)); |
| 670 output_shms_.push_back(shm); | 793 output_shms_.push_back(shm); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 694 const uint8* stream_ptr = static_cast<const uint8*>(shm->memory()); | 817 const uint8* stream_ptr = static_cast<const uint8*>(shm->memory()); |
| 695 if (payload_size > 0) | 818 if (payload_size > 0) |
| 696 validator_->ProcessStreamBuffer(stream_ptr, payload_size); | 819 validator_->ProcessStreamBuffer(stream_ptr, payload_size); |
| 697 | 820 |
| 698 EXPECT_EQ(key_frame, seen_keyframe_in_this_buffer_); | 821 EXPECT_EQ(key_frame, seen_keyframe_in_this_buffer_); |
| 699 seen_keyframe_in_this_buffer_ = false; | 822 seen_keyframe_in_this_buffer_ = false; |
| 700 | 823 |
| 701 if (save_to_file_) { | 824 if (save_to_file_) { |
| 702 int size = base::checked_cast<int>(payload_size); | 825 int size = base::checked_cast<int>(payload_size); |
| 703 EXPECT_EQ(base::AppendToFile( | 826 EXPECT_EQ(base::AppendToFile( |
| 704 base::FilePath::FromUTF8Unsafe(test_stream_.out_filename), | 827 base::FilePath::FromUTF8Unsafe(test_stream_->out_filename), |
| 705 static_cast<char*>(shm->memory()), | 828 static_cast<char*>(shm->memory()), |
| 706 size), | 829 size), |
| 707 size); | 830 size); |
| 708 } | 831 } |
| 709 | 832 |
| 710 FeedEncoderWithOutput(shm); | 833 FeedEncoderWithOutput(shm); |
| 711 } | 834 } |
| 712 | 835 |
| 713 void VEAClient::NotifyError(VideoEncodeAccelerator::Error error) { | 836 void VEAClient::NotifyError(VideoEncodeAccelerator::Error error) { |
| 714 DCHECK(thread_checker_.CalledOnValidThread()); | 837 DCHECK(thread_checker_.CalledOnValidThread()); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 734 } | 857 } |
| 735 | 858 |
| 736 void VEAClient::InputNoLongerNeededCallback(int32 input_id) { | 859 void VEAClient::InputNoLongerNeededCallback(int32 input_id) { |
| 737 std::set<int32>::iterator it = inputs_at_client_.find(input_id); | 860 std::set<int32>::iterator it = inputs_at_client_.find(input_id); |
| 738 ASSERT_NE(it, inputs_at_client_.end()); | 861 ASSERT_NE(it, inputs_at_client_.end()); |
| 739 inputs_at_client_.erase(it); | 862 inputs_at_client_.erase(it); |
| 740 FeedEncoderWithInputs(); | 863 FeedEncoderWithInputs(); |
| 741 } | 864 } |
| 742 | 865 |
| 743 scoped_refptr<media::VideoFrame> VEAClient::PrepareInputFrame(off_t position) { | 866 scoped_refptr<media::VideoFrame> VEAClient::PrepareInputFrame(off_t position) { |
| 744 CHECK_LE(position + input_buffer_size_, test_stream_.input_file.length()); | 867 CHECK_LE(position + test_stream_->aligned_buffer_size, |
| 868 test_stream_->mapped_aligned_in_file.length()); | |
| 745 | 869 |
| 746 uint8* frame_data = | 870 uint8* frame_data_y = const_cast<uint8*>( |
| 747 const_cast<uint8*>(test_stream_.input_file.data() + position); | 871 test_stream_->mapped_aligned_in_file.data() + position); |
| 872 uint8* frame_data_u = frame_data_y + test_stream_->aligned_plane_size[0]; | |
| 873 uint8* frame_data_v = frame_data_u + test_stream_->aligned_plane_size[1]; | |
| 748 | 874 |
| 749 CHECK_GT(current_framerate_, 0U); | 875 CHECK_GT(current_framerate_, 0U); |
| 750 scoped_refptr<media::VideoFrame> frame = | 876 scoped_refptr<media::VideoFrame> frame = |
| 751 media::VideoFrame::WrapExternalYuvData( | 877 media::VideoFrame::WrapExternalYuvData( |
| 752 kInputFormat, | 878 kInputFormat, |
| 753 input_coded_size_, | 879 input_coded_size_, |
| 754 gfx::Rect(test_stream_.size), | 880 gfx::Rect(test_stream_->visible_size), |
| 755 test_stream_.size, | 881 test_stream_->visible_size, |
| 756 input_coded_size_.width(), | 882 input_coded_size_.width(), |
| 757 input_coded_size_.width() / 2, | 883 input_coded_size_.width() / 2, |
| 758 input_coded_size_.width() / 2, | 884 input_coded_size_.width() / 2, |
| 759 frame_data, | 885 frame_data_y, |
| 760 frame_data + input_coded_size_.GetArea(), | 886 frame_data_u, |
| 761 frame_data + (input_coded_size_.GetArea() * 5 / 4), | 887 frame_data_v, |
| 762 base::TimeDelta().FromMilliseconds( | 888 base::TimeDelta().FromMilliseconds( |
| 763 next_input_id_ * base::Time::kMillisecondsPerSecond / | 889 next_input_id_ * base::Time::kMillisecondsPerSecond / |
| 764 current_framerate_), | 890 current_framerate_), |
| 765 media::BindToCurrentLoop( | 891 media::BindToCurrentLoop( |
| 766 base::Bind(&VEAClient::InputNoLongerNeededCallback, | 892 base::Bind(&VEAClient::InputNoLongerNeededCallback, |
| 767 base::Unretained(this), | 893 base::Unretained(this), |
| 768 next_input_id_))); | 894 next_input_id_))); |
| 769 | 895 |
| 770 CHECK(inputs_at_client_.insert(next_input_id_).second); | 896 CHECK(inputs_at_client_.insert(next_input_id_).second); |
| 771 ++next_input_id_; | 897 ++next_input_id_; |
| 772 | 898 |
| 773 return frame; | 899 return frame; |
| 774 } | 900 } |
| 775 | 901 |
| 776 void VEAClient::FeedEncoderWithInputs() { | 902 void VEAClient::FeedEncoderWithInputs() { |
| 777 if (!has_encoder()) | 903 if (!has_encoder()) |
| 778 return; | 904 return; |
| 779 | 905 |
| 780 if (state_ != CS_ENCODING) | 906 if (state_ != CS_ENCODING) |
| 781 return; | 907 return; |
| 782 | 908 |
| 783 while (inputs_at_client_.size() < | 909 while (inputs_at_client_.size() < |
| 784 num_required_input_buffers_ + kNumExtraInputFrames) { | 910 num_required_input_buffers_ + kNumExtraInputFrames) { |
| 785 size_t bytes_left = test_stream_.input_file.length() - pos_in_input_stream_; | 911 size_t bytes_left = |
| 786 if (bytes_left < input_buffer_size_) { | 912 test_stream_->mapped_aligned_in_file.length() - pos_in_input_stream_; |
| 913 if (bytes_left < test_stream_->aligned_buffer_size) { | |
| 787 DCHECK_EQ(bytes_left, 0UL); | 914 DCHECK_EQ(bytes_left, 0UL); |
| 788 // Rewind if at the end of stream and we are still encoding. | 915 // Rewind if at the end of stream and we are still encoding. |
| 789 // This is to flush the encoder with additional frames from the beginning | 916 // This is to flush the encoder with additional frames from the beginning |
| 790 // of the stream, or if the stream is shorter that the number of frames | 917 // of the stream, or if the stream is shorter that the number of frames |
| 791 // we require for bitrate tests. | 918 // we require for bitrate tests. |
| 792 pos_in_input_stream_ = 0; | 919 pos_in_input_stream_ = 0; |
| 793 continue; | 920 continue; |
| 794 } | 921 } |
| 795 | 922 |
| 796 bool force_keyframe = false; | 923 bool force_keyframe = false; |
| 797 if (keyframe_period_ && next_input_id_ % keyframe_period_ == 0) { | 924 if (keyframe_period_ && next_input_id_ % keyframe_period_ == 0) { |
| 798 keyframe_requested_at_ = next_input_id_; | 925 keyframe_requested_at_ = next_input_id_; |
| 799 force_keyframe = true; | 926 force_keyframe = true; |
| 800 } | 927 } |
| 801 | 928 |
| 802 scoped_refptr<media::VideoFrame> video_frame = | 929 scoped_refptr<media::VideoFrame> video_frame = |
| 803 PrepareInputFrame(pos_in_input_stream_); | 930 PrepareInputFrame(pos_in_input_stream_); |
| 804 pos_in_input_stream_ += input_buffer_size_; | 931 pos_in_input_stream_ += test_stream_->aligned_buffer_size; |
| 805 | 932 |
| 806 encoder_->Encode(video_frame, force_keyframe); | 933 encoder_->Encode(video_frame, force_keyframe); |
| 807 } | 934 } |
| 808 } | 935 } |
| 809 | 936 |
| 810 void VEAClient::FeedEncoderWithOutput(base::SharedMemory* shm) { | 937 void VEAClient::FeedEncoderWithOutput(base::SharedMemory* shm) { |
| 811 if (!has_encoder()) | 938 if (!has_encoder()) |
| 812 return; | 939 return; |
| 813 | 940 |
| 814 if (state_ != CS_ENCODING) | 941 if (state_ != CS_ENCODING) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 847 // is asynchronous, i.e. not bound to any concrete frame, and because | 974 // is asynchronous, i.e. not bound to any concrete frame, and because |
| 848 // the pipeline can be deeper than one frame), at that frame, or after. | 975 // the pipeline can be deeper than one frame), at that frame, or after. |
| 849 // So the only constraints we put here is that we get a keyframe not | 976 // So the only constraints we put here is that we get a keyframe not |
| 850 // earlier than we requested one (in time), and not later than | 977 // earlier than we requested one (in time), and not later than |
| 851 // kMaxKeyframeDelay frames after the frame, for which we requested | 978 // kMaxKeyframeDelay frames after the frame, for which we requested |
| 852 // it, comes back encoded. | 979 // it, comes back encoded. |
| 853 EXPECT_LE(num_encoded_frames_, keyframe_requested_at_ + kMaxKeyframeDelay); | 980 EXPECT_LE(num_encoded_frames_, keyframe_requested_at_ + kMaxKeyframeDelay); |
| 854 | 981 |
| 855 if (num_encoded_frames_ == num_frames_to_encode_ / 2) { | 982 if (num_encoded_frames_ == num_frames_to_encode_ / 2) { |
| 856 VerifyStreamProperties(); | 983 VerifyStreamProperties(); |
| 857 if (test_stream_.requested_subsequent_bitrate != | 984 if (requested_subsequent_bitrate_ != current_requested_bitrate_ || |
| 858 current_requested_bitrate_ || | 985 requested_subsequent_framerate_ != current_framerate_) { |
| 859 test_stream_.requested_subsequent_framerate != current_framerate_) { | 986 SetStreamParameters(requested_subsequent_bitrate_, |
| 860 SetStreamParameters(test_stream_.requested_subsequent_bitrate, | 987 requested_subsequent_framerate_); |
| 861 test_stream_.requested_subsequent_framerate); | |
| 862 } | 988 } |
| 863 } else if (num_encoded_frames_ == num_frames_to_encode_) { | 989 } else if (num_encoded_frames_ == num_frames_to_encode_) { |
| 864 VerifyPerf(); | 990 VerifyPerf(); |
| 865 VerifyStreamProperties(); | 991 VerifyStreamProperties(); |
| 866 SetState(CS_FINISHED); | 992 SetState(CS_FINISHED); |
| 867 return false; | 993 return false; |
| 868 } | 994 } |
| 869 | 995 |
| 870 return true; | 996 return true; |
| 871 } | 997 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 890 num_frames_since_last_check_ = 0; | 1016 num_frames_since_last_check_ = 0; |
| 891 encoded_stream_size_since_last_check_ = 0; | 1017 encoded_stream_size_since_last_check_ = 0; |
| 892 | 1018 |
| 893 if (force_bitrate_) { | 1019 if (force_bitrate_) { |
| 894 EXPECT_NEAR(bitrate, | 1020 EXPECT_NEAR(bitrate, |
| 895 current_requested_bitrate_, | 1021 current_requested_bitrate_, |
| 896 kBitrateTolerance * current_requested_bitrate_); | 1022 kBitrateTolerance * current_requested_bitrate_); |
| 897 } | 1023 } |
| 898 } | 1024 } |
| 899 | 1025 |
| 1026 // Setup test stream data and delete temporary aligned files at the beginning | |
| 1027 // and end of unittest. We only need to setup once for all test cases. | |
| 1028 class VideoEncodeAcceleratorTestEnvironment : public ::testing::Environment { | |
| 1029 public: | |
| 1030 VideoEncodeAcceleratorTestEnvironment( | |
| 1031 scoped_ptr<base::FilePath::StringType> data) { | |
| 1032 test_stream_data = data.Pass(); | |
| 1033 } | |
| 1034 | |
| 1035 virtual void SetUp() { | |
| 1036 ParseAndReadTestStreamData(*test_stream_data, &test_streams); | |
| 1037 } | |
| 1038 | |
| 1039 virtual void TearDown() { | |
| 1040 for (size_t i = 0; i < test_streams.size(); i++) { | |
| 1041 base::DeleteFile(test_streams[i]->aligned_in_file, false); | |
| 1042 } | |
| 1043 } | |
| 1044 | |
| 1045 ScopedVector<TestStream> test_streams; | |
| 1046 | |
| 1047 private: | |
| 1048 scoped_ptr<base::FilePath::StringType> test_stream_data; | |
|
Pawel Osciak
2014/09/17 13:42:02
Class members should be suffixed with a "_". Sorry
henryhsu
2014/09/18 03:41:23
Done.
| |
| 1049 }; | |
| 1050 | |
| 900 // Test parameters: | 1051 // Test parameters: |
| 901 // - Number of concurrent encoders. | 1052 // - Number of concurrent encoders. |
| 902 // - If true, save output to file (provided an output filename was supplied). | 1053 // - If true, save output to file (provided an output filename was supplied). |
| 903 // - Force a keyframe every n frames. | 1054 // - Force a keyframe every n frames. |
| 904 // - Force bitrate; the actual required value is provided as a property | 1055 // - Force bitrate; the actual required value is provided as a property |
| 905 // of the input stream, because it depends on stream type/resolution/etc. | 1056 // of the input stream, because it depends on stream type/resolution/etc. |
| 906 // - If true, measure performance. | 1057 // - If true, measure performance. |
| 907 // - If true, switch bitrate mid-stream. | 1058 // - If true, switch bitrate mid-stream. |
| 908 // - If true, switch framerate mid-stream. | 1059 // - If true, switch framerate mid-stream. |
| 909 class VideoEncodeAcceleratorTest | 1060 class VideoEncodeAcceleratorTest |
| 910 : public ::testing::TestWithParam< | 1061 : public ::testing::TestWithParam< |
| 911 Tuple7<int, bool, int, bool, bool, bool, bool> > {}; | 1062 Tuple7<int, bool, int, bool, bool, bool, bool> > {}; |
| 912 | 1063 |
| 913 TEST_P(VideoEncodeAcceleratorTest, TestSimpleEncode) { | 1064 TEST_P(VideoEncodeAcceleratorTest, TestSimpleEncode) { |
| 914 const size_t num_concurrent_encoders = GetParam().a; | 1065 const size_t num_concurrent_encoders = GetParam().a; |
| 915 const bool save_to_file = GetParam().b; | 1066 const bool save_to_file = GetParam().b; |
| 916 const unsigned int keyframe_period = GetParam().c; | 1067 const unsigned int keyframe_period = GetParam().c; |
| 917 const bool force_bitrate = GetParam().d; | 1068 const bool force_bitrate = GetParam().d; |
| 918 const bool test_perf = GetParam().e; | 1069 const bool test_perf = GetParam().e; |
| 919 const bool mid_stream_bitrate_switch = GetParam().f; | 1070 const bool mid_stream_bitrate_switch = GetParam().f; |
| 920 const bool mid_stream_framerate_switch = GetParam().g; | 1071 const bool mid_stream_framerate_switch = GetParam().g; |
| 921 | 1072 |
| 922 // Initialize the test streams. | |
| 923 ScopedVector<TestStream> test_streams; | |
| 924 ParseAndReadTestStreamData(*g_test_stream_data, &test_streams); | |
| 925 UpdateTestStreamData( | |
| 926 mid_stream_bitrate_switch, mid_stream_framerate_switch, &test_streams); | |
| 927 | |
| 928 ScopedVector<ClientStateNotification<ClientState> > notes; | 1073 ScopedVector<ClientStateNotification<ClientState> > notes; |
| 929 ScopedVector<VEAClient> clients; | 1074 ScopedVector<VEAClient> clients; |
| 930 base::Thread encoder_thread("EncoderThread"); | 1075 base::Thread encoder_thread("EncoderThread"); |
| 931 ASSERT_TRUE(encoder_thread.Start()); | 1076 ASSERT_TRUE(encoder_thread.Start()); |
| 932 | 1077 |
| 933 // Create all encoders. | 1078 // Create all encoders. |
| 934 for (size_t i = 0; i < num_concurrent_encoders; i++) { | 1079 for (size_t i = 0; i < num_concurrent_encoders; i++) { |
| 935 size_t test_stream_index = i % test_streams.size(); | 1080 size_t test_stream_index = i % g_env->test_streams.size(); |
| 936 // Disregard save_to_file if we didn't get an output filename. | 1081 // Disregard save_to_file if we didn't get an output filename. |
| 937 bool encoder_save_to_file = | 1082 bool encoder_save_to_file = |
| 938 (save_to_file && | 1083 (save_to_file && |
| 939 !test_streams[test_stream_index]->out_filename.empty()); | 1084 !g_env->test_streams[test_stream_index]->out_filename.empty()); |
| 940 | 1085 |
| 941 notes.push_back(new ClientStateNotification<ClientState>()); | 1086 notes.push_back(new ClientStateNotification<ClientState>()); |
| 942 clients.push_back(new VEAClient(*test_streams[test_stream_index], | 1087 clients.push_back(new VEAClient(g_env->test_streams[test_stream_index], |
| 943 notes.back(), | 1088 notes.back(), |
| 944 encoder_save_to_file, | 1089 encoder_save_to_file, |
| 945 keyframe_period, | 1090 keyframe_period, |
| 946 force_bitrate, | 1091 force_bitrate, |
| 947 test_perf)); | 1092 test_perf, |
| 1093 mid_stream_bitrate_switch, | |
| 1094 mid_stream_framerate_switch)); | |
| 948 | 1095 |
| 949 encoder_thread.message_loop()->PostTask( | 1096 encoder_thread.message_loop()->PostTask( |
| 950 FROM_HERE, | 1097 FROM_HERE, |
| 951 base::Bind(&VEAClient::CreateEncoder, | 1098 base::Bind(&VEAClient::CreateEncoder, |
| 952 base::Unretained(clients.back()))); | 1099 base::Unretained(clients.back()))); |
| 953 } | 1100 } |
| 954 | 1101 |
| 955 // All encoders must pass through states in this order. | 1102 // All encoders must pass through states in this order. |
| 956 enum ClientState state_transitions[] = {CS_ENCODER_SET, CS_INITIALIZED, | 1103 enum ClientState state_transitions[] = {CS_ENCODER_SET, CS_INITIALIZED, |
| 957 CS_ENCODING, CS_FINISHED}; | 1104 CS_ENCODING, CS_FINISHED}; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1029 | 1176 |
| 1030 int main(int argc, char** argv) { | 1177 int main(int argc, char** argv) { |
| 1031 testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args. | 1178 testing::InitGoogleTest(&argc, argv); // Removes gtest-specific args. |
| 1032 base::CommandLine::Init(argc, argv); | 1179 base::CommandLine::Init(argc, argv); |
| 1033 | 1180 |
| 1034 base::ShadowingAtExitManager at_exit_manager; | 1181 base::ShadowingAtExitManager at_exit_manager; |
| 1035 scoped_ptr<base::FilePath::StringType> test_stream_data( | 1182 scoped_ptr<base::FilePath::StringType> test_stream_data( |
| 1036 new base::FilePath::StringType( | 1183 new base::FilePath::StringType( |
| 1037 media::GetTestDataFilePath(content::g_default_in_filename).value() + | 1184 media::GetTestDataFilePath(content::g_default_in_filename).value() + |
| 1038 content::g_default_in_parameters)); | 1185 content::g_default_in_parameters)); |
| 1039 content::g_test_stream_data = test_stream_data.get(); | |
| 1040 | 1186 |
| 1041 // Needed to enable DVLOG through --vmodule. | 1187 // Needed to enable DVLOG through --vmodule. |
| 1042 logging::LoggingSettings settings; | 1188 logging::LoggingSettings settings; |
| 1043 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; | 1189 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; |
| 1044 CHECK(logging::InitLogging(settings)); | 1190 CHECK(logging::InitLogging(settings)); |
| 1045 | 1191 |
| 1046 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 1192 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 1047 DCHECK(cmd_line); | 1193 DCHECK(cmd_line); |
| 1048 | 1194 |
| 1049 base::CommandLine::SwitchMap switches = cmd_line->GetSwitches(); | 1195 base::CommandLine::SwitchMap switches = cmd_line->GetSwitches(); |
| 1050 for (base::CommandLine::SwitchMap::const_iterator it = switches.begin(); | 1196 for (base::CommandLine::SwitchMap::const_iterator it = switches.begin(); |
| 1051 it != switches.end(); | 1197 it != switches.end(); |
| 1052 ++it) { | 1198 ++it) { |
| 1053 if (it->first == "test_stream_data") { | 1199 if (it->first == "test_stream_data") { |
| 1054 test_stream_data->assign(it->second.c_str()); | 1200 test_stream_data->assign(it->second.c_str()); |
| 1055 continue; | 1201 continue; |
| 1056 } | 1202 } |
| 1057 if (it->first == "v" || it->first == "vmodule") | 1203 if (it->first == "v" || it->first == "vmodule") |
| 1058 continue; | 1204 continue; |
| 1059 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; | 1205 LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second; |
| 1060 } | 1206 } |
| 1061 | 1207 |
| 1208 content::g_env = | |
| 1209 reinterpret_cast<content::VideoEncodeAcceleratorTestEnvironment*>( | |
| 1210 testing::AddGlobalTestEnvironment( | |
| 1211 new content::VideoEncodeAcceleratorTestEnvironment( | |
| 1212 test_stream_data.Pass()))); | |
| 1213 | |
| 1062 return RUN_ALL_TESTS(); | 1214 return RUN_ALL_TESTS(); |
| 1063 } | 1215 } |
| OLD | NEW |