blob: bea9178245bb868ac5d7dd0c090a746ba4b06f9d [file] [edit]
/*
* Copyright 2025 The WebRTC project authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/video_coding/utility/av1_qp_parser.h"
#include <cstdint>
#include <memory>
#include <optional>
#include <span>
#include <vector>
#include "third_party/libgav1/src/src/buffer_pool.h"
#include "third_party/libgav1/src/src/decoder_state.h"
#include "third_party/libgav1/src/src/gav1/decoder.h"
#include "third_party/libgav1/src/src/gav1/status_code.h"
#include "third_party/libgav1/src/src/obu_parser.h"
namespace webrtc {
namespace {
class Av1QpHeaderParser : public Av1QpParser {
public:
Av1QpHeaderParser()
: buffer_pool_(/*on_frame_buffer_size_changed=*/nullptr,
/*get_frame_buffer=*/nullptr,
/*release_frame_buffer=*/nullptr,
/*callback_private_data=*/nullptr) {}
std::optional<uint32_t> Parse(std::span<const uint8_t> frame_data) override {
return Parse(frame_data, 0);
}
std::optional<uint32_t> Parse(std::span<const uint8_t> frame_data,
int operating_point) override {
libgav1::RefCountedBufferPtr curr_frame;
libgav1::ObuParser parser(frame_data.data(), frame_data.size(),
operating_point, &buffer_pool_, &decoder_state_);
std::optional<uint32_t> highest_acceptable_spatial_layers_qp;
// Since the temporal unit can have more than 1 frame in scalable coding, we
// go through all the frame's.
while (parser.HasData()) {
// If the frame is not a keyframe, the `parser` must know the information
// from `sequence_header` to parse the OBU properly.
if (sequence_header_) {
parser.set_sequence_header(*sequence_header_);
}
if (parser.ParseOneFrame(&curr_frame) != libgav1::kStatusOk) {
return std::nullopt;
}
// Get QP from frame header.
const auto& frame_header = parser.frame_header();
// frame_header.quantizer.base_index returns 0 if based on
// `operating_point` we are not interested in higher spatial layer's QP
// values.
if (frame_header.quantizer.base_index != 0) {
highest_acceptable_spatial_layers_qp =
frame_header.quantizer.base_index;
}
// Update the state for the next frame.
if (parser.sequence_header_changed()) {
sequence_header_ = parser.sequence_header();
}
decoder_state_.UpdateReferenceFrames(curr_frame,
frame_header.refresh_frame_flags);
}
return highest_acceptable_spatial_layers_qp;
}
private:
libgav1::BufferPool buffer_pool_;
libgav1::DecoderState decoder_state_;
std::optional<libgav1::ObuSequenceHeader> sequence_header_ = std::nullopt;
};
class Av1QpAverageParser : public Av1QpParser {
public:
Av1QpAverageParser() = default;
std::optional<uint32_t> Parse(std::span<const uint8_t> frame_data) override {
return Parse(frame_data, 0);
}
std::optional<uint32_t> Parse(std::span<const uint8_t> frame_data,
int operating_point) override {
if (!decoder_ || operating_point_ != operating_point) {
libgav1::DecoderSettings settings;
settings.parse_only = true;
settings.operating_point = operating_point;
decoder_ = std::make_unique<libgav1::Decoder>();
if (decoder_->Init(&settings) != libgav1::kStatusOk) {
decoder_.reset();
return std::nullopt;
}
operating_point_ = operating_point;
}
if (decoder_->EnqueueFrame(frame_data.data(), frame_data.size(), 0,
nullptr) != libgav1::kStatusOk) {
return std::nullopt;
}
const libgav1::DecoderBuffer* buffer = nullptr;
if (decoder_->DequeueFrame(&buffer) != libgav1::kStatusOk) {
return std::nullopt;
}
std::vector<int> qps = decoder_->GetFramesMeanQpInTemporalUnit();
if (qps.empty()) {
return std::nullopt;
}
return qps.back();
}
private:
std::unique_ptr<libgav1::Decoder> decoder_;
int operating_point_ = -1;
};
} // namespace
std::unique_ptr<Av1QpParser> Av1QpParser::Create(Settings settings) {
if (settings.use_average_qp) {
return std::make_unique<Av1QpAverageParser>();
}
return std::make_unique<Av1QpHeaderParser>();
}
} // namespace webrtc