1、下载:https://github.com/lemenkov/libyuv(我在码云上也做了备份:https://gitee.com/daizhufei/libyuv),虽然这个不是官网,但是内容都是官网里保存过来的。
2、创建一个新的Android项目,模板使用Native C++,如下:
其它都是下一步即可,这样就创建出了一个带NDK环境的项目了,可以直接运行,效果如下:
3、把下载到的libyuv解压,然后把所有内容复制到andrroid studio项目中的cpp目录下,如下:
4、打开CMakeLists.txt,把项目自带的native-lib.cpp添加到如下位置:
这里需要注意,此时的CMakeLists中声明的so的文件名为:yuv,所以在MainActivity中加载so时也要使用这个名字,如下:
5、运行,如果能正常运行,说明编译就没问题了。
6、libyuv并没有提供java直接调用的对应JNI函数,需要我们自己去写JNI,打开“native-lib.cpp”,导入头文件:#include “libyuv.h”,这样就可以调用这里面的相关函数了,如下:
#include <jni.h>
#include <string>
#include "libyuv.h"
void YV12ToI420(jbyte *src_yv12_data, jint width, jint height, jbyte *dst_i420_data) {
jbyte *src_yplane = src_yv12_data;
jbyte *src_uplane = src_yv12_data + width * height;
jbyte *src_vplane = src_uplane + (width * height / 4);
jbyte *dst_yplane = dst_i420_data;
jbyte *dst_uplane = dst_i420_data + width * height;
jbyte *dst_vplane = dst_uplane + (width * height / 4);
// YV12 is YVU => Use I420(YUV) copy and flip U and V.
libyuv::I420Copy(
(const uint8_t *) src_yplane, width,
(const uint8_t *) src_vplane, width / 2,
(const uint8_t *) src_uplane, width / 2,
(uint8_t *) dst_yplane, width,
(uint8_t *) dst_uplane, width / 2,
(uint8_t *) dst_vplane, width / 2,
width, height);
}
extern "C"
JNIEXPORT void JNICALL
Java_a_a_libyuv_MainActivity_YV12ToI420(JNIEnv *env, jobject thiz, jbyteArray yv12_bytes,
jbyteArray i420_bytes, jint width, jint height) {
jbyte *srcP = env->GetByteArrayElements(yv12_bytes, NULL);
jbyte *destP = env->GetByteArrayElements(i420_bytes, NULL);
YV12ToI420(srcP, width, height, destP);
env->ReleaseByteArrayElements(yv12_bytes, srcP, 0);
env->ReleaseByteArrayElements(i420_bytes, destP, 0);
}
extern "C" JNIEXPORT jstring JNICALL
Java_a_a_libyuv_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
MainActivity中的代码如下:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Example of a call to a native method
findViewById<TextView>(R.id.sample_text).text = stringFromJNI()
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
external fun stringFromJNI(): String
external fun YV12ToI420(yv12Bytes: ByteArray, i420Bytes: ByteArray, width: Int, height: Int)
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("yuv")
}
}
}
说明:这里我们声明了一个YV12ToI420方法,我们把yv12的数据传到第1个参数中,创建一个新的空的数组,长度要与参数1的数组一样,传到参数2中,用于接收转换后的结果,参数3和4为视频的宽和高。
在C中使用Logcat可参考另一篇文章:点此跳转
CMakeLists.txt中的相关设置如下: