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

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

Issue 742233002: Implement |pic_order_cnt| computation for VTVideoDecode accelerator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@vt_reorder
Patch Set: Rebase. Created 6 years 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') | content/content_common.gypi » ('j') | 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 <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
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
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
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
OLDNEW
« no previous file with comments | « content/common/gpu/media/vt_video_decode_accelerator.h ('k') | content/content_common.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698