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 | |
83 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( | 86 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( |
84 CGLContextObj cgl_context, | 87 CGLContextObj cgl_context, |
85 const base::Callback<bool(void)>& make_context_current) | 88 const base::Callback<bool(void)>& make_context_current) |
86 : cgl_context_(cgl_context), | 89 : cgl_context_(cgl_context), |
87 make_context_current_(make_context_current), | 90 make_context_current_(make_context_current), |
88 client_(NULL), | 91 client_(NULL), |
89 state_(STATE_DECODING), | 92 state_(STATE_DECODING), |
90 format_(NULL), | 93 format_(NULL), |
91 session_(NULL), | 94 session_(NULL), |
92 last_sps_id_(-1), | 95 last_sps_id_(-1), |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 break; | 314 break; |
312 | 315 |
313 case media::H264NALU::kSliceDataA: | 316 case media::H264NALU::kSliceDataA: |
314 case media::H264NALU::kSliceDataB: | 317 case media::H264NALU::kSliceDataB: |
315 case media::H264NALU::kSliceDataC: | 318 case media::H264NALU::kSliceDataC: |
316 DLOG(ERROR) << "Coded slide data partitions not implemented."; | 319 DLOG(ERROR) << "Coded slide data partitions not implemented."; |
317 NotifyError(PLATFORM_FAILURE); | 320 NotifyError(PLATFORM_FAILURE); |
318 return; | 321 return; |
319 | 322 |
320 case media::H264NALU::kNonIDRSlice: | 323 case media::H264NALU::kNonIDRSlice: |
321 // TODO(sandersd): Check that there has been an SPS or IDR slice since | 324 // TODO(sandersd): Check that there has been an IDR slice since the |
322 // the last reset. | 325 // last reset. |
323 case media::H264NALU::kIDRSlice: | 326 case media::H264NALU::kIDRSlice: |
324 { | 327 { |
325 // TODO(sandersd): Make sure this only happens once per frame. | 328 // TODO(sandersd): Make sure this only happens once per frame. |
326 DCHECK_EQ(frame->pic_order_cnt, 0); | 329 DCHECK_EQ(frame->pic_order_cnt, 0); |
327 | 330 |
328 media::H264SliceHeader slice_hdr; | 331 media::H264SliceHeader slice_hdr; |
329 result = parser_.ParseSliceHeader(nalu, &slice_hdr); | 332 result = parser_.ParseSliceHeader(nalu, &slice_hdr); |
330 if (result != media::H264Parser::kOk) { | 333 if (result != media::H264Parser::kOk) { |
331 DLOG(ERROR) << "Could not parse slice header"; | 334 DLOG(ERROR) << "Could not parse slice header"; |
332 NotifyError(UNREADABLE_INPUT); | 335 NotifyError(UNREADABLE_INPUT); |
333 return; | 336 return; |
334 } | 337 } |
335 | 338 |
336 // TODO(sandersd): Keep a cache of recent SPS/PPS units instead of | 339 // TODO(sandersd): Maintain a cache of configurations and reconfigure |
337 // only the most recent ones. | 340 // only when a slice references a new config. |
338 DCHECK_EQ(slice_hdr.pic_parameter_set_id, last_pps_id_); | 341 DCHECK_EQ(slice_hdr.pic_parameter_set_id, last_pps_id_); |
339 const media::H264PPS* pps = | 342 const media::H264PPS* pps = |
340 parser_.GetPPS(slice_hdr.pic_parameter_set_id); | 343 parser_.GetPPS(slice_hdr.pic_parameter_set_id); |
341 if (!pps) { | 344 if (!pps) { |
342 DLOG(ERROR) << "Mising PPS referenced by slice"; | 345 DLOG(ERROR) << "Mising PPS referenced by slice"; |
343 NotifyError(UNREADABLE_INPUT); | 346 NotifyError(UNREADABLE_INPUT); |
344 return; | 347 return; |
345 } | 348 } |
346 | 349 |
347 DCHECK_EQ(pps->seq_parameter_set_id, last_sps_id_); | 350 DCHECK_EQ(pps->seq_parameter_set_id, last_sps_id_); |
348 const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); | 351 const media::H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); |
349 if (!sps) { | 352 if (!sps) { |
350 DLOG(ERROR) << "Mising SPS referenced by PPS"; | 353 DLOG(ERROR) << "Mising SPS referenced by PPS"; |
351 NotifyError(UNREADABLE_INPUT); | 354 NotifyError(UNREADABLE_INPUT); |
352 return; | 355 return; |
353 } | 356 } |
354 | 357 |
355 // TODO(sandersd): Compute pic_order_cnt. | 358 if (!poc_.ComputePicOrderCnt(sps, slice_hdr, &frame->pic_order_cnt)) { |
356 DCHECK(!slice_hdr.field_pic_flag); | 359 NotifyError(UNREADABLE_INPUT); |
357 frame->pic_order_cnt = 0; | 360 return; |
| 361 } |
| 362 |
| 363 if (sps->vui_parameters_present_flag && |
| 364 sps->bitstream_restriction_flag) { |
| 365 frame->reorder_window = std::min(sps->max_num_reorder_frames, |
| 366 kMaxReorderQueueSize - 1); |
| 367 } |
358 } | 368 } |
359 default: | 369 default: |
360 nalus.push_back(nalu); | 370 nalus.push_back(nalu); |
361 data_size += kNALUHeaderLength + nalu.size; | 371 data_size += kNALUHeaderLength + nalu.size; |
362 break; | 372 break; |
363 } | 373 } |
364 } | 374 } |
365 | 375 |
366 // Initialize VideoToolbox. | 376 // Initialize VideoToolbox. |
367 // TODO(sandersd): Instead of assuming that the last SPS and PPS units are | 377 // 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(); | 621 pending_flush_tasks_.pop(); |
612 client_->NotifyFlushDone(); | 622 client_->NotifyFlushDone(); |
613 task_queue_.pop(); | 623 task_queue_.pop(); |
614 return true; | 624 return true; |
615 } | 625 } |
616 return false; | 626 return false; |
617 | 627 |
618 case TASK_RESET: | 628 case TASK_RESET: |
619 DCHECK_EQ(task.type, pending_flush_tasks_.front()); | 629 DCHECK_EQ(task.type, pending_flush_tasks_.front()); |
620 if (reorder_queue_.size() == 0) { | 630 if (reorder_queue_.size() == 0) { |
| 631 last_sps_id_ = -1; |
| 632 last_pps_id_ = -1; |
| 633 last_sps_.clear(); |
| 634 last_spsext_.clear(); |
| 635 last_pps_.clear(); |
| 636 poc_.Reset(); |
621 pending_flush_tasks_.pop(); | 637 pending_flush_tasks_.pop(); |
622 client_->NotifyResetDone(); | 638 client_->NotifyResetDone(); |
623 task_queue_.pop(); | 639 task_queue_.pop(); |
624 return true; | 640 return true; |
625 } | 641 } |
626 return false; | 642 return false; |
627 | 643 |
628 case TASK_DESTROY: | 644 case TASK_DESTROY: |
629 NOTREACHED() << "Can't destroy while in STATE_DECODING."; | 645 NOTREACHED() << "Can't destroy while in STATE_DECODING."; |
630 NotifyError(ILLEGAL_STATE); | 646 NotifyError(ILLEGAL_STATE); |
631 return false; | 647 return false; |
632 } | 648 } |
633 } | 649 } |
634 | 650 |
635 bool VTVideoDecodeAccelerator::ProcessReorderQueue() { | 651 bool VTVideoDecodeAccelerator::ProcessReorderQueue() { |
636 DCHECK(gpu_thread_checker_.CalledOnValidThread()); | 652 DCHECK(gpu_thread_checker_.CalledOnValidThread()); |
637 DCHECK_EQ(state_, STATE_DECODING); | 653 DCHECK_EQ(state_, STATE_DECODING); |
638 | 654 |
639 if (reorder_queue_.empty()) | 655 if (reorder_queue_.empty()) |
640 return false; | 656 return false; |
641 | 657 |
642 // If the next task is a flush (because there is a pending flush or becuase | 658 // 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 | 659 // the next frame is an IDR), then we don't need a full reorder buffer to send |
644 // the next frame. | 660 // the next frame. |
645 bool flushing = !task_queue_.empty() && | 661 bool flushing = !task_queue_.empty() && |
646 (task_queue_.front().type != TASK_FRAME || | 662 (task_queue_.front().type != TASK_FRAME || |
647 task_queue_.front().frame->pic_order_cnt == 0); | 663 task_queue_.front().frame->pic_order_cnt == 0); |
648 if (flushing || reorder_queue_.size() >= kMinReorderQueueSize) { | 664 |
| 665 size_t reorder_window = std::max(0, reorder_queue_.top()->reorder_window); |
| 666 if (flushing || reorder_queue_.size() > reorder_window) { |
649 if (ProcessFrame(*reorder_queue_.top())) { | 667 if (ProcessFrame(*reorder_queue_.top())) { |
650 reorder_queue_.pop(); | 668 reorder_queue_.pop(); |
651 return true; | 669 return true; |
652 } | 670 } |
653 } | 671 } |
654 | 672 |
655 return false; | 673 return false; |
656 } | 674 } |
657 | 675 |
658 bool VTVideoDecodeAccelerator::ProcessFrame(const Frame& frame) { | 676 bool VTVideoDecodeAccelerator::ProcessFrame(const Frame& frame) { |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
782 assigned_bitstream_ids_.clear(); | 800 assigned_bitstream_ids_.clear(); |
783 state_ = STATE_DESTROYING; | 801 state_ = STATE_DESTROYING; |
784 QueueFlush(TASK_DESTROY); | 802 QueueFlush(TASK_DESTROY); |
785 } | 803 } |
786 | 804 |
787 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { | 805 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { |
788 return false; | 806 return false; |
789 } | 807 } |
790 | 808 |
791 } // namespace content | 809 } // namespace content |
OLD | NEW |