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

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

Issue 653663006: Support configuration changes in VTVideoDecodeAccelerator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@vt_make_context_current
Patch Set: Rebase Created 6 years, 1 month 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/callback_helpers.h" 10 #include "base/callback_helpers.h"
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 nalu_data_ptrs.size(), // parameter_set_count 139 nalu_data_ptrs.size(), // parameter_set_count
140 &nalu_data_ptrs.front(), // &parameter_set_pointers 140 &nalu_data_ptrs.front(), // &parameter_set_pointers
141 &nalu_data_sizes.front(), // &parameter_set_sizes 141 &nalu_data_sizes.front(), // &parameter_set_sizes
142 kNALUHeaderLength, // nal_unit_header_length 142 kNALUHeaderLength, // nal_unit_header_length
143 format_.InitializeInto()); 143 format_.InitializeInto());
144 if (status) { 144 if (status) {
145 NOTIFY_STATUS("CMVideoFormatDescriptionCreateFromH264ParameterSets()", 145 NOTIFY_STATUS("CMVideoFormatDescriptionCreateFromH264ParameterSets()",
146 status); 146 status);
147 return false; 147 return false;
148 } 148 }
149 CMVideoDimensions coded_dimensions = 149
150 CMVideoFormatDescriptionGetDimensions(format_); 150 // If the session is compatible, there's nothing to do.
151 if (session_ &&
152 VTDecompressionSessionCanAcceptFormatDescription(session_, format_)) {
153 return true;
154 }
151 155
152 // Prepare VideoToolbox configuration dictionaries. 156 // Prepare VideoToolbox configuration dictionaries.
153 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config( 157 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config(
154 CFDictionaryCreateMutable( 158 CFDictionaryCreateMutable(
155 kCFAllocatorDefault, 159 kCFAllocatorDefault,
156 1, // capacity 160 1, // capacity
157 &kCFTypeDictionaryKeyCallBacks, 161 &kCFTypeDictionaryKeyCallBacks,
158 &kCFTypeDictionaryValueCallBacks)); 162 &kCFTypeDictionaryValueCallBacks));
159 163
160 CFDictionarySetValue( 164 CFDictionarySetValue(
161 decoder_config, 165 decoder_config,
162 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder 166 // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
163 CFSTR("EnableHardwareAcceleratedVideoDecoder"), 167 CFSTR("EnableHardwareAcceleratedVideoDecoder"),
164 kCFBooleanTrue); 168 kCFBooleanTrue);
165 169
166 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config( 170 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
167 CFDictionaryCreateMutable( 171 CFDictionaryCreateMutable(
168 kCFAllocatorDefault, 172 kCFAllocatorDefault,
169 4, // capacity 173 4, // capacity
170 &kCFTypeDictionaryKeyCallBacks, 174 &kCFTypeDictionaryKeyCallBacks,
171 &kCFTypeDictionaryValueCallBacks)); 175 &kCFTypeDictionaryValueCallBacks));
172 176
177 CMVideoDimensions coded_dimensions =
178 CMVideoFormatDescriptionGetDimensions(format_);
173 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) 179 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
174 // TODO(sandersd): RGBA option for 4:4:4 video. 180 // TODO(sandersd): RGBA option for 4:4:4 video.
175 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8; 181 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
176 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); 182 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
177 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width)); 183 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
178 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height)); 184 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
179 #undef CFINT 185 #undef CFINT
180 CFDictionarySetValue( 186 CFDictionarySetValue(
181 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format); 187 image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
182 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); 188 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
183 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); 189 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
184 CFDictionarySetValue( 190 CFDictionarySetValue(
185 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); 191 image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
186 192
187 // TODO(sandersd): Check if the session is already compatible. 193 // TODO(sandersd): Does the old session need to be flushed first?
188 session_.reset(); 194 session_.reset();
189 status = VTDecompressionSessionCreate( 195 status = VTDecompressionSessionCreate(
190 kCFAllocatorDefault, 196 kCFAllocatorDefault,
191 format_, // video_format_description 197 format_, // video_format_description
192 decoder_config, // video_decoder_specification 198 decoder_config, // video_decoder_specification
193 image_config, // destination_image_buffer_attributes 199 image_config, // destination_image_buffer_attributes
194 &callback_, // output_callback 200 &callback_, // output_callback
195 session_.InitializeInto()); 201 session_.InitializeInto());
196 if (status) { 202 if (status) {
197 NOTIFY_STATUS("VTDecompressionSessionCreate()", status); 203 NOTIFY_STATUS("VTDecompressionSessionCreate()", status);
198 return false; 204 return false;
199 } 205 }
200 206
201 // If the size has changed, trigger a request for new picture buffers.
202 // TODO(sandersd): Move to SendPictures(), and use this just as a hint for an
203 // upcoming size change.
204 gfx::Size new_coded_size(coded_dimensions.width, coded_dimensions.height);
205 if (coded_size_ != new_coded_size) {
206 coded_size_ = new_coded_size;
207 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
208 &VTVideoDecodeAccelerator::SizeChangedTask,
209 weak_this_factory_.GetWeakPtr(),
210 coded_size_));;
211 }
212
213 return true; 207 return true;
214 } 208 }
215 209
216 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) { 210 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
217 DCHECK(CalledOnValidThread()); 211 DCHECK(CalledOnValidThread());
218 // Not actually a requirement of the VDA API, but we're lazy and use negative 212 // Not actually a requirement of the VDA API, but we're lazy and use negative
219 // values as flags internally. Revisit that if this actually happens. 213 // values as flags internally. Revisit that if this actually happens.
220 if (bitstream.id() < 0) { 214 if (bitstream.id() < 0) {
221 LOG(ERROR) << "Negative bitstream ID"; 215 LOG(ERROR) << "Negative bitstream ID";
222 NotifyError(INVALID_ARGUMENT); 216 NotifyError(INVALID_ARGUMENT);
(...skipping 26 matching lines...) Expand all
249 return; 243 return;
250 } 244 }
251 const uint8_t* buf = static_cast<uint8_t*>(memory.memory()); 245 const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
252 246
253 // NALUs are stored with Annex B format in the bitstream buffer (start codes), 247 // NALUs are stored with Annex B format in the bitstream buffer (start codes),
254 // but VideoToolbox expects AVCC/MPEG-4 format (length headers), so we must 248 // but VideoToolbox expects AVCC/MPEG-4 format (length headers), so we must
255 // rewrite the data. 249 // rewrite the data.
256 // 250 //
257 // 1. Locate relevant NALUs and compute the size of the translated data. 251 // 1. Locate relevant NALUs and compute the size of the translated data.
258 // Also record any parameter sets for VideoToolbox initialization. 252 // Also record any parameter sets for VideoToolbox initialization.
253 bool config_changed = false;
259 size_t data_size = 0; 254 size_t data_size = 0;
260 std::vector<media::H264NALU> nalus; 255 std::vector<media::H264NALU> nalus;
261 std::vector<const uint8_t*> config_nalu_data_ptrs;
262 std::vector<size_t> config_nalu_data_sizes;
263 parser_.SetStream(buf, size); 256 parser_.SetStream(buf, size);
264 media::H264NALU nalu; 257 media::H264NALU nalu;
265 while (true) { 258 while (true) {
266 media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu); 259 media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
267 if (result == media::H264Parser::kEOStream) 260 if (result == media::H264Parser::kEOStream)
268 break; 261 break;
269 if (result != media::H264Parser::kOk) { 262 if (result != media::H264Parser::kOk) {
270 LOG(ERROR) << "Failed to find H.264 NALU"; 263 LOG(ERROR) << "Failed to find H.264 NALU";
271 NotifyError(PLATFORM_FAILURE); 264 NotifyError(PLATFORM_FAILURE);
272 return; 265 return;
273 } 266 }
274 // TODO(sandersd): Check that these are only at the start. 267 // TODO(sandersd): Strict ordering rules.
275 if (nalu.nal_unit_type == media::H264NALU::kSPS || 268 switch (nalu.nal_unit_type) {
276 nalu.nal_unit_type == media::H264NALU::kPPS || 269 case media::H264NALU::kSPS:
277 nalu.nal_unit_type == media::H264NALU::kSPSExt) { 270 last_sps_.assign(nalu.data, nalu.data + nalu.size);
278 DVLOG(2) << "Parameter set " << nalu.nal_unit_type; 271 last_spsext_.clear();
279 config_nalu_data_ptrs.push_back(nalu.data); 272 config_changed = true;
280 config_nalu_data_sizes.push_back(nalu.size); 273 break;
281 } else { 274 case media::H264NALU::kSPSExt:
282 nalus.push_back(nalu); 275 // TODO(sandersd): Check that the previous NALU was an SPS.
283 data_size += kNALUHeaderLength + nalu.size; 276 last_spsext_.assign(nalu.data, nalu.data + nalu.size);
277 config_changed = true;
278 break;
279 case media::H264NALU::kPPS:
Pawel Osciak 2014/10/30 11:02:52 Does PPS actually change config? PPSes don't have
sandersd (OOO until July 31) 2014/10/30 22:54:40 If the PPS changes, then VT needs to be reconfigur
280 last_pps_.assign(nalu.data, nalu.data + nalu.size);
281 config_changed = true;
282 break;
283 default:
284 nalus.push_back(nalu);
285 data_size += kNALUHeaderLength + nalu.size;
286 break;
284 } 287 }
285 } 288 }
286 289
287 // 2. Initialize VideoToolbox. 290 // 2. Initialize VideoToolbox.
288 // TODO(sandersd): Reinitialize when there are new parameter sets. 291 // TODO(sandersd): Check if the new configuration is identical before
289 if (!session_) { 292 // reconfiguring.
290 // If configuring fails, ConfigureDecoder() already called NotifyError(). 293 if (config_changed && last_sps_.size() != 0 && last_pps_.size() != 0) {
Pawel Osciak 2014/10/30 11:02:52 Shouldn't we return an error if config_changed, bu
sandersd (OOO until July 31) 2014/10/30 22:54:40 Seems reasonable. Done.
291 if (!ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes)) 294 // TODO(sandersd): Check that the SPS and PPS IDs match.
295 std::vector<const uint8_t*> nalu_data_ptrs;
296 std::vector<size_t> nalu_data_sizes;
297 nalu_data_ptrs.push_back(&last_sps_.front());
298 nalu_data_sizes.push_back(last_sps_.size());
299 if (last_spsext_.size() != 0) {
300 nalu_data_ptrs.push_back(&last_spsext_.front());
301 nalu_data_sizes.push_back(last_spsext_.size());
302 }
303 nalu_data_ptrs.push_back(&last_pps_.front());
304 nalu_data_sizes.push_back(last_pps_.size());
305
306 // If ConfigureDecoder() fails, it already called NotifyError().
307 if (!ConfigureDecoder(nalu_data_ptrs, nalu_data_sizes))
292 return; 308 return;
293 } 309 }
294 310
295 // If there are no non-configuration units, immediately return an empty 311 // If there are no non-configuration units, immediately return an empty
296 // (ie. dropped) frame. It is an error to create a MemoryBlock with zero 312 // (ie. dropped) frame. It is an error to create a MemoryBlock with zero
297 // size. 313 // size.
298 if (!data_size) 314 if (!data_size)
299 return; 315 return;
300 316
317 // If the session is not configured, fail.
318 if (!session_) {
319 LOG(ERROR) << "Image slice without configuration data";
320 NotifyError(INVALID_ARGUMENT);
321 return;
322 }
323
301 // 3. Allocate a memory-backed CMBlockBuffer for the translated data. 324 // 3. Allocate a memory-backed CMBlockBuffer for the translated data.
325 // TODO(sandersd): Check that the slice's PPS matches the current PPS.
Pawel Osciak 2014/10/30 11:02:52 That doesn't have to be the case... You could refe
sandersd (OOO until July 31) 2014/10/30 22:54:40 VT requires that we pack both the SPS and PPS into
302 base::ScopedCFTypeRef<CMBlockBufferRef> data; 326 base::ScopedCFTypeRef<CMBlockBufferRef> data;
303 OSStatus status = CMBlockBufferCreateWithMemoryBlock( 327 OSStatus status = CMBlockBufferCreateWithMemoryBlock(
304 kCFAllocatorDefault, 328 kCFAllocatorDefault,
305 NULL, // &memory_block 329 NULL, // &memory_block
306 data_size, // block_length 330 data_size, // block_length
307 kCFAllocatorDefault, // block_allocator 331 kCFAllocatorDefault, // block_allocator
308 NULL, // &custom_block_source 332 NULL, // &custom_block_source
309 0, // offset_to_data 333 0, // offset_to_data
310 data_size, // data_length 334 data_size, // data_length
311 0, // flags 335 0, // flags
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 weak_this_factory_.GetWeakPtr(), 423 weak_this_factory_.GetWeakPtr(),
400 DecodedFrame(bitstream_id, image_buffer))); 424 DecodedFrame(bitstream_id, image_buffer)));
401 } 425 }
402 426
403 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) { 427 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) {
404 DCHECK(CalledOnValidThread()); 428 DCHECK(CalledOnValidThread());
405 decoded_frames_.push(frame); 429 decoded_frames_.push(frame);
406 ProcessDecodedFrames(); 430 ProcessDecodedFrames();
407 } 431 }
408 432
409 void VTVideoDecodeAccelerator::SizeChangedTask(gfx::Size coded_size) {
410 DCHECK(CalledOnValidThread());
411 texture_size_ = coded_size;
412 // TODO(sandersd): Dismiss existing picture buffers.
413 client_->ProvidePictureBuffers(
414 kNumPictureBuffers, texture_size_, GL_TEXTURE_RECTANGLE_ARB);
415 }
416
417 void VTVideoDecodeAccelerator::AssignPictureBuffers( 433 void VTVideoDecodeAccelerator::AssignPictureBuffers(
418 const std::vector<media::PictureBuffer>& pictures) { 434 const std::vector<media::PictureBuffer>& pictures) {
419 DCHECK(CalledOnValidThread()); 435 DCHECK(CalledOnValidThread());
420 436
421 for (size_t i = 0; i < pictures.size(); i++) { 437 for (size_t i = 0; i < pictures.size(); i++) {
422 DCHECK(!texture_ids_.count(pictures[i].id())); 438 DCHECK(!texture_ids_.count(pictures[i].id()));
423 available_picture_ids_.push(pictures[i].id()); 439 assigned_picture_ids_.insert(pictures[i].id());
440 available_picture_ids_.push_back(pictures[i].id());
424 texture_ids_[pictures[i].id()] = pictures[i].texture_id(); 441 texture_ids_[pictures[i].id()] = pictures[i].texture_id();
425 } 442 }
426 443
427 // Pictures are not marked as uncleared until after this method returns, and 444 // Pictures are not marked as uncleared until after this method returns, and
428 // they will be broken if they are used before that happens. So, schedule 445 // they will be broken if they are used before that happens. So, schedule
429 // future work after that happens. 446 // future work after that happens.
430 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( 447 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
431 &VTVideoDecodeAccelerator::ProcessDecodedFrames, 448 &VTVideoDecodeAccelerator::ProcessDecodedFrames,
432 weak_this_factory_.GetWeakPtr())); 449 weak_this_factory_.GetWeakPtr()));
433 } 450 }
434 451
435 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { 452 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
436 DCHECK(CalledOnValidThread()); 453 DCHECK(CalledOnValidThread());
437 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1); 454 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1);
438 picture_bindings_.erase(picture_id); 455 picture_bindings_.erase(picture_id);
439 available_picture_ids_.push(picture_id); 456 // Don't put the picture back in the available list if has been dismissed.
440 ProcessDecodedFrames(); 457 if (assigned_picture_ids_.count(picture_id) != 0) {
458 available_picture_ids_.push_back(picture_id);
459 ProcessDecodedFrames();
460 }
441 } 461 }
442 462
443 void VTVideoDecodeAccelerator::CompleteAction(Action action) { 463 void VTVideoDecodeAccelerator::CompleteAction(Action action) {
444 DCHECK(CalledOnValidThread()); 464 DCHECK(CalledOnValidThread());
465
445 switch (action) { 466 switch (action) {
446 case ACTION_FLUSH: 467 case ACTION_FLUSH:
447 client_->NotifyFlushDone(); 468 client_->NotifyFlushDone();
448 break; 469 break;
449 case ACTION_RESET: 470 case ACTION_RESET:
450 client_->NotifyResetDone(); 471 client_->NotifyResetDone();
451 break; 472 break;
452 case ACTION_DESTROY: 473 case ACTION_DESTROY:
453 delete this; 474 delete this;
454 break; 475 break;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 // until more frames are decoded. 540 // until more frames are decoded.
520 if (last_sent_bitstream_id != next_action_bitstream_id) 541 if (last_sent_bitstream_id != next_action_bitstream_id)
521 return; 542 return;
522 543
523 // Complete all actions pending for this |bitstream_id|, then loop to see 544 // Complete all actions pending for this |bitstream_id|, then loop to see
524 // if progress can be made on the next action. 545 // if progress can be made on the next action.
525 CompleteActions(next_action_bitstream_id); 546 CompleteActions(next_action_bitstream_id);
526 } 547 }
527 } 548 }
528 549
550 int32_t VTVideoDecodeAccelerator::ProcessDroppedFrames(
551 int32_t last_sent_bitstream_id,
552 int32_t up_to_bitstream_id) {
553 DCHECK(CalledOnValidThread());
554 while (!decoded_frames_.empty() &&
Pawel Osciak 2014/10/30 11:02:52 Please document, this is getting pretty convoluted
sandersd (OOO until July 31) 2014/10/30 22:54:40 Done.
555 last_sent_bitstream_id != up_to_bitstream_id &&
556 decoded_frames_.front().image_buffer.get() == NULL) {
557 const DecodedFrame& frame = decoded_frames_.front();
558 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id);
559 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
560 last_sent_bitstream_id = frame.bitstream_id;
561 decoded_frames_.pop();
562 pending_bitstream_ids_.pop();
563 }
564 return last_sent_bitstream_id;
565 }
566
567 // TODO(sandersd): If GpuVideoDecoder didn't specifically check the size, this
Pawel Osciak 2014/10/30 11:02:52 Could you explain this comment please?
sandersd (OOO until July 31) 2014/10/30 22:54:40 Done.
568 // would be unnecessary, as the size is not a property of the texture.
569 void VTVideoDecodeAccelerator::ProcessSizeChange() {
570 DCHECK(CalledOnValidThread());
571 DCHECK(!decoded_frames_.empty());
572
573 // Find the size of the next image.
574 const DecodedFrame& frame = decoded_frames_.front();
575 CVImageBufferRef image_buffer = frame.image_buffer.get();
576 size_t width = CVPixelBufferGetWidth(image_buffer);
577 size_t height = CVPixelBufferGetHeight(image_buffer);
578 gfx::Size image_size(width, height);
579
580 if (picture_size_ != image_size) {
581 // Dismiss all assigned picture buffers.
582 for (int32_t picture_id : assigned_picture_ids_)
583 client_->DismissPictureBuffer(picture_id);
584 assigned_picture_ids_.clear();
585 available_picture_ids_.clear();
586
587 // Request new pictures.
588 client_->ProvidePictureBuffers(
589 kNumPictureBuffers, image_size, GL_TEXTURE_RECTANGLE_ARB);
590 picture_size_ = image_size;
591 }
592 }
593
529 int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) { 594 int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) {
530 DCHECK(CalledOnValidThread()); 595 DCHECK(CalledOnValidThread());
531 DCHECK(!decoded_frames_.empty()); 596 DCHECK(!decoded_frames_.empty());
532 597
533 // TODO(sandersd): Store the actual last sent bitstream ID? 598 // TODO(sandersd): Store the actual last sent bitstream ID?
534 int32_t last_sent_bitstream_id = -1; 599 int32_t last_sent_bitstream_id = -1;
535 600
601 last_sent_bitstream_id =
602 ProcessDroppedFrames(last_sent_bitstream_id, up_to_bitstream_id);
603 if (last_sent_bitstream_id == up_to_bitstream_id || decoded_frames_.empty())
604 return last_sent_bitstream_id;
605
606 ProcessSizeChange();
536 if (available_picture_ids_.empty()) 607 if (available_picture_ids_.empty())
537 return last_sent_bitstream_id; 608 return last_sent_bitstream_id;
538 609
539 if (!make_context_current_.Run()) { 610 if (!make_context_current_.Run()) {
540 LOG(ERROR) << "Failed to make GL context current"; 611 LOG(ERROR) << "Failed to make GL context current";
541 NotifyError(PLATFORM_FAILURE); 612 NotifyError(PLATFORM_FAILURE);
542 return last_sent_bitstream_id; 613 return last_sent_bitstream_id;
543 } 614 }
544 615
545 glEnable(GL_TEXTURE_RECTANGLE_ARB); 616 glEnable(GL_TEXTURE_RECTANGLE_ARB);
546 while (!available_picture_ids_.empty() && 617 while (!available_picture_ids_.empty() && !has_error_) {
547 !decoded_frames_.empty() && 618 DCHECK_NE(last_sent_bitstream_id, up_to_bitstream_id);
548 last_sent_bitstream_id != up_to_bitstream_id && 619 DCHECK(!decoded_frames_.empty());
549 !has_error_) { 620
550 // We don't pop |frame| until it is consumed, which won't happen if an 621 // We don't pop |frame| or |picture_id| until they are consumed, which may
551 // error occurs. Conveniently, this also removes some refcounting. 622 // not happen if an error occurs. Conveniently, this also removes some
623 // refcounting.
552 const DecodedFrame& frame = decoded_frames_.front(); 624 const DecodedFrame& frame = decoded_frames_.front();
553 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id); 625 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id);
554 626 int32_t picture_id = available_picture_ids_.back();
555 // Likewise, |picture_id| won't be popped if |image_buffer| is NULL or an
556 // error occurs.
557 // TODO(sandersd): Don't block waiting for a |picture_id| when
558 // |image_buffer| is NULL.
559 int32_t picture_id = available_picture_ids_.front();
560 627
561 CVImageBufferRef image_buffer = frame.image_buffer.get(); 628 CVImageBufferRef image_buffer = frame.image_buffer.get();
562 if (image_buffer) { 629 IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer);
563 IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer);
564 630
565 gfx::ScopedTextureBinder 631 gfx::ScopedTextureBinder
566 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]); 632 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]);
567 CGLError status = CGLTexImageIOSurface2D( 633 CGLError status = CGLTexImageIOSurface2D(
568 cgl_context_, // ctx 634 cgl_context_, // ctx
569 GL_TEXTURE_RECTANGLE_ARB, // target 635 GL_TEXTURE_RECTANGLE_ARB, // target
570 GL_RGB, // internal_format 636 GL_RGB, // internal_format
571 texture_size_.width(), // width 637 picture_size_.width(), // width
572 texture_size_.height(), // height 638 picture_size_.height(), // height
573 GL_YCBCR_422_APPLE, // format 639 GL_YCBCR_422_APPLE, // format
574 GL_UNSIGNED_SHORT_8_8_APPLE, // type 640 GL_UNSIGNED_SHORT_8_8_APPLE, // type
575 surface, // io_surface 641 surface, // io_surface
576 0); // plane 642 0); // plane
577 if (status != kCGLNoError) { 643 if (status != kCGLNoError) {
578 NOTIFY_STATUS("CGLTexImageIOSurface2D()", status); 644 NOTIFY_STATUS("CGLTexImageIOSurface2D()", status);
579 break; 645 break;
580 }
581
582 picture_bindings_[picture_id] = frame.image_buffer;
583 client_->PictureReady(media::Picture(
584 picture_id, frame.bitstream_id, gfx::Rect(texture_size_)));
585 available_picture_ids_.pop();
586 } 646 }
587 647
648 picture_bindings_[picture_id] = frame.image_buffer;
649 client_->PictureReady(media::Picture(
650 picture_id, frame.bitstream_id, gfx::Rect(picture_size_)));
651 available_picture_ids_.pop_back();
588 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); 652 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
589 last_sent_bitstream_id = frame.bitstream_id; 653 last_sent_bitstream_id = frame.bitstream_id;
590 decoded_frames_.pop(); 654 decoded_frames_.pop();
591 pending_bitstream_ids_.pop(); 655 pending_bitstream_ids_.pop();
656
657 last_sent_bitstream_id =
658 ProcessDroppedFrames(last_sent_bitstream_id, up_to_bitstream_id);
659 if (last_sent_bitstream_id == up_to_bitstream_id || decoded_frames_.empty())
660 break;
661
662 ProcessSizeChange();
592 } 663 }
593 glDisable(GL_TEXTURE_RECTANGLE_ARB); 664 glDisable(GL_TEXTURE_RECTANGLE_ARB);
594 665
595 return last_sent_bitstream_id; 666 return last_sent_bitstream_id;
596 } 667 }
597 668
598 void VTVideoDecodeAccelerator::FlushTask() { 669 void VTVideoDecodeAccelerator::FlushTask() {
599 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); 670 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
600 OSStatus status = VTDecompressionSessionFinishDelayedFrames(session_); 671 OSStatus status = VTDecompressionSessionFinishDelayedFrames(session_);
601 if (status) 672 if (status)
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 pending_bitstream_ids_.pop(); 732 pending_bitstream_ids_.pop();
662 } 733 }
663 QueueAction(ACTION_DESTROY); 734 QueueAction(ACTION_DESTROY);
664 } 735 }
665 736
666 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { 737 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
667 return false; 738 return false;
668 } 739 }
669 740
670 } // namespace content 741 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698