Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(447)

Unified Diff: content/common/gpu/media/vp9_decoder.cc

Issue 1318863003: Add accelerated VP9 decode infrastructure and an implementation for VA-API. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698