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 "vp8_decoder.h"
6
7 namespace media {
8
VP8Accelerator()9 VP8Decoder::VP8Accelerator::VP8Accelerator() {}
10
~VP8Accelerator()11 VP8Decoder::VP8Accelerator::~VP8Accelerator() {}
12
VP8Decoder(VP8Accelerator * accelerator)13 VP8Decoder::VP8Decoder(VP8Accelerator* accelerator)
14 : state_(kNeedStreamMetadata),
15 curr_frame_start_(nullptr),
16 frame_size_(0),
17 accelerator_(accelerator) {
18 DCHECK(accelerator_);
19 }
20
~VP8Decoder()21 VP8Decoder::~VP8Decoder() {}
22
Flush()23 bool VP8Decoder::Flush() {
24 DVLOG(2) << "Decoder flush";
25 Reset();
26 return true;
27 }
28
SetStream(const uint8_t * ptr,size_t size)29 void VP8Decoder::SetStream(const uint8_t* ptr, size_t size) {
30 DCHECK(ptr);
31 DCHECK(size);
32
33 curr_frame_start_ = ptr;
34 frame_size_ = size;
35 DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size;
36 }
37
Reset()38 void VP8Decoder::Reset() {
39 curr_pic_ = nullptr;
40 curr_frame_hdr_ = nullptr;
41 curr_frame_start_ = nullptr;
42 frame_size_ = 0;
43
44 last_frame_ = nullptr;
45 golden_frame_ = nullptr;
46 alt_frame_ = nullptr;
47
48 if (state_ == kDecoding)
49 state_ = kAfterReset;
50 }
51
Decode()52 VP8Decoder::DecodeResult VP8Decoder::Decode() {
53 if (!curr_frame_start_ || frame_size_ == 0)
54 return kRanOutOfStreamData;
55
56 if (!curr_frame_hdr_) {
57 curr_frame_hdr_.reset(new Vp8FrameHeader());
58 if (!parser_.ParseFrame(curr_frame_start_, frame_size_,
59 curr_frame_hdr_.get())) {
60 DVLOG(1) << "Error during decode";
61 state_ = kError;
62 return kDecodeError;
63 }
64 }
65
66 if (curr_frame_hdr_->IsKeyframe()) {
67 Size new_pic_size(curr_frame_hdr_->width, curr_frame_hdr_->height);
68 if (new_pic_size.IsEmpty())
69 return kDecodeError;
70
71 if (new_pic_size != pic_size_) {
72 DVLOG(2) << "New resolution: " << new_pic_size.ToString();
73 pic_size_ = new_pic_size;
74
75 DCHECK(!curr_pic_);
76 last_frame_ = nullptr;
77 golden_frame_ = nullptr;
78 alt_frame_ = nullptr;
79
80 return kAllocateNewSurfaces;
81 }
82
83 state_ = kDecoding;
84 } else {
85 if (state_ != kDecoding) {
86 // Need a resume point.
87 curr_frame_hdr_.reset();
88 return kRanOutOfStreamData;
89 }
90 }
91
92 curr_pic_ = accelerator_->CreateVP8Picture();
93 if (!curr_pic_)
94 return kRanOutOfSurfaces;
95
96 if (!DecodeAndOutputCurrentFrame())
97 return kDecodeError;
98
99 return kRanOutOfStreamData;
100 }
101
RefreshReferenceFrames()102 void VP8Decoder::RefreshReferenceFrames() {
103 if (curr_frame_hdr_->IsKeyframe()) {
104 last_frame_ = curr_pic_;
105 golden_frame_ = curr_pic_;
106 alt_frame_ = curr_pic_;
107 return;
108 }
109
110 // Save current golden since we overwrite it here,
111 // but may have to use it to update alt below.
112 scoped_refptr<VP8Picture> curr_golden = golden_frame_;
113
114 if (curr_frame_hdr_->refresh_golden_frame) {
115 golden_frame_ = curr_pic_;
116 } else {
117 switch (curr_frame_hdr_->copy_buffer_to_golden) {
118 case Vp8FrameHeader::COPY_LAST_TO_GOLDEN:
119 DCHECK(last_frame_);
120 golden_frame_ = last_frame_;
121 break;
122
123 case Vp8FrameHeader::COPY_ALT_TO_GOLDEN:
124 DCHECK(alt_frame_);
125 golden_frame_ = alt_frame_;
126 break;
127 }
128 }
129
130 if (curr_frame_hdr_->refresh_alternate_frame) {
131 alt_frame_ = curr_pic_;
132 } else {
133 switch (curr_frame_hdr_->copy_buffer_to_alternate) {
134 case Vp8FrameHeader::COPY_LAST_TO_ALT:
135 DCHECK(last_frame_);
136 alt_frame_ = last_frame_;
137 break;
138
139 case Vp8FrameHeader::COPY_GOLDEN_TO_ALT:
140 DCHECK(curr_golden);
141 alt_frame_ = curr_golden;
142 break;
143 }
144 }
145
146 if (curr_frame_hdr_->refresh_last)
147 last_frame_ = curr_pic_;
148 }
149
DecodeAndOutputCurrentFrame()150 bool VP8Decoder::DecodeAndOutputCurrentFrame() {
151 DCHECK(!pic_size_.IsEmpty());
152 DCHECK(curr_pic_);
153 DCHECK(curr_frame_hdr_);
154
155 if (curr_frame_hdr_->IsKeyframe()) {
156 horizontal_scale_ = curr_frame_hdr_->horizontal_scale;
157 vertical_scale_ = curr_frame_hdr_->vertical_scale;
158 } else {
159 // Populate fields from decoder state instead.
160 curr_frame_hdr_->width = pic_size_.width();
161 curr_frame_hdr_->height = pic_size_.height();
162 curr_frame_hdr_->horizontal_scale = horizontal_scale_;
163 curr_frame_hdr_->vertical_scale = vertical_scale_;
164 }
165
166 if (!accelerator_->SubmitDecode(curr_pic_, curr_frame_hdr_.get(), last_frame_,
167 golden_frame_, alt_frame_))
168 return false;
169
170 if (curr_frame_hdr_->show_frame)
171 if (!accelerator_->OutputPicture(curr_pic_))
172 return false;
173
174 RefreshReferenceFrames();
175
176 curr_pic_ = nullptr;
177 curr_frame_hdr_ = nullptr;
178 curr_frame_start_ = nullptr;
179 frame_size_ = 0;
180 return true;
181 }
182
GetPicSize() const183 Size VP8Decoder::GetPicSize() const {
184 return pic_size_;
185 }
186
GetRequiredNumOfPictures() const187 size_t VP8Decoder::GetRequiredNumOfPictures() const {
188 const size_t kVP8NumFramesActive = 4;
189 // TODO(johnylin): see if we could get rid of kMaxVideoFrames.
190 const size_t kMaxVideoFrames = 4;
191 const size_t kPicsInPipeline = kMaxVideoFrames + 2;
192 return kVP8NumFramesActive + kPicsInPipeline;
193 }
194
195 } // namespace media
196