blob: 54a869bbebabf8f92b4432773ee1b6a392fea21d [file]
/*
* 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 "third_party/libgav1/src/src/buffer_pool.h"
#include "third_party/libgav1/src/src/decoder_state.h"
#include "third_party/libgav1/src/src/gav1/status_code.h"
#include "third_party/libgav1/src/src/obu_parser.h"
namespace webrtc {
namespace {
class Av1QpParserImpl : public Av1QpParser {
public:
Av1QpParserImpl()
: 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_);
uint8_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;
};
} // namespace
std::unique_ptr<Av1QpParser> Av1QpParser::Create() {
return std::make_unique<Av1QpParserImpl>();
}
} // namespace webrtc