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