Home | History | Annotate | Download | only in vda
      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