/*
ImageUtils.java
Copyright (c) 2015 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.webrtc.util;
import android.graphics.Bitmap;
import java.nio.ByteBuffer;
/**
* Utility for image transformation.
*
* @author NTT DOCOMO, INC.
*/
public final class ImageUtils {
static {
System.loadLibrary("ImageUtils");
}
private ImageUtils() {
}
/**
* Resize the bitmap.
* <p>
* If bitmap is null, return null.
* </p>
* <p>
* Notice: If the bitmap is resized , the original bitmap is recycled.
* </p>
* @param bitmap bitmap
* @return Resized the bitmap
*/
public static Bitmap resize(final Bitmap bitmap) {
if (bitmap == null) {
return null;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int w = roundUp(width, 16);
int h = roundUp(height, 16);
if (w != width || h != height) {
Bitmap b = Bitmap.createScaledBitmap(bitmap, w, h, false);
// the original bitmap is recycled
bitmap.recycle();
return b;
}
return bitmap;
}
/**
* Create the yuv buffer by Bitmap.
* @param bitmap bitmap
* @return yuv buffer
*/
public static byte[] createBuffer(final Bitmap bitmap) {
return createBuffer(bitmap.getWidth(), bitmap.getHeight());
}
/**
* Create the yuv buffer.
* @param width width
* @param height height
* @return yuv buffer
*/
public static byte[] createBuffer(final int width, final int height) {
int frameSize = frameSize(width, height);
byte[] yuv = new byte[frameSize];
return yuv;
}
/**
* Converts the ARGB to YV12.
* <p>
* Notice: This format assumes
* <ul>
* <li>an even width</li>
* <li>an even height</li>
* <li>a horizontal stride multiple of 16 pixels.</li>
* </ul>
* </p>
* @param outData output
* @param argb RGB
* @param width width
* @param height height
*/
public static void argbToYV12(final byte[] outData, final int[] argb, final int width, final int height) {
nativeEncodeYV12(outData, argb, width, height);
}
/**
* Converts the bitmap to YV12.
* <p>
* Notice: This format assumes
* <ul>
* <li>an even width</li>
* <li>an even height</li>
* <li>a horizontal stride multiple of 16 pixels.</li>
* </ul>
* </p>
* @param bitmap bitmap
* @param outData output
*/
public static void bitmapToYV12(final Bitmap bitmap, final byte[] outData) {
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
int[] argb = new int[width * height];
bitmap.getPixels(argb, 0, width, 0, 0, width, height);
nativeEncodeYV12(outData, argb, width, height);
}
/**
* Converts the ARGB to yuv420sp.
* @param yuv420sp Array for storing output data
* @param argb Array for argb
* @param width width
* @param height height
*/
private static native void nativeEncodeYV12(final byte[] yuv420sp, final int[] argb, final int width, final int height);
/**
* Calculates the frame size from width and height.
* @param width width
* @param height height
* @return frame size
*/
private static int frameSize(int width, int height) {
int yStride = roundUp(width, 16);
int uvStride = roundUp(yStride / 2, 16);
int ySize = yStride * height;
int uvSize = uvStride * height / 2;
return ySize + uvSize * 2;
}
/**
* Rounded up number.
* @param x number
* @param alignment alignment
* @return number
*/
private static int roundUp(int x, int alignment) {
return (int) Math.ceil(x / (double) alignment) * alignment;
}
public static void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0;
else if (r > 262143) r = 262143;
if (g < 0) g = 0;
else if (g > 262143) g = 262143;
if (b < 0) b = 0;
else if (b > 262143) b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
}
public static void decodeYUV420SP(Bitmap bitmap, byte[] yuv420sp, int width, int height) {
nativeDecodeYUV420SP(bitmap, yuv420sp, width, height);
}
private static native void nativeDecodeYUV420SP(Bitmap bitmap, byte[] yuv420sp, int width, int height);
public static void decodeYUV420SP2(Bitmap bitmap, ByteBuffer yuv420sp, int width, int height) {
nativeDecodeYUV420SP2(bitmap, yuv420sp, width, height);
}
private static native void nativeDecodeYUV420SP2(Bitmap bitmap, ByteBuffer yuv420sp, int width, int height);
public static void decodeYUV420SP3(Bitmap bitmap, ByteBuffer[] yuv420sp, int width, int height, int[] strides) {
if (strides[0] != width) {
nativeDecodeYUV420SP4(bitmap, yuv420sp, width, height, strides);
} else if (strides[1] != width / 2) {
nativeDecodeYUV420SP4(bitmap, yuv420sp, width, height, strides);
} else if (strides[2] != width / 2) {
nativeDecodeYUV420SP4(bitmap, yuv420sp, width, height, strides);
} else {
nativeDecodeYUV420SP3(bitmap, yuv420sp, width, height);
}
}
private static native void nativeDecodeYUV420SP3(Bitmap bitmap, ByteBuffer[] yuv420sp, int width, int height);
private static native void nativeDecodeYUV420SP4(Bitmap bitmap, ByteBuffer[] yuv420sp, int width, int height, int[] strides);
}