Add facility to read frames in RGB & RGBA format
[imageviewer.git] / chromaResample.cpp
blobbc910aed89e5166b95b07b1d7ecc85641042da06
1 /* ***** BEGIN LICENSE BLOCK *****
3 * $Id$
5 * The MIT License
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
25 * THE SOFTWARE.
27 * ***** END LICENSE BLOCK ***** */
29 #include "chromaResample.h"
30 #include "rawFrame.h"
32 const RawFrame& ChromaResample::process(const RawFrame& src)
34 process_ext(src, _resampled);
35 return _resampled;
38 //change the source chroma sampling
39 void ChromaResample::process_ext(const RawFrame &src, RawFrame &dest)
41 switch (dest.chroma) {
43 case RawFrame::CrRGB:
44 //doh!
45 assert(false);
46 throw;
48 case RawFrame::Cr444:
49 to444(src, dest);
50 break;
52 case RawFrame::Cr422:
53 to422(src, dest);
54 break;
56 case RawFrame::Cr420:
57 to420(src, dest);
58 break;
60 case RawFrame::Cr411:
61 to411(src, dest);
62 break;
64 case RawFrame::YOnly:
65 toYonly(src, dest);
66 break;
70 void ChromaResample::copyArray(const Array2d<int>& src, Array2d<int>& dest)
72 assert(src.width() == dest.width());
73 assert(src.height() == dest.height());
75 dest = src;
78 void ChromaResample::to422(const RawFrame& src, RawFrame& dest)
80 copyArray(src.luma, dest.luma);
82 switch (src.chroma) {
84 case RawFrame::Cr422:
85 //just copy it
86 copyArray(src.cb, dest.cb);
87 copyArray(src.cr, dest.cr);
88 break;
90 case RawFrame::Cr444:
91 //horizontally subsample
92 horizSubsample(src.cb, dest.cb);
93 horizSubsample(src.cr, dest.cr);
94 break;
96 case RawFrame::Cr420:
97 //vertically interpolate
98 vertInterp(src.cb, dest.cb);
99 vertInterp(src.cr, dest.cr);
100 break;
102 case RawFrame::Cr411:
103 //horizontally interpolate
104 horizInterp(src.cb, dest.cb);
105 horizInterp(src.cr, dest.cr);
106 break;
108 case RawFrame::YOnly:
109 dest.cb.assign(0);
110 dest.cr.assign(0);
112 case RawFrame::CrRGB:
113 throw;
115 break;
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);
130 break;
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);
143 break;
145 case RawFrame::Cr420:
146 //just copy it
147 copyArray(src.cb, dest.cb);
148 copyArray(src.cr, dest.cr);
149 break;
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);
162 break;
164 case RawFrame::YOnly:
165 dest.cb.assign(0);
166 dest.cr.assign(0);
167 break;
169 case RawFrame::CrRGB:
170 throw;
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);
184 break;
186 case RawFrame::Cr444:
187 //just copy it
188 copyArray(src.cb, dest.cb);
189 copyArray(src.cr, dest.cr);
190 break;
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);
203 break;
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);
216 break;
218 case RawFrame::YOnly:
219 dest.cb.assign(0);
220 dest.cr.assign(0);
221 break;
223 case RawFrame::CrRGB:
224 throw;
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);
238 break;
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);
251 break;
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);
264 break;
266 case RawFrame::Cr411:
267 //just copy it
268 copyArray(src.cb, dest.cb);
269 copyArray(src.cr, dest.cr);
270 break;
272 case RawFrame::YOnly:
273 dest.cb.assign(0);
274 dest.cr.assign(0);
275 break;
277 case RawFrame::CrRGB:
278 throw;
282 void ChromaResample::toYonly(const RawFrame &src, RawFrame& dest)
284 //input can't be RGB
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) {
305 int C=0;
307 if (pixel>0)
308 C += in[line][pixel-1];
309 else
310 C += in[line][pixel];
312 C+= in[line][pixel] * 2;
314 if (pixel < in.width()-1)
315 C+= in[line][pixel+1];
316 else
317 C+= in[line][pixel];
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++) {
334 int C=0;
336 if (line>0)
337 C += in[line-1][pixel];
338 else
339 C += in[line][pixel];
341 C+= in[line][pixel] * 2;
343 if (line < in.width()-1)
344 C+= in[line+1][pixel];
345 else
346 C+= in[line][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);
360 buffer.assign(0);
362 /* filter */
363 for (int line=0; line<in.height(); line++) {
365 //copy input data
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];
372 //filter
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)
375 >> 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);
386 buffer.assign(0);
388 /* filter */
389 for (int column=0; column<in.width(); column++) {
391 //copy input data
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];
398 //filter
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)
401 >> 1;