• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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