OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <CoreVideo/CoreVideo.h> | 5 #include <CoreVideo/CoreVideo.h> |
6 #include <OpenGL/CGLIOSurface.h> | 6 #include <OpenGL/CGLIOSurface.h> |
7 #include <OpenGL/gl.h> | 7 #include <OpenGL/gl.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 22 matching lines...) Expand all Loading... | |
33 | 33 |
34 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator. | 34 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator. |
35 static void OutputThunk( | 35 static void OutputThunk( |
36 void* decompression_output_refcon, | 36 void* decompression_output_refcon, |
37 void* source_frame_refcon, | 37 void* source_frame_refcon, |
38 OSStatus status, | 38 OSStatus status, |
39 VTDecodeInfoFlags info_flags, | 39 VTDecodeInfoFlags info_flags, |
40 CVImageBufferRef image_buffer, | 40 CVImageBufferRef image_buffer, |
41 CMTime presentation_time_stamp, | 41 CMTime presentation_time_stamp, |
42 CMTime presentation_duration) { | 42 CMTime presentation_duration) { |
43 // TODO(sandersd): Implement flush-before-delete to guarantee validity. | |
44 VTVideoDecodeAccelerator* vda = | 43 VTVideoDecodeAccelerator* vda = |
45 reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon); | 44 reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon); |
46 int32_t bitstream_id = reinterpret_cast<intptr_t>(source_frame_refcon); | 45 int32_t bitstream_id = reinterpret_cast<intptr_t>(source_frame_refcon); |
47 vda->Output(bitstream_id, status, image_buffer); | 46 vda->Output(bitstream_id, status, image_buffer); |
48 } | 47 } |
49 | 48 |
50 VTVideoDecodeAccelerator::DecodedFrame::DecodedFrame( | 49 VTVideoDecodeAccelerator::DecodedFrame::DecodedFrame( |
51 int32_t bitstream_id, | 50 int32_t bitstream_id, |
52 CVImageBufferRef image_buffer) | 51 CVImageBufferRef image_buffer) |
53 : bitstream_id(bitstream_id), | 52 : bitstream_id(bitstream_id), |
54 image_buffer(image_buffer) { | 53 image_buffer(image_buffer) { |
55 } | 54 } |
56 | 55 |
57 VTVideoDecodeAccelerator::DecodedFrame::~DecodedFrame() { | 56 VTVideoDecodeAccelerator::DecodedFrame::~DecodedFrame() { |
58 } | 57 } |
59 | 58 |
59 VTVideoDecodeAccelerator::PendingAction::PendingAction( | |
60 Action action, | |
61 int32_t bitstream_id) | |
62 : action(action), | |
63 bitstream_id(bitstream_id) { | |
64 } | |
65 | |
66 VTVideoDecodeAccelerator::PendingAction::~PendingAction() { | |
67 } | |
68 | |
60 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context) | 69 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context) |
61 : cgl_context_(cgl_context), | 70 : cgl_context_(cgl_context), |
62 client_(NULL), | 71 client_(NULL), |
63 format_(NULL), | 72 format_(NULL), |
64 session_(NULL), | 73 session_(NULL), |
65 gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 74 gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
66 weak_this_factory_(this), | 75 weak_this_factory_(this), |
67 decoder_thread_("VTDecoderThread") { | 76 decoder_thread_("VTDecoderThread") { |
68 callback_.decompressionOutputCallback = OutputThunk; | 77 callback_.decompressionOutputCallback = OutputThunk; |
69 callback_.decompressionOutputRefCon = this; | 78 callback_.decompressionOutputRefCon = this; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
153 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height)); | 162 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height)); |
154 #undef CFINT | 163 #undef CFINT |
155 CFDictionarySetValue( | 164 CFDictionarySetValue( |
156 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format); | 165 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format); |
157 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); | 166 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); |
158 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); | 167 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); |
159 CFDictionarySetValue( | 168 CFDictionarySetValue( |
160 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); | 169 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); |
161 | 170 |
162 // TODO(sandersd): Check if the session is already compatible. | 171 // TODO(sandersd): Check if the session is already compatible. |
163 // TODO(sandersd): Flush. | |
164 session_.reset(); | 172 session_.reset(); |
165 CHECK(!VTDecompressionSessionCreate( | 173 CHECK(!VTDecompressionSessionCreate( |
166 kCFAllocatorDefault, | 174 kCFAllocatorDefault, |
167 format_, // video_format_description | 175 format_, // video_format_description |
168 decoder_config, // video_decoder_specification | 176 decoder_config, // video_decoder_specification |
169 image_config, // destination_image_buffer_attributes | 177 image_config, // destination_image_buffer_attributes |
170 &callback_, // output_callback | 178 &callback_, // output_callback |
171 session_.InitializeInto())); | 179 session_.InitializeInto())); |
172 | 180 |
173 // If the size has changed, trigger a request for new picture buffers. | 181 // If the size has changed, trigger a request for new picture buffers. |
182 // TODO(sandersd): Move to SendPictures(), and use this just as a hint for an | |
183 // upcoming size change. | |
174 gfx::Size new_coded_size(coded_dimensions.width, coded_dimensions.height); | 184 gfx::Size new_coded_size(coded_dimensions.width, coded_dimensions.height); |
175 if (coded_size_ != new_coded_size) { | 185 if (coded_size_ != new_coded_size) { |
176 coded_size_ = new_coded_size; | 186 coded_size_ = new_coded_size; |
177 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( | 187 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( |
178 &VTVideoDecodeAccelerator::SizeChangedTask, | 188 &VTVideoDecodeAccelerator::SizeChangedTask, |
179 weak_this_factory_.GetWeakPtr(), | 189 weak_this_factory_.GetWeakPtr(), |
180 coded_size_));; | 190 coded_size_));; |
181 } | 191 } |
182 } | 192 } |
183 | 193 |
184 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) { | 194 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) { |
185 DCHECK(CalledOnValidThread()); | 195 DCHECK(CalledOnValidThread()); |
186 // TODO(sandersd): Test what happens if bitstream buffers are passed to VT out | 196 CHECK_GE(bitstream.id(), 0) << "Negative bitstream_id"; |
187 // of order. | 197 pending_bitstream_ids_.push(bitstream.id()); |
188 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( | 198 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( |
189 &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this), | 199 &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this), |
190 bitstream)); | 200 bitstream)); |
191 } | 201 } |
192 | 202 |
193 // TODO(sandersd): Proper error reporting instead of CHECKs. | 203 // TODO(sandersd): Proper error reporting instead of CHECKs. |
194 void VTVideoDecodeAccelerator::DecodeTask( | 204 void VTVideoDecodeAccelerator::DecodeTask( |
195 const media::BitstreamBuffer bitstream) { | 205 const media::BitstreamBuffer bitstream) { |
196 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 206 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
197 | 207 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
229 nalus.push_back(nalu); | 239 nalus.push_back(nalu); |
230 data_size += kNALUHeaderLength + nalu.size; | 240 data_size += kNALUHeaderLength + nalu.size; |
231 } | 241 } |
232 } | 242 } |
233 | 243 |
234 // 2. Initialize VideoToolbox. | 244 // 2. Initialize VideoToolbox. |
235 // TODO(sandersd): Reinitialize when there are new parameter sets. | 245 // TODO(sandersd): Reinitialize when there are new parameter sets. |
236 if (!session_) | 246 if (!session_) |
237 ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes); | 247 ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes); |
238 | 248 |
249 // If there are no non-configuration units, immediately return an empty | |
250 // (ie. dropped) frame. It is an error to create a MemoryBlock with zero | |
251 // size. | |
252 if (!data_size) { | |
253 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( | |
254 &VTVideoDecodeAccelerator::OutputTask, | |
255 weak_this_factory_.GetWeakPtr(), | |
256 DecodedFrame(bitstream.id(), NULL))); | |
257 return; | |
258 } | |
259 | |
239 // 3. Allocate a memory-backed CMBlockBuffer for the translated data. | 260 // 3. Allocate a memory-backed CMBlockBuffer for the translated data. |
240 base::ScopedCFTypeRef<CMBlockBufferRef> data; | 261 base::ScopedCFTypeRef<CMBlockBufferRef> data; |
241 CHECK(!CMBlockBufferCreateWithMemoryBlock( | 262 CHECK(!CMBlockBufferCreateWithMemoryBlock( |
242 kCFAllocatorDefault, | 263 kCFAllocatorDefault, |
243 NULL, // &memory_block | 264 NULL, // &memory_block |
244 data_size, // block_length | 265 data_size, // block_length |
245 kCFAllocatorDefault, // block_allocator | 266 kCFAllocatorDefault, // block_allocator |
246 NULL, // &custom_block_source | 267 NULL, // &custom_block_source |
247 0, // offset_to_data | 268 0, // offset_to_data |
248 data_size, // data_length | 269 data_size, // data_length |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
304 CFRetain(image_buffer); | 325 CFRetain(image_buffer); |
305 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( | 326 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( |
306 &VTVideoDecodeAccelerator::OutputTask, | 327 &VTVideoDecodeAccelerator::OutputTask, |
307 weak_this_factory_.GetWeakPtr(), | 328 weak_this_factory_.GetWeakPtr(), |
308 DecodedFrame(bitstream_id, image_buffer))); | 329 DecodedFrame(bitstream_id, image_buffer))); |
309 } | 330 } |
310 | 331 |
311 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) { | 332 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) { |
312 DCHECK(CalledOnValidThread()); | 333 DCHECK(CalledOnValidThread()); |
313 decoded_frames_.push(frame); | 334 decoded_frames_.push(frame); |
314 SendPictures(); | 335 ProcessDecodedFrames(); |
315 } | 336 } |
316 | 337 |
317 void VTVideoDecodeAccelerator::SizeChangedTask(gfx::Size coded_size) { | 338 void VTVideoDecodeAccelerator::SizeChangedTask(gfx::Size coded_size) { |
318 DCHECK(CalledOnValidThread()); | 339 DCHECK(CalledOnValidThread()); |
319 texture_size_ = coded_size; | 340 texture_size_ = coded_size; |
320 // TODO(sandersd): Dismiss existing picture buffers. | 341 // TODO(sandersd): Dismiss existing picture buffers. |
321 client_->ProvidePictureBuffers( | 342 client_->ProvidePictureBuffers( |
322 kNumPictureBuffers, texture_size_, GL_TEXTURE_RECTANGLE_ARB); | 343 kNumPictureBuffers, texture_size_, GL_TEXTURE_RECTANGLE_ARB); |
323 } | 344 } |
324 | 345 |
325 void VTVideoDecodeAccelerator::AssignPictureBuffers( | 346 void VTVideoDecodeAccelerator::AssignPictureBuffers( |
326 const std::vector<media::PictureBuffer>& pictures) { | 347 const std::vector<media::PictureBuffer>& pictures) { |
327 DCHECK(CalledOnValidThread()); | 348 DCHECK(CalledOnValidThread()); |
328 | 349 |
329 for (size_t i = 0; i < pictures.size(); i++) { | 350 for (size_t i = 0; i < pictures.size(); i++) { |
330 CHECK(!texture_ids_.count(pictures[i].id())); | 351 CHECK(!texture_ids_.count(pictures[i].id())); |
331 available_picture_ids_.push(pictures[i].id()); | 352 available_picture_ids_.push(pictures[i].id()); |
332 texture_ids_[pictures[i].id()] = pictures[i].texture_id(); | 353 texture_ids_[pictures[i].id()] = pictures[i].texture_id(); |
333 } | 354 } |
334 | 355 |
335 // Pictures are not marked as uncleared until this method returns. They will | 356 // Pictures are not marked as uncleared until after this method returns, and |
336 // become broken if they are used before that happens. | 357 // they will be broken if they are used before that happens. So, schedule |
358 // future work after that happens. | |
337 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( | 359 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( |
338 &VTVideoDecodeAccelerator::SendPictures, | 360 &VTVideoDecodeAccelerator::ProcessDecodedFrames, |
339 weak_this_factory_.GetWeakPtr())); | 361 weak_this_factory_.GetWeakPtr())); |
340 } | 362 } |
341 | 363 |
342 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { | 364 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { |
343 DCHECK(CalledOnValidThread()); | 365 DCHECK(CalledOnValidThread()); |
344 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1); | 366 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1); |
345 picture_bindings_.erase(picture_id); | 367 picture_bindings_.erase(picture_id); |
346 available_picture_ids_.push(picture_id); | 368 available_picture_ids_.push(picture_id); |
347 SendPictures(); | 369 ProcessDecodedFrames(); |
348 } | 370 } |
349 | 371 |
350 // TODO(sandersd): Proper error reporting instead of CHECKs. | 372 void VTVideoDecodeAccelerator::CompleteAction(Action action) { |
351 void VTVideoDecodeAccelerator::SendPictures() { | |
352 DCHECK(CalledOnValidThread()); | 373 DCHECK(CalledOnValidThread()); |
353 if (available_picture_ids_.empty() || decoded_frames_.empty()) | 374 switch (action) { |
354 return; | 375 case ACTION_FLUSH: |
376 client_->NotifyFlushDone(); | |
377 break; | |
378 case ACTION_RESET: | |
379 client_->NotifyResetDone(); | |
380 break; | |
381 case ACTION_DESTROY: | |
382 delete this; | |
383 break; | |
384 } | |
385 } | |
386 | |
387 void VTVideoDecodeAccelerator::CompleteActions(int32_t bitstream_id) { | |
388 DCHECK(CalledOnValidThread()); | |
389 while (!pending_actions_.empty() && | |
390 pending_actions_.front().bitstream_id == bitstream_id) { | |
391 CompleteAction(pending_actions_.front().action); | |
392 pending_actions_.pop(); | |
393 } | |
394 } | |
395 | |
396 void VTVideoDecodeAccelerator::ProcessDecodedFrames() { | |
397 DCHECK(CalledOnValidThread()); | |
398 | |
399 while (!decoded_frames_.empty()) { | |
400 if (pending_actions_.empty()) { | |
401 // No pending actions; send frames normally. | |
402 SendPictures(pending_bitstream_ids_.back()); | |
403 return; | |
404 } | |
405 | |
406 int32_t next_action_bitstream_id = pending_actions_.front().bitstream_id; | |
407 int32_t last_sent_bitstream_id = -1; | |
408 switch (pending_actions_.front().action) { | |
409 case ACTION_FLUSH: | |
410 // Send frames normally, then complete any actions. | |
411 last_sent_bitstream_id = SendPictures(next_action_bitstream_id); | |
412 if (last_sent_bitstream_id == next_action_bitstream_id) { | |
413 CompleteActions(last_sent_bitstream_id); | |
414 // Loop again, as there may be work to do for a new pending action. | |
415 continue; | |
416 } | |
417 return; | |
418 | |
419 case ACTION_RESET: | |
420 // Drop decoded frames and then complete any actions. | |
421 while (!decoded_frames_.empty() && | |
422 last_sent_bitstream_id != next_action_bitstream_id) { | |
423 last_sent_bitstream_id = decoded_frames_.front().bitstream_id; | |
424 decoded_frames_.pop(); | |
425 DCHECK_EQ(pending_bitstream_ids_.front(), last_sent_bitstream_id); | |
426 pending_bitstream_ids_.pop(); | |
427 client_->NotifyEndOfBitstreamBuffer(last_sent_bitstream_id); | |
428 } | |
429 if (last_sent_bitstream_id == next_action_bitstream_id) { | |
430 CompleteActions(last_sent_bitstream_id); | |
431 // Loop again, as there may be work to do for a new pending action. | |
432 continue; | |
433 } | |
434 return; | |
435 | |
436 case ACTION_DESTROY: | |
437 // Drop decoded frames and then then destroy if done. | |
438 while (!decoded_frames_.empty()) { | |
439 last_sent_bitstream_id = decoded_frames_.front().bitstream_id; | |
440 decoded_frames_.pop(); | |
441 } | |
442 // Not a loop because there can only be one pending action, and | |
443 // CompleteAction() will delete |this|. | |
444 if (last_sent_bitstream_id == next_action_bitstream_id) | |
445 CompleteAction(ACTION_DESTROY); | |
446 return; | |
447 } | |
448 | |
449 NOTREACHED(); | |
450 } | |
451 } | |
452 | |
453 int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) { | |
454 DCHECK(CalledOnValidThread()); | |
455 DCHECK(!decoded_frames_.empty()); | |
456 | |
457 if (available_picture_ids_.empty()) | |
458 return -1; | |
355 | 459 |
356 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_); | 460 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_); |
357 glEnable(GL_TEXTURE_RECTANGLE_ARB); | 461 glEnable(GL_TEXTURE_RECTANGLE_ARB); |
358 | 462 |
359 while (!available_picture_ids_.empty() && !decoded_frames_.empty()) { | 463 int32_t last_sent_bitstream_id = -1; |
464 while (!available_picture_ids_.empty() && | |
465 !decoded_frames_.empty() && | |
466 last_sent_bitstream_id != up_to_bitstream_id) { | |
467 DecodedFrame frame = decoded_frames_.front(); | |
468 decoded_frames_.pop(); | |
469 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id); | |
470 pending_bitstream_ids_.pop(); | |
360 int32_t picture_id = available_picture_ids_.front(); | 471 int32_t picture_id = available_picture_ids_.front(); |
361 available_picture_ids_.pop(); | 472 available_picture_ids_.pop(); |
362 DecodedFrame frame = decoded_frames_.front(); | |
363 decoded_frames_.pop(); | |
364 IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame.image_buffer); | |
365 | 473 |
366 gfx::ScopedTextureBinder | 474 CVImageBufferRef image_buffer = frame.image_buffer.get(); |
367 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]); | 475 if (image_buffer) { |
368 CHECK(!CGLTexImageIOSurface2D( | 476 IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer); |
369 cgl_context_, // ctx | |
370 GL_TEXTURE_RECTANGLE_ARB, // target | |
371 GL_RGB, // internal_format | |
372 texture_size_.width(), // width | |
373 texture_size_.height(), // height | |
374 GL_YCBCR_422_APPLE, // format | |
375 GL_UNSIGNED_SHORT_8_8_APPLE, // type | |
376 surface, // io_surface | |
377 0)); // plane | |
378 | 477 |
379 picture_bindings_[picture_id] = frame.image_buffer; | 478 // TODO(sandersd): Find out why this sometimes fails due to no GL context. |
380 client_->PictureReady(media::Picture( | 479 gfx::ScopedTextureBinder |
381 picture_id, frame.bitstream_id, gfx::Rect(texture_size_))); | 480 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]); |
481 CHECK(!CGLTexImageIOSurface2D( | |
482 cgl_context_, // ctx | |
483 GL_TEXTURE_RECTANGLE_ARB, // target | |
484 GL_RGB, // internal_format | |
485 texture_size_.width(), // width | |
486 texture_size_.height(), // height | |
487 GL_YCBCR_422_APPLE, // format | |
488 GL_UNSIGNED_SHORT_8_8_APPLE, // type | |
489 surface, // io_surface | |
490 0)); // plane | |
491 | |
492 picture_bindings_[picture_id] = frame.image_buffer; | |
493 client_->PictureReady(media::Picture( | |
494 picture_id, frame.bitstream_id, gfx::Rect(texture_size_))); | |
495 } | |
496 | |
382 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); | 497 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); |
498 last_sent_bitstream_id = frame.bitstream_id; | |
383 } | 499 } |
384 | 500 |
385 glDisable(GL_TEXTURE_RECTANGLE_ARB); | 501 glDisable(GL_TEXTURE_RECTANGLE_ARB); |
502 return last_sent_bitstream_id; | |
503 } | |
504 | |
505 void VTVideoDecodeAccelerator::FlushTask() { | |
506 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); | |
507 CHECK(!VTDecompressionSessionFinishDelayedFrames(session_)); | |
508 } | |
509 | |
510 void VTVideoDecodeAccelerator::QueueAction(Action action) { | |
511 DCHECK(CalledOnValidThread()); | |
512 if (pending_bitstream_ids_.empty()) { | |
513 // If there are no pending frames, all actions complete immediately. | |
514 CompleteAction(action); | |
515 } else { | |
516 // Otherwise, queue the action and try to make progress. | |
517 pending_actions_.push(PendingAction(action, pending_bitstream_ids_.back())); | |
518 ProcessDecodedFrames(); | |
519 // If there are still pending actions, then a flush may be required. | |
Pawel Osciak
2014/09/26 04:25:08
I'm still not clear why a flush is required? If it
sandersd (OOO until July 31)
2014/09/26 04:56:41
We need to flush for all three, because there is n
| |
520 if (!pending_actions_.empty()) { | |
521 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( | |
522 &VTVideoDecodeAccelerator::FlushTask, base::Unretained(this))); | |
523 } | |
524 } | |
386 } | 525 } |
387 | 526 |
388 void VTVideoDecodeAccelerator::Flush() { | 527 void VTVideoDecodeAccelerator::Flush() { |
389 DCHECK(CalledOnValidThread()); | 528 DCHECK(CalledOnValidThread()); |
390 // TODO(sandersd): Trigger flush, sending frames. | 529 QueueAction(ACTION_FLUSH); |
391 } | 530 } |
392 | 531 |
393 void VTVideoDecodeAccelerator::Reset() { | 532 void VTVideoDecodeAccelerator::Reset() { |
394 DCHECK(CalledOnValidThread()); | 533 DCHECK(CalledOnValidThread()); |
395 // TODO(sandersd): Trigger flush, discarding frames. | 534 QueueAction(ACTION_RESET); |
396 } | 535 } |
397 | 536 |
398 void VTVideoDecodeAccelerator::Destroy() { | 537 void VTVideoDecodeAccelerator::Destroy() { |
399 DCHECK(CalledOnValidThread()); | 538 DCHECK(CalledOnValidThread()); |
400 // TODO(sandersd): Trigger flush, discarding frames, and wait for them. | 539 // Drop any other pending actions. |
401 delete this; | 540 while (!pending_actions_.empty()) |
541 pending_actions_.pop(); | |
542 // Return all bitstream buffers. | |
543 while (!pending_bitstream_ids_.empty()) { | |
544 client_->NotifyEndOfBitstreamBuffer(pending_bitstream_ids_.front()); | |
545 pending_bitstream_ids_.pop(); | |
546 } | |
547 QueueAction(ACTION_DESTROY); | |
402 } | 548 } |
403 | 549 |
404 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { | 550 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { |
405 return false; | 551 return false; |
406 } | 552 } |
407 | 553 |
408 } // namespace content | 554 } // namespace content |
OLD | NEW |