Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / common / gpu / media / video_decode_accelerator_unittest.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // The bulk of this file is support code; sorry about that.  Here's an overview
6 // to hopefully help readers of this code:
7 // - RenderingHelper is charged with interacting with X11/{EGL/GLES2,GLX/GL} or
8 //   Win/EGL.
9 // - ClientState is an enum for the state of the decode client used by the test.
10 // - ClientStateNotification is a barrier abstraction that allows the test code
11 //   to be written sequentially and wait for the decode client to see certain
12 //   state transitions.
13 // - GLRenderingVDAClient is a VideoDecodeAccelerator::Client implementation
14 // - Finally actual TEST cases are at the bottom of this file, using the above
15 //   infrastructure.
16
17 #include <fcntl.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <algorithm>
21 #include <deque>
22 #include <map>
23
24 // Include gtest.h out of order because <X11/X.h> #define's Bool & None, which
25 // gtest uses as struct names (inside a namespace).  This means that
26 // #include'ing gtest after anything that pulls in X.h fails to compile.
27 // This is http://code.google.com/p/googletest/issues/detail?id=371
28 #include "testing/gtest/include/gtest/gtest.h"
29
30 #include "base/at_exit.h"
31 #include "base/bind.h"
32 #include "base/command_line.h"
33 #include "base/file_util.h"
34 #include "base/format_macros.h"
35 #include "base/md5.h"
36 #include "base/message_loop/message_loop_proxy.h"
37 #include "base/platform_file.h"
38 #include "base/process/process.h"
39 #include "base/stl_util.h"
40 #include "base/strings/string_number_conversions.h"
41 #include "base/strings/string_split.h"
42 #include "base/strings/stringize_macros.h"
43 #include "base/strings/stringprintf.h"
44 #include "base/strings/utf_string_conversions.h"
45 #include "base/synchronization/condition_variable.h"
46 #include "base/synchronization/lock.h"
47 #include "base/synchronization/waitable_event.h"
48 #include "base/threading/thread.h"
49 #include "content/common/gpu/media/rendering_helper.h"
50 #include "content/common/gpu/media/video_accelerator_unittest_helpers.h"
51 #include "content/public/common/content_switches.h"
52 #include "media/filters/h264_parser.h"
53 #include "ui/gfx/codec/png_codec.h"
54
55 #if defined(OS_WIN)
56 #include "content/common/gpu/media/dxva_video_decode_accelerator.h"
57 #elif defined(OS_CHROMEOS) || defined(OS_LINUX)
58 #if defined(ARCH_CPU_ARMEL)
59 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
60 #include "content/common/gpu/media/v4l2_video_device.h"
61 #elif defined(ARCH_CPU_X86_FAMILY)
62 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
63 #include "content/common/gpu/media/vaapi_wrapper.h"
64 #if defined(USE_X11)
65 #include "ui/gl/gl_implementation.h"
66 #endif  // USE_X11
67 #endif  // ARCH_CPU_ARMEL
68 #else
69 #error The VideoAccelerator tests are not supported on this platform.
70 #endif  // OS_WIN
71
72 using media::VideoDecodeAccelerator;
73
74 namespace content {
75 namespace {
76
77 // Values optionally filled in from flags; see main() below.
78 // The syntax of multiple test videos is:
79 //  test-video1;test-video2;test-video3
80 // where only the first video is required and other optional videos would be
81 // decoded by concurrent decoders.
82 // The syntax of each test-video is:
83 //  filename:width:height:numframes:numfragments:minFPSwithRender:minFPSnoRender
84 // where only the first field is required.  Value details:
85 // - |filename| must be an h264 Annex B (NAL) stream or an IVF VP8 stream.
86 // - |width| and |height| are in pixels.
87 // - |numframes| is the number of picture frames in the file.
88 // - |numfragments| NALU (h264) or frame (VP8) count in the stream.
89 // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds
90 //   expected to be achieved with and without rendering to the screen, resp.
91 //   (the latter tests just decode speed).
92 // - |profile| is the media::VideoCodecProfile set during Initialization.
93 // An empty value for a numeric field means "ignore".
94 const base::FilePath::CharType* g_test_video_data =
95     // FILE_PATH_LITERAL("test-25fps.vp8:320:240:250:250:50:175:11");
96     FILE_PATH_LITERAL("test-25fps.h264:320:240:250:258:50:175:1");
97
98 // The file path of the test output log. This is used to communicate the test
99 // results to CrOS autotests. We can enable the log and specify the filename by
100 // the "--output_log" switch.
101 const base::FilePath::CharType* g_output_log = NULL;
102
103 // The value is set by the switch "--rendering_fps".
104 double g_rendering_fps = 0;
105
106 // Disable rendering, the value is set by the switch "--disable_rendering".
107 bool g_disable_rendering = false;
108
109 // Magic constants for differentiating the reasons for NotifyResetDone being
110 // called.
111 enum ResetPoint {
112   // Reset() just after calling Decode() with a fragment containing config info.
113   RESET_AFTER_FIRST_CONFIG_INFO = -4,
114   START_OF_STREAM_RESET = -3,
115   MID_STREAM_RESET = -2,
116   END_OF_STREAM_RESET = -1
117 };
118
119 const int kMaxResetAfterFrameNum = 100;
120 const int kMaxFramesToDelayReuse = 64;
121 const base::TimeDelta kReuseDelay = base::TimeDelta::FromSeconds(1);
122 // Simulate WebRTC and call VDA::Decode 30 times per second.
123 const int kWebRtcDecodeCallsPerSecond = 30;
124
125 struct TestVideoFile {
126   explicit TestVideoFile(base::FilePath::StringType file_name)
127       : file_name(file_name),
128         width(-1),
129         height(-1),
130         num_frames(-1),
131         num_fragments(-1),
132         min_fps_render(-1),
133         min_fps_no_render(-1),
134         profile(media::VIDEO_CODEC_PROFILE_UNKNOWN),
135         reset_after_frame_num(END_OF_STREAM_RESET) {
136   }
137
138   base::FilePath::StringType file_name;
139   int width;
140   int height;
141   int num_frames;
142   int num_fragments;
143   int min_fps_render;
144   int min_fps_no_render;
145   media::VideoCodecProfile profile;
146   int reset_after_frame_num;
147   std::string data_str;
148 };
149
150 // Presumed minimal display size.
151 // We subtract one pixel from the width because some ARM chromebooks do not
152 // support two fullscreen app running at the same time. See crbug.com/270064.
153 const gfx::Size kThumbnailsDisplaySize(1366 - 1, 768);
154 const gfx::Size kThumbnailsPageSize(1600, 1200);
155 const gfx::Size kThumbnailSize(160, 120);
156 const int kMD5StringLength = 32;
157
158 // Read in golden MD5s for the thumbnailed rendering of this video
159 void ReadGoldenThumbnailMD5s(const TestVideoFile* video_file,
160                              std::vector<std::string>* md5_strings) {
161   base::FilePath filepath(video_file->file_name);
162   filepath = filepath.AddExtension(FILE_PATH_LITERAL(".md5"));
163   std::string all_md5s;
164   base::ReadFileToString(filepath, &all_md5s);
165   base::SplitString(all_md5s, '\n', md5_strings);
166   // Check these are legitimate MD5s.
167   for (std::vector<std::string>::iterator md5_string = md5_strings->begin();
168       md5_string != md5_strings->end(); ++md5_string) {
169       // Ignore the empty string added by SplitString
170       if (!md5_string->length())
171         continue;
172       // Ignore comments
173       if (md5_string->at(0) == '#')
174         continue;
175
176       CHECK_EQ(static_cast<int>(md5_string->length()),
177                kMD5StringLength) << *md5_string;
178       bool hex_only = std::count_if(md5_string->begin(),
179                                     md5_string->end(), isxdigit) ==
180                                     kMD5StringLength;
181       CHECK(hex_only) << *md5_string;
182   }
183   CHECK_GE(md5_strings->size(), 1U) << all_md5s;
184 }
185
186 // State of the GLRenderingVDAClient below.  Order matters here as the test
187 // makes assumptions about it.
188 enum ClientState {
189   CS_CREATED = 0,
190   CS_DECODER_SET = 1,
191   CS_INITIALIZED = 2,
192   CS_FLUSHING = 3,
193   CS_FLUSHED = 4,
194   CS_RESETTING = 5,
195   CS_RESET = 6,
196   CS_ERROR = 7,
197   CS_DESTROYED = 8,
198   CS_MAX,  // Must be last entry.
199 };
200
201 // A wrapper client that throttles the PictureReady callbacks to a given rate.
202 // It may drops or queues frame to deliver them on time.
203 class ThrottlingVDAClient : public VideoDecodeAccelerator::Client,
204                             public base::SupportsWeakPtr<ThrottlingVDAClient> {
205  public:
206   // Callback invoked whan the picture is dropped and should be reused for
207   // the decoder again.
208   typedef base::Callback<void(int32 picture_buffer_id)> ReusePictureCB;
209
210   ThrottlingVDAClient(VideoDecodeAccelerator::Client* client,
211                       double fps,
212                       ReusePictureCB reuse_picture_cb);
213   virtual ~ThrottlingVDAClient();
214
215   // VideoDecodeAccelerator::Client implementation
216   virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers,
217                                      const gfx::Size& dimensions,
218                                      uint32 texture_target) OVERRIDE;
219   virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE;
220   virtual void PictureReady(const media::Picture& picture) OVERRIDE;
221   virtual void NotifyInitializeDone() OVERRIDE;
222   virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE;
223   virtual void NotifyFlushDone() OVERRIDE;
224   virtual void NotifyResetDone() OVERRIDE;
225   virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE;
226
227   int num_decoded_frames() { return num_decoded_frames_; }
228
229  private:
230
231   void CallClientPictureReady(int version);
232
233   VideoDecodeAccelerator::Client* client_;
234   ReusePictureCB reuse_picture_cb_;
235   base::TimeTicks next_frame_delivered_time_;
236   base::TimeDelta frame_duration_;
237
238   int num_decoded_frames_;
239   int stream_version_;
240   std::deque<media::Picture> pending_pictures_;
241
242   DISALLOW_IMPLICIT_CONSTRUCTORS(ThrottlingVDAClient);
243 };
244
245 ThrottlingVDAClient::ThrottlingVDAClient(VideoDecodeAccelerator::Client* client,
246                                          double fps,
247                                          ReusePictureCB reuse_picture_cb)
248     : client_(client),
249       reuse_picture_cb_(reuse_picture_cb),
250       num_decoded_frames_(0),
251       stream_version_(0) {
252   CHECK(client_);
253   CHECK_GT(fps, 0);
254   frame_duration_ = base::TimeDelta::FromSeconds(1) / fps;
255 }
256
257 ThrottlingVDAClient::~ThrottlingVDAClient() {}
258
259 void ThrottlingVDAClient::ProvidePictureBuffers(uint32 requested_num_of_buffers,
260                                                 const gfx::Size& dimensions,
261                                                 uint32 texture_target) {
262   client_->ProvidePictureBuffers(
263       requested_num_of_buffers, dimensions, texture_target);
264 }
265
266 void ThrottlingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) {
267   client_->DismissPictureBuffer(picture_buffer_id);
268 }
269
270 void ThrottlingVDAClient::PictureReady(const media::Picture& picture) {
271   ++num_decoded_frames_;
272
273   if (pending_pictures_.empty()) {
274     base::TimeDelta delay =
275         next_frame_delivered_time_.is_null()
276             ? base::TimeDelta()
277             : next_frame_delivered_time_ - base::TimeTicks::Now();
278     base::MessageLoop::current()->PostDelayedTask(
279         FROM_HERE,
280         base::Bind(&ThrottlingVDAClient::CallClientPictureReady,
281                    AsWeakPtr(),
282                    stream_version_),
283         delay);
284   }
285   pending_pictures_.push_back(picture);
286 }
287
288 void ThrottlingVDAClient::CallClientPictureReady(int version) {
289   // Just return if we have reset the decoder
290   if (version != stream_version_)
291     return;
292
293   base::TimeTicks now = base::TimeTicks::Now();
294
295   if (next_frame_delivered_time_.is_null())
296     next_frame_delivered_time_ = now;
297
298   if (next_frame_delivered_time_ + frame_duration_ < now) {
299     // Too late, drop the frame
300     reuse_picture_cb_.Run(pending_pictures_.front().picture_buffer_id());
301   } else {
302     client_->PictureReady(pending_pictures_.front());
303   }
304
305   pending_pictures_.pop_front();
306   next_frame_delivered_time_ += frame_duration_;
307   if (!pending_pictures_.empty()) {
308     base::MessageLoop::current()->PostDelayedTask(
309         FROM_HERE,
310         base::Bind(&ThrottlingVDAClient::CallClientPictureReady,
311                    AsWeakPtr(),
312                    stream_version_),
313         next_frame_delivered_time_ - base::TimeTicks::Now());
314   }
315 }
316
317 void ThrottlingVDAClient::NotifyInitializeDone() {
318   client_->NotifyInitializeDone();
319 }
320
321 void ThrottlingVDAClient::NotifyEndOfBitstreamBuffer(
322     int32 bitstream_buffer_id) {
323   client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
324 }
325
326 void ThrottlingVDAClient::NotifyFlushDone() {
327   if (!pending_pictures_.empty()) {
328     base::MessageLoop::current()->PostDelayedTask(
329         FROM_HERE,
330         base::Bind(&ThrottlingVDAClient::NotifyFlushDone,
331                    base::Unretained(this)),
332         next_frame_delivered_time_ - base::TimeTicks::Now());
333     return;
334   }
335   client_->NotifyFlushDone();
336 }
337
338 void ThrottlingVDAClient::NotifyResetDone() {
339   ++stream_version_;
340   while (!pending_pictures_.empty()) {
341     reuse_picture_cb_.Run(pending_pictures_.front().picture_buffer_id());
342     pending_pictures_.pop_front();
343   }
344   next_frame_delivered_time_ = base::TimeTicks();
345   client_->NotifyResetDone();
346 }
347
348 void ThrottlingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) {
349   client_->NotifyError(error);
350 }
351
352 // Client that can accept callbacks from a VideoDecodeAccelerator and is used by
353 // the TESTs below.
354 class GLRenderingVDAClient
355     : public VideoDecodeAccelerator::Client,
356       public base::SupportsWeakPtr<GLRenderingVDAClient> {
357  public:
358   // Doesn't take ownership of |rendering_helper| or |note|, which must outlive
359   // |*this|.
360   // |num_play_throughs| indicates how many times to play through the video.
361   // |reset_after_frame_num| can be a frame number >=0 indicating a mid-stream
362   // Reset() should be done after that frame number is delivered, or
363   // END_OF_STREAM_RESET to indicate no mid-stream Reset().
364   // |delete_decoder_state| indicates when the underlying decoder should be
365   // Destroy()'d and deleted and can take values: N<0: delete after -N Decode()
366   // calls have been made, N>=0 means interpret as ClientState.
367   // Both |reset_after_frame_num| & |delete_decoder_state| apply only to the
368   // last play-through (governed by |num_play_throughs|).
369   // |rendering_fps| indicates the target rendering fps. 0 means no target fps
370   // and it would render as fast as possible.
371   // |suppress_rendering| indicates GL rendering is suppressed or not.
372   // After |delay_reuse_after_frame_num| frame has been delivered, the client
373   // will start delaying the call to ReusePictureBuffer() for kReuseDelay.
374   // |decode_calls_per_second| is the number of VDA::Decode calls per second.
375   // If |decode_calls_per_second| > 0, |num_in_flight_decodes| must be 1.
376   GLRenderingVDAClient(RenderingHelper* rendering_helper,
377                        int rendering_window_id,
378                        ClientStateNotification<ClientState>* note,
379                        const std::string& encoded_data,
380                        int num_in_flight_decodes,
381                        int num_play_throughs,
382                        int reset_after_frame_num,
383                        int delete_decoder_state,
384                        int frame_width,
385                        int frame_height,
386                        media::VideoCodecProfile profile,
387                        double rendering_fps,
388                        bool suppress_rendering,
389                        int delay_reuse_after_frame_num,
390                        int decode_calls_per_second);
391   virtual ~GLRenderingVDAClient();
392   void CreateAndStartDecoder();
393
394   // VideoDecodeAccelerator::Client implementation.
395   // The heart of the Client.
396   virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers,
397                                      const gfx::Size& dimensions,
398                                      uint32 texture_target) OVERRIDE;
399   virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE;
400   virtual void PictureReady(const media::Picture& picture) OVERRIDE;
401   // Simple state changes.
402   virtual void NotifyInitializeDone() OVERRIDE;
403   virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE;
404   virtual void NotifyFlushDone() OVERRIDE;
405   virtual void NotifyResetDone() OVERRIDE;
406   virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE;
407
408   void OutputFrameDeliveryTimes(base::PlatformFile output);
409
410   void NotifyFrameDropped(int32 picture_buffer_id);
411
412   // Simple getters for inspecting the state of the Client.
413   int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; }
414   int num_skipped_fragments() { return num_skipped_fragments_; }
415   int num_queued_fragments() { return num_queued_fragments_; }
416   int num_decoded_frames();
417   double frames_per_second();
418   // Return the median of the decode time in milliseconds.
419   int decode_time_median();
420   bool decoder_deleted() { return !decoder_.get(); }
421
422  private:
423   typedef std::map<int, media::PictureBuffer*> PictureBufferById;
424
425   void SetState(ClientState new_state);
426
427   // Delete the associated decoder helper.
428   void DeleteDecoder();
429
430   // Compute & return the first encoded bytes (including a start frame) to send
431   // to the decoder, starting at |start_pos| and returning one fragment. Skips
432   // to the first decodable position.
433   std::string GetBytesForFirstFragment(size_t start_pos, size_t* end_pos);
434   // Compute & return the encoded bytes of next fragment to send to the decoder
435   // (based on |start_pos|).
436   std::string GetBytesForNextFragment(size_t start_pos, size_t* end_pos);
437   // Helpers for GetBytesForNextFragment above.
438   void GetBytesForNextNALU(size_t start_pos, size_t* end_pos);  // For h.264.
439   std::string GetBytesForNextFrame(
440       size_t start_pos, size_t* end_pos);  // For VP8.
441
442   // Request decode of the next fragment in the encoded data.
443   void DecodeNextFragment();
444
445   RenderingHelper* rendering_helper_;
446   int rendering_window_id_;
447   std::string encoded_data_;
448   const int num_in_flight_decodes_;
449   int outstanding_decodes_;
450   size_t encoded_data_next_pos_to_decode_;
451   int next_bitstream_buffer_id_;
452   ClientStateNotification<ClientState>* note_;
453   scoped_ptr<VideoDecodeAccelerator> decoder_;
454   std::set<int> outstanding_texture_ids_;
455   int remaining_play_throughs_;
456   int reset_after_frame_num_;
457   int delete_decoder_state_;
458   ClientState state_;
459   int num_skipped_fragments_;
460   int num_queued_fragments_;
461   int num_decoded_frames_;
462   int num_done_bitstream_buffers_;
463   PictureBufferById picture_buffers_by_id_;
464   base::TimeTicks initialize_done_ticks_;
465   media::VideoCodecProfile profile_;
466   GLenum texture_target_;
467   bool suppress_rendering_;
468   std::vector<base::TimeTicks> frame_delivery_times_;
469   int delay_reuse_after_frame_num_;
470   scoped_ptr<ThrottlingVDAClient> throttling_client_;
471   // A map from bitstream buffer id to the decode start time of the buffer.
472   std::map<int, base::TimeTicks> decode_start_time_;
473   // The decode time of all decoded frames.
474   std::vector<base::TimeDelta> decode_time_;
475   // The number of VDA::Decode calls per second. This is to simulate webrtc.
476   int decode_calls_per_second_;
477
478   DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient);
479 };
480
481 GLRenderingVDAClient::GLRenderingVDAClient(
482     RenderingHelper* rendering_helper,
483     int rendering_window_id,
484     ClientStateNotification<ClientState>* note,
485     const std::string& encoded_data,
486     int num_in_flight_decodes,
487     int num_play_throughs,
488     int reset_after_frame_num,
489     int delete_decoder_state,
490     int frame_width,
491     int frame_height,
492     media::VideoCodecProfile profile,
493     double rendering_fps,
494     bool suppress_rendering,
495     int delay_reuse_after_frame_num,
496     int decode_calls_per_second)
497     : rendering_helper_(rendering_helper),
498       rendering_window_id_(rendering_window_id),
499       encoded_data_(encoded_data),
500       num_in_flight_decodes_(num_in_flight_decodes),
501       outstanding_decodes_(0),
502       encoded_data_next_pos_to_decode_(0),
503       next_bitstream_buffer_id_(0),
504       note_(note),
505       remaining_play_throughs_(num_play_throughs),
506       reset_after_frame_num_(reset_after_frame_num),
507       delete_decoder_state_(delete_decoder_state),
508       state_(CS_CREATED),
509       num_skipped_fragments_(0),
510       num_queued_fragments_(0),
511       num_decoded_frames_(0),
512       num_done_bitstream_buffers_(0),
513       texture_target_(0),
514       suppress_rendering_(suppress_rendering),
515       delay_reuse_after_frame_num_(delay_reuse_after_frame_num),
516       decode_calls_per_second_(decode_calls_per_second) {
517   CHECK_GT(num_in_flight_decodes, 0);
518   CHECK_GT(num_play_throughs, 0);
519   CHECK_GE(rendering_fps, 0);
520   // |num_in_flight_decodes_| is unsupported if |decode_calls_per_second_| > 0.
521   if (decode_calls_per_second_ > 0)
522     CHECK_EQ(1, num_in_flight_decodes_);
523
524   // Default to H264 baseline if no profile provided.
525   profile_ = (profile != media::VIDEO_CODEC_PROFILE_UNKNOWN
526                   ? profile
527                   : media::H264PROFILE_BASELINE);
528
529   if (rendering_fps > 0)
530     throttling_client_.reset(new ThrottlingVDAClient(
531         this,
532         rendering_fps,
533         base::Bind(&GLRenderingVDAClient::NotifyFrameDropped,
534                    base::Unretained(this))));
535 }
536
537 GLRenderingVDAClient::~GLRenderingVDAClient() {
538   DeleteDecoder();  // Clean up in case of expected error.
539   CHECK(decoder_deleted());
540   STLDeleteValues(&picture_buffers_by_id_);
541   SetState(CS_DESTROYED);
542 }
543
544 static bool DoNothingReturnTrue() { return true; }
545
546 void GLRenderingVDAClient::CreateAndStartDecoder() {
547   CHECK(decoder_deleted());
548   CHECK(!decoder_.get());
549
550   VideoDecodeAccelerator::Client* client = this;
551   base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr();
552   if (throttling_client_) {
553     client = throttling_client_.get();
554     weak_client = throttling_client_->AsWeakPtr();
555   }
556 #if defined(OS_WIN)
557   decoder_.reset(
558       new DXVAVideoDecodeAccelerator(client, base::Bind(&DoNothingReturnTrue)));
559 #elif defined(OS_CHROMEOS) || defined(OS_LINUX)
560 #if defined(ARCH_CPU_ARMEL)
561
562   scoped_ptr<V4L2Device> device = V4L2Device::Create();
563   if (!device.get()) {
564     NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
565     return;
566   }
567   decoder_.reset(new V4L2VideoDecodeAccelerator(
568       static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()),
569       client,
570       weak_client,
571       base::Bind(&DoNothingReturnTrue),
572       device.Pass(),
573       base::MessageLoopProxy::current()));
574 #elif defined(ARCH_CPU_X86_FAMILY)
575   CHECK_EQ(gfx::kGLImplementationDesktopGL, gfx::GetGLImplementation())
576       << "Hardware video decode does not work with OSMesa";
577   decoder_.reset(new VaapiVideoDecodeAccelerator(
578       static_cast<Display*>(rendering_helper_->GetGLDisplay()),
579       client,
580       base::Bind(&DoNothingReturnTrue)));
581 #endif  // ARCH_CPU_ARMEL
582 #endif  // OS_WIN
583   CHECK(decoder_.get());
584   SetState(CS_DECODER_SET);
585   if (decoder_deleted())
586     return;
587
588   CHECK(decoder_->Initialize(profile_));
589 }
590
591 void GLRenderingVDAClient::ProvidePictureBuffers(
592     uint32 requested_num_of_buffers,
593     const gfx::Size& dimensions,
594     uint32 texture_target) {
595   if (decoder_deleted())
596     return;
597   std::vector<media::PictureBuffer> buffers;
598
599   texture_target_ = texture_target;
600   for (uint32 i = 0; i < requested_num_of_buffers; ++i) {
601     uint32 id = picture_buffers_by_id_.size();
602     uint32 texture_id;
603     base::WaitableEvent done(false, false);
604     rendering_helper_->CreateTexture(
605         rendering_window_id_, texture_target_, &texture_id, &done);
606     done.Wait();
607     CHECK(outstanding_texture_ids_.insert(texture_id).second);
608     media::PictureBuffer* buffer =
609         new media::PictureBuffer(id, dimensions, texture_id);
610     CHECK(picture_buffers_by_id_.insert(std::make_pair(id, buffer)).second);
611     buffers.push_back(*buffer);
612   }
613   decoder_->AssignPictureBuffers(buffers);
614 }
615
616 void GLRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) {
617   PictureBufferById::iterator it =
618       picture_buffers_by_id_.find(picture_buffer_id);
619   CHECK(it != picture_buffers_by_id_.end());
620   CHECK_EQ(outstanding_texture_ids_.erase(it->second->texture_id()), 1U);
621   rendering_helper_->DeleteTexture(it->second->texture_id());
622   delete it->second;
623   picture_buffers_by_id_.erase(it);
624 }
625
626 void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
627   // We shouldn't be getting pictures delivered after Reset has completed.
628   CHECK_LT(state_, CS_RESET);
629
630   if (decoder_deleted())
631     return;
632
633   base::TimeTicks now = base::TimeTicks::Now();
634   frame_delivery_times_.push_back(now);
635   // Save the decode time of this picture.
636   std::map<int, base::TimeTicks>::iterator it =
637       decode_start_time_.find(picture.bitstream_buffer_id());
638   ASSERT_NE(decode_start_time_.end(), it);
639   decode_time_.push_back(now - it->second);
640   decode_start_time_.erase(it);
641
642   CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_);
643   ++num_decoded_frames_;
644
645   // Mid-stream reset applies only to the last play-through per constructor
646   // comment.
647   if (remaining_play_throughs_ == 1 &&
648       reset_after_frame_num_ == num_decoded_frames()) {
649     reset_after_frame_num_ = MID_STREAM_RESET;
650     decoder_->Reset();
651     // Re-start decoding from the beginning of the stream to avoid needing to
652     // know how to find I-frames and so on in this test.
653     encoded_data_next_pos_to_decode_ = 0;
654   }
655
656   media::PictureBuffer* picture_buffer =
657       picture_buffers_by_id_[picture.picture_buffer_id()];
658   CHECK(picture_buffer);
659   if (!suppress_rendering_) {
660     rendering_helper_->RenderTexture(texture_target_,
661                                      picture_buffer->texture_id());
662   }
663
664   if (num_decoded_frames() > delay_reuse_after_frame_num_) {
665     base::MessageLoop::current()->PostDelayedTask(
666         FROM_HERE,
667         base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer,
668                    decoder_->AsWeakPtr(),
669                    picture.picture_buffer_id()),
670         kReuseDelay);
671   } else {
672     decoder_->ReusePictureBuffer(picture.picture_buffer_id());
673   }
674 }
675
676 void GLRenderingVDAClient::NotifyInitializeDone() {
677   SetState(CS_INITIALIZED);
678   initialize_done_ticks_ = base::TimeTicks::Now();
679
680   if (reset_after_frame_num_ == START_OF_STREAM_RESET) {
681     reset_after_frame_num_ = MID_STREAM_RESET;
682     decoder_->Reset();
683     return;
684   }
685
686   for (int i = 0; i < num_in_flight_decodes_; ++i)
687     DecodeNextFragment();
688   DCHECK_EQ(outstanding_decodes_, num_in_flight_decodes_);
689 }
690
691 void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer(
692     int32 bitstream_buffer_id) {
693   // TODO(fischman): this test currently relies on this notification to make
694   // forward progress during a Reset().  But the VDA::Reset() API doesn't
695   // guarantee this, so stop relying on it (and remove the notifications from
696   // VaapiVideoDecodeAccelerator::FinishReset()).
697   ++num_done_bitstream_buffers_;
698   --outstanding_decodes_;
699   if (decode_calls_per_second_ == 0)
700     DecodeNextFragment();
701 }
702
703 void GLRenderingVDAClient::NotifyFlushDone() {
704   if (decoder_deleted())
705     return;
706   SetState(CS_FLUSHED);
707   --remaining_play_throughs_;
708   DCHECK_GE(remaining_play_throughs_, 0);
709   if (decoder_deleted())
710     return;
711   decoder_->Reset();
712   SetState(CS_RESETTING);
713 }
714
715 void GLRenderingVDAClient::NotifyResetDone() {
716   if (decoder_deleted())
717     return;
718
719   if (reset_after_frame_num_ == MID_STREAM_RESET) {
720     reset_after_frame_num_ = END_OF_STREAM_RESET;
721     DecodeNextFragment();
722     return;
723   } else if (reset_after_frame_num_ == START_OF_STREAM_RESET) {
724     reset_after_frame_num_ = END_OF_STREAM_RESET;
725     for (int i = 0; i < num_in_flight_decodes_; ++i)
726       DecodeNextFragment();
727     return;
728   }
729
730   if (remaining_play_throughs_) {
731     encoded_data_next_pos_to_decode_ = 0;
732     NotifyInitializeDone();
733     return;
734   }
735
736   SetState(CS_RESET);
737   if (!decoder_deleted())
738     DeleteDecoder();
739 }
740
741 void GLRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) {
742   SetState(CS_ERROR);
743 }
744
745 void GLRenderingVDAClient::OutputFrameDeliveryTimes(base::PlatformFile output) {
746   std::string s = base::StringPrintf("frame count: %" PRIuS "\n",
747                                      frame_delivery_times_.size());
748   base::WritePlatformFileAtCurrentPos(output, s.data(), s.length());
749   base::TimeTicks t0 = initialize_done_ticks_;
750   for (size_t i = 0; i < frame_delivery_times_.size(); ++i) {
751     s = base::StringPrintf("frame %04" PRIuS ": %" PRId64 " us\n",
752                            i,
753                            (frame_delivery_times_[i] - t0).InMicroseconds());
754     t0 = frame_delivery_times_[i];
755     base::WritePlatformFileAtCurrentPos(output, s.data(), s.length());
756   }
757 }
758
759 void GLRenderingVDAClient::NotifyFrameDropped(int32 picture_buffer_id) {
760   decoder_->ReusePictureBuffer(picture_buffer_id);
761 }
762
763 static bool LookingAtNAL(const std::string& encoded, size_t pos) {
764   return encoded[pos] == 0 && encoded[pos + 1] == 0 &&
765       encoded[pos + 2] == 0 && encoded[pos + 3] == 1;
766 }
767
768 void GLRenderingVDAClient::SetState(ClientState new_state) {
769   note_->Notify(new_state);
770   state_ = new_state;
771   if (!remaining_play_throughs_ && new_state == delete_decoder_state_) {
772     CHECK(!decoder_deleted());
773     DeleteDecoder();
774   }
775 }
776
777 void GLRenderingVDAClient::DeleteDecoder() {
778   if (decoder_deleted())
779     return;
780   decoder_.release()->Destroy();
781   STLClearObject(&encoded_data_);
782   for (std::set<int>::iterator it = outstanding_texture_ids_.begin();
783        it != outstanding_texture_ids_.end(); ++it) {
784     rendering_helper_->DeleteTexture(*it);
785   }
786   outstanding_texture_ids_.clear();
787   // Cascade through the rest of the states to simplify test code below.
788   for (int i = state_ + 1; i < CS_MAX; ++i)
789     SetState(static_cast<ClientState>(i));
790 }
791
792 std::string GLRenderingVDAClient::GetBytesForFirstFragment(
793     size_t start_pos, size_t* end_pos) {
794   if (profile_ < media::H264PROFILE_MAX) {
795     *end_pos = start_pos;
796     while (*end_pos + 4 < encoded_data_.size()) {
797       if ((encoded_data_[*end_pos + 4] & 0x1f) == 0x7) // SPS start frame
798         return GetBytesForNextFragment(*end_pos, end_pos);
799       GetBytesForNextNALU(*end_pos, end_pos);
800       num_skipped_fragments_++;
801     }
802     *end_pos = start_pos;
803     return std::string();
804   }
805   DCHECK_LE(profile_, media::VP8PROFILE_MAX);
806   return GetBytesForNextFragment(start_pos, end_pos);
807 }
808
809 std::string GLRenderingVDAClient::GetBytesForNextFragment(
810     size_t start_pos, size_t* end_pos) {
811   if (profile_ < media::H264PROFILE_MAX) {
812     *end_pos = start_pos;
813     GetBytesForNextNALU(*end_pos, end_pos);
814     if (start_pos != *end_pos) {
815       num_queued_fragments_++;
816     }
817     return encoded_data_.substr(start_pos, *end_pos - start_pos);
818   }
819   DCHECK_LE(profile_, media::VP8PROFILE_MAX);
820   return GetBytesForNextFrame(start_pos, end_pos);
821 }
822
823 void GLRenderingVDAClient::GetBytesForNextNALU(
824     size_t start_pos, size_t* end_pos) {
825   *end_pos = start_pos;
826   if (*end_pos + 4 > encoded_data_.size())
827     return;
828   CHECK(LookingAtNAL(encoded_data_, start_pos));
829   *end_pos += 4;
830   while (*end_pos + 4 <= encoded_data_.size() &&
831          !LookingAtNAL(encoded_data_, *end_pos)) {
832     ++*end_pos;
833   }
834   if (*end_pos + 3 >= encoded_data_.size())
835     *end_pos = encoded_data_.size();
836 }
837
838 std::string GLRenderingVDAClient::GetBytesForNextFrame(
839     size_t start_pos, size_t* end_pos) {
840   // Helpful description: http://wiki.multimedia.cx/index.php?title=IVF
841   std::string bytes;
842   if (start_pos == 0)
843     start_pos = 32;  // Skip IVF header.
844   *end_pos = start_pos;
845   uint32 frame_size = *reinterpret_cast<uint32*>(&encoded_data_[*end_pos]);
846   *end_pos += 12;  // Skip frame header.
847   bytes.append(encoded_data_.substr(*end_pos, frame_size));
848   *end_pos += frame_size;
849   num_queued_fragments_++;
850   return bytes;
851 }
852
853 static bool FragmentHasConfigInfo(const uint8* data, size_t size,
854                                   media::VideoCodecProfile profile) {
855   if (profile >= media::H264PROFILE_MIN &&
856       profile <= media::H264PROFILE_MAX) {
857     media::H264Parser parser;
858     parser.SetStream(data, size);
859     media::H264NALU nalu;
860     media::H264Parser::Result result = parser.AdvanceToNextNALU(&nalu);
861     if (result != media::H264Parser::kOk) {
862       // Let the VDA figure out there's something wrong with the stream.
863       return false;
864     }
865
866     return nalu.nal_unit_type == media::H264NALU::kSPS;
867   } else if (profile >= media::VP8PROFILE_MIN &&
868              profile <= media::VP8PROFILE_MAX) {
869     return (size > 0 && !(data[0] & 0x01));
870   }
871   // Shouldn't happen at this point.
872   LOG(FATAL) << "Invalid profile: " << profile;
873   return false;
874 }
875
876 void GLRenderingVDAClient::DecodeNextFragment() {
877   if (decoder_deleted())
878     return;
879   if (encoded_data_next_pos_to_decode_ == encoded_data_.size()) {
880     if (outstanding_decodes_ == 0) {
881       decoder_->Flush();
882       SetState(CS_FLUSHING);
883     }
884     return;
885   }
886   size_t end_pos;
887   std::string next_fragment_bytes;
888   if (encoded_data_next_pos_to_decode_ == 0) {
889     next_fragment_bytes = GetBytesForFirstFragment(0, &end_pos);
890   } else {
891     next_fragment_bytes =
892         GetBytesForNextFragment(encoded_data_next_pos_to_decode_, &end_pos);
893   }
894   size_t next_fragment_size = next_fragment_bytes.size();
895
896   // Call Reset() just after Decode() if the fragment contains config info.
897   // This tests how the VDA behaves when it gets a reset request before it has
898   // a chance to ProvidePictureBuffers().
899   bool reset_here = false;
900   if (reset_after_frame_num_ == RESET_AFTER_FIRST_CONFIG_INFO) {
901     reset_here = FragmentHasConfigInfo(
902         reinterpret_cast<const uint8*>(next_fragment_bytes.data()),
903         next_fragment_size,
904         profile_);
905     if (reset_here)
906       reset_after_frame_num_ = END_OF_STREAM_RESET;
907   }
908
909   // Populate the shared memory buffer w/ the fragment, duplicate its handle,
910   // and hand it off to the decoder.
911   base::SharedMemory shm;
912   CHECK(shm.CreateAndMapAnonymous(next_fragment_size));
913   memcpy(shm.memory(), next_fragment_bytes.data(), next_fragment_size);
914   base::SharedMemoryHandle dup_handle;
915   CHECK(shm.ShareToProcess(base::Process::Current().handle(), &dup_handle));
916   media::BitstreamBuffer bitstream_buffer(
917       next_bitstream_buffer_id_, dup_handle, next_fragment_size);
918   decode_start_time_[next_bitstream_buffer_id_] = base::TimeTicks::Now();
919   // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
920   next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
921   decoder_->Decode(bitstream_buffer);
922   ++outstanding_decodes_;
923   if (!remaining_play_throughs_ &&
924       -delete_decoder_state_ == next_bitstream_buffer_id_) {
925     DeleteDecoder();
926   }
927
928   if (reset_here) {
929     reset_after_frame_num_ = MID_STREAM_RESET;
930     decoder_->Reset();
931     // Restart from the beginning to re-Decode() the SPS we just sent.
932     encoded_data_next_pos_to_decode_ = 0;
933   } else {
934     encoded_data_next_pos_to_decode_ = end_pos;
935   }
936
937   if (decode_calls_per_second_ > 0) {
938     base::MessageLoop::current()->PostDelayedTask(
939         FROM_HERE,
940         base::Bind(&GLRenderingVDAClient::DecodeNextFragment, AsWeakPtr()),
941         base::TimeDelta::FromSeconds(1) / decode_calls_per_second_);
942   }
943 }
944
945 int GLRenderingVDAClient::num_decoded_frames() {
946   return throttling_client_ ? throttling_client_->num_decoded_frames()
947                             : num_decoded_frames_;
948 }
949
950 double GLRenderingVDAClient::frames_per_second() {
951   base::TimeDelta delta = frame_delivery_times_.back() - initialize_done_ticks_;
952   if (delta.InSecondsF() == 0)
953     return 0;
954   return num_decoded_frames() / delta.InSecondsF();
955 }
956
957 int GLRenderingVDAClient::decode_time_median() {
958   if (decode_time_.size() == 0)
959     return 0;
960   std::sort(decode_time_.begin(), decode_time_.end());
961   int index = decode_time_.size() / 2;
962   if (decode_time_.size() % 2 != 0)
963     return decode_time_[index].InMilliseconds();
964
965   return (decode_time_[index] + decode_time_[index - 1]).InMilliseconds() / 2;
966 }
967
968 class VideoDecodeAcceleratorTest : public ::testing::Test {
969  protected:
970   VideoDecodeAcceleratorTest();
971   virtual void SetUp();
972   virtual void TearDown();
973
974   // Parse |data| into its constituent parts, set the various output fields
975   // accordingly, and read in video stream. CHECK-fails on unexpected or
976   // missing required data. Unspecified optional fields are set to -1.
977   void ParseAndReadTestVideoData(base::FilePath::StringType data,
978                                  std::vector<TestVideoFile*>* test_video_files);
979
980   // Update the parameters of |test_video_files| according to
981   // |num_concurrent_decoders| and |reset_point|. Ex: the expected number of
982   // frames should be adjusted if decoder is reset in the middle of the stream.
983   void UpdateTestVideoFileParams(
984       size_t num_concurrent_decoders,
985       int reset_point,
986       std::vector<TestVideoFile*>* test_video_files);
987
988   void InitializeRenderingHelper(const RenderingHelperParams& helper_params);
989   void CreateAndStartDecoder(GLRenderingVDAClient* client,
990                              ClientStateNotification<ClientState>* note);
991   void WaitUntilDecodeFinish(ClientStateNotification<ClientState>* note);
992   void WaitUntilIdle();
993   void OutputLogFile(const base::FilePath::CharType* log_path,
994                      const std::string& content);
995
996   std::vector<TestVideoFile*> test_video_files_;
997   RenderingHelper rendering_helper_;
998   scoped_refptr<base::MessageLoopProxy> rendering_loop_proxy_;
999
1000  private:
1001   base::Thread rendering_thread_;
1002   // Required for Thread to work.  Not used otherwise.
1003   base::ShadowingAtExitManager at_exit_manager_;
1004
1005   DISALLOW_COPY_AND_ASSIGN(VideoDecodeAcceleratorTest);
1006 };
1007
1008 VideoDecodeAcceleratorTest::VideoDecodeAcceleratorTest()
1009     : rendering_thread_("GLRenderingVDAClientThread") {}
1010
1011 void VideoDecodeAcceleratorTest::SetUp() {
1012   ParseAndReadTestVideoData(g_test_video_data, &test_video_files_);
1013
1014   // Initialize the rendering thread.
1015   base::Thread::Options options;
1016   options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
1017 #if defined(OS_WIN)
1018   // For windows the decoding thread initializes the media foundation decoder
1019   // which uses COM. We need the thread to be a UI thread.
1020   options.message_loop_type = base::MessageLoop::TYPE_UI;
1021 #endif  // OS_WIN
1022
1023   rendering_thread_.StartWithOptions(options);
1024   rendering_loop_proxy_ = rendering_thread_.message_loop_proxy();
1025 }
1026
1027 void VideoDecodeAcceleratorTest::TearDown() {
1028   rendering_loop_proxy_->PostTask(
1029       FROM_HERE,
1030       base::Bind(&STLDeleteElements<std::vector<TestVideoFile*> >,
1031                  &test_video_files_));
1032
1033   base::WaitableEvent done(false, false);
1034   rendering_loop_proxy_->PostTask(
1035       FROM_HERE,
1036       base::Bind(&RenderingHelper::UnInitialize,
1037                  base::Unretained(&rendering_helper_),
1038                  &done));
1039   done.Wait();
1040
1041   rendering_thread_.Stop();
1042 }
1043
1044 void VideoDecodeAcceleratorTest::ParseAndReadTestVideoData(
1045     base::FilePath::StringType data,
1046     std::vector<TestVideoFile*>* test_video_files) {
1047   std::vector<base::FilePath::StringType> entries;
1048   base::SplitString(data, ';', &entries);
1049   CHECK_GE(entries.size(), 1U) << data;
1050   for (size_t index = 0; index < entries.size(); ++index) {
1051     std::vector<base::FilePath::StringType> fields;
1052     base::SplitString(entries[index], ':', &fields);
1053     CHECK_GE(fields.size(), 1U) << entries[index];
1054     CHECK_LE(fields.size(), 8U) << entries[index];
1055     TestVideoFile* video_file = new TestVideoFile(fields[0]);
1056     if (!fields[1].empty())
1057       CHECK(base::StringToInt(fields[1], &video_file->width));
1058     if (!fields[2].empty())
1059       CHECK(base::StringToInt(fields[2], &video_file->height));
1060     if (!fields[3].empty())
1061       CHECK(base::StringToInt(fields[3], &video_file->num_frames));
1062     if (!fields[4].empty())
1063       CHECK(base::StringToInt(fields[4], &video_file->num_fragments));
1064     if (!fields[5].empty())
1065       CHECK(base::StringToInt(fields[5], &video_file->min_fps_render));
1066     if (!fields[6].empty())
1067       CHECK(base::StringToInt(fields[6], &video_file->min_fps_no_render));
1068     int profile = -1;
1069     if (!fields[7].empty())
1070       CHECK(base::StringToInt(fields[7], &profile));
1071     video_file->profile = static_cast<media::VideoCodecProfile>(profile);
1072
1073     // Read in the video data.
1074     base::FilePath filepath(video_file->file_name);
1075     CHECK(base::ReadFileToString(filepath, &video_file->data_str))
1076         << "test_video_file: " << filepath.MaybeAsASCII();
1077
1078     test_video_files->push_back(video_file);
1079   }
1080 }
1081
1082 void VideoDecodeAcceleratorTest::UpdateTestVideoFileParams(
1083     size_t num_concurrent_decoders,
1084     int reset_point,
1085     std::vector<TestVideoFile*>* test_video_files) {
1086   for (size_t i = 0; i < test_video_files->size(); i++) {
1087     TestVideoFile* video_file = (*test_video_files)[i];
1088     if (reset_point == MID_STREAM_RESET) {
1089       // Reset should not go beyond the last frame;
1090       // reset in the middle of the stream for short videos.
1091       video_file->reset_after_frame_num = kMaxResetAfterFrameNum;
1092       if (video_file->num_frames <= video_file->reset_after_frame_num)
1093         video_file->reset_after_frame_num = video_file->num_frames / 2;
1094
1095       video_file->num_frames += video_file->reset_after_frame_num;
1096     } else {
1097       video_file->reset_after_frame_num = reset_point;
1098     }
1099
1100     if (video_file->min_fps_render != -1)
1101       video_file->min_fps_render /= num_concurrent_decoders;
1102     if (video_file->min_fps_no_render != -1)
1103       video_file->min_fps_no_render /= num_concurrent_decoders;
1104   }
1105 }
1106
1107 void VideoDecodeAcceleratorTest::InitializeRenderingHelper(
1108     const RenderingHelperParams& helper_params) {
1109   base::WaitableEvent done(false, false);
1110   rendering_loop_proxy_->PostTask(
1111       FROM_HERE,
1112       base::Bind(&RenderingHelper::Initialize,
1113                  base::Unretained(&rendering_helper_),
1114                  helper_params,
1115                  &done));
1116   done.Wait();
1117 }
1118
1119 void VideoDecodeAcceleratorTest::CreateAndStartDecoder(
1120     GLRenderingVDAClient* client,
1121     ClientStateNotification<ClientState>* note) {
1122   rendering_loop_proxy_->PostTask(
1123       FROM_HERE,
1124       base::Bind(&GLRenderingVDAClient::CreateAndStartDecoder,
1125                  base::Unretained(client)));
1126   ASSERT_EQ(note->Wait(), CS_DECODER_SET);
1127 }
1128
1129 void VideoDecodeAcceleratorTest::WaitUntilDecodeFinish(
1130     ClientStateNotification<ClientState>* note) {
1131   for (int i = 0; i < CS_MAX; i++) {
1132     if (note->Wait() == CS_DESTROYED)
1133       break;
1134   }
1135 }
1136
1137 void VideoDecodeAcceleratorTest::WaitUntilIdle() {
1138   base::WaitableEvent done(false, false);
1139   rendering_loop_proxy_->PostTask(
1140       FROM_HERE,
1141       base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
1142   done.Wait();
1143 }
1144
1145 void VideoDecodeAcceleratorTest::OutputLogFile(
1146     const base::FilePath::CharType* log_path,
1147     const std::string& content) {
1148   base::PlatformFile file = base::CreatePlatformFile(
1149       base::FilePath(log_path),
1150       base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE,
1151       NULL,
1152       NULL);
1153   base::WritePlatformFileAtCurrentPos(file, content.data(), content.length());
1154   base::ClosePlatformFile(file);
1155 }
1156
1157 // Test parameters:
1158 // - Number of concurrent decoders.
1159 // - Number of concurrent in-flight Decode() calls per decoder.
1160 // - Number of play-throughs.
1161 // - reset_after_frame_num: see GLRenderingVDAClient ctor.
1162 // - delete_decoder_phase: see GLRenderingVDAClient ctor.
1163 // - whether to test slow rendering by delaying ReusePictureBuffer().
1164 // - whether the video frames are rendered as thumbnails.
1165 class VideoDecodeAcceleratorParamTest
1166     : public VideoDecodeAcceleratorTest,
1167       public ::testing::WithParamInterface<
1168         Tuple7<int, int, int, ResetPoint, ClientState, bool, bool> > {
1169 };
1170
1171 // Helper so that gtest failures emit a more readable version of the tuple than
1172 // its byte representation.
1173 ::std::ostream& operator<<(
1174     ::std::ostream& os,
1175     const Tuple7<int, int, int, ResetPoint, ClientState, bool, bool>& t) {
1176   return os << t.a << ", " << t.b << ", " << t.c << ", " << t.d << ", " << t.e
1177             << ", " << t.f << ", " << t.g;
1178 }
1179
1180 // Wait for |note| to report a state and if it's not |expected_state| then
1181 // assert |client| has deleted its decoder.
1182 static void AssertWaitForStateOrDeleted(
1183     ClientStateNotification<ClientState>* note,
1184     GLRenderingVDAClient* client,
1185     ClientState expected_state) {
1186   ClientState state = note->Wait();
1187   if (state == expected_state) return;
1188   ASSERT_TRUE(client->decoder_deleted())
1189       << "Decoder not deleted but Wait() returned " << state
1190       << ", instead of " << expected_state;
1191 }
1192
1193 // We assert a minimal number of concurrent decoders we expect to succeed.
1194 // Different platforms can support more concurrent decoders, so we don't assert
1195 // failure above this.
1196 enum { kMinSupportedNumConcurrentDecoders = 3 };
1197
1198 // Test the most straightforward case possible: data is decoded from a single
1199 // chunk and rendered to the screen.
1200 TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
1201   const size_t num_concurrent_decoders = GetParam().a;
1202   const size_t num_in_flight_decodes = GetParam().b;
1203   const int num_play_throughs = GetParam().c;
1204   const int reset_point = GetParam().d;
1205   const int delete_decoder_state = GetParam().e;
1206   bool test_reuse_delay = GetParam().f;
1207   const bool render_as_thumbnails = GetParam().g;
1208
1209   UpdateTestVideoFileParams(
1210       num_concurrent_decoders, reset_point, &test_video_files_);
1211
1212   // Suppress GL rendering for all tests when the "--disable_rendering" is set.
1213   const bool suppress_rendering = g_disable_rendering;
1214
1215   std::vector<ClientStateNotification<ClientState>*>
1216       notes(num_concurrent_decoders, NULL);
1217   std::vector<GLRenderingVDAClient*> clients(num_concurrent_decoders, NULL);
1218
1219   RenderingHelperParams helper_params;
1220   helper_params.num_windows = num_concurrent_decoders;
1221   helper_params.render_as_thumbnails = render_as_thumbnails;
1222   if (render_as_thumbnails) {
1223     // Only one decoder is supported with thumbnail rendering
1224     CHECK_EQ(num_concurrent_decoders, 1U);
1225     gfx::Size frame_size(test_video_files_[0]->width,
1226                          test_video_files_[0]->height);
1227     helper_params.frame_dimensions.push_back(frame_size);
1228     helper_params.window_dimensions.push_back(kThumbnailsDisplaySize);
1229     helper_params.thumbnails_page_size = kThumbnailsPageSize;
1230     helper_params.thumbnail_size = kThumbnailSize;
1231   } else {
1232     for (size_t index = 0; index < test_video_files_.size(); ++index) {
1233       gfx::Size frame_size(test_video_files_[index]->width,
1234                            test_video_files_[index]->height);
1235       helper_params.frame_dimensions.push_back(frame_size);
1236       helper_params.window_dimensions.push_back(frame_size);
1237     }
1238   }
1239   InitializeRenderingHelper(helper_params);
1240
1241   // First kick off all the decoders.
1242   for (size_t index = 0; index < num_concurrent_decoders; ++index) {
1243     TestVideoFile* video_file =
1244         test_video_files_[index % test_video_files_.size()];
1245     ClientStateNotification<ClientState>* note =
1246         new ClientStateNotification<ClientState>();
1247     notes[index] = note;
1248
1249     int delay_after_frame_num = std::numeric_limits<int>::max();
1250     if (test_reuse_delay &&
1251         kMaxFramesToDelayReuse * 2 < video_file->num_frames) {
1252       delay_after_frame_num = video_file->num_frames - kMaxFramesToDelayReuse;
1253     }
1254
1255     GLRenderingVDAClient* client =
1256         new GLRenderingVDAClient(&rendering_helper_,
1257                                  index,
1258                                  note,
1259                                  video_file->data_str,
1260                                  num_in_flight_decodes,
1261                                  num_play_throughs,
1262                                  video_file->reset_after_frame_num,
1263                                  delete_decoder_state,
1264                                  video_file->width,
1265                                  video_file->height,
1266                                  video_file->profile,
1267                                  g_rendering_fps,
1268                                  suppress_rendering,
1269                                  delay_after_frame_num,
1270                                  0);
1271     clients[index] = client;
1272
1273     CreateAndStartDecoder(client, note);
1274   }
1275   // Then wait for all the decodes to finish.
1276   // Only check performance & correctness later if we play through only once.
1277   bool skip_performance_and_correctness_checks = num_play_throughs > 1;
1278   for (size_t i = 0; i < num_concurrent_decoders; ++i) {
1279     ClientStateNotification<ClientState>* note = notes[i];
1280     ClientState state = note->Wait();
1281     if (state != CS_INITIALIZED) {
1282       skip_performance_and_correctness_checks = true;
1283       // We expect initialization to fail only when more than the supported
1284       // number of decoders is instantiated.  Assert here that something else
1285       // didn't trigger failure.
1286       ASSERT_GT(num_concurrent_decoders,
1287                 static_cast<size_t>(kMinSupportedNumConcurrentDecoders));
1288       continue;
1289     }
1290     ASSERT_EQ(state, CS_INITIALIZED);
1291     for (int n = 0; n < num_play_throughs; ++n) {
1292       // For play-throughs other than the first, we expect initialization to
1293       // succeed unconditionally.
1294       if (n > 0) {
1295         ASSERT_NO_FATAL_FAILURE(
1296             AssertWaitForStateOrDeleted(note, clients[i], CS_INITIALIZED));
1297       }
1298       // InitializeDone kicks off decoding inside the client, so we just need to
1299       // wait for Flush.
1300       ASSERT_NO_FATAL_FAILURE(
1301           AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHING));
1302       ASSERT_NO_FATAL_FAILURE(
1303           AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED));
1304       // FlushDone requests Reset().
1305       ASSERT_NO_FATAL_FAILURE(
1306           AssertWaitForStateOrDeleted(note, clients[i], CS_RESETTING));
1307     }
1308     ASSERT_NO_FATAL_FAILURE(
1309         AssertWaitForStateOrDeleted(note, clients[i], CS_RESET));
1310     // ResetDone requests Destroy().
1311     ASSERT_NO_FATAL_FAILURE(
1312         AssertWaitForStateOrDeleted(note, clients[i], CS_DESTROYED));
1313   }
1314   // Finally assert that decoding went as expected.
1315   for (size_t i = 0; i < num_concurrent_decoders &&
1316            !skip_performance_and_correctness_checks; ++i) {
1317     // We can only make performance/correctness assertions if the decoder was
1318     // allowed to finish.
1319     if (delete_decoder_state < CS_FLUSHED)
1320       continue;
1321     GLRenderingVDAClient* client = clients[i];
1322     TestVideoFile* video_file = test_video_files_[i % test_video_files_.size()];
1323     if (video_file->num_frames > 0) {
1324       // Expect the decoded frames may be more than the video frames as frames
1325       // could still be returned until resetting done.
1326       if (video_file->reset_after_frame_num > 0)
1327         EXPECT_GE(client->num_decoded_frames(), video_file->num_frames);
1328       else
1329         EXPECT_EQ(client->num_decoded_frames(), video_file->num_frames);
1330     }
1331     if (reset_point == END_OF_STREAM_RESET) {
1332       EXPECT_EQ(video_file->num_fragments, client->num_skipped_fragments() +
1333                 client->num_queued_fragments());
1334       EXPECT_EQ(client->num_done_bitstream_buffers(),
1335                 client->num_queued_fragments());
1336     }
1337     VLOG(0) << "Decoder " << i << " fps: " << client->frames_per_second();
1338     if (!render_as_thumbnails) {
1339       int min_fps = suppress_rendering ?
1340           video_file->min_fps_no_render : video_file->min_fps_render;
1341       if (min_fps > 0 && !test_reuse_delay)
1342         EXPECT_GT(client->frames_per_second(), min_fps);
1343     }
1344   }
1345
1346   if (render_as_thumbnails) {
1347     std::vector<unsigned char> rgb;
1348     bool alpha_solid;
1349     base::WaitableEvent done(false, false);
1350     rendering_loop_proxy_->PostTask(
1351       FROM_HERE,
1352       base::Bind(&RenderingHelper::GetThumbnailsAsRGB,
1353                  base::Unretained(&rendering_helper_),
1354                  &rgb, &alpha_solid, &done));
1355     done.Wait();
1356
1357     std::vector<std::string> golden_md5s;
1358     std::string md5_string = base::MD5String(
1359         base::StringPiece(reinterpret_cast<char*>(&rgb[0]), rgb.size()));
1360     ReadGoldenThumbnailMD5s(test_video_files_[0], &golden_md5s);
1361     std::vector<std::string>::iterator match =
1362         find(golden_md5s.begin(), golden_md5s.end(), md5_string);
1363     if (match == golden_md5s.end()) {
1364       // Convert raw RGB into PNG for export.
1365       std::vector<unsigned char> png;
1366       gfx::PNGCodec::Encode(&rgb[0],
1367                             gfx::PNGCodec::FORMAT_RGB,
1368                             kThumbnailsPageSize,
1369                             kThumbnailsPageSize.width() * 3,
1370                             true,
1371                             std::vector<gfx::PNGCodec::Comment>(),
1372                             &png);
1373
1374       LOG(ERROR) << "Unknown thumbnails MD5: " << md5_string;
1375
1376       base::FilePath filepath(test_video_files_[0]->file_name);
1377       filepath = filepath.AddExtension(FILE_PATH_LITERAL(".bad_thumbnails"));
1378       filepath = filepath.AddExtension(FILE_PATH_LITERAL(".png"));
1379       int num_bytes = file_util::WriteFile(filepath,
1380                                            reinterpret_cast<char*>(&png[0]),
1381                                            png.size());
1382       ASSERT_EQ(num_bytes, static_cast<int>(png.size()));
1383     }
1384     ASSERT_NE(match, golden_md5s.end());
1385     EXPECT_EQ(alpha_solid, true) << "RGBA frame had incorrect alpha";
1386   }
1387
1388   // Output the frame delivery time to file
1389   // We can only make performance/correctness assertions if the decoder was
1390   // allowed to finish.
1391   if (g_output_log != NULL && delete_decoder_state >= CS_FLUSHED) {
1392     base::PlatformFile output_file = base::CreatePlatformFile(
1393         base::FilePath(g_output_log),
1394         base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE,
1395         NULL,
1396         NULL);
1397     for (size_t i = 0; i < num_concurrent_decoders; ++i) {
1398       clients[i]->OutputFrameDeliveryTimes(output_file);
1399     }
1400     base::ClosePlatformFile(output_file);
1401   }
1402
1403   rendering_loop_proxy_->PostTask(
1404       FROM_HERE,
1405       base::Bind(&STLDeleteElements<std::vector<GLRenderingVDAClient*> >,
1406                  &clients));
1407   rendering_loop_proxy_->PostTask(
1408       FROM_HERE,
1409       base::Bind(&STLDeleteElements<
1410                       std::vector<ClientStateNotification<ClientState>*> >,
1411                  &notes));
1412   WaitUntilIdle();
1413 };
1414
1415 // Test that replay after EOS works fine.
1416 INSTANTIATE_TEST_CASE_P(
1417     ReplayAfterEOS, VideoDecodeAcceleratorParamTest,
1418     ::testing::Values(
1419         MakeTuple(1, 1, 4, END_OF_STREAM_RESET, CS_RESET, false, false)));
1420
1421 // Test that Reset() before the first Decode() works fine.
1422 INSTANTIATE_TEST_CASE_P(
1423     ResetBeforeDecode, VideoDecodeAcceleratorParamTest,
1424     ::testing::Values(
1425         MakeTuple(1, 1, 1, START_OF_STREAM_RESET, CS_RESET, false, false)));
1426
1427 // Test Reset() immediately after Decode() containing config info.
1428 INSTANTIATE_TEST_CASE_P(
1429     ResetAfterFirstConfigInfo, VideoDecodeAcceleratorParamTest,
1430     ::testing::Values(
1431         MakeTuple(
1432             1, 1, 1, RESET_AFTER_FIRST_CONFIG_INFO, CS_RESET, false, false)));
1433
1434 // Test that Reset() mid-stream works fine and doesn't affect decoding even when
1435 // Decode() calls are made during the reset.
1436 INSTANTIATE_TEST_CASE_P(
1437     MidStreamReset, VideoDecodeAcceleratorParamTest,
1438     ::testing::Values(
1439         MakeTuple(1, 1, 1, MID_STREAM_RESET, CS_RESET, false, false)));
1440
1441 INSTANTIATE_TEST_CASE_P(
1442     SlowRendering, VideoDecodeAcceleratorParamTest,
1443     ::testing::Values(
1444         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, true, false)));
1445
1446 // Test that Destroy() mid-stream works fine (primarily this is testing that no
1447 // crashes occur).
1448 INSTANTIATE_TEST_CASE_P(
1449     TearDownTiming, VideoDecodeAcceleratorParamTest,
1450     ::testing::Values(
1451         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_DECODER_SET, false, false),
1452         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_INITIALIZED, false, false),
1453         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHING, false, false),
1454         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_FLUSHED, false, false),
1455         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESETTING, false, false),
1456         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
1457         MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
1458                   static_cast<ClientState>(-1), false, false),
1459         MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
1460                   static_cast<ClientState>(-10), false, false),
1461         MakeTuple(1, 1, 1, END_OF_STREAM_RESET,
1462                   static_cast<ClientState>(-100), false, false)));
1463
1464 // Test that decoding various variation works with multiple in-flight decodes.
1465 INSTANTIATE_TEST_CASE_P(
1466     DecodeVariations, VideoDecodeAcceleratorParamTest,
1467     ::testing::Values(
1468         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
1469         MakeTuple(1, 10, 1, END_OF_STREAM_RESET, CS_RESET, false, false),
1470         // Tests queuing.
1471         MakeTuple(1, 15, 1, END_OF_STREAM_RESET, CS_RESET, false, false)));
1472
1473 // Find out how many concurrent decoders can go before we exhaust system
1474 // resources.
1475 INSTANTIATE_TEST_CASE_P(
1476     ResourceExhaustion, VideoDecodeAcceleratorParamTest,
1477     ::testing::Values(
1478         // +0 hack below to promote enum to int.
1479         MakeTuple(kMinSupportedNumConcurrentDecoders + 0, 1, 1,
1480                   END_OF_STREAM_RESET, CS_RESET, false, false),
1481         MakeTuple(kMinSupportedNumConcurrentDecoders + 1, 1, 1,
1482                   END_OF_STREAM_RESET, CS_RESET, false, false)));
1483
1484 // Thumbnailing test
1485 INSTANTIATE_TEST_CASE_P(
1486     Thumbnail, VideoDecodeAcceleratorParamTest,
1487     ::testing::Values(
1488         MakeTuple(1, 1, 1, END_OF_STREAM_RESET, CS_RESET, false, true)));
1489
1490 // Measure the median of the decode time when VDA::Decode is called 30 times per
1491 // second.
1492 TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) {
1493   RenderingHelperParams helper_params;
1494   helper_params.num_windows = 1;
1495   helper_params.render_as_thumbnails = false;
1496   gfx::Size frame_size(test_video_files_[0]->width,
1497                        test_video_files_[0]->height);
1498   helper_params.frame_dimensions.push_back(frame_size);
1499   helper_params.window_dimensions.push_back(frame_size);
1500   InitializeRenderingHelper(helper_params);
1501
1502   ClientStateNotification<ClientState>* note =
1503       new ClientStateNotification<ClientState>();
1504   GLRenderingVDAClient* client =
1505       new GLRenderingVDAClient(&rendering_helper_,
1506                                0,
1507                                note,
1508                                test_video_files_[0]->data_str,
1509                                1,
1510                                1,
1511                                test_video_files_[0]->reset_after_frame_num,
1512                                CS_RESET,
1513                                test_video_files_[0]->width,
1514                                test_video_files_[0]->height,
1515                                test_video_files_[0]->profile,
1516                                g_rendering_fps,
1517                                true,
1518                                std::numeric_limits<int>::max(),
1519                                kWebRtcDecodeCallsPerSecond);
1520   CreateAndStartDecoder(client, note);
1521   WaitUntilDecodeFinish(note);
1522
1523   int decode_time_median = client->decode_time_median();
1524   std::string output_string =
1525       base::StringPrintf("Decode time median: %d ms", decode_time_median);
1526   VLOG(0) << output_string;
1527   ASSERT_GT(decode_time_median, 0);
1528
1529   if (g_output_log != NULL)
1530     OutputLogFile(g_output_log, output_string);
1531
1532   rendering_loop_proxy_->DeleteSoon(FROM_HERE, client);
1533   rendering_loop_proxy_->DeleteSoon(FROM_HERE, note);
1534   WaitUntilIdle();
1535 };
1536
1537 // TODO(fischman, vrk): add more tests!  In particular:
1538 // - Test life-cycle: Seek/Stop/Pause/Play for a single decoder.
1539 // - Test alternate configurations
1540 // - Test failure conditions.
1541 // - Test frame size changes mid-stream
1542
1543 }  // namespace
1544 }  // namespace content
1545
1546 int main(int argc, char **argv) {
1547   testing::InitGoogleTest(&argc, argv);  // Removes gtest-specific args.
1548   CommandLine::Init(argc, argv);
1549
1550   // Needed to enable DVLOG through --vmodule.
1551   logging::LoggingSettings settings;
1552   settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
1553   settings.dcheck_state =
1554       logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
1555   CHECK(logging::InitLogging(settings));
1556
1557   CommandLine* cmd_line = CommandLine::ForCurrentProcess();
1558   DCHECK(cmd_line);
1559
1560   CommandLine::SwitchMap switches = cmd_line->GetSwitches();
1561   for (CommandLine::SwitchMap::const_iterator it = switches.begin();
1562        it != switches.end(); ++it) {
1563     if (it->first == "test_video_data") {
1564       content::g_test_video_data = it->second.c_str();
1565       continue;
1566     }
1567     // TODO(wuchengli): remove frame_deliver_log after CrOS test get updated.
1568     // See http://crosreview.com/175426.
1569     if (it->first == "frame_delivery_log" || it->first == "output_log") {
1570       content::g_output_log = it->second.c_str();
1571       continue;
1572     }
1573     if (it->first == "rendering_fps") {
1574       // On Windows, CommandLine::StringType is wstring. We need to convert
1575       // it to std::string first
1576       std::string input(it->second.begin(), it->second.end());
1577       CHECK(base::StringToDouble(input, &content::g_rendering_fps));
1578       continue;
1579     }
1580     if (it->first == "disable_rendering") {
1581       content::g_disable_rendering = true;
1582       continue;
1583     }
1584     if (it->first == "v" || it->first == "vmodule")
1585       continue;
1586     LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second;
1587   }
1588
1589   base::ShadowingAtExitManager at_exit_manager;
1590
1591   return RUN_ALL_TESTS();
1592 }