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 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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |