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 "vp9_decoder.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11
12 namespace media {
13
VP9Accelerator()14 VP9Decoder::VP9Accelerator::VP9Accelerator() {}
15
~VP9Accelerator()16 VP9Decoder::VP9Accelerator::~VP9Accelerator() {}
17
VP9Decoder(VP9Accelerator * accelerator)18 VP9Decoder::VP9Decoder(VP9Accelerator* accelerator)
19 : state_(kNeedStreamMetadata),
20 accelerator_(accelerator),
21 parser_(accelerator->IsFrameContextRequired()) {
22 ref_frames_.resize(kVp9NumRefFrames);
23 }
24
~VP9Decoder()25 VP9Decoder::~VP9Decoder() {}
26
SetStream(const uint8_t * ptr,size_t size)27 void VP9Decoder::SetStream(const uint8_t* ptr, size_t size) {
28 DCHECK(ptr);
29 DCHECK(size);
30
31 DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size;
32 parser_.SetStream(ptr, size);
33 }
34
Flush()35 bool VP9Decoder::Flush() {
36 DVLOG(2) << "Decoder flush";
37 Reset();
38 return true;
39 }
40
Reset()41 void VP9Decoder::Reset() {
42 curr_frame_hdr_ = nullptr;
43 for (auto& ref_frame : ref_frames_)
44 ref_frame = nullptr;
45
46 parser_.Reset();
47
48 if (state_ == kDecoding)
49 state_ = kAfterReset;
50 }
51
Decode()52 VP9Decoder::DecodeResult VP9Decoder::Decode() {
53 while (1) {
54 // Read a new frame header if one is not awaiting decoding already.
55 if (!curr_frame_hdr_) {
56 std::unique_ptr<Vp9FrameHeader> hdr(new Vp9FrameHeader());
57 Vp9Parser::Result res = parser_.ParseNextFrame(hdr.get());
58 switch (res) {
59 case Vp9Parser::kOk:
60 curr_frame_hdr_ = std::move(hdr);
61 break;
62
63 case Vp9Parser::kEOStream:
64 return kRanOutOfStreamData;
65
66 case Vp9Parser::kInvalidStream:
67 DVLOG(1) << "Error parsing stream";
68 SetError();
69 return kDecodeError;
70
71 case Vp9Parser::kAwaitingRefresh:
72 DVLOG(4) << "Awaiting context update";
73 return kNeedContextUpdate;
74 }
75 }
76
77 if (state_ != kDecoding) {
78 // Not kDecoding, so we need a resume point (a keyframe), as we are after
79 // reset or at the beginning of the stream. Drop anything that is not
80 // a keyframe in such case, and continue looking for a keyframe.
81 if (curr_frame_hdr_->IsKeyframe()) {
82 state_ = kDecoding;
83 } else {
84 curr_frame_hdr_.reset();
85 continue;
86 }
87 }
88
89 if (curr_frame_hdr_->show_existing_frame) {
90 // This frame header only instructs us to display one of the
91 // previously-decoded frames, but has no frame data otherwise. Display
92 // and continue decoding subsequent frames.
93 size_t frame_to_show = curr_frame_hdr_->frame_to_show_map_idx;
94 if (frame_to_show >= ref_frames_.size() || !ref_frames_[frame_to_show]) {
95 DVLOG(1) << "Request to show an invalid frame";
96 SetError();
97 return kDecodeError;
98 }
99
100 if (!accelerator_->OutputPicture(ref_frames_[frame_to_show])) {
101 SetError();
102 return kDecodeError;
103 }
104
105 curr_frame_hdr_.reset();
106 continue;
107 }
108
109 Size new_pic_size(curr_frame_hdr_->frame_width,
110 curr_frame_hdr_->frame_height);
111 DCHECK(!new_pic_size.IsEmpty());
112
113 if (new_pic_size != pic_size_) {
114 DVLOG(1) << "New resolution: " << new_pic_size.ToString();
115
116 if (!curr_frame_hdr_->IsKeyframe()) {
117 // TODO(posciak): This is doable, but requires a few modifications to
118 // VDA implementations to allow multiple picture buffer sets in flight.
119 DVLOG(1) << "Resolution change currently supported for keyframes only";
120 SetError();
121 return kDecodeError;
122 }
123
124 // TODO(posciak): This requires us to be on a keyframe (see above) and is
125 // required, because VDA clients expect all surfaces to be returned before
126 // they can cycle surface sets after receiving kAllocateNewSurfaces.
127 // This is only an implementation detail of VDAs and can be improved.
128 for (auto& ref_frame : ref_frames_)
129 ref_frame = nullptr;
130
131 pic_size_ = new_pic_size;
132 return kAllocateNewSurfaces;
133 }
134
135 scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture();
136 if (!pic)
137 return kRanOutOfSurfaces;
138
139 pic->frame_hdr.reset(curr_frame_hdr_.release());
140
141 if (!DecodeAndOutputPicture(pic)) {
142 SetError();
143 return kDecodeError;
144 }
145 }
146 }
147
RefreshReferenceFrames(const scoped_refptr<VP9Picture> & pic)148 void VP9Decoder::RefreshReferenceFrames(const scoped_refptr<VP9Picture>& pic) {
149 for (size_t i = 0; i < kVp9NumRefFrames; ++i) {
150 DCHECK(!pic->frame_hdr->IsKeyframe() || pic->frame_hdr->RefreshFlag(i));
151 if (pic->frame_hdr->RefreshFlag(i))
152 ref_frames_[i] = pic;
153 }
154 }
155
UpdateFrameContext(const scoped_refptr<VP9Picture> & pic,const base::Callback<void (const Vp9FrameContext &)> & context_refresh_cb)156 void VP9Decoder::UpdateFrameContext(
157 const scoped_refptr<VP9Picture>& pic,
158 const base::Callback<void(const Vp9FrameContext&)>& context_refresh_cb) {
159 DCHECK(!context_refresh_cb.is_null());
160 Vp9FrameContext frame_ctx;
161 memset(&frame_ctx, 0, sizeof(frame_ctx));
162
163 if (!accelerator_->GetFrameContext(pic, &frame_ctx)) {
164 SetError();
165 return;
166 }
167
168 context_refresh_cb.Run(frame_ctx);
169 }
170
DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic)171 bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic) {
172 DCHECK(!pic_size_.IsEmpty());
173 DCHECK(pic->frame_hdr);
174
175 base::Closure done_cb;
176 const auto& context_refresh_cb =
177 parser_.GetContextRefreshCb(pic->frame_hdr->frame_context_idx);
178 if (!context_refresh_cb.is_null())
179 done_cb = base::Bind(&VP9Decoder::UpdateFrameContext,
180 base::Unretained(this), pic, context_refresh_cb);
181
182 const Vp9Parser::Context& context = parser_.context();
183 if (!accelerator_->SubmitDecode(pic, context.segmentation(),
184 context.loop_filter(), ref_frames_, done_cb))
185 return false;
186
187 if (pic->frame_hdr->show_frame) {
188 if (!accelerator_->OutputPicture(pic))
189 return false;
190 }
191
192 RefreshReferenceFrames(pic);
193 return true;
194 }
195
SetError()196 void VP9Decoder::SetError() {
197 Reset();
198 state_ = kError;
199 }
200
GetPicSize() const201 Size VP9Decoder::GetPicSize() const {
202 return pic_size_;
203 }
204
GetRequiredNumOfPictures() const205 size_t VP9Decoder::GetRequiredNumOfPictures() const {
206 // kMaxVideoFrames to keep higher level media pipeline populated, +2 for the
207 // pictures being parsed and decoded currently.
208 // TODO(johnylin): see if we could get rid of kMaxVideoFrames.
209 const size_t kMaxVideoFrames = 4;
210 return kMaxVideoFrames + kVp9NumRefFrames + 2;
211 }
212
213 } // namespace media
214