| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/buffers.h" | 5 #include "media/base/buffers.h" |
| 6 #include "media/base/filter_host.h" | 6 #include "media/base/filter_host.h" |
| 7 #include "media/base/video_frame_impl.h" | 7 #include "media/base/video_frame_impl.h" |
| 8 #include "media/filters/video_renderer_base.h" | 8 #include "media/filters/video_renderer_base.h" |
| 9 | 9 |
| 10 namespace media { | 10 namespace media { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 void VideoRendererBase::Play(FilterCallback* callback) { | 67 void VideoRendererBase::Play(FilterCallback* callback) { |
| 68 AutoLock auto_lock(lock_); | 68 AutoLock auto_lock(lock_); |
| 69 DCHECK_EQ(kPaused, state_); | 69 DCHECK_EQ(kPaused, state_); |
| 70 scoped_ptr<FilterCallback> c(callback); | 70 scoped_ptr<FilterCallback> c(callback); |
| 71 state_ = kPlaying; | 71 state_ = kPlaying; |
| 72 callback->Run(); | 72 callback->Run(); |
| 73 } | 73 } |
| 74 | 74 |
| 75 void VideoRendererBase::Pause(FilterCallback* callback) { | 75 void VideoRendererBase::Pause(FilterCallback* callback) { |
| 76 AutoLock auto_lock(lock_); | 76 AutoLock auto_lock(lock_); |
| 77 DCHECK_EQ(kPlaying, state_); | 77 DCHECK(state_ == kPlaying || state_ == kEnded); |
| 78 pause_callback_.reset(callback); | 78 pause_callback_.reset(callback); |
| 79 state_ = kPaused; | 79 state_ = kPaused; |
| 80 | 80 |
| 81 // We'll only pause when we've finished all pending reads. | 81 // We'll only pause when we've finished all pending reads. |
| 82 if (pending_reads_ == 0) { | 82 if (pending_reads_ == 0) { |
| 83 pause_callback_->Run(); | 83 pause_callback_->Run(); |
| 84 pause_callback_.reset(); | 84 pause_callback_.reset(); |
| 85 } else { | 85 } else { |
| 86 state_ = kPaused; | 86 state_ = kPaused; |
| 87 } | 87 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 // TODO(scherkus): do we trust subclasses not to do something silly while | 149 // TODO(scherkus): do we trust subclasses not to do something silly while |
| 150 // we're holding the lock? | 150 // we're holding the lock? |
| 151 if (!OnInitialize(decoder)) { | 151 if (!OnInitialize(decoder)) { |
| 152 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); | 152 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 153 callback->Run(); | 153 callback->Run(); |
| 154 return; | 154 return; |
| 155 } | 155 } |
| 156 | 156 |
| 157 // Create a black frame so clients have something to render before we finish | 157 // Create a black frame so clients have something to render before we finish |
| 158 // prerolling. | 158 // prerolling. |
| 159 CreateBlackFrame(¤t_frame_); | 159 VideoFrameImpl::CreateBlackFrame(width_, height_, ¤t_frame_); |
| 160 | 160 |
| 161 // We're all good! Consider ourselves paused (ThreadMain() should never | 161 // We're all good! Consider ourselves paused (ThreadMain() should never |
| 162 // see us in the kUninitialized state). | 162 // see us in the kUninitialized state). |
| 163 state_ = kPaused; | 163 state_ = kPaused; |
| 164 | 164 |
| 165 // Create our video thread. | 165 // Create our video thread. |
| 166 if (!PlatformThread::Create(0, this, &thread_)) { | 166 if (!PlatformThread::Create(0, this, &thread_)) { |
| 167 NOTREACHED() << "Video thread creation failed"; | 167 NOTREACHED() << "Video thread creation failed"; |
| 168 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); | 168 host()->SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 169 callback->Run(); | 169 callback->Run(); |
| 170 return; | 170 return; |
| 171 } | 171 } |
| 172 | 172 |
| 173 #if defined(OS_WIN) | 173 #if defined(OS_WIN) |
| 174 // Bump up our priority so our sleeping is more accurate. | 174 // Bump up our priority so our sleeping is more accurate. |
| 175 // TODO(scherkus): find out if this is necessary, but it seems to help. | 175 // TODO(scherkus): find out if this is necessary, but it seems to help. |
| 176 ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); | 176 ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); |
| 177 #endif // defined(OS_WIN) | 177 #endif // defined(OS_WIN) |
| 178 | 178 |
| 179 // Finally, execute the start callback. | 179 // Finally, execute the start callback. |
| 180 callback->Run(); | 180 callback->Run(); |
| 181 } | 181 } |
| 182 | 182 |
| 183 bool VideoRendererBase::HasEnded() { |
| 184 AutoLock auto_lock(lock_); |
| 185 return state_ == kEnded; |
| 186 } |
| 187 |
| 183 // PlatformThread::Delegate implementation. | 188 // PlatformThread::Delegate implementation. |
| 184 void VideoRendererBase::ThreadMain() { | 189 void VideoRendererBase::ThreadMain() { |
| 185 PlatformThread::SetName("VideoThread"); | 190 PlatformThread::SetName("VideoThread"); |
| 186 for (;;) { | 191 for (;;) { |
| 187 // State and playback rate to assume for this iteration of the loop. | 192 // State and playback rate to assume for this iteration of the loop. |
| 188 State state; | 193 State state; |
| 189 float playback_rate; | 194 float playback_rate; |
| 195 base::TimeDelta remaining_time; |
| 190 { | 196 { |
| 191 AutoLock auto_lock(lock_); | 197 AutoLock auto_lock(lock_); |
| 192 state = state_; | 198 state = state_; |
| 193 playback_rate = playback_rate_; | 199 playback_rate = playback_rate_; |
| 200 |
| 201 // Calculate how long until we should advance the frame, which is |
| 202 // typically negative but for playback rates < 1.0f may be long enough |
| 203 // that it makes more sense to idle and check again. |
| 204 remaining_time = current_frame_->GetTimestamp() - host()->GetTime(); |
| 194 } | 205 } |
| 195 if (state == kStopped) { | 206 if (state == kStopped) { |
| 196 return; | 207 return; |
| 197 } | 208 } |
| 198 | 209 |
| 199 // Sleep while paused or seeking. | 210 // Idle if we shouldn't be playing or advancing the frame yet. |
| 200 if (state == kPaused || state == kSeeking || playback_rate == 0) { | 211 if (state == kPaused || state == kSeeking || state == kEnded || |
| 212 remaining_time.InMilliseconds() > kIdleMilliseconds || |
| 213 playback_rate == 0) { |
| 201 PlatformThread::Sleep(kIdleMilliseconds); | 214 PlatformThread::Sleep(kIdleMilliseconds); |
| 202 continue; | 215 continue; |
| 203 } | 216 } |
| 204 | 217 |
| 205 // Advance |current_frame_| and try to determine |next_frame|. Note that | 218 // Advance |current_frame_| and try to determine |next_frame|. Note that |
| 206 // this loop executes our "playing" logic. | 219 // this loop executes our "playing" logic. |
| 207 DCHECK_EQ(kPlaying, state); | 220 DCHECK_EQ(kPlaying, state); |
| 208 scoped_refptr<VideoFrame> next_frame; | 221 scoped_refptr<VideoFrame> next_frame; |
| 209 { | 222 { |
| 210 AutoLock auto_lock(lock_); | 223 AutoLock auto_lock(lock_); |
| 211 // Check the actual state to see if we're trying to stop playing. | 224 // Check the actual state to see if we're trying to stop playing. |
| 212 if (state_ != kPlaying) { | 225 if (state_ != kPlaying) { |
| 213 continue; | 226 continue; |
| 214 } | 227 } |
| 215 | 228 |
| 216 // Idle if the next frame is too far ahead. | |
| 217 base::TimeDelta diff = current_frame_->GetTimestamp() - host()->GetTime(); | |
| 218 if (diff.InMilliseconds() > kIdleMilliseconds) { | |
| 219 PlatformThread::Sleep(kIdleMilliseconds); | |
| 220 continue; | |
| 221 } | |
| 222 | |
| 223 // Otherwise we're playing, so advance the frame and keep reading from the | 229 // Otherwise we're playing, so advance the frame and keep reading from the |
| 224 // decoder. |frames_| might be empty if we seeked to the very end of the | 230 // decoder if we haven't reach end of stream. |
| 225 // media where no frames were available. | 231 if (!frames_.empty() && !frames_.front()->IsEndOfStream()) { |
| 226 if (!frames_.empty()) { | |
| 227 DCHECK_EQ(current_frame_, frames_.front()); | 232 DCHECK_EQ(current_frame_, frames_.front()); |
| 228 frames_.pop_front(); | 233 frames_.pop_front(); |
| 229 ScheduleRead_Locked(); | 234 ScheduleRead_Locked(); |
| 230 } | 235 } |
| 231 | 236 |
| 232 // While playing, we'll wait until a new frame arrives before updating | 237 // While playing, we'll wait until a new frame arrives before updating |
| 233 // |current_frame_|. | 238 // |current_frame_|. |
| 234 while (frames_.empty() && state_ == kPlaying) { | 239 while (frames_.empty() && state_ == kPlaying) { |
| 235 frame_available_.Wait(); | 240 frame_available_.Wait(); |
| 236 } | 241 } |
| 237 | 242 |
| 238 // If we ended up transitioning out of playing while waiting for a new | 243 // If we ended up transitioning out of playing while waiting for a new |
| 239 // frame, restart the iteration. | 244 // frame, restart the iteration. |
| 240 if (state_ != kPlaying) { | 245 if (state_ != kPlaying) { |
| 241 continue; | 246 continue; |
| 242 } | 247 } |
| 243 | 248 |
| 249 // If the new front frame is end of stream, we've officially ended. |
| 250 if (frames_.front()->IsEndOfStream()) { |
| 251 state_ = kEnded; |
| 252 host()->NotifyEnded(); |
| 253 continue; |
| 254 } |
| 255 |
| 244 // Update our current frame and attempt to grab the next frame. | 256 // Update our current frame and attempt to grab the next frame. |
| 245 current_frame_ = frames_.front(); | 257 current_frame_ = frames_.front(); |
| 246 if (frames_.size() >= 2) { | 258 if (frames_.size() >= 2 && !frames_[1]->IsEndOfStream()) { |
| 247 next_frame = frames_[1]; | 259 next_frame = frames_[1]; |
| 248 } | 260 } |
| 249 } | 261 } |
| 250 | 262 |
| 251 // Calculate our sleep duration. | 263 // Calculate our sleep duration. |
| 252 base::TimeDelta sleep = CalculateSleepDuration(next_frame, playback_rate); | 264 base::TimeDelta sleep = CalculateSleepDuration(next_frame, playback_rate); |
| 253 int sleep_ms = static_cast<int>(sleep.InMilliseconds()); | 265 int sleep_ms = static_cast<int>(sleep.InMilliseconds()); |
| 254 | 266 |
| 255 // If we're too far behind to catch up, simply drop the frame. | 267 // If we're too far behind to catch up, simply drop the frame. |
| 256 // | 268 // |
| (...skipping 12 matching lines...) Expand all Loading... |
| 269 // Notify subclass that |current_frame_| has been updated. | 281 // Notify subclass that |current_frame_| has been updated. |
| 270 OnFrameAvailable(); | 282 OnFrameAvailable(); |
| 271 | 283 |
| 272 PlatformThread::Sleep(sleep_ms); | 284 PlatformThread::Sleep(sleep_ms); |
| 273 } | 285 } |
| 274 } | 286 } |
| 275 | 287 |
| 276 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { | 288 void VideoRendererBase::GetCurrentFrame(scoped_refptr<VideoFrame>* frame_out) { |
| 277 AutoLock auto_lock(lock_); | 289 AutoLock auto_lock(lock_); |
| 278 // We should have initialized and have the current frame. | 290 // We should have initialized and have the current frame. |
| 279 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying); | 291 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || |
| 292 state_ == kEnded); |
| 280 DCHECK(current_frame_); | 293 DCHECK(current_frame_); |
| 281 *frame_out = current_frame_; | 294 *frame_out = current_frame_; |
| 282 } | 295 } |
| 283 | 296 |
| 284 void VideoRendererBase::OnReadComplete(VideoFrame* frame) { | 297 void VideoRendererBase::OnReadComplete(VideoFrame* frame) { |
| 285 AutoLock auto_lock(lock_); | 298 AutoLock auto_lock(lock_); |
| 286 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying); | 299 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || |
| 300 state_ == kEnded); |
| 287 DCHECK_GT(pending_reads_, 0u); | 301 DCHECK_GT(pending_reads_, 0u); |
| 288 --pending_reads_; | 302 --pending_reads_; |
| 289 | 303 |
| 290 // If this is an end of stream frame, don't enqueue it since it has no data. | 304 // Enqueue the frame. |
| 291 if (!frame->IsEndOfStream()) { | 305 frames_.push_back(frame); |
| 292 frames_.push_back(frame); | 306 DCHECK_LE(frames_.size(), kMaxFrames); |
| 293 DCHECK_LE(frames_.size(), kMaxFrames); | 307 frame_available_.Signal(); |
| 294 frame_available_.Signal(); | |
| 295 } | |
| 296 | 308 |
| 297 // Check for our preroll complete condition. | 309 // Check for our preroll complete condition. |
| 298 if (state_ == kSeeking) { | 310 if (state_ == kSeeking) { |
| 299 DCHECK(seek_callback_.get()); | 311 DCHECK(seek_callback_.get()); |
| 300 if (frames_.size() == kMaxFrames || frame->IsEndOfStream()) { | 312 if (frames_.size() == kMaxFrames) { |
| 301 if (frames_.empty()) { | 313 // We're paused, so make sure we update |current_frame_| to represent |
| 302 // Eeep.. we seeked to somewhere where there's no video data (most | 314 // our new location. |
| 303 // likely the very end of the file). For user-friendliness, we'll | 315 state_ = kPaused; |
| 304 // create a black frame just in case |current_frame_| is old or garbage. | 316 if (frames_.front()->IsEndOfStream()) { |
| 305 CreateBlackFrame(¤t_frame_); | 317 VideoFrameImpl::CreateBlackFrame(width_, height_, ¤t_frame_); |
| 306 } else { | 318 } else { |
| 307 // Update our current frame. | |
| 308 current_frame_ = frames_.front(); | 319 current_frame_ = frames_.front(); |
| 309 } | 320 } |
| 310 // Because we might remain paused, we can't rely on ThreadMain() to | 321 |
| 311 // notify the subclass the frame has been updated. | 322 // Because we might remain paused (i.e., we were not playing before we |
| 323 // received a seek), we can't rely on ThreadMain() to notify the subclass |
| 324 // the frame has been updated. |
| 312 DCHECK(current_frame_); | 325 DCHECK(current_frame_); |
| 313 state_ = kPaused; | |
| 314 OnFrameAvailable(); | 326 OnFrameAvailable(); |
| 315 | 327 |
| 316 seek_callback_->Run(); | 328 seek_callback_->Run(); |
| 317 seek_callback_.reset(); | 329 seek_callback_.reset(); |
| 318 } | 330 } |
| 319 } else if (state_ == kPaused && pending_reads_ == 0) { | 331 } else if (state_ == kPaused && pending_reads_ == 0) { |
| 320 // No more pending reads! We're now officially "paused". | 332 // No more pending reads! We're now officially "paused". |
| 321 if (pause_callback_.get()) { | 333 if (pause_callback_.get()) { |
| 322 pause_callback_->Run(); | 334 pause_callback_->Run(); |
| 323 pause_callback_.reset(); | 335 pause_callback_.reset(); |
| 324 } | 336 } |
| 325 } | 337 } |
| 326 } | 338 } |
| 327 | 339 |
| 328 void VideoRendererBase::ScheduleRead_Locked() { | 340 void VideoRendererBase::ScheduleRead_Locked() { |
| 329 lock_.AssertAcquired(); | 341 lock_.AssertAcquired(); |
| 342 DCHECK_NE(kEnded, state_); |
| 330 DCHECK_LT(pending_reads_, kMaxFrames); | 343 DCHECK_LT(pending_reads_, kMaxFrames); |
| 331 ++pending_reads_; | 344 ++pending_reads_; |
| 332 decoder_->Read(NewCallback(this, &VideoRendererBase::OnReadComplete)); | 345 decoder_->Read(NewCallback(this, &VideoRendererBase::OnReadComplete)); |
| 333 } | 346 } |
| 334 | 347 |
| 335 base::TimeDelta VideoRendererBase::CalculateSleepDuration( | 348 base::TimeDelta VideoRendererBase::CalculateSleepDuration( |
| 336 VideoFrame* next_frame, float playback_rate) { | 349 VideoFrame* next_frame, float playback_rate) { |
| 337 // Determine the current and next presentation timestamps. | 350 // Determine the current and next presentation timestamps. |
| 338 base::TimeDelta now = host()->GetTime(); | 351 base::TimeDelta now = host()->GetTime(); |
| 339 base::TimeDelta this_pts = current_frame_->GetTimestamp(); | 352 base::TimeDelta this_pts = current_frame_->GetTimestamp(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 354 sleep = next_pts - now; | 367 sleep = next_pts - now; |
| 355 previous_time_ = now; | 368 previous_time_ = now; |
| 356 } | 369 } |
| 357 | 370 |
| 358 // Scale our sleep based on the playback rate. | 371 // Scale our sleep based on the playback rate. |
| 359 // TODO(scherkus): floating point badness and degrade gracefully. | 372 // TODO(scherkus): floating point badness and degrade gracefully. |
| 360 return base::TimeDelta::FromMicroseconds( | 373 return base::TimeDelta::FromMicroseconds( |
| 361 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); | 374 static_cast<int64>(sleep.InMicroseconds() / playback_rate)); |
| 362 } | 375 } |
| 363 | 376 |
| 364 void VideoRendererBase::CreateBlackFrame(scoped_refptr<VideoFrame>* frame_out) { | |
| 365 DCHECK_GT(width_, 0); | |
| 366 DCHECK_GT(height_, 0); | |
| 367 *frame_out = NULL; | |
| 368 | |
| 369 // Create our frame. | |
| 370 scoped_refptr<VideoFrame> frame; | |
| 371 const base::TimeDelta kZero; | |
| 372 VideoFrameImpl::CreateFrame(VideoSurface::YV12, width_, height_, kZero, kZero, | |
| 373 &frame); | |
| 374 DCHECK(frame); | |
| 375 | |
| 376 // Now set the data to YUV(0,128,128). | |
| 377 VideoSurface surface; | |
| 378 frame->Lock(&surface); | |
| 379 DCHECK_EQ(VideoSurface::YV12, surface.format) << "Expected YV12 surface"; | |
| 380 | |
| 381 // Fill the Y plane. | |
| 382 for (size_t i = 0; i < surface.height; ++i) { | |
| 383 memset(surface.data[VideoSurface::kYPlane], 0x00, surface.width); | |
| 384 surface.data[VideoSurface::kYPlane] | |
| 385 += surface.strides[VideoSurface::kYPlane]; | |
| 386 } | |
| 387 | |
| 388 // Fill the U and V planes. | |
| 389 for (size_t i = 0; i < (surface.height / 2); ++i) { | |
| 390 memset(surface.data[VideoSurface::kUPlane], 0x80, surface.width / 2); | |
| 391 memset(surface.data[VideoSurface::kVPlane], 0x80, surface.width / 2); | |
| 392 surface.data[VideoSurface::kUPlane] | |
| 393 += surface.strides[VideoSurface::kUPlane]; | |
| 394 surface.data[VideoSurface::kVPlane] | |
| 395 += surface.strides[VideoSurface::kVPlane]; | |
| 396 } | |
| 397 frame->Unlock(); | |
| 398 | |
| 399 // Success! | |
| 400 *frame_out = frame; | |
| 401 } | |
| 402 | |
| 403 } // namespace media | 377 } // namespace media |
| OLD | NEW |