This source file includes following definitions.
- LogMediaSourceError
- main_weak_this_
- Destroy
- IsVideoEncrypted
- StopDemuxer
- InitializeMediaSource
- InitializeDemuxer
- Buffered
- DecodedFrameCount
- DroppedFrameCount
- AudioDecodedByteCount
- VideoDecodedByteCount
- CancelPendingSeek
- StartWaitingForSeek
- Seek
- SeekInternal
- AddBufferedTimeRange
- SetDuration
- OnDurationChanged
- OnReadFromDemuxer
- ReadFromDemuxerStream
- OnBufferReady
- OnDemuxerError
- AddTextStream
- RemoveTextStream
- OnDemuxerInitDone
- InitAudioDecryptingDemuxerStream
- InitVideoDecryptingDemuxerStream
- OnAudioDecryptingDemuxerStreamInitDone
- OnVideoDecryptingDemuxerStreamInitDone
- OnDemuxerSeekDone
- ResetAudioDecryptingDemuxerStream
- ResetVideoDecryptingDemuxerStream
- FinishResettingDecryptingDemuxerStreams
- OnDemuxerStopDone
- DeleteSelf
- OnMediaConfigRequest
- CanNotifyDemuxerReady
- NotifyDemuxerReady
- GetDurationMs
- OnDemuxerOpened
- OnNeedKey
- IsSeeking
- FindBufferedBrowserSeekTime_Locked
#include "content/renderer/media/android/media_source_delegate.h"
#include <limits>
#include <string>
#include <vector>
#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/string_number_conversions.h"
#include "content/renderer/media/android/renderer_demuxer_android.h"
#include "content/renderer/media/webmediaplayer_util.h"
#include "content/renderer/media/webmediasource_impl.h"
#include "media/base/android/demuxer_stream_player_params.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_log.h"
#include "media/filters/chunk_demuxer.h"
#include "media/filters/decrypting_demuxer_stream.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
using media::DemuxerStream;
using media::DemuxerConfigs;
using media::DemuxerData;
using blink::WebMediaPlayer;
using blink::WebString;
namespace {
const size_t kAccessUnitSizeForMediaSource = 4;
const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff };
}
namespace content {
static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
const std::string& error) {
media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
}
MediaSourceDelegate::MediaSourceDelegate(
RendererDemuxerAndroid* demuxer_client,
int demuxer_client_id,
const scoped_refptr<base::MessageLoopProxy>& media_loop,
media::MediaLog* media_log)
: demuxer_client_(demuxer_client),
demuxer_client_id_(demuxer_client_id),
media_log_(media_log),
is_demuxer_ready_(false),
audio_stream_(NULL),
video_stream_(NULL),
seeking_(false),
is_video_encrypted_(false),
doing_browser_seek_(false),
browser_seek_time_(media::kNoTimestamp()),
expecting_regular_seek_(false),
access_unit_size_(0),
main_loop_(base::MessageLoopProxy::current()),
media_loop_(media_loop),
main_weak_factory_(this),
media_weak_factory_(this),
main_weak_this_(main_weak_factory_.GetWeakPtr()) {
DCHECK(main_loop_->BelongsToCurrentThread());
}
MediaSourceDelegate::~MediaSourceDelegate() {
DCHECK(main_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
DCHECK(!chunk_demuxer_);
DCHECK(!demuxer_client_);
DCHECK(!audio_decrypting_demuxer_stream_);
DCHECK(!video_decrypting_demuxer_stream_);
DCHECK(!audio_stream_);
DCHECK(!video_stream_);
}
void MediaSourceDelegate::Destroy() {
DCHECK(main_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
if (!chunk_demuxer_) {
DCHECK(!demuxer_client_);
delete this;
return;
}
duration_change_cb_.Reset();
update_network_state_cb_.Reset();
media_source_opened_cb_.Reset();
main_weak_factory_.InvalidateWeakPtrs();
DCHECK(!main_weak_factory_.HasWeakPtrs());
chunk_demuxer_->Shutdown();
media_loop_->PostTask(FROM_HERE,
base::Bind(&MediaSourceDelegate::StopDemuxer,
base::Unretained(this)));
}
bool MediaSourceDelegate::IsVideoEncrypted() {
DCHECK(main_loop_->BelongsToCurrentThread());
base::AutoLock auto_lock(is_video_encrypted_lock_);
return is_video_encrypted_;
}
void MediaSourceDelegate::StopDemuxer() {
DCHECK(media_loop_->BelongsToCurrentThread());
DCHECK(chunk_demuxer_);
demuxer_client_->RemoveDelegate(demuxer_client_id_);
demuxer_client_ = NULL;
audio_stream_ = NULL;
video_stream_ = NULL;
audio_decrypting_demuxer_stream_.reset();
video_decrypting_demuxer_stream_.reset();
media_weak_factory_.InvalidateWeakPtrs();
DCHECK(!media_weak_factory_.HasWeakPtrs());
chunk_demuxer_->Stop(base::Bind(&MediaSourceDelegate::OnDemuxerStopDone,
base::Unretained(this)));
}
void MediaSourceDelegate::InitializeMediaSource(
const MediaSourceOpenedCB& media_source_opened_cb,
const media::Demuxer::NeedKeyCB& need_key_cb,
const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
const UpdateNetworkStateCB& update_network_state_cb,
const DurationChangeCB& duration_change_cb) {
DCHECK(main_loop_->BelongsToCurrentThread());
DCHECK(!media_source_opened_cb.is_null());
media_source_opened_cb_ = media_source_opened_cb;
need_key_cb_ = need_key_cb;
set_decryptor_ready_cb_ = set_decryptor_ready_cb;
update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb);
duration_change_cb_ = duration_change_cb;
access_unit_size_ = kAccessUnitSizeForMediaSource;
chunk_demuxer_.reset(new media::ChunkDemuxer(
media::BindToCurrentLoop(
base::Bind(&MediaSourceDelegate::OnDemuxerOpened, main_weak_this_)),
media::BindToCurrentLoop(
base::Bind(&MediaSourceDelegate::OnNeedKey, main_weak_this_)),
base::Bind(&LogMediaSourceError, media_log_),
false));
media_loop_->PostTask(FROM_HERE,
base::Bind(&MediaSourceDelegate::InitializeDemuxer,
base::Unretained(this)));
}
void MediaSourceDelegate::InitializeDemuxer() {
DCHECK(media_loop_->BelongsToCurrentThread());
demuxer_client_->AddDelegate(demuxer_client_id_, this);
chunk_demuxer_->Initialize(this,
base::Bind(&MediaSourceDelegate::OnDemuxerInitDone,
media_weak_factory_.GetWeakPtr()),
false);
}
const blink::WebTimeRanges& MediaSourceDelegate::Buffered() {
buffered_web_time_ranges_ =
ConvertToWebTimeRanges(buffered_time_ranges_);
return buffered_web_time_ranges_;
}
size_t MediaSourceDelegate::DecodedFrameCount() const {
return statistics_.video_frames_decoded;
}
size_t MediaSourceDelegate::DroppedFrameCount() const {
return statistics_.video_frames_dropped;
}
size_t MediaSourceDelegate::AudioDecodedByteCount() const {
return statistics_.audio_bytes_decoded;
}
size_t MediaSourceDelegate::VideoDecodedByteCount() const {
return statistics_.video_bytes_decoded;
}
void MediaSourceDelegate::CancelPendingSeek(const base::TimeDelta& seek_time) {
DCHECK(main_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
<< demuxer_client_id_;
if (!chunk_demuxer_)
return;
{
base::AutoLock auto_lock(seeking_lock_);
expecting_regular_seek_ = true;
}
chunk_demuxer_->CancelPendingSeek(seek_time);
}
void MediaSourceDelegate::StartWaitingForSeek(
const base::TimeDelta& seek_time) {
DCHECK(main_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
<< demuxer_client_id_;
if (!chunk_demuxer_)
return;
bool cancel_browser_seek = false;
{
base::AutoLock auto_lock(seeking_lock_);
expecting_regular_seek_ = true;
if (seeking_) {
DCHECK(doing_browser_seek_);
cancel_browser_seek = true;
}
}
if (cancel_browser_seek)
chunk_demuxer_->CancelPendingSeek(seek_time);
chunk_demuxer_->StartWaitingForSeek(seek_time);
}
void MediaSourceDelegate::Seek(
const base::TimeDelta& seek_time, bool is_browser_seek) {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ", "
<< (is_browser_seek ? "browser seek" : "regular seek") << ") : "
<< demuxer_client_id_;
base::TimeDelta internal_seek_time = seek_time;
{
base::AutoLock auto_lock(seeking_lock_);
DCHECK(!seeking_);
seeking_ = true;
doing_browser_seek_ = is_browser_seek;
if (doing_browser_seek_ && (!chunk_demuxer_ || expecting_regular_seek_)) {
seeking_ = false;
doing_browser_seek_ = false;
demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time);
return;
}
if (doing_browser_seek_) {
internal_seek_time = FindBufferedBrowserSeekTime_Locked(seek_time);
browser_seek_time_ = internal_seek_time;
} else {
expecting_regular_seek_ = false;
browser_seek_time_ = media::kNoTimestamp();
}
}
if (is_browser_seek) {
chunk_demuxer_->CancelPendingSeek(internal_seek_time);
chunk_demuxer_->StartWaitingForSeek(internal_seek_time);
}
SeekInternal(internal_seek_time);
}
void MediaSourceDelegate::SeekInternal(const base::TimeDelta& seek_time) {
DCHECK(media_loop_->BelongsToCurrentThread());
DCHECK(IsSeeking());
chunk_demuxer_->Seek(seek_time, base::Bind(
&MediaSourceDelegate::OnDemuxerSeekDone,
media_weak_factory_.GetWeakPtr()));
}
void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start,
base::TimeDelta end) {
buffered_time_ranges_.Add(start, end);
}
void MediaSourceDelegate::SetDuration(base::TimeDelta duration) {
DCHECK(main_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << duration.InSecondsF() << ") : "
<< demuxer_client_id_;
main_loop_->PostTask(FROM_HERE, base::Bind(
&MediaSourceDelegate::OnDurationChanged, main_weak_this_, duration));
}
void MediaSourceDelegate::OnDurationChanged(const base::TimeDelta& duration) {
DCHECK(main_loop_->BelongsToCurrentThread());
if (demuxer_client_)
demuxer_client_->DurationChanged(demuxer_client_id_, duration);
if (!duration_change_cb_.is_null())
duration_change_cb_.Run(duration);
}
void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << type << ") : " << demuxer_client_id_;
if (IsSeeking())
return;
DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO);
DCHECK_GT(access_unit_size_, 0u);
scoped_ptr<DemuxerData> data(new DemuxerData());
data->type = type;
data->access_units.resize(access_unit_size_);
ReadFromDemuxerStream(type, data.Pass(), 0);
}
void MediaSourceDelegate::ReadFromDemuxerStream(media::DemuxerStream::Type type,
scoped_ptr<DemuxerData> data,
size_t index) {
DCHECK(media_loop_->BelongsToCurrentThread());
DemuxerStream* stream =
(type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_;
stream->Read(base::Bind(
&MediaSourceDelegate::OnBufferReady,
media_weak_factory_.GetWeakPtr(), type, base::Passed(&data), index));
}
void MediaSourceDelegate::OnBufferReady(
media::DemuxerStream::Type type,
scoped_ptr<DemuxerData> data,
size_t index,
DemuxerStream::Status status,
const scoped_refptr<media::DecoderBuffer>& buffer) {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << index << ", " << status << ", "
<< ((!buffer || buffer->end_of_stream()) ?
-1 : buffer->timestamp().InMilliseconds())
<< ") : " << demuxer_client_id_;
DCHECK(chunk_demuxer_);
if (IsSeeking()) {
DVLOG(1) << __FUNCTION__ << ": Ignore previous read during seeking.";
return;
}
bool is_audio = (type == DemuxerStream::AUDIO);
if (status != DemuxerStream::kAborted &&
index >= data->access_units.size()) {
LOG(ERROR) << "The internal state inconsistency onBufferReady: "
<< (is_audio ? "Audio" : "Video") << ", index " << index
<< ", size " << data->access_units.size()
<< ", status " << static_cast<int>(status);
NOTREACHED();
return;
}
switch (status) {
case DemuxerStream::kAborted:
DVLOG(1) << __FUNCTION__ << " : Aborted";
data->access_units[index].status = status;
data->access_units.resize(index + 1);
break;
case DemuxerStream::kConfigChanged:
if (is_audio) {
audio_stream_->audio_decoder_config();
} else {
gfx::Size size = video_stream_->video_decoder_config().coded_size();
DVLOG(1) << "Video config is changed: " << size.width() << "x"
<< size.height();
}
data->access_units[index].status = status;
data->access_units.resize(index + 1);
break;
case DemuxerStream::kOk:
data->access_units[index].status = status;
if (buffer->end_of_stream()) {
data->access_units[index].end_of_stream = true;
data->access_units.resize(index + 1);
break;
}
if (is_audio) {
statistics_.audio_bytes_decoded += buffer->data_size();
} else {
statistics_.video_bytes_decoded += buffer->data_size();
statistics_.video_frames_decoded++;
}
data->access_units[index].timestamp = buffer->timestamp();
data->access_units[index].data.assign(
buffer->data(), buffer->data() + buffer->data_size());
if (is_audio && media::kCodecVorbis ==
audio_stream_->audio_decoder_config().codec()) {
data->access_units[index].data.insert(
data->access_units[index].data.end(), kVorbisPadding,
kVorbisPadding + 4);
}
if (buffer->decrypt_config()) {
data->access_units[index].key_id = std::vector<char>(
buffer->decrypt_config()->key_id().begin(),
buffer->decrypt_config()->key_id().end());
data->access_units[index].iv = std::vector<char>(
buffer->decrypt_config()->iv().begin(),
buffer->decrypt_config()->iv().end());
data->access_units[index].subsamples =
buffer->decrypt_config()->subsamples();
}
if (++index < data->access_units.size()) {
ReadFromDemuxerStream(type, data.Pass(), index);
return;
}
break;
default:
NOTREACHED();
}
if (!IsSeeking() && demuxer_client_)
demuxer_client_->ReadFromDemuxerAck(demuxer_client_id_, *data);
}
void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) {
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null())
update_network_state_cb_.Run(PipelineErrorToNetworkState(status));
}
void MediaSourceDelegate::AddTextStream(
media::DemuxerStream* ,
const media::TextTrackConfig& ) {
NOTIMPLEMENTED();
}
void MediaSourceDelegate::RemoveTextStream(
media::DemuxerStream* ) {
NOTIMPLEMENTED();
}
void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
DCHECK(chunk_demuxer_);
if (status != media::PIPELINE_OK) {
OnDemuxerError(status);
return;
}
audio_stream_ = chunk_demuxer_->GetStream(DemuxerStream::AUDIO);
video_stream_ = chunk_demuxer_->GetStream(DemuxerStream::VIDEO);
if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() &&
!set_decryptor_ready_cb_.is_null()) {
InitAudioDecryptingDemuxerStream();
return;
}
if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() &&
!set_decryptor_ready_cb_.is_null()) {
InitVideoDecryptingDemuxerStream();
return;
}
is_demuxer_ready_ = true;
if (CanNotifyDemuxerReady())
NotifyDemuxerReady();
}
void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
DCHECK(!set_decryptor_ready_cb_.is_null());
audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
media_loop_, set_decryptor_ready_cb_));
audio_decrypting_demuxer_stream_->Initialize(
audio_stream_,
base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
media_weak_factory_.GetWeakPtr()));
}
void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
DCHECK(!set_decryptor_ready_cb_.is_null());
video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
media_loop_, set_decryptor_ready_cb_));
video_decrypting_demuxer_stream_->Initialize(
video_stream_,
base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
media_weak_factory_.GetWeakPtr()));
}
void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone(
media::PipelineStatus status) {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
DCHECK(chunk_demuxer_);
if (status != media::PIPELINE_OK)
audio_decrypting_demuxer_stream_.reset();
else
audio_stream_ = audio_decrypting_demuxer_stream_.get();
if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) {
InitVideoDecryptingDemuxerStream();
return;
}
is_demuxer_ready_ = true;
if (CanNotifyDemuxerReady())
NotifyDemuxerReady();
}
void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone(
media::PipelineStatus status) {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
DCHECK(chunk_demuxer_);
if (status != media::PIPELINE_OK)
video_decrypting_demuxer_stream_.reset();
else
video_stream_ = video_decrypting_demuxer_stream_.get();
is_demuxer_ready_ = true;
if (CanNotifyDemuxerReady())
NotifyDemuxerReady();
}
void MediaSourceDelegate::OnDemuxerSeekDone(media::PipelineStatus status) {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
DCHECK(IsSeeking());
if (status != media::PIPELINE_OK) {
OnDemuxerError(status);
return;
}
ResetAudioDecryptingDemuxerStream();
}
void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
if (audio_decrypting_demuxer_stream_) {
audio_decrypting_demuxer_stream_->Reset(
base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream,
media_weak_factory_.GetWeakPtr()));
return;
}
ResetVideoDecryptingDemuxerStream();
}
void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
if (video_decrypting_demuxer_stream_) {
video_decrypting_demuxer_stream_->Reset(base::Bind(
&MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams,
media_weak_factory_.GetWeakPtr()));
return;
}
FinishResettingDecryptingDemuxerStreams();
}
void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
base::AutoLock auto_lock(seeking_lock_);
DCHECK(seeking_);
seeking_ = false;
doing_browser_seek_ = false;
demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_);
}
void MediaSourceDelegate::OnDemuxerStopDone() {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
main_loop_->PostTask(
FROM_HERE,
base::Bind(&MediaSourceDelegate::DeleteSelf, base::Unretained(this)));
}
void MediaSourceDelegate::DeleteSelf() {
DCHECK(main_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
chunk_demuxer_.reset();
delete this;
}
void MediaSourceDelegate::OnMediaConfigRequest() {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
if (CanNotifyDemuxerReady())
NotifyDemuxerReady();
}
bool MediaSourceDelegate::CanNotifyDemuxerReady() {
DCHECK(media_loop_->BelongsToCurrentThread());
return is_demuxer_ready_;
}
void MediaSourceDelegate::NotifyDemuxerReady() {
DCHECK(media_loop_->BelongsToCurrentThread());
DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
DCHECK(CanNotifyDemuxerReady());
scoped_ptr<DemuxerConfigs> configs(new DemuxerConfigs());
if (audio_stream_) {
media::AudioDecoderConfig config = audio_stream_->audio_decoder_config();
configs->audio_codec = config.codec();
configs->audio_channels =
media::ChannelLayoutToChannelCount(config.channel_layout());
configs->audio_sampling_rate = config.samples_per_second();
configs->is_audio_encrypted = config.is_encrypted();
configs->audio_extra_data = std::vector<uint8>(
config.extra_data(), config.extra_data() + config.extra_data_size());
}
if (video_stream_) {
media::VideoDecoderConfig config = video_stream_->video_decoder_config();
configs->video_codec = config.codec();
configs->video_size = config.natural_size();
configs->is_video_encrypted = config.is_encrypted();
configs->video_extra_data = std::vector<uint8>(
config.extra_data(), config.extra_data() + config.extra_data_size());
}
configs->duration_ms = GetDurationMs();
if (demuxer_client_)
demuxer_client_->DemuxerReady(demuxer_client_id_, *configs);
base::AutoLock auto_lock(is_video_encrypted_lock_);
is_video_encrypted_ = configs->is_video_encrypted;
}
int MediaSourceDelegate::GetDurationMs() {
DCHECK(media_loop_->BelongsToCurrentThread());
if (!chunk_demuxer_)
return -1;
double duration_ms = chunk_demuxer_->GetDuration() * 1000;
if (duration_ms > std::numeric_limits<int32>::max()) {
LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably "
"something has gone wrong.";
return std::numeric_limits<int32>::max();
}
return duration_ms;
}
void MediaSourceDelegate::OnDemuxerOpened() {
DCHECK(main_loop_->BelongsToCurrentThread());
if (media_source_opened_cb_.is_null())
return;
media_source_opened_cb_.Run(new WebMediaSourceImpl(
chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
}
void MediaSourceDelegate::OnNeedKey(const std::string& type,
const std::vector<uint8>& init_data) {
DCHECK(main_loop_->BelongsToCurrentThread());
if (need_key_cb_.is_null())
return;
need_key_cb_.Run(type, init_data);
}
bool MediaSourceDelegate::IsSeeking() const {
base::AutoLock auto_lock(seeking_lock_);
return seeking_;
}
base::TimeDelta MediaSourceDelegate::FindBufferedBrowserSeekTime_Locked(
const base::TimeDelta& seek_time) const {
seeking_lock_.AssertAcquired();
DCHECK(seeking_);
DCHECK(doing_browser_seek_);
DCHECK(chunk_demuxer_) << "Browser seek requested, but no chunk demuxer";
media::Ranges<base::TimeDelta> buffered =
chunk_demuxer_->GetBufferedRanges();
for (size_t i = 0; i < buffered.size(); ++i) {
base::TimeDelta range_start = buffered.start(i);
base::TimeDelta range_end = buffered.end(i);
if (range_start <= seek_time) {
if (range_end >= seek_time)
return seek_time;
continue;
}
if ((range_start - seek_time) > base::TimeDelta::FromMilliseconds(100))
break;
return range_start;
}
return seek_time;
}
}