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