PageRenderTime 2ms CodeModel.GetById 215ms app.highlight 18ms RepoModel.GetById 32ms app.codeStats 0ms

/ARViewerAndroid/jni/yuv420sp2rgb/yuv420sp2rgb.c

http://android-ar-base.googlecode.com/
C | 256 lines | 162 code | 32 blank | 62 comment | 10 complexity | 3b7fcf232fc00af63f66d328f07ea3ad MD5 | raw file
  1/* 
  2 * PROJECT: NyARToolkit for Android SDK
  3 * --------------------------------------------------------------------------------
  4 * This work is based on the original ARToolKit developed by
  5 *   Hirokazu Kato
  6 *   Mark Billinghurst
  7 *   HITLab, University of Washington, Seattle
  8 * http://www.hitl.washington.edu/artoolkit/
  9 *
 10 * NyARToolkit for Android SDK
 11 *   Copyright (C)2010 NyARToolkit for Android team
 12 *   Copyright (C)2010 R.Iizuka(nyatla)
 13 *
 14 * This program is free software: you can redistribute it and/or modify
 15 * it under the terms of the GNU General Public License as published by
 16 * the Free Software Foundation, either version 3 of the License, or
 17 * (at your option) any later version.
 18 * 
 19 * This program is distributed in the hope that it will be useful,
 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 22 * GNU General Public License for more details.
 23 *
 24 * You should have received a copy of the GNU General Public License
 25 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 26 * 
 27 * For further information please contact.
 28 *  http://sourceforge.jp/projects/nyartoolkit-and/
 29 *  
 30 * This work is based on the NyARToolKit developed by
 31 *  R.Iizuka (nyatla)
 32 *    http://nyatla.jp/nyatoolkit/
 33 * 
 34 * contributor(s)
 35 *  Atsuo Igarashi
 36 */
 37
 38#include <jni.h>
 39#include <android/log.h>
 40
 41#define  LOG_TAG    "libyuv420sp2rgb"
 42#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
 43#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
 44
 45
 46/*
 47 * derived from development/tools/yuv420sp2rgb/yuv420sp2rgb.c
 48 */
 49#include <unistd.h>
 50
 51#ifndef max
 52#define max(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; })
 53#define min(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; })
 54#endif
 55
 56#define CONVERT_TYPE_PPM 0
 57#define CONVERT_TYPE_RGB 1
 58#define CONVERT_TYPE_ARGB 2
 59
 60/*
 61   YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved
 62   U/V plane containing 8 bit 2x2 subsampled chroma samples.
 63   except the interleave order of U and V is reversed.
 64
 65                        H V
 66   Y Sample Period      1 1
 67   U (Cb) Sample Period 2 2
 68   V (Cr) Sample Period 2 2
 69 */
 70
 71typedef struct rgb_context {
 72    unsigned char *buffer;
 73    int width;
 74    int height;
 75    int rotate;
 76    int i;
 77    int j;
 78    int size; /* for debugging */
 79} rgb_context;
 80
 81typedef void (*rgb_cb)(
 82    unsigned char r,
 83    unsigned char g,
 84    unsigned char b,
 85    rgb_context *ctx);
 86
 87const int bytes_per_pixel = 2;
 88
 89static void color_convert_common(
 90    unsigned char *pY, unsigned char *pUV,
 91    int width, int height,
 92    unsigned char *buffer,
 93    int size, /* buffer size in bytes */
 94    int gray,
 95    int rotate,
 96    rgb_cb cb) 
 97{
 98	int i, j;
 99	int nR, nG, nB;
100	int nY, nU, nV;
101    rgb_context ctx;
102
103    ctx.buffer = buffer;
104    ctx.size = size; /* debug */
105    ctx.width = width;
106    ctx.height = height;
107    ctx.rotate = rotate;
108
109    if (gray) {
110        for (i = 0; i < height; i++) {
111            for (j = 0; j < width; j++) {
112                nB = *(pY + i * width + j);
113                ctx.i = i;
114                ctx.j = j;
115                cb(nB, nB, nB, &ctx);
116            }
117        }	
118    } else {
119        // YUV 4:2:0
120        for (i = 0; i < height; i++) {
121            for (j = 0; j < width; j++) {
122                nY = *(pY + i * width + j);
123                nV = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
124                nU = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
125            
126                // Yuv Convert
127                nY -= 16;
128                nU -= 128;
129                nV -= 128;
130            
131                if (nY < 0)
132                    nY = 0;
133            
134                // nR = (int)(1.164 * nY + 2.018 * nU);
135                // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
136                // nB = (int)(1.164 * nY + 1.596 * nV);
137            
138                nB = (int)(1192 * nY + 2066 * nU);
139                nG = (int)(1192 * nY - 833 * nV - 400 * nU);
140                nR = (int)(1192 * nY + 1634 * nV);
141            
142                nR = min(262143, max(0, nR));
143                nG = min(262143, max(0, nG));
144                nB = min(262143, max(0, nB));
145            
146                nR >>= 10; nR &= 0xff;
147                nG >>= 10; nG &= 0xff;
148                nB >>= 10; nB &= 0xff;
149
150                ctx.i = i;
151                ctx.j = j;
152                cb(nR, nG, nB, &ctx);
153            }
154        }
155    }
156}   
157
158static void common_rgb_cb(
159    unsigned char r,
160    unsigned char g,
161    unsigned char b,
162    rgb_context *ctx,
163    int alpha)
164{
165    unsigned char *out = ctx->buffer;
166    int offset = 0;
167    int bpp;
168    int i = 0;
169    switch(ctx->rotate) {
170    case 0: /* no rotation */
171        offset = ctx->i * ctx->width + ctx->j;
172        break;
173    case 1: /* 90 degrees */
174        offset = ctx->height * (ctx->j + 1) - ctx->i;
175        break;
176    case 2: /* 180 degrees */
177        offset = (ctx->height - 1 - ctx->i) * ctx->width + ctx->j;
178        break;
179    case 3: /* 270 degrees */
180        offset = (ctx->width - 1 - ctx->j) * ctx->height + ctx->i;
181        break;
182    default:
183        //FAILIF(1, "Unexpected roation value %d!\n", ctx->rotate);
184        break;
185    }
186
187    bpp = 3 + !!alpha;
188    offset *= bpp;
189    /*FAILIF(offset < 0, "point (%d, %d) generates a negative offset.\n", ctx->i, ctx->j);
190    FAILIF(offset + bpp > ctx->size, "point (%d, %d) at offset %d exceeds the size %d of the buffer.\n",
191           ctx->i, ctx->j,
192           offset,
193           ctx->size);*/
194
195    out += offset;
196
197    if (alpha) out[i++] = 0xff;
198    out[i++] = r;
199    out[i++] = g;
200    out[i] = b;
201}
202
203static void rgb24_cb(
204    unsigned char r,
205    unsigned char g,
206    unsigned char b,
207    rgb_context *ctx)
208{
209    return common_rgb_cb(r,g,b,ctx,0);
210}
211
212static void argb_cb(
213    unsigned char r,
214    unsigned char g,
215    unsigned char b,
216    rgb_context *ctx)
217{
218    return common_rgb_cb(r,g,b,ctx,1);
219}
220
221JNIEXPORT void JNICALL Java_jp_androidgroup_nyartoolkit_ARToolkitDrawer_decodeYUV420SP(JNIEnv * env, jobject obj, jintArray rgb, jbyteArray yuv420sp, jint width, jint height, jint type)
222{
223    void *in, *out;
224    int psz = getpagesize();
225    int header_size;
226    size_t outsize;
227
228    int bpp = 3;
229    switch (type) {
230    case CONVERT_TYPE_RGB:
231        header_size = 0;
232        break;
233    case CONVERT_TYPE_ARGB:
234        header_size = 0;
235        bpp = 4;
236        break;
237    }
238        
239    outsize = header_size + width * height * bpp;
240    outsize = (outsize + psz - 1) & ~(psz - 1);
241
242    jboolean isCopyIn, isCopyOut;
243    in = (*env)->GetByteArrayElements(env, yuv420sp, &isCopyIn);
244    out = (*env)->GetIntArrayElements(env, rgb, &isCopyOut);
245
246    color_convert_common(in, in + width * height,
247                         width, height, 
248                         out + header_size, outsize - header_size,
249                         0, 0,
250                         type == CONVERT_TYPE_ARGB ? argb_cb : rgb24_cb);
251
252    //if (isCopyIn == JNI_TRUE)
253        (*env)->ReleaseByteArrayElements(env, yuv420sp, in, 0);
254    //if (isCopyOut == JNI_TRUE)
255        (*env)->ReleaseIntArrayElements(env, rgb, out, 0);
256}