summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibVideo/VP9/Decoder.h
blob: 9d219bbe1c5ab3e1668acd188fa4fe8f79994098 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
 * Copyright (c) 2022, Gregory Bertilson <zaggy1024@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/ByteBuffer.h>
#include <AK/Error.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/Queue.h>
#include <AK/Span.h>
#include <LibVideo/Color/CodingIndependentCodePoints.h>
#include <LibVideo/DecoderError.h>
#include <LibVideo/VideoDecoder.h>
#include <LibVideo/VideoFrame.h>

#include "Parser.h"

namespace Video::VP9 {

class Decoder : public VideoDecoder {
    friend class Parser;

public:
    Decoder();
    ~Decoder() override { }
    /* (8.1) General */
    DecoderErrorOr<void> receive_sample(ReadonlyBytes) override;

    DecoderErrorOr<NonnullOwnPtr<VideoFrame>> get_decoded_frame() override;

private:
    typedef i32 Intermediate;

    // Based on the maximum size resulting from num_4x4_blocks_wide_lookup.
    static constexpr size_t maximum_block_dimensions = 64ULL;
    static constexpr size_t maximum_block_size = maximum_block_dimensions * maximum_block_dimensions;
    // Based on the maximum for TXSize.
    static constexpr size_t maximum_transform_size = 32ULL * 32ULL;

    DecoderErrorOr<void> decode_frame(ReadonlyBytes);
    DecoderErrorOr<void> create_video_frame(FrameContext const&);

    DecoderErrorOr<void> allocate_buffers(FrameContext const&);
    Vector<u16>& get_output_buffer(u8 plane);

    /* (8.4) Probability Adaptation Process */
    u8 merge_prob(u8 pre_prob, u32 count_0, u32 count_1, u8 count_sat, u8 max_update_factor);
    u32 merge_probs(int const* tree, int index, u8* probs, u32* counts, u8 count_sat, u8 max_update_factor);
    DecoderErrorOr<void> adapt_coef_probs(FrameContext const&);
    DecoderErrorOr<void> adapt_non_coef_probs(FrameContext const&);
    void adapt_probs(int const* tree, u8* probs, u32* counts);
    u8 adapt_prob(u8 prob, u32 counts[2]);

    /* (8.5) Prediction Processes */
    // (8.5.1) Intra prediction process
    DecoderErrorOr<void> predict_intra(u8 plane, BlockContext const& block_context, u32 x, u32 y, bool have_left, bool have_above, bool not_on_right, TransformSize transform_size, u32 block_index);

    DecoderErrorOr<void> prepare_referenced_frame(Gfx::Size<u32> frame_size, u8 reference_frame_index);

    // (8.5.1) Inter prediction process
    DecoderErrorOr<void> predict_inter(u8 plane, BlockContext const& block_context, u32 x, u32 y, u32 width, u32 height, u32 block_index);
    // (8.5.2.1) Motion vector selection process
    MotionVector select_motion_vector(u8 plane, BlockContext const&, ReferenceIndex, u32 block_index);
    // (8.5.2.2) Motion vector clamping process
    MotionVector clamp_motion_vector(u8 plane, BlockContext const&, u32 block_row, u32 block_column, MotionVector vector);
    // From (8.5.1) Inter prediction process, steps 2-5
    DecoderErrorOr<void> predict_inter_block(u8 plane, BlockContext const&, ReferenceIndex, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index, Span<u16> block_buffer);

    /* (8.6) Reconstruction and Dequantization */

    // Returns the quantizer index for the current block
    static u8 get_base_quantizer_index(BlockContext const&);
    // Returns the quantizer value for the dc coefficient for a particular plane
    static u16 get_dc_quantizer(BlockContext const&, u8 plane);
    // Returns the quantizer value for the ac coefficient for a particular plane
    static u16 get_ac_quantizer(BlockContext const&, u8 plane);

    // (8.6.2) Reconstruct process
    DecoderErrorOr<void> reconstruct(u8 plane, BlockContext const&, u32 transform_block_x, u32 transform_block_y, TransformSize transform_block_size, TransformSet);

    // (8.7) Inverse transform process
    DecoderErrorOr<void> inverse_transform_2d(BlockContext const&, Span<Intermediate> dequantized, u8 log2_of_block_size, TransformSet);

    // (8.7.1) 1D Transforms
    // (8.7.1.1) Butterfly functions

    inline i32 cos64(u8 angle);
    inline i32 sin64(u8 angle);
    // The function B( a, b, angle, 0 ) performs a butterfly rotation.
    inline void butterfly_rotation_in_place(Span<Intermediate> data, size_t index_a, size_t index_b, u8 angle, bool flip);
    // The function H( a, b, 0 ) performs a Hadamard rotation.
    inline void hadamard_rotation_in_place(Span<Intermediate> data, size_t index_a, size_t index_b, bool flip);
    // The function SB( a, b, angle, 0 ) performs a butterfly rotation.
    // Spec defines the source as array T, and the destination array as S.
    template<typename S, typename D>
    inline void butterfly_rotation(Span<S> source, Span<D> destination, size_t index_a, size_t index_b, u8 angle, bool flip);
    // The function SH( a, b ) performs a Hadamard rotation and rounding.
    // Spec defines the source array as S, and the destination array as T.
    template<typename S, typename D>
    inline void hadamard_rotation(Span<S> source, Span<D> destination, size_t index_a, size_t index_b);

    template<typename T>
    inline i32 rounded_right_shift(T value, u8 bits);

    // (8.7.1.10) This process does an in-place Walsh-Hadamard transform of the array T (of length 4).
    inline DecoderErrorOr<void> inverse_walsh_hadamard_transform(Span<Intermediate> data, u8 log2_of_block_size, u8 shift);

    // (8.7.1.2) Inverse DCT array permutation process
    inline DecoderErrorOr<void> inverse_discrete_cosine_transform_array_permutation(Span<Intermediate> data, u8 log2_of_block_size);
    // (8.7.1.3) Inverse DCT process
    inline DecoderErrorOr<void> inverse_discrete_cosine_transform(Span<Intermediate> data, u8 log2_of_block_size);

    // (8.7.1.4) This process performs the in-place permutation of the array T of length 2 n which is required as the first step of
    // the inverse ADST.
    inline void inverse_asymmetric_discrete_sine_transform_input_array_permutation(Span<Intermediate> data, u8 log2_of_block_size);
    // (8.7.1.5) This process performs the in-place permutation of the array T of length 2 n which is required before the final
    // step of the inverse ADST.
    inline void inverse_asymmetric_discrete_sine_transform_output_array_permutation(Span<Intermediate> data, u8 log2_of_block_size);

    // (8.7.1.6) This process does an in-place transform of the array T to perform an inverse ADST.
    inline void inverse_asymmetric_discrete_sine_transform_4(Span<Intermediate> data);
    // (8.7.1.7) This process does an in-place transform of the array T using a higher precision array S for intermediate
    // results.
    inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform_8(Span<Intermediate> data);
    // (8.7.1.8) This process does an in-place transform of the array T using a higher precision array S for intermediate
    // results.
    inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform_16(Span<Intermediate> data);
    // (8.7.1.9) This process performs an in-place inverse ADST process on the array T of size 2 n for 2 ≤ n ≤ 4.
    inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform(Span<Intermediate> data, u8 log2_of_block_size);

    /* (8.10) Reference Frame Update Process */
    DecoderErrorOr<void> update_reference_frames(FrameContext const&);

    NonnullOwnPtr<Parser> m_parser;

    Vector<u16> m_output_buffers[3];

    Queue<NonnullOwnPtr<VideoFrame>, 1> m_video_frame_queue;
};

}