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

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

Powered by Google App Engine
This is Rietveld 408576698