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 @@
#include <limits>
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/float_util.h"
#include "media/filters/chunk_demuxer.h"
#include "third_party/WebKit/public/platform/WebSourceBufferClient.h"
namespace media {
......@@ -34,12 +38,20 @@ WebSourceBufferImpl::WebSourceBufferImpl(
const std::string& id, ChunkDemuxer* demuxer)
: id_(id),
demuxer_(demuxer),
client_(NULL),
append_window_end_(kInfiniteDuration()) {
DCHECK(demuxer_);
}
WebSourceBufferImpl::~WebSourceBufferImpl() {
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) {
......@@ -76,7 +88,9 @@ void WebSourceBufferImpl::append(
base::TimeDelta old_offset = timestamp_offset_;
demuxer_->AppendData(id_, data, length,
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
// provides a non-NULL |timestamp_offset| and frame processing changes the
......@@ -129,6 +143,12 @@ void WebSourceBufferImpl::setAppendWindowEnd(double end) {
void WebSourceBufferImpl::removedFromMediaSource() {
demuxer_->RemoveId(id_);
demuxer_ = NULL;
client_ = NULL;
}
void WebSourceBufferImpl::InitSegmentReceived() {
DVLOG(1) << __FUNCTION__;
client_->initializationSegmentReceived();
}
} // namespace media
......@@ -21,6 +21,7 @@ class WebSourceBufferImpl : public blink::WebSourceBuffer {
virtual ~WebSourceBufferImpl();
// blink::WebSourceBuffer implementation.
virtual void setClient(blink::WebSourceBufferClient* client);
virtual bool setMode(AppendMode mode);
virtual blink::WebTimeRanges buffered();
virtual void append(
......@@ -35,9 +36,15 @@ class WebSourceBufferImpl : public blink::WebSourceBuffer {
virtual void removedFromMediaSource();
private:
// Demuxer callback handler to process an initialization segment received
// during an append() call.
void InitSegmentReceived();
std::string id_;
ChunkDemuxer* demuxer_; // Owned by WebMediaPlayerImpl.
blink::WebSourceBufferClient* client_;
// Controls the offset applied to timestamps when processing appended media
// segments. It is initially 0, which indicates that no offset is being
// applied. Both setTimestampOffset() and append() may update this value.
......
......@@ -90,6 +90,8 @@ class SourceState {
typedef base::Callback<ChunkDemuxerStream*(
DemuxerStream::Type)> CreateDemuxerStreamCB;
typedef ChunkDemuxer::InitSegmentReceivedCB InitSegmentReceivedCB;
typedef base::Callback<void(
ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB;
......@@ -111,11 +113,14 @@ class SourceState {
// error occurred. |*timestamp_offset| is used and possibly updated by the
// append. |append_window_start| and |append_window_end| correspond to the MSE
// spec's similarly named source buffer attributes that are used in coded
// frame processing.
bool Append(const uint8* data, size_t length,
// frame processing. |init_segment_received_cb| is run for each new fully
// parsed initialization segment.
bool Append(const uint8* data,
size_t length,
TimeDelta append_window_start,
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.
void Abort(TimeDelta append_window_start,
......@@ -232,6 +237,13 @@ class SourceState {
LogCB log_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
// OnNewBuffers() based on the earliest end timestamp of the buffers provided.
// TODO(wolenetz): Refactor this function while integrating April 29, 2014
......@@ -300,20 +312,27 @@ void SourceState::SetGroupStartTimestampIfInSequenceMode(
frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset);
}
bool SourceState::Append(const uint8* data, size_t length,
TimeDelta append_window_start,
TimeDelta append_window_end,
TimeDelta* timestamp_offset) {
bool SourceState::Append(
const uint8* data,
size_t length,
TimeDelta append_window_start,
TimeDelta append_window_end,
TimeDelta* timestamp_offset,
const InitSegmentReceivedCB& init_segment_received_cb) {
DCHECK(timestamp_offset);
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_end_during_append_ = append_window_end;
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
// append window and timestamp offset pointer. See http://crbug.com/351454.
bool err = stream_parser_->Parse(data, length);
timestamp_offset_during_append_ = NULL;
init_segment_received_cb_.Reset();
return err;
}
......@@ -534,6 +553,7 @@ bool SourceState::OnNewConfigs(
DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video
<< ", " << audio_config.IsValidConfig()
<< ", " << video_config.IsValidConfig() << ")";
DCHECK(!init_segment_received_cb_.is_null());
if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) {
DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!";
......@@ -676,6 +696,9 @@ bool SourceState::OnNewConfigs(
frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint();
DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed");
if (success)
init_segment_received_cb_.Run();
return success;
}
......@@ -1238,15 +1261,19 @@ Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
}
void ChunkDemuxer::AppendData(const std::string& id,
const uint8* data, size_t length,
TimeDelta append_window_start,
TimeDelta append_window_end,
TimeDelta* timestamp_offset) {
void ChunkDemuxer::AppendData(
const std::string& id,
const uint8* data,
size_t length,
TimeDelta append_window_start,
TimeDelta append_window_end,
TimeDelta* timestamp_offset,
const InitSegmentReceivedCB& init_segment_received_cb) {
DVLOG(1) << "AppendData(" << id << ", " << length << ")";
DCHECK(!id.empty());
DCHECK(timestamp_offset);
DCHECK(!init_segment_received_cb.is_null());
Ranges<TimeDelta> ranges;
......@@ -1269,7 +1296,8 @@ void ChunkDemuxer::AppendData(const std::string& id,
if (!source_state_map_[id]->Append(data, length,
append_window_start,
append_window_end,
timestamp_offset)) {
timestamp_offset,
init_segment_received_cb)) {
ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
return;
}
......@@ -1280,7 +1308,8 @@ void ChunkDemuxer::AppendData(const std::string& id,
if (!source_state_map_[id]->Append(data, length,
append_window_start,
append_window_end,
timestamp_offset)) {
timestamp_offset,
init_segment_received_cb)) {
ReportError_Locked(PIPELINE_ERROR_DECODE);
return;
}
......
......@@ -137,6 +137,8 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
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
// is ready to receive media data via AppenData().
// |need_key_cb| Run when the demuxer determines that an encryption key is
......@@ -211,10 +213,13 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
// |append_window_start| and |append_window_end| correspond to the MSE spec's
// similarly named source buffer attributes that are used in coded frame
// 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,
base::TimeDelta append_window_start,
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
// it can accept a new segment.
......
This diff is collapsed.
......@@ -18,9 +18,11 @@
#include "media/cdm/json_web_key.h"
#include "media/filters/chunk_demuxer.h"
#include "media/filters/renderer_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::_;
using testing::AnyNumber;
using testing::AtLeast;
using testing::AtMost;
using testing::SaveArg;
......@@ -432,7 +434,9 @@ class MockMediaSource {
chunk_demuxer_->AppendData(
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;
}
......@@ -442,7 +446,9 @@ class MockMediaSource {
CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
chunk_demuxer_->AppendData(kSourceId, pData, size,
base::TimeDelta(), kInfiniteDuration(),
&timestamp_offset);
&timestamp_offset,
base::Bind(&MockMediaSource::InitSegmentReceived,
base::Unretained(this)));
last_timestamp_offset_ = timestamp_offset;
}
......@@ -457,7 +463,9 @@ class MockMediaSource {
size,
append_window_start,
append_window_end,
&timestamp_offset);
&timestamp_offset,
base::Bind(&MockMediaSource::InitSegmentReceived,
base::Unretained(this)));
last_timestamp_offset_ = timestamp_offset;
}
......@@ -519,6 +527,8 @@ class MockMediaSource {
return last_timestamp_offset_;
}
MOCK_METHOD0(InitSegmentReceived, void(void));
private:
base::FilePath file_path_;
scoped_refptr<DecoderBuffer> file_data_;
......@@ -536,6 +546,7 @@ class PipelineIntegrationTest
public PipelineIntegrationTestBase {
public:
void StartPipelineWithMediaSource(MockMediaSource* source) {
EXPECT_CALL(*source, InitSegmentReceived()).Times(AtLeast(1));
EXPECT_CALL(*this, OnMetadata(_))
.Times(AtMost(1))
.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