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