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

Side by Side Diff: content/common/gpu/media/vp9_decoder.cc

Issue 1882373004: Migrate content/common/gpu/media code to media/gpu (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Squash and rebase Created 4 years, 7 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 unified diff | Download patch
OLDNEW
(Empty)
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
5 #include "content/common/gpu/media/vp9_decoder.h"
6
7 #include <memory>
8
9 #include "base/logging.h"
10 #include "media/base/limits.h"
11
12 namespace content {
13
14 VP9Decoder::VP9Accelerator::VP9Accelerator() {}
15
16 VP9Decoder::VP9Accelerator::~VP9Accelerator() {}
17
18 VP9Decoder::VP9Decoder(VP9Accelerator* accelerator)
19 : state_(kNeedStreamMetadata), accelerator_(accelerator) {
20 DCHECK(accelerator_);
21 ref_frames_.resize(media::kVp9NumRefFrames);
22 }
23
24 VP9Decoder::~VP9Decoder() {}
25
26 void VP9Decoder::SetStream(const uint8_t* ptr, size_t size) {
27 DCHECK(ptr);
28 DCHECK(size);
29
30 DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size;
31 parser_.SetStream(ptr, size);
32 }
33
34 bool VP9Decoder::Flush() {
35 DVLOG(2) << "Decoder flush";
36 Reset();
37 return true;
38 }
39
40 void VP9Decoder::Reset() {
41 curr_frame_hdr_ = nullptr;
42 for (auto& ref_frame : ref_frames_)
43 ref_frame = nullptr;
44
45 parser_.Reset();
46
47 if (state_ == kDecoding)
48 state_ = kAfterReset;
49 }
50
51 VP9Decoder::DecodeResult VP9Decoder::Decode() {
52 while (1) {
53 // Read a new frame header if one is not awaiting decoding already.
54 if (!curr_frame_hdr_) {
55 std::unique_ptr<media::Vp9FrameHeader> hdr(new media::Vp9FrameHeader());
56 media::Vp9Parser::Result res = parser_.ParseNextFrame(hdr.get());
57 switch (res) {
58 case media::Vp9Parser::kOk:
59 curr_frame_hdr_.reset(hdr.release());
60 break;
61
62 case media::Vp9Parser::kEOStream:
63 return kRanOutOfStreamData;
64
65 case media::Vp9Parser::kInvalidStream:
66 DVLOG(1) << "Error parsing stream";
67 SetError();
68 return kDecodeError;
69 }
70 }
71
72 if (state_ != kDecoding) {
73 // Not kDecoding, so we need a resume point (a keyframe), as we are after
74 // reset or at the beginning of the stream. Drop anything that is not
75 // a keyframe in such case, and continue looking for a keyframe.
76 if (curr_frame_hdr_->IsKeyframe()) {
77 state_ = kDecoding;
78 } else {
79 curr_frame_hdr_.reset();
80 continue;
81 }
82 }
83
84 if (curr_frame_hdr_->show_existing_frame) {
85 // This frame header only instructs us to display one of the
86 // previously-decoded frames, but has no frame data otherwise. Display
87 // and continue decoding subsequent frames.
88 size_t frame_to_show = curr_frame_hdr_->frame_to_show;
89 if (frame_to_show >= ref_frames_.size() || !ref_frames_[frame_to_show]) {
90 DVLOG(1) << "Request to show an invalid frame";
91 SetError();
92 return kDecodeError;
93 }
94
95 if (!accelerator_->OutputPicture(ref_frames_[frame_to_show])) {
96 SetError();
97 return kDecodeError;
98 }
99
100 curr_frame_hdr_.reset();
101 continue;
102 }
103
104 gfx::Size new_pic_size(curr_frame_hdr_->width, curr_frame_hdr_->height);
105 DCHECK(!new_pic_size.IsEmpty());
106
107 if (new_pic_size != pic_size_) {
108 DVLOG(1) << "New resolution: " << new_pic_size.ToString();
109
110 if (!curr_frame_hdr_->IsKeyframe()) {
111 // TODO(posciak): This is doable, but requires a few modifications to
112 // VDA implementations to allow multiple picture buffer sets in flight.
113 DVLOG(1) << "Resolution change currently supported for keyframes only";
114 SetError();
115 return kDecodeError;
116 }
117
118 // TODO(posciak): This requires us to be on a keyframe (see above) and is
119 // required, because VDA clients expect all surfaces to be returned before
120 // they can cycle surface sets after receiving kAllocateNewSurfaces.
121 // This is only an implementation detail of VDAs and can be improved.
122 for (auto& ref_frame : ref_frames_)
123 ref_frame = nullptr;
124
125 pic_size_ = new_pic_size;
126 return kAllocateNewSurfaces;
127 }
128
129 scoped_refptr<VP9Picture> pic = accelerator_->CreateVP9Picture();
130 if (!pic)
131 return kRanOutOfSurfaces;
132
133 pic->frame_hdr.reset(curr_frame_hdr_.release());
134
135 if (!DecodeAndOutputPicture(pic)) {
136 SetError();
137 return kDecodeError;
138 }
139 }
140 }
141
142 void VP9Decoder::RefreshReferenceFrames(const scoped_refptr<VP9Picture>& pic) {
143 for (size_t i = 0; i < media::kVp9NumRefFrames; ++i) {
144 DCHECK(!pic->frame_hdr->IsKeyframe() || pic->frame_hdr->RefreshFlag(i));
145 if (pic->frame_hdr->RefreshFlag(i))
146 ref_frames_[i] = pic;
147 }
148 }
149
150 bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr<VP9Picture> pic) {
151 DCHECK(!pic_size_.IsEmpty());
152 DCHECK(pic->frame_hdr);
153
154 if (!accelerator_->SubmitDecode(pic, parser_.GetSegmentation(),
155 parser_.GetLoopFilter(), ref_frames_))
156 return false;
157
158 if (pic->frame_hdr->show_frame) {
159 if (!accelerator_->OutputPicture(pic))
160 return false;
161 }
162
163 RefreshReferenceFrames(pic);
164 return true;
165 }
166
167 void VP9Decoder::SetError() {
168 Reset();
169 state_ = kError;
170 }
171
172 gfx::Size VP9Decoder::GetPicSize() const {
173 return pic_size_;
174 }
175
176 size_t VP9Decoder::GetRequiredNumOfPictures() const {
177 // kMaxVideoFrames to keep higher level media pipeline populated, +2 for the
178 // pictures being parsed and decoded currently.
179 return media::limits::kMaxVideoFrames + media::kVp9NumRefFrames + 2;
180 }
181
182 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698