Commit 37e3ddb2 authored by wolenetz's avatar wolenetz Committed by Commit bot

MSE: Notify Blink SourceBuffer on init segment received

As the second of a three-sided set of change:
This change lays the groundwork for Blink to own the app-visible pieces
of the MSE initialization segment received algorithm. It lets
SourceState notify WebSourceBufferImpl upon parsing an initialization
segment. WSBI then notifies its WebSourceBufferClient.
Updated unit tests are included.

R=acolwell@chromium.org
TEST=No media_unittest regression
BUG=249428,397243

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

Cr-Commit-Position: refs/heads/master@{#294722}
parent 069fc881
...@@ -6,8 +6,12 @@ ...@@ -6,8 +6,12 @@
#include <limits> #include <limits>
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/float_util.h" #include "base/float_util.h"
#include "media/filters/chunk_demuxer.h" #include "media/filters/chunk_demuxer.h"
#include "third_party/WebKit/public/platform/WebSourceBufferClient.h"
namespace media { namespace media {
...@@ -34,12 +38,20 @@ WebSourceBufferImpl::WebSourceBufferImpl( ...@@ -34,12 +38,20 @@ WebSourceBufferImpl::WebSourceBufferImpl(
const std::string& id, ChunkDemuxer* demuxer) const std::string& id, ChunkDemuxer* demuxer)
: id_(id), : id_(id),
demuxer_(demuxer), demuxer_(demuxer),
client_(NULL),
append_window_end_(kInfiniteDuration()) { append_window_end_(kInfiniteDuration()) {
DCHECK(demuxer_); DCHECK(demuxer_);
} }
WebSourceBufferImpl::~WebSourceBufferImpl() { WebSourceBufferImpl::~WebSourceBufferImpl() {
DCHECK(!demuxer_) << "Object destroyed w/o removedFromMediaSource() call"; DCHECK(!demuxer_) << "Object destroyed w/o removedFromMediaSource() call";
DCHECK(!client_);
}
void WebSourceBufferImpl::setClient(blink::WebSourceBufferClient* client) {
DCHECK(client);
DCHECK(!client_);
client_ = client;
} }
bool WebSourceBufferImpl::setMode(WebSourceBuffer::AppendMode mode) { bool WebSourceBufferImpl::setMode(WebSourceBuffer::AppendMode mode) {
...@@ -76,7 +88,9 @@ void WebSourceBufferImpl::append( ...@@ -76,7 +88,9 @@ void WebSourceBufferImpl::append(
base::TimeDelta old_offset = timestamp_offset_; base::TimeDelta old_offset = timestamp_offset_;
demuxer_->AppendData(id_, data, length, demuxer_->AppendData(id_, data, length,
append_window_start_, append_window_end_, append_window_start_, append_window_end_,
&timestamp_offset_); &timestamp_offset_,
base::Bind(&WebSourceBufferImpl::InitSegmentReceived,
base::Unretained(this)));
// Coded frame processing may update the timestamp offset. If the caller // Coded frame processing may update the timestamp offset. If the caller
// provides a non-NULL |timestamp_offset| and frame processing changes the // provides a non-NULL |timestamp_offset| and frame processing changes the
...@@ -129,6 +143,12 @@ void WebSourceBufferImpl::setAppendWindowEnd(double end) { ...@@ -129,6 +143,12 @@ void WebSourceBufferImpl::setAppendWindowEnd(double end) {
void WebSourceBufferImpl::removedFromMediaSource() { void WebSourceBufferImpl::removedFromMediaSource() {
demuxer_->RemoveId(id_); demuxer_->RemoveId(id_);
demuxer_ = NULL; demuxer_ = NULL;
client_ = NULL;
}
void WebSourceBufferImpl::InitSegmentReceived() {
DVLOG(1) << __FUNCTION__;
client_->initializationSegmentReceived();
} }
} // namespace media } // namespace media
...@@ -21,6 +21,7 @@ class WebSourceBufferImpl : public blink::WebSourceBuffer { ...@@ -21,6 +21,7 @@ class WebSourceBufferImpl : public blink::WebSourceBuffer {
virtual ~WebSourceBufferImpl(); virtual ~WebSourceBufferImpl();
// blink::WebSourceBuffer implementation. // blink::WebSourceBuffer implementation.
virtual void setClient(blink::WebSourceBufferClient* client);
virtual bool setMode(AppendMode mode); virtual bool setMode(AppendMode mode);
virtual blink::WebTimeRanges buffered(); virtual blink::WebTimeRanges buffered();
virtual void append( virtual void append(
...@@ -35,9 +36,15 @@ class WebSourceBufferImpl : public blink::WebSourceBuffer { ...@@ -35,9 +36,15 @@ class WebSourceBufferImpl : public blink::WebSourceBuffer {
virtual void removedFromMediaSource(); virtual void removedFromMediaSource();
private: private:
// Demuxer callback handler to process an initialization segment received
// during an append() call.
void InitSegmentReceived();
std::string id_; std::string id_;
ChunkDemuxer* demuxer_; // Owned by WebMediaPlayerImpl. ChunkDemuxer* demuxer_; // Owned by WebMediaPlayerImpl.
blink::WebSourceBufferClient* client_;
// Controls the offset applied to timestamps when processing appended media // Controls the offset applied to timestamps when processing appended media
// segments. It is initially 0, which indicates that no offset is being // segments. It is initially 0, which indicates that no offset is being
// applied. Both setTimestampOffset() and append() may update this value. // applied. Both setTimestampOffset() and append() may update this value.
......
...@@ -90,6 +90,8 @@ class SourceState { ...@@ -90,6 +90,8 @@ class SourceState {
typedef base::Callback<ChunkDemuxerStream*( typedef base::Callback<ChunkDemuxerStream*(
DemuxerStream::Type)> CreateDemuxerStreamCB; DemuxerStream::Type)> CreateDemuxerStreamCB;
typedef ChunkDemuxer::InitSegmentReceivedCB InitSegmentReceivedCB;
typedef base::Callback<void( typedef base::Callback<void(
ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB;
...@@ -111,11 +113,14 @@ class SourceState { ...@@ -111,11 +113,14 @@ class SourceState {
// error occurred. |*timestamp_offset| is used and possibly updated by the // error occurred. |*timestamp_offset| is used and possibly updated by the
// append. |append_window_start| and |append_window_end| correspond to the MSE // append. |append_window_start| and |append_window_end| correspond to the MSE
// spec's similarly named source buffer attributes that are used in coded // spec's similarly named source buffer attributes that are used in coded
// frame processing. // frame processing. |init_segment_received_cb| is run for each new fully
bool Append(const uint8* data, size_t length, // parsed initialization segment.
bool Append(const uint8* data,
size_t length,
TimeDelta append_window_start, TimeDelta append_window_start,
TimeDelta append_window_end, TimeDelta append_window_end,
TimeDelta* timestamp_offset); TimeDelta* timestamp_offset,
const InitSegmentReceivedCB& init_segment_received_cb);
// Aborts the current append sequence and resets the parser. // Aborts the current append sequence and resets the parser.
void Abort(TimeDelta append_window_start, void Abort(TimeDelta append_window_start,
...@@ -232,6 +237,13 @@ class SourceState { ...@@ -232,6 +237,13 @@ class SourceState {
LogCB log_cb_; LogCB log_cb_;
StreamParser::InitCB init_cb_; StreamParser::InitCB init_cb_;
// During Append(), OnNewConfigs() will trigger the initialization segment
// received algorithm. This callback is only non-NULL during the lifetime of
// an Append() call. Note, the MSE spec explicitly disallows this algorithm
// during an Abort(), since Abort() is allowed only to emit coded frames, and
// only if the parser is PARSING_MEDIA_SEGMENT (not an INIT segment).
InitSegmentReceivedCB init_segment_received_cb_;
// Indicates that timestampOffset should be updated automatically during // Indicates that timestampOffset should be updated automatically during
// OnNewBuffers() based on the earliest end timestamp of the buffers provided. // OnNewBuffers() based on the earliest end timestamp of the buffers provided.
// TODO(wolenetz): Refactor this function while integrating April 29, 2014 // TODO(wolenetz): Refactor this function while integrating April 29, 2014
...@@ -300,20 +312,27 @@ void SourceState::SetGroupStartTimestampIfInSequenceMode( ...@@ -300,20 +312,27 @@ void SourceState::SetGroupStartTimestampIfInSequenceMode(
frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset); frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset);
} }
bool SourceState::Append(const uint8* data, size_t length, bool SourceState::Append(
TimeDelta append_window_start, const uint8* data,
TimeDelta append_window_end, size_t length,
TimeDelta* timestamp_offset) { TimeDelta append_window_start,
TimeDelta append_window_end,
TimeDelta* timestamp_offset,
const InitSegmentReceivedCB& init_segment_received_cb) {
DCHECK(timestamp_offset); DCHECK(timestamp_offset);
DCHECK(!timestamp_offset_during_append_); DCHECK(!timestamp_offset_during_append_);
DCHECK(!init_segment_received_cb.is_null());
DCHECK(init_segment_received_cb_.is_null());
append_window_start_during_append_ = append_window_start; append_window_start_during_append_ = append_window_start;
append_window_end_during_append_ = append_window_end; append_window_end_during_append_ = append_window_end;
timestamp_offset_during_append_ = timestamp_offset; timestamp_offset_during_append_ = timestamp_offset;
init_segment_received_cb_= init_segment_received_cb;
// TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with
// append window and timestamp offset pointer. See http://crbug.com/351454. // append window and timestamp offset pointer. See http://crbug.com/351454.
bool err = stream_parser_->Parse(data, length); bool err = stream_parser_->Parse(data, length);
timestamp_offset_during_append_ = NULL; timestamp_offset_during_append_ = NULL;
init_segment_received_cb_.Reset();
return err; return err;
} }
...@@ -534,6 +553,7 @@ bool SourceState::OnNewConfigs( ...@@ -534,6 +553,7 @@ bool SourceState::OnNewConfigs(
DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video
<< ", " << audio_config.IsValidConfig() << ", " << audio_config.IsValidConfig()
<< ", " << video_config.IsValidConfig() << ")"; << ", " << video_config.IsValidConfig() << ")";
DCHECK(!init_segment_received_cb_.is_null());
if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) {
DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!";
...@@ -676,6 +696,9 @@ bool SourceState::OnNewConfigs( ...@@ -676,6 +696,9 @@ bool SourceState::OnNewConfigs(
frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint(); frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint();
DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed");
if (success)
init_segment_received_cb_.Run();
return success; return success;
} }
...@@ -1238,15 +1261,19 @@ Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { ...@@ -1238,15 +1261,19 @@ Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
return itr->second->GetBufferedRanges(duration_, state_ == ENDED); return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
} }
void ChunkDemuxer::AppendData(const std::string& id, void ChunkDemuxer::AppendData(
const uint8* data, size_t length, const std::string& id,
TimeDelta append_window_start, const uint8* data,
TimeDelta append_window_end, size_t length,
TimeDelta* timestamp_offset) { TimeDelta append_window_start,
TimeDelta append_window_end,
TimeDelta* timestamp_offset,
const InitSegmentReceivedCB& init_segment_received_cb) {
DVLOG(1) << "AppendData(" << id << ", " << length << ")"; DVLOG(1) << "AppendData(" << id << ", " << length << ")";
DCHECK(!id.empty()); DCHECK(!id.empty());
DCHECK(timestamp_offset); DCHECK(timestamp_offset);
DCHECK(!init_segment_received_cb.is_null());
Ranges<TimeDelta> ranges; Ranges<TimeDelta> ranges;
...@@ -1269,7 +1296,8 @@ void ChunkDemuxer::AppendData(const std::string& id, ...@@ -1269,7 +1296,8 @@ void ChunkDemuxer::AppendData(const std::string& id,
if (!source_state_map_[id]->Append(data, length, if (!source_state_map_[id]->Append(data, length,
append_window_start, append_window_start,
append_window_end, append_window_end,
timestamp_offset)) { timestamp_offset,
init_segment_received_cb)) {
ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
return; return;
} }
...@@ -1280,7 +1308,8 @@ void ChunkDemuxer::AppendData(const std::string& id, ...@@ -1280,7 +1308,8 @@ void ChunkDemuxer::AppendData(const std::string& id,
if (!source_state_map_[id]->Append(data, length, if (!source_state_map_[id]->Append(data, length,
append_window_start, append_window_start,
append_window_end, append_window_end,
timestamp_offset)) { timestamp_offset,
init_segment_received_cb)) {
ReportError_Locked(PIPELINE_ERROR_DECODE); ReportError_Locked(PIPELINE_ERROR_DECODE);
return; return;
} }
......
...@@ -137,6 +137,8 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { ...@@ -137,6 +137,8 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
kReachedIdLimit, // Reached ID limit. We can't handle any more IDs. kReachedIdLimit, // Reached ID limit. We can't handle any more IDs.
}; };
typedef base::Closure InitSegmentReceivedCB;
// |open_cb| Run when Initialize() is called to signal that the demuxer // |open_cb| Run when Initialize() is called to signal that the demuxer
// is ready to receive media data via AppenData(). // is ready to receive media data via AppenData().
// |need_key_cb| Run when the demuxer determines that an encryption key is // |need_key_cb| Run when the demuxer determines that an encryption key is
...@@ -211,10 +213,13 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { ...@@ -211,10 +213,13 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
// |append_window_start| and |append_window_end| correspond to the MSE spec's // |append_window_start| and |append_window_end| correspond to the MSE spec's
// similarly named source buffer attributes that are used in coded frame // similarly named source buffer attributes that are used in coded frame
// processing. // processing.
// |init_segment_received_cb| is run for each newly successfully parsed
// initialization segment.
void AppendData(const std::string& id, const uint8* data, size_t length, void AppendData(const std::string& id, const uint8* data, size_t length,
base::TimeDelta append_window_start, base::TimeDelta append_window_start,
base::TimeDelta append_window_end, base::TimeDelta append_window_end,
base::TimeDelta* timestamp_offset); base::TimeDelta* timestamp_offset,
const InitSegmentReceivedCB& init_segment_received_cb);
// Aborts parsing the current segment and reset the parser to a state where // Aborts parsing the current segment and reset the parser to a state where
// it can accept a new segment. // it can accept a new segment.
......
...@@ -162,6 +162,9 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -162,6 +162,9 @@ class ChunkDemuxerTest : public ::testing::Test {
ChunkDemuxerTest() ChunkDemuxerTest()
: append_window_end_for_next_append_(kInfiniteDuration()) { : append_window_end_for_next_append_(kInfiniteDuration()) {
init_segment_received_cb_ =
base::Bind(&ChunkDemuxerTest::InitSegmentReceived,
base::Unretained(this));
CreateNewDemuxer(); CreateNewDemuxer();
} }
...@@ -573,7 +576,8 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -573,7 +576,8 @@ class ChunkDemuxerTest : public ::testing::Test {
demuxer_->AppendData(source_id, data, length, demuxer_->AppendData(source_id, data, length,
append_window_start_for_next_append_, append_window_start_for_next_append_,
append_window_end_for_next_append_, append_window_end_for_next_append_,
&timestamp_offset_map_[source_id]); &timestamp_offset_map_[source_id],
init_segment_received_cb_);
} }
void AppendDataInPieces(const uint8* data, size_t length) { void AppendDataInPieces(const uint8* data, size_t length) {
...@@ -664,6 +668,14 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -664,6 +668,14 @@ class ChunkDemuxerTest : public ::testing::Test {
expected_duration = kDefaultDuration(); expected_duration = kDefaultDuration();
EXPECT_CALL(*this, DemuxerOpened()); EXPECT_CALL(*this, DemuxerOpened());
// Adding expectation prior to CreateInitDoneCB() here because InSequence
// tests require init segment received before duration set. Also, only
// expect an init segment received callback if there is actually a track in
// it.
if (stream_flags != 0)
EXPECT_CALL(*this, InitSegmentReceived());
demuxer_->Initialize( demuxer_->Initialize(
&host_, CreateInitDoneCB(expected_duration, expected_status), true); &host_, CreateInitDoneCB(expected_duration, expected_status), true);
...@@ -696,7 +708,9 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -696,7 +708,9 @@ class ChunkDemuxerTest : public ::testing::Test {
video_flags |= HAS_TEXT; video_flags |= HAS_TEXT;
} }
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegmentWithSourceId(audio_id, audio_flags); AppendInitSegmentWithSourceId(audio_id, audio_flags);
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegmentWithSourceId(video_id, video_flags); AppendInitSegmentWithSourceId(video_id, video_flags);
return true; return true;
} }
...@@ -729,6 +743,9 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -729,6 +743,9 @@ class ChunkDemuxerTest : public ::testing::Test {
EXPECT_CALL(*this, DemuxerOpened()); EXPECT_CALL(*this, DemuxerOpened());
// Adding expectation prior to CreateInitDoneCB() here because InSequence
// tests require init segment received before duration set.
EXPECT_CALL(*this, InitSegmentReceived());
demuxer_->Initialize( demuxer_->Initialize(
&host_, CreateInitDoneCB(base::TimeDelta::FromMilliseconds(2744), &host_, CreateInitDoneCB(base::TimeDelta::FromMilliseconds(2744),
PIPELINE_OK), true); PIPELINE_OK), true);
...@@ -755,6 +772,7 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -755,6 +772,7 @@ class ChunkDemuxerTest : public ::testing::Test {
// media/test/data/bear-320x240-manifest.js which were // media/test/data/bear-320x240-manifest.js which were
// generated from media/test/data/bear-640x360.webm and // generated from media/test/data/bear-640x360.webm and
// media/test/data/bear-320x240.webm respectively. // media/test/data/bear-320x240.webm respectively.
EXPECT_CALL(*this, InitSegmentReceived());
AppendData(bear2->data(), 4340); AppendData(bear2->data(), 4340);
// Append a media segment that goes from [0.527000, 1.014000). // Append a media segment that goes from [0.527000, 1.014000).
...@@ -763,6 +781,7 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -763,6 +781,7 @@ class ChunkDemuxerTest : public ::testing::Test {
// Append initialization segment for bear1 & fill gap with [779-1197) // Append initialization segment for bear1 & fill gap with [779-1197)
// segment. // segment.
EXPECT_CALL(*this, InitSegmentReceived());
AppendData(bear1->data(), 4370); AppendData(bear1->data(), 4370);
AppendData(bear1->data() + 72737, 28183); AppendData(bear1->data() + 72737, 28183);
CheckExpectedRanges(kSourceId, "{ [0,2736) }"); CheckExpectedRanges(kSourceId, "{ [0,2736) }");
...@@ -1098,6 +1117,7 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -1098,6 +1117,7 @@ class ChunkDemuxerTest : public ::testing::Test {
// Read a WebM file into memory and send the data to the demuxer. // Read a WebM file into memory and send the data to the demuxer.
scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename); scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
EXPECT_CALL(*this, InitSegmentReceived());
AppendDataInPieces(buffer->data(), buffer->data_size(), 512); AppendDataInPieces(buffer->data(), buffer->data_size(), 512);
// Verify that the timestamps on the first few packets match what we // Verify that the timestamps on the first few packets match what we
...@@ -1142,6 +1162,8 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -1142,6 +1162,8 @@ class ChunkDemuxerTest : public ::testing::Test {
NeedKeyMock(type, init_data_ptr, init_data.size()); NeedKeyMock(type, init_data_ptr, init_data.size());
} }
MOCK_METHOD0(InitSegmentReceived, void(void));
void Seek(base::TimeDelta seek_time) { void Seek(base::TimeDelta seek_time) {
demuxer_->StartWaitingForSeek(seek_time); demuxer_->StartWaitingForSeek(seek_time);
demuxer_->Seek(seek_time, NewExpectedStatusCB(PIPELINE_OK)); demuxer_->Seek(seek_time, NewExpectedStatusCB(PIPELINE_OK));
...@@ -1166,6 +1188,7 @@ class ChunkDemuxerTest : public ::testing::Test { ...@@ -1166,6 +1188,7 @@ class ChunkDemuxerTest : public ::testing::Test {
MockDemuxerHost host_; MockDemuxerHost host_;
scoped_ptr<ChunkDemuxer> demuxer_; scoped_ptr<ChunkDemuxer> demuxer_;
ChunkDemuxer::InitSegmentReceivedCB init_segment_received_cb_;
base::TimeDelta append_window_start_for_next_append_; base::TimeDelta append_window_start_for_next_append_;
base::TimeDelta append_window_end_for_next_append_; base::TimeDelta append_window_end_for_next_append_;
...@@ -1348,10 +1371,12 @@ TEST_F(ChunkDemuxerTest, SingleTextTrackIdChange) { ...@@ -1348,10 +1371,12 @@ TEST_F(ChunkDemuxerTest, SingleTextTrackIdChange) {
CreateInitSegmentWithAlternateTextTrackNum(HAS_TEXT | HAS_AUDIO | HAS_VIDEO, CreateInitSegmentWithAlternateTextTrackNum(HAS_TEXT | HAS_AUDIO | HAS_VIDEO,
false, false, false, false,
&info_tracks, &info_tracks_size); &info_tracks, &info_tracks_size);
EXPECT_CALL(*this, InitSegmentReceived());
demuxer_->AppendData(kSourceId, info_tracks.get(), info_tracks_size, demuxer_->AppendData(kSourceId, info_tracks.get(), info_tracks_size,
append_window_start_for_next_append_, append_window_start_for_next_append_,
append_window_end_for_next_append_, append_window_end_for_next_append_,
&timestamp_offset_map_[kSourceId]); &timestamp_offset_map_[kSourceId],
init_segment_received_cb_);
AppendMuxedCluster( AppendMuxedCluster(
MuxedStreamInfo(kAudioTrackNum, "46K 69K"), MuxedStreamInfo(kAudioTrackNum, "46K 69K"),
...@@ -1389,6 +1414,7 @@ TEST_F(ChunkDemuxerTest, InitSegmentSetsNeedRandomAccessPointFlag) { ...@@ -1389,6 +1414,7 @@ TEST_F(ChunkDemuxerTest, InitSegmentSetsNeedRandomAccessPointFlag) {
MuxedStreamInfo(kTextTrackNum, "25K 40K")); MuxedStreamInfo(kTextTrackNum, "25K 40K"));
CheckExpectedRanges(kSourceId, "{ [23,46) }"); CheckExpectedRanges(kSourceId, "{ [23,46) }");
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegment(HAS_TEXT | HAS_AUDIO | HAS_VIDEO); AppendInitSegment(HAS_TEXT | HAS_AUDIO | HAS_VIDEO);
AppendMuxedCluster( AppendMuxedCluster(
MuxedStreamInfo(kAudioTrackNum, "46K 69K"), MuxedStreamInfo(kAudioTrackNum, "46K 69K"),
...@@ -1412,6 +1438,7 @@ TEST_F(ChunkDemuxerTest, Shutdown_BeforeAllInitSegmentsAppended) { ...@@ -1412,6 +1438,7 @@ TEST_F(ChunkDemuxerTest, Shutdown_BeforeAllInitSegmentsAppended) {
EXPECT_EQ(AddId("audio", HAS_AUDIO), ChunkDemuxer::kOk); EXPECT_EQ(AddId("audio", HAS_AUDIO), ChunkDemuxer::kOk);
EXPECT_EQ(AddId("video", HAS_VIDEO), ChunkDemuxer::kOk); EXPECT_EQ(AddId("video", HAS_VIDEO), ChunkDemuxer::kOk);
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegmentWithSourceId("audio", HAS_AUDIO); AppendInitSegmentWithSourceId("audio", HAS_AUDIO);
ShutdownDemuxer(); ShutdownDemuxer();
...@@ -1429,6 +1456,7 @@ TEST_F(ChunkDemuxerTest, Shutdown_BeforeAllInitSegmentsAppendedText) { ...@@ -1429,6 +1456,7 @@ TEST_F(ChunkDemuxerTest, Shutdown_BeforeAllInitSegmentsAppendedText) {
EXPECT_CALL(host_, AddTextStream(_, _)) EXPECT_CALL(host_, AddTextStream(_, _))
.Times(Exactly(1)); .Times(Exactly(1));
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegmentWithSourceId("video_and_text", HAS_VIDEO | HAS_TEXT); AppendInitSegmentWithSourceId("video_and_text", HAS_VIDEO | HAS_TEXT);
ShutdownDemuxer(); ShutdownDemuxer();
...@@ -1537,7 +1565,8 @@ TEST_F(ChunkDemuxerTest, AppendDataBeforeInit) { ...@@ -1537,7 +1565,8 @@ TEST_F(ChunkDemuxerTest, AppendDataBeforeInit) {
demuxer_->AppendData(kSourceId, info_tracks.get(), info_tracks_size, demuxer_->AppendData(kSourceId, info_tracks.get(), info_tracks_size,
append_window_start_for_next_append_, append_window_start_for_next_append_,
append_window_end_for_next_append_, append_window_end_for_next_append_,
&timestamp_offset_map_[kSourceId]); &timestamp_offset_map_[kSourceId],
init_segment_received_cb_);
} }
// Make sure Read() callbacks are dispatched with the proper data. // Make sure Read() callbacks are dispatched with the proper data.
...@@ -1573,7 +1602,8 @@ TEST_F(ChunkDemuxerTest, OutOfOrderClusters) { ...@@ -1573,7 +1602,8 @@ TEST_F(ChunkDemuxerTest, OutOfOrderClusters) {
demuxer_->AppendData(kSourceId, cluster_c->data(), cluster_c->size(), demuxer_->AppendData(kSourceId, cluster_c->data(), cluster_c->size(),
append_window_start_for_next_append_, append_window_start_for_next_append_,
append_window_end_for_next_append_, append_window_end_for_next_append_,
&timestamp_offset_map_[kSourceId]); &timestamp_offset_map_[kSourceId],
init_segment_received_cb_);
} }
TEST_F(ChunkDemuxerTest, NonMonotonicButAboveClusterTimecode) { TEST_F(ChunkDemuxerTest, NonMonotonicButAboveClusterTimecode) {
...@@ -1598,7 +1628,8 @@ TEST_F(ChunkDemuxerTest, NonMonotonicButAboveClusterTimecode) { ...@@ -1598,7 +1628,8 @@ TEST_F(ChunkDemuxerTest, NonMonotonicButAboveClusterTimecode) {
demuxer_->AppendData(kSourceId, cluster_b->data(), cluster_b->size(), demuxer_->AppendData(kSourceId, cluster_b->data(), cluster_b->size(),
append_window_start_for_next_append_, append_window_start_for_next_append_,
append_window_end_for_next_append_, append_window_end_for_next_append_,
&timestamp_offset_map_[kSourceId]); &timestamp_offset_map_[kSourceId],
init_segment_received_cb_);
} }
TEST_F(ChunkDemuxerTest, BackwardsAndBeforeClusterTimecode) { TEST_F(ChunkDemuxerTest, BackwardsAndBeforeClusterTimecode) {
...@@ -1623,7 +1654,8 @@ TEST_F(ChunkDemuxerTest, BackwardsAndBeforeClusterTimecode) { ...@@ -1623,7 +1654,8 @@ TEST_F(ChunkDemuxerTest, BackwardsAndBeforeClusterTimecode) {
demuxer_->AppendData(kSourceId, cluster_b->data(), cluster_b->size(), demuxer_->AppendData(kSourceId, cluster_b->data(), cluster_b->size(),
append_window_start_for_next_append_, append_window_start_for_next_append_,
append_window_end_for_next_append_, append_window_end_for_next_append_,
&timestamp_offset_map_[kSourceId]); &timestamp_offset_map_[kSourceId],
init_segment_received_cb_);
} }
...@@ -1934,6 +1966,7 @@ TEST_F(ChunkDemuxerTest, AppendingInPieces) { ...@@ -1934,6 +1966,7 @@ TEST_F(ChunkDemuxerTest, AppendingInPieces) {
memcpy(dst, cluster_b->data(), cluster_b->size()); memcpy(dst, cluster_b->data(), cluster_b->size());
dst += cluster_b->size(); dst += cluster_b->size();
EXPECT_CALL(*this, InitSegmentReceived());
AppendDataInPieces(buffer.get(), buffer_size); AppendDataInPieces(buffer.get(), buffer_size);
GenerateExpectedReads(0, 9); GenerateExpectedReads(0, 9);
...@@ -2092,7 +2125,8 @@ TEST_F(ChunkDemuxerTest, ParseErrorDuringInit) { ...@@ -2092,7 +2125,8 @@ TEST_F(ChunkDemuxerTest, ParseErrorDuringInit) {
demuxer_->AppendData(kSourceId, &tmp, 1, demuxer_->AppendData(kSourceId, &tmp, 1,
append_window_start_for_next_append_, append_window_start_for_next_append_,
append_window_end_for_next_append_, append_window_end_for_next_append_,
&timestamp_offset_map_[kSourceId]); &timestamp_offset_map_[kSourceId],
init_segment_received_cb_);
} }
TEST_F(ChunkDemuxerTest, AVHeadersWithAudioOnlyType) { TEST_F(ChunkDemuxerTest, AVHeadersWithAudioOnlyType) {
...@@ -2129,6 +2163,7 @@ TEST_F(ChunkDemuxerTest, MultipleHeaders) { ...@@ -2129,6 +2163,7 @@ TEST_F(ChunkDemuxerTest, MultipleHeaders) {
AppendCluster(kDefaultFirstCluster()); AppendCluster(kDefaultFirstCluster());
// Append another identical initialization segment. // Append another identical initialization segment.
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegment(HAS_AUDIO | HAS_VIDEO); AppendInitSegment(HAS_AUDIO | HAS_VIDEO);
AppendCluster(kDefaultSecondCluster()); AppendCluster(kDefaultSecondCluster());
...@@ -2183,6 +2218,7 @@ TEST_F(ChunkDemuxerTest, AddIdFailures) { ...@@ -2183,6 +2218,7 @@ TEST_F(ChunkDemuxerTest, AddIdFailures) {
// Adding an id with audio/video should fail because we already added audio. // Adding an id with audio/video should fail because we already added audio.
ASSERT_EQ(AddId(), ChunkDemuxer::kReachedIdLimit); ASSERT_EQ(AddId(), ChunkDemuxer::kReachedIdLimit);
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegmentWithSourceId(audio_id, HAS_AUDIO); AppendInitSegmentWithSourceId(audio_id, HAS_AUDIO);
// Adding an id after append should fail. // Adding an id after append should fail.
...@@ -2415,6 +2451,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_AudioIdOnly) { ...@@ -2415,6 +2451,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_AudioIdOnly) {
&host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK), true); &host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK), true);
ASSERT_EQ(AddId(kSourceId, HAS_AUDIO), ChunkDemuxer::kOk); ASSERT_EQ(AddId(kSourceId, HAS_AUDIO), ChunkDemuxer::kOk);
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegment(HAS_AUDIO); AppendInitSegment(HAS_AUDIO);
// Test a simple cluster. // Test a simple cluster.
...@@ -2437,6 +2474,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_VideoIdOnly) { ...@@ -2437,6 +2474,7 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_VideoIdOnly) {
&host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK), true); &host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK), true);
ASSERT_EQ(AddId(kSourceId, HAS_VIDEO), ChunkDemuxer::kOk); ASSERT_EQ(AddId(kSourceId, HAS_VIDEO), ChunkDemuxer::kOk);
EXPECT_CALL(*this, InitSegmentReceived());
AppendInitSegment(HAS_VIDEO); AppendInitSegment(HAS_VIDEO);
// Test a simple cluster. // Test a simple cluster.
...@@ -3015,6 +3053,7 @@ TEST_F(ChunkDemuxerTest, EmitBuffersDuringAbort) { ...@@ -3015,6 +3053,7 @@ TEST_F(ChunkDemuxerTest, EmitBuffersDuringAbort) {
// PTS: 353788 (0x000565fc) [= 90 kHz-Timestamp: 0:00:03.9309] // PTS: 353788 (0x000565fc) [= 90 kHz-Timestamp: 0:00:03.9309]
scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("bear-1280x720.ts"); scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("bear-1280x720.ts");
EXPECT_CALL(*this, InitSegmentReceived());
AppendData(kSourceId, buffer->data(), buffer->data_size()); AppendData(kSourceId, buffer->data(), buffer->data_size());
// Confirm we're in the middle of parsing a media segment. // Confirm we're in the middle of parsing a media segment.
...@@ -3058,6 +3097,7 @@ TEST_F(ChunkDemuxerTest, SeekCompleteDuringAbort) { ...@@ -3058,6 +3097,7 @@ TEST_F(ChunkDemuxerTest, SeekCompleteDuringAbort) {
// PTS: 353788 (0x000565fc) [= 90 kHz-Timestamp: 0:00:03.9309] // PTS: 353788 (0x000565fc) [= 90 kHz-Timestamp: 0:00:03.9309]
scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("bear-1280x720.ts"); scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("bear-1280x720.ts");
EXPECT_CALL(*this, InitSegmentReceived());
AppendData(kSourceId, buffer->data(), buffer->data_size()); AppendData(kSourceId, buffer->data(), buffer->data_size());
// Confirm we're in the middle of parsing a media segment. // Confirm we're in the middle of parsing a media segment.
...@@ -3447,6 +3487,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_WebMFile_AudioOnly) { ...@@ -3447,6 +3487,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_WebMFile_AudioOnly) {
// partial append window trim must come from a previous Append() call. // partial append window trim must come from a previous Append() call.
scoped_refptr<DecoderBuffer> buffer = scoped_refptr<DecoderBuffer> buffer =
ReadTestDataFile("bear-320x240-audio-only.webm"); ReadTestDataFile("bear-320x240-audio-only.webm");
EXPECT_CALL(*this, InitSegmentReceived());
AppendDataInPieces(buffer->data(), buffer->data_size(), 128); AppendDataInPieces(buffer->data(), buffer->data_size(), 128);
DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::AUDIO); DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::AUDIO);
...@@ -3473,6 +3514,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_AudioConfigUpdateRemovesPreroll) { ...@@ -3473,6 +3514,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_AudioConfigUpdateRemovesPreroll) {
// Read a WebM file into memory and append the data. // Read a WebM file into memory and append the data.
scoped_refptr<DecoderBuffer> buffer = scoped_refptr<DecoderBuffer> buffer =
ReadTestDataFile("bear-320x240-audio-only.webm"); ReadTestDataFile("bear-320x240-audio-only.webm");
EXPECT_CALL(*this, InitSegmentReceived());
AppendDataInPieces(buffer->data(), buffer->data_size(), 512); AppendDataInPieces(buffer->data(), buffer->data_size(), 512);
CheckExpectedRanges(kSourceId, "{ }"); CheckExpectedRanges(kSourceId, "{ }");
...@@ -3482,6 +3524,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_AudioConfigUpdateRemovesPreroll) { ...@@ -3482,6 +3524,7 @@ TEST_F(ChunkDemuxerTest, AppendWindow_AudioConfigUpdateRemovesPreroll) {
// Read a second WebM with a different config in and append the data. // Read a second WebM with a different config in and append the data.
scoped_refptr<DecoderBuffer> buffer2 = scoped_refptr<DecoderBuffer> buffer2 =
ReadTestDataFile("bear-320x240-audio-only-48khz.webm"); ReadTestDataFile("bear-320x240-audio-only-48khz.webm");
EXPECT_CALL(*this, InitSegmentReceived());
EXPECT_CALL(host_, SetDuration(_)).Times(AnyNumber()); EXPECT_CALL(host_, SetDuration(_)).Times(AnyNumber());
ASSERT_TRUE(SetTimestampOffset(kSourceId, duration_1)); ASSERT_TRUE(SetTimestampOffset(kSourceId, duration_1));
AppendDataInPieces(buffer2->data(), buffer2->data_size(), 512); AppendDataInPieces(buffer2->data(), buffer2->data_size(), 512);
......
...@@ -18,9 +18,11 @@ ...@@ -18,9 +18,11 @@
#include "media/cdm/json_web_key.h" #include "media/cdm/json_web_key.h"
#include "media/filters/chunk_demuxer.h" #include "media/filters/chunk_demuxer.h"
#include "media/filters/renderer_impl.h" #include "media/filters/renderer_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::_; using testing::_;
using testing::AnyNumber; using testing::AnyNumber;
using testing::AtLeast;
using testing::AtMost; using testing::AtMost;
using testing::SaveArg; using testing::SaveArg;
...@@ -432,7 +434,9 @@ class MockMediaSource { ...@@ -432,7 +434,9 @@ class MockMediaSource {
chunk_demuxer_->AppendData( chunk_demuxer_->AppendData(
kSourceId, file_data_->data() + current_position_, size, kSourceId, file_data_->data() + current_position_, size,
base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_); base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_,
base::Bind(&MockMediaSource::InitSegmentReceived,
base::Unretained(this)));
current_position_ += size; current_position_ += size;
} }
...@@ -442,7 +446,9 @@ class MockMediaSource { ...@@ -442,7 +446,9 @@ class MockMediaSource {
CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId)); CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
chunk_demuxer_->AppendData(kSourceId, pData, size, chunk_demuxer_->AppendData(kSourceId, pData, size,
base::TimeDelta(), kInfiniteDuration(), base::TimeDelta(), kInfiniteDuration(),
&timestamp_offset); &timestamp_offset,
base::Bind(&MockMediaSource::InitSegmentReceived,
base::Unretained(this)));
last_timestamp_offset_ = timestamp_offset; last_timestamp_offset_ = timestamp_offset;
} }
...@@ -457,7 +463,9 @@ class MockMediaSource { ...@@ -457,7 +463,9 @@ class MockMediaSource {
size, size,
append_window_start, append_window_start,
append_window_end, append_window_end,
&timestamp_offset); &timestamp_offset,
base::Bind(&MockMediaSource::InitSegmentReceived,
base::Unretained(this)));
last_timestamp_offset_ = timestamp_offset; last_timestamp_offset_ = timestamp_offset;
} }
...@@ -519,6 +527,8 @@ class MockMediaSource { ...@@ -519,6 +527,8 @@ class MockMediaSource {
return last_timestamp_offset_; return last_timestamp_offset_;
} }
MOCK_METHOD0(InitSegmentReceived, void(void));
private: private:
base::FilePath file_path_; base::FilePath file_path_;
scoped_refptr<DecoderBuffer> file_data_; scoped_refptr<DecoderBuffer> file_data_;
...@@ -536,6 +546,7 @@ class PipelineIntegrationTest ...@@ -536,6 +546,7 @@ class PipelineIntegrationTest
public PipelineIntegrationTestBase { public PipelineIntegrationTestBase {
public: public:
void StartPipelineWithMediaSource(MockMediaSource* source) { void StartPipelineWithMediaSource(MockMediaSource* source) {
EXPECT_CALL(*source, InitSegmentReceived()).Times(AtLeast(1));
EXPECT_CALL(*this, OnMetadata(_)) EXPECT_CALL(*this, OnMetadata(_))
.Times(AtMost(1)) .Times(AtMost(1))
.WillRepeatedly(SaveArg<0>(&metadata_)); .WillRepeatedly(SaveArg<0>(&metadata_));
......
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