[go: nahoru, domu]

blob: ce7021f72d98046c163f30b782c77f6170c10783 [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"
Hirokazu Honda10df95d2019-07-19 19:31:4310#include "base/feature_list.h"
mostynb6682b1c42016-04-19 10:17:3011#include "base/logging.h"
Hirokazu Honda967b9192019-08-27 00:59:4212#include "build/build_config.h"
posciakd94b2b082015-09-18 04:03:4013#include "media/base/limits.h"
Hirokazu Honda10df95d2019-07-19 19:31:4314#include "media/base/media_switches.h"
markdittmer6e70beb82016-05-02 05:40:4715#include "media/gpu/vp9_decoder.h"
posciakd94b2b082015-09-18 04:03:4016
markdittmer6e70beb82016-05-02 05:40:4717namespace media {
posciakd94b2b082015-09-18 04:03:4018
Hirokazu Honda10df95d2019-07-19 19:31:4319namespace {
20std::vector<uint32_t> GetSpatialLayerFrameSize(
21 const DecoderBuffer& decoder_buffer) {
Hirokazu Honda967b9192019-08-27 00:59:4222#if defined(ARCH_CPU_X86_FAMILY) && defined(OS_CHROMEOS)
Hirokazu Honda10df95d2019-07-19 19:31:4323 const uint32_t* cue_data =
24 reinterpret_cast<const uint32_t*>(decoder_buffer.side_data());
25 if (!cue_data)
26 return {};
27 if (!base::FeatureList::IsEnabled(media::kVp9kSVCHWDecoding)) {
28 DLOG(ERROR) << "Vp9Parser doesn't support parsing SVC stream";
29 return {};
30 }
31
32 size_t num_of_layers = decoder_buffer.side_data_size() / sizeof(uint32_t);
33 if (num_of_layers > 3u) {
34 DLOG(WARNING) << "The maximum number of spatial layers in VP9 is three";
35 return {};
36 }
37 return std::vector<uint32_t>(cue_data, cue_data + num_of_layers);
Hirokazu Honda967b9192019-08-27 00:59:4238#endif // defined(ARCH_CPU_X86_FAMILY) && defined(OS_CHROMEOS)
39 return {};
Hirokazu Honda10df95d2019-07-19 19:31:4340}
Hirokazu Honda7ec32652019-11-22 09:40:2141
42VideoCodecProfile VP9ProfileToVideoCodecProfile(uint8_t profile) {
43 switch (profile) {
44 case 0:
45 return VP9PROFILE_PROFILE0;
46 case 1:
47 return VP9PROFILE_PROFILE1;
48 case 2:
49 return VP9PROFILE_PROFILE2;
50 case 3:
51 return VP9PROFILE_PROFILE3;
52 default:
53 return VIDEO_CODEC_PROFILE_UNKNOWN;
54 }
55}
56
Hirokazu Honda10df95d2019-07-19 19:31:4357} // namespace
58
posciakd94b2b082015-09-18 04:03:4059VP9Decoder::VP9Accelerator::VP9Accelerator() {}
60
61VP9Decoder::VP9Accelerator::~VP9Accelerator() {}
62
Fredrik Hubinette3cebc622018-10-27 01:01:1263VP9Decoder::VP9Decoder(std::unique_ptr<VP9Accelerator> accelerator,
Hirokazu Honda7ec32652019-11-22 09:40:2164 VideoCodecProfile profile,
Fredrik Hubinette3cebc622018-10-27 01:01:1265 const VideoColorSpace& container_color_space)
posciak77118c92016-08-28 13:18:3966 : state_(kNeedStreamMetadata),
Fredrik Hubinette3cebc622018-10-27 01:01:1267 container_color_space_(container_color_space),
Hirokazu Honda7ec32652019-11-22 09:40:2168 // TODO(hiroh): Set profile to UNKNOWN.
69 profile_(profile),
Miguel Casas2d5ecad82018-02-22 19:03:0570 accelerator_(std::move(accelerator)),
Hirokazu Honda7ec32652019-11-22 09:40:2171 parser_(accelerator_->IsFrameContextRequired()) {}
posciakd94b2b082015-09-18 04:03:4072
Miguel Casas2d5ecad82018-02-22 19:03:0573VP9Decoder::~VP9Decoder() = default;
posciakd94b2b082015-09-18 04:03:4074
Hirokazu Honda23132c32019-07-09 14:31:2075void VP9Decoder::SetStream(int32_t id, const DecoderBuffer& decoder_buffer) {
76 const uint8_t* ptr = decoder_buffer.data();
77 const size_t size = decoder_buffer.data_size();
78 const DecryptConfig* decrypt_config = decoder_buffer.decrypt_config();
79
posciakd94b2b082015-09-18 04:03:4080 DCHECK(ptr);
81 DCHECK(size);
Pawel Osciakec6e21b2018-03-19 09:13:0682 DVLOG(4) << "New input stream id: " << id << " at: " << (void*)ptr
83 << " size: " << size;
84 stream_id_ = id;
Ted Meyer0b35c5fd2018-11-27 22:29:2985 if (decrypt_config) {
Hirokazu Honda10df95d2019-07-19 19:31:4386 parser_.SetStream(ptr, size, GetSpatialLayerFrameSize(decoder_buffer),
87 decrypt_config->Clone());
Ted Meyer0b35c5fd2018-11-27 22:29:2988 } else {
Hirokazu Honda10df95d2019-07-19 19:31:4389 parser_.SetStream(ptr, size, GetSpatialLayerFrameSize(decoder_buffer),
90 nullptr);
Ted Meyer0b35c5fd2018-11-27 22:29:2991 }
posciakd94b2b082015-09-18 04:03:4092}
93
94bool VP9Decoder::Flush() {
95 DVLOG(2) << "Decoder flush";
96 Reset();
97 return true;
98}
99
100void VP9Decoder::Reset() {
101 curr_frame_hdr_ = nullptr;
Sreerenj Balachandran1beb5482019-04-03 03:40:05102
103 ref_frames_.Clear();
posciakd94b2b082015-09-18 04:03:40104
105 parser_.Reset();
106
107 if (state_ == kDecoding)
108 state_ = kAfterReset;
109}
110
111VP9Decoder::DecodeResult VP9Decoder::Decode() {
112 while (1) {
113 // Read a new frame header if one is not awaiting decoding already.
Ted Meyer0b35c5fd2018-11-27 22:29:29114 std::unique_ptr<DecryptConfig> decrypt_config;
posciakd94b2b082015-09-18 04:03:40115 if (!curr_frame_hdr_) {
Hirokazu Honda10df95d2019-07-19 19:31:43116 gfx::Size allocate_size;
xhwang60f96672016-06-14 21:47:53117 std::unique_ptr<Vp9FrameHeader> hdr(new Vp9FrameHeader());
Ted Meyer0b35c5fd2018-11-27 22:29:29118 Vp9Parser::Result res =
Hirokazu Honda10df95d2019-07-19 19:31:43119 parser_.ParseNextFrame(hdr.get(), &allocate_size, &decrypt_config);
posciakd94b2b082015-09-18 04:03:40120 switch (res) {
xhwang60f96672016-06-14 21:47:53121 case Vp9Parser::kOk:
brusi_roy8e7155962016-09-14 18:22:58122 curr_frame_hdr_ = std::move(hdr);
Hirokazu Honda10df95d2019-07-19 19:31:43123 curr_frame_size_ = allocate_size;
posciakd94b2b082015-09-18 04:03:40124 break;
125
xhwang60f96672016-06-14 21:47:53126 case Vp9Parser::kEOStream:
posciakd94b2b082015-09-18 04:03:40127 return kRanOutOfStreamData;
128
xhwang60f96672016-06-14 21:47:53129 case Vp9Parser::kInvalidStream:
posciakd94b2b082015-09-18 04:03:40130 DVLOG(1) << "Error parsing stream";
131 SetError();
132 return kDecodeError;
kcwue5a9a6292016-08-17 03:40:02133
134 case Vp9Parser::kAwaitingRefresh:
posciak77118c92016-08-28 13:18:39135 DVLOG(4) << "Awaiting context update";
136 return kNeedContextUpdate;
posciakd94b2b082015-09-18 04:03:40137 }
138 }
139
140 if (state_ != kDecoding) {
141 // Not kDecoding, so we need a resume point (a keyframe), as we are after
142 // reset or at the beginning of the stream. Drop anything that is not
143 // a keyframe in such case, and continue looking for a keyframe.
Sreerenj Balachandran57163302018-11-28 02:45:57144 // Only exception is when the stream/sequence starts with an Intra only
145 // frame.
146 if (curr_frame_hdr_->IsKeyframe() ||
147 (curr_frame_hdr_->IsIntra() && pic_size_.IsEmpty())) {
posciakd94b2b082015-09-18 04:03:40148 state_ = kDecoding;
149 } else {
150 curr_frame_hdr_.reset();
151 continue;
152 }
153 }
154
155 if (curr_frame_hdr_->show_existing_frame) {
156 // This frame header only instructs us to display one of the
157 // previously-decoded frames, but has no frame data otherwise. Display
158 // and continue decoding subsequent frames.
kcwue5a9a6292016-08-17 03:40:02159 size_t frame_to_show = curr_frame_hdr_->frame_to_show_map_idx;
Sreerenj Balachandran1beb5482019-04-03 03:40:05160 if (frame_to_show >= kVp9NumRefFrames ||
161 !ref_frames_.GetFrame(frame_to_show)) {
posciakd94b2b082015-09-18 04:03:40162 DVLOG(1) << "Request to show an invalid frame";
163 SetError();
164 return kDecodeError;
165 }
166
Chih-Yu Huangcd5181e2018-10-23 06:33:06167 // Duplicate the VP9Picture and set the current bitstream id to keep the
168 // correct timestamp.
Sreerenj Balachandran1beb5482019-04-03 03:40:05169 scoped_refptr<VP9Picture> pic =
170 ref_frames_.GetFrame(frame_to_show)->Duplicate();
Chih-Yu Huangcd5181e2018-10-23 06:33:06171 if (pic == nullptr) {
172 DVLOG(1) << "Failed to duplicate the VP9Picture.";
173 SetError();
174 return kDecodeError;
175 }
176 pic->set_bitstream_id(stream_id_);
177 if (!accelerator_->OutputPicture(std::move(pic))) {
posciakd94b2b082015-09-18 04:03:40178 SetError();
179 return kDecodeError;
180 }
181
182 curr_frame_hdr_.reset();
183 continue;
184 }
185
Hirokazu Honda10df95d2019-07-19 19:31:43186 gfx::Size new_pic_size = curr_frame_size_;
Hirokazu Honda436cf27b2019-05-21 10:44:39187 gfx::Rect new_render_rect(curr_frame_hdr_->render_width,
188 curr_frame_hdr_->render_height);
189 // For safety, check the validity of render size or leave it as (0, 0).
190 if (!gfx::Rect(new_pic_size).Contains(new_render_rect)) {
191 DVLOG(1) << "Render size exceeds picture size. render size: "
192 << new_render_rect.ToString()
193 << ", picture size: " << new_pic_size.ToString();
194 new_render_rect = gfx::Rect();
195 }
Hirokazu Honda7ec32652019-11-22 09:40:21196 VideoCodecProfile new_profile =
197 VP9ProfileToVideoCodecProfile(curr_frame_hdr_->profile);
198 if (new_profile == VIDEO_CODEC_PROFILE_UNKNOWN) {
199 VLOG(1) << "Invalid profile: " << curr_frame_hdr_->profile;
200 return kDecodeError;
201 }
posciakd94b2b082015-09-18 04:03:40202
Hirokazu Honda436cf27b2019-05-21 10:44:39203 DCHECK(!new_pic_size.IsEmpty());
Hirokazu Honda7ec32652019-11-22 09:40:21204 if (new_pic_size != pic_size_ || new_profile != profile_) {
205 DVLOG(1) << "New profile: " << GetProfileName(new_profile)
206 << ", New resolution: " << new_pic_size.ToString();
posciakd94b2b082015-09-18 04:03:40207
Sreerenj Balachandran57163302018-11-28 02:45:57208 if (!curr_frame_hdr_->IsKeyframe() &&
Hirokazu Honda7ec32652019-11-22 09:40:21209 !(curr_frame_hdr_->IsIntra() && pic_size_.IsEmpty())) {
posciakd94b2b082015-09-18 04:03:40210 // TODO(posciak): This is doable, but requires a few modifications to
211 // VDA implementations to allow multiple picture buffer sets in flight.
Dongseong Hwang4f20ebb2018-06-07 00:28:20212 // http://crbug.com/832264
Sreerenj Balachandran57163302018-11-28 02:45:57213 DVLOG(1) << "Resolution change currently supported for keyframes and "
214 "sequence begins with Intra only when there is no prior "
215 "frames in the context";
Dongseong Hwang4f20ebb2018-06-07 00:28:20216 if (++size_change_failure_counter_ > kVPxMaxNumOfSizeChangeFailures) {
217 SetError();
218 return kDecodeError;
219 }
220
221 curr_frame_hdr_.reset();
222 return kRanOutOfStreamData;
posciakd94b2b082015-09-18 04:03:40223 }
224
225 // TODO(posciak): This requires us to be on a keyframe (see above) and is
226 // required, because VDA clients expect all surfaces to be returned before
Hirokazu Honda7ec32652019-11-22 09:40:21227 // they can cycle surface sets after receiving kConfigChange.
posciakd94b2b082015-09-18 04:03:40228 // This is only an implementation detail of VDAs and can be improved.
Sreerenj Balachandran1beb5482019-04-03 03:40:05229 ref_frames_.Clear();
posciakd94b2b082015-09-18 04:03:40230
231 pic_size_ = new_pic_size;
Hirokazu Honda436cf27b2019-05-21 10:44:39232 visible_rect_ = new_render_rect;
Hirokazu Honda7ec32652019-11-22 09:40:21233 profile_ = new_profile;
Dongseong Hwang4f20ebb2018-06-07 00:28:20234 size_change_failure_counter_ = 0;
Hirokazu Honda7ec32652019-11-22 09:40:21235 return kConfigChange;
posciakd94b2b082015-09-18 04:03:40236 }
237
238 scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture();
239 if (!pic)
240 return kRanOutOfSurfaces;
johnylin74410872017-06-19 13:05:30241 DVLOG(2) << "Render resolution: " << new_render_rect.ToString();
242
Pawel Osciakec6e21b2018-03-19 09:13:06243 pic->set_visible_rect(new_render_rect);
244 pic->set_bitstream_id(stream_id_);
Fredrik Hubinette3cebc622018-10-27 01:01:12245
Ted Meyer0b35c5fd2018-11-27 22:29:29246 pic->set_decrypt_config(std::move(decrypt_config));
247
Fredrik Hubinette3cebc622018-10-27 01:01:12248 // For VP9, container color spaces override video stream color spaces.
249 if (container_color_space_.IsSpecified()) {
250 pic->set_colorspace(container_color_space_);
251 } else if (curr_frame_hdr_) {
252 pic->set_colorspace(curr_frame_hdr_->GetColorSpace());
253 }
kokihoonfb941e92018-07-10 18:04:24254 pic->frame_hdr = std::move(curr_frame_hdr_);
posciakd94b2b082015-09-18 04:03:40255
256 if (!DecodeAndOutputPicture(pic)) {
257 SetError();
258 return kDecodeError;
259 }
260 }
261}
262
posciak77118c92016-08-28 13:18:39263void VP9Decoder::UpdateFrameContext(
Ted Meyer4fac4f62019-05-08 22:57:15264 scoped_refptr<VP9Picture> pic,
posciak77118c92016-08-28 13:18:39265 const base::Callback<void(const Vp9FrameContext&)>& context_refresh_cb) {
Dale Curtise25163812018-09-21 22:13:39266 DCHECK(context_refresh_cb);
posciak77118c92016-08-28 13:18:39267 Vp9FrameContext frame_ctx;
268 memset(&frame_ctx, 0, sizeof(frame_ctx));
269
Ted Meyer4fac4f62019-05-08 22:57:15270 if (!accelerator_->GetFrameContext(std::move(pic), &frame_ctx)) {
posciak77118c92016-08-28 13:18:39271 SetError();
272 return;
273 }
274
275 context_refresh_cb.Run(frame_ctx);
276}
277
posciakd94b2b082015-09-18 04:03:40278bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic) {
279 DCHECK(!pic_size_.IsEmpty());
280 DCHECK(pic->frame_hdr);
281
posciak77118c92016-08-28 13:18:39282 base::Closure done_cb;
283 const auto& context_refresh_cb =
284 parser_.GetContextRefreshCb(pic->frame_hdr->frame_context_idx);
Dale Curtise25163812018-09-21 22:13:39285 if (context_refresh_cb)
posciak77118c92016-08-28 13:18:39286 done_cb = base::Bind(&VP9Decoder::UpdateFrameContext,
287 base::Unretained(this), pic, context_refresh_cb);
288
289 const Vp9Parser::Context& context = parser_.context();
290 if (!accelerator_->SubmitDecode(pic, context.segmentation(),
291 context.loop_filter(), ref_frames_, done_cb))
posciakd94b2b082015-09-18 04:03:40292 return false;
293
294 if (pic->frame_hdr->show_frame) {
295 if (!accelerator_->OutputPicture(pic))
296 return false;
297 }
298
Ted Meyer4fac4f62019-05-08 22:57:15299 ref_frames_.Refresh(std::move(pic));
posciakd94b2b082015-09-18 04:03:40300 return true;
301}
302
303void VP9Decoder::SetError() {
304 Reset();
305 state_ = kError;
306}
307
308gfx::Size VP9Decoder::GetPicSize() const {
309 return pic_size_;
310}
311
Hirokazu Honda436cf27b2019-05-21 10:44:39312gfx::Rect VP9Decoder::GetVisibleRect() const {
313 return visible_rect_;
314}
315
Hirokazu Honda7ec32652019-11-22 09:40:21316VideoCodecProfile VP9Decoder::GetProfile() const {
317 return profile_;
318}
319
posciakd94b2b082015-09-18 04:03:40320size_t VP9Decoder::GetRequiredNumOfPictures() const {
Miguel Casas477a7062019-01-04 19:13:45321 constexpr size_t kPicsInPipeline = limits::kMaxVideoFrames + 1;
322 return kPicsInPipeline + GetNumReferenceFrames();
323}
324
325size_t VP9Decoder::GetNumReferenceFrames() const {
Miguel Casas3dd7e562019-02-14 17:38:46326 // Maximum number of reference frames
327 return kVp9NumRefFrames;
posciakd94b2b082015-09-18 04:03:40328}
329
markdittmer6e70beb82016-05-02 05:40:47330} // namespace media