// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "vp8_decoder.h" namespace media { VP8Decoder::VP8Accelerator::VP8Accelerator() {} VP8Decoder::VP8Accelerator::~VP8Accelerator() {} VP8Decoder::VP8Decoder(VP8Accelerator* accelerator) : state_(kNeedStreamMetadata), curr_frame_start_(nullptr), frame_size_(0), accelerator_(accelerator) { DCHECK(accelerator_); } VP8Decoder::~VP8Decoder() {} bool VP8Decoder::Flush() { DVLOG(2) << "Decoder flush"; Reset(); return true; } void VP8Decoder::SetStream(const uint8_t* ptr, size_t size) { DCHECK(ptr); DCHECK(size); curr_frame_start_ = ptr; frame_size_ = size; DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size; } void VP8Decoder::Reset() { curr_pic_ = nullptr; curr_frame_hdr_ = nullptr; curr_frame_start_ = nullptr; frame_size_ = 0; last_frame_ = nullptr; golden_frame_ = nullptr; alt_frame_ = nullptr; if (state_ == kDecoding) state_ = kAfterReset; } VP8Decoder::DecodeResult VP8Decoder::Decode() { if (!curr_frame_start_ || frame_size_ == 0) return kRanOutOfStreamData; if (!curr_frame_hdr_) { curr_frame_hdr_.reset(new Vp8FrameHeader()); if (!parser_.ParseFrame(curr_frame_start_, frame_size_, curr_frame_hdr_.get())) { DVLOG(1) << "Error during decode"; state_ = kError; return kDecodeError; } } if (curr_frame_hdr_->IsKeyframe()) { Size new_pic_size(curr_frame_hdr_->width, curr_frame_hdr_->height); if (new_pic_size.IsEmpty()) return kDecodeError; if (new_pic_size != pic_size_) { DVLOG(2) << "New resolution: " << new_pic_size.ToString(); pic_size_ = new_pic_size; DCHECK(!curr_pic_); last_frame_ = nullptr; golden_frame_ = nullptr; alt_frame_ = nullptr; return kAllocateNewSurfaces; } state_ = kDecoding; } else { if (state_ != kDecoding) { // Need a resume point. curr_frame_hdr_.reset(); return kRanOutOfStreamData; } } curr_pic_ = accelerator_->CreateVP8Picture(); if (!curr_pic_) return kRanOutOfSurfaces; if (!DecodeAndOutputCurrentFrame()) return kDecodeError; return kRanOutOfStreamData; } void VP8Decoder::RefreshReferenceFrames() { if (curr_frame_hdr_->IsKeyframe()) { last_frame_ = curr_pic_; golden_frame_ = curr_pic_; alt_frame_ = curr_pic_; return; } // Save current golden since we overwrite it here, // but may have to use it to update alt below. scoped_refptr curr_golden = golden_frame_; if (curr_frame_hdr_->refresh_golden_frame) { golden_frame_ = curr_pic_; } else { switch (curr_frame_hdr_->copy_buffer_to_golden) { case Vp8FrameHeader::COPY_LAST_TO_GOLDEN: DCHECK(last_frame_); golden_frame_ = last_frame_; break; case Vp8FrameHeader::COPY_ALT_TO_GOLDEN: DCHECK(alt_frame_); golden_frame_ = alt_frame_; break; } } if (curr_frame_hdr_->refresh_alternate_frame) { alt_frame_ = curr_pic_; } else { switch (curr_frame_hdr_->copy_buffer_to_alternate) { case Vp8FrameHeader::COPY_LAST_TO_ALT: DCHECK(last_frame_); alt_frame_ = last_frame_; break; case Vp8FrameHeader::COPY_GOLDEN_TO_ALT: DCHECK(curr_golden); alt_frame_ = curr_golden; break; } } if (curr_frame_hdr_->refresh_last) last_frame_ = curr_pic_; } bool VP8Decoder::DecodeAndOutputCurrentFrame() { DCHECK(!pic_size_.IsEmpty()); DCHECK(curr_pic_); DCHECK(curr_frame_hdr_); if (curr_frame_hdr_->IsKeyframe()) { horizontal_scale_ = curr_frame_hdr_->horizontal_scale; vertical_scale_ = curr_frame_hdr_->vertical_scale; } else { // Populate fields from decoder state instead. curr_frame_hdr_->width = pic_size_.width(); curr_frame_hdr_->height = pic_size_.height(); curr_frame_hdr_->horizontal_scale = horizontal_scale_; curr_frame_hdr_->vertical_scale = vertical_scale_; } if (!accelerator_->SubmitDecode(curr_pic_, curr_frame_hdr_.get(), last_frame_, golden_frame_, alt_frame_)) return false; if (curr_frame_hdr_->show_frame) if (!accelerator_->OutputPicture(curr_pic_)) return false; RefreshReferenceFrames(); curr_pic_ = nullptr; curr_frame_hdr_ = nullptr; curr_frame_start_ = nullptr; frame_size_ = 0; return true; } Size VP8Decoder::GetPicSize() const { return pic_size_; } size_t VP8Decoder::GetRequiredNumOfPictures() const { const size_t kVP8NumFramesActive = 4; // TODO(johnylin): see if we could get rid of kMaxVideoFrames. const size_t kMaxVideoFrames = 4; const size_t kPicsInPipeline = kMaxVideoFrames + 2; return kVP8NumFramesActive + kPicsInPipeline; } } // namespace media