Chromium Code Reviews| Index: content/common/gpu/media/vp9_decoder.cc |
| diff --git a/content/common/gpu/media/vp9_decoder.cc b/content/common/gpu/media/vp9_decoder.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4e758c6fd066ec31933afcc315fdc5bd59a50c23 |
| --- /dev/null |
| +++ b/content/common/gpu/media/vp9_decoder.cc |
| @@ -0,0 +1,154 @@ |
| +// 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 "base/logging.h" |
| +#include "content/common/gpu/media/vp9_decoder.h" |
| +#include "media/base/limits.h" |
| + |
| +namespace content { |
| + |
| +VP9Decoder::VP9Accelerator::VP9Accelerator() {} |
| + |
| +VP9Decoder::VP9Accelerator::~VP9Accelerator() {} |
| + |
| +VP9Decoder::VP9Decoder(VP9Accelerator* accelerator) |
| + : state_(kNeedStreamMetadata), accelerator_(accelerator) { |
| + DCHECK(accelerator_); |
| + ref_frames_.resize(media::kVp9NumRefFrames); |
| +} |
| + |
| +VP9Decoder::~VP9Decoder() {} |
| + |
| +void VP9Decoder::SetStream(const uint8_t* ptr, size_t size) { |
| + DCHECK(ptr); |
| + DCHECK(size); |
| + |
| + DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size; |
| + parser_.SetStream(ptr, size); |
| +} |
| + |
| +bool VP9Decoder::Flush() { |
| + DVLOG(2) << "Decoder flush"; |
| + Reset(); |
| + return true; |
| +} |
| + |
| +void VP9Decoder::Reset() { |
| + curr_frame_hdr_ = nullptr; |
| + for (auto& ref_frame : ref_frames_) |
| + ref_frame = nullptr; |
| + |
| + if (state_ == kDecoding) |
| + state_ = kAfterReset; |
| +} |
| + |
| +VP9Decoder::DecodeResult VP9Decoder::Decode() { |
| + while (1) { |
| + // Read a new frame header if one is not awaiting decoding already. |
| + if (!curr_frame_hdr_) { |
| + scoped_ptr<media::Vp9FrameHeader> hdr(new media::Vp9FrameHeader()); |
| + media::Vp9Parser::Result res = parser_.ParseNextFrame(hdr.get()); |
| + switch (res) { |
| + case media::Vp9Parser::kOk: |
| + curr_frame_hdr_.reset(hdr.release()); |
| + break; |
| + |
| + case media::Vp9Parser::kEOStream: |
| + return kRanOutOfStreamData; |
| + |
| + case media::Vp9Parser::kInvalidStream: |
| + DVLOG(1) << "Error parsing stream"; |
| + return kDecodeError; |
|
kcwu
2015/09/02 10:09:45
Should we update |state_| as well for all errors?
Pawel Osciak
2015/09/08 06:43:48
Yes, was missing some cleanup.
|
| + } |
| + } |
| + |
| + // If the frame header instructs us to additionally display any of the |
| + // previously-decoded frames, do so now. |
| + if (curr_frame_hdr_->show_existing_frame) { |
| + size_t frame_to_show = curr_frame_hdr_->frame_to_show; |
| + if (frame_to_show >= ref_frames_.size() || !ref_frames_[frame_to_show]) { |
| + DVLOG(1) << "Request to show an invalid frame"; |
| + return kDecodeError; |
| + } |
| + |
| + if (!accelerator_->OutputPicture(ref_frames_[frame_to_show])) |
| + return kDecodeError; |
| + } |
|
kcwu
2015/09/02 10:09:45
continue; here?
Pawel Osciak
2015/09/08 06:43:48
I treat this as a critical error.
|
| + |
| + if (curr_frame_hdr_->IsKeyframe()) { |
| + gfx::Size new_pic_size(curr_frame_hdr_->width, curr_frame_hdr_->height); |
| + if (new_pic_size.IsEmpty()) |
|
kcwu
2015/09/02 10:09:44
How about DCHECK?
IIUC, the parser never return fr
Pawel Osciak
2015/09/08 06:43:48
Misread the code, true, this is not needed.
|
| + return kDecodeError; |
| + |
| + if (new_pic_size != pic_size_) { |
| + DVLOG(1) << "New resolution: " << new_pic_size.ToString(); |
| + pic_size_ = new_pic_size; |
| + |
| + for (auto& ref_frame : ref_frames_) |
| + ref_frame = nullptr; |
| + |
| + return kAllocateNewSurfaces; |
| + } |
| + |
| + state_ = kDecoding; |
| + } else { |
|
kcwu
2015/09/02 10:09:45
Theoretically the parser may return frames with re
Pawel Osciak
2015/09/08 06:43:48
Good point, this is new in VP9.
|
| + if (state_ != kDecoding) { |
| + // Need a resume point. |
| + curr_frame_hdr_.reset(); |
| + continue; |
| + } |
| + } |
| + |
| + scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture(); |
| + if (!pic) |
| + return kRanOutOfSurfaces; |
| + |
| + pic->frame_hdr.reset(curr_frame_hdr_.release()); |
| + |
| + if (!DecodeAndOutputPicture(pic)) |
| + return kDecodeError; |
| + } |
| +} |
| + |
| +void VP9Decoder::RefreshReferenceFrames(const scoped_refptr<VP9Picture>& pic) { |
| + for (size_t i = 0; i < media::kVp9NumRefFrames; ++i) { |
| + if (pic->frame_hdr->IsKeyframe() || pic->frame_hdr->RefreshFlag(i)) |
|
kcwu
2015/09/02 10:09:45
RefreshFlag should be enough.
How about
DCHECK_IMP
Pawel Osciak
2015/09/08 06:43:48
Correct, I had moved changing refresh flags to ano
|
| + ref_frames_[i] = pic; |
| + } |
| +} |
| + |
| +bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic) { |
| + DCHECK(!pic_size_.IsEmpty()); |
| + |
| + media::Vp9FrameHeader* frame_hdr = pic->frame_hdr.get(); |
| + DCHECK(frame_hdr); |
| + |
| + if (frame_hdr->width == 0 || frame_hdr->height == 0) { |
|
kcwu
2015/09/02 10:09:45
DCHECK instead?
Pawel Osciak
2015/09/08 06:43:48
Acknowledged.
|
| + frame_hdr->width = pic_size_.width(); |
| + frame_hdr->height = pic_size_.height(); |
| + } |
| + |
| + if (!accelerator_->SubmitDecode(pic, parser_.GetSegmentation(), |
| + parser_.GetLoopFilter(), ref_frames_)) |
| + return false; |
| + |
| + if (frame_hdr->show_frame) { |
| + if (!accelerator_->OutputPicture(pic)) |
| + return false; |
| + } |
| + |
| + RefreshReferenceFrames(pic); |
| + return true; |
| +} |
| + |
| +gfx::Size VP9Decoder::GetPicSize() const { |
| + return pic_size_; |
| +} |
| + |
| +size_t VP9Decoder::GetRequiredNumOfPictures() const { |
| + const size_t kPicsInPipeline = media::limits::kMaxVideoFrames + 2; |
| + return media::kVp9NumRefFrames + kPicsInPipeline; |
|
kcwu
2015/09/02 10:09:44
I don't understand these numbers from variable nam
Pawel Osciak
2015/09/08 06:43:48
We should ideally have the media::limits::kMaxVide
|
| +} |
| + |
| +} // namespace content |