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 |