【MediaTek X20开发板试用体验】5.MTX20开发板Android Studio开发APK应用程序预览USB Camera  

分享到:

xble
 xble
Level 1
注册时间:8年 前
帖子数: 15
2017年3月14日 上午9:28  

 MTX20开发板的操作系统是Android,所以APK模式的应用程序才是王道,而不是我上一个帖子里那样使用命令行方式来调用应用程序。Android系统开发APK程序有几种方法:1)在Android源代码里面开发APK;2)Eclipse+ADT+Android SDK+NDK开发APK;3)Android Studio+NDK开发APK。第一种方法自己只是尝试过修改一些Android自带App而已。第二种方法好几年前用过,只记得更新一次SDK真的好慢,还看运气。第三种方法是谷歌近来推荐的方式,当然此方法具有谷歌软件的标志“零碎”,测试版,正式版,1.0、2.0、2.2、2.2.2、等等,每个版本又有许多不同,比如我下载的版本2.2.2,与前面的版本相比改动蛮大滴。

不同于Android系统源代码下载的各种不容易,Android Studio下载简单,看了谷歌为了这个软件肯定做了不少功夫。下载地址为: http://www.android-studio.org/index.php/download,我下载的版本:android-studio-bundle-145.3360264-windows.exe。安装也比以前变得简单多了,不需要安装JDK直接安装即可。
Android Studio安装过程比较简单,只要注意安装的路径即可,我这里默认在C盘。
 
 
 
Android Studio初始化过程如下,我选择的安装方式是“Custom",避免默认方式安装过多无用的东西。虚拟机有761M大小,可能对于有真机的情况也用处不大。
 
 
 
 
 
 
Android Studio添加SDK和NDK等必要库文件
 
 
 
 
 
在上个帖子C语言访问USB Camera设备的基础上暴露JNI接口给Java调用。
JNI关键函数介绍:
1)Java_com_example_administrator_simplewebcam_MainActivity_prepareCamera函数被用于初始化USB Camera设备。

  1. extern "C"
  2. jint
  3. Java_com_example_administrator_simplewebcam_MainActivity_prepareCamera( JNIEnv* env,jobject thiz, jint videoid){
  4.     int ret;
  5.     if(camerabase<0){
  6.         camerabase = checkCamerabase();
  7.     }
  8.     ret = opendevice(camerabase + videoid);
  9.     if(ret != ERROR_LOCAL){
  10.         ret = initdevice();
  11.     }
  12.     if(ret != ERROR_LOCAL){
  13.         ret = startcapturing();
  14.         if(ret != SUCCESS_LOCAL){
  15.             stopcapturing();
  16.             uninitdevice ();
  17.             closedevice ();
  18.             LOGE("device resetted");
  19.         }
  20.     }
  21.     if(ret != ERROR_LOCAL){
  22.         rgb = (int *)malloc(sizeof(int) * (IMG_WIDTH*IMG_HEIGHT));
  23.         ybuf = (int *)malloc(sizeof(int) * (IMG_WIDTH*IMG_HEIGHT));
  24.     }
  25.     return ret;
  26. }

复制代码

2)Java_com_example_administrator_simplewebcam_MainActivity_pixeltobmp函数用于数据转换,USB Camera设备出来的数据是YUV或者MJPG形式,想要显示在Android的界面上必须转化为BMP或者个RGB格式,这里的实现主要来自网上开源代码simplewebcam,根据实际需要做了一些修改。

  1. void
  2. Java_com_example_administrator_simplewebcam_MainActivity_pixeltobmp( JNIEnv* env,jobject thiz,jobject bitmap){
  3.     jboolean bo;
  4.     AndroidBitmapInfo  info;
  5.     void*              pixels;
  6.     int                ret;
  7.     int i;
  8.     int *colors;
  9.     int width=0;
  10.     int height=0;
  11.     if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
  12.         LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
  13.         return;
  14.     }
  15.     width = info.width;
  16.     height = info.height;
  17.     if(!rgb || !ybuf) return;
  18.     if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
  19.         LOGE("Bitmap format is not RGBA_8888 !");
  20.         return;
  21.     }
  22.     if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
  23.         LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
  24.     }
  25.     colors = (int*)pixels;
  26.     int *lrgb =NULL;
  27.     lrgb = &rgb[0];
  28.     for(i=0 ; i<width*height ; i++){
  29.         *colors++ = *lrgb++;
  30.     }
  31.     AndroidBitmap_unlockPixels(env, bitmap);
  32. }

复制代码

3)Java_com_example_administrator_simplewebcam_MainActivity_processCamera函数开始预览。

  1. void
  2. Java_com_example_administrator_simplewebcam_MainActivity_processCamera( JNIEnv* env,
  3.                                                                          jobject thiz){
  4.     readframeonce();
  5. }

复制代码

4)Java_com_example_administrator_simplewebcam_MainActivity_stopCamera函数关闭USB Camera设备。

  1. void
  2. Java_com_example_administrator_simplewebcam_MainActivity_stopCamera(JNIEnv* env,jobject thiz){
  3.     stopcapturing ();
  4.     uninitdevice ();
  5.     closedevice ();
  6.     if(rgb) free(rgb);
  7.     if(ybuf) free(ybuf);
  8.     fd = -1;
  9. }

复制代码

5)因为在代码中使用了AndroidBitmap_getInfo等Bitmap处理函数,所以需要在CMakeLists.txt中添加jnigraphics库支持。

  1. # Sets the minimum version of CMake required to build the native
  2. # library. You should either keep the default value or only pass a
  3. # value of 3.4.0 or lower.
  4. cmake_minimum_required(VERSION 3.4.1)
  5. # Creates and names a library, sets it as either STATIC
  6. # or SHARED, and provides the relative paths to its source code.
  7. # You can define multiple libraries, and CMake builds it for you.
  8. # Gradle automatically packages shared libraries with your APK.
  9. add_library( # Sets the name of the library.
  10.              ImageProc
  11.              # Sets the library as a shared library.
  12.              SHARED
  13.              # Provides a relative path to your source file(s).
  14.              # Associated headers in the same location as their source
  15.              # file are automatically included.
  16.              src/main/cpp/native-lib.cpp )
  17. # Searches for a specified prebuilt library and stores the path as a
  18. # variable. Because system libraries are included in the search path by
  19. # default, you only need to specify the name of the public NDK library
  20. # you want to add. CMake verifies that the library exists before
  21. # completing its build.
  22. find_library( # Sets the name of the path variable.
  23.               log-lib
  24.               # Specifies the name of the NDK library that
  25.               # you want CMake to locate.
  26.               log jnigraphics )
  27. # Specifies libraries CMake should link to your target library. You
  28. # can link multiple libraries, such as libraries you define in the
  29. # build script, prebuilt third-party libraries, or system libraries.
  30. target_link_libraries( # Specifies the target library.
  31.                        ImageProc
  32.                        # Links the target library to the log library
  33.                        # included in the NDK.
  34.                        ${log-lib} jnigraphics )

复制代码

6)activity_main.xml,界面设计代码

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:tools="http://schemas.android.com/tools"
  4.     android:id="@+id/activity_main"
  5.     android:layout_width="match_parent"
  6.     android:layout_height="match_parent"
  7.     android:paddingBottom="@dimen/activity_vertical_margin"
  8.     android:paddingLeft="@dimen/activity_horizontal_margin"
  9.     android:paddingRight="@dimen/activity_horizontal_margin"
  10.     android:paddingTop="@dimen/activity_vertical_margin"
  11.     tools:context="com.example.administrator.simplewebcam.MainActivity">
  12.     <TextView
  13.         android:id="@+id/sample_text"
  14.         android:layout_width="150dp"
  15.         android:layout_height="50dp"
  16.         android:text="Hello World! C++" />
  17.     <Button android:layout_toRightOf="@id/sample_text"
  18.         android:layout_width="80dp"
  19.         android:layout_height="50dp"
  20.         android:text="btn1" android:id="@+id/btn1"/>
  21.     <Button android:layout_toRightOf="@id/btn1"
  22.         android:layout_width="80dp"
  23.         android:layout_height="50dp"
  24.         android:text="btn2" android:id="@+id/btn2"/>
  25.     <SurfaceView android:layout_below="@id/sample_text"
  26.         android:layout_alignLeft="@id/sample_text"
  27.         android:layout_alignParentTop="false"
  28.         android:layout_alignParentLeft="true"
  29.         android:layout_alignParentRight="true"
  30.         android:layout_alignParentBottom="true"
  31.         android:id="@+id/MySurface"
  32.         android:layout_width="fill_parent"
  33.         android:layout_height="fill_parent" />
  34. </RelativeLayout>

复制代码

7)MainActivity.java代码

  1. package com.example.administrator.simplewebcam;
  2. import android.Manifest;
  3. import android.content.Context;
  4. import android.content.DialogInterface;
  5. import android.content.pm.PackageManager;
  6. import android.graphics.Bitmap;
  7. import android.graphics.BitmapFactory;
  8. import android.graphics.Canvas;
  9. import android.graphics.Color;
  10. import android.graphics.Paint;
  11. import android.graphics.PorterDuff;
  12. import android.graphics.PorterDuffXfermode;
  13. import android.graphics.Rect;
  14. import android.graphics.RectF;
  15. import android.os.Environment;
  16. import android.support.annotation.NonNull;
  17. import android.support.v4.app.ActivityCompat;
  18. import android.support.v4.content.ContextCompat;
  19. import android.support.v7.app.AlertDialog;
  20. import android.support.v7.app.AppCompatActivity;
  21. import android.os.Bundle;
  22. import android.util.Log;
  23. import android.view.SurfaceHolder;
  24. import android.view.SurfaceView;
  25. import android.widget.Button;
  26. import android.widget.TextView;
  27. import android.app.Activity;
  28. import android.os.Bundle;
  29. import android.view.View;
  30. import android.view.View.OnClickListener;
  31. import android.widget.Toast;
  32. import java.io.File;
  33. import java.io.IOException;
  34. import java.lang.reflect.Field;
  35. import java.util.ArrayList;
  36. import static android.graphics.BitmapFactory.*;
  37. public class MainActivity extends AppCompatActivity {
  38.     public SurfaceHolder MyHolder;
  39.     private static final boolean DEBUG = true;
  40.     private static final String TAG="WebCam";
  41.     protected Context context;
  42.     Thread mainLoop = null;
  43.     private Bitmap bmp=null;
  44.     private boolean cameraExists=false;
  45.     private boolean shouldStop=false;
  46.     // /dev/videox (x=cameraId+cameraBase) is used.
  47.     // In some omap devices, system uses /dev/video[0-3],
  48.     // so users must use /dev/video[4-].
  49.     // In such a case, try cameraId=0 and cameraBase=4
  50.     private int cameraId=0;
  51.     private int cameraBase=0;
  52.     // This definition also exists in ImageProc.h.
  53.     // Webcam must support the resolution 640x480 with YUYV format.
  54.     static final int IMG_WIDTH=640;
  55.     static final int IMG_HEIGHT=480;
  56.     // The following variables are used to draw camera images.
  57.     private int winWidth=0;
  58.     private int winHeight=0;
  59.     private Rect rect;
  60.     private int dw, dh;
  61.     private float rate;
  62.     // JNI functions
  63.     public native int prepareCamera(int videoid);
  64.     public native int prepareCameraWithBase(int videoid, int camerabase);
  65.     public native void processCamera();
  66.     public native void stopCamera();
  67.     public native void pixeltobmp(Bitmap bitmap);
  68.     public native void testLog();
  69.     public native String stringFromJNI1();
  70.     static {
  71.         System.loadLibrary("ImageProc");
  72.     }
  73. SurfaceView MysurfaceView;
  74.     private static final int MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
  75.     private boolean mExternalStorageAvailable = false;
  76.     private boolean mExternalStorageWriteable = false;
  77.     private static final int CAMERA_REQUEST_CODE = 1;
  78.     private boolean mCamera = false;
  79.     @Override
  80.     protected void onCreate(Bundle savedInstanceState) {
  81.         super.onCreate(savedInstanceState);
  82.         setContentView(R.layout.activity_main);
  83.         Button btn1 = (Button) findViewById(R.id.btn1);
  84.         Button btn2 = (Button) findViewById(R.id.btn2);
  85.         MysurfaceView = (SurfaceView)findViewById(R.id.MySurface);
  86.         MyHolder = MysurfaceView.getHolder();
  87.         btn1.setOnClickListener(new View.OnClickListener() {
  88.             @Override
  89.             public void onClick(View v) {
  90.             }
  91.         });
  92.         btn2.setOnClickListener(new View.OnClickListener() {
  93.             @Override
  94.             public void onClick(View v) {
  95.             }
  96.         });
  97.         // Example of a call to a native method
  98.         TextView tv = (TextView) findViewById(R.id.sample_text);
  99.         tv.setText(stringFromJNI1());
  100.         int nRet = 0;//
  101.         SetExternalStoragepermission_OK();
  102.         nRet = CheckExternalStoragepermission_OK();
  103.         if(nRet == 0)
  104.         {
  105.                 Log.i("Surface:", "nRet ==0");
  106.         }
  107.         else
  108.         {
  109.                 Log.i("Surface:", "nRet !=0");
  110.                 MyHolder.addCallback(new MyCallBack());//  surfaceCreated surfaceChanged
  111.         }
  112.        //   
  113.     }
  114.         private int CheckExternalStoragepermission_OK()
  115.     {
  116.         String externalStorageState = Environment.getExternalStorageState();
  117.         if (Environment.MEDIA_MOUNTED.equals(externalStorageState)) {
  118.             mExternalStorageAvailable = true;
  119.             mExternalStorageWriteable = true;
  120.             return 2;      } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(externalStorageState)) {
  121.             mExternalStorageAvailable = true;
  122.             mExternalStorageWriteable = false;
  123.             return 1;       } else {
  124.             mExternalStorageAvailable = mExternalStorageWriteable = false;
  125.             return 0;
  126.         }
  127.     //    handleExternalStorageState(mExternalStorageAvailable,mExternalStorageWriteable);
  128.     }
  129.     private void SetExternalStoragepermission_OK()
  130.     {
  131.         String externalStorageState = Environment.getExternalStorageState();
  132.         if (Environment.MEDIA_MOUNTED.equals(externalStorageState)) {
  133.             mExternalStorageAvailable = true;
  134.             mExternalStorageWriteable = true;
  135.         } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(externalStorageState)) {
  136.             mExternalStorageAvailable = true;
  137.             mExternalStorageWriteable = false;
  138.         } else {
  139.             mExternalStorageAvailable = mExternalStorageWriteable = false;
  140.         }
  141.         handleExternalStorageState(mExternalStorageAvailable,mExternalStorageWriteable);
  142.         
  143. requestPermission();
  144.         
  145.     }
  146.     private void requestPermission() {
  147.         if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
  148.                 != PackageManager.PERMISSION_GRANTED) {
  149.             // 第一次请求权限时,用户如果拒绝,下一次请求shouldShowRequestPermissionRationale()返回true
  150.             // 向用户解释为什么需要这个权限
  151.             if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
  152.                 new AlertDialog.Builder(this)
  153.                         .setMessage("申请相机权限")
  154.                         .setPositiveButton("确定", new DialogInterface.OnClickListener() {
  155.                             @Override
  156.                             public void onClick(DialogInterface dialog, int which) {
  157.                                 //申请相机权限
  158.                                 ActivityCompat.requestPermissions(MainActivity.this,
  159.                                         new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);
  160.                             }
  161.                         })
  162.                         .show();
  163.             } else {
  164.                 //申请相机权限
  165.                 ActivityCompat.requestPermissions(this,
  166.                         new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);
  167.             }
  168.         } else {
  169.           //  Tv.setTextColor(Color.GREEN);
  170.           //  Tv.setText("相机权限已申请");
  171.         }
  172.     }
  173.     private void handleCameraState(boolean mCamera ) {
  174.                 }
  175.     private void handleExternalStorageState(boolean mExternalStorageAvailable,boolean mExternalStorageWriteable ) {
  176.         if(mExternalStorageAvailable && mExternalStorageWriteable){
  177.             //STORAGE is dangerous so check
  178.             // checkSelfPermission()
  179.             int permissionCheck = ContextCompat.checkSelfPermission(this,
  180.                     Manifest.permission.WRITE_EXTERNAL_STORAGE);
  181.             Log.d("permission", "permissionCheck=="+permissionCheck);
  182.             if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
  183.                 //has not granted request permission
  184.                 // Should we show an explanation?
  185.                 if (ActivityCompat.shouldShowRequestPermissionRationale(this,
  186.                         Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
  187.                     // Show an expanation to the user *asynchronously* -- don't block
  188.                     // this thread waiting for the user's response! After the user
  189.                     // sees the explanation, try again to request the permission.
  190.                     //  Toast.makeText(MainActivity.this, "Permission++++", Toast.LENGTH_SHORT).show();
  191. //                    ActivityCompat.requestPermissions(this,
  192. //                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
  193. //                            MY_PERMISSIONS_REQUEST_READ_CONTACTS);
  194.                     new AlertDialog.Builder(this)
  195.                             .setMessage("您拒绝过授予访问外部存储设备的权限,但是只有申请该权限,才能往外部存储设备写入数据,你确定要重新申请获取权限吗?")
  196.                             .setPositiveButton("ok", new DialogInterface.OnClickListener() {
  197.                                 @Override
  198.                                 public void onClick(DialogInterface dialog, int which) {
  199.                                     dialog.dismiss();
  200.                                     //again request permission
  201.                                     ActivityCompat.requestPermissions(MainActivity.this,
  202.                                             new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
  203.                                             MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
  204.                                 }
  205.                             })
  206.                             .setNegativeButton("no", new DialogInterface.OnClickListener() {
  207.                                 @Override
  208.                                 public void onClick(DialogInterface dialog, int which) {
  209.                                     dialog.dismiss();
  210.                                 }
  211.                             })
  212.                             .create()
  213.                             .show();
  214.                 } else {
  215.                     // No explanation needed, we can request the permission.
  216.                     ActivityCompat.requestPermissions(this,
  217.                             new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
  218.                             MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
  219.                     // MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE is an
  220.                     // app-defined int constant. The callback method gets the
  221.                     // result of the request.
  222.                 }
  223.             }else{
  224.                 //had granted
  225.                 Toast.makeText(MainActivity.this, "run writeDatasToExternalStorage() method", Toast.LENGTH_SHORT).show();
  226.                 // writeDatasToExternalStorage();
  227.             }
  228.         }else{
  229.             Log.d("permission", "ExternalStorage can not be write  or unAvailable");
  230.         }
  231.     }
  232.     /**          */
  233.     private void writeDatasToExternalStorage(){
  234.         File directory = Environment.getExternalStorageDirectory();// 6.0 /storage/emulated/0    5.0 /storage/sdcard
  235.             /*
  236.              Environment.getDataDirectory();//  /data
  237.              Environment.getRootDirectory();// /system
  238.              Environment.getDownloadCacheDirectory();//  /cache
  239.              Environment.getExternalStoragePublicDirectory(
  240.                     Environment.DIRECTORY_PICTURES);// 6.0 /storage/emulated/0/Pictures   5.0/storage/sdcard/Pictures
  241.            */
  242.         File file = new File(directory, "permisson");
  243.         if(!file.exists()){
  244.             try {
  245.                 file.createNewFile();
  246.             } catch (IOException e) {
  247.                 e.printStackTrace();
  248.             }
  249.         }
  250.     }
  251.     /**
  252.      *
  253.      * @param requestCode
  254.      * @param permissions
  255.      * @param grantResults
  256.      */
  257.     @Override
  258.     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  259.         Log.d("permission", "onRequestPermissionsResult  requestCode" + requestCode);
  260.         if (requestCode == MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE) {
  261.                 // If request is cancelled, the result arrays are empty.
  262.                 if (grantResults.length > 0
  263.                         && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  264.                     // permission was granted, yay! Do the
  265.                     // contacts-related task you need to do.
  266.                     Toast.makeText(MainActivity.this, "run writeDatasToExternalStorage() method", Toast.LENGTH_SHORT).show();
  267.                     //   writeDatasToExternalStorage();
  268.                 } else {
  269.                     // Permission Denied
  270.                     Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
  271.                     // permission denied, boo! Disable the
  272.                     // functionality that depends on this permission.
  273.                 }
  274.                 return;
  275.             }
  276.         if (requestCode == CAMERA_REQUEST_CODE) {
  277.                     if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  278.                    // Tv.setTextColor(Color.GREEN);
  279.                   //  Tv.setText("相机权限已申请");
  280.             } else {
  281.                 //用户勾选了不再询问
  282.                 //提示用户手动打开权限
  283.                 if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
  284.                     Toast.makeText(this, "相机权限已被禁止", Toast.LENGTH_SHORT).show();
  285.                 }
  286.             }
  287.             }
  288.             // other 'case' lines to check for other
  289.             // permissions this app might request
  290.         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  291.     }
  292.     class MyCallBack implements SurfaceHolder.Callback , Runnable {
  293.         @Override
  294.         public void run() {
  295.             while (true && cameraExists) {
  296.                 //obtaining display area to draw a large image
  297.                 if(winWidth==0){
  298.                     winWidth=MysurfaceView.getWidth();
  299.                     winHeight=MysurfaceView.getHeight();
  300.                     if(winWidth*3/4<=winHeight){
  301.                         dw = 0;
  302.                         dh = (winHeight-winWidth*3/4)/2;
  303.                         rate = ((float)winWidth)/IMG_WIDTH;
  304.                         rect = new Rect(dw,dh,dw+winWidth-1,dh+winWidth*3/4-1);
  305.                     }else{
  306.                         dw = (winWidth-winHeight*4/3)/2;
  307.                         dh = 0;
  308.                         rate = ((float)winHeight)/IMG_HEIGHT;
  309.                         rect = new Rect(dw,dh,dw+winHeight*4/3 -1,dh+winHeight-1);
  310.                     }
  311.                 }
  312.                 // obtaining a camera image (pixel data are stored in an array in JNI).
  313.                 processCamera();
  314.                 // camera image to bmp
  315.                 pixeltobmp(bmp);
  316.                 Canvas canvas = MyHolder.lockCanvas();
  317.                 if (canvas != null)
  318.                 {
  319.                     // draw camera bmp on canvas
  320.                     canvas.drawBitmap(bmp,null,rect,null);
  321.                     MyHolder.unlockCanvasAndPost(canvas);
  322.                 }
  323.                 if(shouldStop){
  324.                     shouldStop = false;
  325.                     break;
  326.                 }
  327.             }
  328.         }
  329.         @Override
  330.         public void surfaceChanged(SurfaceHolder holder, int format, int width,
  331.                                    int height) {
  332.             Log.i("Surface:", "Change");
  333.         }
  334.         @Override
  335.         public void surfaceCreated(SurfaceHolder holder) {
  336.             Log.i("Surface:", "Create");
  337.             String TAG1 = "test1111";
  338.             Log.d(TAG, "surfaceCreated");
  339.             if(bmp==null){
  340.                 bmp = Bitmap.createBitmap(IMG_WIDTH, IMG_HEIGHT, Bitmap.Config.ARGB_8888);
  341.             }
  342.                     if(DEBUG) Log.d(TAG, "-10-prepareCamera surfaceCreated"  + "TAG1=" + TAG1);
  343.         if(DEBUG) Log.d(TAG, "-11-prepareCamera surfaceCreated cameraId="+ cameraId + "cameraBase="+ cameraBase);
  344.         testLog();
  345.         if(DEBUG) Log.d(TAG, "-12-prepareCamera surfaceCreated cameraId="+ cameraId + "cameraBase="+ cameraBase);
  346.         int ret = prepareCamera(cameraId);
  347.        // int ret = prepareCameraWithBase(cameraId, cameraBase);
  348.         if(DEBUG) Log.d(TAG, "prepareCamera surfaceCreated cameraId="+ cameraId + "cameraBase="+ cameraBase + "ret=" + ret);
  349.         if(ret!=-1) cameraExists = true;
  350.         mainLoop = new Thread(this);
  351.         mainLoop.start();
  352.         }
  353.         @Override
  354.         public void surfaceDestroyed(SurfaceHolder holder) {
  355.             Log.i("Surface:", "Destroy");
  356.         if(DEBUG) Log.d(TAG, "surfaceDestroyed");
  357.         if(cameraExists){
  358.             shouldStop = true;
  359.             while(shouldStop){
  360.                 try{
  361.                     Thread.sleep(100); // wait for thread stopping
  362.                 }catch(Exception e){}
  363.             }
  364.         }
  365.         stopCamera();
  366.         }
  367.     }
  368.     /**
  369.      * A native method that is implemented by the 'native-lib' native library,
  370.      * which is packaged with this application.
  371.      */
  372. }

复制代码

运行抓图如下: 
总结:
1)JNI中定义函数名与Android Studio中Java程序调用的函数名的对应关系:
Java_com_example_administrator_simplewebcam_MainActivity_pixeltobmp pixeltobmp
注意:(1)前者中‘_’是特殊分隔符不能在使用在函数名中,我就遇到了这个坑。
          (2)pixeltobmp函数在哪个类里面调用,这个类名必须包含在JNI函数名的定义里面。
2)Android Studio开发的APK程序如何访问/dev/video0等类似设备节点,可以参考下面的方法 ,在这里自己验证了很多方法,后面会专门开一个帖子记录一下。
       The permission of /dev/video0 is set 0666 in /ueventd.xxxx.rc


DragonCat liked
回复引用
  
Working

登陆 或者 注册