OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/renderer/media/rtc_video_decoder.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/callback_helpers.h" | |
9 #include "base/logging.h" | |
10 #include "base/memory/ref_counted.h" | |
11 #include "base/message_loop_proxy.h" | |
12 #include "base/task_runner_util.h" | |
13 #include "content/renderer/media/native_handle_impl.h" | |
14 #include "media/base/bind_to_loop.h" | |
15 #include "third_party/webrtc/system_wrappers/interface/ref_count.h" | |
16 | |
17 namespace content { | |
18 | |
19 RTCVideoDecoder::RTCVideoDecoder( | |
20 const scoped_refptr<media::GpuVideoDecoder::Factories>& factories) | |
21 : decoder_waiter_(false, false), | |
22 aborted_waiter_(true, false), | |
23 frame_width_(0), | |
24 frame_height_(0), | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
nit: prefer gfx::Size to individual width/height m
wuchengli
2013/06/13 10:28:07
Done.
| |
25 state_(kUninitialized), | |
26 decode_complete_callback_(NULL), | |
27 weak_factory_(this), | |
28 factories_(factories), | |
29 vda_loop_proxy_(factories->GetMessageLoop()), | |
30 decoder_texture_target_(0), | |
31 next_picture_buffer_id_(0), | |
32 next_bitstream_buffer_id_(0) { | |
33 } | |
34 | |
35 RTCVideoDecoder::~RTCVideoDecoder() { | |
36 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
37 DCHECK(!vda_.get()); // Release should have been already called. | |
Pawel Osciak
2013/06/12 23:38:22
.get() shouldn't be required anymore after http://
wuchengli
2013/06/13 10:28:07
Done.
| |
38 DVLOG(2) << "~RTCVideoDecoder"; | |
39 // Delete all shared memories. | |
40 for (size_t i = 0; i < available_shm_segments_.size(); ++i) { | |
41 available_shm_segments_[i]->shm->Close(); | |
42 delete available_shm_segments_[i]; | |
43 } | |
44 available_shm_segments_.clear(); | |
45 for (std::map<int32, SHMBuffer*>::iterator it = | |
46 bitstream_buffers_in_decoder_.begin(); | |
Pawel Osciak
2013/06/12 23:38:22
This looks like invalid indent.
wuchengli
2013/06/13 10:28:07
This should be correct. It indents 4 spaces for th
Ami GONE FROM CHROMIUM
2013/06/13 20:10:03
Yes this is correct.
| |
47 it != bitstream_buffers_in_decoder_.end(); ++it) { | |
48 it->second->shm->Close(); | |
49 delete it->second; | |
50 } | |
51 bitstream_buffers_in_decoder_.clear(); | |
52 for (std::deque<std::pair<SHMBuffer*, BufferData> >::iterator it = | |
53 buffers_to_be_decoded.begin(); | |
Pawel Osciak
2013/06/12 23:38:22
Ditto.
wuchengli
2013/06/13 10:28:07
Same above.
| |
54 it != buffers_to_be_decoded.end(); ++it) { | |
55 it->first->shm->Close(); | |
56 delete it->first; | |
57 } | |
58 buffers_to_be_decoded.clear(); | |
59 | |
60 DestroyTextures(); | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
l.37 implies DestroyVDA() was already called which
wuchengli
2013/06/13 10:28:07
Removed.
| |
61 | |
62 MessageLoop::current()->RemoveDestructionObserver(this); | |
63 } | |
64 | |
65 bool RTCVideoDecoder::Initialize(webrtc::VideoCodecType type) { | |
66 DCHECK(!vda_loop_proxy_->BelongsToCurrentThread()); | |
67 // Convert WebRTC codec type to media codec profile. | |
68 media::VideoCodecProfile profile; | |
69 switch (type) { | |
70 case webrtc::kVideoCodecVP8: | |
71 profile = media::VP8PROFILE_MAIN; | |
72 break; | |
73 default: | |
74 DVLOG(2) << "Video codec not supported:" << type; | |
75 return false; | |
76 } | |
77 vda_loop_proxy_->PostTask( | |
78 FROM_HERE, | |
79 base::Bind(&RTCVideoDecoder::CreateVideoDecodeAccelerator, | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
Isn't this exactly what RGVDF::CreateVideoDecodeAc
wuchengli
2013/06/13 10:28:07
Done. I wanted to initialize a weak pointer in Cre
| |
80 base::Unretained(this), profile)); | |
81 Wait(); | |
82 return (vda_ != NULL); | |
83 } | |
84 | |
85 int32_t RTCVideoDecoder::InitDecode( | |
86 const webrtc::VideoCodec* codecSettings, | |
87 int32_t /*numberOfCores*/) { | |
88 DVLOG(2) << "InitDecode"; | |
89 DCHECK_EQ(codecSettings->codecType, webrtc::kVideoCodecVP8); | |
90 if (codecSettings->codecSpecific.VP8.feedbackModeOn) { | |
91 LOG(ERROR) << "Feedback mode not supported"; | |
92 return WEBRTC_VIDEO_CODEC_ERROR; | |
93 } | |
94 | |
95 base::AutoLock auto_lock(lock_); | |
96 if (state_ == kUninitialized) { | |
97 LOG(ERROR) << "VDA is not initialized."; | |
98 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
99 } | |
100 return WEBRTC_VIDEO_CODEC_OK; | |
101 } | |
102 | |
103 int32_t RTCVideoDecoder::Decode( | |
104 const webrtc::EncodedImage& inputImage, | |
105 bool missingFrames, | |
106 const webrtc::RTPFragmentationHeader* /*fragmentation*/, | |
107 const webrtc::CodecSpecificInfo* /*codecSpecificInfo*/, | |
108 int64_t /*renderTimeMs*/) { | |
109 DVLOG(3) << "Decode"; | |
110 | |
111 { | |
112 base::AutoLock auto_lock(lock_); | |
113 if (state_ == kUninitialized || decode_complete_callback_ == NULL) { | |
114 LOG(ERROR) << "The decoder has not initialized."; | |
115 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
116 } | |
117 if (state_ == kDecodeError) { | |
118 LOG(ERROR) << "Decoding error occurred."; | |
119 return WEBRTC_VIDEO_CODEC_ERROR; | |
120 } | |
121 } | |
122 if (missingFrames || !inputImage._completeFrame) { | |
123 DLOG(ERROR) << "Missing or incomplete frames."; | |
124 // Unlike the SW decoder in libvpx, hw decoder cannot handle broken frames. | |
125 // Return an error to request a key frame. | |
126 return WEBRTC_VIDEO_CODEC_ERROR; | |
127 } | |
128 | |
129 if (inputImage._frameType == webrtc::kKeyFrame) { | |
130 frame_width_ = inputImage._encodedWidth; | |
131 frame_height_ = inputImage._encodedHeight; | |
132 } | |
133 | |
134 // Copy WebRTC buffer to SHM buffer and create buffer data. | |
135 SHMBuffer* shm_buffer = GetSHM(inputImage._length); | |
136 if (!shm_buffer) | |
137 return WEBRTC_VIDEO_CODEC_ERROR; | |
138 memcpy(shm_buffer->shm->memory(), inputImage._buffer, inputImage._length); | |
139 BufferData buffer_data(next_bitstream_buffer_id_, inputImage._timeStamp, | |
140 frame_width_, frame_height_, inputImage._length); | |
141 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. | |
142 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; | |
143 std::pair<SHMBuffer*, BufferData> buffer_pair | |
144 = std::make_pair(shm_buffer, buffer_data); | |
145 | |
146 // Store the buffer and the data to the queue. | |
147 { | |
148 base::AutoLock auto_lock(lock_); | |
149 buffers_to_be_decoded.push_back(buffer_pair); | |
150 } | |
151 | |
152 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
153 &RTCVideoDecoder::RequestBufferDecode, weak_this_)); | |
154 | |
155 return WEBRTC_VIDEO_CODEC_OK; | |
156 } | |
157 | |
158 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback( | |
159 webrtc::DecodedImageCallback* callback) { | |
160 base::AutoLock auto_lock(lock_); | |
161 decode_complete_callback_ = callback; | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
DCHECK d_c_c_ is NULL before this?
wuchengli
2013/06/13 10:28:07
It is more consistent with other implementation wi
| |
162 return WEBRTC_VIDEO_CODEC_OK; | |
163 } | |
164 | |
165 int32_t RTCVideoDecoder::Release() { | |
166 DVLOG(2) << "Release"; | |
167 vda_loop_proxy_->PostTask( | |
168 FROM_HERE, | |
169 base::Bind(&RTCVideoDecoder::ReleaseInternal, weak_this_)); | |
170 Wait(); | |
171 return WEBRTC_VIDEO_CODEC_OK; | |
172 } | |
173 | |
174 int32_t RTCVideoDecoder::Reset() { | |
175 DVLOG(2) << "Reset"; | |
176 { | |
177 base::AutoLock auto_lock(lock_); | |
178 if (state_ == kUninitialized) { | |
179 LOG(ERROR) << "Decoder not initialized."; | |
180 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
181 } | |
182 } | |
183 vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
184 &RTCVideoDecoder::ResetInternal, weak_this_)); | |
185 Wait(); | |
186 return WEBRTC_VIDEO_CODEC_OK; | |
187 } | |
188 | |
189 void RTCVideoDecoder::NotifyInitializeDone() { | |
190 DVLOG(2) << "NotifyInitializeDone"; | |
191 NOTREACHED(); | |
192 } | |
193 | |
194 void RTCVideoDecoder::ProvidePictureBuffers(uint32 count, | |
195 const gfx::Size& size, | |
Pawel Osciak
2013/06/12 23:38:22
indent
wuchengli
2013/06/13 10:28:07
Done.
| |
196 uint32 texture_target) { | |
197 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
198 DVLOG(3) << "ProvidePictureBuffers. texture_target=" << texture_target; | |
199 std::vector<uint32> texture_ids; | |
200 decoder_texture_target_ = texture_target; | |
201 if (!factories_->CreateTextures( | |
202 count, size, &texture_ids, decoder_texture_target_)) { | |
203 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | |
204 return; | |
205 } | |
206 | |
207 if (!vda_) { | |
208 LOG(ERROR) << "vda is NULL"; | |
209 return; | |
210 } | |
211 | |
212 std::vector<media::PictureBuffer> picture_buffers; | |
213 for (size_t i = 0; i < texture_ids.size(); ++i) { | |
214 picture_buffers.push_back(media::PictureBuffer( | |
215 next_picture_buffer_id_++, size, texture_ids[i])); | |
216 bool inserted = picture_buffers_in_decoder_.insert(std::make_pair( | |
217 picture_buffers.back().id(), picture_buffers.back())).second; | |
218 DCHECK(inserted); | |
219 } | |
220 vda_->AssignPictureBuffers(picture_buffers); | |
221 } | |
222 | |
223 void RTCVideoDecoder::DismissPictureBuffer(int32 id) { | |
224 DVLOG(3) << "DismissPictureBuffer. id=" << id; | |
225 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
226 | |
227 std::map<int32, media::PictureBuffer>::iterator it = | |
228 picture_buffers_in_decoder_.find(id); | |
229 if (it == picture_buffers_in_decoder_.end()) { | |
230 NOTREACHED() << "Missing picture buffer: " << id; | |
231 return; | |
232 } | |
233 factories_->DeleteTexture(it->second.texture_id()); | |
234 picture_buffers_in_decoder_.erase(it); | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
What if the texture is being drawn from?
I think y
| |
235 } | |
236 | |
237 void RTCVideoDecoder::PictureReady(const media::Picture& picture) { | |
238 DVLOG(3) << "PictureReady"; | |
239 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
240 | |
241 std::map<int32, media::PictureBuffer>::iterator it = | |
242 picture_buffers_in_decoder_.find(picture.picture_buffer_id()); | |
243 if (it == picture_buffers_in_decoder_.end()) { | |
244 NOTREACHED() << "Missing picture buffer: " << picture.picture_buffer_id(); | |
245 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | |
246 return; | |
247 } | |
248 const media::PictureBuffer& pb = it->second; | |
249 | |
250 // Create a media::VideoFrame. | |
251 uint32_t timestamp = 0; | |
252 uint32_t width = 0, height = 0; | |
253 size_t size = 0; | |
254 GetBufferData(picture.bitstream_buffer_id(), ×tamp, &width, &height, | |
255 &size); | |
256 gfx::Rect visible_rect(width, height); | |
257 gfx::Size natural_size(width, height); | |
258 DCHECK(decoder_texture_target_); | |
259 // Convert timestamp from 90KHz to ms. | |
260 base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue( | |
261 (uint64_t)timestamp * 1000 / 90); | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
static_cast
wuchengli
2013/06/13 10:28:07
Done.
| |
262 scoped_refptr<media::VideoFrame> frame( | |
263 media::VideoFrame::WrapNativeTexture( | |
264 pb.texture_id(), decoder_texture_target_, pb.size(), visible_rect, | |
265 natural_size, timestamp_ms, | |
266 base::Bind(&media::GpuVideoDecoder::Factories::ReadPixels, factories_, | |
267 pb.texture_id(), decoder_texture_target_, | |
268 gfx::Size(visible_rect.width(), visible_rect.height())), | |
269 media::BindToCurrentLoop(base::Bind( | |
270 &RTCVideoDecoder::ReusePictureBuffer, weak_this_, | |
271 picture.picture_buffer_id())))); | |
272 | |
273 // Create a webrtc::I420VideoFrame. | |
274 gfx::Rect rect = frame->visible_rect(); | |
275 webrtc::I420VideoFrame decoded_image; | |
276 decoded_image.CreateEmptyFrame( | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
OOC does this malloc(width*height*1.5)?
(it should
wuchengli
2013/06/13 10:28:07
I haven't finished http://webrtc-codereview.appspo
| |
277 rect.width(), rect.height(), | |
278 rect.width(), rect.width() / 2, rect.width() / 2); | |
279 webrtc::RefCountImpl<NativeHandleImpl>* handle = | |
280 new webrtc::RefCountImpl<NativeHandleImpl>(); | |
281 handle->SetHandle(frame.get()); | |
282 decoded_image.set_native_handle(handle); | |
283 decoded_image.set_timestamp(timestamp); | |
284 | |
285 // Send to decode callback. | |
286 webrtc::DecodedImageCallback *callback; | |
287 { | |
288 base::AutoLock auto_lock(lock_); | |
289 callback = decode_complete_callback_; | |
290 } | |
291 callback->Decoded(decoded_image); | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
what if callback hasn't been set?
wuchengli
2013/06/13 10:28:07
It shouldn't happen because Decode ensures it is s
| |
292 } | |
293 | |
294 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { | |
295 DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id; | |
296 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
297 | |
298 std::map<int32, SHMBuffer*>::iterator it = | |
299 bitstream_buffers_in_decoder_.find(id); | |
300 if (it == bitstream_buffers_in_decoder_.end()) { | |
301 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | |
302 NOTREACHED() << "Missing bitstream buffer: " << id; | |
303 return; | |
304 } | |
305 | |
306 PutSHM(it->second); | |
307 bitstream_buffers_in_decoder_.erase(it); | |
308 | |
309 RequestBufferDecode(); | |
310 } | |
311 | |
312 void RTCVideoDecoder::NotifyFlushDone() { | |
313 DVLOG(3) << "NotifyFlushDone"; | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
NOTREACHED?
wuchengli
2013/06/13 10:28:07
Done.
| |
314 } | |
315 | |
316 void RTCVideoDecoder::NotifyResetDone() { | |
317 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
318 DVLOG(3) << "NotifyResetDone"; | |
319 | |
320 base::AutoLock auto_lock(lock_); | |
321 state_ = kInitialized; | |
322 decoder_waiter_.Signal(); | |
323 } | |
324 | |
325 void RTCVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { | |
326 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
327 if (!vda_) | |
328 return; | |
329 | |
330 DLOG(ERROR) << "VDA Error:" << error; | |
331 DestroyVDA(); | |
332 | |
333 base::AutoLock auto_lock(lock_); | |
334 state_ = kDecodeError; | |
335 } | |
336 | |
337 void RTCVideoDecoder::WillDestroyCurrentMessageLoop() { | |
338 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
339 aborted_waiter_.Signal(); | |
wuchengli
2013/06/10 15:24:22
This makes sure the functions won't block forever
| |
340 factories_->Abort(); | |
341 } | |
342 | |
343 void RTCVideoDecoder::CreateVideoDecodeAccelerator( | |
344 media::VideoCodecProfile profile) { | |
345 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
346 DVLOG(3) << "CreateVideoDecodeAccelerator"; | |
347 media::VideoDecodeAccelerator* vda = | |
348 factories_->CreateVideoDecodeAccelerator(profile, this); | |
349 // vda can be NULL if the codec type is not supported. | |
350 vda_.reset(vda); | |
351 weak_this_ = weak_factory_.GetWeakPtr(); | |
352 | |
353 base::AutoLock auto_lock(lock_); | |
354 state_ = kInitialized; | |
355 decoder_waiter_.Signal(); | |
356 DVLOG(3) << "CreateVideoDecodeAccelerator end"; | |
357 } | |
358 | |
359 void RTCVideoDecoder::RequestBufferDecode() { | |
360 if(!CanMoreDecodeWorkBeDone()) | |
361 return; | |
362 | |
363 // Get a buffer and data from the queue. | |
364 std::pair<SHMBuffer*, BufferData> *buffer_pair; | |
365 { | |
366 base::AutoLock auto_lock(lock_); | |
367 if (buffers_to_be_decoded.size() == 0) | |
368 return; | |
369 buffer_pair = &buffers_to_be_decoded.front(); | |
370 buffers_to_be_decoded.pop_front(); | |
371 } | |
372 SHMBuffer* shm_buffer = buffer_pair->first; | |
373 BufferData buffer_data = buffer_pair->second; | |
374 | |
375 // Create a BitstreamBuffer and send to VDA to decode. | |
376 media::BitstreamBuffer bitstream_buffer( | |
377 buffer_data.bitstream_buffer_id, shm_buffer->shm->handle(), | |
378 buffer_data.size); | |
379 bool inserted = bitstream_buffers_in_decoder_.insert(std::make_pair( | |
380 bitstream_buffer.id(), shm_buffer)).second; | |
381 DCHECK(inserted); | |
382 RecordBufferData(buffer_data); | |
383 vda_->Decode(bitstream_buffer); | |
384 } | |
385 | |
386 // Maximum number of concurrent VDA::Decode() operations GVD will maintain. | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
s/GVD/RVD/
wuchengli
2013/06/13 10:28:07
Done.
| |
387 // Higher values allow better pipelining in the GPU, but also require more | |
388 // resources. | |
389 enum { kMaxInFlightDecodes = 10 }; | |
390 | |
391 bool RTCVideoDecoder::CanMoreDecodeWorkBeDone() { | |
392 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes; | |
393 } | |
394 | |
395 void RTCVideoDecoder::ReleaseInternal() { | |
396 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
397 DVLOG(2) << "ReleaseInternal"; | |
398 | |
399 if (vda_) | |
400 DestroyVDA(); | |
401 | |
402 base::AutoLock auto_lock(lock_); | |
403 state_ = kUninitialized; | |
404 decoder_waiter_.Signal(); | |
405 } | |
406 | |
407 void RTCVideoDecoder::ResetInternal() { | |
408 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
409 vda_->Reset(); | |
410 decoder_waiter_.Signal(); | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
Why this Signal()? (I expected the NotifyResetDon
wuchengli
2013/06/13 10:28:07
Argh... Fixed.
| |
411 } | |
412 | |
413 void RTCVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) { | |
414 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
415 DVLOG(3) << "ReusePictureBuffer. id=" << picture_buffer_id; | |
416 | |
417 if (!vda_) | |
418 return; | |
419 vda_->ReusePictureBuffer(picture_buffer_id); | |
420 } | |
421 | |
422 void RTCVideoDecoder::Wait() { | |
423 base::WaitableEvent* objects[] = {&aborted_waiter_, | |
424 &decoder_waiter_}; | |
425 base::WaitableEvent::WaitMany(objects, arraysize(objects)); | |
426 } | |
427 | |
428 void RTCVideoDecoder::DestroyTextures() { | |
429 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
430 for (std::map<int32, media::PictureBuffer>::iterator it = | |
431 picture_buffers_in_decoder_.begin(); | |
432 it != picture_buffers_in_decoder_.end(); ++it) { | |
433 factories_->DeleteTexture(it->second.texture_id()); | |
434 } | |
435 picture_buffers_in_decoder_.clear(); | |
436 } | |
437 | |
438 void RTCVideoDecoder::DestroyVDA() { | |
439 DVLOG(2) << "DestroyVDA"; | |
440 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
441 if (vda_) | |
442 vda_.release()->Destroy(); | |
443 DestroyTextures(); | |
444 } | |
445 | |
446 // Size of shared-memory segments we allocate. Since we reuse them we let them | |
447 // be on the beefy side. | |
448 static const size_t kSharedMemorySegmentBytes = 100 << 10; | |
449 | |
450 RTCVideoDecoder::SHMBuffer* RTCVideoDecoder::GetSHM(size_t min_size) { | |
451 { | |
452 // Reuse a SHM if possible. | |
453 base::AutoLock auto_lock(lock_); | |
454 if (!available_shm_segments_.empty() && | |
455 available_shm_segments_.back()->size >= min_size) { | |
456 SHMBuffer* ret = available_shm_segments_.back(); | |
457 available_shm_segments_.pop_back(); | |
458 return ret; | |
459 } | |
460 } | |
461 // Create a new shared memory. This is done in main thread. | |
462 size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); | |
463 base::SharedMemory *shm = factories_->CreateSharedMemory(size_to_allocate); | |
464 if (!shm) | |
465 return NULL; | |
466 return new SHMBuffer(shm, size_to_allocate); | |
467 } | |
468 | |
469 void RTCVideoDecoder::PutSHM(SHMBuffer* shm_buffer) { | |
470 DCHECK(vda_loop_proxy_->BelongsToCurrentThread()); | |
471 base::AutoLock auto_lock(lock_); | |
472 available_shm_segments_.push_back(shm_buffer); | |
473 } | |
474 | |
475 void RTCVideoDecoder::RecordBufferData(const BufferData& buffer_data) { | |
476 input_buffer_data_.push_front(buffer_data); | |
477 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but | |
478 // that's too small for some pathological B-frame test videos. The cost of | |
479 // using too-high a value is low (192 bits per extra slot). | |
480 static const size_t kMaxInputBufferDataSize = 128; | |
481 // Pop from the back of the list, because that's the oldest and least likely | |
482 // to be useful in the future data. | |
483 if (input_buffer_data_.size() > kMaxInputBufferDataSize) | |
484 input_buffer_data_.pop_back(); | |
485 } | |
486 | |
487 void RTCVideoDecoder::GetBufferData( | |
488 int32 bitstream_buffer_id, uint32_t* timestamp, uint32_t* width, | |
489 uint32_t* height, size_t *size) { | |
490 for (std::list<BufferData>::const_iterator it = | |
491 input_buffer_data_.begin(); it != input_buffer_data_.end(); | |
Ami GONE FROM CHROMIUM
2013/06/11 23:48:05
This is unlikely to impact perf, and I think this
wuchengli
2013/06/13 10:28:07
I found the element was not removed from the list.
| |
492 ++it) { | |
493 if (it->bitstream_buffer_id != bitstream_buffer_id) | |
494 continue; | |
495 *timestamp = it->timestamp; | |
496 *width = it->width; | |
497 *height = it->height; | |
498 return; | |
499 } | |
500 NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id; | |
501 } | |
502 | |
503 RTCVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* m, size_t s) | |
504 : shm(m), size(s) { | |
505 } | |
506 | |
507 RTCVideoDecoder::SHMBuffer::~SHMBuffer() {} | |
508 | |
509 RTCVideoDecoder::BufferData::BufferData( | |
510 int32 bbid, uint32_t ts, int w, int h, size_t s) | |
511 : bitstream_buffer_id(bbid), timestamp(ts), width(w), | |
512 height(h), size(s) { | |
513 } | |
514 | |
515 RTCVideoDecoder::BufferData::~BufferData() {} | |
516 | |
517 } // namespace content | |
OLD | NEW |