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 9 VP8Decoder::VP8Accelerator::VP8Accelerator() {} 10 11 VP8Decoder::VP8Accelerator::~VP8Accelerator() {} 12 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 21 VP8Decoder::~VP8Decoder() {} 22 23 bool VP8Decoder::Flush() { 24 DVLOG(2) << "Decoder flush"; 25 Reset(); 26 return true; 27 } 28 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 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 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 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 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 183 Size VP8Decoder::GetPicSize() const { 184 return pic_size_; 185 } 186 187 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