Chromium Code Reviews| Index: content/common/gpu/media/vp8_decoder.cc |
| diff --git a/content/common/gpu/media/vp8_decoder.cc b/content/common/gpu/media/vp8_decoder.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4e7d4bc2a16d21c79cf2d66762770628c7678ce1 |
| --- /dev/null |
| +++ b/content/common/gpu/media/vp8_decoder.cc |
| @@ -0,0 +1,184 @@ |
| +// 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 "content/common/gpu/media/vp8_decoder.h" |
| +#include "media/base/limits.h" |
| + |
| +namespace content { |
| + |
| +VP8Decoder::VP8Decoder(VP8Accelerator* accelerator) |
| + : state_(kNeedStreamMetadata), |
| + curr_frame_start_(nullptr), |
| + frame_size_(0), |
| + accelerator_(accelerator) { |
| + DCHECK(accelerator_); |
| +} |
| + |
| +VP8Decoder::~VP8Decoder() { |
| +} |
| + |
| +bool VP8Decoder::Flush() { |
| + DVLOG(2) << "Decoder flush"; |
| + Reset(); |
| + return true; |
| +} |
| + |
| +void VP8Decoder::SetStream(const uint8_t* ptr, size_t size) { |
| + DCHECK(ptr); |
| + DCHECK(size); |
| + |
| + curr_frame_start_ = ptr; |
| + frame_size_ = size; |
| + DVLOG(4) << "New input stream at: " << (void*)ptr << " size: " << size; |
| +} |
| + |
| +void VP8Decoder::Reset() { |
| + curr_pic_ = nullptr; |
| + curr_frame_hdr_ = nullptr; |
| + curr_frame_start_ = nullptr; |
| + frame_size_ = 0; |
| + |
| + last_frame_ = nullptr; |
| + golden_frame_ = nullptr; |
| + alt_frame_ = nullptr; |
| + |
| + if (state_ == kDecoding) |
| + state_ = kAfterReset; |
| +} |
| + |
| +VP8Decoder::DecResult VP8Decoder::Decode() { |
| + if (!curr_frame_start_ || frame_size_ == 0) |
| + return kRanOutOfStreamData; |
| + |
| + if (!curr_frame_hdr_) { |
| + curr_frame_hdr_.reset(new media::VP8FrameHeader()); |
| + if (!parser_.ParseFrame(curr_frame_start_, frame_size_, |
| + curr_frame_hdr_.get())) { |
| + DVLOG(1) << "Error during decode"; |
| + state_ = kError; |
| + return VP8Decoder::kDecodeError; |
|
kcwu
2015/01/09 10:07:48
Maybe it is just not enough data, not really error
Pawel Osciak
2015/01/09 13:50:31
This would indicate a partial frame (since frame_s
|
| + } |
| + } |
| + |
| + if (curr_frame_hdr_->IsKeyframe()) { |
| + gfx::Size new_pic_size(curr_frame_hdr_->width, curr_frame_hdr_->height); |
| + if (new_pic_size.IsEmpty()) |
| + return kDecodeError; |
| + |
| + if (pic_size_.IsEmpty() || new_pic_size != pic_size_) { |
|
Owen Lin
2015/01/09 09:56:14
Do we need to test pic_size_.IsEmpty() ?
Since ne
kcwu
2015/01/09 10:07:48
"new_pic_size != pic_size_" is enough.
Pawel Osciak
2015/01/12 07:18:19
Done.
Pawel Osciak
2015/01/12 07:18:19
Done.
|
| + DVLOG(2) << "New resolution: " << new_pic_size.ToString(); |
| + pic_size_ = new_pic_size; |
| + return kAllocateNewSurfaces; |
| + } |
| + |
| + state_ = kDecoding; |
| + } else { |
| + if (state_ != kDecoding) { |
| + // Need a resume point. |
| + curr_frame_hdr_.reset(); |
| + return kRanOutOfStreamData; |
| + } |
| + } |
| + |
| + curr_pic_ = accelerator_->CreateVP8Picture(); |
| + if (!curr_pic_) |
| + return kRanOutOfSurfaces; |
| + |
| + if (!DecodeAndOutputCurrentFrame()) |
| + return kDecodeError; |
| + |
| + return kRanOutOfStreamData; |
|
kcwu
2015/01/09 10:07:48
IIUC, you only decoded one frame and there may be
Pawel Osciak
2015/01/09 13:50:31
Hm, true, it doesn't happen now since Chrome segme
Pawel Osciak
2015/01/12 07:18:19
Actually, this would apply to H264, but for VP8 we
|
| +} |
| + |
| +void VP8Decoder::RefreshReferenceFrames() { |
| + if (curr_frame_hdr_->IsKeyframe()) { |
| + last_frame_ = curr_pic_; |
| + golden_frame_ = curr_pic_; |
| + alt_frame_ = curr_pic_; |
| + return; |
| + } |
| + |
| + // Save current golden since we overwrite it here, |
| + // but may have to use it to update alt below. |
| + scoped_refptr<VP8Picture> curr_golden = golden_frame_; |
| + |
| + if (curr_frame_hdr_->refresh_golden_frame) { |
| + golden_frame_ = curr_pic_; |
| + } else { |
| + switch (curr_frame_hdr_->copy_buffer_to_golden) { |
| + case media::VP8FrameHeader::kCopyLastToGolden: |
| + DCHECK(last_frame_); |
|
Owen Lin
2015/01/09 09:56:14
Why it is not a decode error? I mean a bad stream
Pawel Osciak
2015/01/09 13:50:31
Ah good point.
Pawel Osciak
2015/01/12 07:18:19
Well, actually, recalling my original line of thou
|
| + golden_frame_ = last_frame_; |
| + break; |
| + |
| + case media::VP8FrameHeader::kCopyAltToGolden: |
| + DCHECK(alt_frame_); |
|
Owen Lin
2015/01/09 09:56:14
Same here.
Pawel Osciak
2015/01/12 07:18:19
As above.
|
| + golden_frame_ = alt_frame_; |
| + break; |
| + } |
| + } |
| + |
| + if (curr_frame_hdr_->refresh_alternate_frame) { |
| + alt_frame_ = curr_pic_; |
| + } else { |
| + switch (curr_frame_hdr_->copy_buffer_to_alternate) { |
| + case media::VP8FrameHeader::kCopyLastToAlt: |
| + DCHECK(last_frame_); |
| + alt_frame_ = last_frame_; |
| + break; |
| + |
| + case media::VP8FrameHeader::kCopyGoldenToAlt: |
| + DCHECK(curr_golden); |
| + alt_frame_ = curr_golden; |
| + break; |
| + } |
| + } |
| + |
| + if (curr_frame_hdr_->refresh_last) |
| + last_frame_ = curr_pic_; |
| +} |
| + |
| +void VP8Decoder::BeginFrame() { |
| + if (curr_frame_hdr_->IsKeyframe()) { |
| + horizontal_scale_ = curr_frame_hdr_->horizontal_scale; |
| + vertical_scale_ = curr_frame_hdr_->vertical_scale; |
| + } else { |
| + // Populate fields from decoder state instead. |
| + curr_frame_hdr_->width = pic_size_.width(); |
| + curr_frame_hdr_->height = pic_size_.height(); |
| + curr_frame_hdr_->horizontal_scale = horizontal_scale_; |
| + curr_frame_hdr_->vertical_scale = vertical_scale_; |
| + } |
| +} |
| + |
| +bool VP8Decoder::DecodeAndOutputCurrentFrame() { |
| + DCHECK(!pic_size_.IsEmpty()); |
| + DCHECK(curr_pic_); |
| + DCHECK(curr_frame_hdr_); |
| + |
| + BeginFrame(); |
|
Owen Lin
2015/01/09 09:56:14
[optional] I am kind of thinking there is no need
Pawel Osciak
2015/01/12 07:18:19
Done.
|
| + |
| + if (!accelerator_->SubmitDecode(curr_pic_, curr_frame_hdr_.get(), last_frame_, |
| + golden_frame_, alt_frame_)) |
| + return false; |
| + |
| + if (!accelerator_->OutputPicture(curr_pic_)) |
| + return false; |
| + |
| + RefreshReferenceFrames(); |
| + |
| + curr_pic_ = nullptr; |
| + curr_frame_hdr_ = nullptr; |
| + curr_frame_start_ = nullptr; |
| + frame_size_ = 0; |
|
kcwu
2015/01/09 10:07:48
maybe some data still remain after current frame?
Pawel Osciak
2015/01/12 07:18:19
Actually we can't use it, since we must be given f
|
| + return true; |
| +} |
| + |
| +size_t VP8Decoder::GetRequiredNumOfPictures() { |
| + static const size_t kVP8NumFramesActive = 4; |
|
kcwu
2015/01/09 10:07:48
no need "static"
Pawel Osciak
2015/01/12 07:18:19
Done.
|
| + static const size_t kPicsInPipeline = media::limits::kMaxVideoFrames + 2; |
|
Owen Lin
2015/01/09 09:56:14
remove static
Pawel Osciak
2015/01/12 07:18:19
Done.
|
| + return kVP8NumFramesActive + kPicsInPipeline; |
| +} |
| + |
| +} // namespace content |