android全平臺編譯libyuv庫實現YUV和RGB的轉換
阿新 • • 發佈:2018-12-03
音視訊實踐學習
- android全平臺編譯ffmpeg以及x264與fdk-aac實踐
- ubuntu下使用nginx和nginx-rtmp-module配置直播推流伺服器
- android全平臺編譯ffmpeg合併為單個庫實踐
- android-studio使用cmake編譯ffmpeg實踐
- android全平臺編譯ffmpeg視訊解碼器實踐
- android全平臺編譯ffmpeg支援命令列實踐
- android全平臺編譯ffmpeg視訊推流實踐
- android平臺下音訊編碼之編譯LAME庫轉碼PCM為MP3
- ubuntu平臺下編譯vlc-android視訊播放器實踐
- 圖解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的區別
- 圖解RGB565、RGB555、RGB16、RGB24、RGB32、ARGB32等格式的區別
- YUV420P、YUV420SP、NV12、NV21和RGB互相轉換並存儲為JPEG以及PNG圖片
- android全平臺編譯libyuv庫實現YUV和RGB的轉換
概述
libyuv
是Google開源的實現各種YUV與RGB
之間相互轉換、旋轉、縮放
的庫。它是跨平臺的,可在Windows、Linux、Mac、Android
等作業系統,x86、x64、arm
SSE、AVX、NEON等SIMD
指令加速。
環境配置
作業系統:ubuntu 16.05
ndk版本:android-ndk-r16b
開始編譯
第一步:
先克隆出最新的libyuv版本
git clone git@github.com:lemenkov/libyuv.git
第二步:
重新命名libyuv
為jni
,編輯Android.mk檔案
,註釋掉JPEG相關的配置
第三步:
新建Application.mk檔案
APP_ABI := armeabi-v7a x86 x86_64
APP_PLATFORM := android- 16
APP_STL := stlport_static
APP_CPPFLAGS += -fno-rtti
開始編譯ndk-build
工程實踐
還是基於之前的graphic4android工程,新建native-libyuv
工程,配置可以參考之前的配置:
enum Type {
TYPE_YUV420P_TO_RGB24 = 0,
TYPE_NV12_TO_RGB24 = 1,
TYPE_NV21_TO_RGB24 = 2
};
/**
* I420就是YUV420P
* @param yuvData
* @param rgb24
* @param width
* @param height
*/
void I420_TO_RGB24(unsigned char *yuvData, unsigned char *rgb24, int width, int height) {
unsigned char *ybase = yuvData;
unsigned char *ubase = &yuvData[width * height];
unsigned char *vbase = &yuvData[width * height * 5 / 4];
//YUV420P轉RGB24
libyuv::I420ToRGB24(ybase, width, ubase, width / 2, vbase, width / 2,
rgb24,
width * 3, width, height);
}
/**
* NV12屬於YUV420SP
* @param yuvData
* @param rgb24
* @param width
* @param height
*/
void NV12_TO_RGB24(unsigned char *yuvData, unsigned char *rgb24, int width, int height) {
unsigned char *ybase = yuvData;
unsigned char *uvbase = &yuvData[width * height];
//NV12轉RGB24
libyuv::NV12ToRGB24(ybase, width, uvbase, width,
rgb24,
width * 3, width, height);
}
/**
* NV21屬於YUV420SP
* @param yuvData
* @param rgb24
* @param width
* @param height
*/
void NV21_TO_RGB24(unsigned char *yuvData, unsigned char *rgb24, int width, int height) {
unsigned char *ybase = yuvData;
unsigned char *vubase = &yuvData[width * height];
//NV21轉RGB24
libyuv::NV21ToRGB24(ybase, width, vubase, width,
rgb24,
width * 3, width, height);
}
void drawYUV(const char *path, int type, int width, int height, ANativeWindow_Buffer buffer) {
FILE *file = fopen(path, "rb");
int frameSize = width * height * 3 / 2;
unsigned char *yuvData = new unsigned char[frameSize];
fread(yuvData, 1, frameSize, file);
unsigned char *rgb24 = new unsigned char[width * height * 3];
//YUV轉RGB24
switch (type) {
case TYPE_YUV420P_TO_RGB24:
//YUV420P轉RGB24
I420_TO_RGB24(yuvData, rgb24, width, height);
break;
case TYPE_NV12_TO_RGB24:
//YUV420SP轉RGB24
NV12_TO_RGB24(yuvData, rgb24, width, height);
break;
case TYPE_NV21_TO_RGB24:
//YUV420SP轉RGB24
NV21_TO_RGB24(yuvData, rgb24, width, height);
break;
}
uint32_t *line = (uint32_t *) buffer.bits;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int index = y * width + x;
line[x] = rgb24[index * 3] << 16
| rgb24[index * 3 + 1] << 8
| rgb24[index * 3 + 2];
}
line = line + buffer.stride;
}
//釋放記憶體
delete[] yuvData;
delete[] rgb24;
//關閉檔案控制代碼
fclose(file);
}
void yuv2rgb(JNIEnv *env, jobject obj, jstring yuvPath, jint type, jint width, jint height,
jobject surface) {
const char *path = env->GetStringUTFChars(yuvPath, 0);
//獲取目標surface
ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
if (NULL == window) {
ThrowException(env, "java/lang/RuntimeException", "unable to get native window");
return;
}
//預設的是RGB_565
int32_t result = ANativeWindow_setBuffersGeometry(window, 0, 0, WINDOW_FORMAT_RGBA_8888);
if (result < 0) {
ThrowException(env, "java/lang/RuntimeException", "unable to set buffers geometry");
//釋放視窗
ANativeWindow_release(window);
window = NULL;
return;
}
ANativeWindow_acquire(window);
ANativeWindow_Buffer buffer;
//鎖定視窗的繪圖表面
if (ANativeWindow_lock(window, &buffer, NULL) < 0) {
ThrowException(env, "java/lang/RuntimeException", "unable to lock native window");
//釋放視窗
ANativeWindow_release(window);
window = NULL;
return;
}
//繪製YUV420P
drawYUV(path, type, width, height, buffer);
//解鎖視窗的繪圖表面
if (ANativeWindow_unlockAndPost(window) < 0) {
ThrowException(env, "java/lang/RuntimeException",
"unable to unlock and post to native window");
}
env->ReleaseStringUTFChars(yuvPath, path);
//釋放
ANativeWindow_release(window);
}
直接呼叫libyuv庫裡的函式即可完成轉換過程
專案地址:native-libyuv
https://github.com/byhook/graphic4android