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 "media/gpu/vp8_decoder.h"
6 
7 #include "base/logging.h"
8 #include "base/notreached.h"
9 #include "media/base/limits.h"
10 
11 namespace media {
12 
13 namespace {
14 constexpr size_t kVP8NumFramesActive = 4;
15 }
16 
VP8Accelerator()17 VP8Decoder::VP8Accelerator::VP8Accelerator() {}
18 
~VP8Accelerator()19 VP8Decoder::VP8Accelerator::~VP8Accelerator() {}
20 
VP8Decoder(std::unique_ptr<VP8Accelerator> accelerator)21 VP8Decoder::VP8Decoder(std::unique_ptr<VP8Accelerator> accelerator)
22     : state_(kNeedStreamMetadata),
23       curr_frame_start_(nullptr),
24       frame_size_(0),
25       accelerator_(std::move(accelerator)) {
26   DCHECK(accelerator_);
27 }
28 
29 VP8Decoder::~VP8Decoder() = default;
30 
Flush()31 bool VP8Decoder::Flush() {
32   DVLOG(2) << "Decoder flush";
33   Reset();
34   return true;
35 }
36 
SetStream(int32_t id,const DecoderBuffer & decoder_buffer)37 void VP8Decoder::SetStream(int32_t id, const DecoderBuffer& decoder_buffer) {
38   const uint8_t* ptr = decoder_buffer.data();
39   const size_t size = decoder_buffer.data_size();
40   const DecryptConfig* decrypt_config = decoder_buffer.decrypt_config();
41 
42   DCHECK(ptr);
43   DCHECK(size);
44   if (decrypt_config) {
45     NOTIMPLEMENTED();
46     state_ = kError;
47     return;
48   }
49 
50   DVLOG(4) << "New input stream id: " << id << " at: " << (void*)ptr
51            << " size: " << size;
52   stream_id_ = id;
53   curr_frame_start_ = ptr;
54   frame_size_ = size;
55 }
56 
Reset()57 void VP8Decoder::Reset() {
58   curr_frame_hdr_ = nullptr;
59   curr_frame_start_ = nullptr;
60   frame_size_ = 0;
61 
62   ref_frames_.Clear();
63 
64   if (state_ == kDecoding)
65     state_ = kAfterReset;
66 }
67 
Decode()68 VP8Decoder::DecodeResult VP8Decoder::Decode() {
69   if (!curr_frame_start_ || frame_size_ == 0)
70     return kRanOutOfStreamData;
71 
72   if (!curr_frame_hdr_) {
73     curr_frame_hdr_.reset(new Vp8FrameHeader());
74     if (!parser_.ParseFrame(curr_frame_start_, frame_size_,
75                             curr_frame_hdr_.get())) {
76       DVLOG(1) << "Error during decode";
77       state_ = kError;
78       return kDecodeError;
79     }
80   }
81 
82   // The |stream_id_|s are expected to be monotonically increasing, and we've
83   // lost (at least) a frame if this condition doesn't uphold.
84   const bool have_skipped_frame = last_decoded_stream_id_ + 1 != stream_id_ &&
85                                   last_decoded_stream_id_ != kInvalidId;
86   if (curr_frame_hdr_->IsKeyframe()) {
87     const gfx::Size new_picture_size(curr_frame_hdr_->width,
88                                      curr_frame_hdr_->height);
89     if (new_picture_size.IsEmpty())
90       return kDecodeError;
91 
92     if (new_picture_size != pic_size_) {
93       DVLOG(2) << "New resolution: " << new_picture_size.ToString();
94       pic_size_ = new_picture_size;
95 
96       ref_frames_.Clear();
97       last_decoded_stream_id_ = stream_id_;
98       size_change_failure_counter_ = 0;
99 
100       return kConfigChange;
101     }
102 
103     state_ = kDecoding;
104   } else if (state_ != kDecoding || have_skipped_frame) {
105     // Only trust the next frame. Otherwise, new keyframe might be missed, so
106     // |pic_size_| might be stale.
107     // TODO(dshwang): if rtc decoder can know the size of inter frame, change
108     // this condition to check if new keyframe is missed.
109     // https://crbug.com/832545
110     DVLOG(4) << "Drop the frame because the size maybe stale.";
111     if (have_skipped_frame &&
112         ++size_change_failure_counter_ > kVPxMaxNumOfSizeChangeFailures) {
113       state_ = kError;
114       return kDecodeError;
115     }
116 
117     // Need a resume point.
118     curr_frame_hdr_ = nullptr;
119     return kRanOutOfStreamData;
120   }
121 
122   scoped_refptr<VP8Picture> pic = accelerator_->CreateVP8Picture();
123   if (!pic)
124     return kRanOutOfSurfaces;
125 
126   if (!DecodeAndOutputCurrentFrame(std::move(pic))) {
127     state_ = kError;
128     return kDecodeError;
129   }
130 
131   last_decoded_stream_id_ = stream_id_;
132   size_change_failure_counter_ = 0;
133   return kRanOutOfStreamData;
134 }
135 
DecodeAndOutputCurrentFrame(scoped_refptr<VP8Picture> pic)136 bool VP8Decoder::DecodeAndOutputCurrentFrame(scoped_refptr<VP8Picture> pic) {
137   DCHECK(pic);
138   DCHECK(!pic_size_.IsEmpty());
139   DCHECK(curr_frame_hdr_);
140 
141   pic->set_visible_rect(gfx::Rect(pic_size_));
142   pic->set_bitstream_id(stream_id_);
143 
144   if (curr_frame_hdr_->IsKeyframe()) {
145     horizontal_scale_ = curr_frame_hdr_->horizontal_scale;
146     vertical_scale_ = curr_frame_hdr_->vertical_scale;
147   } else {
148     // Populate fields from decoder state instead.
149     curr_frame_hdr_->width = pic_size_.width();
150     curr_frame_hdr_->height = pic_size_.height();
151     curr_frame_hdr_->horizontal_scale = horizontal_scale_;
152     curr_frame_hdr_->vertical_scale = vertical_scale_;
153   }
154 
155   const bool show_frame = curr_frame_hdr_->show_frame;
156   pic->frame_hdr = std::move(curr_frame_hdr_);
157 
158   if (!accelerator_->SubmitDecode(pic, ref_frames_))
159     return false;
160 
161   if (show_frame && !accelerator_->OutputPicture(pic))
162     return false;
163 
164   ref_frames_.Refresh(pic);
165 
166   curr_frame_start_ = nullptr;
167   frame_size_ = 0;
168   return true;
169 }
170 
GetPicSize() const171 gfx::Size VP8Decoder::GetPicSize() const {
172   return pic_size_;
173 }
174 
GetVisibleRect() const175 gfx::Rect VP8Decoder::GetVisibleRect() const {
176   return gfx::Rect(pic_size_);
177 }
178 
GetProfile() const179 VideoCodecProfile VP8Decoder::GetProfile() const {
180   return VP8PROFILE_ANY;
181 }
182 
GetRequiredNumOfPictures() const183 size_t VP8Decoder::GetRequiredNumOfPictures() const {
184   constexpr size_t kPicsInPipeline = limits::kMaxVideoFrames + 1;
185   return kVP8NumFramesActive + kPicsInPipeline;
186 }
187 
GetNumReferenceFrames() const188 size_t VP8Decoder::GetNumReferenceFrames() const {
189   // Maximum number of reference frames.
190   return kVP8NumFramesActive;
191 }
192 
193 }  // namespace media
194