// the frame rate is unstable. The duration used for the frame rate is
// based on wall clock time, not media time.
virtual void OnVideoFrameRateChange(absl::optional<int> fps) = 0;
+
+#if defined(TIZEN_MULTIMEDIA)
+ virtual void OnResourceConflict() = 0;
+#endif
};
virtual ~Pipeline() {}
void OnVideoNaturalSizeChange(const gfx::Size& size) final;
void OnVideoOpacityChange(bool opaque) final;
void OnVideoFrameRateChange(absl::optional<int> fps) final;
+#if defined(TIZEN_MULTIMEDIA)
+ void OnResourceConflict() final;
+ void OnRequestSeek(base::TimeDelta time) final;
+#endif
// Common handlers for notifications from renderers and demuxer.
void OnPipelineError(PipelineStatus error);
weak_pipeline_, config));
}
+#if defined(TIZEN_MULTIMEDIA)
+void PipelineImpl::RendererWrapper::OnResourceConflict() {
+ LOG(INFO) << __func__;
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PipelineImpl::OnResourceConflict, weak_pipeline_));
+}
+
+void PipelineImpl::RendererWrapper::OnRequestSeek(base::TimeDelta time) {
+ LOG(INFO) << __func__ << " time:" << time;
+
+ if (!media_task_runner_->BelongsToCurrentThread()) {
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&media::PipelineImpl::RendererWrapper::OnRequestSeek,
+ weak_factory_.GetWeakPtr(), time));
+ }
+
+ SetState(kSeeking);
+
+ SerialRunner::Queue bound_fns;
+ demuxer_->AbortPendingReads();
+ bound_fns.Push(
+ base::BindOnce(&Demuxer::Seek, base::Unretained(demuxer_), time));
+ pending_callbacks_ = SerialRunner::Run(
+ std::move(bound_fns), base::BindOnce(&RendererWrapper::CompleteSeek,
+ weak_factory_.GetWeakPtr(), time));
+}
+#endif
+
void PipelineImpl::RendererWrapper::OnPipelineError(PipelineStatus error) {
DCHECK(media_task_runner_->BelongsToCurrentThread());
DCHECK(!error.is_ok()) << "PIPELINE_OK isn't an error!";
client_->OnVideoPipelineInfoChange(info);
}
+#if defined(TIZEN_MULTIMEDIA)
+void PipelineImpl::OnResourceConflict() {
+ DVLOG(3) << __func__;
+ client_->OnResourceConflict();
+}
+#endif
+
void PipelineImpl::OnSeekDone(bool is_suspended) {
DVLOG(3) << __func__ << ": is_suspended=" << is_suspended;
DCHECK(thread_checker_.CalledOnValidThread());
void OnVideoPipelineInfoChange(const VideoPipelineInfo& info);
void OnRemotePlayStateChange(MediaStatus::State state);
void OnVideoFrameRateChange(absl::optional<int> fps);
+#if defined(TIZEN_MULTIMEDIA)
+ void OnResourceConflict();
+#endif
// Task completion callbacks from RendererWrapper.
void OnSeekDone(bool is_suspended);
// unset if the frame rate is unstable. The duration used for the frame rate
// is based on the wall clock time, not the media time.
virtual void OnVideoFrameRateChange(absl::optional<int> fps) = 0;
+
+#if defined(TIZEN_MULTIMEDIA)
+ virtual void OnResourceConflict() {}
+
+ virtual void OnRequestSeek(base::TimeDelta time) {}
+#endif
};
} // namespace media
}
#if defined(TIZEN_MULTIMEDIA)
+void MojoRenderer::OnResourceConflict() {
+ DVLOG(2) << __func__;
+ client_->OnResourceConflict();
+}
+
+void MojoRenderer::OnRequestSeek(base::TimeDelta time) {
+ DVLOG(2) << __func__ << "(" << time << ")";
+ client_->OnRequestSeek(time);
+}
+
void MojoRenderer::OnSeekCompleted() {
DVLOG(1) << __func__;
DCHECK(task_runner_->BelongsToCurrentThread());
void OnVideoOpacityChange(bool opaque) override;
void OnWaiting(WaitingReason reason) override;
void OnStatisticsUpdate(const PipelineStatistics& stats) override;
+#if defined(TIZEN_MULTIMEDIA)
+ void OnResourceConflict() override;
+ void OnRequestSeek(base::TimeDelta time) override;
+#endif
// Binds |remote_renderer_| to the mojo message pipe. Can be called multiple
// times. If an error occurs during connection, OnConnectionError will be
// Called when the remote rendering service is waiting for `reason`,
// e.g. waiting for decryption key.
OnWaiting(WaitingReason reason);
+
+ [EnableIf=tizen_multimedia]
+ OnResourceConflict();
+
+ [EnableIf=tizen_multimedia]
+ OnRequestSeek(mojo_base.mojom.TimeDelta time);
};
client_->OnVideoOpacityChange(opaque);
}
+#if defined(TIZEN_MULTIMEDIA)
+void MojoRendererService::OnResourceConflict() {
+ DVLOG(2) << __func__;
+ client_->OnResourceConflict();
+}
+
+void MojoRendererService::OnRequestSeek(base::TimeDelta time) {
+ DVLOG(2) << __func__ << "(" << time << ")";
+ client_->OnRequestSeek(time);
+}
+#endif
+
void MojoRendererService::OnVideoFrameRateChange(absl::optional<int> fps) {
DVLOG(2) << __func__ << "(" << (fps ? *fps : -1) << ")";
// TODO(liberato): plumb to |client_|.
void OnVideoNaturalSizeChange(const gfx::Size& size) final;
void OnVideoOpacityChange(bool opaque) final;
void OnVideoFrameRateChange(absl::optional<int> fps) final;
+#if defined(TIZEN_MULTIMEDIA)
+ void OnResourceConflict() final;
+ void OnRequestSeek(base::TimeDelta time) final;
+#endif
// Called when the MediaResourceShim is ready to go (has a config,
// pipe handle, etc) and can be handed off to a renderer for use.
UpdateSecondaryProperties();
}
+#if defined(TIZEN_MULTIMEDIA)
+void WebMediaPlayerImpl::OnResourceConflict() {
+ DVLOG(2) << __func__;
+ client_->PausePlayback(WebMediaPlayerClient::PauseReason::kUnknown);
+ SetSuspendState(true);
+}
+#endif
+
void WebMediaPlayerImpl::OnFrameHidden() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
void OnVideoAverageKeyframeDistanceUpdate() override;
void OnAudioPipelineInfoChange(const media::AudioPipelineInfo& info) override;
void OnVideoPipelineInfoChange(const media::VideoPipelineInfo& info) override;
+#if defined(TIZEN_MULTIMEDIA)
+ void OnResourceConflict() override;
+#endif
// Simplified watch time reporting.
void OnSimpleWatchTimerTick();
&TizenRendererImpl::OnNewFrameAvailable, base::Unretained(this)));
#endif
}
+
+ media_player_->SetResourceConflictCallback(base::BindRepeating(
+ &TizenRendererImpl::OnResourceConflict, base::Unretained(this)));
+
+ media_player_->SetRequestSeekCallback(base::BindRepeating(
+ &TizenRendererImpl::OnRequestSeek, base::Unretained(this)));
}
void TizenRendererImpl::SetCdm(media::CdmContext* cdm_context,
}
#endif
+void TizenRendererImpl::OnResourceConflict() {
+ client_->OnResourceConflict();
+}
+
+void TizenRendererImpl::OnRequestSeek(base::TimeDelta time) {
+ client_->OnRequestSeek(time);
+}
+
} // namespace content
void OnVideoOpacityChange(bool opaque);
void OnVideoFrameRateChange(absl::optional<int> fps);
+ void OnResourceConflict();
+ void OnRequestSeek(base::TimeDelta time);
+
media::RendererClient* client_;
State state_;
return;
}
+ if (MediaPlayerRegistry::GetInstance()->IsMediaPlayerPreparing()) {
+ LOG(WARNING) << "(" << static_cast<void*>(this) << ") " << __func__
+ << " Only one media player can be prepared."
+ << " Call ResourceConflict Callback.";
+ conflict_cb_.Run();
+ return;
+ }
+
#if defined(TIZEN_VIDEO_HOLE)
if (is_video_hole_ && video_plane_controller_) {
if (video_plane_controller_->Initialize() != TIZEN_ERROR_NONE) {
return;
}
is_preparing_ = true;
+ MediaPlayerRegistry::GetInstance()->SetIsPreparing(true);
}
bool MediaPlayerESPlusPlayer::IsPrepared() {
GetBufferQueue(DemuxerStream::VIDEO).clear();
GetBufferQueue(DemuxerStream::AUDIO).clear();
data_cb_.Reset();
+ conflict_cb_.Reset();
+ request_seek_cb_.Reset();
sink_ = nullptr;
if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE) {
base::OnceClosure seek_cb) {
// Ignore seek in release state. Will catch-up later.
if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE) {
+ LOG(INFO) << __func__ << " Ignore seek in release state.";
if (seek_cb)
std::move(seek_cb).Run();
return;
// Ignore seek to 0 during initialization.
if (GetPlayerState() < ESPLUSPLAYER_STATE_READY && time.InSecondsF() == 00) {
- if (seek_cb)
- std::move(seek_cb).Run();
- return;
- }
-
- if (time.FloorToMultiple(base::Seconds(0.1)) ==
- GetCurrentTime().FloorToMultiple(base::Seconds(0.1))) {
+ LOG(INFO) << __func__ << " Ignore seek to 0 during initialization.";
if (seek_cb)
std::move(seek_cb).Run();
return;
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " :"
<< time;
- seek_cb_ = std::move(seek_cb);
if (GetPlayerState() < ESPLUSPLAYER_STATE_READY || !is_prepared_) {
LOG(INFO) << "Add to pending seek ("
<< ") state: " << GetString(GetPlayerState())
std::move(seek_cb).Run();
return;
}
+ seek_cb_ = std::move(seek_cb);
+
SeekInternal(time);
}
packet.pts = buffer->timestamp().InMilliseconds();
packet.duration = buffer->duration().InMilliseconds();
+ LOG(INFO) << __func__ << " " << DemuxerStream::GetTypeName(type) << " : "
+ << "Pushing esplus timestamp: " << packet.pts
+ << ", duration: " << packet.duration
+ << ", size: " << packet.buffer_size
+ << ", is_key_frame: " << buffer->is_key_frame();
+
// This filed only set when PushMediaPacket
packet.matroska_color_info = nullptr;
esplusplayer_submit_status status =
}
void MediaPlayerESPlusPlayer::OnPrepareComplete(bool result) {
+ MediaPlayerRegistry::GetInstance()->SetIsPreparing(false);
+
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&MediaPlayerESPlusPlayer::OnPrepareComplete,
is_prepared_ = true;
if (pending_seek_) {
- SeekInternal(pending_seek_position_);
+ request_seek_cb_.Run(pending_seek_position_);
} else if (!is_paused_) {
Play();
}
}
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
- NOTIMPLEMENTED();
+ conflict_cb_.Run();
}
void MediaPlayerESPlusPlayer::OnError(const esplusplayer_error_type error) {
data_cb_ = datacb;
}
+void MediaPlayerESPlusPlayer::SetResourceConflictCallback(
+ const ResourceConflictCB& conflict_cb) {
+ conflict_cb_ = conflict_cb;
+}
+
+void MediaPlayerESPlusPlayer::SetRequestSeekCallback(
+ const RequestSeekCB& request_seek_cb) {
+ request_seek_cb_ = request_seek_cb;
+}
+
#if defined(TIZEN_VIDEO_HOLE)
void MediaPlayerESPlusPlayer::SetVideoHole(bool is_video_hole) {
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
uint32_t,
uint32_t)>;
#endif
+ using ResourceConflictCB = base::RepeatingCallback<void()>;
+ using RequestSeekCB = base::RepeatingCallback<void(base::TimeDelta)>;
bool CreatePlayer() override;
void Initialize(VideoRendererSink* sink) override;
base::TimeDelta GetCurrentTime() override;
void SetFrameAvailableCallback(const DataRequestCB& datacb) override;
+
+ void SetResourceConflictCallback(
+ const ResourceConflictCB& conflict_cb) override;
+ void SetRequestSeekCallback(const RequestSeekCB& request_seek_cb) override;
+
#if defined(TIZEN_VIDEO_HOLE)
void SetVideoHole(bool is_video_hole) override;
void SetMediaGeometry(const gfx::Rect& viewport_rect,
int player_id_ = 0;
DataRequestCB data_cb_;
+ ResourceConflictCB conflict_cb_;
+ RequestSeekCB request_seek_cb_;
VideoRendererSink* sink_;
return nullptr;
}
+bool MediaPlayerRegistry::IsMediaPlayerPreparing() {
+ return is_preparing_;
+}
+
+void MediaPlayerRegistry::SetIsPreparing(bool is_preparing) {
+ is_preparing_ = is_preparing;
+}
+
} // namespace media
MediaPlayerTizen* GetMediaPlayer(int player_id);
+ bool IsMediaPlayerPreparing();
+ void SetIsPreparing(bool is_preparing);
private:
MediaPlayerRegistry();
~MediaPlayerRegistry();
std::map<int, MediaPlayerTizen*> media_players_;
+ bool is_preparing_ = false;
+
friend struct base::DefaultSingletonTraits<MediaPlayerRegistry>;
};
uint32_t)>;
#endif
+ using ResourceConflictCB = base::RepeatingCallback<void()>;
+ using RequestSeekCB = base::RepeatingCallback<void(base::TimeDelta)>;
+
MediaPlayerTizen() {}
virtual ~MediaPlayerTizen() {}
virtual void SetVolume(double volume) = 0;
virtual base::TimeDelta GetCurrentTime() = 0;
+ virtual void SetResourceConflictCallback(
+ const ResourceConflictCB& conflict_cb) {}
+ virtual void SetRequestSeekCallback(const RequestSeekCB& pending_seek_cb) {}
+
// Will be replaced by |ClientExtention| interface.
virtual void SetFrameAvailableCallback(const DataRequestCB& datacb) = 0;