diff options
Diffstat (limited to 'chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc')
-rw-r--r-- | chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc | 514 |
1 files changed, 200 insertions, 314 deletions
diff --git a/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc b/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc index f1cb85e4c65..58e0e99a980 100644 --- a/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc +++ b/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc @@ -31,10 +31,10 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/file_util.h" +#include "base/files/file.h" #include "base/format_macros.h" #include "base/md5.h" #include "base/message_loop/message_loop_proxy.h" -#include "base/platform_file.h" #include "base/process/process.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" @@ -46,21 +46,23 @@ #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" -#include "content/common/gpu/media/h264_parser.h" #include "content/common/gpu/media/rendering_helper.h" #include "content/common/gpu/media/video_accelerator_unittest_helpers.h" #include "content/public/common/content_switches.h" +#include "media/filters/h264_parser.h" #include "ui/gfx/codec/png_codec.h" #if defined(OS_WIN) #include "content/common/gpu/media/dxva_video_decode_accelerator.h" -#elif defined(OS_CHROMEOS) -#if defined(ARCH_CPU_ARMEL) -#include "content/common/gpu/media/exynos_video_decode_accelerator.h" -#elif defined(ARCH_CPU_X86_FAMILY) +#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) +#include "content/common/gpu/media/v4l2_video_decode_accelerator.h" +#include "content/common/gpu/media/v4l2_video_device.h" +#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" #include "content/common/gpu/media/vaapi_wrapper.h" -#endif // ARCH_CPU_ARMEL +#if defined(USE_X11) +#include "ui/gl/gl_implementation.h" +#endif // USE_X11 #else #error The VideoAccelerator tests are not supported on this platform. #endif // OS_WIN @@ -97,10 +99,7 @@ const base::FilePath::CharType* g_test_video_data = const base::FilePath::CharType* g_output_log = NULL; // The value is set by the switch "--rendering_fps". -double g_rendering_fps = 0; - -// Disable rendering, the value is set by the switch "--disable_rendering". -bool g_disable_rendering = false; +double g_rendering_fps = 60; // Magic constants for differentiating the reasons for NotifyResetDone being // called. @@ -143,10 +142,6 @@ struct TestVideoFile { std::string data_str; }; -// Presumed minimal display size. -// We subtract one pixel from the width because some ARM chromebooks do not -// support two fullscreen app running at the same time. See crbug.com/270064. -const gfx::Size kThumbnailsDisplaySize(1366 - 1, 768); const gfx::Size kThumbnailsPageSize(1600, 1200); const gfx::Size kThumbnailSize(160, 120); const int kMD5StringLength = 32; @@ -194,161 +189,11 @@ enum ClientState { CS_MAX, // Must be last entry. }; -// A wrapper client that throttles the PictureReady callbacks to a given rate. -// It may drops or queues frame to deliver them on time. -class ThrottlingVDAClient : public VideoDecodeAccelerator::Client, - public base::SupportsWeakPtr<ThrottlingVDAClient> { - public: - // Callback invoked whan the picture is dropped and should be reused for - // the decoder again. - typedef base::Callback<void(int32 picture_buffer_id)> ReusePictureCB; - - ThrottlingVDAClient(VideoDecodeAccelerator::Client* client, - double fps, - ReusePictureCB reuse_picture_cb); - virtual ~ThrottlingVDAClient(); - - // VideoDecodeAccelerator::Client implementation - virtual void ProvidePictureBuffers(uint32 requested_num_of_buffers, - const gfx::Size& dimensions, - uint32 texture_target) OVERRIDE; - virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; - virtual void PictureReady(const media::Picture& picture) OVERRIDE; - virtual void NotifyInitializeDone() OVERRIDE; - virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; - virtual void NotifyFlushDone() OVERRIDE; - virtual void NotifyResetDone() OVERRIDE; - virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; - - int num_decoded_frames() { return num_decoded_frames_; } - - private: - - void CallClientPictureReady(int version); - - VideoDecodeAccelerator::Client* client_; - ReusePictureCB reuse_picture_cb_; - base::TimeTicks next_frame_delivered_time_; - base::TimeDelta frame_duration_; - - int num_decoded_frames_; - int stream_version_; - std::deque<media::Picture> pending_pictures_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(ThrottlingVDAClient); -}; - -ThrottlingVDAClient::ThrottlingVDAClient(VideoDecodeAccelerator::Client* client, - double fps, - ReusePictureCB reuse_picture_cb) - : client_(client), - reuse_picture_cb_(reuse_picture_cb), - num_decoded_frames_(0), - stream_version_(0) { - CHECK(client_); - CHECK_GT(fps, 0); - frame_duration_ = base::TimeDelta::FromSeconds(1) / fps; -} - -ThrottlingVDAClient::~ThrottlingVDAClient() {} - -void ThrottlingVDAClient::ProvidePictureBuffers(uint32 requested_num_of_buffers, - const gfx::Size& dimensions, - uint32 texture_target) { - client_->ProvidePictureBuffers( - requested_num_of_buffers, dimensions, texture_target); -} - -void ThrottlingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) { - client_->DismissPictureBuffer(picture_buffer_id); -} - -void ThrottlingVDAClient::PictureReady(const media::Picture& picture) { - ++num_decoded_frames_; - - if (pending_pictures_.empty()) { - base::TimeDelta delay = - next_frame_delivered_time_.is_null() - ? base::TimeDelta() - : next_frame_delivered_time_ - base::TimeTicks::Now(); - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&ThrottlingVDAClient::CallClientPictureReady, - AsWeakPtr(), - stream_version_), - delay); - } - pending_pictures_.push_back(picture); -} - -void ThrottlingVDAClient::CallClientPictureReady(int version) { - // Just return if we have reset the decoder - if (version != stream_version_) - return; - - base::TimeTicks now = base::TimeTicks::Now(); - - if (next_frame_delivered_time_.is_null()) - next_frame_delivered_time_ = now; - - if (next_frame_delivered_time_ + frame_duration_ < now) { - // Too late, drop the frame - reuse_picture_cb_.Run(pending_pictures_.front().picture_buffer_id()); - } else { - client_->PictureReady(pending_pictures_.front()); - } - - pending_pictures_.pop_front(); - next_frame_delivered_time_ += frame_duration_; - if (!pending_pictures_.empty()) { - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&ThrottlingVDAClient::CallClientPictureReady, - AsWeakPtr(), - stream_version_), - next_frame_delivered_time_ - base::TimeTicks::Now()); - } -} - -void ThrottlingVDAClient::NotifyInitializeDone() { - client_->NotifyInitializeDone(); -} - -void ThrottlingVDAClient::NotifyEndOfBitstreamBuffer( - int32 bitstream_buffer_id) { - client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id); -} - -void ThrottlingVDAClient::NotifyFlushDone() { - if (!pending_pictures_.empty()) { - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&ThrottlingVDAClient::NotifyFlushDone, - base::Unretained(this)), - next_frame_delivered_time_ - base::TimeTicks::Now()); - return; - } - client_->NotifyFlushDone(); -} - -void ThrottlingVDAClient::NotifyResetDone() { - ++stream_version_; - while (!pending_pictures_.empty()) { - reuse_picture_cb_.Run(pending_pictures_.front().picture_buffer_id()); - pending_pictures_.pop_front(); - } - next_frame_delivered_time_ = base::TimeTicks(); - client_->NotifyResetDone(); -} - -void ThrottlingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { - client_->NotifyError(error); -} - // Client that can accept callbacks from a VideoDecodeAccelerator and is used by // the TESTs below. class GLRenderingVDAClient : public VideoDecodeAccelerator::Client, + public RenderingHelper::Client, public base::SupportsWeakPtr<GLRenderingVDAClient> { public: // Doesn't take ownership of |rendering_helper| or |note|, which must outlive @@ -362,15 +207,12 @@ class GLRenderingVDAClient // calls have been made, N>=0 means interpret as ClientState. // Both |reset_after_frame_num| & |delete_decoder_state| apply only to the // last play-through (governed by |num_play_throughs|). - // |rendering_fps| indicates the target rendering fps. 0 means no target fps - // and it would render as fast as possible. - // |suppress_rendering| indicates GL rendering is suppressed or not. + // |suppress_rendering| indicates GL rendering is supressed or not. // After |delay_reuse_after_frame_num| frame has been delivered, the client // will start delaying the call to ReusePictureBuffer() for kReuseDelay. // |decode_calls_per_second| is the number of VDA::Decode calls per second. // If |decode_calls_per_second| > 0, |num_in_flight_decodes| must be 1. GLRenderingVDAClient(RenderingHelper* rendering_helper, - int rendering_window_id, ClientStateNotification<ClientState>* note, const std::string& encoded_data, int num_in_flight_decodes, @@ -380,10 +222,10 @@ class GLRenderingVDAClient int frame_width, int frame_height, media::VideoCodecProfile profile, - double rendering_fps, bool suppress_rendering, int delay_reuse_after_frame_num, - int decode_calls_per_second); + int decode_calls_per_second, + bool render_as_thumbnails); virtual ~GLRenderingVDAClient(); void CreateAndStartDecoder(); @@ -395,13 +237,16 @@ class GLRenderingVDAClient virtual void DismissPictureBuffer(int32 picture_buffer_id) OVERRIDE; virtual void PictureReady(const media::Picture& picture) OVERRIDE; // Simple state changes. - virtual void NotifyInitializeDone() OVERRIDE; virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; virtual void NotifyFlushDone() OVERRIDE; virtual void NotifyResetDone() OVERRIDE; virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE; - void OutputFrameDeliveryTimes(base::PlatformFile output); + // RenderingHelper::Client implementation. + virtual void RenderContent(RenderingHelper*) OVERRIDE; + virtual const gfx::Size& GetWindowSize() OVERRIDE; + + void OutputFrameDeliveryTimes(base::File* output); void NotifyFrameDropped(int32 picture_buffer_id); @@ -409,16 +254,18 @@ class GLRenderingVDAClient int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; } int num_skipped_fragments() { return num_skipped_fragments_; } int num_queued_fragments() { return num_queued_fragments_; } - int num_decoded_frames(); + int num_decoded_frames() { return num_decoded_frames_; } double frames_per_second(); - // Return the median of the decode time in milliseconds. - int decode_time_median(); + // Return the median of the decode time of all decoded frames. + base::TimeDelta decode_time_median(); bool decoder_deleted() { return !decoder_.get(); } private: typedef std::map<int, media::PictureBuffer*> PictureBufferById; void SetState(ClientState new_state); + void FinishInitialization(); + void ReturnPicture(int32 picture_buffer_id); // Delete the associated decoder helper. void DeleteDecoder(); @@ -439,7 +286,7 @@ class GLRenderingVDAClient void DecodeNextFragment(); RenderingHelper* rendering_helper_; - int rendering_window_id_; + gfx::Size frame_size_; std::string encoded_data_; const int num_in_flight_decodes_; int outstanding_decodes_; @@ -447,6 +294,8 @@ class GLRenderingVDAClient int next_bitstream_buffer_id_; ClientStateNotification<ClientState>* note_; scoped_ptr<VideoDecodeAccelerator> decoder_; + scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator> > + weak_decoder_factory_; std::set<int> outstanding_texture_ids_; int remaining_play_throughs_; int reset_after_frame_num_; @@ -463,20 +312,21 @@ class GLRenderingVDAClient bool suppress_rendering_; std::vector<base::TimeTicks> frame_delivery_times_; int delay_reuse_after_frame_num_; - scoped_ptr<ThrottlingVDAClient> throttling_client_; // A map from bitstream buffer id to the decode start time of the buffer. std::map<int, base::TimeTicks> decode_start_time_; // The decode time of all decoded frames. std::vector<base::TimeDelta> decode_time_; // The number of VDA::Decode calls per second. This is to simulate webrtc. int decode_calls_per_second_; + bool render_as_thumbnails_; + bool pending_picture_updated_; + std::deque<int32> pending_picture_buffer_ids_; DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient); }; GLRenderingVDAClient::GLRenderingVDAClient( RenderingHelper* rendering_helper, - int rendering_window_id, ClientStateNotification<ClientState>* note, const std::string& encoded_data, int num_in_flight_decodes, @@ -486,12 +336,12 @@ GLRenderingVDAClient::GLRenderingVDAClient( int frame_width, int frame_height, media::VideoCodecProfile profile, - double rendering_fps, bool suppress_rendering, int delay_reuse_after_frame_num, - int decode_calls_per_second) + int decode_calls_per_second, + bool render_as_thumbnails) : rendering_helper_(rendering_helper), - rendering_window_id_(rendering_window_id), + frame_size_(frame_width, frame_height), encoded_data_(encoded_data), num_in_flight_decodes_(num_in_flight_decodes), outstanding_decodes_(0), @@ -506,23 +356,22 @@ GLRenderingVDAClient::GLRenderingVDAClient( num_queued_fragments_(0), num_decoded_frames_(0), num_done_bitstream_buffers_(0), - profile_(profile), texture_target_(0), suppress_rendering_(suppress_rendering), delay_reuse_after_frame_num_(delay_reuse_after_frame_num), - decode_calls_per_second_(decode_calls_per_second) { + decode_calls_per_second_(decode_calls_per_second), + render_as_thumbnails_(render_as_thumbnails), + pending_picture_updated_(true) { CHECK_GT(num_in_flight_decodes, 0); CHECK_GT(num_play_throughs, 0); - CHECK_GE(rendering_fps, 0); // |num_in_flight_decodes_| is unsupported if |decode_calls_per_second_| > 0. if (decode_calls_per_second_ > 0) CHECK_EQ(1, num_in_flight_decodes_); - if (rendering_fps > 0) - throttling_client_.reset(new ThrottlingVDAClient( - this, - rendering_fps, - base::Bind(&GLRenderingVDAClient::NotifyFrameDropped, - base::Unretained(this)))); + + // Default to H264 baseline if no profile provided. + profile_ = (profile != media::VIDEO_CODEC_PROFILE_UNKNOWN + ? profile + : media::H264PROFILE_BASELINE); } GLRenderingVDAClient::~GLRenderingVDAClient() { @@ -540,39 +389,39 @@ void GLRenderingVDAClient::CreateAndStartDecoder() { VideoDecodeAccelerator::Client* client = this; base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr(); - if (throttling_client_) { - client = throttling_client_.get(); - weak_client = throttling_client_->AsWeakPtr(); - } #if defined(OS_WIN) decoder_.reset( - new DXVAVideoDecodeAccelerator(client, base::Bind(&DoNothingReturnTrue))); -#elif defined(OS_CHROMEOS) -#if defined(ARCH_CPU_ARMEL) - decoder_.reset(new ExynosVideoDecodeAccelerator( + new DXVAVideoDecodeAccelerator(base::Bind(&DoNothingReturnTrue))); +#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) + + scoped_ptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); + if (!device.get()) { + NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); + return; + } + decoder_.reset(new V4L2VideoDecodeAccelerator( static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), static_cast<EGLContext>(rendering_helper_->GetGLContext()), - client, weak_client, base::Bind(&DoNothingReturnTrue), + device.Pass(), base::MessageLoopProxy::current())); -#elif defined(ARCH_CPU_X86_FAMILY) +#elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + CHECK_EQ(gfx::kGLImplementationDesktopGL, gfx::GetGLImplementation()) + << "Hardware video decode does not work with OSMesa"; decoder_.reset(new VaapiVideoDecodeAccelerator( static_cast<Display*>(rendering_helper_->GetGLDisplay()), - static_cast<GLXContext>(rendering_helper_->GetGLContext()), - client, base::Bind(&DoNothingReturnTrue))); -#endif // ARCH_CPU_ARMEL #endif // OS_WIN CHECK(decoder_.get()); + weak_decoder_factory_.reset( + new base::WeakPtrFactory<VideoDecodeAccelerator>(decoder_.get())); SetState(CS_DECODER_SET); if (decoder_deleted()) return; - // Configure the decoder. - profile_ = (profile_ != media::VIDEO_CODEC_PROFILE_UNKNOWN ? - profile_ : media::H264PROFILE_BASELINE); - CHECK(decoder_->Initialize(profile_)); + CHECK(decoder_->Initialize(profile_, client)); + FinishInitialization(); } void GLRenderingVDAClient::ProvidePictureBuffers( @@ -589,7 +438,7 @@ void GLRenderingVDAClient::ProvidePictureBuffers( uint32 texture_id; base::WaitableEvent done(false, false); rendering_helper_->CreateTexture( - rendering_window_id_, texture_target_, &texture_id, &done); + texture_target_, &texture_id, dimensions, &done); done.Wait(); CHECK(outstanding_texture_ids_.insert(texture_id).second); media::PictureBuffer* buffer = @@ -610,6 +459,42 @@ void GLRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) { picture_buffers_by_id_.erase(it); } +void GLRenderingVDAClient::RenderContent(RenderingHelper*) { + CHECK(!render_as_thumbnails_); + + // No decoded texture for rendering yet, just skip. + if (pending_picture_buffer_ids_.size() == 0) + return; + + int32 buffer_id = pending_picture_buffer_ids_.front(); + media::PictureBuffer* picture_buffer = picture_buffers_by_id_[buffer_id]; + + CHECK(picture_buffer); + if (!pending_picture_updated_) { + // Frame dropped, just redraw the last texture. + rendering_helper_->RenderTexture(texture_target_, + picture_buffer->texture_id()); + return; + } + + base::TimeTicks now = base::TimeTicks::Now(); + frame_delivery_times_.push_back(now); + + rendering_helper_->RenderTexture(texture_target_, + picture_buffer->texture_id()); + + if (pending_picture_buffer_ids_.size() == 1) { + pending_picture_updated_ = false; + } else { + pending_picture_buffer_ids_.pop_front(); + ReturnPicture(buffer_id); + } +} + +const gfx::Size& GLRenderingVDAClient::GetWindowSize() { + return render_as_thumbnails_ ? kThumbnailsPageSize : frame_size_; +} + void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { // We shouldn't be getting pictures delivered after Reset has completed. CHECK_LT(state_, CS_RESET); @@ -618,7 +503,6 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { return; base::TimeTicks now = base::TimeTicks::Now(); - frame_delivery_times_.push_back(now); // Save the decode time of this picture. std::map<int, base::TimeTicks>::iterator it = decode_start_time_.find(picture.bitstream_buffer_id()); @@ -632,7 +516,7 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { // Mid-stream reset applies only to the last play-through per constructor // comment. if (remaining_play_throughs_ == 1 && - reset_after_frame_num_ == num_decoded_frames()) { + reset_after_frame_num_ == num_decoded_frames_) { reset_after_frame_num_ = MID_STREAM_RESET; decoder_->Reset(); // Re-start decoding from the beginning of the stream to avoid needing to @@ -640,41 +524,43 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) { encoded_data_next_pos_to_decode_ = 0; } - media::PictureBuffer* picture_buffer = - picture_buffers_by_id_[picture.picture_buffer_id()]; - CHECK(picture_buffer); - if (!suppress_rendering_) { - rendering_helper_->RenderTexture(texture_target_, - picture_buffer->texture_id()); + if (render_as_thumbnails_) { + frame_delivery_times_.push_back(now); + media::PictureBuffer* picture_buffer = + picture_buffers_by_id_[picture.picture_buffer_id()]; + CHECK(picture_buffer); + rendering_helper_->RenderThumbnail(texture_target_, + picture_buffer->texture_id()); + ReturnPicture(picture.picture_buffer_id()); + } else if (!suppress_rendering_) { + // Keep the picture for rendering. + pending_picture_buffer_ids_.push_back(picture.picture_buffer_id()); + if (pending_picture_buffer_ids_.size() > 1 && !pending_picture_updated_) { + ReturnPicture(pending_picture_buffer_ids_.front()); + pending_picture_buffer_ids_.pop_front(); + pending_picture_updated_ = true; + } + } else { + frame_delivery_times_.push_back(now); + ReturnPicture(picture.picture_buffer_id()); } +} - if (num_decoded_frames() > delay_reuse_after_frame_num_) { +void GLRenderingVDAClient::ReturnPicture(int32 picture_buffer_id) { + if (decoder_deleted()) + return; + if (num_decoded_frames_ > delay_reuse_after_frame_num_) { base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer, - decoder_->AsWeakPtr(), - picture.picture_buffer_id()), + weak_decoder_factory_->GetWeakPtr(), + picture_buffer_id), kReuseDelay); } else { - decoder_->ReusePictureBuffer(picture.picture_buffer_id()); + decoder_->ReusePictureBuffer(picture_buffer_id); } } -void GLRenderingVDAClient::NotifyInitializeDone() { - SetState(CS_INITIALIZED); - initialize_done_ticks_ = base::TimeTicks::Now(); - - if (reset_after_frame_num_ == START_OF_STREAM_RESET) { - reset_after_frame_num_ = MID_STREAM_RESET; - decoder_->Reset(); - return; - } - - for (int i = 0; i < num_in_flight_decodes_; ++i) - DecodeNextFragment(); - DCHECK_EQ(outstanding_decodes_, num_in_flight_decodes_); -} - void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer( int32 bitstream_buffer_id) { // TODO(fischman): this test currently relies on this notification to make @@ -690,6 +576,7 @@ void GLRenderingVDAClient::NotifyEndOfBitstreamBuffer( void GLRenderingVDAClient::NotifyFlushDone() { if (decoder_deleted()) return; + SetState(CS_FLUSHED); --remaining_play_throughs_; DCHECK_GE(remaining_play_throughs_, 0); @@ -703,6 +590,13 @@ void GLRenderingVDAClient::NotifyResetDone() { if (decoder_deleted()) return; + // Clear pending_pictures and reuse them. + while (!pending_picture_buffer_ids_.empty()) { + decoder_->ReusePictureBuffer(pending_picture_buffer_ids_.front()); + pending_picture_buffer_ids_.pop_front(); + } + pending_picture_updated_ = true; + if (reset_after_frame_num_ == MID_STREAM_RESET) { reset_after_frame_num_ = END_OF_STREAM_RESET; DecodeNextFragment(); @@ -716,7 +610,7 @@ void GLRenderingVDAClient::NotifyResetDone() { if (remaining_play_throughs_) { encoded_data_next_pos_to_decode_ = 0; - NotifyInitializeDone(); + FinishInitialization(); return; } @@ -729,17 +623,17 @@ void GLRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { SetState(CS_ERROR); } -void GLRenderingVDAClient::OutputFrameDeliveryTimes(base::PlatformFile output) { +void GLRenderingVDAClient::OutputFrameDeliveryTimes(base::File* output) { std::string s = base::StringPrintf("frame count: %" PRIuS "\n", frame_delivery_times_.size()); - base::WritePlatformFileAtCurrentPos(output, s.data(), s.length()); + output->WriteAtCurrentPos(s.data(), s.length()); base::TimeTicks t0 = initialize_done_ticks_; for (size_t i = 0; i < frame_delivery_times_.size(); ++i) { s = base::StringPrintf("frame %04" PRIuS ": %" PRId64 " us\n", i, (frame_delivery_times_[i] - t0).InMicroseconds()); t0 = frame_delivery_times_[i]; - base::WritePlatformFileAtCurrentPos(output, s.data(), s.length()); + output->WriteAtCurrentPos(s.data(), s.length()); } } @@ -761,10 +655,26 @@ void GLRenderingVDAClient::SetState(ClientState new_state) { } } +void GLRenderingVDAClient::FinishInitialization() { + SetState(CS_INITIALIZED); + initialize_done_ticks_ = base::TimeTicks::Now(); + + if (reset_after_frame_num_ == START_OF_STREAM_RESET) { + reset_after_frame_num_ = MID_STREAM_RESET; + decoder_->Reset(); + return; + } + + for (int i = 0; i < num_in_flight_decodes_; ++i) + DecodeNextFragment(); + DCHECK_EQ(outstanding_decodes_, num_in_flight_decodes_); +} + void GLRenderingVDAClient::DeleteDecoder() { if (decoder_deleted()) return; - decoder_.release()->Destroy(); + weak_decoder_factory_.reset(); + decoder_.reset(); STLClearObject(&encoded_data_); for (std::set<int>::iterator it = outstanding_texture_ids_.begin(); it != outstanding_texture_ids_.end(); ++it) { @@ -841,22 +751,22 @@ static bool FragmentHasConfigInfo(const uint8* data, size_t size, media::VideoCodecProfile profile) { if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) { - content::H264Parser parser; + media::H264Parser parser; parser.SetStream(data, size); - content::H264NALU nalu; - content::H264Parser::Result result = parser.AdvanceToNextNALU(&nalu); - if (result != content::H264Parser::kOk) { + media::H264NALU nalu; + media::H264Parser::Result result = parser.AdvanceToNextNALU(&nalu); + if (result != media::H264Parser::kOk) { // Let the VDA figure out there's something wrong with the stream. return false; } - return nalu.nal_unit_type == content::H264NALU::kSPS; + return nalu.nal_unit_type == media::H264NALU::kSPS; } else if (profile >= media::VP8PROFILE_MIN && profile <= media::VP8PROFILE_MAX) { return (size > 0 && !(data[0] & 0x01)); } - - CHECK(false) << "Invalid profile"; // Shouldn't happen at this point. + // Shouldn't happen at this point. + LOG(FATAL) << "Invalid profile: " << profile; return false; } @@ -929,27 +839,20 @@ void GLRenderingVDAClient::DecodeNextFragment() { } } -int GLRenderingVDAClient::num_decoded_frames() { - return throttling_client_ ? throttling_client_->num_decoded_frames() - : num_decoded_frames_; -} - double GLRenderingVDAClient::frames_per_second() { base::TimeDelta delta = frame_delivery_times_.back() - initialize_done_ticks_; - if (delta.InSecondsF() == 0) - return 0; - return num_decoded_frames() / delta.InSecondsF(); + return num_decoded_frames_ / delta.InSecondsF(); } -int GLRenderingVDAClient::decode_time_median() { +base::TimeDelta GLRenderingVDAClient::decode_time_median() { if (decode_time_.size() == 0) - return 0; + return base::TimeDelta(); std::sort(decode_time_.begin(), decode_time_.end()); int index = decode_time_.size() / 2; if (decode_time_.size() % 2 != 0) - return decode_time_[index].InMilliseconds(); + return decode_time_[index]; - return (decode_time_[index] + decode_time_[index - 1]).InMilliseconds() / 2; + return (decode_time_[index] + decode_time_[index - 1]) / 2; } class VideoDecodeAcceleratorTest : public ::testing::Test { @@ -1132,13 +1035,9 @@ void VideoDecodeAcceleratorTest::WaitUntilIdle() { void VideoDecodeAcceleratorTest::OutputLogFile( const base::FilePath::CharType* log_path, const std::string& content) { - base::PlatformFile file = base::CreatePlatformFile( - base::FilePath(log_path), - base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE, - NULL, - NULL); - base::WritePlatformFileAtCurrentPos(file, content.data(), content.length()); - base::ClosePlatformFile(file); + base::File file(base::FilePath(log_path), + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + file.WriteAtCurrentPos(content.data(), content.length()); } // Test parameters: @@ -1196,34 +1095,22 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { UpdateTestVideoFileParams( num_concurrent_decoders, reset_point, &test_video_files_); - // Suppress GL rendering for all tests when the "--disable_rendering" is set. - const bool suppress_rendering = g_disable_rendering; + // Suppress GL rendering for all tests when the "--rendering_fps" is 0. + const bool suppress_rendering = g_rendering_fps == 0; std::vector<ClientStateNotification<ClientState>*> notes(num_concurrent_decoders, NULL); std::vector<GLRenderingVDAClient*> clients(num_concurrent_decoders, NULL); RenderingHelperParams helper_params; - helper_params.num_windows = num_concurrent_decoders; + helper_params.rendering_fps = g_rendering_fps; helper_params.render_as_thumbnails = render_as_thumbnails; if (render_as_thumbnails) { // Only one decoder is supported with thumbnail rendering CHECK_EQ(num_concurrent_decoders, 1U); - gfx::Size frame_size(test_video_files_[0]->width, - test_video_files_[0]->height); - helper_params.frame_dimensions.push_back(frame_size); - helper_params.window_dimensions.push_back(kThumbnailsDisplaySize); helper_params.thumbnails_page_size = kThumbnailsPageSize; helper_params.thumbnail_size = kThumbnailSize; - } else { - for (size_t index = 0; index < test_video_files_.size(); ++index) { - gfx::Size frame_size(test_video_files_[index]->width, - test_video_files_[index]->height); - helper_params.frame_dimensions.push_back(frame_size); - helper_params.window_dimensions.push_back(frame_size); - } } - InitializeRenderingHelper(helper_params); // First kick off all the decoders. for (size_t index = 0; index < num_concurrent_decoders; ++index) { @@ -1241,7 +1128,6 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { GLRenderingVDAClient* client = new GLRenderingVDAClient(&rendering_helper_, - index, note, video_file->data_str, num_in_flight_decodes, @@ -1251,14 +1137,21 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { video_file->width, video_file->height, video_file->profile, - g_rendering_fps, suppress_rendering, delay_after_frame_num, - 0); + 0, + render_as_thumbnails); + clients[index] = client; + helper_params.clients.push_back(client->AsWeakPtr()); + } - CreateAndStartDecoder(client, note); + InitializeRenderingHelper(helper_params); + + for (size_t index = 0; index < num_concurrent_decoders; ++index) { + CreateAndStartDecoder(clients[index], notes[index]); } + // Then wait for all the decodes to finish. // Only check performance & correctness later if we play through only once. bool skip_performance_and_correctness_checks = num_play_throughs > 1; @@ -1321,7 +1214,7 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { EXPECT_EQ(client->num_done_bitstream_buffers(), client->num_queued_fragments()); } - VLOG(0) << "Decoder " << i << " fps: " << client->frames_per_second(); + LOG(INFO) << "Decoder " << i << " fps: " << client->frames_per_second(); if (!render_as_thumbnails) { int min_fps = suppress_rendering ? video_file->min_fps_no_render : video_file->min_fps_render; @@ -1363,7 +1256,7 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { base::FilePath filepath(test_video_files_[0]->file_name); filepath = filepath.AddExtension(FILE_PATH_LITERAL(".bad_thumbnails")); filepath = filepath.AddExtension(FILE_PATH_LITERAL(".png")); - int num_bytes = file_util::WriteFile(filepath, + int num_bytes = base::WriteFile(filepath, reinterpret_cast<char*>(&png[0]), png.size()); ASSERT_EQ(num_bytes, static_cast<int>(png.size())); @@ -1376,15 +1269,12 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) { // We can only make performance/correctness assertions if the decoder was // allowed to finish. if (g_output_log != NULL && delete_decoder_state >= CS_FLUSHED) { - base::PlatformFile output_file = base::CreatePlatformFile( + base::File output_file( base::FilePath(g_output_log), - base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE, - NULL, - NULL); + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); for (size_t i = 0; i < num_concurrent_decoders; ++i) { - clients[i]->OutputFrameDeliveryTimes(output_file); + clients[i]->OutputFrameDeliveryTimes(&output_file); } - base::ClosePlatformFile(output_file); } rendering_loop_proxy_->PostTask( @@ -1478,19 +1368,15 @@ INSTANTIATE_TEST_CASE_P( // second. TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) { RenderingHelperParams helper_params; - helper_params.num_windows = 1; + + // Disable rendering by setting the rendering_fps = 0. + helper_params.rendering_fps = 0; helper_params.render_as_thumbnails = false; - gfx::Size frame_size(test_video_files_[0]->width, - test_video_files_[0]->height); - helper_params.frame_dimensions.push_back(frame_size); - helper_params.window_dimensions.push_back(frame_size); - InitializeRenderingHelper(helper_params); ClientStateNotification<ClientState>* note = new ClientStateNotification<ClientState>(); GLRenderingVDAClient* client = new GLRenderingVDAClient(&rendering_helper_, - 0, note, test_video_files_[0]->data_str, 1, @@ -1500,18 +1386,20 @@ TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) { test_video_files_[0]->width, test_video_files_[0]->height, test_video_files_[0]->profile, - g_rendering_fps, true, std::numeric_limits<int>::max(), - kWebRtcDecodeCallsPerSecond); + kWebRtcDecodeCallsPerSecond, + false /* render_as_thumbnail */); + helper_params.clients.push_back(client->AsWeakPtr()); + InitializeRenderingHelper(helper_params); CreateAndStartDecoder(client, note); WaitUntilDecodeFinish(note); - int decode_time_median = client->decode_time_median(); + base::TimeDelta decode_time_median = client->decode_time_median(); std::string output_string = - base::StringPrintf("Decode time median: %d ms", decode_time_median); - VLOG(0) << output_string; - ASSERT_GT(decode_time_median, 0); + base::StringPrintf("Decode time median: %" PRId64 " us", + decode_time_median.InMicroseconds()); + LOG(INFO) << output_string; if (g_output_log != NULL) OutputLogFile(g_output_log, output_string); @@ -1537,8 +1425,6 @@ int main(int argc, char **argv) { // Needed to enable DVLOG through --vmodule. logging::LoggingSettings settings; settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; - settings.dcheck_state = - logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS; CHECK(logging::InitLogging(settings)); CommandLine* cmd_line = CommandLine::ForCurrentProcess(); @@ -1551,9 +1437,8 @@ int main(int argc, char **argv) { content::g_test_video_data = it->second.c_str(); continue; } - // TODO(wuchengli): remove frame_deliver_log after CrOS test get updated. - // See http://crosreview.com/175426. - if (it->first == "frame_delivery_log" || it->first == "output_log") { + // The output log for VDA performance test. + if (it->first == "output_log") { content::g_output_log = it->second.c_str(); continue; } @@ -1564,8 +1449,9 @@ int main(int argc, char **argv) { CHECK(base::StringToDouble(input, &content::g_rendering_fps)); continue; } + // TODO(owenlin): Remove this flag once it is not used in autotest. if (it->first == "disable_rendering") { - content::g_disable_rendering = true; + content::g_rendering_fps = 0; continue; } if (it->first == "v" || it->first == "vmodule") |