summaryrefslogtreecommitdiffstats
path: root/chromium/content/common/gpu/media/video_decode_accelerator_unittest.cc
diff options
context:
space:
mode:
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.cc514
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")