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
- 에어콘
- 컴퓨트쉐이더
- 아끼는 법
- 텍스처
- 재테크
- Android
- 안드로이드
- OpenGLes
- 재태크
- 블로그
- 티스토리
- 경제보복
- OpenGL ES
- 애드센스
- 애드핏
- 전기료
- 전기세
- 컴퓨트셰이더
- TTS
- texture
- choreographer
- 금리
- 사용료
- gpgpu
- 전기요금
- ComputeShader
- 예금
- 공유 컨텍스트
- 적금
- 에어컨
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |