1 package com.rockchip.gpadc.demo; 2 3 import android.app.Activity; 4 import android.content.SharedPreferences; 5 import android.content.res.Resources; 6 import android.graphics.Bitmap; 7 import android.graphics.Canvas; 8 import android.graphics.Paint; 9 import android.graphics.PorterDuff; 10 import android.graphics.PorterDuffXfermode; 11 import android.graphics.RectF; 12 import android.graphics.SurfaceTexture; 13 import android.graphics.Typeface; 14 import android.hardware.Camera; 15 import android.os.Bundle; 16 import android.os.Handler; 17 import android.os.Message; 18 import android.util.Log; 19 import android.view.Gravity; 20 import android.view.SurfaceHolder; 21 import android.view.SurfaceView; 22 import android.view.WindowManager; 23 import android.widget.ImageView; 24 import android.widget.TextView; 25 import android.widget.Toast; 26 27 import com.rockchip.gpadc.demo.rga.RGA; 28 import com.rockchip.gpadc.demo.yolo.InferenceWrapper; 29 30 import java.io.File; 31 import java.io.FileOutputStream; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.lang.reflect.Method; 35 import java.text.DecimalFormat; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 import static com.rockchip.gpadc.demo.rga.HALDefine.CAMERA_PREVIEW_HEIGHT; 40 import static com.rockchip.gpadc.demo.rga.HALDefine.CAMERA_PREVIEW_WIDTH; 41 import static com.rockchip.gpadc.demo.rga.HALDefine.IM_HAL_TRANSFORM_FLIP_H; 42 import static com.rockchip.gpadc.demo.rga.HALDefine.RK_FORMAT_RGBA_8888; 43 import static com.rockchip.gpadc.demo.rga.HALDefine.RK_FORMAT_YCrCb_420_SP; 44 import static com.rockchip.gpadc.demo.yolo.PostProcess.INPUT_CHANNEL; 45 import static java.lang.Thread.sleep; 46 47 48 public class CameraPreviewActivity extends Activity implements Camera.PreviewCallback { 49 50 private final String TAG = "rkyolo"; 51 private static final int MAGIC_TEXTURE_ID = 10; 52 53 TSurfaceHolderCallback mSurfaceHolderCallback = null; 54 55 private Camera mCamera0 = null; 56 private SurfaceView mSurfaceView = null; 57 public SurfaceTexture mSurfaceTexture = null; 58 private SurfaceHolder mSurfaceHolder = null; 59 public int flip = -1; // for CAMERA_FACING_BACK(camera comes with RK3588 using this mode), 60 // we do not need flip, using -1, or we need using 61 // IM_HAL_TRANSFORM_FLIP_H 62 63 private boolean mIsCameraOpened = false; 64 private int mCameraId = -1; 65 public byte textureBuffer[]; 66 67 // for inference 68 private String mModelName = "yolov5s.rknn"; 69 private String platform = "rk3588"; 70 private InferenceWrapper mInferenceWrapper; 71 private String fileDirPath; // file dir to store model cache 72 private ImageBufferQueue mImageBufferQueue; // intermedia between camera thread and inference thread 73 private InferenceResult mInferenceResult = new InferenceResult(); // detection result 74 private int mWidth; //surface width 75 private int mHeight; //surface height 76 private volatile boolean mStopInference = false; 77 78 //draw result 79 private TextView mFpsNum1; 80 private TextView mFpsNum2; 81 private TextView mFpsNum3; 82 private TextView mFpsNum4; 83 private ImageView mTrackResultView; 84 private Bitmap mTrackResultBitmap = null; 85 private Canvas mTrackResultCanvas = null; 86 private Paint mTrackResultPaint = null; 87 private Paint mTrackResultTextPaint = null; 88 89 private PorterDuffXfermode mPorterDuffXfermodeClear; 90 private PorterDuffXfermode mPorterDuffXfermodeSRC; 91 92 @Override onCreate(Bundle savedInstanceState)93 protected void onCreate(Bundle savedInstanceState) { 94 super.onCreate(savedInstanceState); 95 setContentView(R.layout.activity_main); 96 97 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 98 99 mFpsNum1 = (TextView) findViewById(R.id.fps_num1); 100 mFpsNum2 = (TextView) findViewById(R.id.fps_num2); 101 mFpsNum3 = (TextView) findViewById(R.id.fps_num3); 102 mFpsNum4 = (TextView) findViewById(R.id.fps_num4); 103 mTrackResultView = (ImageView) findViewById(R.id.canvasView); 104 105 fileDirPath = getCacheDir().getAbsolutePath(); 106 107 platform = getPlatform(); 108 Log.d(TAG, "get soc platform:" + platform); 109 110 if (platform.equals("rk3588")) { 111 createFile(mModelName, R.raw.yolov5s_rk3588); 112 } else if (platform.equals("rk356x")) { 113 createFile(mModelName, R.raw.yolov5s_rk3566); 114 } else if (platform.equals("rk3562")) { 115 createFile(mModelName, R.raw.yolov5s_rk3562); 116 } else { 117 Toast toast = Toast.makeText(this, "Can not get platform use RK3588 instead.", Toast.LENGTH_LONG); 118 toast.setGravity(Gravity.CENTER, 0, 0); 119 toast.show(); 120 createFile(mModelName, R.raw.yolov5s_rk3588); 121 } 122 123 try { 124 mInferenceResult.init(getAssets()); 125 } catch (IOException e) { 126 e.printStackTrace(); 127 } 128 129 mInferenceWrapper = new InferenceWrapper(); 130 131 } 132 133 @Override onDestroy()134 protected void onDestroy() { 135 Log.d(TAG, "onDestroy"); 136 137 destroyPreviewView(); 138 super.onDestroy(); 139 } 140 141 @Override onPause()142 protected void onPause() { 143 Log.d(TAG, "onPause"); 144 stopTrack(); 145 stopCamera(); 146 destroyPreviewView(); 147 super.onPause(); 148 149 } 150 151 @Override onResume()152 protected void onResume() { 153 Log.d(TAG, "onResume"); 154 155 createPreviewView(); 156 super.onResume(); 157 158 } 159 createPreviewView()160 private boolean createPreviewView() { 161 mSurfaceView = findViewById(R.id.surfaceViewCamera1); 162 mSurfaceHolder = mSurfaceView.getHolder(); 163 // mSurfaceView.setZOrderMediaOverlay(true); 164 165 mSurfaceTexture = new SurfaceTexture(MAGIC_TEXTURE_ID); 166 167 mSurfaceHolderCallback = new TSurfaceHolderCallback(); 168 mSurfaceHolder.addCallback(mSurfaceHolderCallback); 169 170 return true; 171 } 172 destroyPreviewView()173 private void destroyPreviewView() { 174 if (mSurfaceHolder != null) { 175 mSurfaceHolder.removeCallback(mSurfaceHolderCallback); 176 mSurfaceHolderCallback = null; 177 mSurfaceHolder = null; 178 } 179 180 } 181 182 @Override onPreviewFrame(byte[] data, Camera camera)183 public void onPreviewFrame(byte[] data, Camera camera) { 184 mCamera0.addCallbackBuffer(data); 185 ImageBufferQueue.ImageBuffer imageBuffer = mImageBufferQueue.getFreeBuffer(); 186 187 if (imageBuffer != null) { 188 // RK_FORMAT_YCrCb_420_SP -> RK_FORMAT_RGBA_8888 189 // flip for CAMERA_FACING_FRONT 190 RGA.colorConvertAndFlip(data, RK_FORMAT_YCrCb_420_SP, 191 imageBuffer.mImage, RK_FORMAT_RGBA_8888, 192 CAMERA_PREVIEW_WIDTH, CAMERA_PREVIEW_HEIGHT, this.flip); 193 194 mImageBufferQueue.postBuffer(imageBuffer); 195 } 196 } 197 198 private class TSurfaceHolderCallback implements SurfaceHolder.Callback { 199 200 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)201 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 202 Log.d(TAG, "surfaceChanged"); 203 mWidth = width; 204 mHeight = height; 205 206 textureBuffer=new byte[CAMERA_PREVIEW_WIDTH * CAMERA_PREVIEW_HEIGHT * 4]; 207 } 208 209 @Override surfaceCreated(SurfaceHolder holder)210 public void surfaceCreated(SurfaceHolder holder) { 211 Log.d(TAG, "surfaceCreated"); 212 213 startCamera(); 214 startTrack(); 215 216 } 217 218 @Override surfaceDestroyed(SurfaceHolder holder)219 public void surfaceDestroyed(SurfaceHolder holder) { 220 Log.d(TAG, "surfaceDestroyed"); 221 222 stopTrack(); 223 stopCamera(); 224 } 225 } 226 227 startCamera()228 private boolean startCamera() { 229 if (mIsCameraOpened) { 230 return true; 231 } 232 233 //(Camera.CameraInfo.CAMERA_FACING_BACK); 234 int num = Camera.getNumberOfCameras(); 235 if (num > 2) 236 mCameraId = 2; 237 else 238 mCameraId = 0; 239 Log.d(TAG, "mCameraId = " + mCameraId); 240 Camera.CameraInfo camInfo = new Camera.CameraInfo(); 241 try { 242 Camera.getCameraInfo(mCameraId, camInfo); 243 if (mCameraId != -1) { 244 mCamera0 = Camera.open(mCameraId); 245 } else { 246 mCamera0 = Camera.open(); 247 } 248 Log.d(TAG, "mCamera0 = " + mCamera0); 249 Log.d(TAG, "camera facing: " + camInfo.facing); 250 if (Camera.CameraInfo.CAMERA_FACING_FRONT == camInfo.facing) { 251 this.flip = IM_HAL_TRANSFORM_FLIP_H; 252 } 253 254 } catch (RuntimeException e) { 255 Log.w(TAG, "Unable to open camera!"); 256 Toast toast = Toast.makeText(this, "Unable to open camera!", Toast.LENGTH_LONG); 257 toast.setGravity(Gravity.CENTER, 0, 0); 258 toast.show(); 259 return false; 260 } 261 262 setCameraParameters(); 263 264 try { 265 mCamera0.setPreviewDisplay(mSurfaceHolder); 266 mCamera0.setDisplayOrientation(0); 267 int BUFFER_SIZE0 = CAMERA_PREVIEW_WIDTH * CAMERA_PREVIEW_HEIGHT * 3 / 2; // NV21 268 byte[][] mPreviewData0 = new byte[][]{new byte[BUFFER_SIZE0], new byte[BUFFER_SIZE0],new byte[BUFFER_SIZE0]}; 269 //================================ 270 for (byte[] buffer : mPreviewData0) 271 mCamera0.addCallbackBuffer(buffer); 272 mCamera0.setPreviewCallbackWithBuffer(this); 273 //================================== 274 mCamera0.startPreview(); 275 } catch (Exception e) { 276 mCamera0.release(); 277 return false; 278 } 279 280 mIsCameraOpened = true; 281 282 return true; 283 } 284 stopCamera()285 private void stopCamera() { 286 if (mIsCameraOpened) { 287 mCamera0.setPreviewCallback(null); 288 mCamera0.stopPreview(); 289 mCamera0.release(); 290 mCamera0 = null; 291 mIsCameraOpened = false; 292 } 293 294 } 295 setCameraParameters()296 private void setCameraParameters() { 297 Camera.Parameters parameters; 298 boolean checkWH = false; 299 parameters = mCamera0.getParameters(); 300 int nearest_width_index = 0; 301 int nearest_width_value = 1920; 302 303 List<Camera.Size> sizes = parameters.getSupportedPreviewSizes(); 304 for (int i = 0; i < sizes.size(); i++) { 305 Camera.Size size = sizes.get(i); 306 307 if (Math.abs(size.width-CAMERA_PREVIEW_WIDTH) < nearest_width_value ) { 308 nearest_width_value = Math.abs(size.width-CAMERA_PREVIEW_WIDTH); 309 nearest_width_index = i; 310 } 311 312 if ( (size.width == CAMERA_PREVIEW_WIDTH) && (size.height == CAMERA_PREVIEW_HEIGHT)) { 313 checkWH = true; 314 } 315 316 Log.v(TAG, "Camera Supported Preview Size = " + size.width + "x" + size.height); 317 } 318 if (!checkWH) { 319 Log.e(TAG, "Camera don't support this preview Size = " + CAMERA_PREVIEW_WIDTH + "x" + CAMERA_PREVIEW_HEIGHT); 320 CAMERA_PREVIEW_WIDTH = sizes.get(nearest_width_index).width; 321 CAMERA_PREVIEW_HEIGHT = sizes.get(nearest_width_index).height; 322 } 323 324 Log.w(TAG, "Use preview Size = " + CAMERA_PREVIEW_WIDTH + "x" + CAMERA_PREVIEW_HEIGHT); 325 326 parameters.setPreviewSize(CAMERA_PREVIEW_WIDTH, CAMERA_PREVIEW_HEIGHT); 327 328 if (parameters.isZoomSupported()) { 329 parameters.setZoom(0); 330 } 331 mCamera0.setParameters(parameters); 332 Log.i(TAG, "mCamera0 set parameters success."); 333 } 334 startTrack()335 private void startTrack() { 336 mInferenceResult.reset(); 337 mImageBufferQueue = new ImageBufferQueue(3, CAMERA_PREVIEW_WIDTH, CAMERA_PREVIEW_HEIGHT); 338 mStopInference = false; 339 mInferenceThread = new Thread(mInferenceRunnable); 340 mInferenceThread.start(); 341 } 342 stopTrack()343 private void stopTrack() { 344 345 mStopInference = true; 346 try { 347 if (mInferenceThread != null) { 348 mInferenceThread.join(); 349 } 350 } catch (InterruptedException e) { 351 e.printStackTrace(); 352 } 353 354 if (mImageBufferQueue != null) { 355 mImageBufferQueue.release(); 356 mImageBufferQueue = null; 357 } 358 } 359 360 private Thread mInferenceThread; 361 private Runnable mInferenceRunnable = new Runnable() { 362 public void run() { 363 364 int count = 0; 365 long oldTime = System.currentTimeMillis(); 366 long currentTime; 367 368 updateMainUI(1, 0); 369 370 String paramPath = fileDirPath + "/" + mModelName; 371 372 try { 373 mInferenceWrapper.initModel(CAMERA_PREVIEW_HEIGHT, CAMERA_PREVIEW_WIDTH, INPUT_CHANNEL, paramPath); 374 } catch (Exception e) { 375 e.printStackTrace(); 376 System.exit(1); 377 } 378 379 380 while (!mStopInference) { 381 ImageBufferQueue.ImageBuffer buffer = mImageBufferQueue.getReadyBuffer(); 382 383 if (buffer == null) { 384 try { 385 // Log.w(TAG, "buffer is null."); 386 sleep(10); 387 } catch (InterruptedException e) { 388 e.printStackTrace(); 389 } 390 continue; 391 } 392 393 InferenceResult.OutputBuffer outputs = mInferenceWrapper.run(buffer.mImage); 394 395 mInferenceResult.setResult(outputs); 396 397 mImageBufferQueue.releaseBuffer(buffer); 398 399 if (++count >= 30) { 400 currentTime = System.currentTimeMillis(); 401 402 float fps = count * 1000.f / (currentTime - oldTime); 403 404 // Log.d(TAG, "current fps = " + fps); 405 406 oldTime = currentTime; 407 count = 0; 408 updateMainUI(0, fps); 409 410 } 411 412 updateMainUI(1, 0); 413 } 414 415 mInferenceWrapper.deinit(); 416 } 417 }; 418 createFile(String fileName, int id)419 private void createFile(String fileName, int id) { 420 String filePath = fileDirPath + "/" + fileName; 421 try { 422 File dir = new File(fileDirPath); 423 424 if (!dir.exists()) { 425 dir.mkdirs(); 426 } 427 428 // 目录存在,则将apk中raw中的需要的文档复制到该目录下 429 File file = new File(filePath); 430 431 if (!file.exists() || isFirstRun()) { 432 433 InputStream ins = getResources().openRawResource(id);// 通过raw得到数据资源 434 FileOutputStream fos = new FileOutputStream(file); 435 byte[] buffer = new byte[8192]; 436 int count = 0; 437 438 while ((count = ins.read(buffer)) > 0) { 439 fos.write(buffer, 0, count); 440 } 441 442 fos.close(); 443 ins.close(); 444 445 Log.d(TAG, "Create " + filePath); 446 } 447 } catch (Exception e) { 448 e.printStackTrace(); 449 } 450 } 451 isFirstRun()452 private boolean isFirstRun() { 453 SharedPreferences sharedPreferences = getSharedPreferences("setting", MODE_PRIVATE); 454 boolean isFirstRun = sharedPreferences.getBoolean("isFirstRun", true); 455 SharedPreferences.Editor editor = sharedPreferences.edit(); 456 if (isFirstRun) { 457 editor.putBoolean("isFirstRun", false); 458 editor.commit(); 459 } 460 461 return isFirstRun; 462 } 463 464 // UI线程,用于更新处理结果 465 private Handler mHandler = new Handler() 466 { 467 public void handleMessage(Message msg) 468 { 469 if (msg.what == 0) { 470 float fps = (float) msg.obj; 471 472 DecimalFormat decimalFormat = new DecimalFormat("00.00"); 473 String fpsStr = decimalFormat.format(fps); 474 mFpsNum1.setText(String.valueOf(fpsStr.charAt(0))); 475 mFpsNum2.setText(String.valueOf(fpsStr.charAt(1))); 476 mFpsNum3.setText(String.valueOf(fpsStr.charAt(3))); 477 mFpsNum4.setText(String.valueOf(fpsStr.charAt(4))); 478 } else { 479 showTrackSelectResults(); 480 } 481 } 482 }; 483 updateMainUI(int type, Object data)484 private void updateMainUI(int type, Object data) { 485 Message msg = mHandler.obtainMessage(); 486 msg.what = type; 487 msg.obj = data; 488 mHandler.sendMessage(msg); 489 } 490 sp2px(float spValue)491 public static int sp2px(float spValue) { 492 Resources r = Resources.getSystem(); 493 final float scale = r.getDisplayMetrics().scaledDensity; 494 return (int) (spValue * scale + 0.5f); 495 } 496 showTrackSelectResults()497 private void showTrackSelectResults() { 498 499 int width = CAMERA_PREVIEW_WIDTH; 500 int height = CAMERA_PREVIEW_HEIGHT; 501 502 if (mTrackResultBitmap == null) { 503 504 mTrackResultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 505 mTrackResultCanvas = new Canvas(mTrackResultBitmap); 506 507 //用于画线 508 mTrackResultPaint = new Paint(); 509 mTrackResultPaint.setColor(0xff06ebff); 510 mTrackResultPaint.setStrokeJoin(Paint.Join.ROUND); 511 mTrackResultPaint.setStrokeCap(Paint.Cap.ROUND); 512 mTrackResultPaint.setStrokeWidth(4); 513 mTrackResultPaint.setStyle(Paint.Style.STROKE); 514 mTrackResultPaint.setTextAlign(Paint.Align.LEFT); 515 mTrackResultPaint.setTextSize(sp2px(10)); 516 mTrackResultPaint.setTypeface(Typeface.SANS_SERIF); 517 mTrackResultPaint.setFakeBoldText(false); 518 519 //用于文字 520 mTrackResultTextPaint = new Paint(); 521 mTrackResultTextPaint.setColor(0xff06ebff); 522 mTrackResultTextPaint.setStrokeWidth(2); 523 mTrackResultTextPaint.setTextAlign(Paint.Align.LEFT); 524 mTrackResultTextPaint.setTextSize(sp2px(12)); 525 mTrackResultTextPaint.setTypeface(Typeface.SANS_SERIF); 526 mTrackResultTextPaint.setFakeBoldText(false); 527 528 529 mPorterDuffXfermodeClear = new PorterDuffXfermode(PorterDuff.Mode.CLEAR); 530 mPorterDuffXfermodeSRC = new PorterDuffXfermode(PorterDuff.Mode.SRC); 531 } 532 533 // clear canvas 534 mTrackResultPaint.setXfermode(mPorterDuffXfermodeClear); 535 mTrackResultCanvas.drawPaint(mTrackResultPaint); 536 mTrackResultPaint.setXfermode(mPorterDuffXfermodeSRC); 537 538 //detect result 539 ArrayList<InferenceResult.Recognition> recognitions = mInferenceResult.getResult(mInferenceWrapper); 540 for (int i=0; i<recognitions.size(); ++i) { 541 InferenceResult.Recognition rego = recognitions.get(i); 542 RectF detection = rego.getLocation(); 543 544 detection.left *= width; 545 detection.right *= width; 546 detection.top *= height; 547 detection.bottom *= height; 548 549 // Log.d(TAG, rego.toString()); 550 // Log.d(TAG, detection.toString()); 551 552 mTrackResultCanvas.drawRect(detection, mTrackResultPaint); 553 mTrackResultCanvas.drawText(rego.getTrackId() + " - " + mInferenceResult.mPostProcess.getLabelTitle(rego.getId()), 554 detection.left+5, detection.bottom-5, mTrackResultTextPaint); 555 } 556 557 mTrackResultView.setScaleType(ImageView.ScaleType.FIT_XY); 558 mTrackResultView.setImageBitmap(mTrackResultBitmap); 559 } 560 getPlatform()561 private String getPlatform()//取平台版本 562 { 563 String platform = null; 564 try { 565 Class<?> classType = Class.forName("android.os.SystemProperties"); 566 Method getMethod = classType.getDeclaredMethod("get", new Class<?>[]{String.class}); 567 platform = (String) getMethod.invoke(classType, new Object[]{"ro.board.platform"}); 568 } catch (Exception e) { 569 e.printStackTrace(); 570 } 571 return platform; 572 } 573 } 574