forked from suyu/suyu
Merge pull request #4867 from lioncash/vp9
VP9: Minor interface changes and safety improvements
This commit is contained in:
commit
131a75b65d
3 changed files with 91 additions and 71 deletions
|
@ -21,6 +21,12 @@ public:
|
||||||
explicit Stream();
|
explicit Stream();
|
||||||
~Stream();
|
~Stream();
|
||||||
|
|
||||||
|
Stream(const Stream&) = delete;
|
||||||
|
Stream& operator=(const Stream&) = delete;
|
||||||
|
|
||||||
|
Stream(Stream&&) = default;
|
||||||
|
Stream& operator=(Stream&&) = default;
|
||||||
|
|
||||||
/// Reposition bitstream "cursor" to the specified offset from origin
|
/// Reposition bitstream "cursor" to the specified offset from origin
|
||||||
void Seek(s32 offset, SeekOrigin origin);
|
void Seek(s32 offset, SeekOrigin origin);
|
||||||
|
|
||||||
|
@ -30,15 +36,15 @@ public:
|
||||||
/// Writes byte at current position
|
/// Writes byte at current position
|
||||||
void WriteByte(u8 byte);
|
void WriteByte(u8 byte);
|
||||||
|
|
||||||
std::size_t GetPosition() const {
|
[[nodiscard]] std::size_t GetPosition() const {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8>& GetBuffer() {
|
[[nodiscard]] std::vector<u8>& GetBuffer() {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<u8>& GetBuffer() const {
|
[[nodiscard]] const std::vector<u8>& GetBuffer() const {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,60 @@ constexpr std::array<s32, 254> map_lut{
|
||||||
230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 18, 242, 243, 244, 245, 246, 247,
|
230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 18, 242, 243, 244, 245, 246, 247,
|
||||||
248, 249, 250, 251, 252, 253, 19,
|
248, 249, 250, 251, 252, 253, 19,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 6.2.14 Tile size calculation
|
||||||
|
|
||||||
|
[[nodiscard]] s32 CalcMinLog2TileCols(s32 frame_width) {
|
||||||
|
const s32 sb64_cols = (frame_width + 63) / 64;
|
||||||
|
s32 min_log2 = 0;
|
||||||
|
|
||||||
|
while ((64 << min_log2) < sb64_cols) {
|
||||||
|
min_log2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return min_log2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] s32 CalcMaxLog2TileCols(s32 frame_width) {
|
||||||
|
const s32 sb64_cols = (frame_width + 63) / 64;
|
||||||
|
s32 max_log2 = 1;
|
||||||
|
|
||||||
|
while ((sb64_cols >> max_log2) >= 4) {
|
||||||
|
max_log2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_log2 - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recenters probability. Based on section 6.3.6 of VP9 Specification
|
||||||
|
[[nodiscard]] s32 RecenterNonNeg(s32 new_prob, s32 old_prob) {
|
||||||
|
if (new_prob > old_prob * 2) {
|
||||||
|
return new_prob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_prob >= old_prob) {
|
||||||
|
return (new_prob - old_prob) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (old_prob - new_prob) * 2 - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjusts old_prob depending on new_prob. Based on section 6.3.5 of VP9 Specification
|
||||||
|
[[nodiscard]] s32 RemapProbability(s32 new_prob, s32 old_prob) {
|
||||||
|
new_prob--;
|
||||||
|
old_prob--;
|
||||||
|
|
||||||
|
std::size_t index{};
|
||||||
|
|
||||||
|
if (old_prob * 2 <= 0xff) {
|
||||||
|
index = static_cast<std::size_t>(std::max(0, RecenterNonNeg(new_prob, old_prob) - 1));
|
||||||
|
} else {
|
||||||
|
index = static_cast<std::size_t>(
|
||||||
|
std::max(0, RecenterNonNeg(0xff - 1 - new_prob, 0xff - 1 - old_prob) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return map_lut[index];
|
||||||
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
VP9::VP9(GPU& gpu) : gpu(gpu) {}
|
VP9::VP9(GPU& gpu) : gpu(gpu) {}
|
||||||
|
@ -236,32 +290,6 @@ void VP9::WriteProbabilityDelta(VpxRangeEncoder& writer, u8 new_prob, u8 old_pro
|
||||||
EncodeTermSubExp(writer, delta);
|
EncodeTermSubExp(writer, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 VP9::RemapProbability(s32 new_prob, s32 old_prob) {
|
|
||||||
new_prob--;
|
|
||||||
old_prob--;
|
|
||||||
|
|
||||||
std::size_t index{};
|
|
||||||
|
|
||||||
if (old_prob * 2 <= 0xff) {
|
|
||||||
index = static_cast<std::size_t>(std::max(0, RecenterNonNeg(new_prob, old_prob) - 1));
|
|
||||||
} else {
|
|
||||||
index = static_cast<std::size_t>(
|
|
||||||
std::max(0, RecenterNonNeg(0xff - 1 - new_prob, 0xff - 1 - old_prob) - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return map_lut[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 VP9::RecenterNonNeg(s32 new_prob, s32 old_prob) {
|
|
||||||
if (new_prob > old_prob * 2) {
|
|
||||||
return new_prob;
|
|
||||||
} else if (new_prob >= old_prob) {
|
|
||||||
return (new_prob - old_prob) * 2;
|
|
||||||
} else {
|
|
||||||
return (old_prob - new_prob) * 2 - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VP9::EncodeTermSubExp(VpxRangeEncoder& writer, s32 value) {
|
void VP9::EncodeTermSubExp(VpxRangeEncoder& writer, s32 value) {
|
||||||
if (WriteLessThan(writer, value, 16)) {
|
if (WriteLessThan(writer, value, 16)) {
|
||||||
writer.Write(value, 4);
|
writer.Write(value, 4);
|
||||||
|
@ -361,28 +389,6 @@ void VP9::WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 VP9::CalcMinLog2TileCols(s32 frame_width) {
|
|
||||||
const s32 sb64_cols = (frame_width + 63) / 64;
|
|
||||||
s32 min_log2 = 0;
|
|
||||||
|
|
||||||
while ((64 << min_log2) < sb64_cols) {
|
|
||||||
min_log2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return min_log2;
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 VP9::CalcMaxLog2TileCols(s32 frameWidth) {
|
|
||||||
const s32 sb64_cols = (frameWidth + 63) / 64;
|
|
||||||
s32 max_log2 = 1;
|
|
||||||
|
|
||||||
while ((sb64_cols >> max_log2) >= 4) {
|
|
||||||
max_log2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return max_log2 - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) {
|
Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) {
|
||||||
PictureInfo picture_info{};
|
PictureInfo picture_info{};
|
||||||
gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo));
|
gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo));
|
||||||
|
|
|
@ -25,6 +25,12 @@ public:
|
||||||
VpxRangeEncoder();
|
VpxRangeEncoder();
|
||||||
~VpxRangeEncoder();
|
~VpxRangeEncoder();
|
||||||
|
|
||||||
|
VpxRangeEncoder(const VpxRangeEncoder&) = delete;
|
||||||
|
VpxRangeEncoder& operator=(const VpxRangeEncoder&) = delete;
|
||||||
|
|
||||||
|
VpxRangeEncoder(VpxRangeEncoder&&) = default;
|
||||||
|
VpxRangeEncoder& operator=(VpxRangeEncoder&&) = default;
|
||||||
|
|
||||||
/// Writes the rightmost value_size bits from value into the stream
|
/// Writes the rightmost value_size bits from value into the stream
|
||||||
void Write(s32 value, s32 value_size);
|
void Write(s32 value, s32 value_size);
|
||||||
|
|
||||||
|
@ -37,11 +43,11 @@ public:
|
||||||
/// Signal the end of the bitstream
|
/// Signal the end of the bitstream
|
||||||
void End();
|
void End();
|
||||||
|
|
||||||
std::vector<u8>& GetBuffer() {
|
[[nodiscard]] std::vector<u8>& GetBuffer() {
|
||||||
return base_stream.GetBuffer();
|
return base_stream.GetBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<u8>& GetBuffer() const {
|
[[nodiscard]] const std::vector<u8>& GetBuffer() const {
|
||||||
return base_stream.GetBuffer();
|
return base_stream.GetBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +65,12 @@ public:
|
||||||
VpxBitStreamWriter();
|
VpxBitStreamWriter();
|
||||||
~VpxBitStreamWriter();
|
~VpxBitStreamWriter();
|
||||||
|
|
||||||
|
VpxBitStreamWriter(const VpxBitStreamWriter&) = delete;
|
||||||
|
VpxBitStreamWriter& operator=(const VpxBitStreamWriter&) = delete;
|
||||||
|
|
||||||
|
VpxBitStreamWriter(VpxBitStreamWriter&&) = default;
|
||||||
|
VpxBitStreamWriter& operator=(VpxBitStreamWriter&&) = default;
|
||||||
|
|
||||||
/// Write an unsigned integer value
|
/// Write an unsigned integer value
|
||||||
void WriteU(u32 value, u32 value_size);
|
void WriteU(u32 value, u32 value_size);
|
||||||
|
|
||||||
|
@ -75,10 +87,10 @@ public:
|
||||||
void Flush();
|
void Flush();
|
||||||
|
|
||||||
/// Returns byte_array
|
/// Returns byte_array
|
||||||
std::vector<u8>& GetByteArray();
|
[[nodiscard]] std::vector<u8>& GetByteArray();
|
||||||
|
|
||||||
/// Returns const byte_array
|
/// Returns const byte_array
|
||||||
const std::vector<u8>& GetByteArray() const;
|
[[nodiscard]] const std::vector<u8>& GetByteArray() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Write bit_count bits from value into buffer
|
/// Write bit_count bits from value into buffer
|
||||||
|
@ -99,12 +111,18 @@ public:
|
||||||
explicit VP9(GPU& gpu);
|
explicit VP9(GPU& gpu);
|
||||||
~VP9();
|
~VP9();
|
||||||
|
|
||||||
|
VP9(const VP9&) = delete;
|
||||||
|
VP9& operator=(const VP9&) = delete;
|
||||||
|
|
||||||
|
VP9(VP9&&) = default;
|
||||||
|
VP9& operator=(VP9&&) = delete;
|
||||||
|
|
||||||
/// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec
|
/// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec
|
||||||
/// documentation
|
/// documentation
|
||||||
std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state);
|
std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state);
|
||||||
|
|
||||||
/// Returns true if the most recent frame was a hidden frame.
|
/// Returns true if the most recent frame was a hidden frame.
|
||||||
bool WasFrameHidden() const {
|
[[nodiscard]] bool WasFrameHidden() const {
|
||||||
return hidden;
|
return hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,12 +139,6 @@ private:
|
||||||
/// Generates compressed header probability deltas in the bitstream writer
|
/// Generates compressed header probability deltas in the bitstream writer
|
||||||
void WriteProbabilityDelta(VpxRangeEncoder& writer, u8 new_prob, u8 old_prob);
|
void WriteProbabilityDelta(VpxRangeEncoder& writer, u8 new_prob, u8 old_prob);
|
||||||
|
|
||||||
/// Adjusts old_prob depending on new_prob. Based on section 6.3.5 of VP9 Specification
|
|
||||||
s32 RemapProbability(s32 new_prob, s32 old_prob);
|
|
||||||
|
|
||||||
/// Recenters probability. Based on section 6.3.6 of VP9 Specification
|
|
||||||
s32 RecenterNonNeg(s32 new_prob, s32 old_prob);
|
|
||||||
|
|
||||||
/// Inverse of 6.3.4 Decode term subexp
|
/// Inverse of 6.3.4 Decode term subexp
|
||||||
void EncodeTermSubExp(VpxRangeEncoder& writer, s32 value);
|
void EncodeTermSubExp(VpxRangeEncoder& writer, s32 value);
|
||||||
|
|
||||||
|
@ -146,22 +158,18 @@ private:
|
||||||
/// Write motion vector probability updates. 6.3.17 in the spec
|
/// Write motion vector probability updates. 6.3.17 in the spec
|
||||||
void WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_prob);
|
void WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_prob);
|
||||||
|
|
||||||
/// 6.2.14 Tile size calculation
|
|
||||||
s32 CalcMinLog2TileCols(s32 frame_width);
|
|
||||||
s32 CalcMaxLog2TileCols(s32 frame_width);
|
|
||||||
|
|
||||||
/// Returns VP9 information from NVDEC provided offset and size
|
/// Returns VP9 information from NVDEC provided offset and size
|
||||||
Vp9PictureInfo GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state);
|
[[nodiscard]] Vp9PictureInfo GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state);
|
||||||
|
|
||||||
/// Read and convert NVDEC provided entropy probs to Vp9EntropyProbs struct
|
/// Read and convert NVDEC provided entropy probs to Vp9EntropyProbs struct
|
||||||
void InsertEntropy(u64 offset, Vp9EntropyProbs& dst);
|
void InsertEntropy(u64 offset, Vp9EntropyProbs& dst);
|
||||||
|
|
||||||
/// Returns frame to be decoded after buffering
|
/// Returns frame to be decoded after buffering
|
||||||
Vp9FrameContainer GetCurrentFrame(const NvdecCommon::NvdecRegisters& state);
|
[[nodiscard]] Vp9FrameContainer GetCurrentFrame(const NvdecCommon::NvdecRegisters& state);
|
||||||
|
|
||||||
/// Use NVDEC providied information to compose the headers for the current frame
|
/// Use NVDEC providied information to compose the headers for the current frame
|
||||||
std::vector<u8> ComposeCompressedHeader();
|
[[nodiscard]] std::vector<u8> ComposeCompressedHeader();
|
||||||
VpxBitStreamWriter ComposeUncompressedHeader();
|
[[nodiscard]] VpxBitStreamWriter ComposeUncompressedHeader();
|
||||||
|
|
||||||
GPU& gpu;
|
GPU& gpu;
|
||||||
std::vector<u8> frame;
|
std::vector<u8> frame;
|
||||||
|
@ -169,7 +177,7 @@ private:
|
||||||
std::array<s8, 4> loop_filter_ref_deltas{};
|
std::array<s8, 4> loop_filter_ref_deltas{};
|
||||||
std::array<s8, 2> loop_filter_mode_deltas{};
|
std::array<s8, 2> loop_filter_mode_deltas{};
|
||||||
|
|
||||||
bool hidden;
|
bool hidden = false;
|
||||||
s64 current_frame_number = -2; // since we buffer 2 frames
|
s64 current_frame_number = -2; // since we buffer 2 frames
|
||||||
s32 grace_period = 6; // frame offsets need to stabilize
|
s32 grace_period = 6; // frame offsets need to stabilize
|
||||||
std::array<FrameContexts, 4> frame_ctxs{};
|
std::array<FrameContexts, 4> frame_ctxs{};
|
||||||
|
|
Loading…
Reference in a new issue