summaryrefslogtreecommitdiff
path: root/gpr/source/lib/vc5_encoder/sections.c
blob: 47efc0d92d5877c830031e70a94db3193f0739eb (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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/*! @file sections.c
 *
 *  @brief Implementation of code for encoding sections
 *
 *  (C) Copyright 2018 GoPro Inc (http://gopro.com/).
 *
 *  Licensed under either:
 *  - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
 *  - MIT license, http://opensource.org/licenses/MIT
 *  at your option.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "headers.h"

#if VC5_ENABLED_PART(VC5_PART_SECTIONS)

/*
 @brief Write codec state parameters used for decoding the section into the bitstream
 
 A section element may be decoded independently from other sections of the same type.
 Concurrent decoding implies that all codec state parameters needed to decode a section
 element be present in that section element.
 
 In principle, it is only necessary to write the codec state parameters that may be changed
 as other section elements are decoded independently.  This sample encoder takes the simple
 approach and writes all non-header codec state parameters into the bitstream.
 */
static CODEC_ERROR PutCodecState(ENCODER *encoder, BITSTREAM *stream, SECTION_NUMBER section_number)
{
    CODEC_STATE *codec = &encoder->codec;
    TAGWORD prescale_shift = 0;
    
    switch (section_number)
    {
        case SECTION_NUMBER_IMAGE:
            assert(0);
            break;
            
        case SECTION_NUMBER_HEADER:
            // No codec state parameters to be written into the bitstream
            break;
            
        case SECTION_NUMBER_CHANNEL:
            // Encode the transform prescale for the first channel (assume all channels are the same)
            prescale_shift = PackTransformPrescale(&encoder->transform[0]);
            
            PutTagPair(stream, CODEC_TAG_ChannelNumber, codec->channel_number);
            PutTagPair(stream, CODEC_TAG_SubbandNumber, codec->subband_number);
            PutTagPair(stream, CODEC_TAG_LowpassPrecision, codec->lowpass_precision);
            PutTagPair(stream, CODEC_TAG_Quantization, codec->band.quantization);
            PutTagPair(stream, CODEC_TAG_PrescaleShift, prescale_shift);
            
#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
            if (!IsPartEnabled(encoder->enabled_parts, VC5_PART_IMAGE_FORMATS))
            {
                PutTagPair(stream, CODEC_TAG_ChannelWidth, codec->channel_width);
                PutTagPair(stream, CODEC_TAG_ChannelHeight, codec->channel_height);
            }
#endif
#if VC5_ENABLED_PART(VC5_PART_LAYERS)
            if (IsPartEnabled(encoder->enabled_parts, VC5_PART_LAYERS))
            {
                PutTagPair(stream, CODEC_TAG_LayerNumber, codec->layer_number);
            }
#endif
            break;
            
        case SECTION_NUMBER_WAVELET:
            PutTagPair(stream, CODEC_TAG_ChannelNumber, codec->channel_number);
            PutTagPair(stream, CODEC_TAG_SubbandNumber, codec->subband_number);
            PutTagPair(stream, CODEC_TAG_LowpassPrecision, codec->lowpass_precision);
            //PutTagPair(stream, CODEC_TAG_Quantization, codec->band.quantization);
            //PutTagPair(stream, CODEC_TAG_PrescaleShift, prescale_shift);
            break;
            
        case SECTION_NUMBER_SUBBAND:
            PutTagPair(stream, CODEC_TAG_ChannelNumber, codec->channel_number);
            PutTagPair(stream, CODEC_TAG_SubbandNumber, codec->subband_number);
            PutTagPair(stream, CODEC_TAG_LowpassPrecision, codec->lowpass_precision);
            PutTagPair(stream, CODEC_TAG_Quantization, codec->band.quantization);
            //PutTagPair(stream, CODEC_TAG_PrescaleShift, prescale_shift);
            break;
            
        default:
            assert(0);
            return CODEC_ERROR_UNEXPECTED;
    }
    
    return CODEC_ERROR_OKAY;
}

/*
    @brief Return true if specified type of section is enabled
 */
bool IsSectionEnabled(ENCODER *encoder, SECTION_NUMBER section_number)
{
    if (IsPartEnabled(encoder->enabled_parts, VC5_PART_SECTIONS))
    {
        if (SECTION_NUMBER_MINIMUM <= section_number && section_number <= SECTION_NUMBER_MAXIMUM)
        {
            uint32_t section_mask = SECTION_NUMBER_MASK(section_number);
            
            if (encoder->enabled_sections & section_mask) {
                return true;
            }
        }
    }

    // None of the predefined VC-5 sections are enabled
    return false;
}

/*
    @brief Start a new section with the specified tag
 
    The location of the the tag-value pair that marks the beginning of the new
    section is pushed onto a stack so that the tag-value pair can be updated with
    the actual size of the section when the section is ended by a call to the
    @ref EndSection function.
 */
CODEC_ERROR BeginSection(BITSTREAM *bitstream, TAGWORD tag)
{
    return PushSampleSize(bitstream, tag);
}

/*
    @brief End a section
 
    Update the tag-value pair that marks the section with the actual size of the section.
 */
CODEC_ERROR EndSection(BITSTREAM *bitstream)
{
    return PopSampleSize(bitstream);
}

/*!
    @brief Write an image section header into the bitstream
 */
CODEC_ERROR BeginImageSection(struct _encoder *encoder, BITSTREAM *stream)
{
    assert(0);
    return CODEC_ERROR_OKAY;
}

/*
    @brief Write a section header for the bitstream header into the bitstream
 */
CODEC_ERROR BeginHeaderSection(struct _encoder *encoder, BITSTREAM *stream)
{
    // Write the section header for the bitstream header into the bitstream
    return BeginSection(stream, CODEC_TAG_HeaderSectionTag);
}

/*
    @brief Write a layer section header into the bitstream
     
    Any codec state parameters that are required to decode the layer must be explicitly
    written into the bitstream so that the layer sections and be decoded concurrently.
 */
CODEC_ERROR BeginLayerSection(struct _encoder *encoder, BITSTREAM *stream)
{
    CODEC_ERROR error = CODEC_ERROR_OKAY;
    
    // Duplicate all codec state parameters required for decoding the layer
    PutCodecState(encoder, stream, SECTION_NUMBER_LAYER);
    
    // Write the section header for the layer into the bitstream
    error = BeginSection(stream, CODEC_TAG_LayerSectionTag);
    
    return error;
}

/*
    @brief Write a channel section header into the bitstream
 
    Any codec state parameters that are required to decode the channel must be explicitly
    written into the bitstream so that the channel sections and be decoded concurrently.
 */
CODEC_ERROR BeginChannelSection(ENCODER *encoder, BITSTREAM *stream)
{
    CODEC_ERROR error = CODEC_ERROR_OKAY;
    
    // Duplicate all codec state parameters required for decoding the channel
    PutCodecState(encoder, stream, SECTION_NUMBER_CHANNEL);
    
    // Write the section header for the channel into the bitstream
    error = BeginSection(stream, CODEC_TAG_ChannelSectionTag);
    
    return error;
}

/*
    @brief Write a wavelet section header into the bitstream
     
    Any codec state parameters that are required to decode the wavelet must be explicitly
    written into the bitstream so that the wavelet sections and be decoded concurrently.
 */
CODEC_ERROR BeginWaveletSection(struct _encoder *encoder, BITSTREAM *stream)
{
    CODEC_ERROR error = CODEC_ERROR_OKAY;
    
    // Duplicate all codec state parameters required for decoding the wavelet
    PutCodecState(encoder, stream, SECTION_NUMBER_WAVELET);
    
    // Write the section header for the wavelet into the bitstream
    error = BeginSection(stream, CODEC_TAG_WaveletSectionTag);
    
    return error;
}

/*
    @brief Write a subband section header into the bitstream
     
    Any codec state parameters that are required to decode the subband must be explicitly
    written into the bitstream so that the subband sections and be decoded concurrently.
 */
CODEC_ERROR BeginSubbandSection(struct _encoder *encoder, BITSTREAM *stream)
{
    CODEC_ERROR error = CODEC_ERROR_OKAY;
    
    // Duplicate all codec state parameters required for decoding the subband
    PutCodecState(encoder, stream, SECTION_NUMBER_SUBBAND);
    
    // Write the section header for the subband into the bitstream
    error = BeginSection(stream, CODEC_TAG_SubbandSectionTag);
    
    return error;
}

/*!
	@brief Set the flags that indicate which sections in VC-5 Part 6 are enabled
 
	The argument is a list of comma-separated integers for the section numbers
 in the VC-5 Part 2 conformance specification that are enabled for this invocation
 of the encoder.
 
 Note: Enabling sections at runtime has no effect unless support for sections
 is compiled into the program by enabling the corresponding compile-time switch
 for VC-5 part 6 (sections).
 */
bool GetEnabledSections(const char *string, uint32_t *enabled_sections_out)
{
    if (string != NULL && enabled_sections_out != NULL)
    {
        // No sections are enabled by default
        ENABLED_SECTIONS enabled_sections = 0;
        
        const char *p = string;
        assert(p != NULL);
        while (*p != '\0')
        {
            char *q = NULL;
            long section_number;
            if (!isdigit((int)*p)) break;
            section_number = strtol(p, &q, 10);
            
            // Is the section number in bounds?
            if (SECTION_NUMBER_MINIMUM <= section_number && section_number <= SECTION_NUMBER_MAXIMUM)
            {
                // Set the bit that corresponds to this section number
                enabled_sections |= SECTION_NUMBER_MASK(section_number);
                
                // Advance to the next section number in the command-line argument
                p = (*q != '\0') ? q + 1 : q;
            }
            else
            {
                // Invalid section number
                assert(0);
                return false;
            }
        }
        
        // Return the bit mask for the enabled sections
        *enabled_sections_out = enabled_sections;
        
        // Should have parsed all section numbers in the argument string
        assert(*p == '\0');
        return true;
    }
    
    // Invalid input arguments
    return false;
}


#endif