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

Side by Side Diff: content/common/gpu/media/vt_video_decode_accelerator.cc

Issue 491163002: Implement flushing in VTVideoDecodeAccelerator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: New state machine. Created 6 years, 2 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
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
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
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 pending_bitstream_ids_.push(bitstream.id());
187 // of order.
188 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( 197 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
189 &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this), 198 &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this),
190 bitstream)); 199 bitstream));
191 } 200 }
192 201
193 // TODO(sandersd): Proper error reporting instead of CHECKs. 202 // TODO(sandersd): Proper error reporting instead of CHECKs.
194 void VTVideoDecodeAccelerator::DecodeTask( 203 void VTVideoDecodeAccelerator::DecodeTask(
195 const media::BitstreamBuffer bitstream) { 204 const media::BitstreamBuffer bitstream) {
196 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); 205 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
197 206
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 nalus.push_back(nalu); 238 nalus.push_back(nalu);
230 data_size += kNALUHeaderLength + nalu.size; 239 data_size += kNALUHeaderLength + nalu.size;
231 } 240 }
232 } 241 }
233 242
234 // 2. Initialize VideoToolbox. 243 // 2. Initialize VideoToolbox.
235 // TODO(sandersd): Reinitialize when there are new parameter sets. 244 // TODO(sandersd): Reinitialize when there are new parameter sets.
236 if (!session_) 245 if (!session_)
237 ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes); 246 ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes);
238 247
248 if (!data_size) {
Pawel Osciak 2014/09/25 01:27:29 Could you explain? If there is no data we want to
sandersd (OOO until July 31) 2014/09/25 19:18:52 Done. (And yes.)
249 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
250 &VTVideoDecodeAccelerator::OutputTask,
251 weak_this_factory_.GetWeakPtr(),
252 DecodedFrame(bitstream.id(), NULL)));
253 return;
254 }
255
239 // 3. Allocate a memory-backed CMBlockBuffer for the translated data. 256 // 3. Allocate a memory-backed CMBlockBuffer for the translated data.
240 base::ScopedCFTypeRef<CMBlockBufferRef> data; 257 base::ScopedCFTypeRef<CMBlockBufferRef> data;
241 CHECK(!CMBlockBufferCreateWithMemoryBlock( 258 CHECK(!CMBlockBufferCreateWithMemoryBlock(
242 kCFAllocatorDefault, 259 kCFAllocatorDefault,
243 NULL, // &memory_block 260 NULL, // &memory_block
244 data_size, // block_length 261 data_size, // block_length
245 kCFAllocatorDefault, // block_allocator 262 kCFAllocatorDefault, // block_allocator
246 NULL, // &custom_block_source 263 NULL, // &custom_block_source
247 0, // offset_to_data 264 0, // offset_to_data
248 data_size, // data_length 265 data_size, // data_length
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 CFRetain(image_buffer); 321 CFRetain(image_buffer);
305 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( 322 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
306 &VTVideoDecodeAccelerator::OutputTask, 323 &VTVideoDecodeAccelerator::OutputTask,
307 weak_this_factory_.GetWeakPtr(), 324 weak_this_factory_.GetWeakPtr(),
308 DecodedFrame(bitstream_id, image_buffer))); 325 DecodedFrame(bitstream_id, image_buffer)));
309 } 326 }
310 327
311 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) { 328 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) {
312 DCHECK(CalledOnValidThread()); 329 DCHECK(CalledOnValidThread());
313 decoded_frames_.push(frame); 330 decoded_frames_.push(frame);
314 SendPictures(); 331 ProcessDecodedFrames();
315 } 332 }
316 333
317 void VTVideoDecodeAccelerator::SizeChangedTask(gfx::Size coded_size) { 334 void VTVideoDecodeAccelerator::SizeChangedTask(gfx::Size coded_size) {
318 DCHECK(CalledOnValidThread()); 335 DCHECK(CalledOnValidThread());
319 texture_size_ = coded_size; 336 texture_size_ = coded_size;
320 // TODO(sandersd): Dismiss existing picture buffers. 337 // TODO(sandersd): Dismiss existing picture buffers.
321 client_->ProvidePictureBuffers( 338 client_->ProvidePictureBuffers(
322 kNumPictureBuffers, texture_size_, GL_TEXTURE_RECTANGLE_ARB); 339 kNumPictureBuffers, texture_size_, GL_TEXTURE_RECTANGLE_ARB);
323 } 340 }
324 341
325 void VTVideoDecodeAccelerator::AssignPictureBuffers( 342 void VTVideoDecodeAccelerator::AssignPictureBuffers(
326 const std::vector<media::PictureBuffer>& pictures) { 343 const std::vector<media::PictureBuffer>& pictures) {
327 DCHECK(CalledOnValidThread()); 344 DCHECK(CalledOnValidThread());
328 345
329 for (size_t i = 0; i < pictures.size(); i++) { 346 for (size_t i = 0; i < pictures.size(); i++) {
330 CHECK(!texture_ids_.count(pictures[i].id())); 347 CHECK(!texture_ids_.count(pictures[i].id()));
331 available_picture_ids_.push(pictures[i].id()); 348 available_picture_ids_.push(pictures[i].id());
332 texture_ids_[pictures[i].id()] = pictures[i].texture_id(); 349 texture_ids_[pictures[i].id()] = pictures[i].texture_id();
333 } 350 }
334 351
335 // Pictures are not marked as uncleared until this method returns. They will 352 // Pictures are not marked as uncleared until after this method returns, and
336 // become broken if they are used before that happens. 353 // they will be broken if they are used before that happens. So, schedule
354 // future work after that happens.
337 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( 355 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
338 &VTVideoDecodeAccelerator::SendPictures, 356 &VTVideoDecodeAccelerator::ProcessDecodedFrames,
339 weak_this_factory_.GetWeakPtr())); 357 weak_this_factory_.GetWeakPtr()));
340 } 358 }
341 359
342 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { 360 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
343 DCHECK(CalledOnValidThread()); 361 DCHECK(CalledOnValidThread());
344 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1); 362 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1);
345 picture_bindings_.erase(picture_id); 363 picture_bindings_.erase(picture_id);
346 available_picture_ids_.push(picture_id); 364 available_picture_ids_.push(picture_id);
347 SendPictures(); 365 ProcessDecodedFrames();
348 } 366 }
349 367
350 // TODO(sandersd): Proper error reporting instead of CHECKs. 368 void VTVideoDecodeAccelerator::CompleteAction(Action action) {
351 void VTVideoDecodeAccelerator::SendPictures() {
352 DCHECK(CalledOnValidThread()); 369 DCHECK(CalledOnValidThread());
353 if (available_picture_ids_.empty() || decoded_frames_.empty()) 370 switch (action) {
354 return; 371 case ACTION_FLUSH:
372 client_->NotifyFlushDone();
373 break;
374 case ACTION_RESET:
375 client_->NotifyResetDone();
376 break;
377 case ACTION_DESTROY:
378 delete this;
379 break;
380 }
381 }
355 382
383 void VTVideoDecodeAccelerator::CompleteActions(int32_t bitstream_id) {
384 DCHECK(CalledOnValidThread());
385 while (!pending_actions_.empty() &&
386 pending_actions_.front().bitstream_id == bitstream_id) {
Pawel Osciak 2014/09/25 01:27:29 Wouldn't you want to do <= instead of == here?
sandersd (OOO until July 31) 2014/09/25 19:18:53 No, CompleteActions() is called every time a pendi
Pawel Osciak 2014/09/26 04:25:07 Ah, lack of doc for the method confused me. And I
sandersd (OOO until July 31) 2014/09/26 04:56:41 Acknowledged.
387 CompleteAction(pending_actions_.front().action);
388 pending_actions_.pop();
389 }
390 }
391
392 void VTVideoDecodeAccelerator::ProcessDecodedFrames() {
393 DCHECK(CalledOnValidThread());
394
395 while (true) {
Pawel Osciak 2014/09/25 01:27:29 Maybe just while (!decoded_frames_.empty()) instea
sandersd (OOO until July 31) 2014/09/25 19:18:52 Done.
396 if (decoded_frames_.empty())
397 return;
398
399 if (pending_actions_.empty()) {
400 // No pending actions; send frames normally.
401 if (!available_picture_ids_.empty())
402 SendPictures(pending_bitstream_ids_.back());
403 return;
404 } else if (pending_actions_.front().action == ACTION_FLUSH) {
Pawel Osciak 2014/09/25 01:27:28 I think it could be more readable if you: if (pen
sandersd (OOO until July 31) 2014/09/25 19:18:52 I like this, thanks!
405 // Flushing; send frames normally, then complete any actions.
406 if (!available_picture_ids_.empty()) {
Pawel Osciak 2014/09/25 01:27:28 You make this check in SendPictures anyway. I'd re
sandersd (OOO until July 31) 2014/09/25 19:18:52 This check served a few purposes: - It avoids ne
407 int32_t last_sent_bitstream_id =
408 SendPictures(pending_actions_.front().bitstream_id);
409 CompleteActions(last_sent_bitstream_id);
410 // Loop again, as there may be work to do for a new pending action.
411 continue;
412 }
413 return;
Pawel Osciak 2014/09/25 01:27:29 I'd just remove continue and return and let the ex
sandersd (OOO until July 31) 2014/09/25 19:18:53 Acknowledged.
Pawel Osciak 2014/09/26 04:25:07 But not implemented?
sandersd (OOO until July 31) 2014/09/26 04:56:41 I thought the switch version made this clear enoug
Pawel Osciak 2014/09/26 05:20:30 My point is, continue is the default action. So yo
sandersd (OOO until July 31) 2014/09/26 06:56:02 Done.
414 } else if (pending_actions_.front().action == ACTION_RESET) {
415 // Reseting; drop a decoded frame and then complete any actions.
Pawel Osciak 2014/09/25 01:27:28 One frame? Not drop frames until the id for the ac
sandersd (OOO until July 31) 2014/09/25 19:18:53 It's the same, but I've switched it around.
416 int32_t bitstream_id = decoded_frames_.front().bitstream_id;
Pawel Osciak 2014/09/25 01:27:28 Why not do things until action's bitstream id? Thi
sandersd (OOO until July 31) 2014/09/25 19:18:53 Done.
417 decoded_frames_.pop();
418 DCHECK_EQ(pending_bitstream_ids_.front(), bitstream_id);
419 pending_bitstream_ids_.pop();
420 client_->NotifyEndOfBitstreamBuffer(bitstream_id);
421 CompleteActions(bitstream_id);
422 // Loop again, as there may be more frames to drop or work to do for a new
423 // pending action.
424 continue;
Pawel Osciak 2014/09/25 01:27:29 Not needed.
sandersd (OOO until July 31) 2014/09/25 19:18:52 Acknowledged.
Pawel Osciak 2014/09/26 04:25:07 But not removed?
sandersd (OOO until July 31) 2014/09/26 04:56:41 See above.
425 } else {
426 // Destroying; drop a decoded frame, then destroy if ready.
Pawel Osciak 2014/09/25 01:27:28 Why only one not up to action id? That would be si
sandersd (OOO until July 31) 2014/09/25 19:18:52 Done.
427 DCHECK_EQ(pending_actions_.front().action, ACTION_DESTROY);
428 int32_t bitstream_id = decoded_frames_.front().bitstream_id;
429 decoded_frames_.pop();
430 if (pending_actions_.front().bitstream_id == bitstream_id) {
431 CompleteAction(ACTION_DESTROY);
432 return;
433 }
434 // Loop again, as there may be more frames to drop.
435 continue;
436 }
437
438 NOTREACHED();
Pawel Osciak 2014/09/25 01:27:29 This would go to default: clause.
sandersd (OOO until July 31) 2014/09/25 19:18:52 Not quite, I want to be sure that every path at th
Pawel Osciak 2014/09/26 04:25:07 You can do that by removing continues and putting
sandersd (OOO until July 31) 2014/09/26 04:56:41 I don't believe that is the same. The compiler can
Pawel Osciak 2014/09/26 05:20:30 That's exactly the point I'm trying to make. Nobod
sandersd (OOO until July 31) 2014/09/26 06:56:02 Done.
439 }
440 }
441
442 int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) {
443 DCHECK(CalledOnValidThread());
444 DCHECK(!decoded_frames_.empty());
445 DCHECK(!available_picture_ids_.empty());
446
447 int32_t last_sent_bitstream_id = -1;
356 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_); 448 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_);
357 glEnable(GL_TEXTURE_RECTANGLE_ARB); 449 glEnable(GL_TEXTURE_RECTANGLE_ARB);
358 450
359 while (!available_picture_ids_.empty() && !decoded_frames_.empty()) { 451 while (!available_picture_ids_.empty() && !decoded_frames_.empty()) {
452 DecodedFrame frame = decoded_frames_.front();
453 decoded_frames_.pop();
454 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id);
455 pending_bitstream_ids_.pop();
360 int32_t picture_id = available_picture_ids_.front(); 456 int32_t picture_id = available_picture_ids_.front();
361 available_picture_ids_.pop(); 457 available_picture_ids_.pop();
362 DecodedFrame frame = decoded_frames_.front();
363 decoded_frames_.pop();
364 IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame.image_buffer);
365 458
366 gfx::ScopedTextureBinder 459 CVImageBufferRef image_buffer = frame.image_buffer.get();
367 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]); 460 if (image_buffer) {
Pawel Osciak 2014/09/25 01:27:28 What happens if there is no image_buffer? Don't we
sandersd (OOO until July 31) 2014/09/25 19:18:52 This happens in if !data_size, or if the decoder d
368 CHECK(!CGLTexImageIOSurface2D( 461 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 462
379 picture_bindings_[picture_id] = frame.image_buffer; 463 // TODO(sandersd): Find out why this somtimes fails due to no GL context.
Pawel Osciak 2014/09/25 01:27:28 s/somtimes/sometimes/ How do you know it failed?
sandersd (OOO until July 31) 2014/09/25 19:18:53 It fails when the CGLTexImageIOSurface2D() check f
Pawel Osciak 2014/09/26 04:25:07 Well, I'd really like to express my strong prefere
sandersd (OOO until July 31) 2014/09/26 04:56:41 Understood, replacing all the CHECKs is the next i
380 client_->PictureReady(media::Picture( 464 gfx::ScopedTextureBinder
381 picture_id, frame.bitstream_id, gfx::Rect(texture_size_))); 465 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]);
466 CHECK(!CGLTexImageIOSurface2D(
467 cgl_context_, // ctx
468 GL_TEXTURE_RECTANGLE_ARB, // target
469 GL_RGB, // internal_format
470 texture_size_.width(), // width
471 texture_size_.height(), // height
472 GL_YCBCR_422_APPLE, // format
473 GL_UNSIGNED_SHORT_8_8_APPLE, // type
474 surface, // io_surface
475 0)); // plane
476
477 picture_bindings_[picture_id] = frame.image_buffer;
478 client_->PictureReady(media::Picture(
479 picture_id, frame.bitstream_id, gfx::Rect(texture_size_)));
480 }
481
382 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); 482 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
483 last_sent_bitstream_id = frame.bitstream_id;
484 if (frame.bitstream_id == up_to_bitstream_id)
Pawel Osciak 2014/09/25 01:27:29 Make this a part of while() condition?
sandersd (OOO until July 31) 2014/09/25 19:18:53 Done.
485 break;
383 } 486 }
384 487
385 glDisable(GL_TEXTURE_RECTANGLE_ARB); 488 glDisable(GL_TEXTURE_RECTANGLE_ARB);
489 return last_sent_bitstream_id;
490 }
491
492 void VTVideoDecodeAccelerator::FlushTask() {
493 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
494 CHECK(!VTDecompressionSessionFinishDelayedFrames(session_));
495 }
496
497 void VTVideoDecodeAccelerator::QueueAction(Action action) {
498 DCHECK(CalledOnValidThread());
499 if (pending_bitstream_ids_.empty()) {
500 CompleteAction(action);
Pawel Osciak 2014/09/25 01:27:29 Could you just let ProcessDecodedFrames() to this
sandersd (OOO until July 31) 2014/09/25 19:18:52 ProcessDecodedFrames() doesn't currently handle an
501 } else {
502 pending_actions_.push(PendingAction(action, pending_bitstream_ids_.back()));
503 ProcessDecodedFrames();
504 if (!pending_actions_.empty() && !pending_bitstream_ids_.empty()) {
505 decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
506 &VTVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
Pawel Osciak 2014/09/25 01:27:28 This requires an explanation...
sandersd (OOO until July 31) 2014/09/25 19:18:53 I think the condition was just wrong, as there wil
507 }
508 }
386 } 509 }
387 510
388 void VTVideoDecodeAccelerator::Flush() { 511 void VTVideoDecodeAccelerator::Flush() {
389 DCHECK(CalledOnValidThread()); 512 DCHECK(CalledOnValidThread());
390 // TODO(sandersd): Trigger flush, sending frames. 513 QueueAction(ACTION_FLUSH);
391 } 514 }
392 515
393 void VTVideoDecodeAccelerator::Reset() { 516 void VTVideoDecodeAccelerator::Reset() {
394 DCHECK(CalledOnValidThread()); 517 DCHECK(CalledOnValidThread());
395 // TODO(sandersd): Trigger flush, discarding frames. 518 QueueAction(ACTION_RESET);
396 } 519 }
397 520
398 void VTVideoDecodeAccelerator::Destroy() { 521 void VTVideoDecodeAccelerator::Destroy() {
399 DCHECK(CalledOnValidThread()); 522 DCHECK(CalledOnValidThread());
Pawel Osciak 2014/09/25 01:27:29 If you stopped the decoder thread here, you wouldn
sandersd (OOO until July 31) 2014/09/25 19:18:52 This is indeed possible, as long as the FlushTask
Pawel Osciak 2014/09/26 04:25:07 I don't understand the part about FlushTask... Que
sandersd (OOO until July 31) 2014/09/26 04:56:41 Queued to the decoder thread message loop, before
Pawel Osciak 2014/09/26 05:20:30 If you decoder_thread_.Stop() from Destroy(), it w
sandersd (OOO until July 31) 2014/09/26 06:56:02 This makes sense, but I'd still rather hold off. I
Pawel Osciak 2014/09/26 15:30:49 The idea was to do away with ACTION_DESTROY. It wo
sandersd (OOO until July 31) 2014/09/26 17:28:51 Acknowledged.
400 // TODO(sandersd): Trigger flush, discarding frames, and wait for them. 523 // Drop any other pending actions.
401 delete this; 524 while (!pending_actions_.empty())
525 pending_actions_.pop();
526 // Return all bitstream buffers.
527 while (!pending_bitstream_ids_.empty()) {
528 client_->NotifyEndOfBitstreamBuffer(pending_bitstream_ids_.front());
Pawel Osciak 2014/09/25 01:27:29 You shouldn't have to do this on Destroy().
sandersd (OOO until July 31) 2014/09/25 19:18:53 It seems I do, GpuVideoDecoder DCHECKS that there
Pawel Osciak 2014/09/26 04:25:07 Acknowledged.
529 pending_bitstream_ids_.pop();
530 }
531 QueueAction(ACTION_DESTROY);
Pawel Osciak 2014/09/25 01:27:29 Do we actually need this? You dropped everything a
sandersd (OOO until July 31) 2014/09/25 19:18:52 We tell the client we are done with the buffers, b
Pawel Osciak 2014/09/26 04:25:07 How do you guarantee that during that client_ will
sandersd (OOO until July 31) 2014/09/26 04:56:41 During destroy, ProcessDecodedFrames() specificall
Pawel Osciak 2014/09/26 05:20:30 Could you tell me how this is achieved please?
sandersd (OOO until July 31) 2014/09/26 06:56:02 Because there is a queued ACTION_DESTROY, it alway
402 } 532 }
403 533
404 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { 534 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
405 return false; 535 return false;
406 } 536 }
407 537
408 } // namespace content 538 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698