Tistory View
Android NDK Access memory of Bitmap directly
YV12 Structure
YV12 has separeted planes of Y, U and V. Y demension is identical to image, U and V plane has demension of half of image width and height. Colors of pixels are composed like next. 4Y share 1 UV.
YV21 6x4 image(not considering of padding)
[Y00][Y01][Y02][Y03][Y04][Y05]
[Y06][Y07][Y08][Y09][Y10][Y11]
[Y12][Y13][Y14][Y15][Y16][Y17]
[Y18][Y19][Y20][Y21][Y22][Y23]
+
[V0][V1][V2]
[V2][V3][V2]
+
[U0][U1][U2]
[U2][U3][U2]
YV12 STRIDE
NV21 has no paddings, but YV12 has padding, so, must compute this first.
fomulas( asume only even w and h )
y_stride = ALIGN(w, 16)
y_size = stride * height
c_stride = ALIGN(stride/2, 16) // U and V plane stride
c_size = c_stride * height/2
size = y_size + c_size * 2 // Total YV12 bytes size
v_offset = y_size
u_offset = y_size + c_size
There are y_stride, and also c_stride, These must be aligned by 16bytes. by this, YV12 has paddings
It's Convinience when make fomulas like next.
Demension info in C/C++
struct YV12DemensionInfo {
int w; // image w
int h; // image h
int strideY; // Y Plane stride
int strideC; // UV Plane stride( c is by Cr, Cb)
int offsetV; // offset of V
int offsetU; // offset of U
int yPlaneW; // Y Plane W : same to image W
int yPlaneH; // Y Plane H : same to image H
int cPlaneW; // UV Plane Width
int cPlaneH; // UV Plane Height
int yPlaneSize; // Y Plane byte size
int uvPlaneSize; // UV Plane byte size
int totalBytes; // total byte size of YV12
};
void computeYVDemensionInfo( YV12DemensionInfo* p, int w, int h )
{
int pad;
int strideYPlane;
int strideCPlane; // UV plane stide(Cr,Cb)
pad = 16 - w % 16;
if( pad == 16 ) {
pad = 0;
}
strideYPlane = w + pad;
pad = 16 - ( strideYPlane / 2 ) % 16;
if( pad == 16 ) pad = 0;
strideCPlane = ( strideYPlane / 2 ) + pad;
p->w = w;
p->h = h;
p->yPlaneW = w;
p->yPlaneH = h;
p->cPlaneW = strideYPlane / 2;
p->cPlaneH = h / 2;
p->strideY = strideYPlane;
p->strideC = strideCPlane;
p->offsetV = strideYPlane * h;
p->offsetU = strideYPlane * h + strideCPlane * (h / 2);
p->yPlaneSize = strideYPlane * h;
p->uvPlaneSize = strideCPlane * (h / 2);
p->totalBytes = p->yPlaneSize + p->uvPlaneSize * 2;
}
Let't calculate by hand, where image has demension of 176x144
strIdeYPlane = 176 // 16 * 11, no remainer no padding
width = 176;
height = 144;
yPlaneW = 176;
yPlaneH = 144;
cPlaneW = 176 / 2 = 88;
cPlaneH = 144 / 2 = 72;
88( 16 * 5 + 8 ) % 16
strideC => = 88 + ( 16 - 8 ) = 96; <- padding 8
offsetV = 176 * 144= 25344;
offsetU =176 * 144 + 96 * 72 = 25344 + 6912 = 32256;
yPlanSize = 176 * 144 = 25344;
uvPlaneSize = 96 * 72;
totalBytes = 25344 + 6912 * 2 = 39168;
If your camera on android device support previewSize, 176x144, If not considering padding, image shows like next
YV12 Structure in considering padding
onPreviewFrame of Camera api(1), image of 6X4 is reached as next.
[Y00][Y01][Y02][Y03][Y04][Y05][padding 10Bytes]
[Y06][Y07][Y08][Y09][Y10][Y11][padding 10Bytes]
[Y12][Y13][Y14][Y15][Y16][Y17][padding 10Bytes]
[Y18][Y19][Y20][Y21][Y22][Y23][padding 10Bytes]
+
[V0][V1][V2][padding 13Bytes]
[V2][V3][V2][padding 13Bytes]
+
[U0][U1][U2][padding 13Bytes]
[U2][U3][U2][padding 13Bytes]
The code of Converting YV12 to RGB(A)
inline uint8_t clamp16bits( int v )
{
v >>= 16;
// most case 1 ~ 255
if( ( v & 0xffffff00 ) == 0 ) {
return v;
}
if( v <= 0 ) return 0;
return 255;
}
void image_yv12_to_rgba( uint8_t* dst, uint8_t* yv12, int w, int h, int nThread )
{
const int strideDst = w*4; // in byte
YV12DemensionInfo demInfo;
computeYVDemensionInfo( &demInfo, w, h );
for( int y = 0 ; y < demInfo.cPlaneH ; y++ )
{
uint8_t* pSrcY1 = yv12 + ( y * 2 ) * demInfo.strideY;
uint8_t* pSrcY2 = pSrcY1 + demInfo.strideY;
uint8_t* pSrcV = yv12 + demInfo.offsetV + y * demInfo.strideC;
uint8_t* pSrcU = yv12 + demInfo.offsetU + y * demInfo.strideC;
uint8_t* pd1 = dst + y * 2 * strideDst;
uint8_t* pd2 = pd1 + strideDst;
for( int x = 0 ; x < demInfo.cPlaneW ; x++ )
{
const int cU = (int)pSrcU[0] - 128;
const int cV = (int)pSrcV[0] - 128;
const int f1 = 89831 * cV; // 1.370705F * 65536 * ( (int)cV - 128 );
const int f2 = -45744 * cV -22127 * cU;
const int f3 = 113538 * cU; // 1.732446F * 65536 * ( (int)cU - 128 );
int _y;
_y = pSrcY1[0] << 16;
pd1[0] = clamp16bits( _y + f1 ); // r
pd1[1] = clamp16bits( _y + f2 ); // g
pd1[2] = clamp16bits( _y + f3 ); // b
pd1[3] = 0xff; // a
_y = pSrcY1[1] << 16;
pd1[4] = clamp16bits( _y + f1 );
pd1[5] = clamp16bits( _y + f2 );
pd1[6] = clamp16bits( _y + f3 );
pd1[7] = 0xff;
_y = pSrcY2[0] << 16;
pd2[0] = clamp16bits( _y + f1 );
pd2[1] = clamp16bits( _y + f2 );
pd2[2] = clamp16bits( _y + f3 );
pd2[3] = 0xff;
_y = pSrcY2[1] << 16;
pd2[4] = clamp16bits( _y + f1 );
pd2[5] = clamp16bits( _y + f2 );
pd2[6] = clamp16bits( _y + f3 );
pd2[7] = 0xff;
pSrcY1+=2;
pSrcY2+=2;
pSrcU++;
pSrcV++;
pd1 += 8;
pd2 += 8;
}
}
}
Android NDK Access memory of Bitmap directly
'Android Develop > image' 카테고리의 다른 글
안드로이드 이미지의 색변경 ColorMatrix (4) | 2019.12.16 |
---|---|
안드로이드 ImageView의 ScaleType (0) | 2019.12.04 |
안드로이드 YV12, stride와 RGB 변환 (4) | 2019.08.06 |
Android NDK Access memory of Bitmap directly (5) | 2019.08.05 |
Android NDK Bitmap 메모리에 접근하기 (2) | 2019.08.05 |
- Total
- Today
- Yesterday
- 컴퓨트쉐이더
- 전기세
- 텍스처
- 블로그
- 에어콘
- 아끼는 법
- texture
- 애드센스
- 재태크
- ComputeShader
- 재테크
- gpgpu
- OpenGL ES
- Android
- 전기요금
- 애드핏
- 금리
- 사용료
- 에어컨
- TTS
- OpenGLes
- 컴퓨트셰이더
- 공유 컨텍스트
- 안드로이드
- 예금
- 적금
- 전기료
- 경제보복
- 티스토리
- choreographer
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |