[go: nahoru, domu]

blob: 7e622602d6fefc2bac44308f03732322c2e3dcdc [file] [log] [blame]
// Copyright 2020 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 "media/gpu/test/video_encoder/bitstream_validator.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/synchronization/waitable_event.h"
#include "media/base/decoder_buffer.h"
#include "media/base/media_switches.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
#include "media/filters/ffmpeg_video_decoder.h"
#include "media/filters/vpx_video_decoder.h"
#include "media/gpu/test/video_encoder/decoder_buffer_validator.h"
#include "media/gpu/test/video_frame_helpers.h"
namespace media {
namespace test {
namespace {
constexpr int64_t kEOSTimeStamp = -1;
std::unique_ptr<VideoDecoder> CreateDecoder(VideoCodec codec) {
std::unique_ptr<VideoDecoder> decoder;
if (codec == kCodecVP8 || codec == kCodecVP9) {
#if BUILDFLAG(ENABLE_LIBVPX)
LOG_ASSERT(!base::FeatureList::IsEnabled(kFFmpegDecodeOpaqueVP8));
decoder = std::make_unique<VpxVideoDecoder>();
#endif
}
if (!decoder) {
#if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
decoder = std::make_unique<FFmpegVideoDecoder>(nullptr);
#endif
}
return decoder;
}
} // namespace
// static
std::unique_ptr<BitstreamValidator> BitstreamValidator::Create(
const VideoDecoderConfig& decoder_config,
size_t last_frame_index,
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors) {
std::unique_ptr<VideoDecoder> decoder;
decoder = CreateDecoder(decoder_config.codec());
if (!decoder)
return nullptr;
auto validator = base::WrapUnique(new BitstreamValidator(
std::move(decoder), last_frame_index, std::move(video_frame_processors)));
if (!validator->Initialize(decoder_config))
return nullptr;
return validator;
}
bool BitstreamValidator::Initialize(const VideoDecoderConfig& decoder_config) {
DCHECK(decoder_);
if (!validator_thread_.Start()) {
LOG(ERROR) << "Failed to start frame validator thread";
return false;
}
bool success = false;
base::WaitableEvent initialized;
VideoDecoder::InitCB init_done = base::BindOnce(
[](bool* result, base::WaitableEvent* initialized, Status status) {
*result = true;
if (!status.is_ok()) {
LOG(ERROR) << "Failed decoder initialization ("
<< static_cast<int32_t>(status.code())
<< "): " << status.message();
}
initialized->Signal();
},
&success, &initialized);
validator_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&BitstreamValidator::InitializeVideoDecoder,
base::Unretained(this), decoder_config,
std::move(init_done)));
initialized.Wait();
return success;
}
void BitstreamValidator::InitializeVideoDecoder(
const VideoDecoderConfig& decoder_config,
VideoDecoder::InitCB init_cb) {
SEQUENCE_CHECKER(validator_thread_sequence_checker_);
decoder_->Initialize(
decoder_config, false, nullptr, std::move(init_cb),
base::BindRepeating(&BitstreamValidator::VerifyOutputFrame,
base::Unretained(this)),
base::NullCallback());
}
BitstreamValidator::BitstreamValidator(
std::unique_ptr<VideoDecoder> decoder,
size_t last_frame_index,
std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors)
: decoder_(std::move(decoder)),
last_frame_index_(last_frame_index),
video_frame_processors_(std::move(video_frame_processors)),
validator_thread_("BitstreamValidatorThread"),
validator_cv_(&validator_lock_),
num_buffers_validating_(0),
decode_error_(false) {
DETACH_FROM_SEQUENCE(validator_sequence_checker_);
DETACH_FROM_SEQUENCE(validator_thread_sequence_checker_);
}
BitstreamValidator::~BitstreamValidator() = default;
void BitstreamValidator::ProcessBitstream(scoped_refptr<BitstreamRef> bitstream,
size_t frame_index) {
DCHECK_CALLED_ON_VALID_SEQUENCE(validator_sequence_checker_);
base::AutoLock lock(validator_lock_);
num_buffers_validating_++;
validator_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&BitstreamValidator::ProcessBitstreamTask,
base::Unretained(this), std::move(bitstream),
frame_index));
}
void BitstreamValidator::ProcessBitstreamTask(
scoped_refptr<BitstreamRef> bitstream,
size_t frame_index) {
SEQUENCE_CHECKER(validator_thread_sequence_checker_);
scoped_refptr<DecoderBuffer> buffer = bitstream->buffer;
int64_t timestamp = buffer->timestamp().InMicroseconds();
decoding_buffers_.Put(timestamp,
std::make_pair(frame_index, std::move(bitstream)));
// Validate the encoded bitstream buffer by decoding its contents using a
// software decoder.
decoder_->Decode(std::move(buffer),
base::BindOnce(&BitstreamValidator::DecodeDone,
base::Unretained(this), timestamp));
if (frame_index == last_frame_index_) {
// Flush pending buffers.
decoder_->Decode(DecoderBuffer::CreateEOSBuffer(),
base::BindOnce(&BitstreamValidator::DecodeDone,
base::Unretained(this), kEOSTimeStamp));
}
}
void BitstreamValidator::DecodeDone(int64_t timestamp, Status status) {
SEQUENCE_CHECKER(validator_thread_sequence_checker_);
if (!status.is_ok()) {
base::AutoLock lock(validator_lock_);
if (!decode_error_) {
decode_error_ = true;
LOG(ERROR) << "DecodeStatus is not OK, status="
<< GetDecodeStatusString(status.code());
}
}
if (timestamp == kEOSTimeStamp) {
return;
}
// This validator and |decoder_| don't use bitstream any more. Release here,
// so that a caller can use the bitstream buffer and proceed.
auto it = decoding_buffers_.Peek(timestamp);
if (it == decoding_buffers_.end()) {
// This occurs when VerifyfOutputFrame() is called before DecodeDone() and
// the entry has been deleted.
return;
}
it->second.second.reset();
}
void BitstreamValidator::VerifyOutputFrame(scoped_refptr<VideoFrame> frame) {
SEQUENCE_CHECKER(validator_thread_sequence_checker_);
auto it = decoding_buffers_.Peek(frame->timestamp().InMicroseconds());
if (it == decoding_buffers_.end()) {
LOG(WARNING) << "Unexpected timestamp: "
<< frame->timestamp().InMicroseconds();
return;
}
size_t frame_index = it->second.first;
decoding_buffers_.Erase(it);
// Send the decoded frame to the configured video frame processors to perform
// additional verification.
for (const auto& processor : video_frame_processors_)
processor->ProcessVideoFrame(frame, frame_index);
base::AutoLock lock(validator_lock_);
num_buffers_validating_--;
validator_cv_.Signal();
}
bool BitstreamValidator::WaitUntilDone() {
base::AutoLock auto_lock(validator_lock_);
while (num_buffers_validating_ > 0)
validator_cv_.Wait();
bool success = true;
for (const auto& processor : video_frame_processors_) {
if (!processor->WaitUntilDone()) {
LOG(ERROR) << "VideoFrameProcessor error";
success = false;
}
}
if (decode_error_) {
LOG(ERROR) << "VideoDecoder error";
success = false;
}
return success;
}
} // namespace test
} // namespace media