OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
Pawel Osciak
2012/05/03 16:22:07
As the whole threading is rewritten with the next
| |
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 StopOnError(error_code); \ | |
26 return ret; \ | |
27 } \ | |
28 } while (0) | |
29 | |
30 using content::VaapiH264Decoder; | |
31 | |
32 void VaapiVideoDecodeAccelerator::StopOnError( | |
33 media::VideoDecodeAccelerator::Error error) { | |
34 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
35 | |
36 DVLOG(1) << "Stopping on error " << error; | |
37 | |
38 decoder_thread_.Stop(); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
This will drain the thread's messageloop & wait fo
| |
39 | |
40 if (client_) | |
41 client_->NotifyError(error); | |
42 client_ = NULL; | |
43 } | |
44 | |
45 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( | |
46 media::VideoDecodeAccelerator::Client* client) | |
47 : input_ready_(true, false), // manually Reset() and initially not signalled | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
indent is off (and for the rest of the initializer
Pawel Osciak
2012/05/03 16:22:07
Done.
| |
48 message_loop_(MessageLoop::current()), | |
49 client_(client), | |
50 pictures_requested_(false), | |
51 after_reset_(false), | |
52 resetting_(false), | |
53 decoder_thread_("VaapiDecoderThread") { | |
54 } | |
55 | |
56 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { | |
57 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
58 } | |
59 | |
60 bool VaapiVideoDecodeAccelerator::Initialize( | |
61 media::VideoCodecProfile profile) { | |
62 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
63 bool res = true; | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
decl at first use, below.
Pawel Osciak
2012/05/03 16:22:07
Done.
| |
64 | |
65 DVLOG(2) << "Initializing VAVDA, profile: " << profile; | |
66 | |
67 res = CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableVaapi); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
ISTM this would make more sense at a higher layer.
Pawel Osciak
2012/05/03 16:22:07
I'll make a TODO out of it.
| |
68 if (!res) { | |
69 DVLOG(1) << "Vaapi HW acceleration disabled"; | |
70 goto done; | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
seriously? goto?
Are you just testing me for bei
Pawel Osciak
2012/05/03 16:22:07
Well, it's not forbidden by the code style :P
| |
71 } | |
72 | |
73 res = decoder_.Initialize(profile, x_display_, glx_context_, | |
74 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicCallback, | |
75 base::Unretained(this))); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
Unretained is usually the wrong thing to do. (see
Pawel Osciak
2012/05/03 16:22:07
Done.
| |
76 if (!res) { | |
77 DVLOG(1) << "Failed initializing decoder"; | |
78 goto done; | |
79 } | |
80 | |
81 res = decoder_thread_.Start(); | |
82 if (!res) | |
83 DVLOG(1) << "Failed starting decoding thread"; | |
84 | |
85 done: | |
86 MessageLoop::current()->PostTask(FROM_HERE, | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
you mean to say:
message_loop_->PostTask(FROM_HERE
Pawel Osciak
2012/05/03 16:22:07
As we discussed, we'd have to do Unretained(client
| |
87 base::Bind(&VaapiVideoDecodeAccelerator::NotifyInitializeDone, this)); | |
88 return res; | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
s/res/true/ assuming you early-return false on fai
Pawel Osciak
2012/05/03 16:22:07
Done.
| |
89 } | |
90 | |
91 void VaapiVideoDecodeAccelerator::NotifyInitializeDone() { | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
drop
| |
92 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
93 if (client_) | |
94 client_->NotifyInitializeDone(); | |
95 } | |
96 | |
97 void VaapiVideoDecodeAccelerator::SetGlxState(Display* x_display, | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
I'm not sure there's a reason to make this a separ
Pawel Osciak
2012/05/03 16:22:07
I have no preference. I just made it symmetrical t
| |
98 GLXContext glx_context) { | |
99 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
100 x_display_ = x_display; | |
101 glx_context_ = glx_context; | |
102 } | |
103 | |
104 void VaapiVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { | |
105 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
106 | |
107 DVLOG(4) << "Notifying end of input buffer " << input_buffer_id; | |
108 if (client_) | |
109 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); | |
110 } | |
111 | |
112 void VaapiVideoDecodeAccelerator::SyncAndNotifyPictureReady(int32 input_id, | |
113 int32 output_id) { | |
114 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
115 | |
116 // Sync the contents of the texture. | |
117 if (!decoder_.PutPicToTexture(output_id)) { | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
Use the macro?
Pawel Osciak
2012/05/03 16:22:07
Yep, and now we have use for macro not returning f
| |
118 DVLOG(1) << "Failed putting picture to texture"; | |
119 StopOnError(PLATFORM_FAILURE); | |
120 return; | |
121 } | |
122 | |
123 // And notify the client a picture is ready to be displayed. | |
124 media::Picture picture(output_id, input_id); | |
125 DVLOG(4) << "Notifying output picture id " << output_id | |
126 << " for input "<< input_id << " is ready"; | |
127 if (client_) | |
128 client_->PictureReady(picture); | |
129 } | |
130 | |
131 void VaapiVideoDecodeAccelerator::RequestPictureBuffers(int num_pics, | |
132 int width, | |
133 int height) { | |
134 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
135 | |
136 DVLOG(1) << "Requesting " << num_pics << " pictures of size: " | |
137 << width << "x" << height; | |
138 if (client_) | |
139 client_->ProvidePictureBuffers(num_pics, gfx::Size(width, height)); | |
140 } | |
141 | |
142 void VaapiVideoDecodeAccelerator::TryGetNewInputBuffer() { | |
143 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
144 DCHECK(!input_ready_.IsSignaled()); | |
145 | |
146 // If current buffer is still set, return it to the client. | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
It seems strange to me that you only notify the cl
Pawel Osciak
2012/05/03 16:22:07
As we discussed on the call, this is not the case.
| |
147 if (curr_input_buffer_.get()) { | |
148 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | |
149 &VaapiVideoDecodeAccelerator::NotifyInputBufferRead, this, | |
150 curr_input_buffer_->id)); | |
151 | |
152 curr_input_buffer_.reset(); | |
153 } | |
154 | |
155 // If there is no more input buffers ready, return. We will come back | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
s/is/are/
| |
156 // here the next time client provides us with a new input buffer. | |
157 if (input_buffers_.empty()) | |
158 return; | |
159 | |
160 // Otherwise pop a new input buffer and set it up for the decoder thread. | |
161 curr_input_buffer_.reset(input_buffers_.front()); | |
162 input_buffers_.pop(); | |
163 | |
164 DVLOG(4) << "New current bitstream buffer, id: " << curr_input_buffer_->id | |
165 << " size: " << (int)curr_input_buffer_->size; | |
166 | |
167 // Decoder is waiting on |input_ready_|, so we are safe to do this. | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
This is some very fiddly logic! You are effective
| |
168 decoder_.SetStream((uint8*)curr_input_buffer_->shm->memory(), | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
static_cast
Pawel Osciak
2012/05/03 16:22:07
Done.
| |
169 curr_input_buffer_->size); | |
170 | |
171 // Wake up the decoder thread and let it continue. | |
172 input_ready_.Signal(); | |
173 } | |
174 | |
175 void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( | |
176 const media::BitstreamBuffer& bitstream_buffer) { | |
177 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
178 | |
179 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() | |
180 << " size: " << (int)bitstream_buffer.size(); | |
181 | |
182 scoped_ptr<base::SharedMemory> shm( | |
183 new base::SharedMemory(bitstream_buffer.handle(), true)); | |
184 CHECK(shm.get()); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
You never need to CHECK the result of a new in chr
Pawel Osciak
2012/05/03 16:22:07
Done.
Pawel Osciak
2012/05/03 16:22:07
Done.
| |
185 RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()), | |
186 "Failed to map input buffer", UNREADABLE_INPUT,); | |
187 | |
188 // Set up a new input buffer and queue it for later. | |
189 InputBuffer* input_buffer = new InputBuffer(); | |
190 CHECK(input_buffer); | |
191 input_buffer->shm.reset(shm.release()); | |
192 input_buffer->id = bitstream_buffer.id(); | |
193 input_buffer->size = bitstream_buffer.size(); | |
194 input_buffers_.push(input_buffer); | |
195 } | |
196 | |
197 void VaapiVideoDecodeAccelerator::WaitForInput() { | |
198 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
199 | |
200 // Set us up for sleep, request new input buffer from the main thread | |
201 // and go to sleep waiting for good news. | |
202 input_ready_.Reset(); | |
203 message_loop_->PostTask(FROM_HERE, | |
204 base::Bind(&VaapiVideoDecodeAccelerator::TryGetNewInputBuffer, this)); | |
205 input_ready_.Wait(); | |
206 } | |
207 | |
208 void VaapiVideoDecodeAccelerator::DecodeTask() { | |
209 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
210 VaapiH264Decoder::DecResult res; | |
211 | |
212 // Main decode task. | |
213 DVLOG(4) << "Decode task"; | |
214 | |
215 DCHECK(input_ready_.IsSignaled()); | |
216 | |
217 if (resetting_) { | |
218 // Will get back here once we are done with reset. This is needed so we | |
219 // don't sleep indefinitely blocking the decoder from being forced | |
220 // to reset. | |
221 DVLOG(4) << "Resetting, leaving DecodeTask"; | |
222 return; | |
223 } | |
224 | |
225 // Could happen after reset, when we are still waiting for a new buffer. | |
226 if (!curr_input_buffer_.get()) | |
227 return; | |
228 | |
229 if (!pictures_requested_ || after_reset_) { | |
230 // Try to initialize or resume playback after reset. | |
231 res = decoder_.DecodeInitial(curr_input_buffer_->id); | |
232 switch (res) { | |
233 case VaapiH264Decoder::kReadyToDecode: | |
234 if (!pictures_requested_) { | |
235 // Decoder decoded initial stream information and is ready | |
236 // to receive output pictures. Request them from the client. | |
237 message_loop_->PostTask(FROM_HERE, base::Bind( | |
238 &VaapiVideoDecodeAccelerator::RequestPictureBuffers, this, | |
239 decoder_.GetRequiredNumOfPictures(), | |
240 decoder_.pic_width(), decoder_.pic_height())); | |
241 pictures_requested_ = true; | |
242 } else { | |
243 // We are after reset and successfully found a point from which | |
244 // we can resume normal decoding, so post a task for that. | |
245 DCHECK(after_reset_); | |
246 after_reset_ = false; | |
247 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
?? we're already on the decoder's thread. Why pos
Pawel Osciak
2012/05/03 16:22:07
The design was one task per frame. But not relevan
| |
248 base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); | |
249 } | |
250 break; | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
This method might become slightly less confusing i
| |
251 | |
252 case VaapiH264Decoder::kNeedMoreStreamData: | |
253 DVLOG(2) << "Waiting for more stream data to (re)initialize"; | |
254 // May sleep. | |
255 WaitForInput(); | |
256 break; | |
257 | |
258 case VaapiH264Decoder::kDecodeError: | |
259 DVLOG(1) << "Error decoding stream"; | |
260 message_loop_->PostTask(FROM_HERE, | |
261 base::Bind(&VaapiVideoDecodeAccelerator::StopOnError, this, | |
262 PLATFORM_FAILURE)); | |
263 break; | |
264 | |
265 default: | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
drop default cases everywhere in this CL unless th
Pawel Osciak
2012/05/03 16:22:07
Actually, this one is needed. If the decoder retur
| |
266 NOTREACHED() << "Unexpected result from the decoder"; | |
267 } | |
268 } else { | |
269 // Try to decode what stream data is in the decoder until we get | |
270 // a frame or run out of input stream. | |
271 res = decoder_.DecodeOneFrame(curr_input_buffer_->id); | |
272 switch (res) { | |
273 case VaapiH264Decoder::kNeedMoreStreamData: | |
274 // May sleep. | |
275 WaitForInput(); | |
276 // fallthrough | |
277 case VaapiH264Decoder::kDecodedFrame: | |
278 // (still) have more stream, try to decode more | |
279 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
ditto already on decoder thread
Pawel Osciak
2012/05/03 16:22:07
This time, kReadyToDecode would've been a bug.
| |
280 base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); | |
281 break; | |
282 | |
283 case VaapiH264Decoder::kNoOutputAvailable: | |
284 // The decoder does not have any output buffers available, so return. | |
285 // We will come back once the client gives us back a picture buffer | |
286 // after displaying it. | |
287 break; | |
288 | |
289 case VaapiH264Decoder::kDecodeError: | |
290 DVLOG(1) << "Error decoding stream"; | |
291 message_loop_->PostTask(FROM_HERE, | |
292 base::Bind(&VaapiVideoDecodeAccelerator::StopOnError, this, | |
293 PLATFORM_FAILURE)); | |
294 break; | |
295 | |
296 default: | |
297 NOTREACHED() << "Unexpected result from the decoder"; | |
298 } | |
299 } | |
300 } | |
301 | |
302 | |
303 void VaapiVideoDecodeAccelerator::Decode( | |
304 const media::BitstreamBuffer& bitstream_buffer) { | |
305 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
306 | |
307 TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id", | |
308 bitstream_buffer.id()); | |
309 | |
310 // We got a new input buffer from the client, map it and queue for later use. | |
311 MapAndQueueNewInputBuffer(bitstream_buffer); | |
312 | |
313 // Set it up already if there is no current one. | |
314 if (!curr_input_buffer_.get()) | |
315 TryGetNewInputBuffer(); | |
316 | |
317 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
318 base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); | |
319 } | |
320 | |
321 void VaapiVideoDecodeAccelerator::AssignPictureBuffers( | |
322 const std::vector<media::PictureBuffer>& buffers) { | |
323 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
324 | |
325 // Here we call sensitive decoder functions out of its thread, but | |
326 // the decoder thread is not running yet, so we can safely do this. | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
Initialize() calls decoder_thread_.Start(), and In
| |
327 for (size_t i = 0; i < buffers.size(); ++i) { | |
328 DVLOG(2) << "Assigning picture id " << buffers[i].id() | |
329 << " to texture id " << buffers[i].texture_id(); | |
330 decoder_.AssignPictureBuffer(buffers[i].id(), buffers[i].texture_id()); | |
331 } | |
332 | |
333 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
Why is this the right thing to do?
| |
334 base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); | |
335 } | |
336 | |
337 void VaapiVideoDecodeAccelerator::ReusePictureTask(int32 picture_buffer_id) { | |
338 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
339 | |
340 decoder_.ReusePictureBuffer(picture_buffer_id); | |
341 | |
342 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
already on the decoder thread.
| |
343 base::Bind(&VaapiVideoDecodeAccelerator::DecodeTask, this)); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
Why is this right?
| |
344 } | |
345 | |
346 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | |
347 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
348 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", | |
349 "Picture id", picture_buffer_id); | |
350 | |
351 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
352 base::Bind(&VaapiVideoDecodeAccelerator::ReusePictureTask, this, | |
353 picture_buffer_id)); | |
354 } | |
355 | |
356 void VaapiVideoDecodeAccelerator::FlushTask() { | |
357 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
358 | |
359 decoder_.Flush(); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
This only emits already-decoded pictures, but the
| |
360 decoder_.Reset(); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
Why is Reset() necessary?
| |
361 | |
362 message_loop_->PostTask(FROM_HERE, | |
363 base::Bind(&VaapiVideoDecodeAccelerator::NotifyFlushDone, this)); | |
364 | |
365 WaitForInput(); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
why?
| |
366 } | |
367 | |
368 void VaapiVideoDecodeAccelerator::Flush() { | |
369 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
370 | |
371 DVLOG(1) << "Got flush request"; | |
372 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
373 base::Bind(&VaapiVideoDecodeAccelerator::FlushTask, this)); | |
374 } | |
375 | |
376 void VaapiVideoDecodeAccelerator::NotifyFlushDone() { | |
377 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
378 if (client_) | |
379 client_->NotifyFlushDone(); | |
380 DVLOG(1) << "Flush done"; | |
381 } | |
382 | |
383 void VaapiVideoDecodeAccelerator::ResetTask() { | |
384 DCHECK_EQ(decoder_thread_.message_loop(), MessageLoop::current()); | |
385 | |
386 // All the decoding tasks should be done by now, since the client | |
387 // does not give more input and we have scheduled ourselves after | |
388 // we got a reset request. | |
389 decoder_.Reset(); | |
390 | |
391 // Make sure next time decode tasks are run they will reinitialize. | |
392 after_reset_ = true; | |
393 | |
394 // And let client know that we are done with reset. | |
395 message_loop_->PostTask(FROM_HERE, base::Bind( | |
396 &VaapiVideoDecodeAccelerator::NotifyResetDone, this)); | |
397 | |
398 //WaitForInput(); | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
??
| |
399 } | |
400 | |
401 void VaapiVideoDecodeAccelerator::Reset() { | |
402 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
403 | |
404 DVLOG(1) << "Got reset request"; | |
405 decoder_thread_.message_loop()->PostTask(FROM_HERE, | |
406 base::Bind(&VaapiVideoDecodeAccelerator::ResetTask, this)); | |
407 resetting_ = true; | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
this should go before the above call to avoid raci
| |
408 // Release waiting decoder thread, if any. Any additional already posted | |
409 // decoding threads will exit immediately due to resetting_ set to true. | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
s/threads/tasks/
| |
410 input_ready_.Signal(); | |
411 } | |
412 | |
413 void VaapiVideoDecodeAccelerator::NotifyResetDone() { | |
414 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
415 | |
416 if (client_) | |
417 client_->NotifyResetDone(); | |
418 resetting_ = false; | |
419 DVLOG(1) << "Reset done"; | |
420 } | |
421 | |
422 void VaapiVideoDecodeAccelerator::Destroy() { | |
423 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
424 | |
425 decoder_thread_.Stop(); | |
426 // No decoder tasks running anymore, so safe to destroy. | |
Ami GONE FROM CHROMIUM
2012/04/09 21:35:53
decoder_ is also accessed on the main thread, not
| |
427 decoder_.Destroy(); | |
428 client_ = NULL; | |
429 } | |
430 | |
431 //static | |
432 void VaapiVideoDecodeAccelerator::OutputPicCallback( | |
433 VaapiVideoDecodeAccelerator* vavda, | |
434 int32 input_id, | |
435 int32 output_id) { | |
436 TRACE_EVENT2("Video Decoder", "VAVDA::OutputPicCallback", | |
437 "Input id", input_id, "Picture id", output_id); | |
438 DVLOG(4) << "Outputting picture, input id: " << input_id | |
439 << " output id: " << output_id; | |
440 | |
441 // Forward the request to the main thread. | |
442 DCHECK_EQ(vavda->decoder_thread_.message_loop(), MessageLoop::current()); | |
443 vavda->message_loop_->PostTask(FROM_HERE, | |
444 base::Bind(&VaapiVideoDecodeAccelerator::SyncAndNotifyPictureReady, | |
445 vavda, input_id, output_id)); | |
446 } | |
447 | |
OLD | NEW |