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

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

Issue 1345943009: Reland: 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, 3 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
« no previous file with comments | « content/common/gpu/media/vp9_decoder.h ('k') | content/common/gpu/media/vp9_picture.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..7c25832cdc12c89cd6895f6c56744cc620c3d0da
--- /dev/null
+++ b/content/common/gpu/media/vp9_decoder.cc
@@ -0,0 +1,180 @@
+// 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;
+
+ parser_.Reset();
+
+ 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";
+ SetError();
+ return kDecodeError;
+ }
+ }
+
+ if (state_ != kDecoding) {
+ // Not kDecoding, so we need a resume point (a keyframe), as we are after
+ // reset or at the beginning of the stream. Drop anything that is not
+ // a keyframe in such case, and continue looking for a keyframe.
+ if (curr_frame_hdr_->IsKeyframe()) {
+ state_ = kDecoding;
+ } else {
+ curr_frame_hdr_.reset();
+ continue;
+ }
+ }
+
+ if (curr_frame_hdr_->show_existing_frame) {
+ // This frame header only instructs us to display one of the
+ // previously-decoded frames, but has no frame data otherwise. Display
+ // and continue decoding subsequent frames.
+ 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";
+ SetError();
+ return kDecodeError;
+ }
+
+ if (!accelerator_->OutputPicture(ref_frames_[frame_to_show])) {
+ SetError();
+ return kDecodeError;
+ }
+
+ curr_frame_hdr_.reset();
+ continue;
+ }
+
+ gfx::Size new_pic_size(curr_frame_hdr_->width, curr_frame_hdr_->height);
+ DCHECK(!new_pic_size.IsEmpty());
+
+ if (new_pic_size != pic_size_) {
+ DVLOG(1) << "New resolution: " << new_pic_size.ToString();
+
+ if (!curr_frame_hdr_->IsKeyframe()) {
+ // TODO(posciak): This is doable, but requires a few modifications to
+ // VDA implementations to allow multiple picture buffer sets in flight.
+ DVLOG(1) << "Resolution change currently supported for keyframes only";
+ SetError();
+ return kDecodeError;
+ }
+
+ // TODO(posciak): This requires us to be on a keyframe (see above) and is
+ // required, because VDA clients expect all surfaces to be returned before
+ // they can cycle surface sets after receiving kAllocateNewSurfaces.
+ // This is only an implementation detail of VDAs and can be improved.
+ for (auto& ref_frame : ref_frames_)
+ ref_frame = nullptr;
+
+ pic_size_ = new_pic_size;
+ return kAllocateNewSurfaces;
+ }
+
+ scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture();
+ if (!pic)
+ return kRanOutOfSurfaces;
+
+ pic->frame_hdr.reset(curr_frame_hdr_.release());
+
+ if (!DecodeAndOutputPicture(pic)) {
+ SetError();
+ return kDecodeError;
+ }
+ }
+}
+
+void VP9Decoder::RefreshReferenceFrames(const scoped_refptr<VP9Picture>& pic) {
+ for (size_t i = 0; i < media::kVp9NumRefFrames; ++i) {
+ DCHECK_IMPLIES(pic->frame_hdr->IsKeyframe(),
+ pic->frame_hdr->RefreshFlag(i));
+ if (pic->frame_hdr->RefreshFlag(i))
+ ref_frames_[i] = pic;
+ }
+}
+
+bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic) {
+ DCHECK(!pic_size_.IsEmpty());
+ DCHECK(pic->frame_hdr);
+
+ if (!accelerator_->SubmitDecode(pic, parser_.GetSegmentation(),
+ parser_.GetLoopFilter(), ref_frames_))
+ return false;
+
+ if (pic->frame_hdr->show_frame) {
+ if (!accelerator_->OutputPicture(pic))
+ return false;
+ }
+
+ RefreshReferenceFrames(pic);
+ return true;
+}
+
+void VP9Decoder::SetError() {
+ Reset();
+ state_ = kError;
+}
+
+gfx::Size VP9Decoder::GetPicSize() const {
+ return pic_size_;
+}
+
+size_t VP9Decoder::GetRequiredNumOfPictures() const {
+ // kMaxVideoFrames to keep higher level media pipeline populated, +2 for the
+ // pictures being parsed and decoded currently.
+ return media::limits::kMaxVideoFrames + media::kVp9NumRefFrames + 2;
+}
+
+} // namespace content
« no previous file with comments | « content/common/gpu/media/vp9_decoder.h ('k') | content/common/gpu/media/vp9_picture.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698