/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.media.codec.h264;
public class H264Utils {
private static final int CLAMP_BASE = 512;
// Array to clamp values in range [0..255]
private static final int clamp[] = new int[CLAMP_BASE * 2 + 256];
private static final int redMap[][] = new int[256][256];
private static final int blueMap[][] = new int[256][256];
private static final int lumaYuvjToYuvTable[] = new int[256];
static {
initClamp();
initRedMap(0xFF);
initBlueMap();
initYuvj();
}
/**
* Initialize array to clamp values in range [0..255]
*/
private static void initClamp() {
for (int i = 0; i < 256; i++) {
clamp[CLAMP_BASE + i] = i;
}
for (int i = 0; i < CLAMP_BASE; i++) {
clamp[i] = 0;
clamp[i + CLAMP_BASE + 256] = 255;
}
}
/**
* The red color component is only depending on the
* luma and Cr components, not Cb.
* Pre-build a map for all possible combinations of
* luma and Cr values.
*
* @param alpha the value of the alpha component [0..255]
*/
private static void initRedMap(int alpha) {
alpha <<= 24;
for (int luma = 0; luma <= 0xFF; luma++) {
for (int cr = 0; cr <= 0xFF; cr++) {
int c = luma - 16;
int e = cr - 128;
int red = (298 * c + 409 * e + 128) >> 8;
red = clamp[red + CLAMP_BASE]; // clamp to [0..255]
redMap[luma][cr] = alpha | red;
}
}
}
/**
* The blue color component is only depending on the
* luma and Cb components, not Cr.
* Pre-build a map for all possible combinations of
* luma and Cb values.
*/
private static void initBlueMap() {
for (int luma = 0; luma <= 0xFF; luma++) {
for (int cb = 0; cb <= 0xFF; cb++) {
int c = luma - 16;
int d = cb - 128;
int blue = (298 * c + 516 * d + 128) >> 8;
blue = clamp[blue + CLAMP_BASE]; // clamp to [0..255]
blueMap[luma][cb] = blue << 16;
}
}
}
private static void initYuvj() {
for (int i = 0; i < 256; i++) {
lumaYuvjToYuvTable[i] = Math.round(i / 255f * 224f + 16f);
}
}
public static void YUV2ARGB(int width, int height, int luma[], int cb[], int cr[], int argb[]) {
// Convert YUV to ABGR
YUV2ABGR(width, height, luma, cb, cr, argb);
// Convert ABGR to ARGB (i.e. switch blue and red color components)
for (int i = 0; i < argb.length; i++) {
int color = argb[i];
color = (color & 0xFF00FF00) | ((color & 0x00FF0000) >> 16) | ((color & 0x000000FF) << 16);
argb[i] = color;
}
}
public static void YUV2ABGR(int width, int height, int luma[], int cb[], int cr[], int abgr[]) {
final int width2 = width >> 1;
int offset = 0;
for (int y = 0; y < height; y++) {
int offset2 = (y >> 1) * width2;
for (int x = 0; x < width; x++, offset++) {
int c = luma[offset] & 0xFF;
int d = cb[offset2 + (x >> 1)] & 0xFF;
int e = cr[offset2 + (x >> 1)] & 0xFF;
// The red and blue color components have been already
// pre-computed.
int red = redMap[c][e];
int blue = blueMap[c][d];
// The green color components is depending on the
// luma, Cr and Cb components. Pre-computing all the
// possible combinations would result in a too high memory
// usage: 256*256*256*4 bytes = 64Mb.
// So compute the green color component here.
c -= 16;
d -= 128;
e -= 128;
int green = (298 * c - 100 * d - 208 * e + 128) >> 8;
green = clamp[green + CLAMP_BASE]; // clamp to [0..255]
abgr[offset] = blue | (green << 8) | red;
}
}
}
public static void setAlpha(int alpha) {
initRedMap(alpha & 0xFF);
}
public static void YUVJ2YUV(int lumaYuvj[], int lumaYuv[], int size) {
for (int i = 0; i < size; i++) {
lumaYuv[i] = lumaYuvjToYuvTable[lumaYuvj[i]];
}
}
public static int findExtradata(int input[], int inputOffset, int inputLength) {
int state = -1;
boolean hasSps = false;
for (int i = 0; i <= inputLength; i++) {
if ((state & 0xFFFFFF1F) == 0x107) {
hasSps = true;
}
/* if ((state&0xFFFFFF1F) == 0x101 ||
* (state&0xFFFFFF1F) == 0x102 ||
* (state&0xFFFFFF1F) == 0x105) {
* }
*/
if ((state & 0xFFFFFF00) == 0x100 && (state & 0xFFFFFF1F) != 0x107 &&
(state & 0xFFFFFF1F) != 0x108 && (state & 0xFFFFFF1F) != 0x109) {
if (hasSps) {
while (i > 4 && input[inputOffset + i - 5] == 0)
i--;
return i - 4;
}
}
if (i < inputLength) {
state = (state << 8) | input[inputOffset + i];
}
}
return 0;
}
}