#ifndef MEDIA_RENDERERS_RENDERER_IMPL_H_
#define MEDIA_RENDERERS_RENDERER_IMPL_H_
#include <memory>
#include <vector>
#include "base/cancelable_callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/clock.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/buffering_state.h"
#include "media/base/decryptor.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_export.h"
#include "media/base/pipeline_status.h"
#include "media/base/renderer.h"
#include "media/base/tuneable.h"
#include "media/base/video_decoder_config.h"
#include "media/base/waiting.h"
#include "ui/gfx/geometry/size.h"
namespace media {
class AudioRenderer;
class MediaResource;
class TimeSource;
class VideoRenderer;
class WallClockTimeSource;
class MEDIA_EXPORT RendererImpl final : public Renderer {
public:
RendererImpl(const scoped_refptr<base::SequencedTaskRunner>& task_runner,
std::unique_ptr<AudioRenderer> audio_renderer,
std::unique_ptr<VideoRenderer> video_renderer);
RendererImpl(const RendererImpl&) = delete;
RendererImpl& operator=(const RendererImpl&) = delete;
~RendererImpl() final;
void Initialize(MediaResource* media_resource,
RendererClient* client,
#if BUILDFLAG(ARKWEB_VIDEO_ASSISTANT)
RequestSurfaceCB request_surface_cb,
VideoDecoderChangedCB decoder_changed_cb,
#endif
PipelineStatusCallback init_cb) final;
void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) final;
void SetLatencyHint(std::optional<base::TimeDelta> latency_hint) final;
void SetPreservesPitch(bool preserves_pitch) final;
void SetRenderMutedAudio(bool render_muted_audio) final;
void SetWasPlayedWithUserActivationAndHighMediaEngagement(
bool was_played_with_user_activation_and_high_media_engagement) final;
void Flush(base::OnceClosure flush_cb) final;
void StartPlayingFrom(base::TimeDelta time) final;
void SetPlaybackRate(double playback_rate) final;
void SetVolume(float volume) final;
base::TimeDelta GetMediaTime() final;
void OnTracksChanged(DemuxerStream::Type track_type,
DemuxerStream* enabled_track,
base::OnceClosure change_completed_cb) final;
RendererType GetRendererType() final;
void DisableUnderflowForTesting();
void EnableClocklessVideoPlaybackForTesting();
void set_time_source_for_testing(TimeSource* time_source) {
time_source_ = time_source;
}
void set_video_underflow_threshold_for_testing(base::TimeDelta threshold) {
video_underflow_threshold_.set_for_testing(threshold);
}
#if BUILDFLAG(ARKWEB_PIP)
void PipEnable(bool enable) final;
#endif
#if BUILDFLAG(ARKWEB_VIDEO_ASSISTANT)
void SetPreciseSeekTarget(int64_t target_timestamp) final;
#endif
#if BUILDFLAG(ARKWEB_MEDIA_DMABUF)
void RecycleDmaBuffer() final;
void ResumeDmaBuffer() final;
#endif
private:
class RendererClientInternal;
enum State {
STATE_UNINITIALIZED,
STATE_INIT_PENDING_CDM,
STATE_INITIALIZING,
STATE_FLUSHING,
STATE_FLUSHED,
STATE_PLAYING,
STATE_ERROR
};
bool GetWallClockTimes(const std::vector<base::TimeDelta>& media_timestamps,
std::vector<base::TimeTicks>* wall_clock_times);
bool HasEncryptedStream();
void FinishInitialization(PipelineStatus status);
void FinishFlush();
void InitializeAudioRenderer();
void OnAudioRendererInitializeDone(PipelineStatus status);
void InitializeVideoRenderer();
void OnVideoRendererInitializeDone(PipelineStatus status);
void FlushInternal();
void FlushAudioRenderer();
void OnAudioRendererFlushDone();
void FlushVideoRenderer();
void OnVideoRendererFlushDone();
void ReinitializeAudioRenderer(DemuxerStream* stream,
base::TimeDelta time,
base::OnceClosure reinitialize_completed_cb);
void OnAudioRendererReinitialized(DemuxerStream* stream,
base::TimeDelta time,
base::OnceClosure reinitialize_completed_cb,
PipelineStatus status);
void ReinitializeVideoRenderer(DemuxerStream* stream,
base::TimeDelta time,
base::OnceClosure restart_completed_cb);
void OnVideoRendererReinitialized(DemuxerStream* stream,
base::TimeDelta time,
base::OnceClosure restart_completed_cb,
PipelineStatus status);
void RestartAudioRenderer(DemuxerStream* stream,
base::TimeDelta time,
base::OnceClosure restart_completed_cb);
void RestartVideoRenderer(DemuxerStream* stream,
base::TimeDelta time,
base::OnceClosure restart_completed_cb);
void CleanUpTrackChange(base::OnceClosure on_finished,
bool* ended,
bool* playing);
void OnStatisticsUpdate(const PipelineStatistics& stats);
void OnBufferingStateChange(DemuxerStream::Type type,
BufferingState new_buffering_state,
BufferingStateChangeReason reason);
bool HandleRestartedStreamBufferingChanges(
DemuxerStream::Type type,
BufferingState new_buffering_state);
bool WaitingForEnoughData() const;
void PausePlayback();
void StartPlayback();
void OnRendererEnded(DemuxerStream::Type type);
bool PlaybackHasEnded() const;
void RunEndedCallbackIfNeeded();
void OnError(PipelineStatus error);
void OnFallback(PipelineStatus fallback);
void OnWaiting(WaitingReason reason);
void OnVideoNaturalSizeChange(const gfx::Size& size);
void OnAudioConfigChange(const AudioDecoderConfig& config);
void OnVideoConfigChange(const VideoDecoderConfig& config);
void OnVideoOpacityChange(bool opaque);
void OnVideoFrameRateChange(std::optional<int> fps);
void OnStreamRestartCompleted();
State state_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
raw_ptr<MediaResource> media_resource_;
raw_ptr<RendererClient> client_;
PipelineStatusCallback init_cb_;
base::OnceClosure flush_cb_;
std::unique_ptr<RendererClientInternal> audio_renderer_client_;
std::unique_ptr<RendererClientInternal> video_renderer_client_;
std::unique_ptr<AudioRenderer> audio_renderer_;
std::unique_ptr<VideoRenderer> video_renderer_;
raw_ptr<DemuxerStream> current_audio_stream_;
raw_ptr<DemuxerStream> current_video_stream_;
raw_ptr<TimeSource, DanglingUntriaged> time_source_;
std::unique_ptr<WallClockTimeSource> wall_clock_time_source_;
bool time_ticking_;
double playback_rate_;
base::TimeDelta start_time_;
BufferingState audio_buffering_state_;
BufferingState video_buffering_state_;
bool audio_ended_;
bool video_ended_;
bool audio_playing_;
bool video_playing_;
raw_ptr<CdmContext> cdm_context_;
bool underflow_disabled_for_testing_;
bool clockless_video_playback_enabled_for_testing_;
base::CancelableOnceClosure deferred_video_underflow_cb_;
bool has_deferred_buffering_state_change_ = false;
Tuneable<base::TimeDelta> video_underflow_threshold_ = {
"MediaVideoUnderflowThreshold", base::Milliseconds(1000),
base::Milliseconds(3000), base::Milliseconds(8000)};
base::Lock restarting_audio_lock_;
bool pending_audio_track_change_ = false;
base::TimeDelta restarting_audio_time_ = kNoTimestamp;
bool pending_video_track_change_ = false;
#if BUILDFLAG(ARKWEB_VIDEO_ASSISTANT)
RequestSurfaceCB request_surface_cb_;
VideoDecoderChangedCB decoder_changed_cb_;
#endif
base::WeakPtr<RendererImpl> weak_this_;
base::WeakPtrFactory<RendererImpl> weak_factory_{this};
};
}
#endif