: message_loop_(message_loop),
playback_completed_(false),
num_resources_requested_(0),
+ num_metadata_changes_(0),
timestamp_updated_(false) {}
virtual ~MockMediaPlayerManager() {}
}
virtual void OnMediaMetadataChanged(
int player_id, base::TimeDelta duration, int width, int height,
- bool success) OVERRIDE {}
+ bool success) OVERRIDE {
+ num_metadata_changes_++;
+ }
virtual void OnPlaybackComplete(int player_id) OVERRIDE {
playback_completed_ = true;
if (message_loop_->is_running())
return num_resources_requested_;
}
+ int num_metadata_changes() const {
+ return num_metadata_changes_;
+ }
+
void OnMediaResourcesRequested(int player_id) {
num_resources_requested_++;
}
bool playback_completed_;
// The number of resource requests this object has seen.
int num_resources_requested_;
+ // The number of metadata changes reported by the player.
+ int num_metadata_changes_;
// Playback timestamp was updated.
bool timestamp_updated_;
DemuxerConfigs configs;
configs.video_codec = kCodecVP8;
configs.video_size =
- use_larger_size ? gfx::Size(640, 480) : gfx::Size(320, 240);
+ use_larger_size ? gfx::Size(640, 240) : gfx::Size(320, 240);
configs.is_video_encrypted = false;
configs.duration = kDefaultDuration;
return configs;
EXPECT_TRUE(false);
}
- AccessUnit CreateAccessUnitWithData(bool is_audio, int audio_packet_id) {
+ AccessUnit CreateAccessUnitWithData(bool is_audio, int audio_packet_id,
+ bool use_large_size_video) {
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");
+ scoped_refptr<DecoderBuffer> buffer;
+ if (is_audio) {
+ buffer = ReadTestDataFile(
+ base::StringPrintf("vorbis-packet-%d", audio_packet_id));
+ } else {
+ buffer = ReadTestDataFile(
+ use_large_size_video ? "vp8-I-frame-640x240" : "vp8-I-frame-320x240");
+ }
unit.data = std::vector<uint8>(
buffer->data(), buffer->data() + buffer->data_size());
DemuxerData data;
data.type = DemuxerStream::AUDIO;
data.access_units.resize(1);
- data.access_units[0] = CreateAccessUnitWithData(true, packet_id);
+ data.access_units[0] = CreateAccessUnitWithData(true, packet_id, false);
+
return data;
}
- DemuxerData CreateReadFromDemuxerAckForVideo() {
+ DemuxerData CreateReadFromDemuxerAckForVideo(bool use_large_size) {
DemuxerData data;
data.type = DemuxerStream::VIDEO;
data.access_units.resize(1);
- data.access_units[0] = CreateAccessUnitWithData(false, 0);
+ data.access_units[0] = CreateAccessUnitWithData(false, 0, use_large_size);
return data;
}
// |start_timestamp| must be smaller than |target_timestamp|.
EXPECT_LE(start_timestamp, target_timestamp);
DemuxerData data = is_audio ? CreateReadFromDemuxerAckForAudio(1) :
- CreateReadFromDemuxerAckForVideo();
+ CreateReadFromDemuxerAckForVideo(false);
int current_timestamp = start_timestamp.InMilliseconds();
// Send some data with access unit timestamps before the |target_timestamp|,
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[i] = CreateAccessUnitWithData(is_audio, i, false);
data.access_units[config_unit_index].status = DemuxerStream::kConfigChanged;
data.demuxer_configs.resize(1);
if (trigger_with_release_start) {
// Consume the first frame, so that the next VideoDecoderJob will not
// inherit the I-frame from the previous decoder.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
ReleasePlayer();
WaitForVideoDecodeDone();
// Simulate demuxer's response to the video data request. The data will be
// passed to the next MediaCodecBridge.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_FALSE(GetMediaCodecBridge(false));
EXPECT_FALSE(player_.IsPlaying());
EXPECT_EQ(expected_num_seek_requests, demuxer_->num_seek_requests());
message_loop_.RunUntilIdle();
} else {
// Simulate demuxer's response to the video data request.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
// While the decoder is decoding, trigger a browser seek by changing
// surface. Demuxer does not know of browser seek in advance, so no
// Wait for the media codec bridge to finish decoding and be reset pending
// the browser seek.
WaitForVideoDecodeDone();
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
}
// Only one browser seek should have been initiated, and no further data
if (is_audio) {
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
} else {
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EnableAdaptiveVideoPlayback(enable_adaptive_playback);
}
}
DemuxerConfigs configs = is_audio ?
- CreateAudioDemuxerConfigs(kCodecAAC, false) :
+ CreateAudioDemuxerConfigs(kCodecVorbis, true) :
CreateVideoDemuxerConfigs(true);
// Feed and decode access units with data for any units prior to
// |config_unit_index|, and a |kConfigChanged| unit at that index.
if (is_audio)
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
else
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(true));
// If the adaptive playback setting was not passed to the MediaCodecBridge
// earlier, do it here.
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
if (have_video)
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
// Run until more data is requested a number of times equal to the number of
// media types configured. Since prefetching may be in progress, we cannot
if (eos_video)
player_.OnDemuxerDataAvailable(CreateEOSAck(false));
else
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
}
player_.SeekTo(base::TimeDelta());
EXPECT_EQ(0, demuxer_->num_seek_requests());
// Send the first input chunk and verify that decoder will be created.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_TRUE(GetMediaCodecBridge(false));
WaitForVideoDecodeDone();
}
EXPECT_EQ(0, demuxer_->num_seek_requests());
EXPECT_EQ(1, demuxer_->num_data_requests());
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_FALSE(GetMediaCodecBridge(false));
}
player_.OnDemuxerSeekDone(kNoTimestamp());
EXPECT_FALSE(GetMediaCodecBridge(false));
EXPECT_EQ(1, demuxer_->num_data_requests());
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_TRUE(GetMediaCodecBridge(false));
// Reconfirm exactly 1 seek request has been made of demuxer, and that it
EXPECT_EQ(0, demuxer_->num_seek_requests());
// Send the first input chunk.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
// While the decoder is decoding, change multiple surfaces. Pass an empty
// surface first.
// Wait for the media codec bridge to finish decoding and be reset pending a
// browser seek.
WaitForVideoDecodeDone();
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
// Only one browser seek should have been initiated. No further data request
// should have been processed on |message_loop_| before surface change event
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(1, demuxer_->num_seek_requests());
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_TRUE(GetMediaCodecBridge(false));
WaitForVideoDecodeDone();
}
EXPECT_EQ(1, demuxer_->num_data_requests());
// Send the first input chunk.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
// While the decoder is decoding, pass an empty surface.
gfx::ScopedJavaSurface empty_surface;
// surface is empty.
EXPECT_EQ(0, demuxer_->num_browser_seek_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
// Playback resumes once a non-empty surface is passed.
CreateNextTextureAndSetVideoSurface();
// No resource is requested since there is no data to decode.
EXPECT_EQ(0, manager_.num_resources_requested());
ReleasePlayer();
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
// Recreate the video decoder.
CreateNextTextureAndSetVideoSurface();
EXPECT_EQ(1, demuxer_->num_seek_requests());
// Decoder is created after data is received.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_TRUE(GetMediaCodecBridge(false));
WaitForVideoDecodeDone();
}
EXPECT_FALSE(video_decoder_job->is_decoding());
// Sending video data to player, video decoder should not start.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_FALSE(video_decoder_job->is_decoding());
// Sending audio data to player, both decoders should start now.
StartVideoDecoderJob();
// Send the first input chunk.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
WaitForVideoDecodeDone();
VerifyPlaybackCompletesOnEOSDecode(true, false);
// starvation occurs during EOS decode.
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob();
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
WaitForVideoDecodeDone();
// Simulate decoder underrun to trigger prefetch while decoding EOS.
EXPECT_FALSE(GetMediaCodecBridge(false));
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(2, demuxer_->num_seek_requests());
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_TRUE(GetMediaCodecBridge(false));
WaitForVideoDecodeDone();
}
EXPECT_FALSE(GetMediaCodecBridge(false));
// No browser seek is needed.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_EQ(0, demuxer_->num_browser_seek_requests());
EXPECT_EQ(2, demuxer_->num_data_requests());
WaitForVideoDecodeDone();
base::TimeDelta seek_ack_position = base::TimeDelta::FromMilliseconds(70);
DemuxerData audio_data = CreateReadFromDemuxerAckForAudio(0);
audio_data.access_units[0].timestamp = seek_ack_position;
- DemuxerData video_data = CreateReadFromDemuxerAckForVideo();
+ DemuxerData video_data = CreateReadFromDemuxerAckForVideo(false);
video_data.access_units[0].timestamp = seek_ack_position;
player_.OnDemuxerDataAvailable(audio_data);
player_.OnDemuxerDataAvailable(video_data);
CreateNextTextureAndSetVideoSurface();
Start(CreateAudioVideoDemuxerConfigs());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_TRUE(GetMediaCodecBridge(true));
EXPECT_TRUE(GetMediaCodecBridge(false));
EnableAdaptiveVideoPlayback(false);
WaitForAudioVideoDecodeDone();
+ // If audio or video hasn't finished prerolling, let them finish it.
+ if (IsPrerolling(true))
+ PrerollDecoderToTime(true, base::TimeDelta(), base::TimeDelta(), true);
+ if (IsPrerolling(false))
+ PrerollDecoderToTime(false, base::TimeDelta(), base::TimeDelta(), false);
+ int expected_num_data_requests = demuxer_->num_data_requests();
+
// Simulate audio |kConfigChanged| prefetched as standalone access unit.
DemuxerConfigs audio_configs = CreateAudioDemuxerConfigs(kCodecVorbis, true);
player_.OnDemuxerDataAvailable(
player_.OnDemuxerDataAvailable(
CreateReadFromDemuxerAckWithConfigChanged(
false, 0, CreateVideoDemuxerConfigs(true)));
- EXPECT_EQ(6, demuxer_->num_data_requests());
+ EXPECT_EQ(expected_num_data_requests + 2, demuxer_->num_data_requests());
EXPECT_TRUE(IsDrainingDecoder(true));
EXPECT_TRUE(IsDrainingDecoder(false));
CreateNextTextureAndSetVideoSurface();
Start(CreateAudioVideoDemuxerConfigs());
player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0));
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
+ EXPECT_EQ(4, demuxer_->num_data_requests());
EXPECT_TRUE(GetMediaCodecBridge(true));
EXPECT_TRUE(GetMediaCodecBridge(false));
EnableAdaptiveVideoPlayback(true);
WaitForAudioVideoDecodeDone();
+ // If audio or video hasn't finished prerolling, let them finish it.
+ if (IsPrerolling(true))
+ PrerollDecoderToTime(true, base::TimeDelta(), base::TimeDelta(), true);
+ if (IsPrerolling(false))
+ PrerollDecoderToTime(false, base::TimeDelta(), base::TimeDelta(), false);
+ int expected_num_data_requests = demuxer_->num_data_requests();
+
// Simulate audio |kConfigChanged| prefetched as standalone access unit.
DemuxerConfigs audio_configs = CreateAudioDemuxerConfigs(kCodecVorbis, true);
player_.OnDemuxerDataAvailable(
player_.OnDemuxerDataAvailable(
CreateReadFromDemuxerAckWithConfigChanged(
false, 0, CreateVideoDemuxerConfigs(true)));
- EXPECT_EQ(6, demuxer_->num_data_requests());
+ EXPECT_EQ(expected_num_data_requests + 2, demuxer_->num_data_requests());
EXPECT_TRUE(IsDrainingDecoder(true));
EXPECT_FALSE(IsDrainingDecoder(false));
// received in OnDemuxerDataAvailable() ostensibly while
// |PREFETCH_DONE_EVENT_PENDING|.
StartConfigChange(true, true, 0, false);
+ WaitForAudioDecodeDone();
}
TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInPrefetchUnit1) {
// received in OnDemuxerDataAvailable() ostensibly while
// |PREFETCH_DONE_EVENT_PENDING|.
StartConfigChange(true, true, 1, false);
+ WaitForAudioDecodeDone();
}
TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInUnit0AfterPrefetch) {
// received in OnDemuxerDataAvailable() from data requested ostensibly while
// not prefetching.
StartConfigChange(true, false, 0, false);
+ WaitForAudioDecodeDone();
}
TEST_F(MediaSourcePlayerTest, DemuxerConfigRequestedIfInUnit1AfterPrefetch) {
// received in OnDemuxerDataAvailable() from data requested ostensibly while
// not prefetching.
StartConfigChange(true, false, 1, false);
+ WaitForAudioDecodeDone();
}
TEST_F(MediaSourcePlayerTest, BrowserSeek_PrerollAfterBrowserSeek) {
// 2 codecs should have been created, one before the config change, and one
// after it.
EXPECT_EQ(2, manager_.num_resources_requested());
+ WaitForVideoDecodeDone();
}
TEST_F(MediaSourcePlayerTest, VideoDemuxerConfigChangeWithAdaptivePlayback) {
// Only 1 codec should have been created so far.
EXPECT_EQ(1, manager_.num_resources_requested());
+ WaitForVideoDecodeDone();
}
TEST_F(MediaSourcePlayerTest, DecoderDrainInterruptedBySeek) {
WaitForVideoDecodeDone();
EXPECT_FALSE(IsDrainingDecoder(false));
- EXPECT_FALSE(GetMediaCodecBridge(false));
EXPECT_TRUE(player_.IsPlaying());
- EXPECT_EQ(3, demuxer_->num_data_requests());
- // Finish the browser seek introduced by surface change.
- player_.OnDemuxerSeekDone(base::TimeDelta());
+ // The frame after the config change should always be an iframe, so no browser
+ // seek is needed when recreating the video decoder due to surface change.
+ EXPECT_TRUE(GetMediaCodecBridge(false));
EXPECT_EQ(4, demuxer_->num_data_requests());
+ EXPECT_EQ(0, demuxer_->num_seek_requests());
}
TEST_F(MediaSourcePlayerTest,
// should not cause any crashes.
CreateNextTextureAndSetVideoSurface();
StartVideoDecoderJob();
- DemuxerData data = CreateReadFromDemuxerAckForVideo();
+ DemuxerData data = CreateReadFromDemuxerAckForVideo(false);
player_.OnDemuxerDataAvailable(data);
// Trigger a surface change and decoder starvation.
EXPECT_TRUE(player_.IsPlaying());
EXPECT_EQ(3, demuxer_->num_data_requests());
EXPECT_EQ(0, demuxer_->num_seek_requests());
+ WaitForAudioDecodeDone();
}
TEST_F(MediaSourcePlayerTest, BrowserSeek_ThenReleaseThenDemuxerSeekDone) {
EXPECT_EQ(1, demuxer_->num_seek_requests());
// Decoder will be created once data is received.
- player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo());
+ player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForVideo(false));
EXPECT_TRUE(GetMediaCodecBridge(false));
WaitForVideoDecodeDone();
}
DecodeAudioDataUntilOutputBecomesAvailable();
}
+TEST_F(MediaSourcePlayerTest, VideoMetadataChangeAfterConfigChange) {
+ SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE();
+
+ // Test that after a config change, metadata change will be happen
+ // after decoder is drained.
+ StartConfigChange(false, true, 2, false);
+ EXPECT_EQ(1, manager_.num_metadata_changes());
+ EXPECT_FALSE(IsDrainingDecoder(false));
+
+ // Create video data with new resolutions.
+ DemuxerData data = CreateReadFromDemuxerAckForVideo(true);
+
+ // Wait for the metadata change.
+ while(manager_.num_metadata_changes() == 1) {
+ player_.OnDemuxerDataAvailable(data);
+ WaitForVideoDecodeDone();
+ }
+ EXPECT_EQ(2, manager_.num_metadata_changes());
+ WaitForVideoDecodeDone();
+}
+
} // namespace media