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中的相关设置如下: