| 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 <algorithm> |
| 6 |
| 5 #include <CoreVideo/CoreVideo.h> | 7 #include <CoreVideo/CoreVideo.h> |
| 6 #include <OpenGL/CGLIOSurface.h> | 8 #include <OpenGL/CGLIOSurface.h> |
| 7 #include <OpenGL/gl.h> | 9 #include <OpenGL/gl.h> |
| 8 | 10 |
| 9 #include "base/bind.h" | 11 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 11 #include "base/sys_byteorder.h" | 13 #include "base/sys_byteorder.h" |
| 12 #include "base/thread_task_runner_handle.h" | 14 #include "base/thread_task_runner_handle.h" |
| 13 #include "content/common/gpu/media/vt_video_decode_accelerator.h" | 15 #include "content/common/gpu/media/vt_video_decode_accelerator.h" |
| 14 #include "content/public/common/content_switches.h" | 16 #include "content/public/common/content_switches.h" |
| 15 #include "media/base/limits.h" | 17 #include "media/base/limits.h" |
| 16 #include "media/filters/h264_parser.h" | |
| 17 #include "ui/gl/scoped_binders.h" | 18 #include "ui/gl/scoped_binders.h" |
| 18 | 19 |
| 19 using content_common_gpu_media::kModuleVt; | 20 using content_common_gpu_media::kModuleVt; |
| 20 using content_common_gpu_media::InitializeStubs; | 21 using content_common_gpu_media::InitializeStubs; |
| 21 using content_common_gpu_media::IsVtInitialized; | 22 using content_common_gpu_media::IsVtInitialized; |
| 22 using content_common_gpu_media::StubPathMap; | 23 using content_common_gpu_media::StubPathMap; |
| 23 | 24 |
| 24 #define NOTIFY_STATUS(name, status) \ | 25 #define NOTIFY_STATUS(name, status) \ |
| 25 do { \ | 26 do { \ |
| 26 DLOG(ERROR) << name << " failed with status " << status; \ | 27 DLOG(ERROR) << name << " failed with status " << status; \ |
| 27 NotifyError(PLATFORM_FAILURE); \ | 28 NotifyError(PLATFORM_FAILURE); \ |
| 28 } while (0) | 29 } while (0) |
| 29 | 30 |
| 30 namespace content { | 31 namespace content { |
| 31 | 32 |
| 32 // Size to use for NALU length headers in AVC format (can be 1, 2, or 4). | 33 // Size to use for NALU length headers in AVC format (can be 1, 2, or 4). |
| 33 static const int kNALUHeaderLength = 4; | 34 static const int kNALUHeaderLength = 4; |
| 34 | 35 |
| 35 // We request 5 picture buffers from the client, each of which has a texture ID | 36 // We request 5 picture buffers from the client, each of which has a texture ID |
| 36 // that we can bind decoded frames to. We need enough to satisfy preroll, and | 37 // that we can bind decoded frames to. We need enough to satisfy preroll, and |
| 37 // enough to avoid unnecessary stalling, but no more than that. The resource | 38 // enough to avoid unnecessary stalling, but no more than that. The resource |
| 38 // requirements are low, as we don't need the textures to be backed by storage. | 39 // requirements are low, as we don't need the textures to be backed by storage. |
| 39 static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1; | 40 static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1; |
| 40 | 41 |
| 41 // TODO(sandersd): Use the configured reorder window instead. | 42 // Maximum number of frames to queue for reordering before we stop asking for |
| 42 static const int kMinReorderQueueSize = 4; | 43 // more. (NotifyEndOfBitstreamBuffer() is called when frames are moved into the |
| 44 // reorder queue.) |
| 43 static const int kMaxReorderQueueSize = 16; | 45 static const int kMaxReorderQueueSize = 16; |
| 44 | 46 |
| 45 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator. | 47 // Route decoded frame callbacks back into the VTVideoDecodeAccelerator. |
| 46 static void OutputThunk( | 48 static void OutputThunk( |
| 47 void* decompression_output_refcon, | 49 void* decompression_output_refcon, |
| 48 void* source_frame_refcon, | 50 void* source_frame_refcon, |
| 49 OSStatus status, | 51 OSStatus status, |
| 50 VTDecodeInfoFlags info_flags, | 52 VTDecodeInfoFlags info_flags, |
| 51 CVImageBufferRef image_buffer, | 53 CVImageBufferRef image_buffer, |
| 52 CMTime presentation_time_stamp, | 54 CMTime presentation_time_stamp, |
| 53 CMTime presentation_duration) { | 55 CMTime presentation_duration) { |
| 54 VTVideoDecodeAccelerator* vda = | 56 VTVideoDecodeAccelerator* vda = |
| 55 reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon); | 57 reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon); |
| 56 vda->Output(source_frame_refcon, status, image_buffer); | 58 vda->Output(source_frame_refcon, status, image_buffer); |
| 57 } | 59 } |
| 58 | 60 |
| 59 VTVideoDecodeAccelerator::Task::Task(TaskType type) : type(type) { | 61 VTVideoDecodeAccelerator::Task::Task(TaskType type) : type(type) { |
| 60 } | 62 } |
| 61 | 63 |
| 62 VTVideoDecodeAccelerator::Task::~Task() { | 64 VTVideoDecodeAccelerator::Task::~Task() { |
| 63 } | 65 } |
| 64 | 66 |
| 65 VTVideoDecodeAccelerator::Frame::Frame(int32_t bitstream_id) | 67 VTVideoDecodeAccelerator::Frame::Frame(int32_t bitstream_id) |
| 66 : bitstream_id(bitstream_id), pic_order_cnt(0) { | 68 : bitstream_id(bitstream_id), pic_order_cnt(0), reorder_window(0) { |
| 67 } | 69 } |
| 68 | 70 |
| 69 VTVideoDecodeAccelerator::Frame::~Frame() { | 71 VTVideoDecodeAccelerator::Frame::~Frame() { |
| 70 } | 72 } |
| 71 | 73 |
| 72 bool VTVideoDecodeAccelerator::FrameOrder::operator()( | 74 bool VTVideoDecodeAccelerator::FrameOrder::operator()( |
| 73 const linked_ptr<Frame>& lhs, | 75 const linked_ptr<Frame>& lhs, |
| 74 const linked_ptr<Frame>& rhs) const { | 76 const linked_ptr<Frame>& rhs) const { |
| 75 if (lhs->pic_order_cnt != rhs->pic_order_cnt) | 77 if (lhs->pic_order_cnt != rhs->pic_order_cnt) |
| 76 return lhs->pic_order_cnt > rhs->pic_order_cnt; | 78 return lhs->pic_order_cnt > rhs->pic_order_cnt; |
| 77 // If the pic_order is the same, fallback on using the bitstream order. | 79 // If |pic_order_cnt| is the same, fall back on using the bitstream order. |
| 78 // TODO(sandersd): Assign a sequence number in Decode(). | 80 // TODO(sandersd): Assign a sequence number in Decode() and use that instead. |
| 81 // TODO(sandersd): Using the sequence number, ensure that frames older than |
| 82 // |kMaxReorderQueueSize| are ordered first, regardless of |pic_order_cnt|. |
| 79 return lhs->bitstream_id > rhs->bitstream_id; | 83 return lhs->bitstream_id > rhs->bitstream_id; |
| 80 } | 84 } |
| 81 | 85 |
| 82 | 86 |
| 83 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( | 87 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( |
| 84 CGLContextObj cgl_context, | 88 CGLContextObj cgl_context, |
| 85 const base::Callback<bool(void)>& make_context_current) | 89 const base::Callback<bool(void)>& make_context_current) |
| 86 : cgl_context_(cgl_context), | 90 : cgl_context_(cgl_context), |
| 87 make_context_current_(make_context_current), | 91 make_context_current_(make_context_current), |
| 88 client_(NULL), | 92 client_(NULL), |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 break; | 315 break; |
| 312 | 316 |
| 313 case media::H264NALU::kSliceDataA: | 317 case media::H264NALU::kSliceDataA: |
| 314 case media::H264NALU::kSliceDataB: | 318 case media::H264NALU::kSliceDataB: |
| 315 case media::H264NALU::kSliceDataC: | 319 case media::H264NALU::kSliceDataC: |
| 316 DLOG(ERROR) << "Coded slide data partitions not implemented."; | 320 DLOG(ERROR) << "Coded slide data partitions not implemented."; |
| 317 NotifyError(PLATFORM_FAILURE); | 321 NotifyError(PLATFORM_FAILURE); |
| 318 return; | 322 return; |
| 319 | 323 |
| 320 case media::H264NALU::kNonIDRSlice: | 324 case media::H264NALU::kNonIDRSlice: |
| 321 // TODO(sandersd): Check that there has been an SPS or IDR slice since | 325 // TODO(sandersd): Check that there has been an IDR slice since the |
| 322 // the last reset. | 326 // last reset. |
| 323 case media::H264NALU::kIDRSlice: | 327 case media::H264NALU::kIDRSlice: |
| 324 { | 328 { |
| 325 // TODO(sandersd): Make sure this only happens once per frame. | 329 // TODO(sandersd): Make sure this only happens once per frame. |
| 326 DCHECK_EQ(frame->pic_order_cnt, 0); | 330 DCHECK_EQ(frame->pic_order_cnt, 0); |
| 327 | 331 |
| 328 media::H264SliceHeader slice_hdr; | 332 media::H264SliceHeader slice_hdr; |
| 329 result = parser_.ParseSliceHeader(nalu, &slice_hdr); | 333 result = parser_.ParseSliceHeader(nalu, &slice_hdr); |
| 330 if (result != media::H264Parser::kOk) { | 334 if (result != media::H264Parser::kOk) { |
| 331 DLOG(ERROR) << "Could not parse slice header"; | 335 DLOG(ERROR) << "Could not parse slice header"; |
| 332 NotifyError(UNREADABLE_INPUT); | 336 NotifyError(UNREADABLE_INPUT); |
| 333 return; | 337 return; |
| 334 } | 338 } |
| 335 | 339 |
| 336 // TODO(sandersd): Keep a cache of recent SPS/PPS units instead of | 340 // TODO(sandersd): Maintain a cache of configurations and reconfigure |
| 337 // only the most recent ones. | 341 // only when a slice references a new config. |
| 338 DCHECK_EQ(slice_hdr.pic_parameter_set_id, last_pps_id_); | 342 DCHECK_EQ(slice_hdr.pic_parameter_set_id, last_pps_id_); |
| 339 const media::H264PPS* pps = | 343 const media::H264PPS* pps = |
| 340 parser_.GetPPS(slice_hdr.pic_parameter_set_id); | 344 parser_.GetPPS(slice_hdr.pic_parameter_set_id); |
| 341 if (!pps) { | 345 if (!pps) { |
| 342 DLOG(ERROR) << "Mising PPS referenced by slice"; | 346 DLOG(ERROR) << "Mising PPS referenced by slice"; |
| 343 NotifyError(UNREADABLE_INPUT); | 347 NotifyError(UNREADABLE_INPUT); |
| 344 return; | 348 return; |
| 345 } | 349 } |
| 346 | 350 |
| 347 DCHECK_EQ(pps->seq_parameter_set_id, last_sps_id_); | 351 DCHECK_EQ(pps->seq_parameter_set_id, last_sps_id_); |
| 348 const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); | 352 const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); |
| 349 if (!sps) { | 353 if (!sps) { |
| 350 DLOG(ERROR) << "Mising SPS referenced by PPS"; | 354 DLOG(ERROR) << "Mising SPS referenced by PPS"; |
| 351 NotifyError(UNREADABLE_INPUT); | 355 NotifyError(UNREADABLE_INPUT); |
| 352 return; | 356 return; |
| 353 } | 357 } |
| 354 | 358 |
| 355 // TODO(sandersd): Compute pic_order_cnt. | 359 if (!poc_.ComputePicOrderCnt(sps, slice_hdr, &frame->pic_order_cnt)) { |
| 356 DCHECK(!slice_hdr.field_pic_flag); | 360 NotifyError(UNREADABLE_INPUT); |
| 357 frame->pic_order_cnt = 0; | 361 return; |
| 362 } |
| 363 |
| 364 if (sps->vui_parameters_present_flag && |
| 365 sps->bitstream_restriction_flag) { |
| 366 frame->reorder_window = std::min(sps->max_num_reorder_frames, |
| 367 kMaxReorderQueueSize - 1); |
| 368 } |
| 358 } | 369 } |
| 359 default: | 370 default: |
| 360 nalus.push_back(nalu); | 371 nalus.push_back(nalu); |
| 361 data_size += kNALUHeaderLength + nalu.size; | 372 data_size += kNALUHeaderLength + nalu.size; |
| 362 break; | 373 break; |
| 363 } | 374 } |
| 364 } | 375 } |
| 365 | 376 |
| 366 // Initialize VideoToolbox. | 377 // Initialize VideoToolbox. |
| 367 // TODO(sandersd): Instead of assuming that the last SPS and PPS units are | 378 // TODO(sandersd): Instead of assuming that the last SPS and PPS units are |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 pending_flush_tasks_.pop(); | 622 pending_flush_tasks_.pop(); |
| 612 client_->NotifyFlushDone(); | 623 client_->NotifyFlushDone(); |
| 613 task_queue_.pop(); | 624 task_queue_.pop(); |
| 614 return true; | 625 return true; |
| 615 } | 626 } |
| 616 return false; | 627 return false; |
| 617 | 628 |
| 618 case TASK_RESET: | 629 case TASK_RESET: |
| 619 DCHECK_EQ(task.type, pending_flush_tasks_.front()); | 630 DCHECK_EQ(task.type, pending_flush_tasks_.front()); |
| 620 if (reorder_queue_.size() == 0) { | 631 if (reorder_queue_.size() == 0) { |
| 632 last_sps_id_ = -1; |
| 633 last_pps_id_ = -1; |
| 634 last_sps_.clear(); |
| 635 last_spsext_.clear(); |
| 636 last_pps_.clear(); |
| 637 poc_.Reset(); |
| 621 pending_flush_tasks_.pop(); | 638 pending_flush_tasks_.pop(); |
| 622 client_->NotifyResetDone(); | 639 client_->NotifyResetDone(); |
| 623 task_queue_.pop(); | 640 task_queue_.pop(); |
| 624 return true; | 641 return true; |
| 625 } | 642 } |
| 626 return false; | 643 return false; |
| 627 | 644 |
| 628 case TASK_DESTROY: | 645 case TASK_DESTROY: |
| 629 NOTREACHED() << "Can't destroy while in STATE_DECODING."; | 646 NOTREACHED() << "Can't destroy while in STATE_DECODING."; |
| 630 NotifyError(ILLEGAL_STATE); | 647 NotifyError(ILLEGAL_STATE); |
| 631 return false; | 648 return false; |
| 632 } | 649 } |
| 633 } | 650 } |
| 634 | 651 |
| 635 bool VTVideoDecodeAccelerator::ProcessReorderQueue() { | 652 bool VTVideoDecodeAccelerator::ProcessReorderQueue() { |
| 636 DCHECK(gpu_thread_checker_.CalledOnValidThread()); | 653 DCHECK(gpu_thread_checker_.CalledOnValidThread()); |
| 637 DCHECK_EQ(state_, STATE_DECODING); | 654 DCHECK_EQ(state_, STATE_DECODING); |
| 638 | 655 |
| 639 if (reorder_queue_.empty()) | 656 if (reorder_queue_.empty()) |
| 640 return false; | 657 return false; |
| 641 | 658 |
| 642 // If the next task is a flush (because there is a pending flush or becuase | 659 // If the next task is a flush (because there is a pending flush or becuase |
| 643 // the next frame is an IDR), then we don't need a full reorder buffer to send | 660 // the next frame is an IDR), then we don't need a full reorder buffer to send |
| 644 // the next frame. | 661 // the next frame. |
| 645 bool flushing = !task_queue_.empty() && | 662 bool flushing = !task_queue_.empty() && |
| 646 (task_queue_.front().type != TASK_FRAME || | 663 (task_queue_.front().type != TASK_FRAME || |
| 647 task_queue_.front().frame->pic_order_cnt == 0); | 664 task_queue_.front().frame->pic_order_cnt == 0); |
| 648 if (flushing || reorder_queue_.size() >= kMinReorderQueueSize) { | 665 |
| 666 size_t reorder_window = std::max(0, reorder_queue_.top()->reorder_window); |
| 667 if (flushing || reorder_queue_.size() > reorder_window) { |
| 649 if (ProcessFrame(*reorder_queue_.top())) { | 668 if (ProcessFrame(*reorder_queue_.top())) { |
| 650 reorder_queue_.pop(); | 669 reorder_queue_.pop(); |
| 651 return true; | 670 return true; |
| 652 } | 671 } |
| 653 } | 672 } |
| 654 | 673 |
| 655 return false; | 674 return false; |
| 656 } | 675 } |
| 657 | 676 |
| 658 bool VTVideoDecodeAccelerator::ProcessFrame(const Frame& frame) { | 677 bool VTVideoDecodeAccelerator::ProcessFrame(const Frame& frame) { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 assigned_bitstream_ids_.clear(); | 792 assigned_bitstream_ids_.clear(); |
| 774 state_ = STATE_DESTROYING; | 793 state_ = STATE_DESTROYING; |
| 775 QueueFlush(TASK_DESTROY); | 794 QueueFlush(TASK_DESTROY); |
| 776 } | 795 } |
| 777 | 796 |
| 778 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { | 797 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { |
| 779 return false; | 798 return false; |
| 780 } | 799 } |
| 781 | 800 |
| 782 } // namespace content | 801 } // namespace content |
| OLD | NEW |