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.
5 #include "base/logging.h"
6 #include "content/common/gpu/media/vp9_decoder.h"
7 #include "media/base/limits.h"
11 VP9Decoder::VP9Accelerator::VP9Accelerator() {}
13 VP9Decoder::VP9Accelerator::~VP9Accelerator() {}
15 VP9Decoder::VP9Decoder(VP9Accelerator
* accelerator
)
16 : state_(kNeedStreamMetadata
), accelerator_(accelerator
) {
18 ref_frames_
.resize(media::kVp9NumRefFrames
);
21 VP9Decoder::~VP9Decoder() {}
23 void VP9Decoder::SetStream(const uint8_t* ptr
, size_t size
) {
27 DVLOG(4) << "New input stream at: " << (void*)ptr
<< " size: " << size
;
28 parser_
.SetStream(ptr
, size
);
31 bool VP9Decoder::Flush() {
32 DVLOG(2) << "Decoder flush";
37 void VP9Decoder::Reset() {
38 curr_frame_hdr_
= nullptr;
39 for (auto& ref_frame
: ref_frames_
)
44 if (state_
== kDecoding
)
48 VP9Decoder::DecodeResult
VP9Decoder::Decode() {
50 // Read a new frame header if one is not awaiting decoding already.
51 if (!curr_frame_hdr_
) {
52 scoped_ptr
<media::Vp9FrameHeader
> hdr(new media::Vp9FrameHeader());
53 media::Vp9Parser::Result res
= parser_
.ParseNextFrame(hdr
.get());
55 case media::Vp9Parser::kOk
:
56 curr_frame_hdr_
.reset(hdr
.release());
59 case media::Vp9Parser::kEOStream
:
60 return kRanOutOfStreamData
;
62 case media::Vp9Parser::kInvalidStream
:
63 DVLOG(1) << "Error parsing stream";
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()) {
76 curr_frame_hdr_
.reset();
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";
92 if (!accelerator_
->OutputPicture(ref_frames_
[frame_to_show
])) {
97 curr_frame_hdr_
.reset();
101 gfx::Size
new_pic_size(curr_frame_hdr_
->width
, curr_frame_hdr_
->height
);
102 DCHECK(!new_pic_size
.IsEmpty());
104 if (new_pic_size
!= pic_size_
) {
105 DVLOG(1) << "New resolution: " << new_pic_size
.ToString();
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";
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_
)
122 pic_size_
= new_pic_size
;
123 return kAllocateNewSurfaces
;
126 scoped_refptr
<VP9Picture
> pic
= accelerator_
->CreateVP9Picture();
128 return kRanOutOfSurfaces
;
130 pic
->frame_hdr
.reset(curr_frame_hdr_
.release());
132 if (!DecodeAndOutputPicture(pic
)) {
139 void VP9Decoder::RefreshReferenceFrames(const scoped_refptr
<VP9Picture
>& pic
) {
140 for (size_t i
= 0; i
< media::kVp9NumRefFrames
; ++i
) {
141 DCHECK_IMPLIES(pic
->frame_hdr
->IsKeyframe(),
142 pic
->frame_hdr
->RefreshFlag(i
));
143 if (pic
->frame_hdr
->RefreshFlag(i
))
144 ref_frames_
[i
] = pic
;
148 bool VP9Decoder::DecodeAndOutputPicture(scoped_refptr
<VP9Picture
> pic
) {
149 DCHECK(!pic_size_
.IsEmpty());
150 DCHECK(pic
->frame_hdr
);
152 if (!accelerator_
->SubmitDecode(pic
, parser_
.GetSegmentation(),
153 parser_
.GetLoopFilter(), ref_frames_
))
156 if (pic
->frame_hdr
->show_frame
) {
157 if (!accelerator_
->OutputPicture(pic
))
161 RefreshReferenceFrames(pic
);
165 void VP9Decoder::SetError() {
170 gfx::Size
VP9Decoder::GetPicSize() const {
174 size_t VP9Decoder::GetRequiredNumOfPictures() const {
175 // kMaxVideoFrames to keep higher level media pipeline populated, +2 for the
176 // pictures being parsed and decoded currently.
177 return media::limits::kMaxVideoFrames
+ media::kVp9NumRefFrames
+ 2;
180 } // namespace content