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

Unified Diff: media/base/android/media_source_player_unittest.cc

Issue 51613002: Abort MSP::OnPrefetchDone() if just after MSP::Release(). Let seek and config change survive. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove an extra blank line Created 7 years, 2 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
Index: media/base/android/media_source_player_unittest.cc
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index e329ac6eee6dc529fc3f4f6f46c40146036f6f21..72288b6f202138491eba54d9c49feb6b00cbbb9c 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -5,12 +5,14 @@
#include <string>
#include "base/basictypes.h"
+#include "base/callback_helpers.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/stringprintf.h"
#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_drm_bridge.h"
#include "media/base/android/media_player_manager.h"
#include "media/base/android/media_source_player.h"
+#include "media/base/bind_to_loop.h"
#include "media/base/decoder_buffer.h"
#include "media/base/test_data_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -80,9 +82,20 @@ class MockMediaPlayerManager : public MediaPlayerManager {
const std::string& session_id,
const std::vector<uint8>& message,
const std::string& destination_url) OVERRIDE {}
+ virtual void OnMediaDecoderCallback() OVERRIDE {
+ if (media_decoder_test_cb_.is_null())
+ return;
+ base::ResetAndReturn(&media_decoder_test_cb_).Run();
+ }
+
+ // Hook the next OnMediaDecoderCallback() to run the supplied Closure.
+ void HookNextMediaDecoderCallback(const base::Closure& decode_cb) {
+ media_decoder_test_cb_ = decode_cb;
+ }
private:
base::MessageLoop* message_loop_;
+ base::Closure media_decoder_test_cb_;
DISALLOW_COPY_AND_ASSIGN(MockMediaPlayerManager);
};
@@ -142,6 +155,7 @@ class MediaSourcePlayerTest : public testing::Test {
: manager_(&message_loop_),
demuxer_(new MockDemuxerAndroid(&message_loop_)),
player_(0, &manager_, scoped_ptr<DemuxerAndroid>(demuxer_)),
+ decoder_callback_hook_executed_(false),
surface_texture_a_is_next_(true) {}
virtual ~MediaSourcePlayerTest() {}
@@ -167,6 +181,41 @@ class MediaSourcePlayerTest : public testing::Test {
return player_.preroll_timestamp_;
}
+ // Check if the player is pending a surface change event.
+ bool IsPendingSurfaceChange() {
+ return player_.IsEventPending(player_.SURFACE_CHANGE_EVENT_PENDING);
+ }
+
+ // Check if the player is pending a prefetch request event.
+ bool IsPendingPrefetchRequest() {
+ return player_.IsEventPending(player_.PREFETCH_REQUEST_EVENT_PENDING);
+ }
+
+ // Check if the player is pending a prefetch done event.
+ bool IsPendingPrefetchDone() {
+ return player_.IsEventPending(player_.PREFETCH_DONE_EVENT_PENDING);
+ }
+
+ // Simulate player has reached starvation timeout.
+ void TriggerPlayerStarvation() {
+ player_.decoder_starvation_callback_.Cancel();
+ player_.OnDecoderStarved();
+ }
+
+ // Asynch test callback posted upon decode completion to verify that a pending
+ // prefetch done event is cleared across |player_|'s Release(). This helps
+ // ensure the ReleaseWithOnPrefetchDoneAlreadyPosted test scenario is met.
+ void ReleaseWithPendingPrefetchDoneVerification() {
+ EXPECT_TRUE(player_.IsPlaying());
+ EXPECT_FALSE(IsPendingPrefetchRequest());
+ EXPECT_TRUE(IsPendingPrefetchDone());
+ player_.Release();
+ EXPECT_FALSE(IsPendingPrefetchDone());
+ EXPECT_FALSE(player_.IsPlaying());
+ EXPECT_FALSE(decoder_callback_hook_executed_);
+ decoder_callback_hook_executed_ = true;
+ }
+
DemuxerConfigs CreateAudioDemuxerConfigs() {
DemuxerConfigs configs;
configs.audio_codec = kCodecVorbis;
@@ -468,12 +517,14 @@ class MediaSourcePlayerTest : public testing::Test {
scheme_uuid, security_level, container, codecs);
}
- protected:
base::MessageLoop message_loop_;
MockMediaPlayerManager manager_;
MockDemuxerAndroid* demuxer_; // Owned by |player_|.
MediaSourcePlayer player_;
+ // Track whether a possibly asynch decoder callback test hook has run.
+ bool decoder_callback_hook_executed_;
+
// We need to keep the surface texture while the decoder is actively decoding.
// Otherwise, it may trigger unexpected crashes on some devices. To switch
// surfaces, tests need to create a new surface texture without releasing
@@ -1379,6 +1430,88 @@ TEST_F(MediaSourcePlayerTest, NewSurfaceWhileChangingConfigs) {
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
+TEST_F(MediaSourcePlayerTest, ReleaseClearsSurfaceChangeAndPrefetchDone) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ // Test that Release() clears both a pending surface change event as well
+ // as a pending prefetch done event.
+ StartVideoDecoderJob();
+ CreateNextTextureAndSetVideoSurface();
+ EXPECT_EQ(1, demuxer_->num_data_requests());
+ EXPECT_TRUE(GetMediaDecoderJob(false));
+
+ EXPECT_FALSE(IsPendingSurfaceChange());
+ CreateNextTextureAndSetVideoSurface();
+ EXPECT_TRUE(IsPendingSurfaceChange());
+ EXPECT_TRUE(IsPendingPrefetchDone());
+
+ player_.Release();
+ EXPECT_FALSE(IsPendingSurfaceChange());
+ EXPECT_FALSE(IsPendingPrefetchDone());
+
+ // Player should have no decoder job until after Start() and setting non-empty
+ // surface.
+ EXPECT_FALSE(GetMediaDecoderJob(false));
+ EXPECT_FALSE(player_.IsPlaying());
+ StartVideoDecoderJob();
+ EXPECT_FALSE(GetMediaDecoderJob(false));
+ CreateNextTextureAndSetVideoSurface();
+ EXPECT_TRUE(GetMediaDecoderJob(false));
+}
+
+TEST_F(MediaSourcePlayerTest, ReleaseWithOnPrefetchDoneAlreadyPosted) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ // Test that if OnPrefetchDone() had already been posted before and is
+ // executed after Release(), player does not DCHECK.
+ StartAudioDecoderJob();
+
+ // Escape the original prefetch by decoding a single access unit.
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
+ message_loop_.Run();
+
+ // Prime the job with a few more access units, so that a later prefetch,
+ // triggered by starvation to simulate decoder underrun, can trivially
+ // post task to run OnPrefetchDone().
+ player_.OnDemuxerDataAvailable(
+ CreateReadFromDemuxerAckWithConfigChanged(true, 4));
+
+ EXPECT_TRUE(GetMediaDecoderJob(true) &&
+ GetMediaDecoderJob(true)->is_decoding());
+ EXPECT_FALSE(IsPendingPrefetchRequest());
+ EXPECT_FALSE(IsPendingPrefetchDone());
+
+ // Simulate decoder underrun, so trivial prefetch starts while still decoding.
+ // The prefetch and posting of OnPrefetchDone() will not occur until next
+ // MediaDecoderCallBack() occurs.
+ TriggerPlayerStarvation();
+ EXPECT_TRUE(IsPendingPrefetchRequest());
+ EXPECT_FALSE(IsPendingPrefetchDone());
+
+ // Upon the next successful decode callback, post a task to Release()
+ // |player_|, such that the trivial OnPrefetchDone() task posting also occurs
+ // and should execute after the Release().
+ manager_.HookNextMediaDecoderCallback(media::BindToLoop(
+ message_loop_.message_loop_proxy(),
+ base::Bind(
+ &MediaSourcePlayerTest_ReleaseWithOnPrefetchDoneAlreadyPosted_Test::
+ ReleaseWithPendingPrefetchDoneVerification,
+ base::Unretained(this))));
+
+ while (GetMediaDecoderJob(true))
+ message_loop_.RunUntilIdle();
+ EXPECT_TRUE(decoder_callback_hook_executed_);
+ EXPECT_FALSE(IsPendingPrefetchRequest());
+ EXPECT_FALSE(IsPendingPrefetchDone());
+ EXPECT_EQ(2, demuxer_->num_data_requests());
+ EXPECT_FALSE(GetMediaDecoderJob(true));
wolenetz 2013/10/30 00:06:45 This line was redundant with while(), above.
+ EXPECT_FALSE(player_.IsPlaying());
+
+ // Player should have no decoder job until after Start().
+ StartAudioDecoderJob();
+ EXPECT_TRUE(GetMediaDecoderJob(true));
+}
+
// TODO(xhwang): Enable this test when the test devices are updated.
TEST_F(MediaSourcePlayerTest, DISABLED_IsTypeSupported_Widevine) {
if (!MediaCodecBridge::IsAvailable() || !MediaDrmBridge::IsAvailable()) {
« media/base/android/media_source_player.cc ('K') | « media/base/android/media_source_player.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698