| 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 |