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
3 // found in the LICENSE file.
5 #include "base/at_exit.h"
7 #include "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/files/memory_mapped_file.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "base/process/process_handle.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/sys_byteorder.h"
16 #include "base/time/time.h"
17 #include "base/timer/timer.h"
18 #include "content/common/gpu/media/video_accelerator_unittest_helpers.h"
19 #include "media/base/bind_to_current_loop.h"
20 #include "media/base/bitstream_buffer.h"
21 #include "media/base/test_data_util.h"
22 #include "media/filters/h264_parser.h"
23 #include "media/video/fake_video_encode_accelerator.h"
24 #include "media/video/video_encode_accelerator.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 #if defined(USE_OZONE)
28 #include "ui/ozone/public/ozone_platform.h"
31 #if defined(OS_CHROMEOS)
32 #if defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC))
33 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
35 #if defined(ARCH_CPU_X86_FAMILY)
36 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h"
37 #endif // defined(ARCH_CPU_X86_FAMILY)
39 #error The VideoEncodeAcceleratorUnittest is not supported on this platform.
42 using media::VideoEncodeAccelerator
;
47 const media::VideoFrame::Format kInputFormat
= media::VideoFrame::I420
;
49 // Arbitrarily chosen to add some depth to the pipeline.
50 const unsigned int kNumOutputBuffers
= 4;
51 const unsigned int kNumExtraInputFrames
= 4;
52 // Maximum delay between requesting a keyframe and receiving one, in frames.
53 // Arbitrarily chosen as a reasonable requirement.
54 const unsigned int kMaxKeyframeDelay
= 4;
55 // Value to use as max frame number for keyframe detection.
56 const unsigned int kMaxFrameNum
=
57 std::numeric_limits
<unsigned int>::max() - kMaxKeyframeDelay
;
58 // Default initial bitrate.
59 const uint32 kDefaultBitrate
= 2000000;
60 // Default ratio of requested_subsequent_bitrate to initial_bitrate
61 // (see test parameters below) if one is not provided.
62 const double kDefaultSubsequentBitrateRatio
= 2.0;
63 // Default initial framerate.
64 const uint32 kDefaultFramerate
= 30;
65 // Default ratio of requested_subsequent_framerate to initial_framerate
66 // (see test parameters below) if one is not provided.
67 const double kDefaultSubsequentFramerateRatio
= 0.1;
68 // Tolerance factor for how encoded bitrate can differ from requested bitrate.
69 const double kBitrateTolerance
= 0.1;
70 // Minimum required FPS throughput for the basic performance test.
71 const uint32 kMinPerfFPS
= 30;
72 // Minimum (arbitrary) number of frames required to enforce bitrate requirements
73 // over. Streams shorter than this may be too short to realistically require
74 // an encoder to be able to converge to the requested bitrate over.
75 // The input stream will be looped as many times as needed in bitrate tests
76 // to reach at least this number of frames before calculating final bitrate.
77 const unsigned int kMinFramesForBitrateTests
= 300;
79 // The syntax of multiple test streams is:
80 // test-stream1;test-stream2;test-stream3
81 // The syntax of each test stream is:
82 // "in_filename:width:height:out_filename:requested_bitrate:requested_framerate
83 // :requested_subsequent_bitrate:requested_subsequent_framerate"
84 // - |in_filename| must be an I420 (YUV planar) raw stream
85 // (see http://www.fourcc.org/yuv.php#IYUV).
86 // - |width| and |height| are in pixels.
87 // - |profile| to encode into (values of media::VideoCodecProfile).
88 // - |out_filename| filename to save the encoded stream to (optional). The
89 // format for H264 is Annex-B byte stream. The format for VP8 is IVF. Output
90 // stream is saved for the simple encode test only. H264 raw stream and IVF
91 // can be used as input of VDA unittest. H264 raw stream can be played by
92 // "mplayer -fps 25 out.h264" and IVF can be played by mplayer directly.
93 // Helpful description: http://wiki.multimedia.cx/index.php?title=IVF
94 // Further parameters are optional (need to provide preceding positional
95 // parameters if a specific subsequent parameter is required):
96 // - |requested_bitrate| requested bitrate in bits per second.
97 // - |requested_framerate| requested initial framerate.
98 // - |requested_subsequent_bitrate| bitrate to switch to in the middle of the
100 // - |requested_subsequent_framerate| framerate to switch to in the middle
102 // Bitrate is only forced for tests that test bitrate.
103 const char* g_default_in_filename
= "bear_320x192_40frames.yuv";
104 const char* g_default_in_parameters
= ":320:192:1:out.h264:200000";
106 // Enabled by including a --fake_encoder flag to the command line invoking the
108 bool g_fake_encoder
= false;
110 // Environment to store test stream data for all test cases.
111 class VideoEncodeAcceleratorTestEnvironment
;
112 VideoEncodeAcceleratorTestEnvironment
* g_env
;
114 struct IvfFileHeader
{
115 char signature
[4]; // signature: 'DKIF'
116 uint16_t version
; // version (should be 0)
117 uint16_t header_size
; // size of header in bytes
118 uint32_t fourcc
; // codec FourCC (e.g., 'VP80')
119 uint16_t width
; // width in pixels
120 uint16_t height
; // height in pixels
121 uint32_t framerate
; // frame rate per seconds
122 uint32_t timescale
; // time scale. For example, if framerate is 30 and
123 // timescale is 2, the unit of IvfFrameHeader.timestamp
125 uint32_t num_frames
; // number of frames in file
126 uint32_t unused
; // unused
127 } __attribute__((packed
));
129 struct IvfFrameHeader
{
130 uint32_t frame_size
; // Size of frame in bytes (not including the header)
131 uint64_t timestamp
; // 64-bit presentation timestamp
132 } __attribute__((packed
));
134 // The number of frames to be encoded. This variable is set by the switch
135 // "--num_frames_to_encode". Ignored if 0.
136 int g_num_frames_to_encode
= 0;
141 aligned_buffer_size(0),
142 requested_bitrate(0),
143 requested_framerate(0),
144 requested_subsequent_bitrate(0),
145 requested_subsequent_framerate(0) {}
148 gfx::Size visible_size
;
149 gfx::Size coded_size
;
150 unsigned int num_frames
;
152 // Original unaligned input file name provided as an argument to the test.
153 // And the file must be an I420 (YUV planar) raw stream.
154 std::string in_filename
;
156 // A temporary file used to prepare aligned input buffers of |in_filename|.
157 // The file makes sure starting address of YUV planes are 64 byte-aligned.
158 base::FilePath aligned_in_file
;
160 // The memory mapping of |aligned_in_file|
161 base::MemoryMappedFile mapped_aligned_in_file
;
163 // Byte size of a frame of |aligned_in_file|.
164 size_t aligned_buffer_size
;
166 // Byte size for each aligned plane of a frame
167 std::vector
<size_t> aligned_plane_size
;
169 std::string out_filename
;
170 media::VideoCodecProfile requested_profile
;
171 unsigned int requested_bitrate
;
172 unsigned int requested_framerate
;
173 unsigned int requested_subsequent_bitrate
;
174 unsigned int requested_subsequent_framerate
;
177 inline static size_t Align64Bytes(size_t value
) {
178 return (value
+ 63) & ~63;
181 // Write |data| of |size| bytes at |offset| bytes into |file|.
182 static bool WriteFile(base::File
* file
,
186 size_t written_bytes
= 0;
187 while (written_bytes
< size
) {
188 int bytes
= file
->Write(offset
+ written_bytes
,
189 reinterpret_cast<const char*>(data
+ written_bytes
),
190 size
- written_bytes
);
193 written_bytes
+= bytes
;
198 static bool IsH264(media::VideoCodecProfile profile
) {
199 return profile
>= media::H264PROFILE_MIN
&& profile
<= media::H264PROFILE_MAX
;
202 static bool IsVP8(media::VideoCodecProfile profile
) {
203 return profile
>= media::VP8PROFILE_MIN
&& profile
<= media::VP8PROFILE_MAX
;
206 // ARM performs CPU cache management with CPU cache line granularity. We thus
207 // need to ensure our buffers are CPU cache line-aligned (64 byte-aligned).
208 // Otherwise newer kernels will refuse to accept them, and on older kernels
209 // we'll be treating ourselves to random corruption.
210 // Since we are just mapping and passing chunks of the input file directly to
211 // the VEA as input frames to avoid copying large chunks of raw data on each
212 // frame and thus affecting performance measurements, we have to prepare a
213 // temporary file with all planes aligned to 64-byte boundaries beforehand.
214 static void CreateAlignedInputStreamFile(const gfx::Size
& coded_size
,
215 TestStream
* test_stream
) {
216 // Test case may have many encoders and memory should be prepared once.
217 if (test_stream
->coded_size
== coded_size
&&
218 test_stream
->mapped_aligned_in_file
.IsValid())
221 // All encoders in multiple encoder test reuse the same test_stream, make
222 // sure they requested the same coded_size
223 ASSERT_TRUE(!test_stream
->mapped_aligned_in_file
.IsValid() ||
224 coded_size
== test_stream
->coded_size
);
225 test_stream
->coded_size
= coded_size
;
227 size_t num_planes
= media::VideoFrame::NumPlanes(kInputFormat
);
228 std::vector
<size_t> padding_sizes(num_planes
);
229 std::vector
<size_t> coded_bpl(num_planes
);
230 std::vector
<size_t> visible_bpl(num_planes
);
231 std::vector
<size_t> visible_plane_rows(num_planes
);
233 // Calculate padding in bytes to be added after each plane required to keep
234 // starting addresses of all planes at a 64 byte boudnary. This padding will
235 // be added after each plane when copying to the temporary file.
236 // At the same time we also need to take into account coded_size requested by
237 // the VEA; each row of visible_bpl bytes in the original file needs to be
238 // copied into a row of coded_bpl bytes in the aligned file.
239 for (size_t i
= 0; i
< num_planes
; i
++) {
241 media::VideoFrame::PlaneAllocationSize(kInputFormat
, i
, coded_size
);
242 test_stream
->aligned_plane_size
.push_back(Align64Bytes(size
));
243 test_stream
->aligned_buffer_size
+= test_stream
->aligned_plane_size
.back();
246 media::VideoFrame::RowBytes(i
, kInputFormat
, coded_size
.width());
247 visible_bpl
[i
] = media::VideoFrame::RowBytes(
248 i
, kInputFormat
, test_stream
->visible_size
.width());
249 visible_plane_rows
[i
] = media::VideoFrame::Rows(
250 i
, kInputFormat
, test_stream
->visible_size
.height());
251 size_t padding_rows
=
252 media::VideoFrame::Rows(i
, kInputFormat
, coded_size
.height()) -
253 visible_plane_rows
[i
];
254 padding_sizes
[i
] = padding_rows
* coded_bpl
[i
] + Align64Bytes(size
) - size
;
257 base::MemoryMappedFile src_file
;
258 CHECK(src_file
.Initialize(base::FilePath(test_stream
->in_filename
)));
259 CHECK(base::CreateTemporaryFile(&test_stream
->aligned_in_file
));
261 size_t visible_buffer_size
= media::VideoFrame::AllocationSize(
262 kInputFormat
, test_stream
->visible_size
);
263 CHECK_EQ(src_file
.length() % visible_buffer_size
, 0U)
264 << "Stream byte size is not a product of calculated frame byte size";
266 test_stream
->num_frames
= src_file
.length() / visible_buffer_size
;
267 uint32 flags
= base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_WRITE
|
268 base::File::FLAG_READ
;
270 // Create a temporary file with coded_size length.
271 base::File
dest_file(test_stream
->aligned_in_file
, flags
);
272 CHECK_GT(test_stream
->aligned_buffer_size
, 0UL);
273 dest_file
.SetLength(test_stream
->aligned_buffer_size
*
274 test_stream
->num_frames
);
276 const uint8
* src
= src_file
.data();
277 off_t dest_offset
= 0;
278 for (size_t frame
= 0; frame
< test_stream
->num_frames
; frame
++) {
279 for (size_t i
= 0; i
< num_planes
; i
++) {
280 // Assert that each plane of frame starts at 64 byte boundary.
281 ASSERT_EQ(dest_offset
& 63, 0)
282 << "Planes of frame should be mapped at a 64 byte boundary";
283 for (size_t j
= 0; j
< visible_plane_rows
[i
]; j
++) {
284 CHECK(WriteFile(&dest_file
, dest_offset
, src
, visible_bpl
[i
]));
285 src
+= visible_bpl
[i
];
286 dest_offset
+= coded_bpl
[i
];
288 dest_offset
+= padding_sizes
[i
];
291 CHECK(test_stream
->mapped_aligned_in_file
.Initialize(dest_file
.Pass()));
292 // Assert that memory mapped of file starts at 64 byte boundary. So each
293 // plane of frames also start at 64 byte boundary.
295 reinterpret_cast<off_t
>(test_stream
->mapped_aligned_in_file
.data()) & 63,
297 << "File should be mapped at a 64 byte boundary";
299 CHECK_EQ(test_stream
->mapped_aligned_in_file
.length() %
300 test_stream
->aligned_buffer_size
,
302 << "Stream byte size is not a product of calculated frame byte size";
303 CHECK_GT(test_stream
->num_frames
, 0UL);
304 CHECK_LE(test_stream
->num_frames
, kMaxFrameNum
);
307 // Parse |data| into its constituent parts, set the various output fields
308 // accordingly, read in video stream, and store them to |test_streams|.
309 static void ParseAndReadTestStreamData(const base::FilePath::StringType
& data
,
310 ScopedVector
<TestStream
>* test_streams
) {
311 // Split the string to individual test stream data.
312 std::vector
<base::FilePath::StringType
> test_streams_data
;
313 base::SplitString(data
, ';', &test_streams_data
);
314 CHECK_GE(test_streams_data
.size(), 1U) << data
;
316 // Parse each test stream data and read the input file.
317 for (size_t index
= 0; index
< test_streams_data
.size(); ++index
) {
318 std::vector
<base::FilePath::StringType
> fields
;
319 base::SplitString(test_streams_data
[index
], ':', &fields
);
320 CHECK_GE(fields
.size(), 4U) << data
;
321 CHECK_LE(fields
.size(), 9U) << data
;
322 TestStream
* test_stream
= new TestStream();
324 test_stream
->in_filename
= fields
[0];
326 CHECK(base::StringToInt(fields
[1], &width
));
327 CHECK(base::StringToInt(fields
[2], &height
));
328 test_stream
->visible_size
= gfx::Size(width
, height
);
329 CHECK(!test_stream
->visible_size
.IsEmpty());
331 CHECK(base::StringToInt(fields
[3], &profile
));
332 CHECK_GT(profile
, media::VIDEO_CODEC_PROFILE_UNKNOWN
);
333 CHECK_LE(profile
, media::VIDEO_CODEC_PROFILE_MAX
);
334 test_stream
->requested_profile
=
335 static_cast<media::VideoCodecProfile
>(profile
);
337 if (fields
.size() >= 5 && !fields
[4].empty())
338 test_stream
->out_filename
= fields
[4];
340 if (fields
.size() >= 6 && !fields
[5].empty())
341 CHECK(base::StringToUint(fields
[5], &test_stream
->requested_bitrate
));
343 if (fields
.size() >= 7 && !fields
[6].empty())
344 CHECK(base::StringToUint(fields
[6], &test_stream
->requested_framerate
));
346 if (fields
.size() >= 8 && !fields
[7].empty()) {
347 CHECK(base::StringToUint(fields
[7],
348 &test_stream
->requested_subsequent_bitrate
));
351 if (fields
.size() >= 9 && !fields
[8].empty()) {
352 CHECK(base::StringToUint(fields
[8],
353 &test_stream
->requested_subsequent_framerate
));
355 test_streams
->push_back(test_stream
);
368 // Performs basic, codec-specific sanity checks on the stream buffers passed
369 // to ProcessStreamBuffer(): whether we've seen keyframes before non-keyframes,
370 // correct sequences of H.264 NALUs (SPS before PPS and before slices), etc.
371 // Calls given FrameFoundCallback when a complete frame is found while
373 class StreamValidator
{
375 // To be called when a complete frame is found while processing a stream
376 // buffer, passing true if the frame is a keyframe. Returns false if we
377 // are not interested in more frames and further processing should be aborted.
378 typedef base::Callback
<bool(bool)> FrameFoundCallback
;
380 virtual ~StreamValidator() {}
382 // Provide a StreamValidator instance for the given |profile|.
383 static scoped_ptr
<StreamValidator
> Create(media::VideoCodecProfile profile
,
384 const FrameFoundCallback
& frame_cb
);
386 // Process and verify contents of a bitstream buffer.
387 virtual void ProcessStreamBuffer(const uint8
* stream
, size_t size
) = 0;
390 explicit StreamValidator(const FrameFoundCallback
& frame_cb
)
391 : frame_cb_(frame_cb
) {}
393 FrameFoundCallback frame_cb_
;
396 class H264Validator
: public StreamValidator
{
398 explicit H264Validator(const FrameFoundCallback
& frame_cb
)
399 : StreamValidator(frame_cb
),
404 void ProcessStreamBuffer(const uint8
* stream
, size_t size
) override
;
407 // Set to true when encoder provides us with the corresponding NALU type.
412 media::H264Parser h264_parser_
;
415 void H264Validator::ProcessStreamBuffer(const uint8
* stream
, size_t size
) {
416 h264_parser_
.SetStream(stream
, size
);
419 media::H264NALU nalu
;
420 media::H264Parser::Result result
;
422 result
= h264_parser_
.AdvanceToNextNALU(&nalu
);
423 if (result
== media::H264Parser::kEOStream
)
426 ASSERT_EQ(media::H264Parser::kOk
, result
);
428 bool keyframe
= false;
430 switch (nalu
.nal_unit_type
) {
431 case media::H264NALU::kIDRSlice
:
432 ASSERT_TRUE(seen_sps_
);
433 ASSERT_TRUE(seen_pps_
);
437 case media::H264NALU::kNonIDRSlice
: {
438 ASSERT_TRUE(seen_idr_
);
439 if (!frame_cb_
.Run(keyframe
))
444 case media::H264NALU::kSPS
: {
446 ASSERT_EQ(media::H264Parser::kOk
, h264_parser_
.ParseSPS(&sps_id
));
451 case media::H264NALU::kPPS
: {
452 ASSERT_TRUE(seen_sps_
);
454 ASSERT_EQ(media::H264Parser::kOk
, h264_parser_
.ParsePPS(&pps_id
));
465 class VP8Validator
: public StreamValidator
{
467 explicit VP8Validator(const FrameFoundCallback
& frame_cb
)
468 : StreamValidator(frame_cb
),
469 seen_keyframe_(false) {}
471 void ProcessStreamBuffer(const uint8
* stream
, size_t size
) override
;
474 // Have we already got a keyframe in the stream?
478 void VP8Validator::ProcessStreamBuffer(const uint8
* stream
, size_t size
) {
479 bool keyframe
= !(stream
[0] & 0x01);
481 seen_keyframe_
= true;
483 EXPECT_TRUE(seen_keyframe_
);
485 frame_cb_
.Run(keyframe
);
486 // TODO(posciak): We could be getting more frames in the buffer, but there is
487 // no simple way to detect this. We'd need to parse the frames and go through
488 // partition numbers/sizes. For now assume one frame per buffer.
492 scoped_ptr
<StreamValidator
> StreamValidator::Create(
493 media::VideoCodecProfile profile
,
494 const FrameFoundCallback
& frame_cb
) {
495 scoped_ptr
<StreamValidator
> validator
;
497 if (IsH264(profile
)) {
498 validator
.reset(new H264Validator(frame_cb
));
499 } else if (IsVP8(profile
)) {
500 validator
.reset(new VP8Validator(frame_cb
));
502 LOG(FATAL
) << "Unsupported profile: " << profile
;
505 return validator
.Pass();
508 class VEAClient
: public VideoEncodeAccelerator::Client
{
510 VEAClient(TestStream
* test_stream
,
511 ClientStateNotification
<ClientState
>* note
,
513 unsigned int keyframe_period
,
516 bool mid_stream_bitrate_switch
,
517 bool mid_stream_framerate_switch
,
519 ~VEAClient() override
;
520 void CreateEncoder();
521 void DestroyEncoder();
523 // Return the number of encoded frames per second.
524 double frames_per_second();
526 // VideoDecodeAccelerator::Client implementation.
527 void RequireBitstreamBuffers(unsigned int input_count
,
528 const gfx::Size
& input_coded_size
,
529 size_t output_buffer_size
) override
;
530 void BitstreamBufferReady(int32 bitstream_buffer_id
,
532 bool key_frame
) override
;
533 void NotifyError(VideoEncodeAccelerator::Error error
) override
;
536 bool has_encoder() { return encoder_
.get(); }
538 scoped_ptr
<media::VideoEncodeAccelerator
> CreateFakeVEA();
539 scoped_ptr
<media::VideoEncodeAccelerator
> CreateV4L2VEA();
540 scoped_ptr
<media::VideoEncodeAccelerator
> CreateVaapiVEA();
542 void SetState(ClientState new_state
);
544 // Set current stream parameters to given |bitrate| at |framerate|.
545 void SetStreamParameters(unsigned int bitrate
, unsigned int framerate
);
547 // Called when encoder is done with a VideoFrame.
548 void InputNoLongerNeededCallback(int32 input_id
);
550 // Feed the encoder with one input frame.
551 void FeedEncoderWithOneInput();
553 // Provide the encoder with a new output buffer.
554 void FeedEncoderWithOutput(base::SharedMemory
* shm
);
556 // Called on finding a complete frame (with |keyframe| set to true for
557 // keyframes) in the stream, to perform codec-independent, per-frame checks
558 // and accounting. Returns false once we have collected all frames we needed.
559 bool HandleEncodedFrame(bool keyframe
);
561 // Verify that stream bitrate has been close to current_requested_bitrate_,
562 // assuming current_framerate_ since the last time VerifyStreamProperties()
563 // was called. Fail the test if |force_bitrate_| is true and the bitrate
564 // is not within kBitrateTolerance.
565 void VerifyStreamProperties();
567 // Test codec performance, failing the test if we are currently running
568 // the performance test.
571 // Write IVF file header to test_stream_->out_filename.
572 void WriteIvfFileHeader();
574 // Write an IVF frame header to test_stream_->out_filename.
575 void WriteIvfFrameHeader(int frame_index
, size_t frame_size
);
577 // Prepare and return a frame wrapping the data at |position| bytes in
578 // the input stream, ready to be sent to encoder.
579 scoped_refptr
<media::VideoFrame
> PrepareInputFrame(off_t position
);
581 // Update the parameters according to |mid_stream_bitrate_switch| and
582 // |mid_stream_framerate_switch|.
583 void UpdateTestStreamData(bool mid_stream_bitrate_switch
,
584 bool mid_stream_framerate_switch
);
586 // Callback function of the |input_timer_|.
590 scoped_ptr
<VideoEncodeAccelerator
> encoder_
;
592 TestStream
* test_stream_
;
594 // Used to notify another thread about the state. VEAClient does not own this.
595 ClientStateNotification
<ClientState
>* note_
;
597 // Ids assigned to VideoFrames (start at 1 for easy comparison with
598 // num_encoded_frames_).
599 std::set
<int32
> inputs_at_client_
;
600 int32 next_input_id_
;
602 // Ids for output BitstreamBuffers.
603 typedef std::map
<int32
, base::SharedMemory
*> IdToSHM
;
604 ScopedVector
<base::SharedMemory
> output_shms_
;
605 IdToSHM output_buffers_at_client_
;
606 int32 next_output_buffer_id_
;
608 // Current offset into input stream.
609 off_t pos_in_input_stream_
;
610 gfx::Size input_coded_size_
;
611 // Requested by encoder.
612 unsigned int num_required_input_buffers_
;
613 size_t output_buffer_size_
;
615 // Number of frames to encode. This may differ from the number of frames in
616 // stream if we need more frames for bitrate tests.
617 unsigned int num_frames_to_encode_
;
619 // Number of encoded frames we've got from the encoder thus far.
620 unsigned int num_encoded_frames_
;
622 // Frames since last bitrate verification.
623 unsigned int num_frames_since_last_check_
;
625 // True if received a keyframe while processing current bitstream buffer.
626 bool seen_keyframe_in_this_buffer_
;
628 // True if we are to save the encoded stream to a file.
631 // Request a keyframe every keyframe_period_ frames.
632 const unsigned int keyframe_period_
;
634 // Number of keyframes requested by now.
635 unsigned int num_keyframes_requested_
;
637 // Next keyframe expected before next_keyframe_at_ + kMaxKeyframeDelay.
638 unsigned int next_keyframe_at_
;
640 // True if we are asking encoder for a particular bitrate.
643 // Current requested bitrate.
644 unsigned int current_requested_bitrate_
;
646 // Current expected framerate.
647 unsigned int current_framerate_
;
649 // Byte size of the encoded stream (for bitrate calculation) since last
650 // time we checked bitrate.
651 size_t encoded_stream_size_since_last_check_
;
653 // If true, verify performance at the end of the test.
656 scoped_ptr
<StreamValidator
> validator_
;
658 // The time when the encoding started.
659 base::TimeTicks encode_start_time_
;
661 // The time when the last encoded frame is ready.
662 base::TimeTicks last_frame_ready_time_
;
664 // All methods of this class should be run on the same thread.
665 base::ThreadChecker thread_checker_
;
667 // Requested bitrate in bits per second.
668 unsigned int requested_bitrate_
;
670 // Requested initial framerate.
671 unsigned int requested_framerate_
;
673 // Bitrate to switch to in the middle of the stream.
674 unsigned int requested_subsequent_bitrate_
;
676 // Framerate to switch to in the middle of the stream.
677 unsigned int requested_subsequent_framerate_
;
679 // The timer used to feed the encoder with the input frames.
680 scoped_ptr
<base::RepeatingTimer
<VEAClient
>> input_timer_
;
682 // Feed the encoder with the input buffers at the |requested_framerate_|. If
683 // false, feed as fast as possible. This is set by the command line switch
688 VEAClient::VEAClient(TestStream
* test_stream
,
689 ClientStateNotification
<ClientState
>* note
,
691 unsigned int keyframe_period
,
694 bool mid_stream_bitrate_switch
,
695 bool mid_stream_framerate_switch
,
697 : state_(CS_CREATED
),
698 test_stream_(test_stream
),
701 next_output_buffer_id_(0),
702 pos_in_input_stream_(0),
703 num_required_input_buffers_(0),
704 output_buffer_size_(0),
705 num_frames_to_encode_(0),
706 num_encoded_frames_(0),
707 num_frames_since_last_check_(0),
708 seen_keyframe_in_this_buffer_(false),
709 save_to_file_(save_to_file
),
710 keyframe_period_(keyframe_period
),
711 num_keyframes_requested_(0),
712 next_keyframe_at_(kMaxFrameNum
),
713 force_bitrate_(force_bitrate
),
714 current_requested_bitrate_(0),
715 current_framerate_(0),
716 encoded_stream_size_since_last_check_(0),
717 test_perf_(test_perf
),
718 requested_bitrate_(0),
719 requested_framerate_(0),
720 requested_subsequent_bitrate_(0),
721 requested_subsequent_framerate_(0),
722 run_at_fps_(run_at_fps
) {
723 if (keyframe_period_
)
724 CHECK_LT(kMaxKeyframeDelay
, keyframe_period_
);
726 // Fake encoder produces an invalid stream, so skip validating it.
727 if (!g_fake_encoder
) {
728 validator_
= StreamValidator::Create(
729 test_stream_
->requested_profile
,
730 base::Bind(&VEAClient::HandleEncodedFrame
, base::Unretained(this)));
735 CHECK(!test_stream_
->out_filename
.empty());
736 base::FilePath
out_filename(test_stream_
->out_filename
);
737 // This creates or truncates out_filename.
738 // Without it, AppendToFile() will not work.
739 EXPECT_EQ(0, base::WriteFile(out_filename
, NULL
, 0));
742 // Initialize the parameters of the test streams.
743 UpdateTestStreamData(mid_stream_bitrate_switch
, mid_stream_framerate_switch
);
745 thread_checker_
.DetachFromThread();
748 VEAClient::~VEAClient() { CHECK(!has_encoder()); }
750 scoped_ptr
<media::VideoEncodeAccelerator
> VEAClient::CreateFakeVEA() {
751 scoped_ptr
<media::VideoEncodeAccelerator
> encoder
;
752 if (g_fake_encoder
) {
754 new media::FakeVideoEncodeAccelerator(
755 scoped_refptr
<base::SingleThreadTaskRunner
>(
756 base::MessageLoopProxy::current())));
758 return encoder
.Pass();
761 scoped_ptr
<media::VideoEncodeAccelerator
> VEAClient::CreateV4L2VEA() {
762 scoped_ptr
<media::VideoEncodeAccelerator
> encoder
;
763 #if defined(OS_CHROMEOS) && (defined(ARCH_CPU_ARMEL) || \
764 (defined(USE_OZONE) && defined(USE_V4L2_CODEC)))
765 scoped_refptr
<V4L2Device
> device
= V4L2Device::Create(V4L2Device::kEncoder
);
767 encoder
.reset(new V4L2VideoEncodeAccelerator(device
));
769 return encoder
.Pass();
772 scoped_ptr
<media::VideoEncodeAccelerator
> VEAClient::CreateVaapiVEA() {
773 scoped_ptr
<media::VideoEncodeAccelerator
> encoder
;
774 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
775 encoder
.reset(new VaapiVideoEncodeAccelerator());
777 return encoder
.Pass();
780 void VEAClient::CreateEncoder() {
781 DCHECK(thread_checker_
.CalledOnValidThread());
782 CHECK(!has_encoder());
784 scoped_ptr
<media::VideoEncodeAccelerator
> encoders
[] = {
790 DVLOG(1) << "Profile: " << test_stream_
->requested_profile
791 << ", initial bitrate: " << requested_bitrate_
;
793 for (size_t i
= 0; i
< arraysize(encoders
); ++i
) {
796 encoder_
= encoders
[i
].Pass();
797 SetState(CS_ENCODER_SET
);
798 if (encoder_
->Initialize(kInputFormat
,
799 test_stream_
->visible_size
,
800 test_stream_
->requested_profile
,
803 SetStreamParameters(requested_bitrate_
, requested_framerate_
);
804 SetState(CS_INITIALIZED
);
809 LOG(ERROR
) << "VideoEncodeAccelerator::Initialize() failed";
813 void VEAClient::DestroyEncoder() {
814 DCHECK(thread_checker_
.CalledOnValidThread());
818 input_timer_
.reset();
821 void VEAClient::UpdateTestStreamData(bool mid_stream_bitrate_switch
,
822 bool mid_stream_framerate_switch
) {
823 // Use defaults for bitrate/framerate if they are not provided.
824 if (test_stream_
->requested_bitrate
== 0)
825 requested_bitrate_
= kDefaultBitrate
;
827 requested_bitrate_
= test_stream_
->requested_bitrate
;
829 if (test_stream_
->requested_framerate
== 0)
830 requested_framerate_
= kDefaultFramerate
;
832 requested_framerate_
= test_stream_
->requested_framerate
;
834 // If bitrate/framerate switch is requested, use the subsequent values if
835 // provided, or, if not, calculate them from their initial values using
836 // the default ratios.
837 // Otherwise, if a switch is not requested, keep the initial values.
838 if (mid_stream_bitrate_switch
) {
839 if (test_stream_
->requested_subsequent_bitrate
== 0)
840 requested_subsequent_bitrate_
=
841 requested_bitrate_
* kDefaultSubsequentBitrateRatio
;
843 requested_subsequent_bitrate_
=
844 test_stream_
->requested_subsequent_bitrate
;
846 requested_subsequent_bitrate_
= requested_bitrate_
;
848 if (requested_subsequent_bitrate_
== 0)
849 requested_subsequent_bitrate_
= 1;
851 if (mid_stream_framerate_switch
) {
852 if (test_stream_
->requested_subsequent_framerate
== 0)
853 requested_subsequent_framerate_
=
854 requested_framerate_
* kDefaultSubsequentFramerateRatio
;
856 requested_subsequent_framerate_
=
857 test_stream_
->requested_subsequent_framerate
;
859 requested_subsequent_framerate_
= requested_framerate_
;
861 if (requested_subsequent_framerate_
== 0)
862 requested_subsequent_framerate_
= 1;
865 double VEAClient::frames_per_second() {
866 base::TimeDelta duration
= last_frame_ready_time_
- encode_start_time_
;
867 return num_encoded_frames_
/ duration
.InSecondsF();
870 void VEAClient::RequireBitstreamBuffers(unsigned int input_count
,
871 const gfx::Size
& input_coded_size
,
872 size_t output_size
) {
873 DCHECK(thread_checker_
.CalledOnValidThread());
874 ASSERT_EQ(state_
, CS_INITIALIZED
);
875 SetState(CS_ENCODING
);
877 CreateAlignedInputStreamFile(input_coded_size
, test_stream_
);
879 num_frames_to_encode_
= test_stream_
->num_frames
;
880 if (g_num_frames_to_encode
> 0)
881 num_frames_to_encode_
= g_num_frames_to_encode
;
883 // We may need to loop over the stream more than once if more frames than
884 // provided is required for bitrate tests.
885 if (force_bitrate_
&& num_frames_to_encode_
< kMinFramesForBitrateTests
) {
886 DVLOG(1) << "Stream too short for bitrate test ("
887 << test_stream_
->num_frames
<< " frames), will loop it to reach "
888 << kMinFramesForBitrateTests
<< " frames";
889 num_frames_to_encode_
= kMinFramesForBitrateTests
;
891 if (save_to_file_
&& IsVP8(test_stream_
->requested_profile
))
892 WriteIvfFileHeader();
894 input_coded_size_
= input_coded_size
;
895 num_required_input_buffers_
= input_count
;
896 ASSERT_GT(num_required_input_buffers_
, 0UL);
898 output_buffer_size_
= output_size
;
899 ASSERT_GT(output_buffer_size_
, 0UL);
901 for (unsigned int i
= 0; i
< kNumOutputBuffers
; ++i
) {
902 base::SharedMemory
* shm
= new base::SharedMemory();
903 CHECK(shm
->CreateAndMapAnonymous(output_buffer_size_
));
904 output_shms_
.push_back(shm
);
905 FeedEncoderWithOutput(shm
);
908 encode_start_time_
= base::TimeTicks::Now();
910 input_timer_
.reset(new base::RepeatingTimer
<VEAClient
>());
912 FROM_HERE
, base::TimeDelta::FromSeconds(1) / current_framerate_
,
913 base::Bind(&VEAClient::OnInputTimer
, base::Unretained(this)));
915 while (inputs_at_client_
.size() <
916 num_required_input_buffers_
+ kNumExtraInputFrames
)
917 FeedEncoderWithOneInput();
921 void VEAClient::BitstreamBufferReady(int32 bitstream_buffer_id
,
924 DCHECK(thread_checker_
.CalledOnValidThread());
925 ASSERT_LE(payload_size
, output_buffer_size_
);
927 IdToSHM::iterator it
= output_buffers_at_client_
.find(bitstream_buffer_id
);
928 ASSERT_NE(it
, output_buffers_at_client_
.end());
929 base::SharedMemory
* shm
= it
->second
;
930 output_buffers_at_client_
.erase(it
);
932 if (state_
== CS_FINISHED
)
935 encoded_stream_size_since_last_check_
+= payload_size
;
937 const uint8
* stream_ptr
= static_cast<const uint8
*>(shm
->memory());
938 if (payload_size
> 0) {
940 validator_
->ProcessStreamBuffer(stream_ptr
, payload_size
);
942 HandleEncodedFrame(key_frame
);
946 if (IsVP8(test_stream_
->requested_profile
))
947 WriteIvfFrameHeader(num_encoded_frames_
- 1, payload_size
);
949 EXPECT_TRUE(base::AppendToFile(
950 base::FilePath::FromUTF8Unsafe(test_stream_
->out_filename
),
951 static_cast<char*>(shm
->memory()),
952 base::checked_cast
<int>(payload_size
)));
956 EXPECT_EQ(key_frame
, seen_keyframe_in_this_buffer_
);
957 seen_keyframe_in_this_buffer_
= false;
959 FeedEncoderWithOutput(shm
);
962 void VEAClient::NotifyError(VideoEncodeAccelerator::Error error
) {
963 DCHECK(thread_checker_
.CalledOnValidThread());
967 void VEAClient::SetState(ClientState new_state
) {
968 DVLOG(4) << "Changing state " << state_
<< "->" << new_state
;
969 note_
->Notify(new_state
);
973 void VEAClient::SetStreamParameters(unsigned int bitrate
,
974 unsigned int framerate
) {
975 current_requested_bitrate_
= bitrate
;
976 current_framerate_
= framerate
;
977 CHECK_GT(current_requested_bitrate_
, 0UL);
978 CHECK_GT(current_framerate_
, 0UL);
979 encoder_
->RequestEncodingParametersChange(current_requested_bitrate_
,
981 DVLOG(1) << "Switched parameters to " << current_requested_bitrate_
982 << " bps @ " << current_framerate_
<< " FPS";
985 void VEAClient::InputNoLongerNeededCallback(int32 input_id
) {
986 std::set
<int32
>::iterator it
= inputs_at_client_
.find(input_id
);
987 ASSERT_NE(it
, inputs_at_client_
.end());
988 inputs_at_client_
.erase(it
);
990 FeedEncoderWithOneInput();
993 scoped_refptr
<media::VideoFrame
> VEAClient::PrepareInputFrame(off_t position
) {
994 CHECK_LE(position
+ test_stream_
->aligned_buffer_size
,
995 test_stream_
->mapped_aligned_in_file
.length());
997 uint8
* frame_data_y
= const_cast<uint8
*>(
998 test_stream_
->mapped_aligned_in_file
.data() + position
);
999 uint8
* frame_data_u
= frame_data_y
+ test_stream_
->aligned_plane_size
[0];
1000 uint8
* frame_data_v
= frame_data_u
+ test_stream_
->aligned_plane_size
[1];
1002 CHECK_GT(current_framerate_
, 0U);
1003 scoped_refptr
<media::VideoFrame
> frame
=
1004 media::VideoFrame::WrapExternalYuvData(
1007 gfx::Rect(test_stream_
->visible_size
),
1008 test_stream_
->visible_size
,
1009 input_coded_size_
.width(),
1010 input_coded_size_
.width() / 2,
1011 input_coded_size_
.width() / 2,
1015 base::TimeDelta().FromMilliseconds(
1016 next_input_id_
* base::Time::kMillisecondsPerSecond
/
1017 current_framerate_
),
1018 media::BindToCurrentLoop(
1019 base::Bind(&VEAClient::InputNoLongerNeededCallback
,
1020 base::Unretained(this),
1023 CHECK(inputs_at_client_
.insert(next_input_id_
).second
);
1029 void VEAClient::OnInputTimer() {
1030 if (!has_encoder() || state_
!= CS_ENCODING
)
1031 input_timer_
.reset();
1032 else if (inputs_at_client_
.size() <
1033 num_required_input_buffers_
+ kNumExtraInputFrames
)
1034 FeedEncoderWithOneInput();
1036 DVLOG(1) << "Dropping input frame";
1039 void VEAClient::FeedEncoderWithOneInput() {
1040 if (!has_encoder() || state_
!= CS_ENCODING
)
1044 test_stream_
->mapped_aligned_in_file
.length() - pos_in_input_stream_
;
1045 if (bytes_left
< test_stream_
->aligned_buffer_size
) {
1046 DCHECK_EQ(bytes_left
, 0UL);
1047 // Rewind if at the end of stream and we are still encoding.
1048 // This is to flush the encoder with additional frames from the beginning
1049 // of the stream, or if the stream is shorter that the number of frames
1050 // we require for bitrate tests.
1051 pos_in_input_stream_
= 0;
1054 bool force_keyframe
= false;
1055 if (keyframe_period_
&& next_input_id_
% keyframe_period_
== 0) {
1056 force_keyframe
= true;
1057 ++num_keyframes_requested_
;
1060 scoped_refptr
<media::VideoFrame
> video_frame
=
1061 PrepareInputFrame(pos_in_input_stream_
);
1062 pos_in_input_stream_
+= test_stream_
->aligned_buffer_size
;
1064 encoder_
->Encode(video_frame
, force_keyframe
);
1067 void VEAClient::FeedEncoderWithOutput(base::SharedMemory
* shm
) {
1071 if (state_
!= CS_ENCODING
)
1074 base::SharedMemoryHandle dup_handle
;
1075 CHECK(shm
->ShareToProcess(base::GetCurrentProcessHandle(), &dup_handle
));
1077 media::BitstreamBuffer
bitstream_buffer(
1078 next_output_buffer_id_
++, dup_handle
, output_buffer_size_
);
1079 CHECK(output_buffers_at_client_
.insert(std::make_pair(bitstream_buffer
.id(),
1081 encoder_
->UseOutputBitstreamBuffer(bitstream_buffer
);
1084 bool VEAClient::HandleEncodedFrame(bool keyframe
) {
1085 // This would be a bug in the test, which should not ignore false
1086 // return value from this method.
1087 CHECK_LE(num_encoded_frames_
, num_frames_to_encode_
);
1089 ++num_encoded_frames_
;
1090 ++num_frames_since_last_check_
;
1092 last_frame_ready_time_
= base::TimeTicks::Now();
1094 // Because the keyframe behavior requirements are loose, we give
1095 // the encoder more freedom here. It could either deliver a keyframe
1096 // immediately after we requested it, which could be for a frame number
1097 // before the one we requested it for (if the keyframe request
1098 // is asynchronous, i.e. not bound to any concrete frame, and because
1099 // the pipeline can be deeper than one frame), at that frame, or after.
1100 // So the only constraints we put here is that we get a keyframe not
1101 // earlier than we requested one (in time), and not later than
1102 // kMaxKeyframeDelay frames after the frame, for which we requested
1103 // it, comes back encoded.
1104 EXPECT_LE(num_encoded_frames_
, next_keyframe_at_
+ kMaxKeyframeDelay
);
1107 if (num_keyframes_requested_
> 0)
1108 --num_keyframes_requested_
;
1109 next_keyframe_at_
+= keyframe_period_
;
1110 seen_keyframe_in_this_buffer_
= true;
1113 if (num_encoded_frames_
== num_frames_to_encode_
/ 2) {
1114 VerifyStreamProperties();
1115 if (requested_subsequent_bitrate_
!= current_requested_bitrate_
||
1116 requested_subsequent_framerate_
!= current_framerate_
) {
1117 SetStreamParameters(requested_subsequent_bitrate_
,
1118 requested_subsequent_framerate_
);
1119 if (run_at_fps_
&& input_timer_
)
1120 input_timer_
->Start(
1121 FROM_HERE
, base::TimeDelta::FromSeconds(1) / current_framerate_
,
1122 base::Bind(&VEAClient::OnInputTimer
, base::Unretained(this)));
1124 } else if (num_encoded_frames_
== num_frames_to_encode_
) {
1126 VerifyStreamProperties();
1127 SetState(CS_FINISHED
);
1134 void VEAClient::VerifyPerf() {
1135 double measured_fps
= frames_per_second();
1136 LOG(INFO
) << "Measured encoder FPS: " << measured_fps
;
1138 EXPECT_GE(measured_fps
, kMinPerfFPS
);
1141 void VEAClient::VerifyStreamProperties() {
1142 CHECK_GT(num_frames_since_last_check_
, 0UL);
1143 CHECK_GT(encoded_stream_size_since_last_check_
, 0UL);
1144 unsigned int bitrate
= encoded_stream_size_since_last_check_
* 8 *
1145 current_framerate_
/ num_frames_since_last_check_
;
1146 DVLOG(1) << "Current chunk's bitrate: " << bitrate
1147 << " (expected: " << current_requested_bitrate_
1148 << " @ " << current_framerate_
<< " FPS,"
1149 << " num frames in chunk: " << num_frames_since_last_check_
;
1151 num_frames_since_last_check_
= 0;
1152 encoded_stream_size_since_last_check_
= 0;
1154 if (force_bitrate_
) {
1155 EXPECT_NEAR(bitrate
,
1156 current_requested_bitrate_
,
1157 kBitrateTolerance
* current_requested_bitrate_
);
1160 // All requested keyframes should've been provided. Allow the last requested
1161 // frame to remain undelivered if we haven't reached the maximum frame number
1162 // by which it should have arrived.
1163 if (num_encoded_frames_
< next_keyframe_at_
+ kMaxKeyframeDelay
)
1164 EXPECT_LE(num_keyframes_requested_
, 1UL);
1166 EXPECT_EQ(num_keyframes_requested_
, 0UL);
1169 void VEAClient::WriteIvfFileHeader() {
1170 IvfFileHeader header
;
1172 memset(&header
, 0, sizeof(header
));
1173 header
.signature
[0] = 'D';
1174 header
.signature
[1] = 'K';
1175 header
.signature
[2] = 'I';
1176 header
.signature
[3] = 'F';
1178 header
.header_size
= base::ByteSwapToLE16(sizeof(header
));
1179 header
.fourcc
= base::ByteSwapToLE32(0x30385056); // VP80
1180 header
.width
= base::ByteSwapToLE16(
1181 base::checked_cast
<uint16_t>(test_stream_
->visible_size
.width()));
1182 header
.height
= base::ByteSwapToLE16(
1183 base::checked_cast
<uint16_t>(test_stream_
->visible_size
.height()));
1184 header
.framerate
= base::ByteSwapToLE32(requested_framerate_
);
1185 header
.timescale
= base::ByteSwapToLE32(1);
1186 header
.num_frames
= base::ByteSwapToLE32(num_frames_to_encode_
);
1188 EXPECT_TRUE(base::AppendToFile(
1189 base::FilePath::FromUTF8Unsafe(test_stream_
->out_filename
),
1190 reinterpret_cast<char*>(&header
), sizeof(header
)));
1193 void VEAClient::WriteIvfFrameHeader(int frame_index
, size_t frame_size
) {
1194 IvfFrameHeader header
;
1196 memset(&header
, 0, sizeof(header
));
1197 header
.frame_size
= base::ByteSwapToLE32(frame_size
);
1198 header
.timestamp
= base::ByteSwapToLE64(frame_index
);
1199 EXPECT_TRUE(base::AppendToFile(
1200 base::FilePath::FromUTF8Unsafe(test_stream_
->out_filename
),
1201 reinterpret_cast<char*>(&header
), sizeof(header
)));
1204 // Setup test stream data and delete temporary aligned files at the beginning
1205 // and end of unittest. We only need to setup once for all test cases.
1206 class VideoEncodeAcceleratorTestEnvironment
: public ::testing::Environment
{
1208 VideoEncodeAcceleratorTestEnvironment(
1209 scoped_ptr
<base::FilePath::StringType
> data
,
1211 test_stream_data_
= data
.Pass();
1212 run_at_fps_
= run_at_fps
;
1215 virtual void SetUp() {
1216 ParseAndReadTestStreamData(*test_stream_data_
, &test_streams_
);
1219 virtual void TearDown() {
1220 for (size_t i
= 0; i
< test_streams_
.size(); i
++) {
1221 base::DeleteFile(test_streams_
[i
]->aligned_in_file
, false);
1225 ScopedVector
<TestStream
> test_streams_
;
1229 scoped_ptr
<base::FilePath::StringType
> test_stream_data_
;
1233 // - Number of concurrent encoders. The value takes effect when there is only
1234 // one input stream; otherwise, one encoder per input stream will be
1236 // - If true, save output to file (provided an output filename was supplied).
1237 // - Force a keyframe every n frames.
1238 // - Force bitrate; the actual required value is provided as a property
1239 // of the input stream, because it depends on stream type/resolution/etc.
1240 // - If true, measure performance.
1241 // - If true, switch bitrate mid-stream.
1242 // - If true, switch framerate mid-stream.
1243 class VideoEncodeAcceleratorTest
1244 : public ::testing::TestWithParam
<
1245 Tuple
<int, bool, int, bool, bool, bool, bool>> {};
1247 TEST_P(VideoEncodeAcceleratorTest
, TestSimpleEncode
) {
1248 size_t num_concurrent_encoders
= get
<0>(GetParam());
1249 const bool save_to_file
= get
<1>(GetParam());
1250 const unsigned int keyframe_period
= get
<2>(GetParam());
1251 const bool force_bitrate
= get
<3>(GetParam());
1252 const bool test_perf
= get
<4>(GetParam());
1253 const bool mid_stream_bitrate_switch
= get
<5>(GetParam());
1254 const bool mid_stream_framerate_switch
= get
<6>(GetParam());
1256 ScopedVector
<ClientStateNotification
<ClientState
> > notes
;
1257 ScopedVector
<VEAClient
> clients
;
1258 base::Thread
encoder_thread("EncoderThread");
1259 ASSERT_TRUE(encoder_thread
.Start());
1261 if (g_env
->test_streams_
.size() > 1)
1262 num_concurrent_encoders
= g_env
->test_streams_
.size();
1264 // Create all encoders.
1265 for (size_t i
= 0; i
< num_concurrent_encoders
; i
++) {
1266 size_t test_stream_index
= i
% g_env
->test_streams_
.size();
1267 // Disregard save_to_file if we didn't get an output filename.
1268 bool encoder_save_to_file
=
1270 !g_env
->test_streams_
[test_stream_index
]->out_filename
.empty());
1272 notes
.push_back(new ClientStateNotification
<ClientState
>());
1274 new VEAClient(g_env
->test_streams_
[test_stream_index
], notes
.back(),
1275 encoder_save_to_file
, keyframe_period
, force_bitrate
,
1276 test_perf
, mid_stream_bitrate_switch
,
1277 mid_stream_framerate_switch
, g_env
->run_at_fps_
));
1279 encoder_thread
.message_loop()->PostTask(
1281 base::Bind(&VEAClient::CreateEncoder
,
1282 base::Unretained(clients
.back())));
1285 // All encoders must pass through states in this order.
1286 enum ClientState state_transitions
[] = {CS_ENCODER_SET
, CS_INITIALIZED
,
1287 CS_ENCODING
, CS_FINISHED
};
1289 // Wait for all encoders to go through all states and finish.
1290 // Do this by waiting for all encoders to advance to state n before checking
1291 // state n+1, to verify that they are able to operate concurrently.
1292 // It also simulates the real-world usage better, as the main thread, on which
1293 // encoders are created/destroyed, is a single GPU Process ChildThread.
1294 // Moreover, we can't have proper multithreading on X11, so this could cause
1295 // hard to debug issues there, if there were multiple "ChildThreads".
1296 for (size_t state_no
= 0; state_no
< arraysize(state_transitions
); ++state_no
)
1297 for (size_t i
= 0; i
< num_concurrent_encoders
; i
++)
1298 ASSERT_EQ(notes
[i
]->Wait(), state_transitions
[state_no
]);
1300 for (size_t i
= 0; i
< num_concurrent_encoders
; ++i
) {
1301 encoder_thread
.message_loop()->PostTask(
1303 base::Bind(&VEAClient::DestroyEncoder
, base::Unretained(clients
[i
])));
1306 // This ensures all tasks have finished.
1307 encoder_thread
.Stop();
1310 INSTANTIATE_TEST_CASE_P(
1312 VideoEncodeAcceleratorTest
,
1313 ::testing::Values(MakeTuple(1, true, 0, false, false, false, false)));
1315 INSTANTIATE_TEST_CASE_P(
1317 VideoEncodeAcceleratorTest
,
1318 ::testing::Values(MakeTuple(1, false, 0, false, true, false, false)));
1320 INSTANTIATE_TEST_CASE_P(
1322 VideoEncodeAcceleratorTest
,
1323 ::testing::Values(MakeTuple(1, false, 10, false, false, false, false)));
1325 INSTANTIATE_TEST_CASE_P(
1327 VideoEncodeAcceleratorTest
,
1328 ::testing::Values(MakeTuple(1, false, 0, true, false, false, false)));
1330 INSTANTIATE_TEST_CASE_P(
1331 MidStreamParamSwitchBitrate
,
1332 VideoEncodeAcceleratorTest
,
1333 ::testing::Values(MakeTuple(1, false, 0, true, false, true, false)));
1335 INSTANTIATE_TEST_CASE_P(
1336 MidStreamParamSwitchFPS
,
1337 VideoEncodeAcceleratorTest
,
1338 ::testing::Values(MakeTuple(1, false, 0, true, false, false, true)));
1340 INSTANTIATE_TEST_CASE_P(
1342 VideoEncodeAcceleratorTest
,
1343 ::testing::Values(MakeTuple(3, false, 0, false, false, false, false),
1344 MakeTuple(3, false, 0, true, false, false, true),
1345 MakeTuple(3, false, 0, true, false, true, false)));
1347 // TODO(posciak): more tests:
1348 // - async FeedEncoderWithOutput
1349 // - out-of-order return of outputs to encoder
1350 // - multiple encoders + decoders
1351 // - mid-stream encoder_->Destroy()
1354 } // namespace content
1356 int main(int argc
, char** argv
) {
1357 testing::InitGoogleTest(&argc
, argv
); // Removes gtest-specific args.
1358 base::CommandLine::Init(argc
, argv
);
1360 base::ShadowingAtExitManager at_exit_manager
;
1361 base::MessageLoop main_loop
;
1363 #if defined(USE_OZONE)
1364 ui::OzonePlatform::InitializeForUI();
1365 ui::OzonePlatform::InitializeForGPU();
1368 scoped_ptr
<base::FilePath::StringType
> test_stream_data(
1369 new base::FilePath::StringType(
1370 media::GetTestDataFilePath(content::g_default_in_filename
).value() +
1371 content::g_default_in_parameters
));
1373 // Needed to enable DVLOG through --vmodule.
1374 logging::LoggingSettings settings
;
1375 settings
.logging_dest
= logging::LOG_TO_SYSTEM_DEBUG_LOG
;
1376 CHECK(logging::InitLogging(settings
));
1378 const base::CommandLine
* cmd_line
= base::CommandLine::ForCurrentProcess();
1381 bool run_at_fps
= false;
1382 base::CommandLine::SwitchMap switches
= cmd_line
->GetSwitches();
1383 for (base::CommandLine::SwitchMap::const_iterator it
= switches
.begin();
1384 it
!= switches
.end();
1386 if (it
->first
== "test_stream_data") {
1387 test_stream_data
->assign(it
->second
.c_str());
1390 if (it
->first
== "num_frames_to_encode") {
1391 std::string
input(it
->second
.begin(), it
->second
.end());
1392 CHECK(base::StringToInt(input
, &content::g_num_frames_to_encode
));
1395 if (it
->first
== "fake_encoder") {
1396 content::g_fake_encoder
= true;
1399 if (it
->first
== "run_at_fps") {
1403 if (it
->first
== "v" || it
->first
== "vmodule")
1405 if (it
->first
== "ozone-platform" || it
->first
== "ozone-use-surfaceless")
1407 LOG(FATAL
) << "Unexpected switch: " << it
->first
<< ":" << it
->second
;
1411 reinterpret_cast<content::VideoEncodeAcceleratorTestEnvironment
*>(
1412 testing::AddGlobalTestEnvironment(
1413 new content::VideoEncodeAcceleratorTestEnvironment(
1414 test_stream_data
.Pass(), run_at_fps
)));
1416 return RUN_ALL_TESTS();