Commit 44a866db authored by sergeyu@chromium.org's avatar sergeyu@chromium.org

Add live mode detection in WebM MediaSource parser.

The live mode is indicated by presense of DateUTC element and unknown
segment duration and size.

BUG=338529

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266452 0039d316-1c4b-4281-b951-d872f2087c98
parent 7f45a688
......@@ -44,6 +44,12 @@ class MEDIA_EXPORT DemuxerHost {
class MEDIA_EXPORT Demuxer {
public:
enum Liveness {
LIVENESS_UNKNOWN,
LIVENESS_RECORDED,
LIVENESS_LIVE,
};
// A new potentially encrypted stream has been parsed.
// First parameter - The type of initialization data.
// Second parameter - The initialization data associated with the stream.
......@@ -92,6 +98,9 @@ class MEDIA_EXPORT Demuxer {
// a null Time is returned.
virtual base::Time GetTimelineOffset() const = 0;
// Returns liveness of the stream, i.e. whether it is recorded or live.
virtual Liveness GetLiveness() const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Demuxer);
};
......
......@@ -40,6 +40,7 @@ class MockDemuxer : public Demuxer {
MOCK_METHOD1(GetStream, DemuxerStream*(DemuxerStream::Type));
MOCK_CONST_METHOD0(GetStartTime, base::TimeDelta());
MOCK_CONST_METHOD0(GetTimelineOffset, base::Time());
MOCK_CONST_METHOD0(GetLiveness, Liveness());
private:
DISALLOW_COPY_AND_ASSIGN(MockDemuxer);
......
......@@ -11,7 +11,8 @@ namespace media {
StreamParser::InitParameters::InitParameters(base::TimeDelta duration)
: duration(duration),
auto_update_timestamp_offset(false) {
auto_update_timestamp_offset(false),
liveness(Demuxer::LIVENESS_UNKNOWN) {
}
StreamParser::StreamParser() {}
......
......@@ -60,6 +60,9 @@ class MEDIA_EXPORT StreamParser {
// Indicates that timestampOffset should be updated based on the earliest
// end timestamp (audio or video) provided during each NewBuffersCB.
bool auto_update_timestamp_offset;
// Indicates live stream.
Demuxer::Liveness liveness;
};
// Indicates completion of parser initialization.
......
......@@ -974,6 +974,7 @@ ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb,
log_cb_(log_cb),
duration_(kNoTimestamp()),
user_specified_duration_(-1),
liveness_(LIVENESS_UNKNOWN),
splice_frames_enabled_(splice_frames_enabled) {
DCHECK(!open_cb_.is_null());
DCHECK(!need_key_cb_.is_null());
......@@ -1064,6 +1065,10 @@ base::Time ChunkDemuxer::GetTimelineOffset() const {
return timeline_offset_;
}
Demuxer::Liveness ChunkDemuxer::GetLiveness() const {
return liveness_;
}
void ChunkDemuxer::StartWaitingForSeek(TimeDelta seek_time) {
DVLOG(1) << "StartWaitingForSeek()";
base::AutoLock auto_lock(lock_);
......@@ -1508,6 +1513,17 @@ void ChunkDemuxer::OnSourceInitDone(
timeline_offset_ = params.timeline_offset;
}
if (params.liveness != LIVENESS_UNKNOWN) {
if (liveness_ != LIVENESS_UNKNOWN && params.liveness != liveness_) {
MEDIA_LOG(log_cb_)
<< "Liveness is not the same across all SourceBuffers.";
ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
return;
}
liveness_ = params.liveness;
}
// Wait until all streams have initialized.
if ((!source_id_audio_.empty() && !audio_) ||
(!source_id_video_.empty() && !video_)) {
......
......@@ -159,6 +159,7 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
virtual DemuxerStream* GetStream(DemuxerStream::Type type) OVERRIDE;
virtual base::TimeDelta GetStartTime() const OVERRIDE;
virtual base::Time GetTimelineOffset() const OVERRIDE;
virtual Liveness GetLiveness() const OVERRIDE;
// Methods used by an external object to control this demuxer.
//
......@@ -366,6 +367,7 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
double user_specified_duration_;
base::Time timeline_offset_;
Liveness liveness_;
typedef std::map<std::string, SourceState*> SourceStateMap;
SourceStateMap source_state_map_;
......
......@@ -394,6 +394,7 @@ FFmpegDemuxer::FFmpegDemuxer(
media_log_(media_log),
bitrate_(0),
start_time_(kNoTimestamp()),
liveness_(LIVENESS_UNKNOWN),
audio_disabled_(false),
text_enabled_(false),
duration_known_(false),
......@@ -506,6 +507,11 @@ base::Time FFmpegDemuxer::GetTimelineOffset() const {
return timeline_offset_;
}
Demuxer::Liveness FFmpegDemuxer::GetLiveness() const {
DCHECK(task_runner_->BelongsToCurrentThread());
return liveness_;
}
void FFmpegDemuxer::AddTextStreams() {
DCHECK(task_runner_->BelongsToCurrentThread());
......@@ -696,6 +702,14 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
timeline_offset_ = ExtractTimelineOffset(format_context);
if (max_duration == kInfiniteDuration() && !timeline_offset_.is_null()) {
liveness_ = LIVENESS_LIVE;
} else if (max_duration != kInfiniteDuration()) {
liveness_ = LIVENESS_RECORDED;
} else {
liveness_ = LIVENESS_UNKNOWN;
}
// Good to go: set the duration and bitrate and notify we're done
// initializing.
host_->SetDuration(max_duration);
......
......@@ -155,6 +155,7 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer {
virtual DemuxerStream* GetStream(DemuxerStream::Type type) OVERRIDE;
virtual base::TimeDelta GetStartTime() const OVERRIDE;
virtual base::Time GetTimelineOffset() const OVERRIDE;
virtual Liveness GetLiveness() const OVERRIDE;
// Calls |need_key_cb_| with the initialization data encountered in the file.
void FireNeedKey(const std::string& init_data_type,
......@@ -251,6 +252,9 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer {
// time if the file doesn't have an association to Time.
base::Time timeline_offset_;
// Liveness of the stream.
Liveness liveness_;
// Whether audio has been disabled for this demuxer (in which case this class
// drops packets destined for AUDIO demuxer streams on the floor).
bool audio_disabled_;
......
......@@ -20,6 +20,7 @@ namespace media {
WebMStreamParser::WebMStreamParser()
: state_(kWaitingForInit),
unknown_segment_size_(false),
parsing_cluster_(false) {
}
......@@ -150,6 +151,9 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
return result + element_size;
break;
case kWebMIdSegment:
// Segment of unknown size indicates live stream.
if (element_size == kWebMUnknownSize)
unknown_segment_size_ = true;
// Just consume the segment header.
return result;
break;
......@@ -190,6 +194,15 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
params.timeline_offset = info_parser.date_utc();
if (unknown_segment_size_ && (info_parser.duration() <= 0) &&
!info_parser.date_utc().is_null()) {
params.liveness = Demuxer::LIVENESS_LIVE;
} else if (info_parser.duration() >= 0) {
params.liveness = Demuxer::LIVENESS_RECORDED;
} else {
params.liveness = Demuxer::LIVENESS_UNKNOWN;
}
const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config();
if (audio_config.is_encrypted())
FireNeedKey(tracks_parser.audio_encryption_key_id());
......@@ -205,7 +218,6 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
return -1;
}
cluster_parser_.reset(new WebMClusterParser(
info_parser.timecode_scale(),
tracks_parser.audio_track_num(),
......
......@@ -76,6 +76,8 @@ class WebMStreamParser : public StreamParser {
base::Closure end_of_segment_cb_;
LogCB log_cb_;
bool unknown_segment_size_;
// True if a new cluster id has been seen and its end has not yet been parsed.
bool parsing_cluster_;
......
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