Chromium Code Reviews| Index: content/renderer/media/rtc_video_decoder.cc |
| diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc |
| index ecb488b6e8110c1f397926fcfb90590c90acbdc6..0afdef07a1f693e8f1b9fc7fb82e24bd01af87f8 100644 |
| --- a/content/renderer/media/rtc_video_decoder.cc |
| +++ b/content/renderer/media/rtc_video_decoder.cc |
| @@ -32,16 +32,11 @@ const int32 RTCVideoDecoder::ID_INVALID = -1; |
| // resources. |
| static const size_t kMaxInFlightDecodes = 8; |
| -// Size of shared-memory segments we allocate. Since we reuse them we let them |
| -// be on the beefy side. |
| -static const size_t kSharedMemorySegmentBytes = 100 << 10; |
| +// Number of allocated shared memory segments. |
| +static const size_t kNumSharedMemorySegments = 16; |
| -// Maximum number of allocated shared-memory segments. |
| -static const int kMaxNumSharedMemorySegments = 16; |
| - |
| -// Maximum number of pending WebRTC buffers that are waiting for the shared |
| -// memory. 10 seconds for 30 fps. |
| -static const size_t kMaxNumOfPendingBuffers = 300; |
| +// Maximum number of pending WebRTC buffers that are waiting for shared memory. |
| +static const size_t kMaxNumOfPendingBuffers = 8; |
| // A shared memory segment and its allocated size. This class has the ownership |
| // of |shm|. |
| @@ -99,14 +94,7 @@ RTCVideoDecoder::~RTCVideoDecoder() { |
| STLDeleteContainerPairFirstPointers(decode_buffers_.begin(), |
| decode_buffers_.end()); |
| decode_buffers_.clear(); |
| - |
| - // Delete WebRTC input buffers. |
| - for (std::deque<std::pair<webrtc::EncodedImage, BufferData> >::iterator it = |
| - pending_buffers_.begin(); |
| - it != pending_buffers_.end(); |
| - ++it) { |
| - delete[] it->first._buffer; |
| - } |
| + ClearPendingBuffers(); |
| } |
| // static |
| @@ -161,15 +149,7 @@ int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings, |
| LOG(ERROR) << "VDA is not initialized. state=" << state_; |
| return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_UNINITIALIZED); |
| } |
| - // Create some shared memory if the queue is empty. |
| - if (available_shm_segments_.size() == 0) { |
| - factories_->GetTaskRunner()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&RTCVideoDecoder::CreateSHM, |
| - weak_factory_.GetWeakPtr(), |
| - kMaxInFlightDecodes, |
| - kSharedMemorySegmentBytes)); |
| - } |
| + |
| return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_OK); |
| } |
| @@ -249,15 +229,24 @@ int32_t RTCVideoDecoder::Decode( |
| // this isn't a mid-stream resolution change, then send the buffer for decode |
| // immediately. Otherwise, save the buffer in the queue for later decode. |
| scoped_ptr<SHMBuffer> shm_buffer; |
| - if (!need_to_reset_for_midstream_resize && pending_buffers_.size() == 0) |
| + if (!need_to_reset_for_midstream_resize && pending_buffers_.empty()) |
| shm_buffer = GetSHM_Locked(inputImage._length); |
| if (!shm_buffer) { |
| - if (!SaveToPendingBuffers_Locked(inputImage, buffer_data)) |
| + if (!SaveToPendingBuffers_Locked(inputImage, buffer_data)) { |
| + // We have exceeded the pending buffers count, we are severely behind. |
| + // Since we are returning ERROR, WebRTC will not be interested in the |
| + // remaining buffers, and will provide us with a new keyframe instead. |
| + // Better to drop any pending buffers and start afresh to catch up faster. |
| + DVLOG(1) << "Exceeded maximum pending buffer count, dropping"; |
| + ClearPendingBuffers(); |
| return WEBRTC_VIDEO_CODEC_ERROR; |
| + } |
| + |
| if (need_to_reset_for_midstream_resize) { |
| base::AutoUnlock auto_unlock(lock_); |
| Reset(); |
| } |
| + |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| @@ -511,7 +500,7 @@ void RTCVideoDecoder::RequestBufferDecode() { |
| { |
| base::AutoLock auto_lock(lock_); |
| // Do not request decode if VDA is resetting. |
| - if (decode_buffers_.size() == 0 || state_ == RESETTING) |
| + if (decode_buffers_.empty() || state_ == RESETTING) |
| return; |
| shm_buffer = decode_buffers_.front().first; |
| buffer_data = decode_buffers_.front().second; |
| @@ -732,50 +721,58 @@ void RTCVideoDecoder::DestroyVDA() { |
| scoped_ptr<RTCVideoDecoder::SHMBuffer> RTCVideoDecoder::GetSHM_Locked( |
| size_t min_size) { |
| // Reuse a SHM if possible. |
| - SHMBuffer* ret = NULL; |
| if (!available_shm_segments_.empty() && |
| available_shm_segments_.back()->size >= min_size) { |
| - ret = available_shm_segments_.back(); |
| + scoped_ptr<SHMBuffer> buffer(available_shm_segments_.back()); |
| available_shm_segments_.pop_back(); |
| + return buffer; |
| } |
| - // Post to vda thread to create shared memory if SHM cannot be reused or the |
| - // queue is almost empty. |
| - if (num_shm_buffers_ < kMaxNumSharedMemorySegments && |
| - (ret == NULL || available_shm_segments_.size() <= 1)) { |
| - factories_->GetTaskRunner()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&RTCVideoDecoder::CreateSHM, |
| - weak_factory_.GetWeakPtr(), |
| - 1, |
| - min_size)); |
| + |
| + if (available_shm_segments_.size() != num_shm_buffers_) { |
| + // Either available_shm_segments_ is empty (and we already have some SHM |
| + // buffers allocated), or the size of available segments is not large |
| + // enough. In the former case we need to wait for buffers to be returned, |
| + // in the latter we need to wait for all buffers to be returned to drop |
| + // them and reallocate with a new size. |
| + return NULL; |
| + } |
| + |
| + if (num_shm_buffers_ != 0) { |
| + STLDeleteElements(&available_shm_segments_); |
| + num_shm_buffers_ = 0; |
| } |
| - return scoped_ptr<SHMBuffer>(ret); |
| + |
| + // Create twice as large buffers as required, to avoid frequent reallocation. |
| + factories_->GetTaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&RTCVideoDecoder::CreateSHM, weak_factory_.GetWeakPtr(), |
| + kNumSharedMemorySegments, min_size * 2)); |
| + |
| + // We'll be called again after the shared memory is created. |
| + return NULL; |
| } |
| void RTCVideoDecoder::PutSHM_Locked(scoped_ptr<SHMBuffer> shm_buffer) { |
| available_shm_segments_.push_back(shm_buffer.release()); |
| } |
| -void RTCVideoDecoder::CreateSHM(int number, size_t min_size) { |
| +void RTCVideoDecoder::CreateSHM(size_t count, size_t size) { |
| DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); |
| - DVLOG(2) << "CreateSHM. size=" << min_size; |
| - int number_to_allocate; |
| - { |
| - base::AutoLock auto_lock(lock_); |
| - number_to_allocate = |
| - std::min(kMaxNumSharedMemorySegments - num_shm_buffers_, number); |
| - } |
| - size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); |
| - for (int i = 0; i < number_to_allocate; i++) { |
| - scoped_ptr<base::SharedMemory> shm = |
| - factories_->CreateSharedMemory(size_to_allocate); |
| - if (shm) { |
| - base::AutoLock auto_lock(lock_); |
| - num_shm_buffers_++; |
| - PutSHM_Locked( |
| - scoped_ptr<SHMBuffer>(new SHMBuffer(shm.Pass(), size_to_allocate))); |
| + DVLOG(2) << "CreateSHM. count=" << count << ", size=" << size; |
| + |
| + for (size_t i = 0; i < count; i++) { |
| + scoped_ptr<base::SharedMemory> shm = factories_->CreateSharedMemory(size); |
|
Ville-Mikko Rautio
2015/07/17 11:26:15
Earlier it was quaranteed that each buffer would b
Pawel Osciak
2015/07/21 07:10:07
Yes, that was intentional. We may have to realloca
|
| + if (!shm) { |
| + LOG(ERROR) << "Failed allocating shared memory of size=" << size; |
| + NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); |
| + return; |
| } |
| + |
| + base::AutoLock auto_lock(lock_); |
| + PutSHM_Locked(scoped_ptr<SHMBuffer>(new SHMBuffer(shm.Pass(), size))); |
| + ++num_shm_buffers_; |
| } |
| + |
| // Kick off the decoding. |
| RequestBufferDecode(); |
| } |
| @@ -818,4 +815,15 @@ void RTCVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() |
| DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); |
| } |
| +void RTCVideoDecoder::ClearPendingBuffers() { |
| + // Delete WebRTC input buffers. |
| + for (std::deque<std::pair<webrtc::EncodedImage, BufferData>>::iterator it = |
| + pending_buffers_.begin(); |
| + it != pending_buffers_.end(); ++it) { |
| + delete[] it->first._buffer; |
| + } |
| + |
| + pending_buffers_.clear(); |
| +} |
| + |
| } // namespace content |