Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(321)

Side by Side Diff: content/renderer/media/rtc_video_decoder.cc

Issue 13890012: Integrate VDA with WebRTC. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Create new VDA thread, copy gpu_factories, and add DestructionObserver Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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(), &timestamp, &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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698