Commit 5025fd8f authored by jiajia.qin's avatar jiajia.qin Committed by Commit bot

Report PIPELINE_ERROR_DECODE when SourceState::Append fails.

In old implementaion, when SourceState::Append failed, it will report
DEMUXER_ERROR_COULD_NOT_OPEN error in ChunkDemuxer::AppendData case INITIALIZING.
But in fact, appended data may include initialization segment and media segment both.
The error can happen in any point.
In MSE spec
( http://w3c.github.io/media-source/#byte-stream-formats )
The user agent must run the end of stream algorithm with the error parameter
set to "decode" when in some conditions. They all happen in parsing the appended data.
So, here when SourceState::Append fails, it should report PIPELINE_ERROR_DECODE.

Another side, when the segment parser loop successfully parses a complete
initialization segment, it should call ReportMetadata immediately. Otherwise,
when meeting PIPELINE_ERROR_DECODE but WebMediaPlayer's ready_state_ is still
ReadyStateHaveNothing, it will be treated as NetworkStateFormatError not
NetworkStateDecodeError.

This Cl will resolve above two problems.

BUG=None
TEST=LayoutTest: https://codereview.chromium.org/742653002

Review URL: https://codereview.chromium.org/710693003

Cr-Commit-Position: refs/heads/master@{#313358}
parent 5232fbbf
...@@ -39,7 +39,6 @@ Pipeline::Pipeline( ...@@ -39,7 +39,6 @@ Pipeline::Pipeline(
volume_(1.0f), volume_(1.0f),
playback_rate_(0.0f), playback_rate_(0.0f),
status_(PIPELINE_OK), status_(PIPELINE_OK),
is_initialized_(false),
state_(kCreated), state_(kCreated),
renderer_ended_(false), renderer_ended_(false),
text_renderer_ended_(false), text_renderer_ended_(false),
...@@ -335,16 +334,17 @@ void Pipeline::StateTransitionTask(PipelineStatus status) { ...@@ -335,16 +334,17 @@ void Pipeline::StateTransitionTask(PipelineStatus status) {
return InitializeDemuxer(done_cb); return InitializeDemuxer(done_cb);
case kInitRenderer: case kInitRenderer:
// When the state_ transfers to kInitRenderer, it means the demuxer has
// finished parsing the init info. It should call ReportMetadata in case
// meeting 'decode' error when passing media segment but WebMediaPlayer's
// ready_state_ is still ReadyStateHaveNothing. In that case, it will
// treat it as NetworkStateFormatError not NetworkStateDecodeError.
ReportMetadata();
start_timestamp_ = demuxer_->GetStartTime();
return InitializeRenderer(done_cb); return InitializeRenderer(done_cb);
case kPlaying: case kPlaying:
// Report metadata the first time we enter the playing state.
if (!is_initialized_) {
is_initialized_ = true;
ReportMetadata();
start_timestamp_ = demuxer_->GetStartTime();
}
DCHECK(start_timestamp_ >= base::TimeDelta()); DCHECK(start_timestamp_ >= base::TimeDelta());
renderer_->StartPlayingFrom(start_timestamp_); renderer_->StartPlayingFrom(start_timestamp_);
...@@ -730,14 +730,16 @@ void Pipeline::InitializeRenderer(const PipelineStatusCB& done_cb) { ...@@ -730,14 +730,16 @@ void Pipeline::InitializeRenderer(const PipelineStatusCB& done_cb) {
void Pipeline::ReportMetadata() { void Pipeline::ReportMetadata() {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
PipelineMetadata metadata; PipelineMetadata metadata;
metadata.has_audio = renderer_->HasAudio();
metadata.has_video = renderer_->HasVideo();
metadata.timeline_offset = demuxer_->GetTimelineOffset(); metadata.timeline_offset = demuxer_->GetTimelineOffset();
DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
if (stream) { if (stream) {
metadata.has_video = true;
metadata.natural_size = stream->video_decoder_config().natural_size(); metadata.natural_size = stream->video_decoder_config().natural_size();
metadata.video_rotation = stream->video_rotation(); metadata.video_rotation = stream->video_rotation();
} }
if (demuxer_->GetStream(DemuxerStream::AUDIO)) {
metadata.has_audio = true;
}
metadata_cb_.Run(metadata); metadata_cb_.Run(metadata);
} }
......
...@@ -336,8 +336,6 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost { ...@@ -336,8 +336,6 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost {
// The following data members are only accessed by tasks posted to // The following data members are only accessed by tasks posted to
// |task_runner_|. // |task_runner_|.
bool is_initialized_;
// Member that tracks the current state. // Member that tracks the current state.
State state_; State state_;
......
...@@ -423,6 +423,7 @@ TEST_F(PipelineTest, NoStreams) { ...@@ -423,6 +423,7 @@ TEST_F(PipelineTest, NoStreams) {
EXPECT_CALL(*demuxer_, Initialize(_, _, _)) EXPECT_CALL(*demuxer_, Initialize(_, _, _))
.WillOnce(PostCallback<1>(PIPELINE_OK)); .WillOnce(PostCallback<1>(PIPELINE_OK));
EXPECT_CALL(*demuxer_, Stop()); EXPECT_CALL(*demuxer_, Stop());
EXPECT_CALL(callbacks_, OnMetadata(_));
StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER); StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER);
} }
...@@ -867,6 +868,7 @@ class PipelineTeardownTest : public PipelineTest { ...@@ -867,6 +868,7 @@ class PipelineTeardownTest : public PipelineTest {
} }
EXPECT_CALL(*demuxer_, Stop()); EXPECT_CALL(*demuxer_, Stop());
EXPECT_CALL(callbacks_, OnMetadata(_));
return status; return status;
} }
......
...@@ -1348,18 +1348,7 @@ void ChunkDemuxer::AppendData( ...@@ -1348,18 +1348,7 @@ void ChunkDemuxer::AppendData(
switch (state_) { switch (state_) {
case INITIALIZING: case INITIALIZING:
DCHECK(IsValidId(id)); case INITIALIZED:
if (!source_state_map_[id]->Append(data, length,
append_window_start,
append_window_end,
timestamp_offset,
init_segment_received_cb)) {
ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
return;
}
break;
case INITIALIZED: {
DCHECK(IsValidId(id)); DCHECK(IsValidId(id));
if (!source_state_map_[id]->Append(data, length, if (!source_state_map_[id]->Append(data, length,
append_window_start, append_window_start,
...@@ -1369,7 +1358,7 @@ void ChunkDemuxer::AppendData( ...@@ -1369,7 +1358,7 @@ void ChunkDemuxer::AppendData(
ReportError_Locked(PIPELINE_ERROR_DECODE); ReportError_Locked(PIPELINE_ERROR_DECODE);
return; return;
} }
} break; break;
case PARSE_ERROR: case PARSE_ERROR:
DVLOG(1) << "AppendData(): Ignoring data after a parse error."; DVLOG(1) << "AppendData(): Ignoring data after a parse error.";
......
...@@ -667,7 +667,7 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -667,7 +667,7 @@ class ChunkDemuxerTest : public ::testing::Test {
int stream_flags, bool is_audio_encrypted, bool is_video_encrypted) { int stream_flags, bool is_audio_encrypted, bool is_video_encrypted) {
PipelineStatus expected_status = PipelineStatus expected_status =
(stream_flags != 0) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN; (stream_flags != 0) ? PIPELINE_OK : PIPELINE_ERROR_DECODE;
base::TimeDelta expected_duration = kNoTimestamp(); base::TimeDelta expected_duration = kNoTimestamp();
if (expected_status == PIPELINE_OK) if (expected_status == PIPELINE_OK)
...@@ -1687,7 +1687,7 @@ TEST_F(ChunkDemuxerTest, PerStreamMonotonicallyIncreasingTimestamps) { ...@@ -1687,7 +1687,7 @@ TEST_F(ChunkDemuxerTest, PerStreamMonotonicallyIncreasingTimestamps) {
TEST_F(ChunkDemuxerTest, ClusterBeforeInitSegment) { TEST_F(ChunkDemuxerTest, ClusterBeforeInitSegment) {
EXPECT_CALL(*this, DemuxerOpened()); EXPECT_CALL(*this, DemuxerOpened());
demuxer_->Initialize( demuxer_->Initialize(
&host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN), true); &host_, NewExpectedStatusCB(PIPELINE_ERROR_DECODE), true);
ASSERT_EQ(AddId(), ChunkDemuxer::kOk); ASSERT_EQ(AddId(), ChunkDemuxer::kOk);
...@@ -2127,7 +2127,7 @@ TEST_F(ChunkDemuxerTest, ParseErrorDuringInit) { ...@@ -2127,7 +2127,7 @@ TEST_F(ChunkDemuxerTest, ParseErrorDuringInit) {
EXPECT_CALL(*this, DemuxerOpened()); EXPECT_CALL(*this, DemuxerOpened());
demuxer_->Initialize( demuxer_->Initialize(
&host_, CreateInitDoneCB( &host_, CreateInitDoneCB(
kNoTimestamp(), DEMUXER_ERROR_COULD_NOT_OPEN), true); kNoTimestamp(), PIPELINE_ERROR_DECODE), true);
ASSERT_EQ(AddId(), ChunkDemuxer::kOk); ASSERT_EQ(AddId(), ChunkDemuxer::kOk);
...@@ -2143,7 +2143,7 @@ TEST_F(ChunkDemuxerTest, AVHeadersWithAudioOnlyType) { ...@@ -2143,7 +2143,7 @@ TEST_F(ChunkDemuxerTest, AVHeadersWithAudioOnlyType) {
EXPECT_CALL(*this, DemuxerOpened()); EXPECT_CALL(*this, DemuxerOpened());
demuxer_->Initialize( demuxer_->Initialize(
&host_, CreateInitDoneCB(kNoTimestamp(), &host_, CreateInitDoneCB(kNoTimestamp(),
DEMUXER_ERROR_COULD_NOT_OPEN), true); PIPELINE_ERROR_DECODE), true);
std::vector<std::string> codecs(1); std::vector<std::string> codecs(1);
codecs[0] = "vorbis"; codecs[0] = "vorbis";
...@@ -2157,7 +2157,7 @@ TEST_F(ChunkDemuxerTest, AVHeadersWithVideoOnlyType) { ...@@ -2157,7 +2157,7 @@ TEST_F(ChunkDemuxerTest, AVHeadersWithVideoOnlyType) {
EXPECT_CALL(*this, DemuxerOpened()); EXPECT_CALL(*this, DemuxerOpened());
demuxer_->Initialize( demuxer_->Initialize(
&host_, CreateInitDoneCB(kNoTimestamp(), &host_, CreateInitDoneCB(kNoTimestamp(),
DEMUXER_ERROR_COULD_NOT_OPEN), true); PIPELINE_ERROR_DECODE), true);
std::vector<std::string> codecs(1); std::vector<std::string> codecs(1);
codecs[0] = "vp8"; codecs[0] = "vp8";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment