[M120 Migration][MM] Handle live stream duration and currenttime
[platform/framework/web/chromium-efl.git] / media / base / pipeline_impl.cc
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/base/pipeline_impl.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <utility>
10
11 #include "base/command_line.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/location.h"
16 #include "base/memory/raw_ptr.h"
17 #include "base/metrics/histogram_functions.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/synchronization/lock.h"
21 #include "base/synchronization/waitable_event.h"
22 #include "base/task/bind_post_task.h"
23 #include "base/task/sequenced_task_runner.h"
24 #include "base/task/single_thread_task_runner.h"
25 #include "build/build_config.h"
26 #include "media/base/callback_timeout_helpers.h"
27 #include "media/base/cdm_context.h"
28 #include "media/base/decoder.h"
29 #include "media/base/demuxer.h"
30 #include "media/base/media_log.h"
31 #include "media/base/media_switches.h"
32 #include "media/base/renderer.h"
33 #include "media/base/renderer_client.h"
34 #include "media/base/serial_runner.h"
35 #include "media/base/timestamp_constants.h"
36 #include "media/base/video_decoder_config.h"
37
38 #if BUILDFLAG(IS_WIN)
39 #include "media/base/win/mf_feature_checks.h"
40 #endif  // BUILDFLAG(IS_WIN)
41
42 #if BUILDFLAG(IS_TIZEN_TV)
43 #include "media/filters/decrypting_media_resource.h"
44 #endif
45
46 static const double kDefaultPlaybackRate = 0.0;
47 static const float kDefaultVolume = 1.0f;
48
49 namespace media {
50
51 namespace {
52
53 gfx::Size GetRotatedVideoSize(VideoRotation rotation, gfx::Size natural_size) {
54   if (rotation == VIDEO_ROTATION_90 || rotation == VIDEO_ROTATION_270)
55     return gfx::Size(natural_size.height(), natural_size.width());
56   return natural_size;
57 }
58
59 void OnCallbackTimeout(const std::string& uma_name,
60                        bool called_on_destruction) {
61   DVLOG(1) << "Callback Timeout: " << uma_name
62            << ", called_on_destruction=" << called_on_destruction;
63   base::UmaHistogramEnumeration(
64       uma_name, called_on_destruction
65                     ? CallbackTimeoutStatus::kDestructedBeforeTimeout
66                     : CallbackTimeoutStatus::kTimeout);
67 }
68
69 }  // namespace
70
71 // A wrapper of Renderer that runs on the |media_task_runner|.
72 // |default_renderer| in Start() and Resume() helps avoid a round trip to the
73 // render main task runner for Renderer creation in most cases which could add
74 // latency to start-to-play time.
75 class PipelineImpl::RendererWrapper final : public DemuxerHost,
76                                             public RendererClient {
77  public:
78   RendererWrapper(scoped_refptr<base::SequencedTaskRunner> media_task_runner,
79                   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
80 #if defined(TIZEN_VIDEO_HOLE)
81                   bool is_video_hole,
82 #endif
83                   MediaLog* media_log);
84
85   RendererWrapper(const RendererWrapper&) = delete;
86   RendererWrapper& operator=(const RendererWrapper&) = delete;
87
88   ~RendererWrapper() final;
89
90   void Start(StartType start_type,
91              Demuxer* demuxer,
92              std::unique_ptr<Renderer> default_renderer,
93              base::WeakPtr<PipelineImpl> weak_pipeline);
94   void Stop();
95   void Seek(base::TimeDelta time);
96   void Suspend();
97   void Resume(std::unique_ptr<Renderer> default_renderer, base::TimeDelta time);
98   void SetPlaybackRate(double playback_rate);
99   void SetVolume(float volume);
100   void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint);
101   void SetPreservesPitch(bool preserves_pitch);
102   void SetWasPlayedWithUserActivation(bool was_played_with_user_activation);
103   base::TimeDelta GetMediaTime() const;
104   Ranges<base::TimeDelta> GetBufferedTimeRanges() const;
105   bool DidLoadingProgress();
106   PipelineStatistics GetStatistics() const;
107   void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb);
108
109 #if defined(TIZEN_MULTIMEDIA)
110   void ToggleFullscreenMode(bool is_fullscreen, ToggledFullscreenCB cb);
111   bool IsRendererSuspended() { return renderer_suspended_; }
112 #endif
113
114 #if defined(TIZEN_VIDEO_HOLE)
115   void SetMediaGeometry(const gfx::RectF rect_f);
116 #endif
117 #if BUILDFLAG(IS_TIZEN_TV)
118   void SetContentMimeType(const std::string& mime_type);
119   void SetParentalRatingResult(bool is_pass);
120 #endif
121
122   // |enabled_track_ids| contains track ids of enabled audio tracks.
123   void OnEnabledAudioTracksChanged(
124       const std::vector<MediaTrack::Id>& enabled_track_ids,
125       base::OnceClosure change_completed_cb);
126
127   // |selected_track_id| is either empty, which means no video track is
128   // selected, or contains the selected video track id.
129   void OnSelectedVideoTrackChanged(
130       absl::optional<MediaTrack::Id> selected_track_id,
131       base::OnceClosure change_completed_cb);
132
133   void OnExternalVideoFrameRequest();
134
135  private:
136   // Contains state shared between main and media thread. On the media thread
137   // each member can be read without locking, but writing requires locking. On
138   // the main thread reading requires a lock and writing is prohibited.
139   //
140   // This struct should only contain state that is not immediately needed by
141   // PipelineClient and can be cached on the media thread until queried.
142   // Alternatively we could cache it on the main thread by posting the
143   // notification to the main thread. But some of the state change notifications
144   // (OnStatisticsUpdate and OnBufferedTimeRangesChanged) arrive much more
145   // frequently than needed. Posting all those notifications to the main thread
146   // causes performance issues: crbug.com/619975.
147   struct SharedState {
148     // TODO(scherkus): Enforce that Renderer is only called on a single thread,
149     // even for accessing media time http://crbug.com/370634
150     //
151     // Note: Renderer implementations must support GetMediaTime() being called
152     // on both the main and media threads. RendererWrapper::GetMediaTime() calls
153     // it from the main thread (locked).
154     std::unique_ptr<Renderer> renderer;
155
156     // True when OnBufferedTimeRangesChanged() has been called more recently
157     // than DidLoadingProgress().
158     bool did_loading_progress = false;
159
160     // Amount of available buffered data as reported by Demuxer.
161     Ranges<base::TimeDelta> buffered_time_ranges;
162
163     // Accumulated statistics reported by the renderer.
164     PipelineStatistics statistics;
165
166     // The media timestamp to return while the pipeline is suspended.
167     // Otherwise set to kNoTimestamp.
168     base::TimeDelta suspend_timestamp = kNoTimestamp;
169   };
170
171   base::TimeDelta GetCurrentTimestamp();
172
173   void OnDemuxerCompletedTrackChange(
174       base::OnceClosure change_completed_cb,
175       DemuxerStream::Type stream_type,
176       const std::vector<DemuxerStream*>& streams);
177
178   // DemuxerHost implementaion.
179   void OnBufferedTimeRangesChanged(const Ranges<base::TimeDelta>& ranges) final;
180   void SetDuration(base::TimeDelta duration) final;
181   void OnDemuxerError(PipelineStatus error) final;
182
183   // RendererClient implementation.
184   void OnError(PipelineStatus error) final;
185   void OnFallback(PipelineStatus status) final;
186   void OnEnded() final;
187   void OnStatisticsUpdate(const PipelineStatistics& stats) final;
188   void OnBufferingStateChange(BufferingState state,
189                               BufferingStateChangeReason reason) final;
190   void OnWaiting(WaitingReason reason) final;
191   void OnAudioConfigChange(const AudioDecoderConfig& config) final;
192   void OnVideoConfigChange(const VideoDecoderConfig& config) final;
193   void OnVideoNaturalSizeChange(const gfx::Size& size) final;
194   void OnVideoOpacityChange(bool opaque) final;
195   void OnVideoFrameRateChange(absl::optional<int> fps) final;
196 #if defined(TIZEN_MULTIMEDIA)
197   void OnRequestSuspend(bool resource_conflict) final;
198   void OnRequestSeek(base::TimeDelta time) final;
199   void OnSeekableTimeChange(base::TimeDelta min_time,
200                             base::TimeDelta max_time,
201                             bool is_live) final;
202   void OnLivePlaybackComplete() final;
203 #endif
204
205   // Common handlers for notifications from renderers and demuxer.
206   void OnPipelineError(PipelineStatus error);
207   void OnCdmAttached(CdmAttachedCB cdm_attached_cb,
208                      CdmContext* cdm_context,
209                      bool success);
210   void CheckPlaybackEnded();
211
212   // State transition tasks.
213   void SetState(State next_state);
214   void CompleteSeek(base::TimeDelta seek_time, PipelineStatus status);
215   void CompleteSuspend(PipelineStatus status);
216   void InitializeDemuxer(PipelineStatusCallback done_cb);
217   void CreateRenderer(PipelineStatusCallback done_cb);
218   void OnRendererCreated(PipelineStatusCallback done_cb,
219                          std::unique_ptr<Renderer> renderer);
220   void InitializeRenderer(PipelineStatusCallback done_cb);
221   void DestroyRenderer();
222   void ReportMetadata(StartType start_type);
223
224 #if BUILDFLAG(IS_TIZEN_TV)
225   // Create decrypting media resource
226   void CreateAndInitializeDecryptingMediaResource();
227   void OnDecryptInitDone(bool success);
228 #endif
229
230   // Returns whether there's any encrypted stream in the demuxer.
231   bool HasEncryptedStream();
232
233   // Uses |default_renderer_| as the Renderer or asynchronously creates a new
234   // one by calling back to PipelineImpl. Fires |done_cb| with the result.
235   void CreateRendererInternal(PipelineStatusCallback done_cb);
236
237   const scoped_refptr<base::SequencedTaskRunner> media_task_runner_;
238   const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
239   const raw_ptr<MediaLog, AcrossTasksDanglingUntriaged> media_log_;
240
241   // A weak pointer to PipelineImpl. Must only use on the main task runner.
242   base::WeakPtr<PipelineImpl> weak_pipeline_;
243
244   raw_ptr<Demuxer> demuxer_;
245
246   // Optional default renderer to be used during Start() and Resume(). If not
247   // available, or if a different Renderer is needed,
248   // PipelineImpl::AsyncCreateRenderer() will be called to create a new one.
249   std::unique_ptr<Renderer> default_renderer_;
250
251   double playback_rate_;
252   float volume_;
253   absl::optional<base::TimeDelta> latency_hint_;
254   raw_ptr<CdmContext> cdm_context_;
255
256   // By default, apply pitch adjustments.
257   bool preserves_pitch_ = true;
258
259   bool was_played_with_user_activation_ = false;
260
261   // Lock used to serialize |shared_state_|.
262   // TODO(crbug.com/893739): Add GUARDED_BY annotations.
263   mutable base::Lock shared_state_lock_;
264
265   // State shared between main and media thread.
266   SharedState shared_state_;
267
268   // Current state of the pipeline.
269   State state_;
270
271   // Status of the pipeline.  Initialized to PIPELINE_OK which indicates that
272   // the pipeline is operating correctly. Any other value indicates that the
273   // pipeline is stopped or is stopping.  Clients can call the Stop() method to
274   // reset the pipeline state, and restore this to PIPELINE_OK.
275   PipelineStatus status_;
276
277 #if defined(TIZEN_MULTIMEDIA)
278   bool renderer_suspended_ = false;
279   base::DelayedTaskHandle request_suspend_task_handle_;
280 #endif
281
282 #if defined(TIZEN_VIDEO_HOLE)
283   bool is_video_hole_;
284 #endif
285
286 #if BUILDFLAG(IS_TIZEN_TV)
287   std::string mime_type_;
288   std::unique_ptr<DecryptingMediaResource> decrypting_media_resource_{nullptr};
289 #endif
290
291   // Whether we've received the audio/video ended events.
292   bool renderer_ended_;
293
294   // Series of tasks to Start(), Seek(), and Resume().
295   std::unique_ptr<SerialRunner> pending_callbacks_;
296
297   // Callback to store the |done_cb| when CreateRenderer() needs to wait for a
298   // CDM to be set. Should only be set in kStarting or kResuming states.
299   PipelineStatusCallback create_renderer_done_cb_;
300
301   // Called from non-media threads when an error occurs.
302   PipelineStatusCB error_cb_;
303
304   base::WeakPtrFactory<RendererWrapper> weak_factory_{this};
305 };
306
307 PipelineImpl::RendererWrapper::RendererWrapper(
308     scoped_refptr<base::SequencedTaskRunner> media_task_runner,
309     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
310 #if defined(TIZEN_VIDEO_HOLE)
311     bool is_video_hole,
312 #endif
313     MediaLog* media_log)
314     : media_task_runner_(std::move(media_task_runner)),
315       main_task_runner_(std::move(main_task_runner)),
316       media_log_(media_log),
317       demuxer_(nullptr),
318       playback_rate_(kDefaultPlaybackRate),
319       volume_(kDefaultVolume),
320       cdm_context_(nullptr),
321       state_(kCreated),
322       status_(PIPELINE_OK),
323 #if defined(TIZEN_VIDEO_HOLE)
324       is_video_hole_(is_video_hole),
325 #endif
326       renderer_ended_(false) {}
327
328 PipelineImpl::RendererWrapper::~RendererWrapper() {
329   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
330   DCHECK(state_ == kCreated || state_ == kStopped);
331 }
332
333 // Note that the usage of base::Unretained() with the renderers is considered
334 // safe as they are owned by |pending_callbacks_| and share the same lifetime.
335 //
336 // That being said, deleting the renderers while keeping |pending_callbacks_|
337 // running on the media thread would result in crashes.
338
339 void PipelineImpl::RendererWrapper::Start(
340     StartType start_type,
341     Demuxer* demuxer,
342     std::unique_ptr<Renderer> default_renderer,
343     base::WeakPtr<PipelineImpl> weak_pipeline) {
344   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
345   DCHECK(state_ == kCreated || state_ == kStopped)
346       << "Received start in unexpected state: " << state_;
347   DCHECK(!demuxer_);
348   DCHECK(!renderer_ended_);
349
350   SetState(kStarting);
351   demuxer_ = demuxer;
352   default_renderer_ = std::move(default_renderer);
353   weak_pipeline_ = weak_pipeline;
354
355   // Setup |error_cb_| on the media thread.
356   error_cb_ = base::BindRepeating(&RendererWrapper::OnPipelineError,
357                                   weak_factory_.GetWeakPtr());
358
359   // Queue asynchronous actions required to start.
360   DCHECK(!pending_callbacks_);
361   SerialRunner::Queue fns;
362
363   // Initialize demuxer.
364   fns.Push(base::BindOnce(&RendererWrapper::InitializeDemuxer,
365                           weak_factory_.GetWeakPtr()));
366
367   // Once the demuxer is initialized successfully, media metadata must be
368   // available - report the metadata to client. If starting without a renderer
369   // we'll complete initialization at this point.
370   fns.Push(base::BindOnce(&RendererWrapper::ReportMetadata,
371                           weak_factory_.GetWeakPtr(), start_type));
372
373   // Create renderer.
374   fns.Push(base::BindOnce(&RendererWrapper::CreateRenderer,
375                           weak_factory_.GetWeakPtr()));
376
377   // Initialize renderer.
378   fns.Push(base::BindOnce(&RendererWrapper::InitializeRenderer,
379                           weak_factory_.GetWeakPtr()));
380
381   // Run tasks.
382   pending_callbacks_ = SerialRunner::Run(
383       std::move(fns),
384       base::BindOnce(&RendererWrapper::CompleteSeek, weak_factory_.GetWeakPtr(),
385                      base::TimeDelta()));
386 }
387
388 void PipelineImpl::RendererWrapper::Stop() {
389   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
390   DCHECK(state_ != kStopping && state_ != kStopped);
391
392   SetState(kStopping);
393
394   if (shared_state_.statistics.video_frames_decoded > 0) {
395     UMA_HISTOGRAM_COUNTS_1M("Media.DroppedFrameCount",
396                             shared_state_.statistics.video_frames_dropped);
397   }
398
399   // If we stop during starting/seeking/suspending/resuming we don't want to
400   // leave outstanding callbacks around. The callbacks also do not get run if
401   // the pipeline is stopped before it had a chance to complete outstanding
402   // tasks.
403   pending_callbacks_.reset();
404   weak_factory_.InvalidateWeakPtrs();
405
406   DestroyRenderer();
407
408   if (demuxer_) {
409     demuxer_->Stop();
410     demuxer_ = nullptr;
411   }
412
413   SetState(kStopped);
414
415   // Reset the status. Otherwise, if we encountered an error, new errors will
416   // never be propagated. See https://crbug.com/812465.
417   status_ = PIPELINE_OK;
418 }
419
420 void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) {
421   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
422
423   // Suppress seeking if we're not fully started.
424   if (state_ != kPlaying) {
425     DCHECK(state_ == kStopping || state_ == kStopped)
426         << "Receive seek in unexpected state: " << state_;
427     OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
428     return;
429   }
430
431   base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime());
432
433   SetState(kSeeking);
434   renderer_ended_ = false;
435
436   // Queue asynchronous actions required to start.
437   DCHECK(!pending_callbacks_);
438   SerialRunner::Queue bound_fns;
439
440   // Abort any reads the renderer may be blocked on.
441   demuxer_->AbortPendingReads();
442
443   // Flush.
444   DCHECK(shared_state_.renderer);
445   bound_fns.Push(base::BindOnce(
446       &Renderer::Flush, base::Unretained(shared_state_.renderer.get())));
447
448   // Seek demuxer.
449   bound_fns.Push(base::BindOnce(&Demuxer::Seek, base::Unretained(demuxer_),
450                                 seek_timestamp));
451
452 #if defined(TIZEN_MULTIMEDIA)
453   // Calling seek is completely redundant, because upstream StartPlayingFrom()
454   // will do the same thing any moment now. Skip this call for EMSS && URL
455   // demuxer, to avoid unnecessary slowdown of the pipeline
456   bool skip_unnecessary_double_seek =
457       demuxer_->GetType() == MediaResource::Type::KUrl;
458   if (!skip_unnecessary_double_seek) {
459     bound_fns.Push(base::BindOnce(
460         &Renderer::Seek, base::Unretained(shared_state_.renderer.get()),
461         seek_timestamp));
462   }
463 #endif  // defined(TIZEN_MULTIMEDIA)
464
465   // Run tasks.
466   pending_callbacks_ = SerialRunner::Run(
467       std::move(bound_fns),
468       base::BindOnce(&RendererWrapper::CompleteSeek, weak_factory_.GetWeakPtr(),
469                      seek_timestamp));
470 }
471
472 void PipelineImpl::RendererWrapper::Suspend() {
473   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
474
475   // Suppress suspending if we're not playing.
476   if (state_ != kPlaying) {
477     DCHECK(state_ == kStopping || state_ == kStopped)
478         << "Receive suspend in unexpected state: " << state_;
479     OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
480     return;
481   }
482   DCHECK(!pending_callbacks_.get());
483
484   SetState(kSuspending);
485
486 #if defined(TIZEN_MULTIMEDIA)
487   if (request_suspend_task_handle_.IsValid()) {
488     LOG(INFO) << " Cancel posted request suspend task if pended.";
489     request_suspend_task_handle_.CancelTask();
490   }
491
492   shared_state_.renderer->Suspend();
493 #endif
494
495   // Freeze playback and record the media time before destroying the renderer.
496   shared_state_.renderer->SetPlaybackRate(0.0);
497   {
498     base::AutoLock auto_lock(shared_state_lock_);
499     DCHECK(shared_state_.renderer);
500     shared_state_.suspend_timestamp = shared_state_.renderer->GetMediaTime();
501     DCHECK(shared_state_.suspend_timestamp != kNoTimestamp);
502   }
503
504   // Queue the asynchronous actions required to stop playback.
505   SerialRunner::Queue fns;
506
507   // No need to flush the renderer since it's going to be destroyed.
508   pending_callbacks_ = SerialRunner::Run(
509       std::move(fns), base::BindOnce(&RendererWrapper::CompleteSuspend,
510                                      weak_factory_.GetWeakPtr()));
511 }
512
513 void PipelineImpl::RendererWrapper::Resume(
514     std::unique_ptr<Renderer> default_renderer,
515     base::TimeDelta timestamp) {
516   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
517
518   // Suppress resuming if we're not suspended.
519   if (state_ != kSuspended) {
520     DCHECK(state_ == kStopping || state_ == kStopped)
521         << "Receive resume in unexpected state: " << state_;
522     OnPipelineError(PIPELINE_ERROR_INVALID_STATE);
523     return;
524   }
525   DCHECK(!pending_callbacks_.get());
526
527   if (!default_renderer) {
528     OnPipelineError({PIPELINE_ERROR_INITIALIZATION_FAILED,
529                      "Media Renderer creation failed during resume!"});
530     return;
531   }
532
533   SetState(kResuming);
534
535   {
536     base::AutoLock auto_lock(shared_state_lock_);
537     DCHECK(!shared_state_.renderer);
538   }
539
540 #if defined(TIZEN_MULTIMEDIA)
541   if (request_suspend_task_handle_.IsValid()) {
542     LOG(INFO) << " Cancel posted request suspend task if pended.";
543     request_suspend_task_handle_.CancelTask();
544   }
545
546   renderer_suspended_ = false;
547
548   bool default_renderer_created = default_renderer.get() ? true : false;
549   if (default_renderer_created)
550 #endif
551     default_renderer_ = std::move(default_renderer);
552   renderer_ended_ = false;
553   base::TimeDelta start_timestamp =
554       std::max(timestamp, demuxer_->GetStartTime());
555
556   // Queue the asynchronous actions required to start playback.
557   SerialRunner::Queue fns;
558
559   fns.Push(base::BindOnce(&Demuxer::Seek, base::Unretained(demuxer_),
560                           start_timestamp));
561
562 #if defined(TIZEN_MULTIMEDIA)
563   if (default_renderer_created)
564 #endif
565   {
566     fns.Push(base::BindOnce(&RendererWrapper::CreateRenderer,
567                             weak_factory_.GetWeakPtr()));
568
569     fns.Push(base::BindOnce(&RendererWrapper::InitializeRenderer,
570                             weak_factory_.GetWeakPtr()));
571   }
572
573   pending_callbacks_ = SerialRunner::Run(
574       std::move(fns),
575       base::BindOnce(&RendererWrapper::CompleteSeek, weak_factory_.GetWeakPtr(),
576                      start_timestamp));
577 }
578
579 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) {
580   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
581
582   playback_rate_ = playback_rate;
583   if (state_ == kPlaying)
584     shared_state_.renderer->SetPlaybackRate(playback_rate_);
585
586   if (state_ != kCreated && state_ != kStopping && state_ != kStopped) {
587     DCHECK(demuxer_);
588     demuxer_->SetPlaybackRate(playback_rate);
589   }
590 }
591
592 void PipelineImpl::RendererWrapper::SetVolume(float volume) {
593   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
594
595   volume_ = volume;
596   if (shared_state_.renderer)
597     shared_state_.renderer->SetVolume(volume_);
598 }
599
600 void PipelineImpl::RendererWrapper::SetLatencyHint(
601     absl::optional<base::TimeDelta> latency_hint) {
602   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
603
604   if (latency_hint_ == latency_hint)
605     return;
606
607   latency_hint_ = latency_hint;
608   if (shared_state_.renderer)
609     shared_state_.renderer->SetLatencyHint(latency_hint_);
610 }
611
612 void PipelineImpl::RendererWrapper::SetPreservesPitch(bool preserves_pitch) {
613   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
614
615   if (preserves_pitch_ == preserves_pitch)
616     return;
617
618   preserves_pitch_ = preserves_pitch;
619   if (shared_state_.renderer)
620     shared_state_.renderer->SetPreservesPitch(preserves_pitch_);
621 }
622
623 void PipelineImpl::RendererWrapper::SetWasPlayedWithUserActivation(
624     bool was_played_with_user_activation) {
625   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
626
627   was_played_with_user_activation_ = was_played_with_user_activation;
628   if (shared_state_.renderer) {
629     shared_state_.renderer->SetWasPlayedWithUserActivation(
630         was_played_with_user_activation_);
631   }
632 }
633
634 base::TimeDelta PipelineImpl::RendererWrapper::GetMediaTime() const {
635   DCHECK(main_task_runner_->BelongsToCurrentThread());
636
637   base::AutoLock auto_lock(shared_state_lock_);
638   if (shared_state_.suspend_timestamp != kNoTimestamp)
639     return shared_state_.suspend_timestamp;
640   return shared_state_.renderer ? shared_state_.renderer->GetMediaTime()
641                                 : base::TimeDelta();
642 }
643
644 Ranges<base::TimeDelta> PipelineImpl::RendererWrapper::GetBufferedTimeRanges()
645     const {
646   DCHECK(main_task_runner_->BelongsToCurrentThread());
647
648   base::AutoLock auto_lock(shared_state_lock_);
649   return shared_state_.buffered_time_ranges;
650 }
651
652 bool PipelineImpl::RendererWrapper::DidLoadingProgress() {
653   DCHECK(main_task_runner_->BelongsToCurrentThread());
654
655   base::AutoLock auto_lock(shared_state_lock_);
656   bool did_progress = shared_state_.did_loading_progress;
657   shared_state_.did_loading_progress = false;
658   return did_progress;
659 }
660
661 PipelineStatistics PipelineImpl::RendererWrapper::GetStatistics() const {
662   DCHECK(main_task_runner_->BelongsToCurrentThread());
663
664   base::AutoLock auto_lock(shared_state_lock_);
665   return shared_state_.statistics;
666 }
667
668 void PipelineImpl::RendererWrapper::SetCdm(CdmContext* cdm_context,
669                                            CdmAttachedCB cdm_attached_cb) {
670   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
671   DCHECK(cdm_context);
672
673   // If there's already a renderer, set the CDM on the renderer directly.
674   if (shared_state_.renderer) {
675     shared_state_.renderer->SetCdm(
676         cdm_context, base::BindOnce(&RendererWrapper::OnCdmAttached,
677                                     weak_factory_.GetWeakPtr(),
678                                     std::move(cdm_attached_cb), cdm_context));
679     return;
680   }
681
682   // Otherwise, wait for the Renderer to be created and the CDM will be set
683   // in InitializeRenderer().
684   cdm_context_ = cdm_context;
685   std::move(cdm_attached_cb).Run(true);
686
687   // Continue Renderer creation if it's waiting for the CDM to be set.
688   if (create_renderer_done_cb_)
689     CreateRendererInternal(std::move(create_renderer_done_cb_));
690 }
691
692 #if defined(TIZEN_VIDEO_HOLE)
693 void PipelineImpl::RendererWrapper::SetMediaGeometry(const gfx::RectF rect_f) {
694   LOG(INFO) << __func__;
695   if (shared_state_.renderer)
696     shared_state_.renderer->SetMediaGeometry(rect_f);
697 }
698 #endif
699
700 #if BUILDFLAG(IS_TIZEN_TV)
701 void PipelineImpl::RendererWrapper::SetContentMimeType(
702     const std::string& mime_type) {
703   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
704   mime_type_ = mime_type;
705   if (shared_state_.renderer)
706     shared_state_.renderer->SetContentMimeType(mime_type_);
707 }
708
709 void PipelineImpl::RendererWrapper::SetParentalRatingResult(bool is_pass) {
710   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
711
712   if (shared_state_.renderer)
713     shared_state_.renderer->SetParentalRatingResult(is_pass);
714   else
715     LOG(ERROR) << "renderer is null";
716 }
717 #endif
718
719 #if BUILDFLAG(IS_TIZEN_TV)
720 void PipelineImpl::RendererWrapper::OnDecryptInitDone(bool success) {
721   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
722   LOG(INFO) << "OnDecryptInitDone,this:" << (void*)this;
723 }
724
725 void PipelineImpl::RendererWrapper::
726     CreateAndInitializeDecryptingMediaResource() {
727   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
728   DCHECK(cdm_context_);
729   decrypting_media_resource_ = std::make_unique<DecryptingMediaResource>(
730       demuxer_, cdm_context_, media_log_, media_task_runner_);
731
732   LOG(INFO) << "(" << static_cast<void*>(this) << __func__
733             << ") decrypting_media_resource_:"
734             << decrypting_media_resource_.get();
735
736   decrypting_media_resource_->Initialize(
737       base::BindOnce(&RendererWrapper::OnDecryptInitDone,
738                      weak_factory_.GetWeakPtr()),
739       base::BindRepeating(&RendererWrapper::OnWaiting,
740                           weak_factory_.GetWeakPtr()));
741 }
742 #endif
743
744 void PipelineImpl::RendererWrapper::CreateRendererInternal(
745     PipelineStatusCallback done_cb) {
746   DVLOG(1) << __func__;
747
748   DCHECK(state_ == kStarting || state_ == kResuming);
749   DCHECK(cdm_context_ || !HasEncryptedStream())
750       << "CDM should be available now if has encrypted stream";
751
752   absl::optional<RendererType> renderer_type;
753
754 #if BUILDFLAG(IS_WIN)
755   if (cdm_context_) {
756     if (cdm_context_->RequiresMediaFoundationRenderer()) {
757       renderer_type = RendererType::kMediaFoundation;
758     } else if (media::SupportMediaFoundationClearPlayback()) {
759       // When MediaFoundation for Clear is enabled, the base renderer
760       // type is set to MediaFoundation. In order to ensure DRM systems
761       // built on non-Media Foundation pipelines continue to work we
762       // explicitly set renderer_type to Default.
763       renderer_type = RendererType::kRendererImpl;
764     }
765   }
766 #endif  // BUILDFLAG(IS_WIN)
767
768   // TODO(xhwang): During Resume(), the |default_renderer_| might already match
769   // the |renderer_type|, in which case we shouldn't need to create a new one.
770   if (!default_renderer_ || renderer_type) {
771     // Create the Renderer asynchronously on the main task runner. Use
772     // base::BindPostTaskToCurrentDefault to call OnRendererCreated() on the
773     // media task runner.
774     auto renderer_created_cb = base::BindPostTaskToCurrentDefault(
775         base::BindOnce(&RendererWrapper::OnRendererCreated,
776                        weak_factory_.GetWeakPtr(), std::move(done_cb)));
777     main_task_runner_->PostTask(
778         FROM_HERE,
779         base::BindOnce(&PipelineImpl::AsyncCreateRenderer, weak_pipeline_,
780                        renderer_type, std::move(renderer_created_cb)));
781     return;
782   }
783
784   // Just use the default one.
785   OnRendererCreated(std::move(done_cb), std::move(default_renderer_));
786 }
787
788 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged(
789     const Ranges<base::TimeDelta>& ranges) {
790   // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
791   // implementations call DemuxerHost on the media thread.
792   base::AutoLock auto_lock(shared_state_lock_);
793   shared_state_.did_loading_progress = true;
794   shared_state_.buffered_time_ranges = ranges;
795 }
796
797 void PipelineImpl::RendererWrapper::SetDuration(base::TimeDelta duration) {
798   // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
799   // implementations call DemuxerHost on the media thread.
800   media_log_->AddEvent<MediaLogEvent::kDurationChanged>(duration);
801   main_task_runner_->PostTask(
802       FROM_HERE, base::BindOnce(&PipelineImpl::OnDurationChange, weak_pipeline_,
803                                 duration));
804 }
805
806 void PipelineImpl::RendererWrapper::OnDemuxerError(PipelineStatus error) {
807   // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
808   // implementations call DemuxerHost on the media thread.
809   DCHECK(error_cb_);
810   media_task_runner_->PostTask(FROM_HERE, base::BindOnce(error_cb_, error));
811 }
812
813 void PipelineImpl::RendererWrapper::OnError(PipelineStatus error) {
814   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
815   DCHECK(error_cb_);
816   media_task_runner_->PostTask(FROM_HERE, base::BindOnce(error_cb_, error));
817 }
818
819 void PipelineImpl::RendererWrapper::OnFallback(PipelineStatus fallback) {
820   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
821   main_task_runner_->PostTask(
822       FROM_HERE, base::BindOnce(&PipelineImpl::OnFallback, weak_pipeline_,
823                                 std::move(fallback).AddHere()));
824 }
825
826 void PipelineImpl::RendererWrapper::OnEnded() {
827   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
828   media_log_->AddEvent<MediaLogEvent::kEnded>();
829
830   if (state_ != kPlaying)
831     return;
832
833   DCHECK(!renderer_ended_);
834   renderer_ended_ = true;
835   CheckPlaybackEnded();
836 }
837
838 // TODO(crbug/817089): Combine this functionality into renderer->GetMediaTime().
839 base::TimeDelta PipelineImpl::RendererWrapper::GetCurrentTimestamp() {
840   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
841   DCHECK(demuxer_);
842   DCHECK(shared_state_.renderer || state_ != kPlaying);
843
844   return state_ == kPlaying ? shared_state_.renderer->GetMediaTime()
845                             : demuxer_->GetStartTime();
846 }
847
848 void PipelineImpl::OnEnabledAudioTracksChanged(
849     const std::vector<MediaTrack::Id>& enabled_track_ids,
850     base::OnceClosure change_completed_cb) {
851   DCHECK(thread_checker_.CalledOnValidThread());
852   media_task_runner_->PostTask(
853       FROM_HERE,
854       base::BindOnce(
855           &RendererWrapper::OnEnabledAudioTracksChanged,
856           base::Unretained(renderer_wrapper_.get()), enabled_track_ids,
857           base::BindPostTaskToCurrentDefault(std::move(change_completed_cb))));
858 }
859
860 void PipelineImpl::RendererWrapper::OnEnabledAudioTracksChanged(
861     const std::vector<MediaTrack::Id>& enabled_track_ids,
862     base::OnceClosure change_completed_cb) {
863   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
864
865   // If the pipeline has been created, but not started yet, we may still receive
866   // track notifications from blink level (e.g. when video track gets deselected
867   // due to player/pipeline belonging to a background tab). We can safely ignore
868   // these, since WebMediaPlayerImpl will ensure that demuxer stream / track
869   // status is in sync with blink after pipeline is started.
870   if (state_ == kCreated) {
871     DCHECK(!demuxer_);
872     std::move(change_completed_cb).Run();
873     return;
874   }
875
876   // Track status notifications might be delivered asynchronously. If we receive
877   // a notification when pipeline is stopped/shut down, it's safe to ignore it.
878   if (state_ == kStopping || state_ == kStopped) {
879     std::move(change_completed_cb).Run();
880     return;
881   }
882   demuxer_->OnEnabledAudioTracksChanged(
883       enabled_track_ids, GetCurrentTimestamp(),
884       base::BindOnce(&RendererWrapper::OnDemuxerCompletedTrackChange,
885                      weak_factory_.GetWeakPtr(),
886                      std::move(change_completed_cb)));
887 }
888
889 void PipelineImpl::OnSelectedVideoTrackChanged(
890     absl::optional<MediaTrack::Id> selected_track_id,
891     base::OnceClosure change_completed_cb) {
892   DCHECK(thread_checker_.CalledOnValidThread());
893   media_task_runner_->PostTask(
894       FROM_HERE,
895       base::BindOnce(
896           &RendererWrapper::OnSelectedVideoTrackChanged,
897           base::Unretained(renderer_wrapper_.get()), selected_track_id,
898           base::BindPostTaskToCurrentDefault(std::move(change_completed_cb))));
899 }
900
901 void PipelineImpl::RendererWrapper::OnSelectedVideoTrackChanged(
902     absl::optional<MediaTrack::Id> selected_track_id,
903     base::OnceClosure change_completed_cb) {
904   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
905
906   // See RenderWrapper::OnEnabledAudioTracksChanged.
907   if (state_ == kCreated) {
908     DCHECK(!demuxer_);
909     std::move(change_completed_cb).Run();
910     return;
911   }
912
913   if (state_ == kStopping || state_ == kStopped) {
914     std::move(change_completed_cb).Run();
915     return;
916   }
917
918   std::vector<MediaTrack::Id> tracks;
919   if (selected_track_id)
920     tracks.push_back(*selected_track_id);
921
922   demuxer_->OnSelectedVideoTrackChanged(
923       tracks, GetCurrentTimestamp(),
924       base::BindOnce(&RendererWrapper::OnDemuxerCompletedTrackChange,
925                      weak_factory_.GetWeakPtr(),
926                      std::move(change_completed_cb)));
927 }
928
929 void PipelineImpl::OnExternalVideoFrameRequest() {
930   // This function is currently a no-op unless we're on a Windows build with
931   // Media Foundation for Clear running.
932   DCHECK(thread_checker_.CalledOnValidThread());
933   if (!external_video_frame_request_signaled_) {
934     external_video_frame_request_signaled_ = true;
935     media_task_runner_->PostTask(
936         FROM_HERE, base::BindOnce(&RendererWrapper::OnExternalVideoFrameRequest,
937                                   base::Unretained(renderer_wrapper_.get())));
938   }
939 }
940
941 void PipelineImpl::RendererWrapper::OnExternalVideoFrameRequest() {
942   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
943   if (!shared_state_.renderer) {
944     return;
945   }
946
947   shared_state_.renderer->OnExternalVideoFrameRequest();
948 }
949
950 void PipelineImpl::RendererWrapper::OnDemuxerCompletedTrackChange(
951     base::OnceClosure change_completed_cb,
952     DemuxerStream::Type stream_type,
953     const std::vector<DemuxerStream*>& streams) {
954   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
955   if (!shared_state_.renderer) {
956     // This can happen if the pipeline has been suspended.
957     std::move(change_completed_cb).Run();
958     return;
959   }
960
961   switch (stream_type) {
962     case DemuxerStream::AUDIO:
963       shared_state_.renderer->OnEnabledAudioTracksChanged(
964           streams, std::move(change_completed_cb));
965       break;
966     case DemuxerStream::VIDEO:
967       shared_state_.renderer->OnSelectedVideoTracksChanged(
968           streams, std::move(change_completed_cb));
969       break;
970     case DemuxerStream::UNKNOWN:  // Fail on unknown type.
971       NOTREACHED_NORETURN();
972   }
973 }
974
975 void PipelineImpl::RendererWrapper::OnStatisticsUpdate(
976     const PipelineStatistics& stats) {
977   DVLOG(3) << __func__;
978   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
979
980   base::AutoLock auto_lock(shared_state_lock_);
981   shared_state_.statistics.audio_bytes_decoded += stats.audio_bytes_decoded;
982   shared_state_.statistics.video_bytes_decoded += stats.video_bytes_decoded;
983   shared_state_.statistics.video_frames_decoded += stats.video_frames_decoded;
984   shared_state_.statistics.video_frames_decoded_power_efficient +=
985       stats.video_frames_decoded_power_efficient;
986   shared_state_.statistics.video_frames_dropped += stats.video_frames_dropped;
987   shared_state_.statistics.audio_memory_usage += stats.audio_memory_usage;
988   shared_state_.statistics.video_memory_usage += stats.video_memory_usage;
989
990   if (stats.audio_pipeline_info.decoder_type != AudioDecoderType::kUnknown &&
991       stats.audio_pipeline_info !=
992           shared_state_.statistics.audio_pipeline_info) {
993     shared_state_.statistics.audio_pipeline_info = stats.audio_pipeline_info;
994     main_task_runner_->PostTask(
995         FROM_HERE, base::BindOnce(&PipelineImpl::OnAudioPipelineInfoChange,
996                                   weak_pipeline_, stats.audio_pipeline_info));
997   }
998
999   if (stats.video_pipeline_info.decoder_type != VideoDecoderType::kUnknown &&
1000       stats.video_pipeline_info !=
1001           shared_state_.statistics.video_pipeline_info) {
1002     shared_state_.statistics.video_pipeline_info = stats.video_pipeline_info;
1003     main_task_runner_->PostTask(
1004         FROM_HERE, base::BindOnce(&PipelineImpl::OnVideoPipelineInfoChange,
1005                                   weak_pipeline_, stats.video_pipeline_info));
1006   }
1007
1008   if (stats.video_frame_duration_average != kNoTimestamp) {
1009     shared_state_.statistics.video_frame_duration_average =
1010         stats.video_frame_duration_average;
1011   }
1012
1013   base::TimeDelta old_key_frame_distance_average =
1014       shared_state_.statistics.video_keyframe_distance_average;
1015   if (stats.video_keyframe_distance_average != kNoTimestamp) {
1016     shared_state_.statistics.video_keyframe_distance_average =
1017         stats.video_keyframe_distance_average;
1018   }
1019
1020   if (shared_state_.statistics.video_keyframe_distance_average !=
1021       old_key_frame_distance_average) {
1022     main_task_runner_->PostTask(
1023         FROM_HERE,
1024         base::BindOnce(&PipelineImpl::OnVideoAverageKeyframeDistanceUpdate,
1025                        weak_pipeline_));
1026   }
1027 }
1028
1029 void PipelineImpl::RendererWrapper::OnBufferingStateChange(
1030     BufferingState state,
1031     BufferingStateChangeReason reason) {
1032   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1033   DVLOG(2) << __func__ << "(" << state << ", " << reason << ") ";
1034
1035   main_task_runner_->PostTask(
1036       FROM_HERE, base::BindOnce(&PipelineImpl::OnBufferingStateChange,
1037                                 weak_pipeline_, state, reason));
1038 }
1039
1040 void PipelineImpl::RendererWrapper::OnWaiting(WaitingReason reason) {
1041   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1042
1043   main_task_runner_->PostTask(
1044       FROM_HERE,
1045       base::BindOnce(&PipelineImpl::OnWaiting, weak_pipeline_, reason));
1046 }
1047
1048 void PipelineImpl::RendererWrapper::OnVideoNaturalSizeChange(
1049     const gfx::Size& size) {
1050   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1051
1052   main_task_runner_->PostTask(
1053       FROM_HERE, base::BindOnce(&PipelineImpl::OnVideoNaturalSizeChange,
1054                                 weak_pipeline_, size));
1055 }
1056
1057 void PipelineImpl::RendererWrapper::OnVideoOpacityChange(bool opaque) {
1058   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1059
1060   main_task_runner_->PostTask(
1061       FROM_HERE, base::BindOnce(&PipelineImpl::OnVideoOpacityChange,
1062                                 weak_pipeline_, opaque));
1063 }
1064
1065 void PipelineImpl::RendererWrapper::OnVideoFrameRateChange(
1066     absl::optional<int> fps) {
1067   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1068
1069   main_task_runner_->PostTask(
1070       FROM_HERE, base::BindOnce(&PipelineImpl::OnVideoFrameRateChange,
1071                                 weak_pipeline_, fps));
1072 }
1073
1074 void PipelineImpl::RendererWrapper::OnAudioConfigChange(
1075     const AudioDecoderConfig& config) {
1076   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1077
1078   main_task_runner_->PostTask(FROM_HERE,
1079                               base::BindOnce(&PipelineImpl::OnAudioConfigChange,
1080                                              weak_pipeline_, config));
1081 }
1082
1083 void PipelineImpl::RendererWrapper::OnVideoConfigChange(
1084     const VideoDecoderConfig& config) {
1085   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1086
1087   main_task_runner_->PostTask(FROM_HERE,
1088                               base::BindOnce(&PipelineImpl::OnVideoConfigChange,
1089                                              weak_pipeline_, config));
1090 }
1091
1092 #if defined(TIZEN_MULTIMEDIA)
1093 void PipelineImpl::RendererWrapper::ToggleFullscreenMode(
1094     bool is_fullscreen,
1095     ToggledFullscreenCB cb) {
1096   LOG(INFO) << __func__;
1097   if (shared_state_.renderer)
1098     shared_state_.renderer->ToggleFullscreenMode(is_fullscreen, std::move(cb));
1099 }
1100
1101 void PipelineImpl::RendererWrapper::OnRequestSuspend(bool resource_conflict) {
1102   if (state_ == kSuspending || state_ == kSuspended)
1103     return;
1104
1105   LOG(INFO) << __func__;
1106   request_suspend_task_handle_ = main_task_runner_->PostCancelableDelayedTask(
1107       base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
1108       base::BindOnce(&PipelineImpl::OnRequestSuspend, weak_pipeline_,
1109                      resource_conflict),
1110       base::TimeDelta());
1111 }
1112
1113 void PipelineImpl::RendererWrapper::OnRequestSeek(base::TimeDelta time) {
1114   LOG(INFO) << __func__ << " time:" << time;
1115
1116   if (!media_task_runner_->RunsTasksInCurrentSequence()) {
1117     media_task_runner_->PostTask(
1118         FROM_HERE,
1119         base::BindOnce(&media::PipelineImpl::RendererWrapper::OnRequestSeek,
1120                        weak_factory_.GetWeakPtr(), time));
1121   }
1122
1123   SetState(kSeeking);
1124
1125   SerialRunner::Queue bound_fns;
1126   demuxer_->AbortPendingReads();
1127
1128   bound_fns.Push(base::BindOnce(
1129       &Renderer::Flush, base::Unretained(shared_state_.renderer.get())));
1130   bound_fns.Push(
1131       base::BindOnce(&Demuxer::Seek, base::Unretained(demuxer_), time));
1132   pending_callbacks_ = SerialRunner::Run(
1133       std::move(bound_fns), base::BindOnce(&RendererWrapper::CompleteSeek,
1134                                            weak_factory_.GetWeakPtr(), time));
1135 }
1136
1137 void PipelineImpl::RendererWrapper::OnSeekableTimeChange(
1138     base::TimeDelta min_time,
1139     base::TimeDelta max_time,
1140     bool is_live) {
1141   main_task_runner_->PostTask(
1142       FROM_HERE, base::BindOnce(&PipelineImpl::OnSeekableTimeChange,
1143                                 weak_pipeline_, min_time, max_time, is_live));
1144 }
1145
1146 void PipelineImpl::RendererWrapper::OnLivePlaybackComplete() {
1147   main_task_runner_->PostTask(
1148       FROM_HERE,
1149       base::BindOnce(&PipelineImpl::OnLivePlaybackComplete, weak_pipeline_));
1150 }
1151 #endif
1152
1153 void PipelineImpl::RendererWrapper::OnPipelineError(PipelineStatus error) {
1154   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1155   DCHECK(!error.is_ok()) << "PIPELINE_OK isn't an error!";
1156
1157   // Preserve existing abnormal status.
1158   if (status_ != PIPELINE_OK)
1159     return;
1160
1161   // If the pipeline is already stopping or stopped we don't need to report an
1162   // error. Similarly if the pipeline is suspending or suspended, the error may
1163   // be recoverable, so don't propagate it now, instead let the subsequent seek
1164   // during resume propagate it if it's unrecoverable.
1165   if (state_ == kStopping || state_ == kStopped || state_ == kSuspending ||
1166       state_ == kSuspended) {
1167     return;
1168   }
1169
1170   // PIPELINE_ERROR_HARDWARE_CONTEXT_RESET and DEMUXER_ERROR_DETECTED_HLS are
1171   // not fatal errors. They are just signals to restart or reconfig the
1172   // pipeline.
1173   if (error != PIPELINE_ERROR_HARDWARE_CONTEXT_RESET &&
1174       error != DEMUXER_ERROR_DETECTED_HLS) {
1175     status_ = error;
1176   }
1177
1178   main_task_runner_->PostTask(
1179       FROM_HERE, base::BindOnce(&PipelineImpl::OnError, weak_pipeline_, error));
1180 }
1181
1182 void PipelineImpl::RendererWrapper::OnCdmAttached(CdmAttachedCB cdm_attached_cb,
1183                                                   CdmContext* cdm_context,
1184                                                   bool success) {
1185   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1186
1187   if (success)
1188     cdm_context_ = cdm_context;
1189   std::move(cdm_attached_cb).Run(success);
1190 }
1191
1192 void PipelineImpl::RendererWrapper::CheckPlaybackEnded() {
1193   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1194
1195   if (shared_state_.renderer && !renderer_ended_)
1196     return;
1197
1198   // Don't fire an ended event if we're already in an error state.
1199   if (status_ != PIPELINE_OK)
1200     return;
1201
1202   main_task_runner_->PostTask(
1203       FROM_HERE, base::BindOnce(&PipelineImpl::OnEnded, weak_pipeline_));
1204 }
1205
1206 void PipelineImpl::RendererWrapper::SetState(State next_state) {
1207   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1208   DVLOG(1) << PipelineImpl::GetStateString(state_) << " -> "
1209            << PipelineImpl::GetStateString(next_state);
1210
1211   state_ = next_state;
1212
1213   // TODO(tmathmeyer) Make State serializable so GetStateString won't need
1214   // to be called here.
1215   media_log_->AddEvent<MediaLogEvent::kPipelineStateChange>(
1216       std::string(PipelineImpl::GetStateString(next_state)));
1217 }
1218
1219 void PipelineImpl::RendererWrapper::CompleteSeek(base::TimeDelta seek_time,
1220                                                  PipelineStatus status) {
1221   DVLOG(1) << __func__ << ": seek_time=" << seek_time << ", status=" << status;
1222   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1223   DCHECK(state_ == kStarting || state_ == kSeeking || state_ == kResuming);
1224
1225   if (state_ == kStarting) {
1226     UMA_HISTOGRAM_ENUMERATION("Media.PipelineStatus.Start", status.code(),
1227                               PIPELINE_STATUS_MAX + 1);
1228   }
1229
1230   DCHECK(pending_callbacks_);
1231   pending_callbacks_.reset();
1232
1233   if (status != PIPELINE_OK) {
1234     OnPipelineError(status);
1235     return;
1236   }
1237
1238 #if BUILDFLAG(IS_TIZEN_TV)
1239   shared_state_.renderer->SetContentMimeType(mime_type_);
1240 #endif
1241
1242   shared_state_.renderer->StartPlayingFrom(
1243       std::max(seek_time, demuxer_->GetStartTime()));
1244   {
1245     base::AutoLock auto_lock(shared_state_lock_);
1246     shared_state_.suspend_timestamp = kNoTimestamp;
1247   }
1248
1249   shared_state_.renderer->SetPlaybackRate(playback_rate_);
1250
1251   SetState(kPlaying);
1252   main_task_runner_->PostTask(
1253       FROM_HERE,
1254       base::BindOnce(&PipelineImpl::OnSeekDone, weak_pipeline_, false));
1255 }
1256
1257 void PipelineImpl::RendererWrapper::CompleteSuspend(PipelineStatus status) {
1258   DVLOG(1) << __func__ << ": status=" << status;
1259   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1260   DCHECK_EQ(kSuspending, state_);
1261
1262   DCHECK(pending_callbacks_);
1263   pending_callbacks_.reset();
1264
1265   // In case we are suspending or suspended, the error may be recoverable,
1266   // so don't propagate it now, instead let the subsequent seek during resume
1267   // propagate it if it's unrecoverable.
1268   LOG_IF(WARNING, status != PIPELINE_OK)
1269       << "Encountered pipeline error while suspending: " << status;
1270
1271 #if defined(TIZEN_MULTIMEDIA)
1272   // Keep the renderer without destroying it in tizen.
1273   renderer_suspended_ = true;
1274 #else
1275   DestroyRenderer();
1276 #endif
1277   {
1278     base::AutoLock auto_lock(shared_state_lock_);
1279     shared_state_.statistics.audio_memory_usage = 0;
1280     shared_state_.statistics.video_memory_usage = 0;
1281   }
1282
1283   // Abort any reads the renderer may have kicked off.
1284   demuxer_->AbortPendingReads();
1285
1286   SetState(kSuspended);
1287   main_task_runner_->PostTask(
1288       FROM_HERE, base::BindOnce(&PipelineImpl::OnSuspendDone, weak_pipeline_));
1289 }
1290
1291 void PipelineImpl::RendererWrapper::InitializeDemuxer(
1292     PipelineStatusCallback done_cb) {
1293   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1294
1295   demuxer_->Initialize(this, std::move(done_cb));
1296 }
1297
1298 void PipelineImpl::RendererWrapper::CreateRenderer(
1299     PipelineStatusCallback done_cb) {
1300   DVLOG(1) << __func__;
1301   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1302   DCHECK(state_ == kStarting || state_ == kResuming);
1303
1304   if (HasEncryptedStream() && !cdm_context_) {
1305     LOG(INFO) << __func__ << ": Has encrypted stream but CDM is not set.";
1306     create_renderer_done_cb_ = std::move(done_cb);
1307     OnWaiting(WaitingReason::kNoCdm);
1308     return;
1309   }
1310
1311   CreateRendererInternal(std::move(done_cb));
1312 }
1313
1314 void PipelineImpl::RendererWrapper::OnRendererCreated(
1315     PipelineStatusCallback done_cb,
1316     std::unique_ptr<Renderer> renderer) {
1317   DVLOG(1) << __func__ << ": renderer=" << renderer.get();
1318   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1319
1320   if (!renderer) {
1321     std::move(done_cb).Run({PIPELINE_ERROR_INITIALIZATION_FAILED,
1322                             "Media Renderer creation failed!"});
1323     return;
1324   }
1325
1326   {
1327     base::AutoLock auto_lock(shared_state_lock_);
1328     DCHECK(!shared_state_.renderer);
1329     shared_state_.renderer = std::move(renderer);
1330   }
1331   std::move(done_cb).Run(PIPELINE_OK);
1332 }
1333
1334 void PipelineImpl::RendererWrapper::InitializeRenderer(
1335     PipelineStatusCallback done_cb) {
1336   DVLOG(1) << __func__;
1337   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1338
1339   switch (demuxer_->GetType()) {
1340     case MediaResource::Type::kStream:
1341       if (demuxer_->GetAllStreams().empty()) {
1342         DVLOG(1) << "Error: demuxer does not have an audio or a video stream.";
1343         std::move(done_cb).Run(PIPELINE_ERROR_COULD_NOT_RENDER);
1344         return;
1345       }
1346       break;
1347
1348     case MediaResource::Type::KUrl:
1349       // NOTE: Empty GURL are not valid.
1350       if (!demuxer_->GetMediaUrlParams().media_url.is_valid()) {
1351         DVLOG(1) << "Error: demuxer does not have a valid URL.";
1352         std::move(done_cb).Run(PIPELINE_ERROR_COULD_NOT_RENDER);
1353         return;
1354       }
1355       break;
1356   }
1357
1358   if (cdm_context_) {
1359     shared_state_.renderer->SetCdm(cdm_context_, base::DoNothing());
1360
1361 #if BUILDFLAG(IS_TIZEN_TV)
1362     // Create decrypt media resource for eme
1363     CreateAndInitializeDecryptingMediaResource();
1364 #endif
1365   }
1366
1367   if (latency_hint_)
1368     shared_state_.renderer->SetLatencyHint(latency_hint_);
1369
1370   shared_state_.renderer->SetPreservesPitch(preserves_pitch_);
1371
1372   // Calling SetVolume() before Initialize() allows renderers to optimize for
1373   // power by avoiding initialization of audio output until necessary.
1374   shared_state_.renderer->SetVolume(volume_);
1375
1376   shared_state_.renderer->SetWasPlayedWithUserActivation(
1377       was_played_with_user_activation_);
1378
1379 #if defined(TIZEN_VIDEO_HOLE)
1380   LOG(INFO) << __func__ << " call SetVideoHole : " << is_video_hole_;
1381   shared_state_.renderer->SetVideoHole(is_video_hole_);
1382 #endif
1383 #if BUILDFLAG(IS_TIZEN_TV)
1384   // We need to set the mime type before Initialize() in the case of URL streams
1385   // where the content is dash, because the Initialize() calls prepare in this
1386   // case, and the player needs the mime type to configure itself correctly.
1387   shared_state_.renderer->SetContentMimeType(mime_type_);
1388 #endif
1389
1390   // Initialize Renderer and report timeout UMA.
1391   std::string uma_name = "Media.InitializeRendererTimeout";
1392   base::UmaHistogramEnumeration(uma_name, CallbackTimeoutStatus::kCreate);
1393
1394 #if BUILDFLAG(IS_TIZEN_TV)
1395   if ((MediaResource::Type::kStream == demuxer_->GetType()) && (cdm_context_)) {
1396     if (!decrypting_media_resource_.get()) {
1397       LOG(ERROR) << "decrypting_media_resource is not created yet";
1398       return;
1399     }
1400     shared_state_.renderer->Initialize(decrypting_media_resource_.get(), this,
1401                                        std::move(done_cb));
1402   } else
1403 #endif
1404     shared_state_.renderer->Initialize(
1405         demuxer_, this,
1406         WrapCallbackWithTimeoutHandler(
1407             std::move(done_cb), /*timeout_delay=*/base::Seconds(10),
1408             base::BindOnce(&OnCallbackTimeout, uma_name)));
1409 }
1410
1411 void PipelineImpl::RendererWrapper::DestroyRenderer() {
1412   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1413
1414   // Destroy the renderer outside the lock scope to avoid holding the lock
1415   // while renderer is being destroyed (in case Renderer destructor is costly).
1416   std::unique_ptr<Renderer> renderer;
1417   {
1418     base::AutoLock auto_lock(shared_state_lock_);
1419     renderer.swap(shared_state_.renderer);
1420   }
1421 }
1422
1423 void PipelineImpl::RendererWrapper::ReportMetadata(StartType start_type) {
1424   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
1425
1426   PipelineMetadata metadata;
1427   std::vector<DemuxerStream*> streams;
1428
1429   switch (demuxer_->GetType()) {
1430     case MediaResource::Type::kStream:
1431       metadata.timeline_offset = demuxer_->GetTimelineOffset();
1432       // TODO(servolk): What should we do about metadata for multiple streams?
1433       streams = demuxer_->GetAllStreams();
1434       for (auto* stream : streams) {
1435         if (stream->type() == DemuxerStream::VIDEO && !metadata.has_video) {
1436           metadata.has_video = true;
1437           metadata.natural_size = GetRotatedVideoSize(
1438               stream->video_decoder_config().video_transformation().rotation,
1439               stream->video_decoder_config().natural_size());
1440           metadata.video_decoder_config = stream->video_decoder_config();
1441         }
1442         if (stream->type() == DemuxerStream::AUDIO && !metadata.has_audio) {
1443           metadata.has_audio = true;
1444           metadata.audio_decoder_config = stream->audio_decoder_config();
1445         }
1446       }
1447       break;
1448
1449     case MediaResource::Type::KUrl:
1450       // We don't know if the MediaPlayerRender has Audio/Video until we start
1451       // playing. Conservatively assume that they do.
1452       metadata.has_video = true;
1453       metadata.has_audio = true;
1454       break;
1455   }
1456
1457   main_task_runner_->PostTask(
1458       FROM_HERE,
1459       base::BindOnce(&PipelineImpl::OnMetadata, weak_pipeline_, metadata));
1460
1461   // If suspended start has not been requested, or is not allowed given the
1462   // metadata, continue the normal renderer initialization path.
1463   if (start_type == StartType::kNormal ||
1464       (start_type == StartType::kSuspendAfterMetadataForAudioOnly &&
1465        metadata.has_video)) {
1466     return;
1467   }
1468
1469   // Abort pending render initialization tasks and suspend the pipeline.
1470   pending_callbacks_.reset();
1471   DestroyRenderer();
1472   shared_state_.suspend_timestamp =
1473       std::max(base::TimeDelta(), demuxer_->GetStartTime());
1474   SetState(kSuspended);
1475   main_task_runner_->PostTask(
1476       FROM_HERE,
1477       base::BindOnce(&PipelineImpl::OnSeekDone, weak_pipeline_, true));
1478 }
1479
1480 bool PipelineImpl::RendererWrapper::HasEncryptedStream() {
1481   // Encrypted streams are only handled explicitly for STREAM type.
1482   if (demuxer_->GetType() != MediaResource::Type::kStream)
1483     return false;
1484
1485   auto streams = demuxer_->GetAllStreams();
1486
1487   for (auto* stream : streams) {
1488     if (stream->type() == DemuxerStream::AUDIO &&
1489         stream->audio_decoder_config().is_encrypted())
1490       return true;
1491     if (stream->type() == DemuxerStream::VIDEO &&
1492         stream->video_decoder_config().is_encrypted())
1493       return true;
1494   }
1495
1496   return false;
1497 }
1498
1499 PipelineImpl::PipelineImpl(
1500     scoped_refptr<base::SequencedTaskRunner> media_task_runner,
1501     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
1502     CreateRendererCB create_renderer_cb,
1503 #if defined(TIZEN_VIDEO_HOLE)
1504     bool is_video_hole,
1505 #endif
1506     MediaLog* media_log)
1507     : media_task_runner_(media_task_runner),
1508       create_renderer_cb_(create_renderer_cb),
1509       media_log_(media_log),
1510       client_(nullptr),
1511       playback_rate_(kDefaultPlaybackRate),
1512       volume_(kDefaultVolume),
1513       is_suspended_(false) {
1514   DVLOG(2) << __func__;
1515   DCHECK(create_renderer_cb_);
1516
1517   renderer_wrapper_ = std::make_unique<RendererWrapper>(
1518       media_task_runner_, std::move(main_task_runner),
1519 #if defined(TIZEN_VIDEO_HOLE)
1520       is_video_hole,
1521 #endif
1522       media_log_);
1523 }
1524
1525 PipelineImpl::~PipelineImpl() {
1526   DVLOG(2) << __func__;
1527   DCHECK(thread_checker_.CalledOnValidThread());
1528   DCHECK(!client_) << "Stop() must complete before destroying object";
1529   DCHECK(!seek_cb_);
1530   DCHECK(!suspend_cb_);
1531   DCHECK(!weak_factory_.HasWeakPtrs())
1532       << "Stop() should have invalidated all weak pointers";
1533
1534   // RendererWrapper is deleted on the media thread.
1535   media_task_runner_->DeleteSoon(FROM_HERE, renderer_wrapper_.release());
1536 }
1537
1538 void PipelineImpl::Start(StartType start_type,
1539                          Demuxer* demuxer,
1540                          Client* client,
1541                          PipelineStatusCallback seek_cb) {
1542   DVLOG(2) << __func__ << ": start_type=" << static_cast<int>(start_type);
1543   DCHECK(thread_checker_.CalledOnValidThread());
1544   DCHECK(demuxer);
1545   DCHECK(client);
1546   DCHECK(seek_cb);
1547
1548   DCHECK(!client_);
1549   DCHECK(!seek_cb_);
1550   client_ = client;
1551   seek_cb_ = std::move(seek_cb);
1552   last_media_time_ = base::TimeDelta();
1553   seek_time_ = kNoTimestamp;
1554   external_video_frame_request_signaled_ = false;
1555
1556   // By default, create a default renderer to avoid additional start-to-play
1557   // latency caused by asynchronous Renderer creation. When |start_type| is
1558   // kSuspendAfterMetadata, latency is not important and the video may never
1559   // play. In this case, not creating a default renderer to reduce memory usage.
1560   std::unique_ptr<Renderer> default_renderer;
1561   if (start_type != StartType::kSuspendAfterMetadata)
1562     default_renderer = create_renderer_cb_.Run(absl::nullopt);
1563
1564   media_task_runner_->PostTask(
1565       FROM_HERE,
1566       base::BindOnce(&RendererWrapper::Start,
1567                      base::Unretained(renderer_wrapper_.get()), start_type,
1568                      demuxer, std::move(default_renderer),
1569                      weak_factory_.GetWeakPtr()));
1570 }
1571
1572 void PipelineImpl::Stop() {
1573   DVLOG(2) << __func__;
1574   DCHECK(thread_checker_.CalledOnValidThread());
1575
1576   if (!IsRunning()) {
1577     DVLOG(2) << "Media pipeline isn't running. Ignoring Stop()";
1578     return;
1579   }
1580
1581   if (media_task_runner_->RunsTasksInCurrentSequence()) {
1582     // This path is executed by unittests that share media and main threads.
1583     renderer_wrapper_->Stop();
1584   } else {
1585     // This path is executed by production code where the two task runners -
1586     // main and media - live on different threads.
1587     media_task_runner_->PostTask(
1588         FROM_HERE, base::BindOnce(&RendererWrapper::Stop,
1589                                   base::Unretained(renderer_wrapper_.get())));
1590   }
1591
1592   // Once the pipeline is stopped, nothing is reported back to the client.
1593   // Reset all callbacks and client handle.
1594   seek_cb_.Reset();
1595   suspend_cb_.Reset();
1596   client_ = nullptr;
1597
1598   // Invalidate self weak pointers effectively canceling all pending
1599   // notifications in the message queue.
1600   weak_factory_.InvalidateWeakPtrs();
1601 }
1602
1603 void PipelineImpl::Seek(base::TimeDelta time, PipelineStatusCallback seek_cb) {
1604   DVLOG(2) << __func__ << " to " << time;
1605   DCHECK(thread_checker_.CalledOnValidThread());
1606   DCHECK(seek_cb);
1607
1608   if (!IsRunning()) {
1609     DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek().";
1610     std::move(seek_cb).Run(PIPELINE_ERROR_INVALID_STATE);
1611     return;
1612   }
1613
1614   DCHECK(!seek_cb_);
1615   seek_cb_ = std::move(seek_cb);
1616   seek_time_ = time;
1617   last_media_time_ = base::TimeDelta();
1618   media_task_runner_->PostTask(
1619       FROM_HERE,
1620       base::BindOnce(&RendererWrapper::Seek,
1621                      base::Unretained(renderer_wrapper_.get()), time));
1622 }
1623
1624 void PipelineImpl::Suspend(PipelineStatusCallback suspend_cb) {
1625   DVLOG(2) << __func__;
1626   DCHECK(suspend_cb);
1627
1628   DCHECK(IsRunning());
1629   DCHECK(!suspend_cb_);
1630   suspend_cb_ = std::move(suspend_cb);
1631
1632   media_task_runner_->PostTask(
1633       FROM_HERE, base::BindOnce(&RendererWrapper::Suspend,
1634                                 base::Unretained(renderer_wrapper_.get())));
1635 }
1636
1637 void PipelineImpl::Resume(base::TimeDelta time,
1638                           PipelineStatusCallback seek_cb) {
1639   DVLOG(2) << __func__;
1640   DCHECK(thread_checker_.CalledOnValidThread());
1641   DCHECK(seek_cb);
1642
1643   DCHECK(IsRunning());
1644   DCHECK(!seek_cb_);
1645   seek_cb_ = std::move(seek_cb);
1646   seek_time_ = time;
1647   last_media_time_ = base::TimeDelta();
1648   external_video_frame_request_signaled_ = false;
1649
1650   std::unique_ptr<Renderer> default_renderer;
1651 #if defined(TIZEN_MULTIMEDIA)
1652   // Do not need to create the renderer if suspended in tizen.
1653   if (!renderer_wrapper_->IsRendererSuspended())
1654 #endif
1655   {
1656     // Always create a default renderer for Resume(). Creation error is handled in
1657     // `RendererWrapper::Resume()`.
1658     default_renderer = create_renderer_cb_.Run(absl::nullopt);
1659   }
1660
1661   media_task_runner_->PostTask(
1662       FROM_HERE, base::BindOnce(&RendererWrapper::Resume,
1663                                 base::Unretained(renderer_wrapper_.get()),
1664                                 std::move(default_renderer), time));
1665 }
1666
1667 bool PipelineImpl::IsRunning() const {
1668   DCHECK(thread_checker_.CalledOnValidThread());
1669   return !!client_;
1670 }
1671
1672 bool PipelineImpl::IsSuspended() const {
1673   DVLOG(2) << __func__ << "(" << is_suspended_ << ")";
1674   DCHECK(thread_checker_.CalledOnValidThread());
1675   return is_suspended_;
1676 }
1677
1678 double PipelineImpl::GetPlaybackRate() const {
1679   DCHECK(thread_checker_.CalledOnValidThread());
1680   return playback_rate_;
1681 }
1682
1683 void PipelineImpl::SetPlaybackRate(double playback_rate) {
1684   DVLOG(2) << __func__ << "(" << playback_rate << ")";
1685   DCHECK(thread_checker_.CalledOnValidThread());
1686
1687   // Not checking IsRunning() so we can set the playback rate before Start().
1688
1689   if (playback_rate < 0.0) {
1690     DVLOG(1) << __func__ << ": Invalid playback rate " << playback_rate;
1691     return;
1692   }
1693
1694   playback_rate_ = playback_rate;
1695   media_task_runner_->PostTask(
1696       FROM_HERE, base::BindOnce(&RendererWrapper::SetPlaybackRate,
1697                                 base::Unretained(renderer_wrapper_.get()),
1698                                 playback_rate_));
1699 }
1700
1701 float PipelineImpl::GetVolume() const {
1702   DCHECK(thread_checker_.CalledOnValidThread());
1703   return volume_;
1704 }
1705
1706 void PipelineImpl::SetVolume(float volume) {
1707   DVLOG(2) << __func__ << "(" << volume << ")";
1708   DCHECK(thread_checker_.CalledOnValidThread());
1709
1710   // Not checking IsRunning() so we can set the volume before Start().
1711
1712   if (volume < 0.0f) {
1713     DVLOG(1) << __func__ << ": Invalid volume " << volume;
1714     return;
1715   }
1716
1717   volume_ = volume;
1718   media_task_runner_->PostTask(
1719       FROM_HERE,
1720       base::BindOnce(&RendererWrapper::SetVolume,
1721                      base::Unretained(renderer_wrapper_.get()), volume_));
1722 }
1723
1724 void PipelineImpl::SetLatencyHint(
1725     absl::optional<base::TimeDelta> latency_hint) {
1726   DVLOG(1) << __func__ << "("
1727            << (latency_hint
1728                    ? base::NumberToString(latency_hint->InMilliseconds()) + "ms"
1729                    : "null_opt")
1730            << ")";
1731   DCHECK(!latency_hint || (*latency_hint >= base::TimeDelta()));
1732   DCHECK(thread_checker_.CalledOnValidThread());
1733
1734   // Not checking IsRunning() so we can set the latency hint before Start().
1735   media_task_runner_->PostTask(
1736       FROM_HERE,
1737       base::BindOnce(&RendererWrapper::SetLatencyHint,
1738                      base::Unretained(renderer_wrapper_.get()), latency_hint));
1739 }
1740
1741 void PipelineImpl::SetPreservesPitch(bool preserves_pitch) {
1742   DCHECK(thread_checker_.CalledOnValidThread());
1743
1744   media_task_runner_->PostTask(
1745       FROM_HERE, base::BindOnce(&RendererWrapper::SetPreservesPitch,
1746                                 base::Unretained(renderer_wrapper_.get()),
1747                                 preserves_pitch));
1748 }
1749
1750 void PipelineImpl::SetWasPlayedWithUserActivation(
1751     bool was_played_with_user_activation) {
1752   DCHECK(thread_checker_.CalledOnValidThread());
1753
1754   media_task_runner_->PostTask(
1755       FROM_HERE,
1756       base::BindOnce(&RendererWrapper::SetWasPlayedWithUserActivation,
1757                      base::Unretained(renderer_wrapper_.get()),
1758                      was_played_with_user_activation));
1759 }
1760
1761 base::TimeDelta PipelineImpl::GetMediaTime() const {
1762   DCHECK(thread_checker_.CalledOnValidThread());
1763
1764   // Don't trust renderer time during a pending seek. Renderer may return
1765   // pre-seek time which may corrupt |last_media_time_| used for clamping.
1766   if (seek_time_ != kNoTimestamp) {
1767     DVLOG(3) << __func__ << ": (seeking) " << seek_time_.InMilliseconds()
1768              << " ms";
1769     return seek_time_;
1770   }
1771
1772   base::TimeDelta media_time = renderer_wrapper_->GetMediaTime();
1773
1774   // Clamp current media time to the last reported value, this prevents higher
1775   // level clients from seeing time go backwards based on inaccurate or spurious
1776   // delay values reported to the AudioClock.
1777   //
1778   // It is expected that such events are transient and will be recovered as
1779   // rendering continues over time.
1780   if (media_time < last_media_time_) {
1781     DVLOG(2) << __func__ << ": actual=" << media_time
1782              << " clamped=" << last_media_time_;
1783     return last_media_time_;
1784   }
1785
1786   DVLOG(3) << __func__ << ": " << media_time.InMilliseconds() << " ms";
1787   last_media_time_ = media_time;
1788   return last_media_time_;
1789 }
1790
1791 Ranges<base::TimeDelta> PipelineImpl::GetBufferedTimeRanges() const {
1792   DCHECK(thread_checker_.CalledOnValidThread());
1793   return renderer_wrapper_->GetBufferedTimeRanges();
1794 }
1795
1796 base::TimeDelta PipelineImpl::GetMediaDuration() const {
1797   DCHECK(thread_checker_.CalledOnValidThread());
1798   return duration_;
1799 }
1800
1801 bool PipelineImpl::DidLoadingProgress() {
1802   DCHECK(thread_checker_.CalledOnValidThread());
1803   return renderer_wrapper_->DidLoadingProgress();
1804 }
1805
1806 PipelineStatistics PipelineImpl::GetStatistics() const {
1807   DCHECK(thread_checker_.CalledOnValidThread());
1808   return renderer_wrapper_->GetStatistics();
1809 }
1810
1811 void PipelineImpl::SetCdm(CdmContext* cdm_context,
1812                           CdmAttachedCB cdm_attached_cb) {
1813   DVLOG(2) << __func__;
1814   DCHECK(thread_checker_.CalledOnValidThread());
1815   DCHECK(cdm_context);
1816   DCHECK(cdm_attached_cb);
1817
1818   // Not checking IsRunning() so we can set the CDM before Start().
1819
1820   media_task_runner_->PostTask(
1821       FROM_HERE,
1822       base::BindOnce(
1823           &RendererWrapper::SetCdm, base::Unretained(renderer_wrapper_.get()),
1824           cdm_context,
1825           base::BindPostTaskToCurrentDefault(std::move(cdm_attached_cb))));
1826 }
1827
1828 #if defined(TIZEN_MULTIMEDIA)
1829 void PipelineImpl::ToggleFullscreenMode(bool is_fullscreen,
1830                                         ToggledFullscreenCB cb) {
1831   media_task_runner_->PostTask(
1832       FROM_HERE, base::BindOnce(&RendererWrapper::ToggleFullscreenMode,
1833                                 base::Unretained(renderer_wrapper_.get()),
1834                                 is_fullscreen, std::move(cb)));
1835 }
1836 #endif
1837
1838 #if defined(TIZEN_VIDEO_HOLE)
1839 void PipelineImpl::SetMediaGeometry(const gfx::RectF rect_f) {
1840   media_task_runner_->PostTask(
1841       FROM_HERE,
1842       base::BindOnce(&RendererWrapper::SetMediaGeometry,
1843                      base::Unretained(renderer_wrapper_.get()), rect_f));
1844 }
1845 #endif
1846
1847 #define RETURN_STRING(state) \
1848   case state:                \
1849     return #state;
1850
1851 // static
1852 const char* PipelineImpl::GetStateString(State state) {
1853   switch (state) {
1854     RETURN_STRING(kCreated);
1855     RETURN_STRING(kStarting);
1856     RETURN_STRING(kSeeking);
1857     RETURN_STRING(kPlaying);
1858     RETURN_STRING(kStopping);
1859     RETURN_STRING(kStopped);
1860     RETURN_STRING(kSuspending);
1861     RETURN_STRING(kSuspended);
1862     RETURN_STRING(kResuming);
1863   }
1864   NOTREACHED_NORETURN();
1865 }
1866
1867 #undef RETURN_STRING
1868
1869 void PipelineImpl::AsyncCreateRenderer(
1870     absl::optional<RendererType> renderer_type,
1871     RendererCreatedCB renderer_created_cb) {
1872   DVLOG(2) << __func__;
1873   DCHECK(thread_checker_.CalledOnValidThread());
1874
1875   std::move(renderer_created_cb).Run(create_renderer_cb_.Run(renderer_type));
1876 }
1877
1878 void PipelineImpl::OnError(PipelineStatus error) {
1879   DVLOG(2) << __func__;
1880   DCHECK(thread_checker_.CalledOnValidThread());
1881   DCHECK(!error.is_ok()) << "PIPELINE_OK isn't an error!";
1882   DCHECK(IsRunning());
1883
1884   // If the error happens during starting/seeking/suspending/resuming,
1885   // report the error via the completion callback for those tasks.
1886   // Else report error via the client interface.
1887   if (seek_cb_) {
1888     std::move(seek_cb_).Run(error);
1889     return;
1890   }
1891
1892   if (suspend_cb_) {
1893     std::move(suspend_cb_).Run(error);
1894     return;
1895   }
1896
1897   DCHECK(client_);
1898   client_->OnError(error);
1899 }
1900
1901 void PipelineImpl::OnFallback(PipelineStatus status) {
1902   client_->OnFallback(std::move(status).AddHere());
1903 }
1904
1905 void PipelineImpl::OnEnded() {
1906   DVLOG(2) << __func__;
1907   DCHECK(thread_checker_.CalledOnValidThread());
1908   DCHECK(IsRunning());
1909
1910   DCHECK(client_);
1911   client_->OnEnded();
1912 }
1913
1914 void PipelineImpl::OnMetadata(const PipelineMetadata& metadata) {
1915   DVLOG(2) << __func__;
1916   DCHECK(thread_checker_.CalledOnValidThread());
1917   DCHECK(IsRunning());
1918
1919   DCHECK(client_);
1920   client_->OnMetadata(metadata);
1921 }
1922
1923 void PipelineImpl::OnBufferingStateChange(BufferingState state,
1924                                           BufferingStateChangeReason reason) {
1925   DCHECK(thread_checker_.CalledOnValidThread());
1926   DCHECK(IsRunning());
1927
1928   DCHECK(client_);
1929   client_->OnBufferingStateChange(state, reason);
1930 }
1931
1932 #if BUILDFLAG(IS_TIZEN_TV)
1933 void PipelineImpl::SetContentMimeType(const std::string& mime_type) {
1934   DVLOG(2) << __func__ << "(" << mime_type << ")";
1935   DCHECK(thread_checker_.CalledOnValidThread());
1936   media_task_runner_->PostTask(
1937       FROM_HERE,
1938       base::BindOnce(&RendererWrapper::SetContentMimeType,
1939                      base::Unretained(renderer_wrapper_.get()), mime_type));
1940 }
1941
1942 void PipelineImpl::SetParentalRatingResult(bool is_pass) {
1943   DVLOG(2) << __func__;
1944   DCHECK(thread_checker_.CalledOnValidThread());
1945   renderer_wrapper_->SetParentalRatingResult(is_pass);
1946 }
1947 #endif
1948
1949 void PipelineImpl::OnDurationChange(base::TimeDelta duration) {
1950   DVLOG(2) << __func__;
1951   DCHECK(thread_checker_.CalledOnValidThread());
1952   DCHECK(IsRunning());
1953
1954   duration_ = duration;
1955
1956   DCHECK(client_);
1957   client_->OnDurationChange();
1958 }
1959
1960 void PipelineImpl::OnWaiting(WaitingReason reason) {
1961   DVLOG(2) << __func__;
1962   DCHECK(thread_checker_.CalledOnValidThread());
1963   DCHECK(IsRunning());
1964
1965   DCHECK(client_);
1966   client_->OnWaiting(reason);
1967 }
1968
1969 void PipelineImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
1970   DVLOG(2) << __func__;
1971   DCHECK(thread_checker_.CalledOnValidThread());
1972   DCHECK(IsRunning());
1973
1974   DCHECK(client_);
1975   client_->OnVideoNaturalSizeChange(size);
1976 }
1977
1978 void PipelineImpl::OnVideoOpacityChange(bool opaque) {
1979   DVLOG(2) << __func__;
1980   DCHECK(thread_checker_.CalledOnValidThread());
1981   DCHECK(IsRunning());
1982
1983   DCHECK(client_);
1984   client_->OnVideoOpacityChange(opaque);
1985 }
1986
1987 void PipelineImpl::OnVideoFrameRateChange(absl::optional<int> fps) {
1988   DVLOG(2) << __func__;
1989   DCHECK(thread_checker_.CalledOnValidThread());
1990   DCHECK(IsRunning());
1991
1992   DCHECK(client_);
1993   client_->OnVideoFrameRateChange(fps);
1994 }
1995
1996 void PipelineImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
1997   DVLOG(2) << __func__;
1998   DCHECK(thread_checker_.CalledOnValidThread());
1999   DCHECK(IsRunning());
2000
2001   DCHECK(client_);
2002   client_->OnAudioConfigChange(config);
2003 }
2004
2005 void PipelineImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
2006   DVLOG(2) << __func__;
2007   DCHECK(thread_checker_.CalledOnValidThread());
2008   DCHECK(IsRunning());
2009
2010   DCHECK(client_);
2011   client_->OnVideoConfigChange(config);
2012 }
2013
2014 void PipelineImpl::OnVideoAverageKeyframeDistanceUpdate() {
2015   DVLOG(2) << __func__;
2016   DCHECK(thread_checker_.CalledOnValidThread());
2017   DCHECK(IsRunning());
2018
2019   DCHECK(client_);
2020   client_->OnVideoAverageKeyframeDistanceUpdate();
2021 }
2022
2023 void PipelineImpl::OnAudioPipelineInfoChange(const AudioPipelineInfo& info) {
2024   DVLOG(2) << __func__ << ": info=" << info;
2025   DCHECK(thread_checker_.CalledOnValidThread());
2026   DCHECK(IsRunning());
2027
2028   DCHECK(client_);
2029   client_->OnAudioPipelineInfoChange(info);
2030 }
2031
2032 void PipelineImpl::OnVideoPipelineInfoChange(const VideoPipelineInfo& info) {
2033   DVLOG(2) << __func__ << ": info=" << info;
2034   DCHECK(thread_checker_.CalledOnValidThread());
2035   DCHECK(IsRunning());
2036
2037   DCHECK(client_);
2038   client_->OnVideoPipelineInfoChange(info);
2039 }
2040
2041 #if defined(TIZEN_MULTIMEDIA)
2042 void PipelineImpl::OnRequestSuspend(bool resource_conflicted) {
2043   DVLOG(3) << __func__;
2044   client_->OnRequestSuspend(resource_conflicted);
2045 }
2046
2047 void PipelineImpl::OnSeekableTimeChange(base::TimeDelta min_time,
2048                                         base::TimeDelta max_time,
2049                                         bool is_live) {
2050   DVLOG(3) << __func__;
2051   client_->OnSeekableTimeChange(min_time, max_time, is_live);
2052 }
2053
2054 void PipelineImpl::OnLivePlaybackComplete() {
2055   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
2056   client_->OnLivePlaybackComplete();
2057 }
2058 #endif
2059
2060 void PipelineImpl::OnSeekDone(bool is_suspended) {
2061   DVLOG(3) << __func__ << ": is_suspended=" << is_suspended;
2062   DCHECK(thread_checker_.CalledOnValidThread());
2063   DCHECK(IsRunning());
2064
2065   seek_time_ = kNoTimestamp;
2066   is_suspended_ = is_suspended;
2067
2068   // `seek_cb_` could have been reset in OnError().
2069   if (seek_cb_)
2070     std::move(seek_cb_).Run(PIPELINE_OK);
2071 }
2072
2073 void PipelineImpl::OnSuspendDone() {
2074   DVLOG(3) << __func__;
2075   DCHECK(thread_checker_.CalledOnValidThread());
2076   DCHECK(IsRunning());
2077
2078   is_suspended_ = true;
2079
2080   // `suspend_cb_` could have been reset in OnError().
2081   if (suspend_cb_)
2082     std::move(suspend_cb_).Run(PIPELINE_OK);
2083 }
2084
2085 }  // namespace media