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 // Note: ported from Chromium commit head: 7441087
      5 
      6 #include "rect.h"
      7 #include "vp9_decoder.h"
      8 
      9 #include <memory>
     10 
     11 #include "base/bind.h"
     12 #include "base/logging.h"
     13 
     14 namespace media {
     15 
     16 VP9Decoder::VP9Accelerator::VP9Accelerator() {}
     17 
     18 VP9Decoder::VP9Accelerator::~VP9Accelerator() {}
     19 
     20 VP9Decoder::VP9Decoder(VP9Accelerator* accelerator)
     21     : state_(kNeedStreamMetadata),
     22       accelerator_(accelerator),
     23       parser_(accelerator->IsFrameContextRequired()) {
     24   ref_frames_.resize(kVp9NumRefFrames);
     25 }
     26 
     27 VP9Decoder::~VP9Decoder() {}
     28 
     29 void VP9Decoder::SetStream(const uint8_t* ptr, size_t size) {
     30   DCHECK(ptr);
     31   DCHECK(size);
     32 
     33   DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size;
     34   parser_.SetStream(ptr, size);
     35 }
     36 
     37 bool VP9Decoder::Flush() {
     38   DVLOG(2) << "Decoder flush";
     39   Reset();
     40   return true;
     41 }
     42 
     43 void VP9Decoder::Reset() {
     44   curr_frame_hdr_ = nullptr;
     45   for (auto& ref_frame : ref_frames_)
     46     ref_frame = nullptr;
     47 
     48   parser_.Reset();
     49 
     50   if (state_ == kDecoding)
     51     state_ = kAfterReset;
     52 }
     53 
     54 VP9Decoder::DecodeResult VP9Decoder::Decode() {
     55   while (1) {
     56     // Read a new frame header if one is not awaiting decoding already.
     57     if (!curr_frame_hdr_) {
     58       std::unique_ptr<Vp9FrameHeader> hdr(new Vp9FrameHeader());
     59       Vp9Parser::Result res = parser_.ParseNextFrame(hdr.get());
     60       switch (res) {
     61         case Vp9Parser::kOk:
     62           curr_frame_hdr_ = std::move(hdr);
     63           break;
     64 
     65         case Vp9Parser::kEOStream:
     66           return kRanOutOfStreamData;
     67 
     68         case Vp9Parser::kInvalidStream:
     69           DVLOG(1) << "Error parsing stream";
     70           SetError();
     71           return kDecodeError;
     72 
     73         case Vp9Parser::kAwaitingRefresh:
     74           DVLOG(4) << "Awaiting context update";
     75           return kNeedContextUpdate;
     76       }
     77     }
     78 
     79     if (state_ != kDecoding) {
     80       // Not kDecoding, so we need a resume point (a keyframe), as we are after
     81       // reset or at the beginning of the stream. Drop anything that is not
     82       // a keyframe in such case, and continue looking for a keyframe.
     83       if (curr_frame_hdr_->IsKeyframe()) {
     84         state_ = kDecoding;
     85       } else {
     86         curr_frame_hdr_.reset();
     87         continue;
     88       }
     89     }
     90 
     91     if (curr_frame_hdr_->show_existing_frame) {
     92       // This frame header only instructs us to display one of the
     93       // previously-decoded frames, but has no frame data otherwise. Display
     94       // and continue decoding subsequent frames.
     95       size_t frame_to_show = curr_frame_hdr_->frame_to_show_map_idx;
     96       if (frame_to_show >= ref_frames_.size() || !ref_frames_[frame_to_show]) {
     97         DVLOG(1) << "Request to show an invalid frame";
     98         SetError();
     99         return kDecodeError;
    100       }
    101 
    102       if (!accelerator_->OutputPicture(ref_frames_[frame_to_show])) {
    103         SetError();
    104         return kDecodeError;
    105       }
    106 
    107       curr_frame_hdr_.reset();
    108       continue;
    109     }
    110 
    111     Size new_pic_size(curr_frame_hdr_->frame_width,
    112                            curr_frame_hdr_->frame_height);
    113     DCHECK(!new_pic_size.IsEmpty());
    114 
    115     if (new_pic_size != pic_size_) {
    116       DVLOG(1) << "New resolution: " << new_pic_size.ToString();
    117 
    118       if (!curr_frame_hdr_->IsKeyframe()) {
    119         // TODO(posciak): This is doable, but requires a few modifications to
    120         // VDA implementations to allow multiple picture buffer sets in flight.
    121         DVLOG(1) << "Resolution change currently supported for keyframes only";
    122         SetError();
    123         return kDecodeError;
    124       }
    125 
    126       // TODO(posciak): This requires us to be on a keyframe (see above) and is
    127       // required, because VDA clients expect all surfaces to be returned before
    128       // they can cycle surface sets after receiving kAllocateNewSurfaces.
    129       // This is only an implementation detail of VDAs and can be improved.
    130       for (auto& ref_frame : ref_frames_)
    131         ref_frame = nullptr;
    132 
    133       pic_size_ = new_pic_size;
    134       return kAllocateNewSurfaces;
    135     }
    136 
    137     scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture();
    138     if (!pic)
    139       return kRanOutOfSurfaces;
    140 
    141     Rect new_render_rect(curr_frame_hdr_->render_width,
    142                          curr_frame_hdr_->render_height);
    143     // For safety, check the validity of render size or leave it as (0, 0).
    144     if (!Rect(pic_size_).Contains(new_render_rect)) {
    145       DVLOG(1) << "Render size exceeds picture size. render size: "
    146                << new_render_rect.ToString()
    147                << ", picture size: " << pic_size_.ToString();
    148       new_render_rect = Rect();
    149     }
    150     DVLOG(2) << "Render resolution: " << new_render_rect.ToString();
    151 
    152     pic->visible_rect = new_render_rect;
    153     pic->frame_hdr.reset(curr_frame_hdr_.release());
    154 
    155     if (!DecodeAndOutputPicture(pic)) {
    156       SetError();
    157       return kDecodeError;
    158     }
    159   }
    160 }
    161 
    162 void VP9Decoder::RefreshReferenceFrames(const scoped_refptr<VP9Picture>& pic) {
    163   for (size_t i = 0; i < kVp9NumRefFrames; ++i) {
    164     DCHECK(!pic->frame_hdr->IsKeyframe() || pic->frame_hdr->RefreshFlag(i));
    165     if (pic->frame_hdr->RefreshFlag(i))
    166       ref_frames_[i] = pic;
    167   }
    168 }
    169 
    170 void VP9Decoder::UpdateFrameContext(
    171     const scoped_refptr<VP9Picture>& pic,
    172     const base::Callback<void(const Vp9FrameContext&)>& context_refresh_cb) {
    173   DCHECK(!context_refresh_cb.is_null());
    174   Vp9FrameContext frame_ctx;
    175   memset(&frame_ctx, 0, sizeof(frame_ctx));
    176 
    177   if (!accelerator_->GetFrameContext(pic, &frame_ctx)) {
    178     SetError();
    179     return;
    180   }
    181 
    182   context_refresh_cb.Run(frame_ctx);
    183 }
    184 
    185 bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic) {
    186   DCHECK(!pic_size_.IsEmpty());
    187   DCHECK(pic->frame_hdr);
    188 
    189   base::Closure done_cb;
    190   const auto& context_refresh_cb =
    191       parser_.GetContextRefreshCb(pic->frame_hdr->frame_context_idx);
    192   if (!context_refresh_cb.is_null())
    193     done_cb = base::Bind(&VP9Decoder::UpdateFrameContext,
    194                          base::Unretained(this), pic, context_refresh_cb);
    195 
    196   const Vp9Parser::Context& context = parser_.context();
    197   if (!accelerator_->SubmitDecode(pic, context.segmentation(),
    198                                   context.loop_filter(), ref_frames_, done_cb))
    199     return false;
    200 
    201   if (pic->frame_hdr->show_frame) {
    202     if (!accelerator_->OutputPicture(pic))
    203       return false;
    204   }
    205 
    206   RefreshReferenceFrames(pic);
    207   return true;
    208 }
    209 
    210 void VP9Decoder::SetError() {
    211   Reset();
    212   state_ = kError;
    213 }
    214 
    215 Size VP9Decoder::GetPicSize() const {
    216   return pic_size_;
    217 }
    218 
    219 size_t VP9Decoder::GetRequiredNumOfPictures() const {
    220   // kMaxVideoFrames to keep higher level media pipeline populated, +2 for the
    221   // pictures being parsed and decoded currently.
    222   // TODO(johnylin): see if we could get rid of kMaxVideoFrames.
    223   const size_t kMaxVideoFrames = 4;
    224   return kMaxVideoFrames + kVp9NumRefFrames + 2;
    225 }
    226 
    227 }  // namespace media
    228