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