OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/logging.h" | |
6 #include "content/common/gpu/media/vp9_decoder.h" | |
7 #include "media/base/limits.h" | |
8 | |
9 namespace content { | |
10 | |
11 VP9Decoder::VP9Accelerator::VP9Accelerator() {} | |
12 | |
13 VP9Decoder::VP9Accelerator::~VP9Accelerator() {} | |
14 | |
15 VP9Decoder::VP9Decoder(VP9Accelerator* accelerator) | |
16 : state_(kNeedStreamMetadata), accelerator_(accelerator) { | |
17 DCHECK(accelerator_); | |
18 ref_frames_.resize(media::kVp9NumRefFrames); | |
19 } | |
20 | |
21 VP9Decoder::~VP9Decoder() {} | |
22 | |
23 void VP9Decoder::SetStream(const uint8_t* ptr, size_t size) { | |
24 DCHECK(ptr); | |
25 DCHECK(size); | |
26 | |
27 DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size; | |
28 parser_.SetStream(ptr, size); | |
29 } | |
30 | |
31 bool VP9Decoder::Flush() { | |
32 DVLOG(2) << "Decoder flush"; | |
33 Reset(); | |
34 return true; | |
35 } | |
36 | |
37 void VP9Decoder::Reset() { | |
38 curr_frame_hdr_ = nullptr; | |
39 for (auto& ref_frame : ref_frames_) | |
40 ref_frame = nullptr; | |
41 | |
42 parser_.Reset(); | |
43 | |
44 if (state_ == kDecoding) | |
45 state_ = kAfterReset; | |
46 } | |
47 | |
48 VP9Decoder::DecodeResult VP9Decoder::Decode() { | |
49 while (1) { | |
50 // Read a new frame header if one is not awaiting decoding already. | |
51 if (!curr_frame_hdr_) { | |
52 std::unique_ptr<media::Vp9FrameHeader> hdr(new media::Vp9FrameHeader()); | |
53 media::Vp9Parser::Result res = parser_.ParseNextFrame(hdr.get()); | |
54 switch (res) { | |
55 case media::Vp9Parser::kOk: | |
56 curr_frame_hdr_.reset(hdr.release()); | |
57 break; | |
58 | |
59 case media::Vp9Parser::kEOStream: | |
60 return kRanOutOfStreamData; | |
61 | |
62 case media::Vp9Parser::kInvalidStream: | |
63 DVLOG(1) << "Error parsing stream"; | |
64 SetError(); | |
65 return kDecodeError; | |
66 } | |
67 } | |
68 | |
69 if (state_ != kDecoding) { | |
70 // Not kDecoding, so we need a resume point (a keyframe), as we are after | |
71 // reset or at the beginning of the stream. Drop anything that is not | |
72 // a keyframe in such case, and continue looking for a keyframe. | |
73 if (curr_frame_hdr_->IsKeyframe()) { | |
74 state_ = kDecoding; | |
75 } else { | |
76 curr_frame_hdr_.reset(); | |
77 continue; | |
78 } | |
79 } | |
80 | |
81 if (curr_frame_hdr_->show_existing_frame) { | |
82 // This frame header only instructs us to display one of the | |
83 // previously-decoded frames, but has no frame data otherwise. Display | |
84 // and continue decoding subsequent frames. | |
85 size_t frame_to_show = curr_frame_hdr_->frame_to_show; | |
86 if (frame_to_show >= ref_frames_.size() || !ref_frames_[frame_to_show]) { | |
87 DVLOG(1) << "Request to show an invalid frame"; | |
88 SetError(); | |
89 return kDecodeError; | |
90 } | |
91 | |
92 if (!accelerator_->OutputPicture(ref_frames_[frame_to_show])) { | |
93 SetError(); | |
94 return kDecodeError; | |
95 } | |
96 | |
97 curr_frame_hdr_.reset(); | |
98 continue; | |
99 } | |
100 | |
101 gfx::Size new_pic_size(curr_frame_hdr_->width, curr_frame_hdr_->height); | |
102 DCHECK(!new_pic_size.IsEmpty()); | |
103 | |
104 if (new_pic_size != pic_size_) { | |
105 DVLOG(1) << "New resolution: " << new_pic_size.ToString(); | |
106 | |
107 if (!curr_frame_hdr_->IsKeyframe()) { | |
108 // TODO(posciak): This is doable, but requires a few modifications to | |
109 // VDA implementations to allow multiple picture buffer sets in flight. | |
110 DVLOG(1) << "Resolution change currently supported for keyframes only"; | |
111 SetError(); | |
112 return kDecodeError; | |
113 } | |
114 | |
115 // TODO(posciak): This requires us to be on a keyframe (see above) and is | |
116 // required, because VDA clients expect all surfaces to be returned before | |
117 // they can cycle surface sets after receiving kAllocateNewSurfaces. | |
118 // This is only an implementation detail of VDAs and can be improved. | |
119 for (auto& ref_frame : ref_frames_) | |
120 ref_frame = nullptr; | |
121 | |
122 pic_size_ = new_pic_size; | |
123 return kAllocateNewSurfaces; | |
124 } | |
125 | |
126 scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture(); | |
127 if (!pic) | |
128 return kRanOutOfSurfaces; | |
129 | |
130 pic->frame_hdr.reset(curr_frame_hdr_.release()); | |
131 | |
132 if (!DecodeAndOutputPicture(pic)) { | |
133 SetError(); | |
134 return kDecodeError; | |
135 } | |
136 } | |
137 } | |
138 | |
139 void VP9Decoder::RefreshReferenceFrames(const scoped_refptr<VP9Picture>& pic) { | |
140 for (size_t i = 0; i < media::kVp9NumRefFrames; ++i) { | |
141 DCHECK(!pic->frame_hdr->IsKeyframe() || pic->frame_hdr->RefreshFlag(i)); | |
142 if (pic->frame_hdr->RefreshFlag(i)) | |
143 ref_frames_[i] = pic; | |
144 } | |
145 } | |
146 | |
147 bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic) { | |
148 DCHECK(!pic_size_.IsEmpty()); | |
149 DCHECK(pic->frame_hdr); | |
150 | |
151 if (!accelerator_->SubmitDecode(pic, parser_.GetSegmentation(), | |
152 parser_.GetLoopFilter(), ref_frames_)) | |
153 return false; | |
154 | |
155 if (pic->frame_hdr->show_frame) { | |
156 if (!accelerator_->OutputPicture(pic)) | |
157 return false; | |
158 } | |
159 | |
160 RefreshReferenceFrames(pic); | |
161 return true; | |
162 } | |
163 | |
164 void VP9Decoder::SetError() { | |
165 Reset(); | |
166 state_ = kError; | |
167 } | |
168 | |
169 gfx::Size VP9Decoder::GetPicSize() const { | |
170 return pic_size_; | |
171 } | |
172 | |
173 size_t VP9Decoder::GetRequiredNumOfPictures() const { | |
174 // kMaxVideoFrames to keep higher level media pipeline populated, +2 for the | |
175 // pictures being parsed and decoded currently. | |
176 return media::limits::kMaxVideoFrames + media::kVp9NumRefFrames + 2; | |
177 } | |
178 | |
179 } // namespace content | |
OLD | NEW |