OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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 "vaapi_video_decode_accelerator.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/command_line.h" | |
9 #include "base/debug/trace_event.h" | |
10 #include "base/logging.h" | |
11 #include "base/stl_util.h" | |
12 #include "base/string_util.h" | |
13 #include "base/synchronization/waitable_event.h" | |
14 #include "gpu/command_buffer/service/gpu_switches.h" | |
15 #include "content/public/common/content_switches.h" | |
16 #include "content/common/gpu/gpu_channel.h" | |
17 #include "media/video/picture.h" | |
18 #include "third_party/libva/va/va.h" | |
19 #include "ui/gfx/gl/gl_bindings.h" | |
20 | |
21 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ | |
22 do { \ | |
23 if (!(result)) { \ | |
24 DVLOG(1) << log; \ | |
25 Destroy(); \ | |
26 NotifyError(error_code); \ | |
27 return ret; \ | |
28 } \ | |
29 } while (0) | |
30 | |
31 using content::VaapiH264Decoder; | |
32 | |
33 void VaapiVideoDecodeAccelerator::NotifyError(Error error) { | |
34 if (message_loop_ != MessageLoop::current()) { | |
35 message_loop_->PostTask(FROM_HERE, base::Bind( | |
36 &VaapiVideoDecodeAccelerator::NotifyError, this, error)); | |
37 return; | |
38 } | |
39 | |
40 DVLOG(1) << "Notifying of error " << error; | |
41 | |
42 if (client_) | |
43 client_->NotifyError(error); | |
44 client_ = NULL; | |
45 } | |
46 | |
47 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator(Client* client) | |
48 : state_(kUninitialized), | |
49 input_ready_(&lock_), | |
50 output_ready_(&lock_), | |
51 message_loop_(MessageLoop::current()), | |
52 client_(client), | |
53 decoder_thread_("VaapiDecoderThread") { | |
54 DCHECK(client_); | |
55 } | |
56 | |
57 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { | |
58 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
59 } | |
60 | |
61 bool VaapiVideoDecodeAccelerator::Initialize( | |
62 media::VideoCodecProfile profile) { | |
63 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
64 | |
65 base::AutoLock auto_lock(lock_); | |
66 DCHECK_EQ(state_, kUninitialized); | |
67 DVLOG(2) << "Initializing VAVDA, profile: " << profile; | |
68 | |
69 // TODO(posciak): try moving the flag check up to higher layers, possibly | |
70 // out of the GPU process. | |
71 bool res = CommandLine::ForCurrentProcess()->HasSwitch( | |
72 switches::kEnableVaapi); | |
73 RETURN_AND_NOTIFY_ON_FAILURE(res, "Vaapi HW acceleration disabled", | |
74 PLATFORM_FAILURE, false); | |
75 | |
76 res = decoder_.Initialize( | |
77 profile, x_display_, glx_context_, | |
78 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicCallback, this)); | |
79 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed initializing decoder", | |
80 PLATFORM_FAILURE, false); | |
81 | |
82 res = decoder_thread_.Start(); | |
83 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed starting decoder thread", | |
84 PLATFORM_FAILURE, false); | |
85 | |
86 state_ = kInitialized; | |
87 | |
88 message_loop_->PostTask(FROM_HERE, base::Bind( | |
89 &VaapiVideoDecodeAccelerator::NotifyInitializeDone, this)); | |
90 return true; | |
91 } | |
92 | |
93 void VaapiVideoDecodeAccelerator::NotifyInitializeDone() { | |
94 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
95 if (client_) | |
Ami GONE FROM CHROMIUM
2012/05/07 16:38:05
How can this fail?
Pawel Osciak
2012/05/07 17:58:00
Not really, done.
| |
96 client_->NotifyInitializeDone(); | |
97 } | |
98 | |
99 // TODO(posciak, fischman): try to move these to constructor parameters, | |
100 // but while removing SetEglState from OVDA as well for symmetry. | |
101 void VaapiVideoDecodeAccelerator::SetGlxState(Display* x_display, | |
102 GLXContext glx_context) { | |
103 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
104 x_display_ = x_display; | |
105 glx_context_ = glx_context; | |
106 } | |
107 | |
108 void VaapiVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { | |
109 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
110 | |
111 DVLOG(4) << "Notifying end of input buffer " << input_buffer_id; | |
112 if (client_) | |
113 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); | |
114 } | |
115 | |
116 void VaapiVideoDecodeAccelerator::SyncAndNotifyPictureReady(int32 input_id, | |
117 int32 output_id) { | |
118 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
119 | |
120 // Sync the contents of the texture. | |
121 RETURN_AND_NOTIFY_ON_FAILURE(decoder_.PutPicToTexture(output_id), | |
122 "Failed putting picture to texture", | |
123 PLATFORM_FAILURE, ); | |
124 | |
125 // And notify the client a picture is ready to be displayed. | |
126 media::Picture picture(output_id, input_id); | |
127 DVLOG(4) << "Notifying output picture id " << output_id | |
128 << " for input "<< input_id << " is ready"; | |
129 if (client_) | |
130 client_->PictureReady(picture); | |
131 } | |
132 | |
133 void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( | |
134 const media::BitstreamBuffer& bitstream_buffer) { | |
135 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
136 | |
137 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() | |
138 << " size: " << (int)bitstream_buffer.size(); | |
139 | |
140 scoped_ptr<base::SharedMemory> shm( | |
141 new base::SharedMemory(bitstream_buffer.handle(), true)); | |
142 RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()), | |
143 "Failed to map input buffer", UNREADABLE_INPUT,); | |
144 | |
145 // Set up a new input buffer and queue it for later. | |
146 linked_ptr<InputBuffer> input_buffer(new InputBuffer()); | |
147 input_buffer->shm.reset(shm.release()); | |
148 input_buffer->id = bitstream_buffer.id(); | |
149 input_buffer->size = bitstream_buffer.size(); | |
150 | |
151 base::AutoLock auto_lock(lock_); | |
152 input_buffers_.push(input_buffer); | |
153 input_ready_.Signal(); | |
154 } | |
155 | |
156 void VaapiVideoDecodeAccelerator::InitialDecodeTask() { | |
157 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
158 | |
159 // Try to initialize or resume playback after reset. | |
160 for (;;) { | |
161 if (!GetInputBuffer()) | |
162 return; | |
163 DCHECK(curr_input_buffer_.get()); | |
164 | |
165 VaapiH264Decoder::DecResult res = decoder_.DecodeInitial( | |
166 curr_input_buffer_->id); | |
167 switch (res) { | |
168 case VaapiH264Decoder::kReadyToDecode: | |
169 message_loop_->PostTask(FROM_HERE, base::Bind( | |
170 &VaapiVideoDecodeAccelerator::ReadyToDecode, this, | |
171 decoder_.GetRequiredNumOfPictures(), | |
172 gfx::Size(decoder_.pic_width(), decoder_.pic_height()))); | |
173 return; | |
174 | |
175 case VaapiH264Decoder::kNeedMoreStreamData: | |
176 ReturnCurrInputBuffer(); | |
177 break; | |
178 | |
179 case VaapiH264Decoder::kDecodeError: | |
180 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error in decoding", | |
181 PLATFORM_FAILURE, ); | |
182 | |
183 default: | |
184 RETURN_AND_NOTIFY_ON_FAILURE(false, | |
185 "Unexpected result from decoder: " << res, | |
186 PLATFORM_FAILURE, ); | |
187 } | |
188 } | |
189 } | |
190 | |
191 bool VaapiVideoDecodeAccelerator::GetInputBuffer() { | |
192 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
193 | |
194 base::AutoLock auto_lock(lock_); | |
195 | |
196 if (curr_input_buffer_.get()) | |
197 return true; | |
198 | |
199 // Will only wait if it is expected that in current state new buffers will | |
200 // be queued from the client via Decode(). The state can change during wait. | |
201 while (input_buffers_.empty() && | |
202 (state_ == kDecoding || state_ == kInitialized || state_ == kIdle)) { | |
203 input_ready_.Wait(); | |
204 } | |
205 | |
206 // We could have got woken up in a different state or never got to sleep | |
207 // due to current state; check for that. | |
208 switch (state_) { | |
209 case kFlushing: | |
210 // Here we are only interested in finishing up decoding buffers that are | |
211 // already queued up. Otherwise will stop decoding. | |
212 if (input_buffers_.empty()) | |
213 return false; | |
214 // else fallthrough | |
215 case kDecoding: | |
216 case kInitialized: | |
217 case kIdle: | |
218 DCHECK(!input_buffers_.empty()); | |
219 | |
220 curr_input_buffer_ = input_buffers_.front(); | |
221 input_buffers_.pop(); | |
222 | |
223 DVLOG(4) << "New current bitstream buffer, id: " << curr_input_buffer_->id | |
224 << " size: " << curr_input_buffer_->size; | |
Ami GONE FROM CHROMIUM
2012/05/07 16:38:05
inconsistently, the style guide requires the << to
Pawel Osciak
2012/05/07 17:58:00
Oh yeah, this rule I actually agree with ;), must
| |
225 | |
226 decoder_.SetStream(static_cast<uint8*>(curr_input_buffer_->shm->memory()), | |
227 curr_input_buffer_->size); | |
Ami GONE FROM CHROMIUM
2012/05/07 16:38:05
inconsistent indent style
Pawel Osciak
2012/05/07 17:58:00
Done.
| |
228 return true; | |
229 | |
230 default: | |
231 // We got woken up due to being destroyed/reset, ignore any already | |
232 // queued inputs. | |
233 return false; | |
234 } | |
235 } | |
236 | |
237 void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer() { | |
238 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
239 | |
240 base::AutoLock auto_lock(lock_); | |
241 DCHECK(curr_input_buffer_.get()); | |
242 int32 id = curr_input_buffer_->id; | |
243 curr_input_buffer_.reset(); | |
244 message_loop_->PostTask(FROM_HERE, base::Bind( | |
245 &VaapiVideoDecodeAccelerator::NotifyInputBufferRead, this, id)); | |
246 } | |
247 | |
248 bool VaapiVideoDecodeAccelerator::GetOutputBuffers() { | |
249 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
250 | |
251 base::AutoLock auto_lock(lock_); | |
252 | |
253 while (output_buffers_.empty() && | |
254 (state_ == kDecoding || state_ == kFlushing)) { | |
255 output_ready_.Wait(); | |
256 } | |
257 | |
258 if (state_ != kDecoding && state_ != kFlushing) | |
259 return false; | |
260 | |
261 while (!output_buffers_.empty()) { | |
262 decoder_.ReusePictureBuffer(output_buffers_.front()); | |
263 output_buffers_.pop(); | |
264 } | |
265 | |
266 return true; | |
267 } | |
268 | |
269 void VaapiVideoDecodeAccelerator::DecodeTask() { | |
270 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
271 | |
272 // Main decode task. | |
273 DVLOG(4) << "Decode task"; | |
274 | |
275 // Try to decode what stream data is (still) in the decoder until we run out | |
276 // of it. | |
277 for (;;) { | |
278 if (!GetInputBuffer()) | |
279 // Early exit requested. | |
280 return; | |
281 DCHECK(curr_input_buffer_.get()); | |
282 | |
283 VaapiH264Decoder::DecResult res = | |
284 decoder_.DecodeOneFrame(curr_input_buffer_->id); | |
285 switch (res) { | |
286 case VaapiH264Decoder::kNeedMoreStreamData: | |
287 ReturnCurrInputBuffer(); | |
288 break; | |
289 | |
290 case VaapiH264Decoder::kDecodedFrame: | |
291 // May still have more stream data, continue decoding. | |
292 break; | |
293 | |
294 case VaapiH264Decoder::kNoOutputAvailable: | |
295 // No more output buffers in the decoder, try getting more or go to | |
296 // sleep waiting for them. | |
297 if (!GetOutputBuffers()) | |
298 return; | |
299 break; | |
300 | |
301 case VaapiH264Decoder::kDecodeError: | |
302 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream", | |
303 PLATFORM_FAILURE, ); | |
304 return; | |
305 | |
306 default: | |
307 RETURN_AND_NOTIFY_ON_FAILURE( | |
308 false, "Unexpected result from the decoder: " << res, | |
309 PLATFORM_FAILURE, ); | |
310 return; | |
311 } | |
312 } | |
313 } | |
314 | |
315 void VaapiVideoDecodeAccelerator::ReadyToDecode(int num_pics, | |
316 const gfx::Size& size) { | |
317 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
318 | |
319 base::AutoLock auto_lock(lock_); | |
320 switch (state_) { | |
321 case kInitialized: | |
322 DVLOG(1) << "Requesting " << num_pics << " pictures of size: " | |
323 << size.width() << "x" << size.height(); | |
324 if (client_) | |
325 client_->ProvidePictureBuffers(num_pics, size); | |
326 state_ = kPicturesRequested; | |
327 break; | |
328 case kIdle: | |
329 state_ = kDecoding; | |
330 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
331 base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); | |
332 break; | |
333 default: | |
334 NOTREACHED() << "Invalid state"; | |
335 } | |
336 } | |
337 | |
338 void VaapiVideoDecodeAccelerator::Decode( | |
339 const media::BitstreamBuffer& bitstream_buffer) { | |
340 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
341 | |
342 TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id", | |
343 bitstream_buffer.id()); | |
344 | |
345 // We got a new input buffer from the client, map it and queue for later use. | |
346 MapAndQueueNewInputBuffer(bitstream_buffer); | |
347 | |
348 base::AutoLock auto_lock(lock_); | |
349 switch (state_) { | |
350 case kInitialized: | |
351 // Initial decode to get the required size of output buffers. | |
352 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
353 base::Bind(&VaapiVideoDecodeAccelerator::InitialDecodeTask, this)); | |
354 break; | |
355 | |
356 case kPicturesRequested: | |
357 // Waiting for pictures, return. | |
358 break; | |
359 | |
360 case kDecoding: | |
361 break; | |
362 | |
363 case kIdle: | |
364 // Need to get decoder into suitable stream location to resume. | |
365 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
366 base::Bind(&VaapiVideoDecodeAccelerator::InitialDecodeTask, this)); | |
367 break; | |
368 | |
369 default: | |
370 DVLOG(1) << "Decode request from client in invalid state: " << state_; | |
371 return; | |
372 } | |
373 } | |
374 | |
375 void VaapiVideoDecodeAccelerator::AssignPictureBuffers( | |
376 const std::vector<media::PictureBuffer>& buffers) { | |
377 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
378 | |
379 base::AutoLock auto_lock(lock_); | |
380 DCHECK_EQ(state_, kPicturesRequested); | |
381 | |
382 for (size_t i = 0; i < buffers.size(); ++i) { | |
383 DVLOG(2) << "Assigning picture id " << buffers[i].id() | |
384 << " to texture id " << buffers[i].texture_id(); | |
385 | |
386 bool res = decoder_.AssignPictureBuffer(buffers[i].id(), | |
387 buffers[i].texture_id()); | |
388 RETURN_AND_NOTIFY_ON_FAILURE( | |
389 res, "Failed assigning picture buffer id: " << buffers[i].id() << | |
390 ", texture id: " << buffers[i].texture_id(), PLATFORM_FAILURE, ); | |
391 } | |
392 | |
393 state_ = kDecoding; | |
394 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
395 base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); | |
396 } | |
397 | |
398 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | |
399 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
400 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id", | |
401 picture_buffer_id); | |
402 | |
403 base::AutoLock auto_lock(lock_); | |
404 output_buffers_.push(picture_buffer_id); | |
405 output_ready_.Signal(); | |
406 } | |
407 | |
408 void VaapiVideoDecodeAccelerator::FlushTask() { | |
409 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
410 DVLOG(1) << "Flush task"; | |
411 | |
412 // First flush all the pictures that haven't been outputted, notifying the | |
413 // client to output them. | |
414 bool res = decoder_.Flush(); | |
415 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.", | |
416 PLATFORM_FAILURE, ); | |
417 | |
418 // Put the decoder in idle state, ready to resume. | |
419 decoder_.Reset(); | |
420 | |
421 message_loop_->PostTask(FROM_HERE, | |
422 base::Bind(&VaapiVideoDecodeAccelerator::FinishFlush, this)); | |
423 } | |
424 | |
425 void VaapiVideoDecodeAccelerator::Flush() { | |
426 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
427 DVLOG(1) << "Got flush request"; | |
428 | |
429 base::AutoLock auto_lock(lock_); | |
430 state_ = kFlushing; | |
431 // Queue a flush task after all existing decoding tasks to clean up. | |
432 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
433 base::Bind(&VaapiVideoDecodeAccelerator::FlushTask, this)); | |
434 | |
435 input_ready_.Signal(); | |
Ami GONE FROM CHROMIUM
2012/05/07 16:38:05
Why *not* move the Signal()'s above the posttask?
Pawel Osciak
2012/05/07 17:58:00
Leaving as is per IM.
| |
436 output_ready_.Signal(); | |
437 } | |
438 | |
439 void VaapiVideoDecodeAccelerator::FinishFlush() { | |
440 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
441 | |
442 base::AutoLock auto_lock(lock_); | |
443 if (state_ != kFlushing) | |
444 return; // We could've gotten destroyed already. | |
Ami GONE FROM CHROMIUM
2012/05/07 16:38:05
I meant that in this case you can
DCHECK_EQ(state
Pawel Osciak
2012/05/07 17:58:00
Oh, ok.
| |
445 | |
446 state_ = kIdle; | |
447 | |
448 if (client_) | |
449 client_->NotifyFlushDone(); | |
450 | |
451 DVLOG(1) << "Flush finished"; | |
452 } | |
453 | |
454 void VaapiVideoDecodeAccelerator::ResetTask() { | |
455 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
456 | |
457 // All the decoding tasks from before the reset request from client are done | |
458 // by now, as this task was scheduled after them and client is expected not | |
459 // to call Decode() after Reset() and before NotifyResetDone. | |
460 decoder_.Reset(); | |
461 | |
462 // Return current input buffer, if present. | |
463 if (curr_input_buffer_.get()) | |
464 ReturnCurrInputBuffer(); | |
465 | |
466 // And let client know that we are done with reset. | |
467 message_loop_->PostTask(FROM_HERE, base::Bind( | |
468 &VaapiVideoDecodeAccelerator::FinishReset, this)); | |
469 } | |
470 | |
471 void VaapiVideoDecodeAccelerator::Reset() { | |
472 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
473 DVLOG(1) << "Got reset request"; | |
474 | |
475 // This will make any new decode tasks exit early. | |
476 base::AutoLock auto_lock(lock_); | |
477 state_ = kResetting; | |
478 | |
479 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
480 base::Bind(&VaapiVideoDecodeAccelerator::ResetTask, this)); | |
481 | |
482 input_ready_.Signal(); | |
483 output_ready_.Signal(); | |
484 } | |
485 | |
486 void VaapiVideoDecodeAccelerator::FinishReset() { | |
487 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
488 | |
489 base::AutoLock auto_lock(lock_); | |
490 if (state_ != kResetting) | |
491 return; // We could've gotten destroyed already. | |
Ami GONE FROM CHROMIUM
2012/05/07 16:38:05
Again,
DCHECK_EQ(state_, kDestroying);
Pawel Osciak
2012/05/07 17:58:00
Done.
| |
492 | |
493 // Drop all remaining input buffers, if present. | |
494 while (!input_buffers_.empty()) | |
495 input_buffers_.pop(); | |
496 | |
497 state_ = kIdle; | |
498 | |
499 if (client_) | |
500 client_->NotifyResetDone(); | |
501 | |
502 DVLOG(1) << "Reset finished"; | |
503 } | |
504 | |
505 void VaapiVideoDecodeAccelerator::DestroyTask() { | |
506 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
507 | |
508 DVLOG(1) << "DestroyTask"; | |
509 base::AutoLock auto_lock(lock_); | |
510 decoder_.Destroy(); | |
511 | |
512 message_loop_->PostTask(FROM_HERE, base::Bind( | |
513 &VaapiVideoDecodeAccelerator::FinishDestroy, this)); | |
514 } | |
515 | |
516 void VaapiVideoDecodeAccelerator::Destroy() { | |
517 if (message_loop_ != MessageLoop::current()) { | |
518 message_loop_->PostTask(FROM_HERE, base::Bind( | |
519 &VaapiVideoDecodeAccelerator::Destroy, this)); | |
520 return; | |
521 } | |
522 | |
523 if (state_ == kUninitialized || state_ == kDestroying) | |
524 return; | |
525 | |
526 DVLOG(1) << "Destroying VAVDA"; | |
527 base::AutoLock auto_lock(lock_); | |
528 state_ = kDestroying; | |
529 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
530 base::Bind(&VaapiVideoDecodeAccelerator::DestroyTask, this)); | |
531 client_ = NULL; | |
532 | |
533 input_ready_.Signal(); | |
534 output_ready_.Signal(); | |
535 } | |
536 | |
537 void VaapiVideoDecodeAccelerator::FinishDestroy() { | |
538 base::AutoLock auto_lock(lock_); | |
539 state_ = kUninitialized; | |
540 } | |
541 | |
542 void VaapiVideoDecodeAccelerator::OutputPicCallback(int32 input_id, | |
543 int32 output_id) { | |
544 TRACE_EVENT2("Video Decoder", "VAVDA::OutputPicCallback", | |
545 "Input id", input_id, "Picture id", output_id); | |
546 DVLOG(4) << "Outputting picture, input id: " << input_id | |
547 << " output id: " << output_id; | |
548 | |
549 // Forward the request to the main thread. | |
550 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
551 message_loop_->PostTask(FROM_HERE, | |
552 base::Bind(&VaapiVideoDecodeAccelerator::SyncAndNotifyPictureReady, | |
553 this, input_id, output_id)); | |
554 } | |
555 | |
OLD | NEW |