Last active
March 27, 2019 08:00
-
-
Save iegrsy/eb0a707ac0cbd069a45d926e771b4df0 to your computer and use it in GitHub Desktop.
Android Camera Preview Fragment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
tools:context=".MainActivity"> | |
<FrameLayout | |
android:id="@+id/main_container" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
app:layout_constraintBottom_toBottomOf="parent" | |
app:layout_constraintLeft_toLeftOf="parent" | |
app:layout_constraintRight_toRightOf="parent" | |
app:layout_constraintTop_toTopOf="parent" /> | |
</android.support.constraint.ConstraintLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.graphics.ImageFormat; | |
import android.hardware.Camera; | |
import android.os.Bundle; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.Fragment; | |
import android.view.Display; | |
import android.view.LayoutInflater; | |
import android.view.Surface; | |
import android.view.SurfaceHolder; | |
import android.view.SurfaceView; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.view.WindowManager; | |
import java.util.List; | |
import static java.lang.Math.ceil; | |
public class CameraPreviewFragment extends Fragment implements SurfaceHolder.Callback, Camera.PreviewCallback { | |
private Camera mCamera; | |
private Camera.Size mPreviewSize; | |
private byte[] mPreviewBuffer; | |
private Context context; | |
private SurfaceHolder holder; | |
private boolean isPreviewRunning = false; | |
public CameraPreviewFragment() { | |
} | |
@Nullable | |
@Override | |
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { | |
View rootView = inflater.inflate(R.layout.fragment_camera_preview, container, false); | |
SurfaceView surfaceView = (SurfaceView) rootView.findViewById(R.id.preview_surface); | |
holder = surfaceView.getHolder(); | |
holder.addCallback(this); | |
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); | |
return rootView; | |
} | |
@Override | |
public void onAttach(Context context) { | |
super.onAttach(context); | |
this.context = context; | |
} | |
@Override | |
public void onPreviewFrame(byte[] data, Camera camera) { | |
camera.addCallbackBuffer(mPreviewBuffer); | |
// TODO: Implement this: [data ==> Frame format YV12] | |
} | |
@Override | |
public void surfaceCreated(SurfaceHolder holder) { | |
try { | |
startCamera(holder); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
@Override | |
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { | |
setupCameraParameters(context, mCamera); | |
mCamera.startPreview(); | |
} | |
@Override | |
public void surfaceDestroyed(SurfaceHolder holder) { | |
stopCamera(); | |
} | |
private void startCamera(SurfaceHolder surfaceHolder) throws Exception { | |
if (isPreviewRunning) | |
stopCamera(); | |
mCamera = Camera.open(); | |
mPreviewSize = setupCameraParameters(context, mCamera); | |
mPreviewBuffer = new byte[calculateBufferSize(mPreviewSize.width, mPreviewSize.height)]; | |
surfaceHolder.setFixedSize(mPreviewSize.width, mPreviewSize.height); | |
mCamera.setPreviewDisplay(surfaceHolder); | |
mCamera.addCallbackBuffer(mPreviewBuffer); | |
mCamera.setPreviewCallbackWithBuffer(this); | |
mCamera.startPreview(); | |
isPreviewRunning = true; | |
} | |
private void stopCamera() { | |
if (mCamera != null) { | |
mCamera.setPreviewCallback(null); | |
mCamera.stopPreview(); | |
mCamera.release(); | |
mCamera = null; | |
} | |
isPreviewRunning = false; | |
} | |
private static Camera.Size setupCameraParameters(Context context, Camera camera) { | |
Camera.Parameters parameters = camera.getParameters(); | |
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); | |
Camera.Size previewSize = previewSizes.get(0); //Max preview size | |
parameters.setPreviewFormat(ImageFormat.YV12); | |
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO); | |
parameters.setPreviewSize(previewSize.width, previewSize.height); | |
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); | |
camera.setParameters(parameters); | |
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); | |
if (display.getRotation() == Surface.ROTATION_0) { | |
camera.setDisplayOrientation(90); | |
} else if (display.getRotation() == Surface.ROTATION_270) { | |
camera.setDisplayOrientation(180); | |
} | |
return previewSize; | |
} | |
private static int calculateBufferSize(int w, int h) { | |
int yStride = (int) ceil(w / 16.0) * 16; | |
int uvStride = (int) ceil((yStride / 2.0) / 16.0) * 16; | |
int ySize = yStride * h; | |
int uvSize = uvStride * h / 2; | |
return ySize + uvSize * 2; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
tools:context=".CameraPreviewFragment"> | |
<SurfaceView | |
android:id="@+id/preview_surface" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_gravity="center" /> | |
</FrameLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.Manifest; | |
import android.app.Activity; | |
import android.app.AlertDialog; | |
import android.app.Dialog; | |
import android.content.DialogInterface; | |
import android.content.pm.PackageManager; | |
import android.os.Build; | |
import android.support.annotation.NonNull; | |
import android.support.v4.app.DialogFragment; | |
import android.support.v4.app.Fragment; | |
import android.support.v4.app.FragmentManager; | |
import android.support.v4.content.ContextCompat; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
public class MainActivity extends AppCompatActivity { | |
public static final String[] PERMISSION_STRINGS = new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}; | |
public static final int REQUEST_CAMERA_PERMISSION = 123; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
setContainer(new CameraPreviewFragment()); | |
} | |
private void setContainer(Fragment fragment) { | |
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || | |
ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { | |
requestCameraPermission(); | |
return; | |
} | |
FragmentManager fragmentManager = getSupportFragmentManager(); | |
fragmentManager.beginTransaction().replace(R.id.main_container, fragment).commitNow(); | |
} | |
private void requestCameraPermission() { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) | |
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { | |
new ConfirmationDialog().show(getSupportFragmentManager(), "Camera Permission"); | |
} else { | |
requestPermissions(PERMISSION_STRINGS, REQUEST_CAMERA_PERMISSION); | |
} | |
} | |
public static class ConfirmationDialog extends DialogFragment { | |
@NonNull | |
@Override | |
public Dialog onCreateDialog(Bundle savedInstanceState) { | |
final Fragment parent = getParentFragment(); | |
return new AlertDialog.Builder(getActivity()) | |
.setMessage("Need permissions") | |
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int which) { | |
parent.requestPermissions(PERMISSION_STRINGS, REQUEST_CAMERA_PERMISSION); | |
} | |
}) | |
.setNegativeButton(android.R.string.cancel, | |
new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int which) { | |
Activity activity = parent.getActivity(); | |
if (activity != null) { | |
activity.finish(); | |
} | |
} | |
}) | |
.create(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment