| /* | |
| * 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 |