OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/callback.h" | 5 #include "base/callback.h" |
6 #include "base/threading/platform_thread.h" | 6 #include "base/threading/platform_thread.h" |
7 #include "media/base/buffers.h" | 7 #include "media/base/buffers.h" |
8 #include "media/base/callback.h" | 8 #include "media/base/callback.h" |
9 #include "media/base/filter_host.h" | 9 #include "media/base/filter_host.h" |
10 #include "media/base/limits.h" | 10 #include "media/base/limits.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 frame_available_(&lock_), | 32 frame_available_(&lock_), |
33 state_(kUninitialized), | 33 state_(kUninitialized), |
34 thread_(base::kNullThreadHandle), | 34 thread_(base::kNullThreadHandle), |
35 pending_reads_(0), | 35 pending_reads_(0), |
36 pending_paint_(false), | 36 pending_paint_(false), |
37 pending_paint_with_last_available_(false), | 37 pending_paint_with_last_available_(false), |
38 playback_rate_(0) { | 38 playback_rate_(0) { |
39 } | 39 } |
40 | 40 |
41 VideoRendererBase::~VideoRendererBase() { | 41 VideoRendererBase::~VideoRendererBase() { |
42 AutoLock auto_lock(lock_); | 42 base::AutoLock auto_lock(lock_); |
43 DCHECK(state_ == kUninitialized || state_ == kStopped); | 43 DCHECK(state_ == kUninitialized || state_ == kStopped); |
44 } | 44 } |
45 | 45 |
46 // static | 46 // static |
47 bool VideoRendererBase::ParseMediaFormat( | 47 bool VideoRendererBase::ParseMediaFormat( |
48 const MediaFormat& media_format, | 48 const MediaFormat& media_format, |
49 VideoFrame::SurfaceType* surface_type_out, | 49 VideoFrame::SurfaceType* surface_type_out, |
50 VideoFrame::Format* surface_format_out, | 50 VideoFrame::Format* surface_format_out, |
51 int* width_out, int* height_out) { | 51 int* width_out, int* height_out) { |
52 std::string mime_type; | 52 std::string mime_type; |
(...skipping 18 matching lines...) Expand all Loading... |
71 if (!media_format.GetAsInteger(MediaFormat::kWidth, &width)) | 71 if (!media_format.GetAsInteger(MediaFormat::kWidth, &width)) |
72 return false; | 72 return false; |
73 if (!media_format.GetAsInteger(MediaFormat::kHeight, &height)) | 73 if (!media_format.GetAsInteger(MediaFormat::kHeight, &height)) |
74 return false; | 74 return false; |
75 if (width_out) *width_out = width; | 75 if (width_out) *width_out = width; |
76 if (height_out) *height_out = height; | 76 if (height_out) *height_out = height; |
77 return true; | 77 return true; |
78 } | 78 } |
79 | 79 |
80 void VideoRendererBase::Play(FilterCallback* callback) { | 80 void VideoRendererBase::Play(FilterCallback* callback) { |
81 AutoLock auto_lock(lock_); | 81 base::AutoLock auto_lock(lock_); |
82 DCHECK_EQ(kPrerolled, state_); | 82 DCHECK_EQ(kPrerolled, state_); |
83 scoped_ptr<FilterCallback> c(callback); | 83 scoped_ptr<FilterCallback> c(callback); |
84 state_ = kPlaying; | 84 state_ = kPlaying; |
85 callback->Run(); | 85 callback->Run(); |
86 } | 86 } |
87 | 87 |
88 void VideoRendererBase::Pause(FilterCallback* callback) { | 88 void VideoRendererBase::Pause(FilterCallback* callback) { |
89 AutoLock auto_lock(lock_); | 89 base::AutoLock auto_lock(lock_); |
90 DCHECK(state_ != kUninitialized || state_ == kError); | 90 DCHECK(state_ != kUninitialized || state_ == kError); |
91 AutoCallbackRunner done_runner(callback); | 91 AutoCallbackRunner done_runner(callback); |
92 state_ = kPaused; | 92 state_ = kPaused; |
93 } | 93 } |
94 | 94 |
95 void VideoRendererBase::Flush(FilterCallback* callback) { | 95 void VideoRendererBase::Flush(FilterCallback* callback) { |
96 DCHECK_EQ(state_, kPaused); | 96 DCHECK_EQ(state_, kPaused); |
97 | 97 |
98 AutoLock auto_lock(lock_); | 98 base::AutoLock auto_lock(lock_); |
99 flush_callback_.reset(callback); | 99 flush_callback_.reset(callback); |
100 state_ = kFlushing; | 100 state_ = kFlushing; |
101 | 101 |
102 if (pending_paint_ == false) | 102 if (pending_paint_ == false) |
103 FlushBuffers(); | 103 FlushBuffers(); |
104 } | 104 } |
105 | 105 |
106 void VideoRendererBase::Stop(FilterCallback* callback) { | 106 void VideoRendererBase::Stop(FilterCallback* callback) { |
107 DCHECK_EQ(pending_reads_, 0); | 107 DCHECK_EQ(pending_reads_, 0); |
108 | 108 |
109 { | 109 { |
110 AutoLock auto_lock(lock_); | 110 base::AutoLock auto_lock(lock_); |
111 state_ = kStopped; | 111 state_ = kStopped; |
112 | 112 |
113 // Clean up our thread if present. | 113 // Clean up our thread if present. |
114 if (thread_) { | 114 if (thread_) { |
115 // Signal the thread since it's possible to get stopped with the video | 115 // Signal the thread since it's possible to get stopped with the video |
116 // thread waiting for a read to complete. | 116 // thread waiting for a read to complete. |
117 frame_available_.Signal(); | 117 frame_available_.Signal(); |
118 { | 118 { |
119 AutoUnlock auto_unlock(lock_); | 119 base::AutoUnlock auto_unlock(lock_); |
120 base::PlatformThread::Join(thread_); | 120 base::PlatformThread::Join(thread_); |
121 } | 121 } |
122 thread_ = base::kNullThreadHandle; | 122 thread_ = base::kNullThreadHandle; |
123 } | 123 } |
124 | 124 |
125 } | 125 } |
126 // Signal the subclass we're stopping. | 126 // Signal the subclass we're stopping. |
127 OnStop(callback); | 127 OnStop(callback); |
128 } | 128 } |
129 | 129 |
130 void VideoRendererBase::SetPlaybackRate(float playback_rate) { | 130 void VideoRendererBase::SetPlaybackRate(float playback_rate) { |
131 AutoLock auto_lock(lock_); | 131 base::AutoLock auto_lock(lock_); |
132 playback_rate_ = playback_rate; | 132 playback_rate_ = playback_rate; |
133 } | 133 } |
134 | 134 |
135 void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { | 135 void VideoRendererBase::Seek(base::TimeDelta time, FilterCallback* callback) { |
136 AutoLock auto_lock(lock_); | 136 base::AutoLock auto_lock(lock_); |
137 // There is a race condition between filters to receive SeekTask(). | 137 // There is a race condition between filters to receive SeekTask(). |
138 // It turns out we could receive buffer from decoder before seek() | 138 // It turns out we could receive buffer from decoder before seek() |
139 // is called on us. so we do the following: | 139 // is called on us. so we do the following: |
140 // kFlushed => ( Receive first buffer or Seek() ) => kSeeking and | 140 // kFlushed => ( Receive first buffer or Seek() ) => kSeeking and |
141 // kSeeking => ( Receive enough buffers) => kPrerolled. ) | 141 // kSeeking => ( Receive enough buffers) => kPrerolled. ) |
142 DCHECK(kPrerolled == state_ || kFlushed == state_ || kSeeking == state_); | 142 DCHECK(kPrerolled == state_ || kFlushed == state_ || kSeeking == state_); |
143 | 143 |
144 if (state_ == kPrerolled) { | 144 if (state_ == kPrerolled) { |
145 // Already get enough buffers from decoder. | 145 // Already get enough buffers from decoder. |
146 callback->Run(); | 146 callback->Run(); |
147 delete callback; | 147 delete callback; |
148 } else { | 148 } else { |
149 // Otherwise we are either kFlushed or kSeeking, but without enough buffers; | 149 // Otherwise we are either kFlushed or kSeeking, but without enough buffers; |
150 // we should save the callback function and call it later. | 150 // we should save the callback function and call it later. |
151 state_ = kSeeking; | 151 state_ = kSeeking; |
152 seek_callback_.reset(callback); | 152 seek_callback_.reset(callback); |
153 } | 153 } |
154 | 154 |
155 seek_timestamp_ = time; | 155 seek_timestamp_ = time; |
156 ScheduleRead_Locked(); | 156 ScheduleRead_Locked(); |
157 } | 157 } |
158 | 158 |
159 void VideoRendererBase::Initialize(VideoDecoder* decoder, | 159 void VideoRendererBase::Initialize(VideoDecoder* decoder, |
160 FilterCallback* callback) { | 160 FilterCallback* callback) { |
161 AutoLock auto_lock(lock_); | 161 base::AutoLock auto_lock(lock_); |
162 DCHECK(decoder); | 162 DCHECK(decoder); |
163 DCHECK(callback); | 163 DCHECK(callback); |
164 DCHECK_EQ(kUninitialized, state_); | 164 DCHECK_EQ(kUninitialized, state_); |
165 decoder_ = decoder; | 165 decoder_ = decoder; |
166 AutoCallbackRunner done_runner(callback); | 166 AutoCallbackRunner done_runner(callback); |
167 | 167 |
168 decoder_->set_consume_video_frame_callback( | 168 decoder_->set_consume_video_frame_callback( |
169 NewCallback(this, &VideoRendererBase::ConsumeVideoFrame)); | 169 NewCallback(this, &VideoRendererBase::ConsumeVideoFrame)); |
170 // Notify the pipeline of the video dimensions. | 170 // Notify the pipeline of the video dimensions. |
171 if (!ParseMediaFormat(decoder->media_format(), | 171 if (!ParseMediaFormat(decoder->media_format(), |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 | 203 |
204 #if defined(OS_WIN) | 204 #if defined(OS_WIN) |
205 // Bump up our priority so our sleeping is more accurate. | 205 // Bump up our priority so our sleeping is more accurate. |
206 // TODO(scherkus): find out if this is necessary, but it seems to help. | 206 // TODO(scherkus): find out if this is necessary, but it seems to help. |
207 ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); | 207 ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); |
208 #endif // defined(OS_WIN) | 208 #endif // defined(OS_WIN) |
209 | 209 |
210 } | 210 } |
211 | 211 |
212 bool VideoRendererBase::HasEnded() { | 212 bool VideoRendererBase::HasEnded() { |
213 AutoLock auto_lock(lock_); | 213 base::AutoLock auto_lock(lock_); |
214 return state_ == kEnded; | 214 return state_ == kEnded; |
215 } | 215 } |
216 | 216 |
217 // PlatformThread::Delegate implementation. | 217 // PlatformThread::Delegate implementation. |
218 void VideoRendererBase::ThreadMain() { | 218 void VideoRendererBase::ThreadMain() { |
219 base::PlatformThread::SetName("CrVideoRenderer"); | 219 base::PlatformThread::SetName("CrVideoRenderer"); |
220 base::TimeDelta remaining_time; | 220 base::TimeDelta remaining_time; |
221 | 221 |
222 for (;;) { | 222 for (;;) { |
223 AutoLock auto_lock(lock_); | 223 base::AutoLock auto_lock(lock_); |
224 | 224 |
225 const base::TimeDelta kIdleTimeDelta = | 225 const base::TimeDelta kIdleTimeDelta = |
226 base::TimeDelta::FromMilliseconds(kIdleMilliseconds); | 226 base::TimeDelta::FromMilliseconds(kIdleMilliseconds); |
227 | 227 |
228 if (state_ == kStopped) | 228 if (state_ == kStopped) |
229 return; | 229 return; |
230 | 230 |
231 if (state_ != kPlaying || playback_rate_ == 0) { | 231 if (state_ != kPlaying || playback_rate_ == 0) { |
232 remaining_time = kIdleTimeDelta; | 232 remaining_time = kIdleTimeDelta; |
233 } else if (frames_queue_ready_.empty() || | 233 } else if (frames_queue_ready_.empty() || |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 // which is the first frame in the queue. | 310 // which is the first frame in the queue. |
311 timeout_frame = frames_queue_ready_.front(); | 311 timeout_frame = frames_queue_ready_.front(); |
312 frames_queue_ready_.pop_front(); | 312 frames_queue_ready_.pop_front(); |
313 } | 313 } |
314 } | 314 } |
315 if (timeout_frame.get()) { | 315 if (timeout_frame.get()) { |
316 frames_queue_done_.push_back(timeout_frame); | 316 frames_queue_done_.push_back(timeout_frame); |
317 ScheduleRead_Locked(); | 317 ScheduleRead_Locked(); |
318 } | 318 } |
319 if (new_frame_available) { | 319 if (new_frame_available) { |
320 AutoUnlock auto_unlock(lock_); | 320 base::AutoUnlock auto_unlock(lock_); |
321 // Notify subclass that |current_frame_| has been updated. | 321 // Notify subclass that |current_frame_| has been updated. |
322 OnFrameAvailable(); | 322 OnFrameAvailable(); |
323 } | 323 } |
324 } | 324 } |
325 } | 325 } |
326 } | 326 } |
327 | 327 |
328 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { | 328 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { |
329 AutoLock auto_lock(lock_); | 329 base::AutoLock auto_lock(lock_); |
330 DCHECK(!pending_paint_ && !pending_paint_with_last_available_); | 330 DCHECK(!pending_paint_ && !pending_paint_with_last_available_); |
331 | 331 |
332 if (!current_frame_.get() || current_frame_->IsEndOfStream()) { | 332 if (!current_frame_.get() || current_frame_->IsEndOfStream()) { |
333 if (!last_available_frame_.get() || | 333 if (!last_available_frame_.get() || |
334 last_available_frame_->IsEndOfStream()) { | 334 last_available_frame_->IsEndOfStream()) { |
335 *frame_out = NULL; | 335 *frame_out = NULL; |
336 return; | 336 return; |
337 } | 337 } |
338 } | 338 } |
339 | 339 |
340 // We should have initialized and have the current frame. | 340 // We should have initialized and have the current frame. |
341 DCHECK(state_ != kUninitialized && state_ != kStopped && state_ != kError); | 341 DCHECK(state_ != kUninitialized && state_ != kStopped && state_ != kError); |
342 | 342 |
343 if (current_frame_) { | 343 if (current_frame_) { |
344 *frame_out = current_frame_; | 344 *frame_out = current_frame_; |
345 last_available_frame_ = current_frame_; | 345 last_available_frame_ = current_frame_; |
346 pending_paint_ = true; | 346 pending_paint_ = true; |
347 } else { | 347 } else { |
348 DCHECK(last_available_frame_.get() != NULL); | 348 DCHECK(last_available_frame_.get() != NULL); |
349 *frame_out = last_available_frame_; | 349 *frame_out = last_available_frame_; |
350 pending_paint_with_last_available_ = true; | 350 pending_paint_with_last_available_ = true; |
351 } | 351 } |
352 } | 352 } |
353 | 353 |
354 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) { | 354 void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) { |
355 AutoLock auto_lock(lock_); | 355 base::AutoLock auto_lock(lock_); |
356 | 356 |
357 // Note that we do not claim |pending_paint_| when we return NULL frame, in | 357 // Note that we do not claim |pending_paint_| when we return NULL frame, in |
358 // that case, |current_frame_| could be changed before PutCurrentFrame. | 358 // that case, |current_frame_| could be changed before PutCurrentFrame. |
359 if (pending_paint_) { | 359 if (pending_paint_) { |
360 DCHECK(current_frame_.get() == frame.get()); | 360 DCHECK(current_frame_.get() == frame.get()); |
361 DCHECK(pending_paint_with_last_available_ == false); | 361 DCHECK(pending_paint_with_last_available_ == false); |
362 pending_paint_ = false; | 362 pending_paint_ = false; |
363 } else if (pending_paint_with_last_available_) { | 363 } else if (pending_paint_with_last_available_) { |
364 DCHECK(last_available_frame_.get() == frame.get()); | 364 DCHECK(last_available_frame_.get() == frame.get()); |
365 pending_paint_with_last_available_ = false; | 365 pending_paint_with_last_available_ = false; |
366 } else { | 366 } else { |
367 DCHECK(frame.get() == NULL); | 367 DCHECK(frame.get() == NULL); |
368 } | 368 } |
369 | 369 |
370 // We had cleared the |pending_paint_| flag, there are chances that current | 370 // We had cleared the |pending_paint_| flag, there are chances that current |
371 // frame is timed-out. We will wake up our main thread to advance the current | 371 // frame is timed-out. We will wake up our main thread to advance the current |
372 // frame when this is true. | 372 // frame when this is true. |
373 frame_available_.Signal(); | 373 frame_available_.Signal(); |
374 if (state_ == kFlushing) | 374 if (state_ == kFlushing) |
375 FlushBuffers(); | 375 FlushBuffers(); |
376 } | 376 } |
377 | 377 |
378 void VideoRendererBase::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { | 378 void VideoRendererBase::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { |
379 AutoLock auto_lock(lock_); | 379 base::AutoLock auto_lock(lock_); |
380 | 380 |
381 // Decoder could reach seek state before our Seek() get called. | 381 // Decoder could reach seek state before our Seek() get called. |
382 // We will enter kSeeking | 382 // We will enter kSeeking |
383 if (kFlushed == state_) | 383 if (kFlushed == state_) |
384 state_ = kSeeking; | 384 state_ = kSeeking; |
385 | 385 |
386 // Synchronous flush between filters should prevent this from happening. | 386 // Synchronous flush between filters should prevent this from happening. |
387 DCHECK_NE(state_, kStopped); | 387 DCHECK_NE(state_, kStopped); |
388 if (frame.get() && !frame->IsEndOfStream()) | 388 if (frame.get() && !frame->IsEndOfStream()) |
389 --pending_reads_; | 389 --pending_reads_; |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 previous_time_ = now; | 541 previous_time_ = now; |
542 } | 542 } |
543 | 543 |
544 // Scale our sleep based on the playback rate. | 544 // Scale our sleep based on the playback rate. |
545 // TODO(scherkus): floating point badness and degrade gracefully. | 545 // TODO(scherkus): floating point badness and degrade gracefully. |
546 return base::TimeDelta::FromMicroseconds( | 546 return base::TimeDelta::FromMicroseconds( |
547 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); | 547 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); |
548 } | 548 } |
549 | 549 |
550 } // namespace media | 550 } // namespace media |
OLD | NEW |