| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "content/renderer/media/rtc_video_decoder.h" | 5 #include "content/renderer/media/rtc_video_decoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 | 69 |
| 70 RTCVideoDecoder::BufferData::BufferData() {} | 70 RTCVideoDecoder::BufferData::BufferData() {} |
| 71 | 71 |
| 72 RTCVideoDecoder::BufferData::~BufferData() {} | 72 RTCVideoDecoder::BufferData::~BufferData() {} |
| 73 | 73 |
| 74 RTCVideoDecoder::RTCVideoDecoder( | 74 RTCVideoDecoder::RTCVideoDecoder( |
| 75 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) | 75 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) |
| 76 : weak_factory_(this), | 76 : weak_factory_(this), |
| 77 weak_this_(weak_factory_.GetWeakPtr()), | 77 weak_this_(weak_factory_.GetWeakPtr()), |
| 78 factories_(factories), | 78 factories_(factories), |
| 79 vda_loop_proxy_(factories->GetMessageLoop()), | 79 vda_task_runner_(factories->GetTaskRunner()), |
| 80 decoder_texture_target_(0), | 80 decoder_texture_target_(0), |
| 81 next_picture_buffer_id_(0), | 81 next_picture_buffer_id_(0), |
| 82 state_(UNINITIALIZED), | 82 state_(UNINITIALIZED), |
| 83 decode_complete_callback_(NULL), | 83 decode_complete_callback_(NULL), |
| 84 num_shm_buffers_(0), | 84 num_shm_buffers_(0), |
| 85 next_bitstream_buffer_id_(0), | 85 next_bitstream_buffer_id_(0), |
| 86 reset_bitstream_buffer_id_(ID_INVALID) { | 86 reset_bitstream_buffer_id_(ID_INVALID) { |
| 87 DCHECK(!vda_loop_proxy_->BelongsToCurrentThread()); | 87 DCHECK(!vda_task_runner_->BelongsToCurrentThread()); |
| 88 base::WaitableEvent message_loop_async_waiter(false, false); | 88 base::WaitableEvent message_loop_async_waiter(false, false); |
| 89 // Waiting here is safe. The media thread is stopped in the child thread and | 89 // Waiting here is safe. The media thread is stopped in the child thread and |
| 90 // the child thread is blocked when VideoDecoderFactory::CreateVideoDecoder | 90 // the child thread is blocked when VideoDecoderFactory::CreateVideoDecoder |
| 91 // runs. | 91 // runs. |
| 92 vda_loop_proxy_->PostTask(FROM_HERE, | 92 vda_task_runner_->PostTask(FROM_HERE, |
| 93 base::Bind(&RTCVideoDecoder::Initialize, | 93 base::Bind(&RTCVideoDecoder::Initialize, |
| 94 base::Unretained(this), | 94 base::Unretained(this), |
| 95 &message_loop_async_waiter)); | 95 &message_loop_async_waiter)); |
| 96 message_loop_async_waiter.Wait(); | 96 message_loop_async_waiter.Wait(); |
| 97 } | 97 } |
| 98 | 98 |
| 99 RTCVideoDecoder::~RTCVideoDecoder() { | 99 RTCVideoDecoder::~RTCVideoDecoder() { |
| 100 DVLOG(2) << "~RTCVideoDecoder"; | 100 DVLOG(2) << "~RTCVideoDecoder"; |
| 101 // Destroy VDA and remove |this| from the observer if this is vda thread. | 101 // Destroy VDA and remove |this| from the observer if this is vda thread. |
| 102 if (vda_loop_proxy_->BelongsToCurrentThread()) { | 102 if (vda_task_runner_->BelongsToCurrentThread()) { |
| 103 base::MessageLoop::current()->RemoveDestructionObserver(this); | 103 base::MessageLoop::current()->RemoveDestructionObserver(this); |
| 104 DestroyVDA(); | 104 DestroyVDA(); |
| 105 } else { | 105 } else { |
| 106 // VDA should have been destroyed in WillDestroyCurrentMessageLoop. | 106 // VDA should have been destroyed in WillDestroyCurrentMessageLoop. |
| 107 DCHECK(!vda_); | 107 DCHECK(!vda_); |
| 108 } | 108 } |
| 109 | 109 |
| 110 // Delete all shared memories. | 110 // Delete all shared memories. |
| 111 STLDeleteElements(&available_shm_segments_); | 111 STLDeleteElements(&available_shm_segments_); |
| 112 STLDeleteValues(&bitstream_buffers_in_decoder_); | 112 STLDeleteValues(&bitstream_buffers_in_decoder_); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 138 return decoder.Pass(); | 138 return decoder.Pass(); |
| 139 } | 139 } |
| 140 | 140 |
| 141 decoder.reset(new RTCVideoDecoder(factories)); | 141 decoder.reset(new RTCVideoDecoder(factories)); |
| 142 decoder->vda_ = | 142 decoder->vda_ = |
| 143 factories->CreateVideoDecodeAccelerator(profile, decoder.get()).Pass(); | 143 factories->CreateVideoDecodeAccelerator(profile, decoder.get()).Pass(); |
| 144 // vda can be NULL if VP8 is not supported. | 144 // vda can be NULL if VP8 is not supported. |
| 145 if (decoder->vda_ != NULL) { | 145 if (decoder->vda_ != NULL) { |
| 146 decoder->state_ = INITIALIZED; | 146 decoder->state_ = INITIALIZED; |
| 147 } else { | 147 } else { |
| 148 factories->GetMessageLoop()->DeleteSoon(FROM_HERE, decoder.release()); | 148 factories->GetTaskRunner()->DeleteSoon(FROM_HERE, decoder.release()); |
| 149 } | 149 } |
| 150 return decoder.Pass(); | 150 return decoder.Pass(); |
| 151 } | 151 } |
| 152 | 152 |
| 153 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, | 153 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, |
| 154 int32_t /*numberOfCores*/) { | 154 int32_t /*numberOfCores*/) { |
| 155 DVLOG(2) << "InitDecode"; | 155 DVLOG(2) << "InitDecode"; |
| 156 DCHECK_EQ(codecSettings->codecType, webrtc::kVideoCodecVP8); | 156 DCHECK_EQ(codecSettings->codecType, webrtc::kVideoCodecVP8); |
| 157 if (codecSettings->codecSpecific.VP8.feedbackModeOn) { | 157 if (codecSettings->codecSpecific.VP8.feedbackModeOn) { |
| 158 LOG(ERROR) << "Feedback mode not supported"; | 158 LOG(ERROR) << "Feedback mode not supported"; |
| 159 return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_ERROR); | 159 return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_ERROR); |
| 160 } | 160 } |
| 161 | 161 |
| 162 base::AutoLock auto_lock(lock_); | 162 base::AutoLock auto_lock(lock_); |
| 163 if (state_ == UNINITIALIZED || state_ == DECODE_ERROR) { | 163 if (state_ == UNINITIALIZED || state_ == DECODE_ERROR) { |
| 164 LOG(ERROR) << "VDA is not initialized. state=" << state_; | 164 LOG(ERROR) << "VDA is not initialized. state=" << state_; |
| 165 return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_UNINITIALIZED); | 165 return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_UNINITIALIZED); |
| 166 } | 166 } |
| 167 // Create some shared memory if the queue is empty. | 167 // Create some shared memory if the queue is empty. |
| 168 if (available_shm_segments_.size() == 0) { | 168 if (available_shm_segments_.size() == 0) { |
| 169 vda_loop_proxy_->PostTask(FROM_HERE, | 169 vda_task_runner_->PostTask(FROM_HERE, |
| 170 base::Bind(&RTCVideoDecoder::CreateSHM, | 170 base::Bind(&RTCVideoDecoder::CreateSHM, |
| 171 weak_this_, | 171 weak_this_, |
| 172 kMaxInFlightDecodes, | 172 kMaxInFlightDecodes, |
| 173 kSharedMemorySegmentBytes)); | 173 kSharedMemorySegmentBytes)); |
| 174 } | 174 } |
| 175 return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_OK); | 175 return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_OK); |
| 176 } | 176 } |
| 177 | 177 |
| 178 int32_t RTCVideoDecoder::Decode( | 178 int32_t RTCVideoDecoder::Decode( |
| 179 const webrtc::EncodedImage& inputImage, | 179 const webrtc::EncodedImage& inputImage, |
| 180 bool missingFrames, | 180 bool missingFrames, |
| 181 const webrtc::RTPFragmentationHeader* /*fragmentation*/, | 181 const webrtc::RTPFragmentationHeader* /*fragmentation*/, |
| 182 const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/, | 182 const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/, |
| 183 int64_t /*renderTimeMs*/) { | 183 int64_t /*renderTimeMs*/) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 if (!SaveToPendingBuffers_Locked(inputImage, buffer_data)) | 249 if (!SaveToPendingBuffers_Locked(inputImage, buffer_data)) |
| 250 return WEBRTC_VIDEO_CODEC_ERROR; | 250 return WEBRTC_VIDEO_CODEC_ERROR; |
| 251 if (need_to_reset_for_midstream_resize) { | 251 if (need_to_reset_for_midstream_resize) { |
| 252 base::AutoUnlock auto_unlock(lock_); | 252 base::AutoUnlock auto_unlock(lock_); |
| 253 Reset(); | 253 Reset(); |
| 254 } | 254 } |
| 255 return WEBRTC_VIDEO_CODEC_OK; | 255 return WEBRTC_VIDEO_CODEC_OK; |
| 256 } | 256 } |
| 257 | 257 |
| 258 SaveToDecodeBuffers_Locked(inputImage, shm_buffer.Pass(), buffer_data); | 258 SaveToDecodeBuffers_Locked(inputImage, shm_buffer.Pass(), buffer_data); |
| 259 vda_loop_proxy_->PostTask( | 259 vda_task_runner_->PostTask( |
| 260 FROM_HERE, base::Bind(&RTCVideoDecoder::RequestBufferDecode, weak_this_)); | 260 FROM_HERE, base::Bind(&RTCVideoDecoder::RequestBufferDecode, weak_this_)); |
| 261 return WEBRTC_VIDEO_CODEC_OK; | 261 return WEBRTC_VIDEO_CODEC_OK; |
| 262 } | 262 } |
| 263 | 263 |
| 264 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback( | 264 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback( |
| 265 webrtc::DecodedImageCallback* callback) { | 265 webrtc::DecodedImageCallback* callback) { |
| 266 DVLOG(2) << "RegisterDecodeCompleteCallback"; | 266 DVLOG(2) << "RegisterDecodeCompleteCallback"; |
| 267 base::AutoLock auto_lock(lock_); | 267 base::AutoLock auto_lock(lock_); |
| 268 decode_complete_callback_ = callback; | 268 decode_complete_callback_ = callback; |
| 269 return WEBRTC_VIDEO_CODEC_OK; | 269 return WEBRTC_VIDEO_CODEC_OK; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 283 LOG(ERROR) << "Decoder not initialized."; | 283 LOG(ERROR) << "Decoder not initialized."; |
| 284 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 284 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 285 } | 285 } |
| 286 if (next_bitstream_buffer_id_ != 0) | 286 if (next_bitstream_buffer_id_ != 0) |
| 287 reset_bitstream_buffer_id_ = next_bitstream_buffer_id_ - 1; | 287 reset_bitstream_buffer_id_ = next_bitstream_buffer_id_ - 1; |
| 288 else | 288 else |
| 289 reset_bitstream_buffer_id_ = ID_LAST; | 289 reset_bitstream_buffer_id_ = ID_LAST; |
| 290 // If VDA is already resetting, no need to request the reset again. | 290 // If VDA is already resetting, no need to request the reset again. |
| 291 if (state_ != RESETTING) { | 291 if (state_ != RESETTING) { |
| 292 state_ = RESETTING; | 292 state_ = RESETTING; |
| 293 vda_loop_proxy_->PostTask( | 293 vda_task_runner_->PostTask( |
| 294 FROM_HERE, base::Bind(&RTCVideoDecoder::ResetInternal, weak_this_)); | 294 FROM_HERE, base::Bind(&RTCVideoDecoder::ResetInternal, weak_this_)); |
| 295 } | 295 } |
| 296 return WEBRTC_VIDEO_CODEC_OK; | 296 return WEBRTC_VIDEO_CODEC_OK; |
| 297 } | 297 } |
| 298 | 298 |
| 299 void RTCVideoDecoder::NotifyInitializeDone() { | 299 void RTCVideoDecoder::NotifyInitializeDone() { |
| 300 DVLOG(2) << "NotifyInitializeDone"; | 300 DVLOG(2) << "NotifyInitializeDone"; |
| 301 NOTREACHED(); | 301 NOTREACHED(); |
| 302 } | 302 } |
| 303 | 303 |
| 304 void RTCVideoDecoder::ProvidePictureBuffers(uint32 count, | 304 void RTCVideoDecoder::ProvidePictureBuffers(uint32 count, |
| 305 const gfx::Size& size, | 305 const gfx::Size& size, |
| 306 uint32 texture_target) { | 306 uint32 texture_target) { |
| 307 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 307 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 308 DVLOG(3) << "ProvidePictureBuffers. texture_target=" << texture_target; | 308 DVLOG(3) << "ProvidePictureBuffers. texture_target=" << texture_target; |
| 309 | 309 |
| 310 if (!vda_) | 310 if (!vda_) |
| 311 return; | 311 return; |
| 312 | 312 |
| 313 std::vector<uint32> texture_ids; | 313 std::vector<uint32> texture_ids; |
| 314 std::vector<gpu::Mailbox> texture_mailboxes; | 314 std::vector<gpu::Mailbox> texture_mailboxes; |
| 315 decoder_texture_target_ = texture_target; | 315 decoder_texture_target_ = texture_target; |
| 316 // Discards the sync point returned here since PictureReady will imply that | 316 // Discards the sync point returned here since PictureReady will imply that |
| 317 // the produce has already happened, and the texture is ready for use. | 317 // the produce has already happened, and the texture is ready for use. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 332 next_picture_buffer_id_++, size, texture_ids[i], texture_mailboxes[i])); | 332 next_picture_buffer_id_++, size, texture_ids[i], texture_mailboxes[i])); |
| 333 bool inserted = assigned_picture_buffers_.insert(std::make_pair( | 333 bool inserted = assigned_picture_buffers_.insert(std::make_pair( |
| 334 picture_buffers.back().id(), picture_buffers.back())).second; | 334 picture_buffers.back().id(), picture_buffers.back())).second; |
| 335 DCHECK(inserted); | 335 DCHECK(inserted); |
| 336 } | 336 } |
| 337 vda_->AssignPictureBuffers(picture_buffers); | 337 vda_->AssignPictureBuffers(picture_buffers); |
| 338 } | 338 } |
| 339 | 339 |
| 340 void RTCVideoDecoder::DismissPictureBuffer(int32 id) { | 340 void RTCVideoDecoder::DismissPictureBuffer(int32 id) { |
| 341 DVLOG(3) << "DismissPictureBuffer. id=" << id; | 341 DVLOG(3) << "DismissPictureBuffer. id=" << id; |
| 342 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 342 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 343 | 343 |
| 344 std::map<int32, media::PictureBuffer>::iterator it = | 344 std::map<int32, media::PictureBuffer>::iterator it = |
| 345 assigned_picture_buffers_.find(id); | 345 assigned_picture_buffers_.find(id); |
| 346 if (it == assigned_picture_buffers_.end()) { | 346 if (it == assigned_picture_buffers_.end()) { |
| 347 NOTREACHED() << "Missing picture buffer: " << id; | 347 NOTREACHED() << "Missing picture buffer: " << id; |
| 348 return; | 348 return; |
| 349 } | 349 } |
| 350 | 350 |
| 351 media::PictureBuffer buffer_to_dismiss = it->second; | 351 media::PictureBuffer buffer_to_dismiss = it->second; |
| 352 assigned_picture_buffers_.erase(it); | 352 assigned_picture_buffers_.erase(it); |
| 353 | 353 |
| 354 std::set<int32>::iterator at_display_it = | 354 std::set<int32>::iterator at_display_it = |
| 355 picture_buffers_at_display_.find(id); | 355 picture_buffers_at_display_.find(id); |
| 356 | 356 |
| 357 if (at_display_it == picture_buffers_at_display_.end()) { | 357 if (at_display_it == picture_buffers_at_display_.end()) { |
| 358 // We can delete the texture immediately as it's not being displayed. | 358 // We can delete the texture immediately as it's not being displayed. |
| 359 factories_->DeleteTexture(buffer_to_dismiss.texture_id()); | 359 factories_->DeleteTexture(buffer_to_dismiss.texture_id()); |
| 360 } else { | 360 } else { |
| 361 // Texture in display. Postpone deletion until after it's returned to us. | 361 // Texture in display. Postpone deletion until after it's returned to us. |
| 362 bool inserted = dismissed_picture_buffers_ | 362 bool inserted = dismissed_picture_buffers_ |
| 363 .insert(std::make_pair(id, buffer_to_dismiss)).second; | 363 .insert(std::make_pair(id, buffer_to_dismiss)).second; |
| 364 DCHECK(inserted); | 364 DCHECK(inserted); |
| 365 } | 365 } |
| 366 } | 366 } |
| 367 | 367 |
| 368 void RTCVideoDecoder::PictureReady(const media::Picture& picture) { | 368 void RTCVideoDecoder::PictureReady(const media::Picture& picture) { |
| 369 DVLOG(3) << "PictureReady"; | 369 DVLOG(3) << "PictureReady"; |
| 370 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 370 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 371 | 371 |
| 372 std::map<int32, media::PictureBuffer>::iterator it = | 372 std::map<int32, media::PictureBuffer>::iterator it = |
| 373 assigned_picture_buffers_.find(picture.picture_buffer_id()); | 373 assigned_picture_buffers_.find(picture.picture_buffer_id()); |
| 374 if (it == assigned_picture_buffers_.end()) { | 374 if (it == assigned_picture_buffers_.end()) { |
| 375 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); | 375 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); |
| 376 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 376 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
| 377 return; | 377 return; |
| 378 } | 378 } |
| 379 const media::PictureBuffer& pb = it->second; | 379 const media::PictureBuffer& pb = it->second; |
| 380 | 380 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 timestamp_ms, | 433 timestamp_ms, |
| 434 base::Bind(&media::GpuVideoAcceleratorFactories::ReadPixels, | 434 base::Bind(&media::GpuVideoAcceleratorFactories::ReadPixels, |
| 435 factories_, | 435 factories_, |
| 436 pb.texture_id(), | 436 pb.texture_id(), |
| 437 natural_size), | 437 natural_size), |
| 438 base::Closure()); | 438 base::Closure()); |
| 439 } | 439 } |
| 440 | 440 |
| 441 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { | 441 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { |
| 442 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; | 442 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; |
| 443 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 443 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 444 | 444 |
| 445 std::map<int32, SHMBuffer*>::iterator it = | 445 std::map<int32, SHMBuffer*>::iterator it = |
| 446 bitstream_buffers_in_decoder_.find(id); | 446 bitstream_buffers_in_decoder_.find(id); |
| 447 if (it == bitstream_buffers_in_decoder_.end()) { | 447 if (it == bitstream_buffers_in_decoder_.end()) { |
| 448 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 448 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
| 449 NOTREACHED() << "Missing bitstream buffer: " << id; | 449 NOTREACHED() << "Missing bitstream buffer: " << id; |
| 450 return; | 450 return; |
| 451 } | 451 } |
| 452 | 452 |
| 453 { | 453 { |
| 454 base::AutoLock auto_lock(lock_); | 454 base::AutoLock auto_lock(lock_); |
| 455 PutSHM_Locked(scoped_ptr<SHMBuffer>(it->second)); | 455 PutSHM_Locked(scoped_ptr<SHMBuffer>(it->second)); |
| 456 } | 456 } |
| 457 bitstream_buffers_in_decoder_.erase(it); | 457 bitstream_buffers_in_decoder_.erase(it); |
| 458 | 458 |
| 459 RequestBufferDecode(); | 459 RequestBufferDecode(); |
| 460 } | 460 } |
| 461 | 461 |
| 462 void RTCVideoDecoder::NotifyFlushDone() { | 462 void RTCVideoDecoder::NotifyFlushDone() { |
| 463 DVLOG(3) << "NotifyFlushDone"; | 463 DVLOG(3) << "NotifyFlushDone"; |
| 464 NOTREACHED() << "Unexpected flush done notification."; | 464 NOTREACHED() << "Unexpected flush done notification."; |
| 465 } | 465 } |
| 466 | 466 |
| 467 void RTCVideoDecoder::NotifyResetDone() { | 467 void RTCVideoDecoder::NotifyResetDone() { |
| 468 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 468 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 469 DVLOG(3) << "NotifyResetDone"; | 469 DVLOG(3) << "NotifyResetDone"; |
| 470 | 470 |
| 471 if (!vda_) | 471 if (!vda_) |
| 472 return; | 472 return; |
| 473 | 473 |
| 474 input_buffer_data_.clear(); | 474 input_buffer_data_.clear(); |
| 475 { | 475 { |
| 476 base::AutoLock auto_lock(lock_); | 476 base::AutoLock auto_lock(lock_); |
| 477 state_ = INITIALIZED; | 477 state_ = INITIALIZED; |
| 478 } | 478 } |
| 479 // Send the pending buffers for decoding. | 479 // Send the pending buffers for decoding. |
| 480 RequestBufferDecode(); | 480 RequestBufferDecode(); |
| 481 } | 481 } |
| 482 | 482 |
| 483 void RTCVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { | 483 void RTCVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { |
| 484 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 484 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 485 if (!vda_) | 485 if (!vda_) |
| 486 return; | 486 return; |
| 487 | 487 |
| 488 LOG(ERROR) << "VDA Error:" << error; | 488 LOG(ERROR) << "VDA Error:" << error; |
| 489 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", | 489 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoDecoderError", |
| 490 error, | 490 error, |
| 491 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); | 491 media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM); |
| 492 DestroyVDA(); | 492 DestroyVDA(); |
| 493 | 493 |
| 494 base::AutoLock auto_lock(lock_); | 494 base::AutoLock auto_lock(lock_); |
| 495 state_ = DECODE_ERROR; | 495 state_ = DECODE_ERROR; |
| 496 } | 496 } |
| 497 | 497 |
| 498 void RTCVideoDecoder::WillDestroyCurrentMessageLoop() { | 498 void RTCVideoDecoder::WillDestroyCurrentMessageLoop() { |
| 499 DVLOG(2) << "WillDestroyCurrentMessageLoop"; | 499 DVLOG(2) << "WillDestroyCurrentMessageLoop"; |
| 500 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 500 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 501 factories_->Abort(); | 501 factories_->Abort(); |
| 502 weak_factory_.InvalidateWeakPtrs(); | 502 weak_factory_.InvalidateWeakPtrs(); |
| 503 DestroyVDA(); | 503 DestroyVDA(); |
| 504 } | 504 } |
| 505 | 505 |
| 506 void RTCVideoDecoder::Initialize(base::WaitableEvent* waiter) { | 506 void RTCVideoDecoder::Initialize(base::WaitableEvent* waiter) { |
| 507 DVLOG(2) << "Initialize"; | 507 DVLOG(2) << "Initialize"; |
| 508 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 508 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 509 base::MessageLoop::current()->AddDestructionObserver(this); | 509 base::MessageLoop::current()->AddDestructionObserver(this); |
| 510 waiter->Signal(); | 510 waiter->Signal(); |
| 511 } | 511 } |
| 512 | 512 |
| 513 void RTCVideoDecoder::RequestBufferDecode() { | 513 void RTCVideoDecoder::RequestBufferDecode() { |
| 514 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 514 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 515 if (!vda_) | 515 if (!vda_) |
| 516 return; | 516 return; |
| 517 | 517 |
| 518 MovePendingBuffersToDecodeBuffers(); | 518 MovePendingBuffersToDecodeBuffers(); |
| 519 | 519 |
| 520 while (CanMoreDecodeWorkBeDone()) { | 520 while (CanMoreDecodeWorkBeDone()) { |
| 521 // Get a buffer and data from the queue. | 521 // Get a buffer and data from the queue. |
| 522 SHMBuffer* shm_buffer = NULL; | 522 SHMBuffer* shm_buffer = NULL; |
| 523 BufferData buffer_data; | 523 BufferData buffer_data; |
| 524 { | 524 { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 626 scoped_ptr<SHMBuffer> shm_buffer = GetSHM_Locked(input_image._length); | 626 scoped_ptr<SHMBuffer> shm_buffer = GetSHM_Locked(input_image._length); |
| 627 if (!shm_buffer) | 627 if (!shm_buffer) |
| 628 return; | 628 return; |
| 629 SaveToDecodeBuffers_Locked(input_image, shm_buffer.Pass(), buffer_data); | 629 SaveToDecodeBuffers_Locked(input_image, shm_buffer.Pass(), buffer_data); |
| 630 delete[] input_image._buffer; | 630 delete[] input_image._buffer; |
| 631 pending_buffers_.pop_front(); | 631 pending_buffers_.pop_front(); |
| 632 } | 632 } |
| 633 } | 633 } |
| 634 | 634 |
| 635 void RTCVideoDecoder::ResetInternal() { | 635 void RTCVideoDecoder::ResetInternal() { |
| 636 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 636 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 637 DVLOG(2) << "ResetInternal"; | 637 DVLOG(2) << "ResetInternal"; |
| 638 if (vda_) | 638 if (vda_) |
| 639 vda_->Reset(); | 639 vda_->Reset(); |
| 640 } | 640 } |
| 641 | 641 |
| 642 void RTCVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id, | 642 void RTCVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id, |
| 643 uint32 sync_point) { | 643 uint32 sync_point) { |
| 644 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 644 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 645 DVLOG(3) << "ReusePictureBuffer. id=" << picture_buffer_id; | 645 DVLOG(3) << "ReusePictureBuffer. id=" << picture_buffer_id; |
| 646 | 646 |
| 647 if (!vda_) | 647 if (!vda_) |
| 648 return; | 648 return; |
| 649 | 649 |
| 650 CHECK(!picture_buffers_at_display_.empty()); | 650 CHECK(!picture_buffers_at_display_.empty()); |
| 651 | 651 |
| 652 size_t num_erased = picture_buffers_at_display_.erase(picture_buffer_id); | 652 size_t num_erased = picture_buffers_at_display_.erase(picture_buffer_id); |
| 653 DCHECK(num_erased); | 653 DCHECK(num_erased); |
| 654 | 654 |
| 655 std::map<int32, media::PictureBuffer>::iterator it = | 655 std::map<int32, media::PictureBuffer>::iterator it = |
| 656 assigned_picture_buffers_.find(picture_buffer_id); | 656 assigned_picture_buffers_.find(picture_buffer_id); |
| 657 | 657 |
| 658 if (it == assigned_picture_buffers_.end()) { | 658 if (it == assigned_picture_buffers_.end()) { |
| 659 // This picture was dismissed while in display, so we postponed deletion. | 659 // This picture was dismissed while in display, so we postponed deletion. |
| 660 it = dismissed_picture_buffers_.find(picture_buffer_id); | 660 it = dismissed_picture_buffers_.find(picture_buffer_id); |
| 661 DCHECK(it != dismissed_picture_buffers_.end()); | 661 DCHECK(it != dismissed_picture_buffers_.end()); |
| 662 factories_->DeleteTexture(it->second.texture_id()); | 662 factories_->DeleteTexture(it->second.texture_id()); |
| 663 dismissed_picture_buffers_.erase(it); | 663 dismissed_picture_buffers_.erase(it); |
| 664 return; | 664 return; |
| 665 } | 665 } |
| 666 | 666 |
| 667 factories_->WaitSyncPoint(sync_point); | 667 factories_->WaitSyncPoint(sync_point); |
| 668 | 668 |
| 669 vda_->ReusePictureBuffer(picture_buffer_id); | 669 vda_->ReusePictureBuffer(picture_buffer_id); |
| 670 } | 670 } |
| 671 | 671 |
| 672 void RTCVideoDecoder::DestroyTextures() { | 672 void RTCVideoDecoder::DestroyTextures() { |
| 673 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 673 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 674 std::map<int32, media::PictureBuffer>::iterator it; | 674 std::map<int32, media::PictureBuffer>::iterator it; |
| 675 | 675 |
| 676 for (it = assigned_picture_buffers_.begin(); | 676 for (it = assigned_picture_buffers_.begin(); |
| 677 it != assigned_picture_buffers_.end(); | 677 it != assigned_picture_buffers_.end(); |
| 678 ++it) { | 678 ++it) { |
| 679 factories_->DeleteTexture(it->second.texture_id()); | 679 factories_->DeleteTexture(it->second.texture_id()); |
| 680 } | 680 } |
| 681 assigned_picture_buffers_.clear(); | 681 assigned_picture_buffers_.clear(); |
| 682 | 682 |
| 683 for (it = dismissed_picture_buffers_.begin(); | 683 for (it = dismissed_picture_buffers_.begin(); |
| 684 it != dismissed_picture_buffers_.end(); | 684 it != dismissed_picture_buffers_.end(); |
| 685 ++it) { | 685 ++it) { |
| 686 factories_->DeleteTexture(it->second.texture_id()); | 686 factories_->DeleteTexture(it->second.texture_id()); |
| 687 } | 687 } |
| 688 dismissed_picture_buffers_.clear(); | 688 dismissed_picture_buffers_.clear(); |
| 689 } | 689 } |
| 690 | 690 |
| 691 void RTCVideoDecoder::DestroyVDA() { | 691 void RTCVideoDecoder::DestroyVDA() { |
| 692 DVLOG(2) << "DestroyVDA"; | 692 DVLOG(2) << "DestroyVDA"; |
| 693 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 693 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 694 if (vda_) | 694 if (vda_) |
| 695 vda_.release()->Destroy(); | 695 vda_.release()->Destroy(); |
| 696 DestroyTextures(); | 696 DestroyTextures(); |
| 697 base::AutoLock auto_lock(lock_); | 697 base::AutoLock auto_lock(lock_); |
| 698 state_ = UNINITIALIZED; | 698 state_ = UNINITIALIZED; |
| 699 } | 699 } |
| 700 | 700 |
| 701 scoped_ptr<RTCVideoDecoder::SHMBuffer> RTCVideoDecoder::GetSHM_Locked( | 701 scoped_ptr<RTCVideoDecoder::SHMBuffer> RTCVideoDecoder::GetSHM_Locked( |
| 702 size_t min_size) { | 702 size_t min_size) { |
| 703 // Reuse a SHM if possible. | 703 // Reuse a SHM if possible. |
| 704 SHMBuffer* ret = NULL; | 704 SHMBuffer* ret = NULL; |
| 705 if (!available_shm_segments_.empty() && | 705 if (!available_shm_segments_.empty() && |
| 706 available_shm_segments_.back()->size >= min_size) { | 706 available_shm_segments_.back()->size >= min_size) { |
| 707 ret = available_shm_segments_.back(); | 707 ret = available_shm_segments_.back(); |
| 708 available_shm_segments_.pop_back(); | 708 available_shm_segments_.pop_back(); |
| 709 } | 709 } |
| 710 // Post to vda thread to create shared memory if SHM cannot be reused or the | 710 // Post to vda thread to create shared memory if SHM cannot be reused or the |
| 711 // queue is almost empty. | 711 // queue is almost empty. |
| 712 if (num_shm_buffers_ < kMaxNumSharedMemorySegments && | 712 if (num_shm_buffers_ < kMaxNumSharedMemorySegments && |
| 713 (ret == NULL || available_shm_segments_.size() <= 1)) { | 713 (ret == NULL || available_shm_segments_.size() <= 1)) { |
| 714 vda_loop_proxy_->PostTask( | 714 vda_task_runner_->PostTask( |
| 715 FROM_HERE, | 715 FROM_HERE, |
| 716 base::Bind(&RTCVideoDecoder::CreateSHM, weak_this_, 1, min_size)); | 716 base::Bind(&RTCVideoDecoder::CreateSHM, weak_this_, 1, min_size)); |
| 717 } | 717 } |
| 718 return scoped_ptr<SHMBuffer>(ret); | 718 return scoped_ptr<SHMBuffer>(ret); |
| 719 } | 719 } |
| 720 | 720 |
| 721 void RTCVideoDecoder::PutSHM_Locked(scoped_ptr<SHMBuffer> shm_buffer) { | 721 void RTCVideoDecoder::PutSHM_Locked(scoped_ptr<SHMBuffer> shm_buffer) { |
| 722 available_shm_segments_.push_back(shm_buffer.release()); | 722 available_shm_segments_.push_back(shm_buffer.release()); |
| 723 } | 723 } |
| 724 | 724 |
| 725 void RTCVideoDecoder::CreateSHM(int number, size_t min_size) { | 725 void RTCVideoDecoder::CreateSHM(int number, size_t min_size) { |
| 726 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | 726 DCHECK(vda_task_runner_->BelongsToCurrentThread()); |
| 727 DVLOG(2) << "CreateSHM. size=" << min_size; | 727 DVLOG(2) << "CreateSHM. size=" << min_size; |
| 728 int number_to_allocate; | 728 int number_to_allocate; |
| 729 { | 729 { |
| 730 base::AutoLock auto_lock(lock_); | 730 base::AutoLock auto_lock(lock_); |
| 731 number_to_allocate = | 731 number_to_allocate = |
| 732 std::min(kMaxNumSharedMemorySegments - num_shm_buffers_, number); | 732 std::min(kMaxNumSharedMemorySegments - num_shm_buffers_, number); |
| 733 } | 733 } |
| 734 size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); | 734 size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); |
| 735 for (int i = 0; i < number_to_allocate; i++) { | 735 for (int i = 0; i < number_to_allocate; i++) { |
| 736 base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); | 736 base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 | 777 |
| 778 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { | 778 int32_t RTCVideoDecoder::RecordInitDecodeUMA(int32_t status) { |
| 779 // Logging boolean is enough to know if HW decoding has been used. Also, | 779 // Logging boolean is enough to know if HW decoding has been used. Also, |
| 780 // InitDecode is less likely to return an error so enum is not used here. | 780 // InitDecode is less likely to return an error so enum is not used here. |
| 781 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; | 781 bool sample = (status == WEBRTC_VIDEO_CODEC_OK) ? true : false; |
| 782 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); | 782 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoDecoderInitDecodeSuccess", sample); |
| 783 return status; | 783 return status; |
| 784 } | 784 } |
| 785 | 785 |
| 786 } // namespace content | 786 } // namespace content |
| OLD | NEW |