MainActivity.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright 2020 Google LLC. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.example.myapplication;
  17. import android.graphics.SurfaceTexture;
  18. import android.os.Bundle;
  19. import android.util.Log;
  20. import android.util.Size;
  21. import android.view.SurfaceHolder;
  22. import android.view.SurfaceView;
  23. import android.view.View;
  24. import android.view.ViewGroup;
  25. import androidx.appcompat.app.AppCompatActivity;
  26. import com.google.mediapipe.components.CameraHelper;
  27. import com.google.mediapipe.components.CameraXPreviewHelper;
  28. import com.google.mediapipe.components.ExternalTextureConverter;
  29. import com.google.mediapipe.components.FrameProcessor;
  30. import com.google.mediapipe.components.PermissionHelper;
  31. import com.google.mediapipe.formats.proto.LandmarkProto.NormalizedLandmarkList;
  32. import com.google.mediapipe.formats.proto.LandmarkProto.NormalizedLandmark;
  33. import com.google.mediapipe.framework.AndroidAssetUtil;
  34. import com.google.mediapipe.framework.PacketGetter;
  35. import com.google.mediapipe.glutil.EglManager;
  36. import com.google.protobuf.InvalidProtocolBufferException;
  37. import android.content.pm.ApplicationInfo;
  38. import android.content.pm.PackageManager;
  39. import android.content.pm.PackageManager.NameNotFoundException;
  40. /**
  41. * Main activity of MediaPipe example apps.
  42. */
  43. public class MainActivity extends AppCompatActivity {
  44. private static final String TAG = "MainActivity";
  45. private static final String BINARY_GRAPH_NAME = "pose_tracking_gpu.binarypb";
  46. private static final String INPUT_VIDEO_STREAM_NAME = "input_video";
  47. private static final String OUTPUT_VIDEO_STREAM_NAME = "output_video";
  48. private static final String OUTPUT_LANDMARKS_STREAM_NAME = "pose_landmarks";
  49. // Flips the camera-preview frames vertically before sending them into FrameProcessor to be
  50. // processed in a MediaPipe graph, and flips the processed frames back when they are displayed.
  51. // This is needed because OpenGL represents images assuming the image origin is at the bottom-left
  52. // corner, whereas MediaPipe in general assumes the image origin is at top-left.
  53. private static final boolean FLIP_FRAMES_VERTICALLY = true;
  54. static {
  55. // Load all native libraries needed by the app.
  56. System.loadLibrary("mediapipe_jni");
  57. System.loadLibrary("opencv_java3");
  58. }
  59. // {@link SurfaceTexture} where the camera-preview frames can be accessed.
  60. private SurfaceTexture previewFrameTexture;
  61. // {@link SurfaceView} that displays the camera-preview frames processed by a MediaPipe graph.
  62. private SurfaceView previewDisplayView;
  63. // Creates and manages an {@link EGLContext}.
  64. private EglManager eglManager;
  65. // Sends camera-preview frames into a MediaPipe graph for processing, and displays the processed
  66. // frames onto a {@link Surface}.
  67. private FrameProcessor processor;
  68. // Converts the GL_TEXTURE_EXTERNAL_OES texture from Android camera into a regular texture to be
  69. // consumed by {@link FrameProcessor} and the underlying MediaPipe graph.
  70. private ExternalTextureConverter converter;
  71. // ApplicationInfo for retrieving metadata defined in the manifest.
  72. private ApplicationInfo applicationInfo;
  73. // Handles camera access via the {@link CameraX} Jetpack support library.
  74. private CameraXPreviewHelper cameraHelper;
  75. private ResultHandler resultHandler;
  76. @Override
  77. protected void onCreate(Bundle savedInstanceState) {
  78. super.onCreate(savedInstanceState);
  79. setContentView(getContentViewLayoutResId());
  80. resultHandler = new ResultHandler(this);
  81. previewDisplayView = new SurfaceView(this);
  82. setupPreviewDisplayView();
  83. try {
  84. applicationInfo =
  85. getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
  86. } catch (NameNotFoundException e) {
  87. Log.e(TAG, "Cannot find application info: " + e);
  88. }
  89. // Initialize asset manager so that MediaPipe native libraries can access the app assets, e.g.,
  90. // binary graphs.
  91. AndroidAssetUtil.initializeNativeAssetManager(this);
  92. eglManager = new EglManager(null);
  93. processor =
  94. new FrameProcessor(
  95. this,
  96. eglManager.getNativeContext(),
  97. BINARY_GRAPH_NAME,
  98. INPUT_VIDEO_STREAM_NAME,
  99. OUTPUT_VIDEO_STREAM_NAME);
  100. processor
  101. .getVideoSurfaceOutput()
  102. .setFlipY(FLIP_FRAMES_VERTICALLY);
  103. processor.addPacketCallback(
  104. OUTPUT_LANDMARKS_STREAM_NAME,
  105. (packet) -> {
  106. try {
  107. byte[] landmarksRaw = PacketGetter.getProtoBytes(packet);
  108. NormalizedLandmarkList poseLandmarks = NormalizedLandmarkList.parseFrom(landmarksRaw);
  109. NormalizedLandmark lm = poseLandmarks.getLandmark(0);
  110. resultHandler.handlePosition(lm.getX(), lm.getY());
  111. } catch (InvalidProtocolBufferException exception) {
  112. Log.e(TAG, "failed to get proto.", exception);
  113. }
  114. }
  115. );
  116. PermissionHelper.checkAndRequestCameraPermissions(this);
  117. }
  118. // Used to obtain the content view for this application. If you are extending this class, and
  119. // have a custom layout, override this method and return the custom layout.
  120. protected int getContentViewLayoutResId() {
  121. return R.layout.activity_main;
  122. }
  123. @Override
  124. protected void onResume() {
  125. super.onResume();
  126. converter =
  127. new ExternalTextureConverter(
  128. eglManager.getContext(), 2);
  129. converter.setFlipY(FLIP_FRAMES_VERTICALLY);
  130. converter.setConsumer(processor);
  131. if (PermissionHelper.cameraPermissionsGranted(this)) {
  132. startCamera();
  133. }
  134. }
  135. @Override
  136. protected void onPause() {
  137. super.onPause();
  138. converter.close();
  139. // Hide preview display until we re-open the camera again.
  140. previewDisplayView.setVisibility(View.GONE);
  141. }
  142. @Override
  143. public void onRequestPermissionsResult(
  144. int requestCode, String[] permissions, int[] grantResults) {
  145. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  146. PermissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
  147. }
  148. protected void onCameraStarted(SurfaceTexture surfaceTexture) {
  149. previewFrameTexture = surfaceTexture;
  150. // Make the display view visible to start showing the preview. This triggers the
  151. // SurfaceHolder.Callback added to (the holder of) previewDisplayView.
  152. previewDisplayView.setVisibility(View.VISIBLE);
  153. }
  154. protected Size cameraTargetResolution() {
  155. return null; // No preference and let the camera (helper) decide.
  156. }
  157. public void startCamera() {
  158. cameraHelper = new CameraXPreviewHelper();
  159. cameraHelper.setOnCameraStartedListener(
  160. surfaceTexture -> {
  161. onCameraStarted(surfaceTexture);
  162. });
  163. CameraHelper.CameraFacing cameraFacing = CameraHelper.CameraFacing.FRONT;
  164. cameraHelper.startCamera(
  165. this, cameraFacing,
  166. /*unusedSurfaceTexture=*/ null, cameraTargetResolution());
  167. }
  168. protected Size computeViewSize(int width, int height) {
  169. return new Size(width, height);
  170. }
  171. protected void onPreviewDisplaySurfaceChanged(
  172. SurfaceHolder holder, int format, int width, int height) {
  173. // (Re-)Compute the ideal size of the camera-preview display (the area that the
  174. // camera-preview frames get rendered onto, potentially with scaling and rotation)
  175. // based on the size of the SurfaceView that contains the display.
  176. Size viewSize = computeViewSize(width, height);
  177. Size displaySize = cameraHelper.computeDisplaySizeFromViewSize(viewSize);
  178. boolean isCameraRotated = cameraHelper.isCameraRotated();
  179. Log.v(TAG, "Meaning the size of the phone display screen ("
  180. + displaySize.getWidth() + "," + displaySize.getHeight() + ")");
  181. // Connect the converter to the camera-preview frames as its input (via
  182. // previewFrameTexture), and configure the output width and height as the computed
  183. // display size.
  184. converter.setSurfaceTextureAndAttachToGLContext(
  185. previewFrameTexture,
  186. isCameraRotated ? displaySize.getHeight() : displaySize.getWidth(),
  187. isCameraRotated ? displaySize.getWidth() : displaySize.getHeight());
  188. }
  189. private void setupPreviewDisplayView() {
  190. previewDisplayView.setVisibility(View.GONE);
  191. ViewGroup viewGroup = findViewById(R.id.preview_display_layout);
  192. viewGroup.addView(previewDisplayView);
  193. previewDisplayView
  194. .getHolder()
  195. .addCallback(
  196. new SurfaceHolder.Callback() {
  197. @Override
  198. public void surfaceCreated(SurfaceHolder holder) {
  199. processor.getVideoSurfaceOutput().setSurface(holder.getSurface());
  200. Log.d("Surface","Surface Created");
  201. }
  202. @Override
  203. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  204. onPreviewDisplaySurfaceChanged(holder, format, width, height);
  205. Log.d("Surface","Surface Changed");
  206. }
  207. @Override
  208. public void surfaceDestroyed(SurfaceHolder holder) {
  209. processor.getVideoSurfaceOutput().setSurface(null);
  210. Log.d("Surface","Surface destroy");
  211. }
  212. });
  213. }
  214. }