Line data Source code
1 : /*
2 : Copyright 2021 Esri
3 : Licensed under the Apache License, Version 2.0 (the "License");
4 : you may not use this file except in compliance with the License.
5 : You may obtain a copy of the License at
6 : http://www.apache.org/licenses/LICENSE-2.0
7 : Unless required by applicable law or agreed to in writing, software
8 : distributed under the License is distributed on an "AS IS" BASIS,
9 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 : See the License for the specific language governing permissions and
11 : limitations under the License.
12 :
13 : QB3 band implementation
14 : QB3 page compression and decompression functions
15 :
16 : Authors: Lucian Plesea
17 : */
18 : #include "marfa.h"
19 : #include <QB3.h>
20 :
21 : NAMESPACE_MRF_START
22 14 : CPLErr QB3_Band::Compress(buf_mgr &dst, buf_mgr &src)
23 : {
24 14 : auto bands = static_cast<size_t>(img.pagesize.c);
25 14 : encsp pQB3 = nullptr;
26 : #define CREATE_QB3(T) \
27 : qb3_create_encoder(img.pagesize.x, img.pagesize.y, bands, qb3_dtype::T)
28 :
29 14 : switch (img.dt)
30 : {
31 9 : case (GDT_Byte):
32 9 : pQB3 = CREATE_QB3(QB3_U8);
33 9 : break;
34 1 : case (GDT_Int16):
35 1 : pQB3 = CREATE_QB3(QB3_I16);
36 1 : break;
37 1 : case (GDT_UInt16):
38 1 : pQB3 = CREATE_QB3(QB3_U16);
39 1 : break;
40 1 : case (GDT_Int32):
41 1 : pQB3 = CREATE_QB3(QB3_I32);
42 1 : break;
43 1 : case (GDT_UInt32):
44 1 : pQB3 = CREATE_QB3(QB3_U32);
45 1 : break;
46 1 : case (GDT_Int64):
47 1 : pQB3 = CREATE_QB3(QB3_I64);
48 1 : break;
49 0 : case (GDT_UInt64):
50 0 : pQB3 = CREATE_QB3(QB3_U64);
51 0 : break;
52 0 : default:
53 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
54 : "MRF:QB3 Data type not supported");
55 0 : return CE_Failure;
56 : }
57 : #undef CREATE_QB3
58 :
59 14 : if (nullptr == pQB3)
60 : {
61 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
62 : "MRF:QB3 Cannot create encoder");
63 0 : return CE_Failure;
64 : }
65 :
66 14 : CPLErr status = CE_None;
67 : try
68 : {
69 14 : if (dst.size < qb3_max_encoded_size(pQB3))
70 : {
71 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
72 : "MRF:QB3 encoded buffer size too small");
73 0 : throw CE_Failure;
74 : }
75 :
76 : // Use independent band compression when by default band 1 is core band
77 15 : if (coreband.empty() && (3 == bands || 4 == bands) &&
78 1 : EQUAL(poMRFDS->GetPhotometricInterpretation(), "MULTISPECTRAL"))
79 : {
80 0 : size_t corebands[] = {0, 1, 2, 3}; // Identity, no core bands
81 0 : qb3_set_encoder_coreband(pQB3, bands, corebands);
82 : }
83 :
84 14 : if (!coreband.empty())
85 1 : qb3_set_encoder_coreband(pQB3, bands, coreband.data());
86 :
87 : // Quality of 90 and above trigger the better encoding
88 14 : qb3_set_encoder_mode(pQB3, (img.quality > 90) ? QB3M_BEST : QB3M_BASE);
89 :
90 : #if defined(QB3_HAS_FTL)
91 : // Quality below 5 triggers the faster encoding, when available
92 14 : if (img.quality < 5)
93 0 : qb3_set_encoder_mode(pQB3, QB3M_FTL);
94 : #endif
95 :
96 14 : dst.size = qb3_encode(pQB3, src.buffer, dst.buffer);
97 14 : if (0 == dst.size)
98 : {
99 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
100 : "MRF:QB3 encoding failed");
101 0 : throw CE_Failure;
102 : }
103 :
104 : // Never happens if qb3_max_encoded doesn't lie
105 14 : if (dst.size > qb3_max_encoded_size(pQB3))
106 : {
107 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
108 : "MRF:QB3 encoded size exceeds limit, check QB3 library");
109 0 : throw CE_Failure;
110 : }
111 : }
112 0 : catch (CPLErr error)
113 : {
114 0 : status = error;
115 : }
116 14 : qb3_destroy_encoder(pQB3);
117 14 : return status;
118 : }
119 :
120 10 : CPLErr QB3_Band::Decompress(buf_mgr &dst, buf_mgr &src)
121 : {
122 : size_t img_size[3];
123 10 : auto pdQB3 = qb3_read_start(src.buffer, src.size, img_size);
124 10 : if (nullptr == pdQB3)
125 : {
126 0 : CPLError(CE_Failure, CPLE_AppDefined,
127 : "MRF: QB3 can't create decoder, is it a valid QB3 stream?");
128 0 : return CE_Failure;
129 : }
130 :
131 10 : CPLErr status = CE_None;
132 : try
133 : {
134 10 : if (img_size[0] != static_cast<size_t>(img.pagesize.x) ||
135 10 : img_size[1] != static_cast<size_t>(img.pagesize.y) ||
136 10 : img_size[2] != static_cast<size_t>(img.pagesize.c))
137 : {
138 0 : CPLError(CE_Failure, CPLE_AppDefined,
139 : "MRF: QB Page has invalid size");
140 0 : throw CE_Failure;
141 : }
142 :
143 10 : if (!qb3_read_info(pdQB3))
144 : {
145 0 : CPLError(CE_Failure, CPLE_AppDefined,
146 : "MRF: QB3 metadata read failure");
147 0 : throw CE_Failure;
148 : }
149 :
150 10 : if (static_cast<size_t>(img.pageSizeBytes) != qb3_decoded_size(pdQB3))
151 : {
152 0 : CPLError(CE_Failure, CPLE_AppDefined,
153 : "MRF: QB3 incorrect decoded tile size");
154 0 : throw CE_Failure;
155 : }
156 :
157 10 : dst.size = qb3_read_data(pdQB3, dst.buffer);
158 10 : if (static_cast<size_t>(img.pageSizeBytes) != dst.size)
159 : {
160 0 : CPLError(CE_Failure, CPLE_AppDefined, "MRF: QB3 decoding error");
161 0 : throw CE_Failure;
162 : }
163 : }
164 0 : catch (CPLErr error)
165 : {
166 0 : status = error;
167 : }
168 10 : qb3_destroy_decoder(pdQB3);
169 10 : return status;
170 : }
171 :
172 53 : QB3_Band::QB3_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
173 53 : : MRFRasterBand(pDS, image, b, level)
174 : {
175 : static_assert(CPL_IS_LSB,
176 : "QB3 is only implemented for little endian architectures");
177 53 : if (image.pageSizeBytes > INT_MAX / 4)
178 : {
179 0 : CPLError(CE_Failure, CPLE_AppDefined, "QB3 page too large");
180 0 : return;
181 : }
182 :
183 53 : if (0 != nBlockXSize % 4 || 0 != nBlockYSize % 4)
184 : {
185 0 : CPLError(CE_Failure, CPLE_NotSupported,
186 : "QB3 page size has to be a multiple of 4");
187 0 : return;
188 : }
189 :
190 53 : if (!GDALDataTypeIsInteger(image.dt) || GDALDataTypeIsComplex(image.dt))
191 : {
192 0 : CPLError(CE_Failure, CPLE_NotSupported,
193 : "Data type not supported by QB3 compression");
194 0 : return;
195 : }
196 :
197 : // Pick up the band map. Comma separated list of bands
198 : // Either identity (core) or derived from a core band.
199 : // Missing entries are assumed to be identity.
200 106 : std::string setting(GetOptionValue("QB3_BAND_MAP", ""));
201 53 : if (image.pagesize.c != 1 && !setting.empty())
202 : {
203 : auto tokens =
204 9 : CSLTokenizeString2(setting.c_str(), ",", CSLT_ALLOWEMPTYTOKENS);
205 9 : coreband.resize(image.pagesize.c);
206 36 : for (int i = 0; i < image.pagesize.c; i++)
207 : {
208 27 : coreband[i] = i;
209 27 : if (tokens && tokens[i] && strlen(tokens[i]) > 0 &&
210 18 : std::isdigit(tokens[i][0]))
211 : {
212 18 : auto c = atoi(tokens[i]);
213 18 : if (c < 0 || c >= image.pagesize.c)
214 : {
215 0 : CPLError(CE_Warning, CPLE_NotSupported,
216 : "Invalid band %d in QB3_BAND_MAP", c);
217 0 : continue;
218 : }
219 18 : coreband[i] = c;
220 : }
221 : }
222 9 : CSLDestroy(tokens);
223 : // Second pass to check that bands are either core or derived
224 36 : for (int i = 0; i < image.pagesize.c; i++)
225 : {
226 27 : const auto c = coreband[i];
227 27 : if (c == static_cast<size_t>(i) || c == coreband[c])
228 27 : continue; // Core band or derived from core band
229 0 : CPLError(CE_Warning, CPLE_NotSupported,
230 : "Band %d in QB3_BAND_MAP is not a core band", i);
231 0 : coreband[i] = i; // Reset to identity
232 : }
233 : }
234 : // Should use qb3_max_encoded_size();
235 :
236 : // Enlarge the page buffer, QB3 may expand data.
237 53 : pDS->SetPBufferSize(2 * image.pageSizeBytes);
238 : }
239 :
240 : NAMESPACE_MRF_END
|