Skip to content

Commit

Permalink
Adding support for incremental cluster parsing.
Browse files Browse the repository at this point in the history
BUG=104160
TEST=Covered by ChunkDemuxer unittests.



Review URL: http://codereview.chromium.org/8775035

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114163 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
acolwell@chromium.org committed Dec 13, 2011
1 parent 375003a commit 7048540
Show file tree
Hide file tree
Showing 11 changed files with 796 additions and 267 deletions.
52 changes: 29 additions & 23 deletions media/filters/chunk_demuxer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ void ChunkDemuxerStream::Flush() {
bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const {
base::AutoLock auto_lock(lock_);

// If we haven't seen any buffers yet than anything can be added.
// If we haven't seen any buffers yet, then anything can be added.
if (last_buffer_timestamp_ == kNoTimestamp)
return true;

Expand Down Expand Up @@ -434,7 +434,7 @@ bool ChunkDemuxer::AppendData(const uint8* data, size_t length) {
int cur_size = 0;
int bytes_parsed = 0;
int result = -1;
bool parsed_a_cluster = false;
bool can_complete_seek = false;

byte_queue_.Peek(&cur, &cur_size);

Expand All @@ -449,16 +449,19 @@ bool ChunkDemuxer::AppendData(const uint8* data, size_t length) {
}
break;

case INITIALIZED:
result = ParseCluster_Locked(cur, cur_size);
case INITIALIZED: {
bool buffers_added = false;
result = ParseCluster_Locked(cur, cur_size, &buffers_added);
if (result < 0) {
VLOG(1) << "AppendData(): parsing data failed";
ReportError_Locked(PIPELINE_ERROR_DECODE);
return true;
}

parsed_a_cluster = (result > 0);
break;
// We can complete the seek if we have successfully parsed
// some data and buffers were added to one of the DemuxerStreams.
can_complete_seek |= (result > 0 && buffers_added);
} break;

case WAITING_FOR_INIT:
case ENDED:
Expand All @@ -477,7 +480,7 @@ bool ChunkDemuxer::AppendData(const uint8* data, size_t length) {

byte_queue_.Pop(bytes_parsed);

if (parsed_a_cluster && seek_waits_for_data_) {
if (can_complete_seek && seek_waits_for_data_) {
seek_waits_for_data_ = false;

if (!seek_cb_.is_null())
Expand Down Expand Up @@ -730,7 +733,8 @@ bool ChunkDemuxer::SetupStreams() {
return !no_supported_streams;
}

int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size) {
int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size,
bool* buffers_added) {
lock_.AssertAcquired();
if (!cluster_parser_.get())
return -1;
Expand All @@ -749,30 +753,32 @@ int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size) {
}
// Skip the element.
return result + element_size;
} else if (id != kWebMIdCluster) {
VLOG(1) << "Unexpected ID 0x" << std::hex << id;
return -1;
}

int bytes_parsed = cluster_parser_->Parse(data, size);

if (bytes_parsed <= 0)
return bytes_parsed;

// Make sure we can add the buffers to both streams before we actutally
// add them. This allows us to accept all of the data or none of it.
if ((audio_.get() &&
!audio_->CanAddBuffers(cluster_parser_->audio_buffers())) ||
(video_.get() &&
!video_->CanAddBuffers(cluster_parser_->video_buffers()))) {
return -1;
}
if (!cluster_parser_->audio_buffers().empty() ||
!cluster_parser_->video_buffers().empty()) {
// Make sure we can add the buffers to both streams before we actually
// add them. This allows us to accept all of the data or none of it.
if ((audio_.get() &&
!audio_->CanAddBuffers(cluster_parser_->audio_buffers())) ||
(video_.get() &&
!video_->CanAddBuffers(cluster_parser_->video_buffers()))) {
return -1;
}

if (audio_.get())
audio_->AddBuffers(cluster_parser_->audio_buffers());
if (audio_.get())
audio_->AddBuffers(cluster_parser_->audio_buffers());

if (video_.get())
video_->AddBuffers(cluster_parser_->video_buffers());
if (video_.get())
video_->AddBuffers(cluster_parser_->video_buffers());

*buffers_added = true;
}

// TODO(acolwell) : make this more representative of what is actually
// buffered.
Expand Down
11 changes: 8 additions & 3 deletions media/filters/chunk_demuxer.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,18 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
// found.
bool SetupStreams();

// Parse a cluster add add the buffers to the appropriate DemxuerStream.
// |data| is expected to point to the beginning of a cluster element.
// Parse a cluster and add the buffers to the appropriate DemuxerStream. This
// method also skips over CUES elements if it happens to encounter them.
//
// |data| is expected to point to the beginning of an element.
//
// |buffers_added| - Indicates whether Buffers were added to DemuxerStreams
// during the call. This is only valid if the return value > 0.
//
// Returns -1 if the parse fails.
// Returns 0 if more data is needed.
// Returns the number of bytes parsed on success.
int ParseCluster_Locked(const uint8* data, int size);
int ParseCluster_Locked(const uint8* data, int size, bool* buffers_added);

// Reports an error and puts the demuxer in a state where it won't accept more
// data.
Expand Down
1 change: 1 addition & 0 deletions media/media.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,7 @@
'video/capture/video_capture_device_unittest.cc',
'webm/cluster_builder.cc',
'webm/cluster_builder.h',
'webm/webm_parser_unittest.cc',
],
'conditions': [
['os_posix==1 and OS!="mac"', {
Expand Down
36 changes: 25 additions & 11 deletions media/webm/webm_cluster_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,33 @@ WebMClusterParser::WebMClusterParser(int64 timecode_scale,
audio_default_duration_(audio_default_duration),
video_track_num_(video_track_num),
video_default_duration_(video_default_duration),
parser_(kWebMIdCluster),
last_block_timecode_(-1),
cluster_timecode_(-1) {
}

WebMClusterParser::~WebMClusterParser() {}

int WebMClusterParser::Parse(const uint8* buf, int size) {
last_block_timecode_ = -1;
cluster_timecode_ = -1;
audio_buffers_.clear();
video_buffers_.clear();

return WebMParseListElement(buf, size, kWebMIdCluster, 1, this);
int result = parser_.Parse(buf, size, this);

if (result <= 0)
return result;

if (parser_.IsParsingComplete()) {
// Reset the parser if we're done parsing so that
// it is ready to accept another cluster on the next
// call.
parser_.Reset();

last_block_timecode_ = -1;
cluster_timecode_ = -1;
}

return result;
}

bool WebMClusterParser::OnListStart(int id) {
Expand Down Expand Up @@ -67,35 +81,35 @@ bool WebMClusterParser::OnUInt(int id, int64 val) {
}

bool WebMClusterParser::OnFloat(int id, double val) {
VLOG(1) << "Unexpected float element with ID " << std::hex << id;
DVLOG(1) << "Unexpected float element with ID " << std::hex << id;
return false;
}

bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) {
VLOG(1) << "Unexpected binary element with ID " << std::hex << id;
DVLOG(1) << "Unexpected binary element with ID " << std::hex << id;
return false;
}

bool WebMClusterParser::OnString(int id, const std::string& str) {
VLOG(1) << "Unexpected string element with ID " << std::hex << id;
DVLOG(1) << "Unexpected string element with ID " << std::hex << id;
return false;
}

bool WebMClusterParser::OnSimpleBlock(int track_num, int timecode,
int flags,
const uint8* data, int size) {
if (cluster_timecode_ == -1) {
VLOG(1) << "Got SimpleBlock before cluster timecode.";
DVLOG(1) << "Got SimpleBlock before cluster timecode.";
return false;
}

if (timecode < 0) {
VLOG(1) << "Got SimpleBlock with negative timecode offset " << timecode;
DVLOG(1) << "Got SimpleBlock with negative timecode offset " << timecode;
return false;
}

if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
VLOG(1) << "Got SimpleBlock with a timecode before the previous block.";
DVLOG(1) << "Got SimpleBlock with a timecode before the previous block.";
return false;
}

Expand All @@ -115,13 +129,13 @@ bool WebMClusterParser::OnSimpleBlock(int track_num, int timecode,
buffer->SetDuration(video_default_duration_);
queue = &video_buffers_;
} else {
VLOG(1) << "Unexpected track number " << track_num;
DVLOG(1) << "Unexpected track number " << track_num;
return false;
}

if (!queue->empty() &&
buffer->GetTimestamp() == queue->back()->GetTimestamp()) {
VLOG(1) << "Got SimpleBlock timecode is not strictly monotonically "
DVLOG(1) << "Got SimpleBlock timecode is not strictly monotonically "
<< "increasing for track " << track_num;
return false;
}
Expand Down
2 changes: 2 additions & 0 deletions media/webm/webm_cluster_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class WebMClusterParser : public WebMParserClient {
int video_track_num_;
base::TimeDelta video_default_duration_;

WebMListParser parser_;

int64 last_block_timecode_;

int64 cluster_timecode_;
Expand Down
2 changes: 2 additions & 0 deletions media/webm/webm_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ const int kWebMIdVideo = 0xE0;
const int kWebMIdVoid = 0xEC;
const int kWebMIdWritingApp = 0x5741;

const int64 kWebMUnknownSize = GG_LONGLONG(0x00FFFFFFFFFFFFFF);

// Default timecode scale if the TimecodeScale element is
// not specified in the INFO element.
const int kWebMDefaultTimecodeScale = 1000000;
Expand Down
18 changes: 14 additions & 4 deletions media/webm/webm_info_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ WebMInfoParser::WebMInfoParser()
WebMInfoParser::~WebMInfoParser() {}

int WebMInfoParser::Parse(const uint8* buf, int size) {
return WebMParseListElement(buf, size, kWebMIdInfo, 1, this);
timecode_scale_ = -1;
duration_ = -1;

WebMListParser parser(kWebMIdInfo);
int result = parser.Parse(buf, size, this);

if (result <= 0)
return result;

// For now we do all or nothing parsing.
return parser.IsParsingComplete() ? result : 0;
}

bool WebMInfoParser::OnListStart(int id) { return true; }
Expand All @@ -36,7 +46,7 @@ bool WebMInfoParser::OnUInt(int id, int64 val) {
return true;

if (timecode_scale_ != -1) {
VLOG(1) << "Multiple values for id " << std::hex << id << " specified";
DVLOG(1) << "Multiple values for id " << std::hex << id << " specified";
return false;
}

Expand All @@ -46,12 +56,12 @@ bool WebMInfoParser::OnUInt(int id, int64 val) {

bool WebMInfoParser::OnFloat(int id, double val) {
if (id != kWebMIdDuration) {
VLOG(1) << "Unexpected float for id" << std::hex << id;
DVLOG(1) << "Unexpected float for id" << std::hex << id;
return false;
}

if (duration_ != -1) {
VLOG(1) << "Multiple values for duration.";
DVLOG(1) << "Multiple values for duration.";
return false;
}

Expand Down
Loading

0 comments on commit 7048540

Please sign in to comment.