1 /* ***** BEGIN LICENSE BLOCK *****
7 * Copyright (c) 2008 BBC Research
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * ***** END LICENSE BLOCK ***** */
29 #include "chromaResample.h"
32 const RawFrame
& ChromaResample::process(const RawFrame
& src
)
34 process_ext(src
, _resampled
);
38 //change the source chroma sampling
39 void ChromaResample::process_ext(const RawFrame
&src
, RawFrame
&dest
)
41 switch (dest
.chroma
) {
70 void ChromaResample::copyArray(const Array2d
<int>& src
, Array2d
<int>& dest
)
72 assert(src
.width() == dest
.width());
73 assert(src
.height() == dest
.height());
78 void ChromaResample::to422(const RawFrame
& src
, RawFrame
& dest
)
80 copyArray(src
.luma
, dest
.luma
);
86 copyArray(src
.cb
, dest
.cb
);
87 copyArray(src
.cr
, dest
.cr
);
91 //horizontally subsample
92 horizSubsample(src
.cb
, dest
.cb
);
93 horizSubsample(src
.cr
, dest
.cr
);
97 //vertically interpolate
98 vertInterp(src
.cb
, dest
.cb
);
99 vertInterp(src
.cr
, dest
.cr
);
102 case RawFrame::Cr411
:
103 //horizontally interpolate
104 horizInterp(src
.cb
, dest
.cb
);
105 horizInterp(src
.cr
, dest
.cr
);
108 case RawFrame::YOnly
:
112 case RawFrame::CrRGB
:
119 void ChromaResample::to420(const RawFrame
& src
, RawFrame
& dest
)
121 copyArray(src
.luma
, dest
.luma
);
123 switch (src
.chroma
) {
125 case RawFrame::Cr422
:
126 //vertically subsample
127 vertSubsample(src
.cb
, dest
.cb
);
128 vertSubsample(src
.cr
, dest
.cr
);
132 case RawFrame::Cr444
:
134 Array2d
<int> hsub(src
.luma
.width()/2, src
.luma
.height());
136 //horizontally then vertically subsample
137 horizSubsample(src
.cb
, hsub
);
138 vertSubsample(hsub
, dest
.cb
);
140 horizSubsample(src
.cr
, hsub
);
141 vertSubsample(hsub
, dest
.cr
);
145 case RawFrame::Cr420
:
147 copyArray(src
.cb
, dest
.cb
);
148 copyArray(src
.cr
, dest
.cr
);
151 case RawFrame::Cr411
:
153 Array2d
<int> hinterp(src
.luma
.width()*2, src
.luma
.height());
155 //horizontally interpolate then vertically subsample
156 horizInterp(src
.cb
, hinterp
);
157 vertSubsample(hinterp
, dest
.cb
);
159 horizInterp(src
.cr
, hinterp
);
160 vertSubsample(hinterp
, dest
.cr
);
164 case RawFrame::YOnly
:
169 case RawFrame::CrRGB
:
174 void ChromaResample::to444(const RawFrame
& src
, RawFrame
& dest
)
176 copyArray(src
.luma
, dest
.luma
);
178 switch (src
.chroma
) {
180 case RawFrame::Cr422
:
181 //interpolate horizontally
182 horizInterp(src
.cb
, dest
.cb
);
183 horizInterp(src
.cr
, dest
.cr
);
186 case RawFrame::Cr444
:
188 copyArray(src
.cb
, dest
.cb
);
189 copyArray(src
.cr
, dest
.cr
);
192 case RawFrame::Cr420
:
194 Array2d
<int> vinterp(src
.luma
.width()/2, src
.luma
.height());
196 //vertically then horizontally interpolate
197 vertInterp(src
.cb
, vinterp
);
198 horizInterp(vinterp
, dest
.cb
);
200 vertInterp(src
.cr
, vinterp
);
201 horizInterp(vinterp
, dest
.cr
);
205 case RawFrame::Cr411
:
207 Array2d
<int> hinterp(src
.luma
.width()/2, src
.luma
.height());
209 //horizontally interpolate twice
210 horizInterp(src
.cb
, hinterp
);
211 horizInterp(hinterp
, dest
.cb
);
213 horizInterp(src
.cr
, hinterp
);
214 horizInterp(hinterp
, dest
.cr
);
218 case RawFrame::YOnly
:
223 case RawFrame::CrRGB
:
228 void ChromaResample::to411(const RawFrame
& src
, RawFrame
& dest
)
230 copyArray(src
.luma
, dest
.luma
);
232 switch (src
.chroma
) {
234 case RawFrame::Cr422
:
235 //subsample horizontally
236 horizSubsample(src
.cb
, dest
.cb
);
237 horizSubsample(src
.cr
, dest
.cr
);
240 case RawFrame::Cr444
:
242 Array2d
<int> hsub(src
.luma
.width()/2, src
.luma
.height());
244 //subsample horizontally twice
245 horizSubsample(src
.cb
, hsub
);
246 horizSubsample(hsub
, dest
.cb
);
248 horizSubsample(src
.cr
, hsub
);
249 horizSubsample(hsub
, dest
.cr
);
253 case RawFrame::Cr420
:
255 Array2d
<int> vinterp(src
.luma
.width()*2, src
.luma
.height());
257 //interpolate vertically then subsample horizontally
258 vertInterp(src
.cb
, vinterp
);
259 horizSubsample(vinterp
, dest
.cb
);
261 vertInterp(src
.cr
, vinterp
);
262 horizSubsample(vinterp
, dest
.cr
);
266 case RawFrame::Cr411
:
268 copyArray(src
.cb
, dest
.cb
);
269 copyArray(src
.cr
, dest
.cr
);
272 case RawFrame::YOnly
:
277 case RawFrame::CrRGB
:
282 void ChromaResample::toYonly(const RawFrame
&src
, RawFrame
& dest
)
285 assert(src
.chroma
!= RawFrame::CrRGB
);
287 //no conversion required
288 copyArray(src
.luma
, dest
.luma
);
291 //filtering functions
292 void ChromaResample::horizSubsample(const Array2d
<int>& in
, Array2d
<int>& out
)
294 //FIXME - this needs rewriting like the interpolator code and testing
296 assert(in
.width() / 2 == out
.width());
297 assert(in
.height() == out
.height());
299 Array1d
<int> buffer(in
.width()+2);
301 for (int line
=0; line
<in
.height(); line
++) {
303 for (int pixel
= 0; pixel
<in
.width(); pixel
+=2) {
308 C
+= in
[line
][pixel
-1];
310 C
+= in
[line
][pixel
];
312 C
+= in
[line
][pixel
] * 2;
314 if (pixel
< in
.width()-1)
315 C
+= in
[line
][pixel
+1];
319 out
[line
][pixel
/2] = C
;
324 void ChromaResample::vertSubsample(const Array2d
<int>& in
, Array2d
<int> &out
)
326 //FIXME - this needs rewriting like the interpolator code and testing
328 assert(in
.width() == out
.width());
329 assert(in
.height() / 2 == out
.height());
331 for (int line
=0; line
<in
.height(); line
+=2) {
332 for (int pixel
= 0; pixel
<in
.width(); pixel
++) {
337 C
+= in
[line
-1][pixel
];
339 C
+= in
[line
][pixel
];
341 C
+= in
[line
][pixel
] * 2;
343 if (line
< in
.width()-1)
344 C
+= in
[line
+1][pixel
];
348 out
[line
/2][pixel
] = C
;
354 void ChromaResample::horizInterp(const Array2d
<int>& in
, Array2d
<int>& out
)
356 assert(in
.width() == out
.width() / 2);
357 assert(in
.height() == out
.height());
359 Array1d
<int> buffer(out
.width()+2);
363 for (int line
=0; line
<in
.height(); line
++) {
366 for (int pixel
=0, x
=1; pixel
<in
.width(); pixel
++, x
+=2)
367 buffer
[x
] = in
[line
][pixel
];
369 //edge extend to get the last pixel correct
370 buffer
[out
.width() + 1] = in
[line
][in
.width() - 1];
373 for (int pixel
=0, x
=1; pixel
<out
.width(); pixel
++, x
++) {
374 out
[line
][pixel
] = (buffer
[x
-1] + 2*buffer
[x
] + buffer
[x
+1] + 1)
380 void ChromaResample::vertInterp(const Array2d
<int>& in
, Array2d
<int> &out
)
382 assert(in
.width() == out
.width());
383 assert(in
.height() == out
.height() / 2);
385 Array1d
<int> buffer(out
.height()+2);
389 for (int column
=0; column
<in
.width(); column
++) {
392 for (int pixel
=0, x
=1; x
<out
.height(); pixel
++, x
+=2)
393 buffer
[x
] = in
[pixel
][column
];
395 //edge extend to get the last pixel correct
396 buffer
[out
.height() + 1] = in
[in
.height() - 1][column
];
399 for (int pixel
=0, x
=1; pixel
<out
.height(); pixel
++, x
++)
400 out
[pixel
][column
] = (buffer
[x
-1] + 2*buffer
[x
] + buffer
[x
+1] + 1)