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

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: Rename ProcessSizeChange. 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
« no previous file with comments | « content/common/gpu/media/vt_video_decode_accelerator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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:
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) {
291 if (!ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes)) 294 if (last_sps_.size() == 0 || last_pps_.size() == 0) {
295 LOG(ERROR) << "Invalid configuration data";
296 NotifyError(INVALID_ARGUMENT);
297 return;
298 }
299 // TODO(sandersd): Check that the SPS and PPS IDs match.
300 std::vector<const uint8_t*> nalu_data_ptrs;
301 std::vector<size_t> nalu_data_sizes;
302 nalu_data_ptrs.push_back(&last_sps_.front());
303 nalu_data_sizes.push_back(last_sps_.size());
304 if (last_spsext_.size() != 0) {
305 nalu_data_ptrs.push_back(&last_spsext_.front());
306 nalu_data_sizes.push_back(last_spsext_.size());
307 }
308 nalu_data_ptrs.push_back(&last_pps_.front());
309 nalu_data_sizes.push_back(last_pps_.size());
310
311 // If ConfigureDecoder() fails, it already called NotifyError().
312 if (!ConfigureDecoder(nalu_data_ptrs, nalu_data_sizes))
292 return; 313 return;
293 } 314 }
294 315
295 // If there are no non-configuration units, immediately return an empty 316 // 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 317 // (ie. dropped) frame. It is an error to create a MemoryBlock with zero
297 // size. 318 // size.
298 if (!data_size) 319 if (!data_size)
299 return; 320 return;
300 321
322 // If the session is not configured, fail.
323 if (!session_) {
324 LOG(ERROR) << "Image slice without configuration data";
325 NotifyError(INVALID_ARGUMENT);
326 return;
327 }
328
301 // 3. Allocate a memory-backed CMBlockBuffer for the translated data. 329 // 3. Allocate a memory-backed CMBlockBuffer for the translated data.
330 // TODO(sandersd): Check that the slice's PPS matches the current PPS.
302 base::ScopedCFTypeRef<CMBlockBufferRef> data; 331 base::ScopedCFTypeRef<CMBlockBufferRef> data;
303 OSStatus status = CMBlockBufferCreateWithMemoryBlock( 332 OSStatus status = CMBlockBufferCreateWithMemoryBlock(
304 kCFAllocatorDefault, 333 kCFAllocatorDefault,
305 NULL, // &memory_block 334 NULL, // &memory_block
306 data_size, // block_length 335 data_size, // block_length
307 kCFAllocatorDefault, // block_allocator 336 kCFAllocatorDefault, // block_allocator
308 NULL, // &custom_block_source 337 NULL, // &custom_block_source
309 0, // offset_to_data 338 0, // offset_to_data
310 data_size, // data_length 339 data_size, // data_length
311 0, // flags 340 0, // flags
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 weak_this_factory_.GetWeakPtr(), 428 weak_this_factory_.GetWeakPtr(),
400 DecodedFrame(bitstream_id, image_buffer))); 429 DecodedFrame(bitstream_id, image_buffer)));
401 } 430 }
402 431
403 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) { 432 void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) {
404 DCHECK(CalledOnValidThread()); 433 DCHECK(CalledOnValidThread());
405 decoded_frames_.push(frame); 434 decoded_frames_.push(frame);
406 ProcessDecodedFrames(); 435 ProcessDecodedFrames();
407 } 436 }
408 437
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( 438 void VTVideoDecodeAccelerator::AssignPictureBuffers(
418 const std::vector<media::PictureBuffer>& pictures) { 439 const std::vector<media::PictureBuffer>& pictures) {
419 DCHECK(CalledOnValidThread()); 440 DCHECK(CalledOnValidThread());
420 441
421 for (size_t i = 0; i < pictures.size(); i++) { 442 for (size_t i = 0; i < pictures.size(); i++) {
422 DCHECK(!texture_ids_.count(pictures[i].id())); 443 DCHECK(!texture_ids_.count(pictures[i].id()));
423 available_picture_ids_.push(pictures[i].id()); 444 assigned_picture_ids_.insert(pictures[i].id());
445 available_picture_ids_.push_back(pictures[i].id());
424 texture_ids_[pictures[i].id()] = pictures[i].texture_id(); 446 texture_ids_[pictures[i].id()] = pictures[i].texture_id();
425 } 447 }
426 448
427 // Pictures are not marked as uncleared until after this method returns, and 449 // 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 450 // they will be broken if they are used before that happens. So, schedule
429 // future work after that happens. 451 // future work after that happens.
430 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( 452 gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
431 &VTVideoDecodeAccelerator::ProcessDecodedFrames, 453 &VTVideoDecodeAccelerator::ProcessDecodedFrames,
432 weak_this_factory_.GetWeakPtr())); 454 weak_this_factory_.GetWeakPtr()));
433 } 455 }
434 456
435 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) { 457 void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
436 DCHECK(CalledOnValidThread()); 458 DCHECK(CalledOnValidThread());
437 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1); 459 DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1);
438 picture_bindings_.erase(picture_id); 460 picture_bindings_.erase(picture_id);
439 available_picture_ids_.push(picture_id); 461 // Don't put the picture back in the available list if has been dismissed.
440 ProcessDecodedFrames(); 462 if (assigned_picture_ids_.count(picture_id) != 0) {
463 available_picture_ids_.push_back(picture_id);
464 ProcessDecodedFrames();
465 }
441 } 466 }
442 467
443 void VTVideoDecodeAccelerator::CompleteAction(Action action) { 468 void VTVideoDecodeAccelerator::CompleteAction(Action action) {
444 DCHECK(CalledOnValidThread()); 469 DCHECK(CalledOnValidThread());
470
445 switch (action) { 471 switch (action) {
446 case ACTION_FLUSH: 472 case ACTION_FLUSH:
447 client_->NotifyFlushDone(); 473 client_->NotifyFlushDone();
448 break; 474 break;
449 case ACTION_RESET: 475 case ACTION_RESET:
450 client_->NotifyResetDone(); 476 client_->NotifyResetDone();
451 break; 477 break;
452 case ACTION_DESTROY: 478 case ACTION_DESTROY:
453 delete this; 479 delete this;
454 break; 480 break;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 // until more frames are decoded. 545 // until more frames are decoded.
520 if (last_sent_bitstream_id != next_action_bitstream_id) 546 if (last_sent_bitstream_id != next_action_bitstream_id)
521 return; 547 return;
522 548
523 // Complete all actions pending for this |bitstream_id|, then loop to see 549 // Complete all actions pending for this |bitstream_id|, then loop to see
524 // if progress can be made on the next action. 550 // if progress can be made on the next action.
525 CompleteActions(next_action_bitstream_id); 551 CompleteActions(next_action_bitstream_id);
526 } 552 }
527 } 553 }
528 554
555 int32_t VTVideoDecodeAccelerator::ProcessDroppedFrames(
556 int32_t last_sent_bitstream_id,
557 int32_t up_to_bitstream_id) {
558 DCHECK(CalledOnValidThread());
559 // Drop frames as long as there is a frame, we have not reached the next
560 // action, and the next frame has no image.
561 while (!decoded_frames_.empty() &&
562 last_sent_bitstream_id != up_to_bitstream_id &&
563 decoded_frames_.front().image_buffer.get() == NULL) {
564 const DecodedFrame& frame = decoded_frames_.front();
565 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id);
566 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
567 last_sent_bitstream_id = frame.bitstream_id;
568 decoded_frames_.pop();
569 pending_bitstream_ids_.pop();
570 }
571 return last_sent_bitstream_id;
572 }
573
574 // TODO(sandersd): If GpuVideoDecoder didn't specifically check the size of
575 // textures, this would be unnecessary, as the size is actually a property of
576 // the texture binding, not the texture. We rebind every frame, so the size
577 // passed to ProvidePictureBuffers() is meaningless.
578 void VTVideoDecodeAccelerator::ProcessSizeChangeIfNeeded() {
579 DCHECK(CalledOnValidThread());
580 DCHECK(!decoded_frames_.empty());
581
582 // Find the size of the next image.
583 const DecodedFrame& frame = decoded_frames_.front();
584 CVImageBufferRef image_buffer = frame.image_buffer.get();
585 size_t width = CVPixelBufferGetWidth(image_buffer);
586 size_t height = CVPixelBufferGetHeight(image_buffer);
587 gfx::Size image_size(width, height);
588
589 if (picture_size_ != image_size) {
590 // Dismiss all assigned picture buffers.
591 for (int32_t picture_id : assigned_picture_ids_)
592 client_->DismissPictureBuffer(picture_id);
593 assigned_picture_ids_.clear();
594 available_picture_ids_.clear();
595
596 // Request new pictures.
597 client_->ProvidePictureBuffers(
598 kNumPictureBuffers, image_size, GL_TEXTURE_RECTANGLE_ARB);
599 picture_size_ = image_size;
600 }
601 }
602
529 int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) { 603 int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) {
530 DCHECK(CalledOnValidThread()); 604 DCHECK(CalledOnValidThread());
531 DCHECK(!decoded_frames_.empty()); 605 DCHECK(!decoded_frames_.empty());
532 606
533 // TODO(sandersd): Store the actual last sent bitstream ID? 607 // TODO(sandersd): Store the actual last sent bitstream ID?
534 int32_t last_sent_bitstream_id = -1; 608 int32_t last_sent_bitstream_id = -1;
535 609
610 last_sent_bitstream_id =
611 ProcessDroppedFrames(last_sent_bitstream_id, up_to_bitstream_id);
612 if (last_sent_bitstream_id == up_to_bitstream_id || decoded_frames_.empty())
613 return last_sent_bitstream_id;
614
615 ProcessSizeChangeIfNeeded();
536 if (available_picture_ids_.empty()) 616 if (available_picture_ids_.empty())
537 return last_sent_bitstream_id; 617 return last_sent_bitstream_id;
538 618
539 if (!make_context_current_.Run()) { 619 if (!make_context_current_.Run()) {
540 LOG(ERROR) << "Failed to make GL context current"; 620 LOG(ERROR) << "Failed to make GL context current";
541 NotifyError(PLATFORM_FAILURE); 621 NotifyError(PLATFORM_FAILURE);
542 return last_sent_bitstream_id; 622 return last_sent_bitstream_id;
543 } 623 }
544 624
545 glEnable(GL_TEXTURE_RECTANGLE_ARB); 625 glEnable(GL_TEXTURE_RECTANGLE_ARB);
546 while (!available_picture_ids_.empty() && 626 while (!available_picture_ids_.empty() && !has_error_) {
547 !decoded_frames_.empty() && 627 DCHECK_NE(last_sent_bitstream_id, up_to_bitstream_id);
548 last_sent_bitstream_id != up_to_bitstream_id && 628 DCHECK(!decoded_frames_.empty());
549 !has_error_) { 629
550 // We don't pop |frame| until it is consumed, which won't happen if an 630 // We don't pop |frame| or |picture_id| until they are consumed, which may
551 // error occurs. Conveniently, this also removes some refcounting. 631 // not happen if an error occurs. Conveniently, this also removes some
632 // refcounting.
552 const DecodedFrame& frame = decoded_frames_.front(); 633 const DecodedFrame& frame = decoded_frames_.front();
553 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id); 634 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id);
554 635 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 636
561 CVImageBufferRef image_buffer = frame.image_buffer.get(); 637 CVImageBufferRef image_buffer = frame.image_buffer.get();
562 if (image_buffer) { 638 IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer);
563 IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer);
564 639
565 gfx::ScopedTextureBinder 640 gfx::ScopedTextureBinder
566 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]); 641 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]);
567 CGLError status = CGLTexImageIOSurface2D( 642 CGLError status = CGLTexImageIOSurface2D(
568 cgl_context_, // ctx 643 cgl_context_, // ctx
569 GL_TEXTURE_RECTANGLE_ARB, // target 644 GL_TEXTURE_RECTANGLE_ARB, // target
570 GL_RGB, // internal_format 645 GL_RGB, // internal_format
571 texture_size_.width(), // width 646 picture_size_.width(), // width
572 texture_size_.height(), // height 647 picture_size_.height(), // height
573 GL_YCBCR_422_APPLE, // format 648 GL_YCBCR_422_APPLE, // format
574 GL_UNSIGNED_SHORT_8_8_APPLE, // type 649 GL_UNSIGNED_SHORT_8_8_APPLE, // type
575 surface, // io_surface 650 surface, // io_surface
576 0); // plane 651 0); // plane
577 if (status != kCGLNoError) { 652 if (status != kCGLNoError) {
578 NOTIFY_STATUS("CGLTexImageIOSurface2D()", status); 653 NOTIFY_STATUS("CGLTexImageIOSurface2D()", status);
579 break; 654 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 } 655 }
587 656
657 picture_bindings_[picture_id] = frame.image_buffer;
658 client_->PictureReady(media::Picture(
659 picture_id, frame.bitstream_id, gfx::Rect(picture_size_)));
660 available_picture_ids_.pop_back();
588 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); 661 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
589 last_sent_bitstream_id = frame.bitstream_id; 662 last_sent_bitstream_id = frame.bitstream_id;
590 decoded_frames_.pop(); 663 decoded_frames_.pop();
591 pending_bitstream_ids_.pop(); 664 pending_bitstream_ids_.pop();
665
666 last_sent_bitstream_id =
667 ProcessDroppedFrames(last_sent_bitstream_id, up_to_bitstream_id);
668 if (last_sent_bitstream_id == up_to_bitstream_id || decoded_frames_.empty())
669 break;
670
671 ProcessSizeChangeIfNeeded();
592 } 672 }
593 glDisable(GL_TEXTURE_RECTANGLE_ARB); 673 glDisable(GL_TEXTURE_RECTANGLE_ARB);
594 674
595 return last_sent_bitstream_id; 675 return last_sent_bitstream_id;
596 } 676 }
597 677
598 void VTVideoDecodeAccelerator::FlushTask() { 678 void VTVideoDecodeAccelerator::FlushTask() {
599 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); 679 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
600 OSStatus status = VTDecompressionSessionFinishDelayedFrames(session_); 680 OSStatus status = VTDecompressionSessionFinishDelayedFrames(session_);
601 if (status) 681 if (status)
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 pending_bitstream_ids_.pop(); 741 pending_bitstream_ids_.pop();
662 } 742 }
663 QueueAction(ACTION_DESTROY); 743 QueueAction(ACTION_DESTROY);
664 } 744 }
665 745
666 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { 746 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
667 return false; 747 return false;
668 } 748 }
669 749
670 } // namespace content 750 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/vt_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698