This source file includes following definitions.
- num_resources_released_
- GetMediaResourceGetter
- OnTimeUpdate
- OnMediaMetadataChanged
- OnPlaybackComplete
- OnMediaInterrupted
- OnBufferingUpdate
- OnSeekComplete
- OnError
- OnVideoSizeChanged
- GetFullscreenPlayer
- GetPlayer
- DestroyAllMediaPlayers
- GetDrmBridge
- OnProtectedSurfaceRequested
- OnSessionCreated
- OnSessionMessage
- OnSessionReady
- OnSessionClosed
- OnSessionError
- playback_completed
- num_resources_requested
- num_resources_released
- OnMediaResourcesRequested
- OnMediaResourcesReleased
- num_config_requests_
- Initialize
- RequestDemuxerConfigs
- RequestDemuxerData
- RequestDemuxerSeek
- num_data_requests
- num_seek_requests
- num_browser_seek_requests
- num_config_requests
- surface_texture_a_is_next_
- GetMediaDecoderJob
- IsPrerolling
- GetPrerollTimestamp
- TriggerPlayerStarvation
- ReleasePlayer
- OnNextTestDecodeCallbackPostTaskToReleasePlayer
- ReleaseWithPendingPrefetchDoneVerification
- IsPendingSurfaceChange
- CreateAudioDemuxerConfigs
- CreateVideoDemuxerConfigs
- CreateAudioVideoDemuxerConfigs
- CreateDemuxerConfigs
- StartAudioDecoderJob
- StartVideoDecoderJob
- Start
- CreateAccessUnitWithData
- CreateReadFromDemuxerAckForAudio
- CreateReadFromDemuxerAckForVideo
- CreateEOSAck
- CreateAbortedAck
- StartAudioDecoderJobAndSeekToWhileDecoding
- SeekPlayerWithAbort
- PrerollDecoderToTime
- CreateReadFromDemuxerAckWithConfigChanged
- BrowserSeekPlayer
- StartConfigChange
- CreateNextTextureAndSetVideoSurface
- WaitForDecodeDone
- WaitForAudioDecodeDone
- WaitForVideoDecodeDone
- WaitForAudioVideoDecodeDone
- VerifyPlaybackCompletesOnEOSDecode
- VerifyCompletedPlaybackResumesOnSeekPlusStart
- VerifySeekDuringEOSDecodePreventsPlaybackCompletion
- StartTimeTicks
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include <string>
#include "base/basictypes.h"
#include "base/logging.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_current_loop.h"
#include "media/base/decoder_buffer.h"
#include "media/base/test_data_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/gl/android/surface_texture.h"
namespace media {
#define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \
do { \
if (!MediaCodecBridge::IsAvailable()) { \
VLOG(0) << "Could not run test - not supported on device."; \
return; \
} \
} while (0)
const int kDefaultDurationInMs = 10000;
class MockMediaPlayerManager : public MediaPlayerManager {
public:
explicit MockMediaPlayerManager(base::MessageLoop* message_loop)
: message_loop_(message_loop),
playback_completed_(false),
num_resources_requested_(0),
num_resources_released_(0) {}
virtual ~MockMediaPlayerManager() {}
virtual MediaResourceGetter* GetMediaResourceGetter() OVERRIDE {
return NULL;
}
virtual void OnTimeUpdate(int player_id,
base::TimeDelta current_time) OVERRIDE {}
virtual void OnMediaMetadataChanged(
int player_id, base::TimeDelta duration, int width, int height,
bool success) OVERRIDE {}
virtual void OnPlaybackComplete(int player_id) OVERRIDE {
playback_completed_ = true;
if (message_loop_->is_running())
message_loop_->Quit();
}
virtual void OnMediaInterrupted(int player_id) OVERRIDE {}
virtual void OnBufferingUpdate(int player_id, int percentage) OVERRIDE {}
virtual void OnSeekComplete(int player_id,
const base::TimeDelta& current_time) OVERRIDE {}
virtual void OnError(int player_id, int error) OVERRIDE {}
virtual void OnVideoSizeChanged(int player_id, int width,
int height) OVERRIDE {}
virtual MediaPlayerAndroid* GetFullscreenPlayer() OVERRIDE { return NULL; }
virtual MediaPlayerAndroid* GetPlayer(int player_id) OVERRIDE { return NULL; }
virtual void DestroyAllMediaPlayers() OVERRIDE {}
virtual MediaDrmBridge* GetDrmBridge(int cdm_id) OVERRIDE { return NULL; }
virtual void OnProtectedSurfaceRequested(int player_id) OVERRIDE {}
virtual void OnSessionCreated(int cdm_id,
uint32 session_id,
const std::string& web_session_id) OVERRIDE {}
virtual void OnSessionMessage(int cdm_id,
uint32 session_id,
const std::vector<uint8>& message,
const GURL& destination_url) OVERRIDE {}
virtual void OnSessionReady(int cdm_id, uint32 session_id) OVERRIDE {}
virtual void OnSessionClosed(int cdm_id, uint32 session_id) OVERRIDE {}
virtual void OnSessionError(int cdm_id,
uint32 session_id,
media::MediaKeys::KeyError error_code,
uint32 system_code) OVERRIDE {}
bool playback_completed() const {
return playback_completed_;
}
int num_resources_requested() const {
return num_resources_requested_;
}
int num_resources_released() const {
return num_resources_released_;
}
void OnMediaResourcesRequested(int player_id) {
num_resources_requested_++;
}
void OnMediaResourcesReleased(int player_id) {
num_resources_released_++;
}
private:
base::MessageLoop* message_loop_;
bool playback_completed_;
int num_resources_requested_;
int num_resources_released_;
DISALLOW_COPY_AND_ASSIGN(MockMediaPlayerManager);
};
class MockDemuxerAndroid : public DemuxerAndroid {
public:
explicit MockDemuxerAndroid(base::MessageLoop* message_loop)
: message_loop_(message_loop),
num_data_requests_(0),
num_seek_requests_(0),
num_browser_seek_requests_(0),
num_config_requests_(0) {}
virtual ~MockDemuxerAndroid() {}
virtual void Initialize(DemuxerAndroidClient* client) OVERRIDE {}
virtual void RequestDemuxerConfigs() OVERRIDE {
num_config_requests_++;
}
virtual void RequestDemuxerData(DemuxerStream::Type type) OVERRIDE {
num_data_requests_++;
if (message_loop_->is_running())
message_loop_->Quit();
}
virtual void RequestDemuxerSeek(const base::TimeDelta& time_to_seek,
bool is_browser_seek) OVERRIDE {
num_seek_requests_++;
if (is_browser_seek)
num_browser_seek_requests_++;
}
int num_data_requests() const { return num_data_requests_; }
int num_seek_requests() const { return num_seek_requests_; }
int num_browser_seek_requests() const { return num_browser_seek_requests_; }
int num_config_requests() const { return num_config_requests_; }
private:
base::MessageLoop* message_loop_;
int num_data_requests_;
int num_seek_requests_;
int num_browser_seek_requests_;
int num_config_requests_;
DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid);
};
class MediaSourcePlayerTest : public testing::Test {
public:
MediaSourcePlayerTest()
: manager_(&message_loop_),
demuxer_(new MockDemuxerAndroid(&message_loop_)),
player_(0, &manager_,
base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested,
base::Unretained(&manager_)),
base::Bind(&MockMediaPlayerManager::OnMediaResourcesReleased,
base::Unretained(&manager_)),
scoped_ptr<DemuxerAndroid>(demuxer_)),
decoder_callback_hook_executed_(false),
surface_texture_a_is_next_(true) {}
virtual ~MediaSourcePlayerTest() {}
protected:
MediaDecoderJob* GetMediaDecoderJob(bool is_audio) {
if (is_audio) {
return reinterpret_cast<MediaDecoderJob*>(
player_.audio_decoder_job_.get());
}
return reinterpret_cast<MediaDecoderJob*>(
player_.video_decoder_job_.get());
}
bool IsPrerolling(bool is_audio) {
return GetMediaDecoderJob(is_audio)->prerolling();
}
base::TimeDelta GetPrerollTimestamp() {
return player_.preroll_timestamp_;
}
void TriggerPlayerStarvation() {
player_.decoder_starvation_callback_.Cancel();
player_.OnDecoderStarved();
}
void ReleasePlayer() {
EXPECT_TRUE(player_.IsPlaying());
player_.Release();
EXPECT_FALSE(player_.IsPlaying());
EXPECT_FALSE(GetMediaDecoderJob(true));
EXPECT_FALSE(GetMediaDecoderJob(false));
}
void OnNextTestDecodeCallbackPostTaskToReleasePlayer() {
DCHECK_EQ(&message_loop_, base::MessageLoop::current());
player_.set_decode_callback_for_testing(media::BindToCurrentLoop(
base::Bind(
&MediaSourcePlayerTest::ReleaseWithPendingPrefetchDoneVerification,
base::Unretained(this))));
}
void ReleaseWithPendingPrefetchDoneVerification() {
EXPECT_TRUE(player_.IsEventPending(player_.PREFETCH_DONE_EVENT_PENDING));
ReleasePlayer();
EXPECT_FALSE(player_.IsEventPending(player_.PREFETCH_DONE_EVENT_PENDING));
EXPECT_FALSE(decoder_callback_hook_executed_);
decoder_callback_hook_executed_ = true;
}
bool IsPendingSurfaceChange() {
return player_.IsEventPending(player_.SURFACE_CHANGE_EVENT_PENDING);
}
DemuxerConfigs CreateAudioDemuxerConfigs(AudioCodec audio_codec) {
DemuxerConfigs configs;
configs.audio_codec = audio_codec;
configs.audio_channels = 2;
configs.is_audio_encrypted = false;
configs.duration_ms = kDefaultDurationInMs;
if (audio_codec == kCodecVorbis) {
configs.audio_sampling_rate = 44100;
scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(
"vorbis-extradata");
configs.audio_extra_data = std::vector<uint8>(
buffer->data(),
buffer->data() + buffer->data_size());
return configs;
}
EXPECT_EQ(audio_codec, kCodecAAC);
configs.audio_sampling_rate = 48000;
uint8 aac_extra_data[] = { 0x13, 0x10 };
configs.audio_extra_data = std::vector<uint8>(
aac_extra_data,
aac_extra_data + 2);
return configs;
}
DemuxerConfigs CreateVideoDemuxerConfigs() {
DemuxerConfigs configs;
configs.video_codec = kCodecVP8;
configs.video_size = gfx::Size(320, 240);
configs.is_video_encrypted = false;
configs.duration_ms = kDefaultDurationInMs;
return configs;
}
DemuxerConfigs CreateAudioVideoDemuxerConfigs() {
DemuxerConfigs configs = CreateAudioDemuxerConfigs(kCodecVorbis);
configs.video_codec = kCodecVP8;
configs.video_size = gfx::Size(320, 240);
configs.is_video_encrypted = false;
return configs;
}
DemuxerConfigs CreateDemuxerConfigs(bool have_audio, bool have_video) {
DCHECK(have_audio || have_video);
if (have_audio && !have_video)
return CreateAudioDemuxerConfigs(kCodecVorbis);
if (have_video && !have_audio)
return CreateVideoDemuxerConfigs();
return CreateAudioVideoDemuxerConfigs();
}
void StartAudioDecoderJob(bool expect_player_requests_data) {
Start(CreateAudioDemuxerConfigs(kCodecVorbis), expect_player_requests_data);
}
void StartVideoDecoderJob(bool expect_player_requests_data) {
Start(CreateVideoDemuxerConfigs(), expect_player_requests_data);
}
void Start(const DemuxerConfigs& configs, bool expect_player_requests_data) {
bool has_audio = configs.audio_codec != kUnknownAudioCodec;
bool has_video = configs.video_codec != kUnknownVideoCodec;
int original_num_data_requests = demuxer_->num_data_requests();
int expected_request_delta = expect_player_requests_data ?
((has_audio ? 1 : 0) + (has_video ? 1 : 0)) : 0;
player_.OnDemuxerConfigsAvailable(configs);
player_.Start();
EXPECT_TRUE(player_.IsPlaying());
EXPECT_EQ(original_num_data_requests + expected_request_delta,
demuxer_->num_data_requests());
EXPECT_EQ(expect_player_requests_data && has_audio,
GetMediaDecoderJob(true) != NULL);
EXPECT_EQ(expect_player_requests_data && has_video,
GetMediaDecoderJob(false) != NULL);
}
AccessUnit CreateAccessUnitWithData(bool is_audio, int audio_packet_id) {
AccessUnit unit;
unit.status = DemuxerStream::kOk;
scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(
is_audio ? base::StringPrintf("vorbis-packet-%d", audio_packet_id)
: "vp8-I-frame-320x240");
unit.data = std::vector<uint8>(
buffer->data(), buffer->data() + buffer->data_size());
if (is_audio) {
uint8 padding[4] = { 0xff , 0xff , 0xff , 0xff };
unit.data.insert(unit.data.end(), padding, padding + 4);
}
return unit;
}
DemuxerData CreateReadFromDemuxerAckForAudio(int packet_id) {
DemuxerData data;
data.type = DemuxerStream::AUDIO;
data.access_units.resize(1);
data.access_units[0] = CreateAccessUnitWithData(true, packet_id);
return data;
}
DemuxerData CreateReadFromDemuxerAckForVideo() {
DemuxerData data;
data.type = DemuxerStream::VIDEO;
data.access_units.resize(1);
data.access_units[0] = CreateAccessUnitWithData(false, 0);
return data;
}
DemuxerData CreateEOSAck(bool is_audio) {
DemuxerData data;
data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
data.access_units.resize(1);
data.access_units[0].status = DemuxerStream::kOk;
data.access_units[0].end_of_stream = true;
return data;
}
DemuxerData CreateAbortedAck(bool is_audio) {
DemuxerData data;
data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
data.access_units.resize(1);
data.access_units[0].status = DemuxerStream::kAborted;
return data;
}
void StartAudioDecoderJobAndSeekToWhileDecoding(
const base::TimeDelta& seek_time) {
EXPECT_FALSE(GetMediaDecoderJob(true));
EXPECT_FALSE(player_.IsPlaying());
EXPECT_EQ(0, demuxer_->num_data_requests());
EXPECT_EQ(0.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_EQ(player_.GetCurrentTime(), GetPrerollTimestamp());
StartAudioDecoderJob(true);
EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
EXPECT_EQ(2, demuxer_->num_data_requests());
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
player_.SeekTo(seek_time);
EXPECT_EQ(0.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_EQ(0, demuxer_->num_seek_requests());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
}
void SeekPlayerWithAbort(bool is_audio, const base::TimeDelta& seek_time) {
int original_num_seeks = demuxer_->num_seek_requests();
int original_num_data_requests = demuxer_->num_data_requests();
player_.SeekTo(seek_time);
EXPECT_EQ(original_num_seeks, demuxer_->num_seek_requests());
player_.OnDemuxerDataAvailable(CreateAbortedAck(is_audio));
EXPECT_EQ(original_num_seeks + 1, demuxer_->num_seek_requests());
EXPECT_EQ(original_num_data_requests, demuxer_->num_data_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_EQ(original_num_data_requests + 1, demuxer_->num_data_requests());
EXPECT_EQ(original_num_seeks + 1, demuxer_->num_seek_requests());
}
void PrerollDecoderToTime(bool is_audio,
const base::TimeDelta& start_timestamp,
const base::TimeDelta& target_timestamp) {
EXPECT_EQ(target_timestamp, player_.GetCurrentTime());
EXPECT_LE(start_timestamp, target_timestamp);
DemuxerData data = is_audio ? CreateReadFromDemuxerAckForAudio(1) :
CreateReadFromDemuxerAckForVideo();
int current_timestamp = start_timestamp.InMilliseconds();
while (IsPrerolling(is_audio)) {
data.access_units[0].timestamp =
base::TimeDelta::FromMilliseconds(current_timestamp);
player_.OnDemuxerDataAvailable(data);
EXPECT_TRUE(GetMediaDecoderJob(is_audio)->is_decoding());
EXPECT_EQ(target_timestamp, player_.GetCurrentTime());
current_timestamp += 30;
WaitForDecodeDone(is_audio, !is_audio);
}
EXPECT_LE(target_timestamp, player_.GetCurrentTime());
}
DemuxerData CreateReadFromDemuxerAckWithConfigChanged(bool is_audio,
int config_unit_index) {
DemuxerData data;
data.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
data.access_units.resize(config_unit_index + 1);
for (int i = 0; i < config_unit_index; ++i)
data.access_units[i] = CreateAccessUnitWithData(is_audio, i);
data.access_units[config_unit_index].status = DemuxerStream::kConfigChanged;
return data;
}
void BrowserSeekPlayer(bool trigger_with_release_start) {
int expected_num_data_requests = demuxer_->num_data_requests() +
(trigger_with_release_start ? 1 : 2);
int expected_num_seek_requests = demuxer_->num_seek_requests();
int expected_num_browser_seek_requests =
demuxer_->num_browser_seek_requests();
EXPECT_FALSE(GetMediaDecoderJob(false));
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
if (trigger_with_release_start) {
ReleasePlayer();
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
EXPECT_FALSE(GetMediaDecoderJob(false));
EXPECT_FALSE(player_.IsPlaying());
EXPECT_EQ(expected_num_seek_requests, demuxer_->num_seek_requests());
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(false);
EXPECT_FALSE(GetMediaDecoderJob(false));
} else {
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
CreateNextTextureAndSetVideoSurface();
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(expected_num_seek_requests, demuxer_->num_seek_requests());
WaitForVideoDecodeDone();
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
}
expected_num_seek_requests++;
expected_num_browser_seek_requests++;
EXPECT_EQ(expected_num_seek_requests, demuxer_->num_seek_requests());
EXPECT_EQ(expected_num_browser_seek_requests,
demuxer_->num_browser_seek_requests());
EXPECT_EQ(expected_num_data_requests, demuxer_->num_data_requests());
}
void StartConfigChange(bool is_audio,
bool config_unit_in_prefetch,
int config_unit_index) {
int expected_num_config_requests = demuxer_->num_config_requests();
EXPECT_FALSE(GetMediaDecoderJob(is_audio));
if (is_audio) {
StartAudioDecoderJob(true);
} else {
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
}
int expected_num_data_requests = demuxer_->num_data_requests();
if (!config_unit_in_prefetch) {
if (is_audio)
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
else
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
WaitForDecodeDone(is_audio, !is_audio);
expected_num_data_requests++;
EXPECT_EQ(expected_num_data_requests, demuxer_->num_data_requests());
}
EXPECT_EQ(expected_num_config_requests, demuxer_->num_config_requests());
player_.OnDemuxerDataAvailable(
CreateReadFromDemuxerAckWithConfigChanged(is_audio, config_unit_index));
WaitForDecodeDone(is_audio, !is_audio);
expected_num_config_requests++;
EXPECT_EQ(expected_num_data_requests, demuxer_->num_data_requests());
EXPECT_EQ(expected_num_config_requests, demuxer_->num_config_requests());
}
void CreateNextTextureAndSetVideoSurface() {
gfx::SurfaceTexture* surface_texture;
if (surface_texture_a_is_next_) {
surface_texture_a_ = gfx::SurfaceTexture::Create(next_texture_id_++);
surface_texture = surface_texture_a_.get();
} else {
surface_texture_b_ = gfx::SurfaceTexture::Create(next_texture_id_++);
surface_texture = surface_texture_b_.get();
}
surface_texture_a_is_next_ = !surface_texture_a_is_next_;
gfx::ScopedJavaSurface surface = gfx::ScopedJavaSurface(surface_texture);
player_.SetVideoSurface(surface.Pass());
}
void WaitForDecodeDone(bool wait_for_audio, bool wait_for_video) {
DCHECK(wait_for_audio || wait_for_video);
while ((wait_for_audio && GetMediaDecoderJob(true) &&
GetMediaDecoderJob(true)->HasData() &&
GetMediaDecoderJob(true)->is_decoding()) ||
(wait_for_video && GetMediaDecoderJob(false) &&
GetMediaDecoderJob(false)->HasData() &&
GetMediaDecoderJob(false)->is_decoding())) {
message_loop_.RunUntilIdle();
}
}
void WaitForAudioDecodeDone() {
WaitForDecodeDone(true, false);
}
void WaitForVideoDecodeDone() {
WaitForDecodeDone(false, true);
}
void WaitForAudioVideoDecodeDone() {
WaitForDecodeDone(true, true);
}
void VerifyPlaybackCompletesOnEOSDecode(bool send_eos, bool eos_for_audio) {
int original_num_data_requests = demuxer_->num_data_requests();
if (send_eos)
player_.OnDemuxerDataAvailable(CreateEOSAck(eos_for_audio));
EXPECT_FALSE(manager_.playback_completed());
message_loop_.Run();
EXPECT_TRUE(manager_.playback_completed());
EXPECT_EQ(original_num_data_requests, demuxer_->num_data_requests());
}
void VerifyCompletedPlaybackResumesOnSeekPlusStart(bool have_audio,
bool have_video) {
DCHECK(have_audio || have_video);
EXPECT_TRUE(manager_.playback_completed());
player_.SeekTo(base::TimeDelta());
player_.OnDemuxerSeekDone(kNoTimestamp());
Start(CreateDemuxerConfigs(have_audio, have_video), true);
}
void VerifySeekDuringEOSDecodePreventsPlaybackCompletion(bool have_audio,
bool have_video,
bool eos_audio,
bool eos_video) {
DCHECK(have_audio || have_video);
if (have_video)
CreateNextTextureAndSetVideoSurface();
Start(CreateDemuxerConfigs(have_audio, have_video), true);
if (have_audio)
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
if (have_video)
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
WaitForDecodeDone(have_audio, have_video);
if (have_audio) {
if (eos_audio)
player_.OnDemuxerDataAvailable(CreateEOSAck(true));
else
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(1));
}
if (have_video) {
if (eos_video)
player_.OnDemuxerDataAvailable(CreateEOSAck(false));
else
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
}
player_.SeekTo(base::TimeDelta());
EXPECT_EQ(0, demuxer_->num_seek_requests());
WaitForDecodeDone(have_audio, have_video);
EXPECT_EQ(1, demuxer_->num_seek_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_FALSE(manager_.playback_completed());
}
base::TimeTicks StartTimeTicks() {
return player_.start_time_ticks_;
}
base::MessageLoop message_loop_;
MockMediaPlayerManager manager_;
MockDemuxerAndroid* demuxer_;
MediaSourcePlayer player_;
bool decoder_callback_hook_executed_;
scoped_refptr<gfx::SurfaceTexture> surface_texture_a_;
scoped_refptr<gfx::SurfaceTexture> surface_texture_b_;
bool surface_texture_a_is_next_;
int next_texture_id_;
DISALLOW_COPY_AND_ASSIGN(MediaSourcePlayerTest);
};
TEST_F(MediaSourcePlayerTest, StartAudioDecoderWithValidConfig) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, StartAudioDecoderWithInvalidConfig) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
DemuxerConfigs configs = CreateAudioDemuxerConfigs(kCodecVorbis);
configs.audio_extra_data.clear();
uint8 invalid_codec_data[] = { 0x00, 0xff, 0xff, 0xff, 0xff };
configs.audio_extra_data.insert(configs.audio_extra_data.begin(),
invalid_codec_data, invalid_codec_data + 4);
Start(configs, false);
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, StartVideoCodecWithValidSurface) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartVideoDecoderJob(false);
CreateNextTextureAndSetVideoSurface();
MediaDecoderJob* first_job = GetMediaDecoderJob(false);
EXPECT_TRUE(first_job);
CreateNextTextureAndSetVideoSurface();
EXPECT_EQ(first_job, GetMediaDecoderJob(false));
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, StartVideoCodecWithInvalidSurface) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
scoped_refptr<gfx::SurfaceTexture> surface_texture(
gfx::SurfaceTexture::Create(0));
gfx::ScopedJavaSurface surface(surface_texture.get());
StartVideoDecoderJob(false);
surface_texture = NULL;
player_.SetVideoSurface(surface.Pass());
EXPECT_EQ(0, demuxer_->num_seek_requests());
EXPECT_FALSE(GetMediaDecoderJob(false));
EXPECT_EQ(0, demuxer_->num_data_requests());
}
TEST_F(MediaSourcePlayerTest, ReadFromDemuxerAfterSeek) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
SeekPlayerWithAbort(true, base::TimeDelta());
}
TEST_F(MediaSourcePlayerTest, SetSurfaceWhileSeeking) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartVideoDecoderJob(false);
EXPECT_EQ(0, demuxer_->num_seek_requests());
player_.SeekTo(base::TimeDelta());
EXPECT_EQ(1, demuxer_->num_seek_requests());
CreateNextTextureAndSetVideoSurface();
EXPECT_FALSE(GetMediaDecoderJob(false));
EXPECT_EQ(1, demuxer_->num_seek_requests());
EXPECT_EQ(0, demuxer_->num_data_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(1, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
EXPECT_EQ(0, demuxer_->num_browser_seek_requests());
}
TEST_F(MediaSourcePlayerTest, ChangeMultipleSurfaceWhileDecoding) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
EXPECT_EQ(0, demuxer_->num_seek_requests());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
gfx::ScopedJavaSurface empty_surface;
player_.SetVideoSurface(empty_surface.Pass());
CreateNextTextureAndSetVideoSurface();
WaitForVideoDecodeDone();
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
EXPECT_EQ(1, demuxer_->num_browser_seek_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
player_.OnDemuxerSeekDone(player_.GetCurrentTime());
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, SetEmptySurfaceAndStarveWhileDecoding) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
EXPECT_EQ(1, demuxer_->num_data_requests());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
gfx::ScopedJavaSurface empty_surface;
player_.SetVideoSurface(empty_surface.Pass());
TriggerPlayerStarvation();
while (GetMediaDecoderJob(false))
message_loop_.RunUntilIdle();
EXPECT_EQ(0, demuxer_->num_browser_seek_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
CreateNextTextureAndSetVideoSurface();
EXPECT_EQ(1, demuxer_->num_browser_seek_requests());
}
TEST_F(MediaSourcePlayerTest, ReleaseVideoDecoderResourcesWhileDecoding) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
EXPECT_EQ(1, manager_.num_resources_requested());
ReleasePlayer();
EXPECT_EQ(1, manager_.num_resources_released());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
CreateNextTextureAndSetVideoSurface();
player_.Start();
EXPECT_EQ(1, demuxer_->num_browser_seek_requests());
player_.OnDemuxerSeekDone(base::TimeDelta());
EXPECT_EQ(2, manager_.num_resources_requested());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
ReleasePlayer();
EXPECT_EQ(1, manager_.num_resources_released());
while (manager_.num_resources_released() != 2)
message_loop_.RunUntilIdle();
}
TEST_F(MediaSourcePlayerTest, AudioOnlyStartAfterSeekFinish) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
DemuxerConfigs configs = CreateAudioDemuxerConfigs(kCodecVorbis);
player_.OnDemuxerConfigsAvailable(configs);
EXPECT_FALSE(GetMediaDecoderJob(true));
player_.SeekTo(base::TimeDelta());
EXPECT_EQ(1, demuxer_->num_seek_requests());
player_.Start();
EXPECT_FALSE(GetMediaDecoderJob(true));
EXPECT_EQ(0, demuxer_->num_data_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_EQ(1, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, VideoOnlyStartAfterSeekFinish) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
DemuxerConfigs configs = CreateVideoDemuxerConfigs();
player_.OnDemuxerConfigsAvailable(configs);
EXPECT_FALSE(GetMediaDecoderJob(false));
player_.SeekTo(base::TimeDelta());
EXPECT_EQ(1, demuxer_->num_seek_requests());
player_.Start();
EXPECT_FALSE(GetMediaDecoderJob(false));
EXPECT_EQ(0, demuxer_->num_data_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(1, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, StartImmediatelyAfterPause) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
MediaDecoderJob* decoder_job = GetMediaDecoderJob(true);
EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
EXPECT_EQ(2, demuxer_->num_data_requests());
player_.Pause(true);
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
player_.Start();
EXPECT_EQ(decoder_job, GetMediaDecoderJob(true));
while (GetMediaDecoderJob(true)->is_decoding())
message_loop_.RunUntilIdle();
EXPECT_EQ(2, demuxer_->num_data_requests());
EXPECT_TRUE(GetMediaDecoderJob(true)->is_requesting_demuxer_data());
}
TEST_F(MediaSourcePlayerTest, DecoderJobsCannotStartWithoutAudio) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
Start(CreateAudioVideoDemuxerConfigs(), true);
MediaDecoderJob* audio_decoder_job = GetMediaDecoderJob(true);
MediaDecoderJob* video_decoder_job = GetMediaDecoderJob(false);
EXPECT_FALSE(audio_decoder_job->is_decoding());
EXPECT_FALSE(video_decoder_job->is_decoding());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
EXPECT_FALSE(video_decoder_job->is_decoding());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
EXPECT_TRUE(audio_decoder_job->is_decoding());
EXPECT_TRUE(video_decoder_job->is_decoding());
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, StartTimeTicksResetAfterDecoderUnderruns) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
for (int i = 0; i < 4; ++i) {
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(i));
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
WaitForAudioDecodeDone();
}
EXPECT_EQ(5, demuxer_->num_data_requests());
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
base::TimeTicks previous = StartTimeTicks();
TriggerPlayerStarvation();
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(3));
WaitForAudioDecodeDone();
EXPECT_TRUE(StartTimeTicks() == base::TimeTicks());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(3));
EXPECT_TRUE(StartTimeTicks() != base::TimeTicks());
base::TimeTicks current = StartTimeTicks();
EXPECT_LE(0, (current - previous).InMillisecondsF());
}
TEST_F(MediaSourcePlayerTest, V_SecondAccessUnitIsEOSAndResumePlayAfterSeek) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
WaitForVideoDecodeDone();
VerifyPlaybackCompletesOnEOSDecode(true, false);
VerifyCompletedPlaybackResumesOnSeekPlusStart(false, true);
}
TEST_F(MediaSourcePlayerTest, A_FirstAccessUnitIsEOSAndResumePlayAfterSeek) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
Start(CreateAudioDemuxerConfigs(kCodecAAC), true);
VerifyPlaybackCompletesOnEOSDecode(true, true);
VerifyCompletedPlaybackResumesOnSeekPlusStart(true, false);
}
TEST_F(MediaSourcePlayerTest, V_FirstAccessUnitAfterSeekIsEOS) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
SeekPlayerWithAbort(false, base::TimeDelta());
VerifyPlaybackCompletesOnEOSDecode(true, false);
}
TEST_F(MediaSourcePlayerTest, A_FirstAccessUnitAfterSeekIsEOS) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
Start(CreateAudioDemuxerConfigs(kCodecAAC), true);
SeekPlayerWithAbort(true, base::TimeDelta());
VerifyPlaybackCompletesOnEOSDecode(true, true);
}
TEST_F(MediaSourcePlayerTest, AV_PlaybackCompletionAcrossConfigChange) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
Start(CreateAudioVideoDemuxerConfigs(), true);
player_.OnDemuxerDataAvailable(CreateEOSAck(true));
EXPECT_EQ(0, demuxer_->num_config_requests());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckWithConfigChanged(
false, 0));
WaitForAudioVideoDecodeDone();
EXPECT_EQ(1, demuxer_->num_config_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
player_.OnDemuxerConfigsAvailable(CreateAudioVideoDemuxerConfigs());
EXPECT_EQ(3, demuxer_->num_data_requests());
VerifyPlaybackCompletesOnEOSDecode(true, false);
VerifyCompletedPlaybackResumesOnSeekPlusStart(true, true);
}
TEST_F(MediaSourcePlayerTest, VA_PlaybackCompletionAcrossConfigChange) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
Start(CreateAudioVideoDemuxerConfigs(), true);
player_.OnDemuxerDataAvailable(CreateEOSAck(false));
EXPECT_EQ(0, demuxer_->num_config_requests());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckWithConfigChanged(
true, 0));
WaitForAudioVideoDecodeDone();
EXPECT_EQ(2, demuxer_->num_config_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
player_.OnDemuxerConfigsAvailable(CreateAudioVideoDemuxerConfigs());
EXPECT_EQ(3, demuxer_->num_data_requests());
VerifyPlaybackCompletesOnEOSDecode(true, true);
VerifyCompletedPlaybackResumesOnSeekPlusStart(true, true);
}
TEST_F(MediaSourcePlayerTest, AV_NoPrefetchForFinishedVideoOnAudioStarvation) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
Start(CreateAudioVideoDemuxerConfigs(), true);
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
player_.OnDemuxerDataAvailable(CreateEOSAck(false));
WaitForAudioVideoDecodeDone();
EXPECT_EQ(3, demuxer_->num_data_requests());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(1));
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding() &&
!GetMediaDecoderJob(false)->is_decoding());
TriggerPlayerStarvation();
WaitForAudioDecodeDone();
EXPECT_EQ(4, demuxer_->num_data_requests());
player_.OnDemuxerDataAvailable(CreateEOSAck(true));
EXPECT_FALSE(GetMediaDecoderJob(false)->is_decoding());
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
TriggerPlayerStarvation();
VerifyPlaybackCompletesOnEOSDecode(false, true );
}
TEST_F(MediaSourcePlayerTest, V_StarvationDuringEOSDecode) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
WaitForVideoDecodeDone();
player_.OnDemuxerDataAvailable(CreateEOSAck(false));
EXPECT_TRUE(GetMediaDecoderJob(false)->is_decoding());
TriggerPlayerStarvation();
VerifyPlaybackCompletesOnEOSDecode(false, false );
}
TEST_F(MediaSourcePlayerTest, A_StarvationDuringEOSDecode) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
WaitForAudioDecodeDone();
player_.OnDemuxerDataAvailable(CreateEOSAck(true));
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
TriggerPlayerStarvation();
VerifyPlaybackCompletesOnEOSDecode(false, true );
}
TEST_F(MediaSourcePlayerTest, AV_SeekDuringEOSDecodePreventsCompletion) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
VerifySeekDuringEOSDecodePreventsPlaybackCompletion(true, true, true, true);
}
TEST_F(MediaSourcePlayerTest, AV_SeekDuringAudioEOSDecodePreventsCompletion) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
VerifySeekDuringEOSDecodePreventsPlaybackCompletion(true, true, true, false);
}
TEST_F(MediaSourcePlayerTest, AV_SeekDuringVideoEOSDecodePreventsCompletion) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
VerifySeekDuringEOSDecodePreventsPlaybackCompletion(true, true, false, true);
}
TEST_F(MediaSourcePlayerTest, V_SeekDuringEOSDecodePreventsCompletion) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
VerifySeekDuringEOSDecodePreventsPlaybackCompletion(false, true, false, true);
}
TEST_F(MediaSourcePlayerTest, A_SeekDuringEOSDecodePreventsCompletion) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
VerifySeekDuringEOSDecodePreventsPlaybackCompletion(true, false, true, false);
}
TEST_F(MediaSourcePlayerTest, NoRequestForDataAfterAbort) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
player_.OnDemuxerDataAvailable(CreateAbortedAck(true));
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
WaitForAudioDecodeDone();
EXPECT_EQ(1, demuxer_->num_data_requests());
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, DemuxerDataArrivesAfterRelease) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
ReleasePlayer();
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
EXPECT_FALSE(player_.IsPlaying());
EXPECT_EQ(1, demuxer_->num_data_requests());
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, BrowserSeek_RegularSeekPendsBrowserSeekDone) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
BrowserSeekPlayer(false);
player_.SeekTo(base::TimeDelta());
EXPECT_FALSE(GetMediaDecoderJob(false));
EXPECT_EQ(1, demuxer_->num_seek_requests());
player_.OnDemuxerSeekDone(base::TimeDelta());
EXPECT_FALSE(GetMediaDecoderJob(false));
EXPECT_EQ(2, demuxer_->num_seek_requests());
EXPECT_EQ(1, demuxer_->num_browser_seek_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(2, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, BrowserSeek_InitialReleaseAndStart) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
ReleasePlayer();
CreateNextTextureAndSetVideoSurface();
player_.Start();
EXPECT_EQ(1, demuxer_->num_data_requests());
EXPECT_FALSE(GetMediaDecoderJob(false));
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
EXPECT_EQ(1, demuxer_->num_browser_seek_requests());
EXPECT_EQ(1, demuxer_->num_data_requests());
}
TEST_F(MediaSourcePlayerTest, BrowserSeek_MidStreamReleaseAndStart) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
BrowserSeekPlayer(true);
player_.OnDemuxerSeekDone(base::TimeDelta());
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(2, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, PrerollAudioAfterSeek) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
SeekPlayerWithAbort(true, base::TimeDelta::FromMilliseconds(100));
EXPECT_TRUE(IsPrerolling(true));
PrerollDecoderToTime(
true, base::TimeDelta(), base::TimeDelta::FromMilliseconds(100));
}
TEST_F(MediaSourcePlayerTest, PrerollVideoAfterSeek) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
SeekPlayerWithAbort(false, base::TimeDelta::FromMilliseconds(100));
EXPECT_TRUE(IsPrerolling(false));
PrerollDecoderToTime(
false, base::TimeDelta(), base::TimeDelta::FromMilliseconds(100));
}
TEST_F(MediaSourcePlayerTest, SeekingAfterCompletingPrerollRestartsPreroll) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
MediaDecoderJob* decoder_job = GetMediaDecoderJob(true);
EXPECT_TRUE(IsPrerolling(true));
for (int i = 0; i < 4; ++i) {
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(i));
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
WaitForAudioDecodeDone();
}
EXPECT_LT(0.0, player_.GetCurrentTime().InMillisecondsF());
EXPECT_FALSE(IsPrerolling(true));
SeekPlayerWithAbort(true, base::TimeDelta::FromMilliseconds(500));
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(500.0, GetPrerollTimestamp().InMillisecondsF());
for (int i = 0; i < 4; ++i) {
DemuxerData data = CreateReadFromDemuxerAckForAudio(i);
data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(
500 + 30 * (i - 1));
player_.OnDemuxerDataAvailable(data);
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
WaitForAudioDecodeDone();
}
EXPECT_LT(500.0, player_.GetCurrentTime().InMillisecondsF());
EXPECT_FALSE(IsPrerolling(true));
EXPECT_EQ(decoder_job, GetMediaDecoderJob(true));
}
TEST_F(MediaSourcePlayerTest, PrerollContinuesAcrossReleaseAndStart) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
base::TimeDelta target_timestamp = base::TimeDelta::FromMilliseconds(100);
SeekPlayerWithAbort(true, target_timestamp);
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
DemuxerData data;
for (int i = 0; i < 10; ++i) {
data = CreateReadFromDemuxerAckForAudio(3);
data.access_units[0].timestamp = base::TimeDelta::FromMilliseconds(i * 10);
if (i == 1) {
ReleasePlayer();
player_.OnDemuxerDataAvailable(data);
WaitForAudioDecodeDone();
EXPECT_FALSE(GetMediaDecoderJob(true));
StartAudioDecoderJob(true);
} else {
player_.OnDemuxerDataAvailable(data);
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
WaitForAudioDecodeDone();
}
EXPECT_TRUE(IsPrerolling(true));
}
EXPECT_EQ(100.0, player_.GetCurrentTime().InMillisecondsF());
EXPECT_TRUE(IsPrerolling(true));
PrerollDecoderToTime(true, target_timestamp, target_timestamp);
}
TEST_F(MediaSourcePlayerTest, PrerollContinuesAcrossConfigChange) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
SeekPlayerWithAbort(true, base::TimeDelta::FromMilliseconds(100));
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
DemuxerData data = CreateReadFromDemuxerAckWithConfigChanged(true, 0);
EXPECT_EQ(0, demuxer_->num_config_requests());
player_.OnDemuxerDataAvailable(data);
EXPECT_EQ(1, demuxer_->num_config_requests());
player_.OnDemuxerConfigsAvailable(CreateAudioDemuxerConfigs(kCodecVorbis));
PrerollDecoderToTime(
true, base::TimeDelta(), base::TimeDelta::FromMilliseconds(100));
}
TEST_F(MediaSourcePlayerTest, SimultaneousAudioVideoConfigChange) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
Start(CreateAudioVideoDemuxerConfigs(), true);
MediaDecoderJob* first_audio_job = GetMediaDecoderJob(true);
MediaDecoderJob* first_video_job = GetMediaDecoderJob(false);
player_.OnDemuxerDataAvailable(
CreateReadFromDemuxerAckWithConfigChanged(true, 0));
EXPECT_EQ(0, demuxer_->num_config_requests());
player_.OnDemuxerDataAvailable(
CreateReadFromDemuxerAckWithConfigChanged(false, 0));
EXPECT_EQ(1, demuxer_->num_config_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
EXPECT_EQ(first_audio_job, GetMediaDecoderJob(true));
EXPECT_EQ(first_video_job, GetMediaDecoderJob(false));
player_.OnDemuxerConfigsAvailable(CreateAudioVideoDemuxerConfigs());
EXPECT_EQ(4, demuxer_->num_data_requests());
MediaDecoderJob* second_audio_job = GetMediaDecoderJob(true);
MediaDecoderJob* second_video_job = GetMediaDecoderJob(false);
EXPECT_NE(first_audio_job, second_audio_job);
EXPECT_NE(first_video_job, second_video_job);
EXPECT_TRUE(second_audio_job && second_video_job);
EXPECT_EQ(1, demuxer_->num_config_requests());
}
TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInPrefetchUnit0) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(true, true, 0);
}
TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInPrefetchUnit1) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(true, true, 1);
}
TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInUnit0AfterPrefetch) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(true, false, 0);
}
TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInUnit1AfterPrefetch) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(true, false, 1);
}
TEST_F(MediaSourcePlayerTest, BrowserSeek_PrerollAfterBrowserSeek) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
BrowserSeekPlayer(false);
EXPECT_LT(player_.GetCurrentTime().InMillisecondsF(), 100);
player_.OnDemuxerSeekDone(base::TimeDelta::FromMilliseconds(100));
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(100.0, player_.GetCurrentTime().InMillisecondsF());
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_EQ(3, demuxer_->num_data_requests());
PrerollDecoderToTime(
false, base::TimeDelta(), base::TimeDelta::FromMilliseconds(100));
}
TEST_F(MediaSourcePlayerTest, VideoDemuxerConfigChange) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(false, true, 1);
MediaDecoderJob* first_job = GetMediaDecoderJob(false);
EXPECT_TRUE(first_job);
EXPECT_EQ(1, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_config_requests());
player_.OnDemuxerConfigsAvailable(CreateVideoDemuxerConfigs());
MediaDecoderJob* second_job = GetMediaDecoderJob(false);
EXPECT_TRUE(second_job);
EXPECT_NE(first_job, second_job);
EXPECT_EQ(2, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_config_requests());
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, VideoConfigChangeContinuesAcrossSeek) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(false, false, 1);
MediaDecoderJob* first_job = GetMediaDecoderJob(false);
EXPECT_TRUE(first_job);
EXPECT_EQ(1, demuxer_->num_config_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
EXPECT_EQ(0, demuxer_->num_seek_requests());
player_.SeekTo(base::TimeDelta::FromMilliseconds(100));
EXPECT_EQ(1, demuxer_->num_seek_requests());
player_.OnDemuxerConfigsAvailable(CreateVideoDemuxerConfigs());
MediaDecoderJob* second_job = GetMediaDecoderJob(false);
EXPECT_NE(first_job, second_job);
EXPECT_TRUE(second_job);
EXPECT_EQ(2, demuxer_->num_data_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_EQ(3, demuxer_->num_data_requests());
}
TEST_F(MediaSourcePlayerTest, NewSurfaceWhileChangingConfigs) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(false, false, 1);
MediaDecoderJob* first_job = GetMediaDecoderJob(false);
EXPECT_TRUE(first_job);
EXPECT_EQ(1, demuxer_->num_config_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
CreateNextTextureAndSetVideoSurface();
EXPECT_EQ(first_job, GetMediaDecoderJob(false));
player_.OnDemuxerConfigsAvailable(CreateVideoDemuxerConfigs());
MediaDecoderJob* second_job = GetMediaDecoderJob(false);
EXPECT_NE(first_job, second_job);
EXPECT_TRUE(second_job);
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_config_requests());
EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest,
BrowserSeek_DecoderStarvationWhilePendingSurfaceChange) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
DemuxerData data = CreateReadFromDemuxerAckForVideo();
player_.OnDemuxerDataAvailable(data);
CreateNextTextureAndSetVideoSurface();
TriggerPlayerStarvation();
WaitForVideoDecodeDone();
EXPECT_EQ(0, demuxer_->num_browser_seek_requests());
player_.OnDemuxerDataAvailable(data);
EXPECT_EQ(1, demuxer_->num_browser_seek_requests());
player_.OnDemuxerSeekDone(base::TimeDelta());
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_EQ(3, demuxer_->num_data_requests());
}
TEST_F(MediaSourcePlayerTest, ReleaseWithOnPrefetchDoneAlreadyPosted) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJob(true);
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
WaitForAudioDecodeDone();
player_.OnDemuxerDataAvailable(
CreateReadFromDemuxerAckWithConfigChanged(true, 4));
EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
TriggerPlayerStarvation();
OnNextTestDecodeCallbackPostTaskToReleasePlayer();
WaitForAudioDecodeDone();
EXPECT_TRUE(decoder_callback_hook_executed_);
EXPECT_EQ(2, demuxer_->num_data_requests());
StartAudioDecoderJob(true);
}
TEST_F(MediaSourcePlayerTest, SeekToThenReleaseThenDemuxerSeekAndDone) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJobAndSeekToWhileDecoding(
base::TimeDelta::FromMilliseconds(100));
ReleasePlayer();
EXPECT_EQ(1, demuxer_->num_seek_requests());
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_FALSE(GetMediaDecoderJob(true));
EXPECT_FALSE(player_.IsPlaying());
EXPECT_EQ(2, demuxer_->num_data_requests());
StartAudioDecoderJob(true);
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, SeekToThenReleaseThenDemuxerSeekThenStart) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJobAndSeekToWhileDecoding(
base::TimeDelta::FromMilliseconds(100));
ReleasePlayer();
EXPECT_EQ(1, demuxer_->num_seek_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
StartAudioDecoderJob(false);
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, SeekToThenDemuxerSeekThenReleaseThenSeekDone) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJobAndSeekToWhileDecoding(
base::TimeDelta::FromMilliseconds(100));
WaitForAudioDecodeDone();
EXPECT_EQ(1, demuxer_->num_seek_requests());
ReleasePlayer();
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_FALSE(player_.IsPlaying());
EXPECT_FALSE(GetMediaDecoderJob(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_EQ(2, demuxer_->num_data_requests());
StartAudioDecoderJob(true);
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, SeekToThenReleaseThenStart) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartAudioDecoderJobAndSeekToWhileDecoding(
base::TimeDelta::FromMilliseconds(100));
WaitForAudioDecodeDone();
EXPECT_EQ(1, demuxer_->num_seek_requests());
ReleasePlayer();
EXPECT_EQ(2, demuxer_->num_data_requests());
StartAudioDecoderJob(false);
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_TRUE(IsPrerolling(true));
EXPECT_EQ(100.0, GetPrerollTimestamp().InMillisecondsF());
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, ConfigChangedThenReleaseThenConfigsAvailable) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(true, true, 0);
ReleasePlayer();
player_.OnDemuxerConfigsAvailable(CreateAudioDemuxerConfigs(kCodecVorbis));
EXPECT_FALSE(GetMediaDecoderJob(true));
EXPECT_FALSE(player_.IsPlaying());
EXPECT_EQ(1, demuxer_->num_data_requests());
player_.Start();
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_TRUE(player_.IsPlaying());
EXPECT_EQ(2, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_config_requests());
}
TEST_F(MediaSourcePlayerTest, ConfigChangedThenReleaseThenStart) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
StartConfigChange(true, true, 0);
ReleasePlayer();
player_.Start();
EXPECT_TRUE(player_.IsPlaying());
EXPECT_FALSE(GetMediaDecoderJob(true));
EXPECT_EQ(1, demuxer_->num_data_requests());
player_.OnDemuxerConfigsAvailable(CreateAudioDemuxerConfigs(kCodecVorbis));
EXPECT_TRUE(GetMediaDecoderJob(true));
EXPECT_EQ(2, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_config_requests());
}
TEST_F(MediaSourcePlayerTest, BrowserSeek_ThenReleaseThenDemuxerSeekDone) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
BrowserSeekPlayer(false);
base::TimeDelta expected_preroll_timestamp = player_.GetCurrentTime();
ReleasePlayer();
player_.OnDemuxerSeekDone(expected_preroll_timestamp);
EXPECT_FALSE(player_.IsPlaying());
EXPECT_FALSE(GetMediaDecoderJob(false));
EXPECT_EQ(expected_preroll_timestamp, GetPrerollTimestamp());
EXPECT_EQ(2, demuxer_->num_data_requests());
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(true);
EXPECT_TRUE(IsPrerolling(false));
EXPECT_EQ(expected_preroll_timestamp, GetPrerollTimestamp());
EXPECT_EQ(expected_preroll_timestamp, player_.GetCurrentTime());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, BrowserSeek_ThenReleaseThenStart) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
BrowserSeekPlayer(false);
base::TimeDelta expected_preroll_timestamp = player_.GetCurrentTime();
ReleasePlayer();
EXPECT_EQ(2, demuxer_->num_data_requests());
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob(false);
player_.OnDemuxerSeekDone(expected_preroll_timestamp);
EXPECT_TRUE(GetMediaDecoderJob(false));
EXPECT_TRUE(IsPrerolling(false));
EXPECT_EQ(expected_preroll_timestamp, GetPrerollTimestamp());
EXPECT_EQ(expected_preroll_timestamp, player_.GetCurrentTime());
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest, SurfaceChangeClearedEvenIfMediaCryptoAbsent) {
SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
DemuxerConfigs configs = CreateVideoDemuxerConfigs();
configs.is_video_encrypted = true;
player_.OnDemuxerConfigsAvailable(configs);
CreateNextTextureAndSetVideoSurface();
EXPECT_FALSE(IsPendingSurfaceChange());
EXPECT_FALSE(GetMediaDecoderJob(false));
}
}