[go: nahoru, domu]

blob: a8d2f2ac2b604e7b722fd4f886f63f6599e7f9f8 [file] [log] [blame]
posciakd94b2b082015-09-18 04:03:401// 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
markdittmer6e70beb82016-05-02 05:40:475#include "media/gpu/vp9_decoder.h"
mostynb6682b1c42016-04-19 10:17:306
7#include <memory>
8
posciak77118c92016-08-28 13:18:399#include "base/bind.h"
mostynb6682b1c42016-04-19 10:17:3010#include "base/logging.h"
posciakd94b2b082015-09-18 04:03:4011#include "media/base/limits.h"
markdittmer6e70beb82016-05-02 05:40:4712#include "media/gpu/vp9_decoder.h"
posciakd94b2b082015-09-18 04:03:4013
markdittmer6e70beb82016-05-02 05:40:4714namespace media {
posciakd94b2b082015-09-18 04:03:4015
16VP9Decoder::VP9Accelerator::VP9Accelerator() {}
17
18VP9Decoder::VP9Accelerator::~VP9Accelerator() {}
19
Fredrik Hubinette3cebc622018-10-27 01:01:1220VP9Decoder::VP9Decoder(std::unique_ptr<VP9Accelerator> accelerator,
21 const VideoColorSpace& container_color_space)
posciak77118c92016-08-28 13:18:3922 : state_(kNeedStreamMetadata),
Fredrik Hubinette3cebc622018-10-27 01:01:1223 container_color_space_(container_color_space),
Miguel Casas2d5ecad82018-02-22 19:03:0524 accelerator_(std::move(accelerator)),
25 parser_(accelerator_->IsFrameContextRequired()) {
xhwang60f96672016-06-14 21:47:5326 ref_frames_.resize(kVp9NumRefFrames);
posciakd94b2b082015-09-18 04:03:4027}
28
Miguel Casas2d5ecad82018-02-22 19:03:0529VP9Decoder::~VP9Decoder() = default;
posciakd94b2b082015-09-18 04:03:4030
Miguel Casas22094b82018-05-22 21:16:4831void VP9Decoder::SetStream(int32_t id,
32 const uint8_t* ptr,
33 size_t size,
34 const DecryptConfig* decrypt_config) {
posciakd94b2b082015-09-18 04:03:4035 DCHECK(ptr);
36 DCHECK(size);
Pawel Osciakec6e21b2018-03-19 09:13:0637 DVLOG(4) << "New input stream id: " << id << " at: " << (void*)ptr
38 << " size: " << size;
39 stream_id_ = id;
Ted Meyer0b35c5fd2018-11-27 22:29:2940 if (decrypt_config) {
41 parser_.SetStream(ptr, size, decrypt_config->Clone());
42 } else {
43 parser_.SetStream(ptr, size, nullptr);
44 }
posciakd94b2b082015-09-18 04:03:4045}
46
47bool VP9Decoder::Flush() {
48 DVLOG(2) << "Decoder flush";
49 Reset();
50 return true;
51}
52
53void VP9Decoder::Reset() {
54 curr_frame_hdr_ = nullptr;
55 for (auto& ref_frame : ref_frames_)
56 ref_frame = nullptr;
57
58 parser_.Reset();
59
60 if (state_ == kDecoding)
61 state_ = kAfterReset;
62}
63
64VP9Decoder::DecodeResult VP9Decoder::Decode() {
65 while (1) {
66 // Read a new frame header if one is not awaiting decoding already.
Ted Meyer0b35c5fd2018-11-27 22:29:2967 std::unique_ptr<DecryptConfig> decrypt_config;
posciakd94b2b082015-09-18 04:03:4068 if (!curr_frame_hdr_) {
xhwang60f96672016-06-14 21:47:5369 std::unique_ptr<Vp9FrameHeader> hdr(new Vp9FrameHeader());
Ted Meyer0b35c5fd2018-11-27 22:29:2970 Vp9Parser::Result res =
71 parser_.ParseNextFrame(hdr.get(), &decrypt_config);
posciakd94b2b082015-09-18 04:03:4072 switch (res) {
xhwang60f96672016-06-14 21:47:5373 case Vp9Parser::kOk:
brusi_roy8e7155962016-09-14 18:22:5874 curr_frame_hdr_ = std::move(hdr);
posciakd94b2b082015-09-18 04:03:4075 break;
76
xhwang60f96672016-06-14 21:47:5377 case Vp9Parser::kEOStream:
posciakd94b2b082015-09-18 04:03:4078 return kRanOutOfStreamData;
79
xhwang60f96672016-06-14 21:47:5380 case Vp9Parser::kInvalidStream:
posciakd94b2b082015-09-18 04:03:4081 DVLOG(1) << "Error parsing stream";
82 SetError();
83 return kDecodeError;
kcwue5a9a6292016-08-17 03:40:0284
85 case Vp9Parser::kAwaitingRefresh:
posciak77118c92016-08-28 13:18:3986 DVLOG(4) << "Awaiting context update";
87 return kNeedContextUpdate;
posciakd94b2b082015-09-18 04:03:4088 }
89 }
90
91 if (state_ != kDecoding) {
92 // Not kDecoding, so we need a resume point (a keyframe), as we are after
93 // reset or at the beginning of the stream. Drop anything that is not
94 // a keyframe in such case, and continue looking for a keyframe.
Sreerenj Balachandran57163302018-11-28 02:45:5795 // Only exception is when the stream/sequence starts with an Intra only
96 // frame.
97 if (curr_frame_hdr_->IsKeyframe() ||
98 (curr_frame_hdr_->IsIntra() && pic_size_.IsEmpty())) {
posciakd94b2b082015-09-18 04:03:4099 state_ = kDecoding;
100 } else {
101 curr_frame_hdr_.reset();
102 continue;
103 }
104 }
105
106 if (curr_frame_hdr_->show_existing_frame) {
107 // This frame header only instructs us to display one of the
108 // previously-decoded frames, but has no frame data otherwise. Display
109 // and continue decoding subsequent frames.
kcwue5a9a6292016-08-17 03:40:02110 size_t frame_to_show = curr_frame_hdr_->frame_to_show_map_idx;
posciakd94b2b082015-09-18 04:03:40111 if (frame_to_show >= ref_frames_.size() || !ref_frames_[frame_to_show]) {
112 DVLOG(1) << "Request to show an invalid frame";
113 SetError();
114 return kDecodeError;
115 }
116
Chih-Yu Huangcd5181e2018-10-23 06:33:06117 // Duplicate the VP9Picture and set the current bitstream id to keep the
118 // correct timestamp.
119 scoped_refptr<VP9Picture> pic = ref_frames_[frame_to_show]->Duplicate();
120 if (pic == nullptr) {
121 DVLOG(1) << "Failed to duplicate the VP9Picture.";
122 SetError();
123 return kDecodeError;
124 }
125 pic->set_bitstream_id(stream_id_);
126 if (!accelerator_->OutputPicture(std::move(pic))) {
posciakd94b2b082015-09-18 04:03:40127 SetError();
128 return kDecodeError;
129 }
130
131 curr_frame_hdr_.reset();
132 continue;
133 }
134
kcwue5a9a6292016-08-17 03:40:02135 gfx::Size new_pic_size(curr_frame_hdr_->frame_width,
136 curr_frame_hdr_->frame_height);
posciakd94b2b082015-09-18 04:03:40137 DCHECK(!new_pic_size.IsEmpty());
138
139 if (new_pic_size != pic_size_) {
140 DVLOG(1) << "New resolution: " << new_pic_size.ToString();
141
Sreerenj Balachandran57163302018-11-28 02:45:57142 if (!curr_frame_hdr_->IsKeyframe() &&
143 (curr_frame_hdr_->IsIntra() && pic_size_.IsEmpty())) {
posciakd94b2b082015-09-18 04:03:40144 // TODO(posciak): This is doable, but requires a few modifications to
145 // VDA implementations to allow multiple picture buffer sets in flight.
Dongseong Hwang4f20ebb2018-06-07 00:28:20146 // http://crbug.com/832264
Sreerenj Balachandran57163302018-11-28 02:45:57147 DVLOG(1) << "Resolution change currently supported for keyframes and "
148 "sequence begins with Intra only when there is no prior "
149 "frames in the context";
Dongseong Hwang4f20ebb2018-06-07 00:28:20150 if (++size_change_failure_counter_ > kVPxMaxNumOfSizeChangeFailures) {
151 SetError();
152 return kDecodeError;
153 }
154
155 curr_frame_hdr_.reset();
156 return kRanOutOfStreamData;
posciakd94b2b082015-09-18 04:03:40157 }
158
159 // TODO(posciak): This requires us to be on a keyframe (see above) and is
160 // required, because VDA clients expect all surfaces to be returned before
161 // they can cycle surface sets after receiving kAllocateNewSurfaces.
162 // This is only an implementation detail of VDAs and can be improved.
163 for (auto& ref_frame : ref_frames_)
164 ref_frame = nullptr;
165
166 pic_size_ = new_pic_size;
Dongseong Hwang4f20ebb2018-06-07 00:28:20167 size_change_failure_counter_ = 0;
posciakd94b2b082015-09-18 04:03:40168 return kAllocateNewSurfaces;
169 }
170
171 scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture();
172 if (!pic)
173 return kRanOutOfSurfaces;
174
johnylin74410872017-06-19 13:05:30175 gfx::Rect new_render_rect(curr_frame_hdr_->render_width,
176 curr_frame_hdr_->render_height);
177 // For safety, check the validity of render size or leave it as (0, 0).
178 if (!gfx::Rect(pic_size_).Contains(new_render_rect)) {
179 DVLOG(1) << "Render size exceeds picture size. render size: "
180 << new_render_rect.ToString()
181 << ", picture size: " << pic_size_.ToString();
182 new_render_rect = gfx::Rect();
183 }
184 DVLOG(2) << "Render resolution: " << new_render_rect.ToString();
185
Pawel Osciakec6e21b2018-03-19 09:13:06186 pic->set_visible_rect(new_render_rect);
187 pic->set_bitstream_id(stream_id_);
Fredrik Hubinette3cebc622018-10-27 01:01:12188
Ted Meyer0b35c5fd2018-11-27 22:29:29189 pic->set_decrypt_config(std::move(decrypt_config));
190
Fredrik Hubinette3cebc622018-10-27 01:01:12191 // For VP9, container color spaces override video stream color spaces.
192 if (container_color_space_.IsSpecified()) {
193 pic->set_colorspace(container_color_space_);
194 } else if (curr_frame_hdr_) {
195 pic->set_colorspace(curr_frame_hdr_->GetColorSpace());
196 }
kokihoonfb941e92018-07-10 18:04:24197 pic->frame_hdr = std::move(curr_frame_hdr_);
posciakd94b2b082015-09-18 04:03:40198
199 if (!DecodeAndOutputPicture(pic)) {
200 SetError();
201 return kDecodeError;
202 }
203 }
204}
205
206void VP9Decoder::RefreshReferenceFrames(const scoped_refptr<VP9Picture>& pic) {
xhwang60f96672016-06-14 21:47:53207 for (size_t i = 0; i < kVp9NumRefFrames; ++i) {
vmpstracfa9222015-10-28 22:42:23208 DCHECK(!pic->frame_hdr->IsKeyframe() || pic->frame_hdr->RefreshFlag(i));
posciakd94b2b082015-09-18 04:03:40209 if (pic->frame_hdr->RefreshFlag(i))
210 ref_frames_[i] = pic;
211 }
212}
213
posciak77118c92016-08-28 13:18:39214void VP9Decoder::UpdateFrameContext(
215 const scoped_refptr<VP9Picture>& pic,
216 const base::Callback<void(const Vp9FrameContext&)>& context_refresh_cb) {
Dale Curtise25163812018-09-21 22:13:39217 DCHECK(context_refresh_cb);
posciak77118c92016-08-28 13:18:39218 Vp9FrameContext frame_ctx;
219 memset(&frame_ctx, 0, sizeof(frame_ctx));
220
221 if (!accelerator_->GetFrameContext(pic, &frame_ctx)) {
222 SetError();
223 return;
224 }
225
226 context_refresh_cb.Run(frame_ctx);
227}
228
posciakd94b2b082015-09-18 04:03:40229bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic) {
230 DCHECK(!pic_size_.IsEmpty());
231 DCHECK(pic->frame_hdr);
232
posciak77118c92016-08-28 13:18:39233 base::Closure done_cb;
234 const auto& context_refresh_cb =
235 parser_.GetContextRefreshCb(pic->frame_hdr->frame_context_idx);
Dale Curtise25163812018-09-21 22:13:39236 if (context_refresh_cb)
posciak77118c92016-08-28 13:18:39237 done_cb = base::Bind(&VP9Decoder::UpdateFrameContext,
238 base::Unretained(this), pic, context_refresh_cb);
239
240 const Vp9Parser::Context& context = parser_.context();
241 if (!accelerator_->SubmitDecode(pic, context.segmentation(),
242 context.loop_filter(), ref_frames_, done_cb))
posciakd94b2b082015-09-18 04:03:40243 return false;
244
245 if (pic->frame_hdr->show_frame) {
246 if (!accelerator_->OutputPicture(pic))
247 return false;
248 }
249
250 RefreshReferenceFrames(pic);
251 return true;
252}
253
254void VP9Decoder::SetError() {
255 Reset();
256 state_ = kError;
257}
258
259gfx::Size VP9Decoder::GetPicSize() const {
260 return pic_size_;
261}
262
263size_t VP9Decoder::GetRequiredNumOfPictures() const {
Miguel Casas477a7062019-01-04 19:13:45264 constexpr size_t kPicsInPipeline = limits::kMaxVideoFrames + 1;
265 return kPicsInPipeline + GetNumReferenceFrames();
266}
267
268size_t VP9Decoder::GetNumReferenceFrames() const {
269 // Maximum number of reference frames needed plus one for the one being
270 // currently egressed.
271 return kVp9NumRefFrames + 1;
posciakd94b2b082015-09-18 04:03:40272}
273
markdittmer6e70beb82016-05-02 05:40:47274} // namespace media