Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(221)

Unified Diff: content/common/gpu/media/video_decode_accelerator_unittest.cc

Issue 19151002: Add switches: "target_fps" and "disable_rendering" to video_decode_accelerator_unittest. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address review comment Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/common/gpu/media/video_decode_accelerator_unittest.cc
diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc
index ec1ab8bbf009bdde2c4fd08229e21694374cf8a5..5d71f54140730db36ab71829a59312c3dadae568 100644
--- a/content/common/gpu/media/video_decode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc
@@ -90,6 +90,12 @@ const base::FilePath::CharType* test_video_data =
// the filename by the "--frame_delivery_log" switch.
const base::FilePath::CharType* frame_delivery_log = NULL;
+// The value is set by the switch "--rendering_fps".
+double rendering_fps = 0;
Ami GONE FROM CHROMIUM 2013/08/02 00:33:22 global vars should be prefixed with g_ to avoid co
Owen Lin 2013/08/02 05:38:19 Done.
+
+// Disable rendering, the value is set by the switch "--disable_rendering".
+bool disable_rendering = false;
+
// Magic constants for differentiating the reasons for NotifyResetDone being
// called.
enum ResetPoint {
@@ -99,7 +105,9 @@ enum ResetPoint {
const int kMaxResetAfterFrameNum = 100;
const int kMaxFramesToDelayReuse = 64;
-const int kReuseDelayMs = 1000;
+const base::TimeDelta kReuseDelay = base::TimeDelta::FromSeconds(1);
+const base::TimeDelta kFrameDelayTolerance =
+ base::TimeDelta::FromMilliseconds(1);
struct TestVideoFile {
explicit TestVideoFile(base::FilePath::StringType file_name)
@@ -220,11 +228,10 @@ enum ClientState {
CS_INITIALIZED = 2,
CS_FLUSHING = 3,
CS_FLUSHED = 4,
- CS_DONE = 5,
- CS_RESETTING = 6,
- CS_RESET = 7,
- CS_ERROR = 8,
- CS_DESTROYED = 9,
+ CS_RESETTING = 5,
+ CS_RESET = 6,
+ CS_ERROR = 7,
+ CS_DESTROYED = 8,
CS_MAX, // Must be last entry.
};
@@ -266,6 +273,159 @@ ClientState ClientStateNotification::Wait() {
return ret;
}
+// 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_ + kFrameDelayTolerance < now) {
Ami GONE FROM CHROMIUM 2013/08/02 00:33:22 Shouldn't kFrameDelayTolerance always be equal to
Owen Lin 2013/08/02 05:38:19 Good point. Thanks.
+ // 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());
Ami GONE FROM CHROMIUM 2013/08/02 00:33:22 indent is off here and elsewhere. why not give [gi
Owen Lin 2013/08/02 05:38:19 Done. I tried "git cl format" but it changed the c
+ 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 {
@@ -282,8 +442,11 @@ class GLRenderingVDAClient : public VideoDecodeAccelerator::Client {
// 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.
// After |delay_reuse_after_frame_num| frame has been delivered, the client
- // will start delaying the call to ReusePictureBuffer() for kReuseDelayMs.
+ // will start delaying the call to ReusePictureBuffer() for kReuseDelay.
GLRenderingVDAClient(RenderingHelper* rendering_helper,
int rendering_window_id,
ClientStateNotification* note,
@@ -296,6 +459,7 @@ class GLRenderingVDAClient : public VideoDecodeAccelerator::Client {
int frame_width,
int frame_height,
int profile,
+ double rendering_fps,
bool suppress_rendering,
int delay_reuse_after_frame_num);
virtual ~GLRenderingVDAClient();
@@ -317,6 +481,8 @@ class GLRenderingVDAClient : public VideoDecodeAccelerator::Client {
void OutputFrameDeliveryTimes(base::PlatformFile output);
+ void NotifyFrameDropped(int32 picture_buffer_id);
+
// Simple getters for inspecting the state of the Client.
int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; }
int num_skipped_fragments() { return num_skipped_fragments_; }
@@ -373,6 +539,9 @@ class GLRenderingVDAClient : public VideoDecodeAccelerator::Client {
bool suppress_rendering_;
std::vector<base::TimeTicks> frame_delivery_times_;
int delay_reuse_after_frame_num_;
+ scoped_ptr<ThrottlingVDAClient> throttling_client_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient);
};
GLRenderingVDAClient::GLRenderingVDAClient(
@@ -388,6 +557,7 @@ GLRenderingVDAClient::GLRenderingVDAClient(
int frame_width,
int frame_height,
int profile,
+ double rendering_fps,
bool suppress_rendering,
int delay_reuse_after_frame_num)
: rendering_helper_(rendering_helper),
@@ -409,6 +579,13 @@ GLRenderingVDAClient::GLRenderingVDAClient(
CHECK_GT(num_fragments_per_decode, 0);
CHECK_GT(num_in_flight_decodes, 0);
CHECK_GT(num_play_throughs, 0);
+ CHECK_GE(rendering_fps, 0);
+ if (rendering_fps > 0)
+ throttling_client_.reset(new ThrottlingVDAClient(
+ this,
+ rendering_fps,
+ base::Bind(&GLRenderingVDAClient::NotifyFrameDropped,
+ base::Unretained(this))));
}
GLRenderingVDAClient::~GLRenderingVDAClient() {
@@ -423,21 +600,25 @@ static bool DoNothingReturnTrue() { return true; }
void GLRenderingVDAClient::CreateDecoder() {
CHECK(decoder_deleted());
CHECK(!decoder_.get());
+
+ VideoDecodeAccelerator::Client* client = this;
+ if (throttling_client_)
+ client = throttling_client_.get();
#if defined(OS_WIN)
decoder_.reset(new DXVAVideoDecodeAccelerator(
- this, base::Bind(&DoNothingReturnTrue)));
+ client, base::Bind(&DoNothingReturnTrue)));
#elif defined(OS_CHROMEOS)
#if defined(ARCH_CPU_ARMEL)
decoder_.reset(
new ExynosVideoDecodeAccelerator(
static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()),
static_cast<EGLContext>(rendering_helper_->GetGLContext()),
- this, base::Bind(&DoNothingReturnTrue)));
+ client, base::Bind(&DoNothingReturnTrue)));
#elif defined(ARCH_CPU_X86_FAMILY)
decoder_.reset(new VaapiVideoDecodeAccelerator(
static_cast<Display*>(rendering_helper_->GetGLDisplay()),
static_cast<GLXContext>(rendering_helper_->GetGLContext()),
- this, base::Bind(&DoNothingReturnTrue)));
+ client, base::Bind(&DoNothingReturnTrue)));
#endif // ARCH_CPU_ARMEL
#endif // OS_WIN
CHECK(decoder_.get());
@@ -492,6 +673,7 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
if (decoder_deleted())
return;
+
frame_delivery_times_.push_back(base::TimeTicks::Now());
CHECK_LE(picture.bitstream_buffer_id(), next_bitstream_buffer_id_);
@@ -519,7 +701,7 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
base::MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind(
&VideoDecodeAccelerator::ReusePictureBuffer,
decoder_->AsWeakPtr(), picture.picture_buffer_id()),
- base::TimeDelta::FromMilliseconds(kReuseDelayMs));
+ kReuseDelay);
} else {
decoder_->ReusePictureBuffer(picture.picture_buffer_id());
}
@@ -595,6 +777,10 @@ void GLRenderingVDAClient::OutputFrameDeliveryTimes(base::PlatformFile output) {
}
}
+void GLRenderingVDAClient::NotifyFrameDropped(int32 picture_buffer_id) {
+ decoder_->ReusePictureBuffer(picture_buffer_id);
+}
+
static bool LookingAtNAL(const std::string& encoded, size_t pos) {
return encoded[pos] == 0 && encoded[pos + 1] == 0 &&
encoded[pos + 2] == 0 && encoded[pos + 3] == 1;
@@ -784,9 +970,6 @@ enum { kMinSupportedNumConcurrentDecoders = 3 };
// Test the most straightforward case possible: data is decoded from a single
// chunk and rendered to the screen.
TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) {
- // Can be useful for debugging VLOGs from OVDA.
- // logging::SetMinLogLevel(-1);
-
// Required for Thread to work. Not used otherwise.
base::ShadowingAtExitManager at_exit_manager;
@@ -803,10 +986,11 @@ TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) {
ParseAndReadTestVideoData(test_video_data, num_concurrent_decoders,
reset_point, &test_video_files);
- // Suppress GL rendering when we are logging the frame delivery time and a
- // few other tests, to cut down overall test runtime.
+ // Suppress GL rendering for all tests when the "--disable_rendering" is set.
+ // Otherwise, suppress rendering in all but a few tests, to cut down overall
+ // test runtime.
const bool suppress_rendering = num_fragments_per_decode > 1 ||
- frame_delivery_log != NULL;
+ content::disable_rendering;
std::vector<ClientStateNotification*> notes(num_concurrent_decoders, NULL);
std::vector<GLRenderingVDAClient*> clients(num_concurrent_decoders, NULL);
@@ -871,7 +1055,7 @@ TEST_P(VideoDecodeAcceleratorTest, TestSimpleDecode) {
num_fragments_per_decode, num_in_flight_decodes, num_play_throughs,
video_file->reset_after_frame_num, delete_decoder_state,
video_file->width, video_file->height, video_file->profile,
- suppress_rendering, delay_after_frame_num);
+ rendering_fps, suppress_rendering, delay_after_frame_num);
clients[index] = client;
rendering_thread.message_loop()->PostTask(
@@ -1140,6 +1324,14 @@ int main(int argc, char **argv) {
content::frame_delivery_log = it->second.c_str();
continue;
}
+ if (it->first == "rendering_fps") {
+ CHECK(base::StringToDouble(it->second, &content::rendering_fps));
+ continue;
+ }
+ if (it->first == "disable_rendering") {
+ content::disable_rendering = true;
+ continue;
+ }
if (it->first == "v" || it->first == "vmodule")
continue;
LOG(FATAL) << "Unexpected switch: " << it->first << ":" << it->second;
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698