1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/renderers/video_renderer_impl.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/location.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/threading/platform_thread.h"
13 #include "base/trace_event/trace_event.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "media/base/buffers.h"
16 #include "media/base/limits.h"
17 #include "media/base/pipeline.h"
18 #include "media/base/video_frame.h"
22 VideoRendererImpl::VideoRendererImpl(
23 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
24 ScopedVector
<VideoDecoder
> decoders
,
26 const scoped_refptr
<MediaLog
>& media_log
)
27 : task_runner_(task_runner
),
29 new VideoFrameStream(task_runner
, decoders
.Pass(), media_log
)),
31 received_end_of_stream_(false),
32 rendered_end_of_stream_(false),
33 frame_available_(&lock_
),
34 state_(kUninitialized
),
37 drop_frames_(drop_frames
),
38 buffering_state_(BUFFERING_HAVE_NOTHING
),
39 last_timestamp_(kNoTimestamp()),
40 last_painted_timestamp_(kNoTimestamp()),
43 is_shutting_down_(false),
47 VideoRendererImpl::~VideoRendererImpl() {
48 DCHECK(task_runner_
->BelongsToCurrentThread());
51 base::AutoLock
auto_lock(lock_
);
52 is_shutting_down_
= true;
53 frame_available_
.Signal();
56 if (!thread_
.is_null())
57 base::PlatformThread::Join(thread_
);
59 if (!init_cb_
.is_null())
60 base::ResetAndReturn(&init_cb_
).Run(PIPELINE_ERROR_ABORT
);
62 if (!flush_cb_
.is_null())
63 base::ResetAndReturn(&flush_cb_
).Run();
66 void VideoRendererImpl::Flush(const base::Closure
& callback
) {
67 DVLOG(1) << __FUNCTION__
;
68 DCHECK(task_runner_
->BelongsToCurrentThread());
69 base::AutoLock
auto_lock(lock_
);
70 DCHECK_EQ(state_
, kPlaying
);
74 // This is necessary if the |video_frame_stream_| has already seen an end of
75 // stream and needs to drain it before flushing it.
76 ready_frames_
.clear();
77 if (buffering_state_
!= BUFFERING_HAVE_NOTHING
) {
78 buffering_state_
= BUFFERING_HAVE_NOTHING
;
79 buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
81 received_end_of_stream_
= false;
82 rendered_end_of_stream_
= false;
84 video_frame_stream_
->Reset(
85 base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone
,
86 weak_factory_
.GetWeakPtr()));
89 void VideoRendererImpl::StartPlayingFrom(base::TimeDelta timestamp
) {
90 DVLOG(1) << __FUNCTION__
<< "(" << timestamp
.InMicroseconds() << ")";
91 DCHECK(task_runner_
->BelongsToCurrentThread());
92 base::AutoLock
auto_lock(lock_
);
93 DCHECK_EQ(state_
, kFlushed
);
94 DCHECK(!pending_read_
);
95 DCHECK(ready_frames_
.empty());
96 DCHECK_EQ(buffering_state_
, BUFFERING_HAVE_NOTHING
);
99 start_timestamp_
= timestamp
;
100 AttemptRead_Locked();
103 void VideoRendererImpl::Initialize(
104 DemuxerStream
* stream
,
105 const PipelineStatusCB
& init_cb
,
106 const SetDecryptorReadyCB
& set_decryptor_ready_cb
,
107 const StatisticsCB
& statistics_cb
,
108 const BufferingStateCB
& buffering_state_cb
,
109 const PaintCB
& paint_cb
,
110 const base::Closure
& ended_cb
,
111 const PipelineStatusCB
& error_cb
,
112 const TimeDeltaCB
& get_time_cb
,
113 const base::Closure
& waiting_for_decryption_key_cb
) {
114 DCHECK(task_runner_
->BelongsToCurrentThread());
115 base::AutoLock
auto_lock(lock_
);
117 DCHECK_EQ(stream
->type(), DemuxerStream::VIDEO
);
118 DCHECK(!init_cb
.is_null());
119 DCHECK(!statistics_cb
.is_null());
120 DCHECK(!buffering_state_cb
.is_null());
121 DCHECK(!paint_cb
.is_null());
122 DCHECK(!ended_cb
.is_null());
123 DCHECK(!get_time_cb
.is_null());
124 DCHECK_EQ(kUninitialized
, state_
);
126 low_delay_
= (stream
->liveness() == DemuxerStream::LIVENESS_LIVE
);
128 // Always post |init_cb_| because |this| could be destroyed if initialization
130 init_cb_
= BindToCurrentLoop(init_cb
);
132 statistics_cb_
= statistics_cb
;
133 buffering_state_cb_
= buffering_state_cb
;
134 paint_cb_
= paint_cb
,
135 ended_cb_
= ended_cb
;
136 error_cb_
= error_cb
;
137 get_time_cb_
= get_time_cb
;
138 state_
= kInitializing
;
140 video_frame_stream_
->Initialize(
141 stream
, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized
,
142 weak_factory_
.GetWeakPtr()),
143 set_decryptor_ready_cb
, statistics_cb
, waiting_for_decryption_key_cb
);
146 void VideoRendererImpl::CreateVideoThread() {
147 // This may fail and cause a crash if there are too many threads created in
148 // the current process. See http://crbug.com/443291
149 CHECK(base::PlatformThread::Create(0, this, &thread_
));
152 // Bump up our priority so our sleeping is more accurate.
153 // TODO(scherkus): find out if this is necessary, but it seems to help.
154 ::SetThreadPriority(thread_
.platform_handle(), THREAD_PRIORITY_ABOVE_NORMAL
);
155 #endif // defined(OS_WIN)
158 void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success
) {
159 DCHECK(task_runner_
->BelongsToCurrentThread());
160 base::AutoLock
auto_lock(lock_
);
161 DCHECK_EQ(state_
, kInitializing
);
164 state_
= kUninitialized
;
165 base::ResetAndReturn(&init_cb_
).Run(DECODER_ERROR_NOT_SUPPORTED
);
169 // We're all good! Consider ourselves flushed. (ThreadMain() should never
170 // see us in the kUninitialized state).
171 // Since we had an initial Preroll(), we consider ourself flushed, because we
172 // have not populated any buffers yet.
177 base::ResetAndReturn(&init_cb_
).Run(PIPELINE_OK
);
180 // PlatformThread::Delegate implementation.
181 void VideoRendererImpl::ThreadMain() {
182 base::PlatformThread::SetName("CrVideoRenderer");
184 // The number of milliseconds to idle when we do not have anything to do.
185 // Nothing special about the value, other than we're being more OS-friendly
186 // than sleeping for 1 millisecond.
188 // TODO(scherkus): switch to pure event-driven frame timing instead of this
189 // kIdleTimeDelta business http://crbug.com/106874
190 const base::TimeDelta kIdleTimeDelta
=
191 base::TimeDelta::FromMilliseconds(10);
193 // If we have no frames and haven't painted any frame for certain amount of
194 // time, declare BUFFERING_HAVE_NOTHING.
195 const base::TimeDelta kTimeToDeclareHaveNothing
=
196 base::TimeDelta::FromSeconds(3);
199 base::AutoLock
auto_lock(lock_
);
201 // Thread exit condition.
202 if (is_shutting_down_
)
205 // Remain idle as long as we're not playing.
206 if (state_
!= kPlaying
|| buffering_state_
!= BUFFERING_HAVE_ENOUGH
) {
207 UpdateStatsAndWait_Locked(kIdleTimeDelta
);
211 base::TimeDelta now
= get_time_cb_
.Run();
213 // Remain idle until we have the next frame ready for rendering.
214 if (ready_frames_
.empty()) {
215 if (received_end_of_stream_
) {
216 if (!rendered_end_of_stream_
) {
217 rendered_end_of_stream_
= true;
218 task_runner_
->PostTask(FROM_HERE
, ended_cb_
);
220 } else if (last_painted_timestamp_
!= kNoTimestamp() &&
221 now
- last_painted_timestamp_
>= kTimeToDeclareHaveNothing
) {
222 buffering_state_
= BUFFERING_HAVE_NOTHING
;
223 task_runner_
->PostTask(
224 FROM_HERE
, base::Bind(buffering_state_cb_
, BUFFERING_HAVE_NOTHING
));
227 UpdateStatsAndWait_Locked(kIdleTimeDelta
);
231 base::TimeDelta target_paint_timestamp
= ready_frames_
.front()->timestamp();
232 base::TimeDelta latest_paint_timestamp
;
234 // Deadline is defined as the duration between this frame and the next
235 // frame, using the delta between this frame and the previous frame as the
236 // assumption for frame duration.
238 // TODO(scherkus): This can be vastly improved. Use a histogram to measure
239 // the accuracy of our frame timing code. http://crbug.com/149829
240 if (last_timestamp_
== kNoTimestamp()) {
241 latest_paint_timestamp
= base::TimeDelta::Max();
243 base::TimeDelta duration
= target_paint_timestamp
- last_timestamp_
;
244 latest_paint_timestamp
= target_paint_timestamp
+ duration
;
247 // Remain idle until we've reached our target paint window.
248 if (now
< target_paint_timestamp
) {
249 UpdateStatsAndWait_Locked(kIdleTimeDelta
);
253 if (now
> latest_paint_timestamp
&& drop_frames_
) {
254 DropNextReadyFrame_Locked();
258 // Congratulations! You've made it past the video frame timing gauntlet.
260 // At this point enough time has passed that the next frame that ready for
262 PaintNextReadyFrame_Locked();
266 void VideoRendererImpl::PaintNextReadyFrame_Locked() {
267 lock_
.AssertAcquired();
269 scoped_refptr
<VideoFrame
> next_frame
= ready_frames_
.front();
270 ready_frames_
.pop_front();
273 last_timestamp_
= next_frame
->timestamp();
274 last_painted_timestamp_
= next_frame
->timestamp();
276 paint_cb_
.Run(next_frame
);
278 task_runner_
->PostTask(
280 base::Bind(&VideoRendererImpl::AttemptRead
, weak_factory_
.GetWeakPtr()));
283 void VideoRendererImpl::DropNextReadyFrame_Locked() {
284 TRACE_EVENT0("media", "VideoRendererImpl:frameDropped");
286 lock_
.AssertAcquired();
288 last_timestamp_
= ready_frames_
.front()->timestamp();
289 ready_frames_
.pop_front();
293 task_runner_
->PostTask(
295 base::Bind(&VideoRendererImpl::AttemptRead
, weak_factory_
.GetWeakPtr()));
298 void VideoRendererImpl::FrameReady(VideoFrameStream::Status status
,
299 const scoped_refptr
<VideoFrame
>& frame
) {
300 DCHECK(task_runner_
->BelongsToCurrentThread());
301 base::AutoLock
auto_lock(lock_
);
302 DCHECK_NE(state_
, kUninitialized
);
303 DCHECK_NE(state_
, kFlushed
);
305 CHECK(pending_read_
);
306 pending_read_
= false;
308 if (status
== VideoFrameStream::DECODE_ERROR
||
309 status
== VideoFrameStream::DECRYPT_ERROR
) {
310 DCHECK(!frame
.get());
311 PipelineStatus error
= PIPELINE_ERROR_DECODE
;
312 if (status
== VideoFrameStream::DECRYPT_ERROR
)
313 error
= PIPELINE_ERROR_DECRYPT
;
314 task_runner_
->PostTask(FROM_HERE
, base::Bind(error_cb_
, error
));
318 // Already-queued VideoFrameStream ReadCB's can fire after various state
319 // transitions have happened; in that case just drop those frames immediately.
320 if (state_
== kFlushing
)
323 DCHECK_EQ(state_
, kPlaying
);
325 // Can happen when demuxers are preparing for a new Seek().
327 DCHECK_EQ(status
, VideoFrameStream::DEMUXER_READ_ABORTED
);
331 if (frame
->end_of_stream()) {
332 DCHECK(!received_end_of_stream_
);
333 received_end_of_stream_
= true;
335 // Maintain the latest frame decoded so the correct frame is displayed after
336 // prerolling has completed.
337 if (frame
->timestamp() <= start_timestamp_
)
338 ready_frames_
.clear();
339 AddReadyFrame_Locked(frame
);
342 // Signal buffering state if we've met our conditions for having enough data.
343 if (buffering_state_
!= BUFFERING_HAVE_ENOUGH
&& HaveEnoughData_Locked())
344 TransitionToHaveEnough_Locked();
346 // Always request more decoded video if we have capacity. This serves two
348 // 1) Prerolling while paused
349 // 2) Keeps decoding going if video rendering thread starts falling behind
350 AttemptRead_Locked();
353 bool VideoRendererImpl::HaveEnoughData_Locked() {
354 DCHECK_EQ(state_
, kPlaying
);
355 return received_end_of_stream_
||
356 !video_frame_stream_
->CanReadWithoutStalling() ||
357 ready_frames_
.size() >= static_cast<size_t>(limits::kMaxVideoFrames
) ||
358 (low_delay_
&& ready_frames_
.size() > 0);
361 void VideoRendererImpl::TransitionToHaveEnough_Locked() {
362 DCHECK(task_runner_
->BelongsToCurrentThread());
363 DCHECK_EQ(buffering_state_
, BUFFERING_HAVE_NOTHING
);
365 if (!ready_frames_
.empty()) {
366 // Because the clock might remain paused in for an undetermined amount
367 // of time (e.g., seeking while paused), paint the first frame.
368 PaintNextReadyFrame_Locked();
371 buffering_state_
= BUFFERING_HAVE_ENOUGH
;
372 buffering_state_cb_
.Run(BUFFERING_HAVE_ENOUGH
);
375 void VideoRendererImpl::AddReadyFrame_Locked(
376 const scoped_refptr
<VideoFrame
>& frame
) {
377 DCHECK(task_runner_
->BelongsToCurrentThread());
378 lock_
.AssertAcquired();
379 DCHECK(!frame
->end_of_stream());
381 ready_frames_
.push_back(frame
);
382 DCHECK_LE(ready_frames_
.size(),
383 static_cast<size_t>(limits::kMaxVideoFrames
));
385 // Avoid needlessly waking up |thread_| unless playing.
386 if (state_
== kPlaying
)
387 frame_available_
.Signal();
390 void VideoRendererImpl::AttemptRead() {
391 base::AutoLock
auto_lock(lock_
);
392 AttemptRead_Locked();
395 void VideoRendererImpl::AttemptRead_Locked() {
396 DCHECK(task_runner_
->BelongsToCurrentThread());
397 lock_
.AssertAcquired();
399 if (pending_read_
|| received_end_of_stream_
||
400 ready_frames_
.size() == static_cast<size_t>(limits::kMaxVideoFrames
)) {
406 pending_read_
= true;
407 video_frame_stream_
->Read(base::Bind(&VideoRendererImpl::FrameReady
,
408 weak_factory_
.GetWeakPtr()));
419 void VideoRendererImpl::OnVideoFrameStreamResetDone() {
420 base::AutoLock
auto_lock(lock_
);
421 DCHECK_EQ(kFlushing
, state_
);
422 DCHECK(!pending_read_
);
423 DCHECK(ready_frames_
.empty());
424 DCHECK(!received_end_of_stream_
);
425 DCHECK(!rendered_end_of_stream_
);
426 DCHECK_EQ(buffering_state_
, BUFFERING_HAVE_NOTHING
);
429 last_timestamp_
= kNoTimestamp();
430 last_painted_timestamp_
= kNoTimestamp();
431 base::ResetAndReturn(&flush_cb_
).Run();
434 void VideoRendererImpl::UpdateStatsAndWait_Locked(
435 base::TimeDelta wait_duration
) {
436 lock_
.AssertAcquired();
437 DCHECK_GE(frames_decoded_
, 0);
438 DCHECK_LE(frames_dropped_
, frames_decoded_
);
440 if (frames_decoded_
) {
441 PipelineStatistics statistics
;
442 statistics
.video_frames_decoded
= frames_decoded_
;
443 statistics
.video_frames_dropped
= frames_dropped_
;
444 task_runner_
->PostTask(FROM_HERE
, base::Bind(statistics_cb_
, statistics
));
450 frame_available_
.TimedWait(wait_duration
);