pull/1/head
Dylan McIntyre 8 years ago
parent 5940f5b1b5
commit 782efedc6b
  1. 13
      README.md
  2. 7
      camerakit/build.gradle
  3. 27
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  4. 493
      camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java
  5. 29
      camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java
  6. 2
      camerakit/src/main/base/com/flurgle/camerakit/PreviewImpl.java
  7. 0
      camerakit/src/main/base/com/flurgle/camerakit/TextureViewPreview.java
  8. 4
      camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java
  9. 74
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  10. 14
      camerakit/src/main/java/com/flurgle/camerakit/types/PictureMode.java
  11. 8
      camerakit/src/main/res/values/attrs.xml
  12. 14
      camerakit/src/main/types/com/flurgle/camerakit/CaptureMode.java
  13. 2
      camerakit/src/main/types/com/flurgle/camerakit/Facing.java
  14. 2
      camerakit/src/main/types/com/flurgle/camerakit/Flash.java
  15. 2
      camerakit/src/main/types/com/flurgle/camerakit/TapToFocus.java
  16. 2
      camerakit/src/main/utils/com/flurgle/camerakit/AspectRatio.java
  17. 6
      camerakit/src/main/utils/com/flurgle/camerakit/CenterCrop.java
  18. 2
      camerakit/src/main/utils/com/flurgle/camerakit/DisplayOrientationDetector.java
  19. 2
      camerakit/src/main/utils/com/flurgle/camerakit/Size.java
  20. 5
      camerakit/src/main/utils/com/flurgle/camerakit/YuvUtils.java
  21. 4
      demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java
  22. 4
      demo/src/main/java/com/flurgle/camerakit/demo/PreviewActivity.java
  23. 2
      demo/src/main/java/com/flurgle/camerakit/demo/ResultHolder.java
  24. 2
      demo/src/main/res/layout/activity_main.xml

@ -8,6 +8,7 @@ Try out all the unique features using the CameraKit Demo from the Google Play st
<a href='https://play.google.com/store/apps/details?id=com.flurgle.camerakit.demo&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height='80'/></a> <a href='https://play.google.com/store/apps/details?id=com.flurgle.camerakit.demo&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height='80'/></a>
<img src=".repo/demo1.png" width="120"/>
## Table of Contents ## Table of Contents
@ -19,7 +20,7 @@ Try out all the unique features using the CameraKit Demo from the Google Play st
- [`ckCropOutput`](#ckcropoutput) - [`ckCropOutput`](#ckcropoutput)
- [`ckFacing`](#ckfacing) - [`ckFacing`](#ckfacing)
- [`ckFlash`](#ckflash) - [`ckFlash`](#ckflash)
- [`ckPictureMode`](#ckpicturemode) - [`ckCaptureMode`](#ckcapturemode)
- [`ckTapToFocus`](#cktaptofocus) - [`ckTapToFocus`](#cktaptofocus)
- [`ckAutoFocus`](#ckautofocus) - [`ckAutoFocus`](#ckautofocus)
- [`ckCaptureSize`](#ckcapturesize) - [`ckCaptureSize`](#ckcapturesize)
@ -125,7 +126,7 @@ camera.setCameraListener(new CameraListener() {
camerakit:ckCropOutput="true" camerakit:ckCropOutput="true"
camerakit:ckFacing="back" camerakit:ckFacing="back"
camerakit:ckFlash="off" camerakit:ckFlash="off"
camerakit:ckPictureMode="quality" camerakit:ckCaptureMode="quality"
camerakit:ckTapToFocus="on" camerakit:ckTapToFocus="on"
camerakit:ckAutoFocus="true" camerakit:ckAutoFocus="true"
camerakit:ckCaptureSize="8" /> camerakit:ckCaptureSize="8" />
@ -154,13 +155,13 @@ camera.setCameraListener(new CameraListener() {
| `on` | Default `CameraView` flash to on. | | `on` | Default `CameraView` flash to on. |
| `auto` | Default `CameraView` flash to automatic. | | `auto` | Default `CameraView` flash to automatic. |
#### `ckPictureMode` #### `ckCaptureMode`
| Value | Description | | Value | Description |
| --------------| -------------| | --------------| -------------|
| `quality` | Use normal Android Camera API image capturing. | | `standard` | Use normal Android Camera API image capturing. |
| `speed` | Freeze the `CameraView` preview and grab a `Bitmap` of the frame. | | `still` | Freeze the `CameraView` preview and grab a `Bitmap` of the frame. |
| `auto` | Default picture mode to `quality`, but fallback to `speed` if capturing is determined to be too slow. | | `auto` (coming soon) | Default picture mode to `standard`, but fallback to `still` if capturing is determined to be too slow. |
#### `ckTapToFocus` #### `ckTapToFocus`

@ -22,6 +22,13 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
sourceSets {
main.java.srcDirs += 'src/main/base'
main.java.srcDirs += 'src/main/api16'
main.java.srcDirs += 'src/main/api21'
main.java.srcDirs += 'src/main/types'
main.java.srcDirs += 'src/main/utils'
}
} }
dependencies { dependencies {

@ -9,10 +9,6 @@ import android.support.annotation.NonNull;
import android.support.v4.util.SparseArrayCompat; import android.support.v4.util.SparseArrayCompat;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import com.flurgle.camerakit.utils.AspectRatio;
import com.flurgle.camerakit.utils.Size;
import com.flurgle.camerakit.utils.YuvUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
@ -23,6 +19,7 @@ import java.util.TreeSet;
public class Camera1 extends CameraImpl { public class Camera1 extends CameraImpl {
private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>(); private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>();
static { static {
FLASH_MODES.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF); FLASH_MODES.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF);
FLASH_MODES.put(CameraKit.Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON); FLASH_MODES.put(CameraKit.Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON);
@ -30,6 +27,7 @@ public class Camera1 extends CameraImpl {
} }
private static final SparseArrayCompat<Integer> FACING_MODES = new SparseArrayCompat<>(); private static final SparseArrayCompat<Integer> FACING_MODES = new SparseArrayCompat<>();
static { static {
FACING_MODES.put(CameraKit.Constants.FACING_BACK, Camera.CameraInfo.CAMERA_FACING_BACK); FACING_MODES.put(CameraKit.Constants.FACING_BACK, Camera.CameraInfo.CAMERA_FACING_BACK);
FACING_MODES.put(CameraKit.Constants.FACING_FRONT, Camera.CameraInfo.CAMERA_FACING_FRONT); FACING_MODES.put(CameraKit.Constants.FACING_FRONT, Camera.CameraInfo.CAMERA_FACING_FRONT);
@ -63,7 +61,7 @@ public class Camera1 extends CameraImpl {
this.mCameraListener = cameraListener; this.mCameraListener = cameraListener;
this.mPreviewSizes = new TreeSet<>(); this.mPreviewSizes = new TreeSet<>();
this.mCaptureSizes = new TreeSet<>(); this.mCaptureSizes = new TreeSet<>();
this.mVideoFile = new File(getView().getContext().getExternalFilesDir(null), "video.mp4"); this.mVideoFile = new File(mPreview.getView().getContext().getExternalFilesDir(null), "video.mp4");
preview.setCallback(new PreviewImpl.Callback() { preview.setCallback(new PreviewImpl.Callback() {
@Override @Override
@ -194,20 +192,11 @@ public class Camera1 extends CameraImpl {
} }
@Override @Override
boolean getAutoFocus() { void captureStandard() {
if (!isCameraOpened()) {
return mAutoFocus;
}
String focusMode = mCameraParameters.getFocusMode();
return focusMode != null && focusMode.contains("continuous");
}
@Override
void capturePicture() {
if (!isCameraOpened()) { if (!isCameraOpened()) {
throw new IllegalStateException("Camera is not ready. Call start() before takePicture()."); throw new IllegalStateException("Camera is not ready. Call start() before takePicture().");
} }
if (getAutoFocus()) { if (mAutoFocus) {
mCamera.cancelAutoFocus(); mCamera.cancelAutoFocus();
mCamera.autoFocus(new Camera.AutoFocusCallback() { mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override @Override
@ -238,7 +227,7 @@ public class Camera1 extends CameraImpl {
new Thread(new ProcessStillTask(data, camera, mCameraInfo, new ProcessStillTask.OnStillProcessedListener() { new Thread(new ProcessStillTask(data, camera, mCameraInfo, new ProcessStillTask.OnStillProcessedListener() {
@Override @Override
public void onStillProcessed(final YuvImage yuv) { public void onStillProcessed(final YuvImage yuv) {
getView().post(new Runnable() { mPreview.getView().post(new Runnable() {
@Override @Override
public void run() { public void run() {
mCameraListener.onPictureTaken(yuv); mCameraListener.onPictureTaken(yuv);
@ -493,12 +482,12 @@ public class Camera1 extends CameraImpl {
} }
@Override @Override
Size getCaptureSize() { Size getCaptureResolution() {
return mCaptureSize; return mCaptureSize;
} }
@Override @Override
Size getPreviewSize() { Size getPreviewResolution() {
return mPreviewSize; return mPreviewSize;
} }
} }

@ -0,0 +1,493 @@
package com.flurgle.camerakit;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.util.SparseArrayCompat;
import android.view.SurfaceHolder;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
public class Camera2 extends CameraImpl {
private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>();
static {
FLASH_MODES.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF);
FLASH_MODES.put(CameraKit.Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON);
FLASH_MODES.put(CameraKit.Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO);
}
private static final SparseArrayCompat<Integer> FACING_MODES = new SparseArrayCompat<>();
static {
FACING_MODES.put(CameraKit.Constants.FACING_BACK, Camera.CameraInfo.CAMERA_FACING_BACK);
FACING_MODES.put(CameraKit.Constants.FACING_FRONT, Camera.CameraInfo.CAMERA_FACING_FRONT);
}
private File mVideoFile;
private int mCameraId;
private Camera mCamera;
private Camera.Parameters mCameraParameters;
private final Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
private Size mPreviewSize;
private Size mCaptureSize;
private boolean mShowingPreview;
private boolean mAutoFocus;
private int mFacing;
private int mFlash;
private int mDisplayOrientation;
private TreeSet<Size> mPreviewSizes;
private TreeSet<Size> mCaptureSizes;
private MediaRecorder mMediaRecorder;
private CameraListener mCameraListener;
Camera2(@NonNull CameraListener cameraListener, @NonNull PreviewImpl preview) {
super(cameraListener, preview);
this.mCameraListener = cameraListener;
this.mPreviewSizes = new TreeSet<>();
this.mCaptureSizes = new TreeSet<>();
this.mVideoFile = new File(mPreview.getView().getContext().getExternalFilesDir(null), "video.mp4");
preview.setCallback(new PreviewImpl.Callback() {
@Override
public void onSurfaceChanged() {
if (mCamera != null) {
setUpPreview();
adjustCameraParameters();
}
}
});
}
@Override
void start() {
setFacingInternal(mFacing);
openCamera();
if (mPreview.isReady()) {
setUpPreview();
}
mShowingPreview = true;
mCamera.startPreview();
}
@Override
void stop() {
if (mCamera != null) {
mCamera.stopPreview();
}
mShowingPreview = false;
releaseCamera();
}
@Override
boolean isCameraOpened() {
return mCamera != null;
}
@Override
void setFacing(int facing) {
if (mFacing == facing) {
return;
}
if (setFacingInternal(facing) && isCameraOpened()) {
stop();
start();
}
}
private boolean setFacingInternal(int facing) {
int trueValue = FACING_MODES.get(facing, -1);
if (trueValue == -1) {
return false;
}
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, mCameraInfo);
if (mCameraInfo.facing == trueValue) {
mCameraId = i;
mFacing = facing;
return true;
}
}
return false;
}
@Override
void setFlash(int flash) {
if (flash == mFlash) {
return;
}
if (setFlashInternal(flash)) {
mCamera.setParameters(mCameraParameters);
}
}
private boolean setFlashInternal(int flash) {
if (isCameraOpened()) {
List<String> modes = mCameraParameters.getSupportedFlashModes();
String mode = FLASH_MODES.get(flash);
if (modes != null && modes.contains(mode)) {
mCameraParameters.setFlashMode(mode);
mFlash = flash;
return true;
}
String currentMode = FLASH_MODES.get(mFlash);
if (modes == null || !modes.contains(currentMode)) {
mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mFlash = CameraKit.Constants.FLASH_OFF;
return true;
}
return false;
} else {
mFlash = flash;
return false;
}
}
@Override
void setAutoFocus(boolean autoFocus) {
if (autoFocus == mAutoFocus) {
return;
}
if (setAutoFocusInternal(autoFocus)) {
mCamera.setParameters(mCameraParameters);
}
}
private boolean setAutoFocusInternal(boolean autoFocus) {
mAutoFocus = autoFocus;
if (isCameraOpened()) {
final List<String> modes = mCameraParameters.getSupportedFocusModes();
if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
} else {
mCameraParameters.setFocusMode(modes.get(0));
}
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
return true;
} else {
return false;
}
}
@Override
void captureStandard() {
if (!isCameraOpened()) {
throw new IllegalStateException("Camera is not ready. Call start() before takePicture().");
}
if (mAutoFocus) {
mCamera.cancelAutoFocus();
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
takePictureInternal();
}
});
} else {
takePictureInternal();
}
}
void takePictureInternal() {
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
mCameraListener.onPictureTaken(data);
camera.startPreview();
}
});
}
@Override
void captureStill() {
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
new Thread(new ProcessStillTask(data, camera, mCameraInfo, new ProcessStillTask.OnStillProcessedListener() {
@Override
public void onStillProcessed(final YuvImage yuv) {
mPreview.getView().post(new Runnable() {
@Override
public void run() {
mCameraListener.onPictureTaken(yuv);
}
});
}
})).start();
}
});
}
static class ProcessStillTask implements Runnable {
byte[] data;
Camera camera;
Camera.CameraInfo cameraInfo;
OnStillProcessedListener onStillProcessedListener;
public ProcessStillTask(byte[] data, Camera camera, Camera.CameraInfo cameraInfo, OnStillProcessedListener onStillProcessedListener) {
this.data = data;
this.camera = camera;
this.cameraInfo = cameraInfo;
this.onStillProcessedListener = onStillProcessedListener;
}
@Override
public void run() {
Camera.Parameters parameters = camera.getParameters();
int width = parameters.getPreviewSize().width;
int height = parameters.getPreviewSize().height;
int rotation = cameraInfo.orientation;
byte[] rotatedData = YuvUtils.rotateNV21(data, width, height, rotation);
int postWidth;
int postHeight;
switch (rotation) {
case 90:
case 270:
postWidth = height;
postHeight = width;
break;
case 0:
case 180:
default:
postWidth = width;
postHeight = height;
break;
}
YuvImage yuv = new YuvImage(rotatedData, parameters.getPreviewFormat(), postWidth, postHeight, null);
onStillProcessedListener.onStillProcessed(yuv);
}
interface OnStillProcessedListener {
void onStillProcessed(YuvImage yuv);
}
}
@Override
void startVideo() {
try {
prepareMediaRecorder();
} catch (IOException e) {
if (mMediaRecorder != null) {
mMediaRecorder.release();
}
return;
}
}
void prepareMediaRecorder() throws IOException {
mCamera.unlock();
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
mMediaRecorder.setOutputFile(mVideoFile.getAbsolutePath());
mMediaRecorder.setOrientationHint(mCameraInfo.orientation);
mMediaRecorder.prepare();
mMediaRecorder.start();
}
@Override
void endVideo() {
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder = null;
}
mCameraListener.onVideoTaken(mVideoFile);
}
@Override
void focus() {
mCamera.autoFocus(null);
}
@Override
void setDisplayOrientation(int displayOrientation) {
if (mDisplayOrientation == displayOrientation) {
return;
}
mDisplayOrientation = displayOrientation;
if (isCameraOpened()) {
int cameraRotation = calcCameraRotation(displayOrientation);
mCameraParameters.setRotation(cameraRotation);
mCamera.setParameters(mCameraParameters);
final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14;
if (needsToStopPreview) {
mCamera.stopPreview();
}
mCamera.setDisplayOrientation(cameraRotation);
if (needsToStopPreview) {
mCamera.startPreview();
}
}
}
private int calcCameraRotation(int rotation) {
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
return (360 - (mCameraInfo.orientation + rotation) % 360) % 360;
} else {
return (mCameraInfo.orientation - rotation + 360) % 360;
}
}
private void setUpPreview() {
try {
if (mPreview.getOutputClass() == SurfaceHolder.class) {
final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14;
if (needsToStopPreview) {
mCamera.stopPreview();
}
mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
if (needsToStopPreview) {
mCamera.startPreview();
}
} else {
mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void adjustCameraParameters() {
SortedSet<Size> sizes = mPreviewSizes;
mPreviewSize = chooseOptimalSize(sizes);
final Camera.Size currentSize = mCameraParameters.getPictureSize();
if (currentSize.width != mPreviewSize.getWidth() || currentSize.height != mPreviewSize.getHeight()) {
Iterator<Size> iterator = mCaptureSizes.descendingIterator();
Size pictureSize;
while ((pictureSize = iterator.next()) != null) {
if (AspectRatio.of(mPreviewSize.getWidth(), mPreviewSize.getHeight()).matches(pictureSize)) {
break;
}
}
if (pictureSize == null) {
pictureSize = mCaptureSizes.last();
}
mCaptureSize = pictureSize;
if (mShowingPreview) {
mCamera.stopPreview();
}
mCameraParameters.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreview.setTruePreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation) + (mFacing == CameraKit.Constants.FACING_FRONT ? 180 : 0));
setAutoFocusInternal(mAutoFocus);
//setFlashInternal(mFlash);
mCamera.setParameters(mCameraParameters);
if (mShowingPreview) {
mCamera.startPreview();
}
}
}
private Size chooseOptimalSize(SortedSet<Size> sizes) {
if (!mPreview.isReady()) { // Not yet laid out
return sizes.last(); // Return the smallest size
}
int desiredWidth;
int desiredHeight;
final int surfaceWidth = mPreview.getWidth();
final int surfaceHeight = mPreview.getHeight();
if (mDisplayOrientation == 90 || mDisplayOrientation == 270) {
desiredWidth = surfaceHeight;
desiredHeight = surfaceWidth;
} else {
desiredWidth = surfaceWidth;
desiredHeight = surfaceHeight;
}
Size result = null;
for (Size size : sizes) { // Iterate from small to large
if (desiredWidth <= size.getWidth() && desiredHeight <= size.getHeight()) {
return size;
}
result = size;
}
return result;
}
private void openCamera() {
if (mCamera != null) {
releaseCamera();
}
mCamera = Camera.open(mCameraId);
mCameraParameters = mCamera.getParameters();
// Supported preview sizes
mPreviewSizes.clear();
for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()) {
mPreviewSizes.add(new Size(size.width, size.height));
}
// Supported picture sizes;
mCaptureSizes.clear();
for (Camera.Size size : mCameraParameters.getSupportedPictureSizes()) {
mCaptureSizes.add(new Size(size.width, size.height));
}
adjustCameraParameters();
mCamera.setDisplayOrientation(calcCameraRotation(mDisplayOrientation));
mCameraListener.onCameraOpened();
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
mCameraListener.onCameraClosed();
}
}
@Override
Size getCaptureResolution() {
return mCaptureSize;
}
@Override
Size getPreviewResolution() {
return mPreviewSize;
}
}

@ -1,11 +1,5 @@
package com.flurgle.camerakit; package com.flurgle.camerakit;
import android.view.View;
import com.flurgle.camerakit.types.Facing;
import com.flurgle.camerakit.types.Flash;
import com.flurgle.camerakit.utils.Size;
public abstract class CameraImpl { public abstract class CameraImpl {
protected CameraListener mCameraListener; protected CameraListener mCameraListener;
@ -16,38 +10,25 @@ public abstract class CameraImpl {
mPreview = preview; mPreview = preview;
} }
View getView() {
return mPreview.getView();
}
abstract void start(); abstract void start();
abstract void stop(); abstract void stop();
abstract boolean isCameraOpened(); abstract boolean isCameraOpened();
abstract void setFacing(@Facing int facing); abstract void setFacing(@Facing int facing);
abstract void setFlash(@Flash int flash); abstract void setFlash(@Flash int flash);
abstract void setAutoFocus(boolean autoFocus); abstract void setAutoFocus(boolean autoFocus);
abstract boolean getAutoFocus(); abstract void setDisplayOrientation(int displayOrientation);
abstract void focus();
abstract void capturePicture();
abstract void captureStandard();
abstract void captureStill(); abstract void captureStill();
abstract void startVideo(); abstract void startVideo();
abstract void endVideo(); abstract void endVideo();
abstract void focus(); abstract Size getCaptureResolution();
abstract Size getPreviewResolution();
abstract void setDisplayOrientation(int displayOrientation);
abstract Size getCaptureSize();
abstract Size getPreviewSize();
} }

@ -5,8 +5,6 @@ import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.View; import android.view.View;
import com.flurgle.camerakit.utils.AspectRatio;
public abstract class PreviewImpl { public abstract class PreviewImpl {
interface Callback { interface Callback {

@ -11,8 +11,8 @@ public class CameraKit {
public static final int FLASH_ON = 1; public static final int FLASH_ON = 1;
public static final int FLASH_AUTO = 2; public static final int FLASH_AUTO = 2;
public static final int PICTURE_MODE_QUALITY = 0; public static final int CAPTURE_MODE_STANDARD = 0;
public static final int PICTURE_MODE_SPEED = 1; public static final int CAPTURE_MODE_STILL = 1;
public static final int PICTURE_MODE_AUTO = 2; public static final int PICTURE_MODE_AUTO = 2;
public static final int TAP_TO_FOCUS_VISIBLE = 0; public static final int TAP_TO_FOCUS_VISIBLE = 0;

@ -24,15 +24,6 @@ import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import com.flurgle.camerakit.types.Facing;
import com.flurgle.camerakit.types.Flash;
import com.flurgle.camerakit.types.PictureMode;
import com.flurgle.camerakit.types.TapToFocus;
import com.flurgle.camerakit.utils.AspectRatio;
import com.flurgle.camerakit.utils.CenterCrop;
import com.flurgle.camerakit.utils.DisplayOrientationDetector;
import com.flurgle.camerakit.utils.Size;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -41,14 +32,15 @@ import static com.flurgle.camerakit.CameraKit.Constants.FACING_FRONT;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_AUTO; import static com.flurgle.camerakit.CameraKit.Constants.FLASH_AUTO;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_OFF; import static com.flurgle.camerakit.CameraKit.Constants.FLASH_OFF;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_ON; import static com.flurgle.camerakit.CameraKit.Constants.FLASH_ON;
import static com.flurgle.camerakit.CameraKit.Constants.PICTURE_MODE_QUALITY; import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STANDARD;
import static com.flurgle.camerakit.CameraKit.Constants.PICTURE_MODE_SPEED; import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STILL;
import static com.flurgle.camerakit.CameraKit.Constants.TAP_TO_FOCUS_VISIBLE; import static com.flurgle.camerakit.CameraKit.Constants.TAP_TO_FOCUS_VISIBLE;
public class CameraView extends FrameLayout { public class CameraView extends FrameLayout {
private static final int PERMISSION_REQUEST_CAMERA = 16; private static final int PERMISSION_REQUEST_CAMERA = 16;
private static final int DEFAULT_CAPTURE_SIZE = -1; private static final int DEFAULT_CAPTURE_SIZE = -1;
private static final int DEFAULT_JPEG_COMPRESSION = 100;
@Facing @Facing
private int mFacing; private int mFacing;
@ -56,18 +48,20 @@ public class CameraView extends FrameLayout {
@Flash @Flash
private int mFlash; private int mFlash;
@PictureMode
private int mPictureMode;
private boolean mCropOutput;
@TapToFocus @TapToFocus
private int mTapToFocus; private int mTapToFocus;
@CaptureMode
private int mCaptureMode;
private boolean mCropOutput;
private boolean mAutoFocus; private boolean mAutoFocus;
private float mCaptureSize; private float mCaptureSize;
private int mJpegCompression;
private boolean mAdjustViewBounds; private boolean mAdjustViewBounds;
private boolean mWaitingForPermission; private boolean mWaitingForPermission;
@ -100,18 +94,18 @@ public class CameraView extends FrameLayout {
mFlash = a.getInteger(R.styleable.CameraView_ckFlash, FLASH_OFF); mFlash = a.getInteger(R.styleable.CameraView_ckFlash, FLASH_OFF);
} }
if (attr == R.styleable.CameraView_ckPictureMode) { if (attr == R.styleable.CameraView_ckTapToFocus) {
mPictureMode = a.getInteger(R.styleable.CameraView_ckPictureMode, PICTURE_MODE_QUALITY); mTapToFocus = a.getInteger(R.styleable.CameraView_ckTapToFocus, TAP_TO_FOCUS_VISIBLE);
}
if (attr == R.styleable.CameraView_ckCaptureMode) {
mCaptureMode = a.getInteger(R.styleable.CameraView_ckCaptureMode, CAPTURE_MODE_STANDARD);
} }
if (attr == R.styleable.CameraView_ckCropOutput) { if (attr == R.styleable.CameraView_ckCropOutput) {
mCropOutput = a.getBoolean(R.styleable.CameraView_ckCropOutput, false); mCropOutput = a.getBoolean(R.styleable.CameraView_ckCropOutput, false);
} }
if (attr == R.styleable.CameraView_ckTapToFocus) {
mTapToFocus = a.getInteger(R.styleable.CameraView_ckTapToFocus, TAP_TO_FOCUS_VISIBLE);
}
if (attr == R.styleable.CameraView_ckAutoFocus) { if (attr == R.styleable.CameraView_ckAutoFocus) {
mAutoFocus = a.getBoolean(R.styleable.CameraView_ckAutoFocus, true); mAutoFocus = a.getBoolean(R.styleable.CameraView_ckAutoFocus, true);
} }
@ -120,6 +114,10 @@ public class CameraView extends FrameLayout {
mCaptureSize = a.getFloat(R.styleable.CameraView_ckCaptureSize, DEFAULT_CAPTURE_SIZE); mCaptureSize = a.getFloat(R.styleable.CameraView_ckCaptureSize, DEFAULT_CAPTURE_SIZE);
} }
if (attr == R.styleable.CameraView_ckJpegCompression) {
mJpegCompression = a.getInteger(R.styleable.CameraView_ckJpegCompression, DEFAULT_JPEG_COMPRESSION);
}
if (attr == R.styleable.CameraView_android_adjustViewBounds) { if (attr == R.styleable.CameraView_android_adjustViewBounds) {
mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false); mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false);
} }
@ -134,7 +132,7 @@ public class CameraView extends FrameLayout {
setFacing(mFacing); setFacing(mFacing);
setFlash(mFlash); setFlash(mFlash);
setPictureMode(mPictureMode); setPictureMode(mCaptureMode);
setCropOutput(mCropOutput); setCropOutput(mCropOutput);
setTapToFocus(mTapToFocus); setTapToFocus(mTapToFocus);
setAutoFocus(mAutoFocus); setAutoFocus(mAutoFocus);
@ -243,13 +241,13 @@ public class CameraView extends FrameLayout {
return mFlash; return mFlash;
} }
public void setPictureMode(@PictureMode int pictureMode) { public void setPictureMode(@CaptureMode int pictureMode) {
this.mPictureMode = pictureMode; this.mCaptureMode = pictureMode;
} }
@PictureMode @CaptureMode
public int getPictureMode() { public int getPictureMode() {
return mPictureMode; return mCaptureMode;
} }
public void setCropOutput(boolean cropOutput) { public void setCropOutput(boolean cropOutput) {
@ -278,11 +276,11 @@ public class CameraView extends FrameLayout {
} }
public void capturePicture() { public void capturePicture() {
switch (mPictureMode) { switch (mCaptureMode) {
case PICTURE_MODE_QUALITY: case CAPTURE_MODE_STANDARD:
mCameraImpl.capturePicture(); mCameraImpl.captureStandard();
break; break;
case PICTURE_MODE_SPEED: case CAPTURE_MODE_STILL:
mCameraImpl.captureStill(); mCameraImpl.captureStill();
break; break;
} }
@ -297,11 +295,11 @@ public class CameraView extends FrameLayout {
} }
public Size getPreviewSize() { public Size getPreviewSize() {
return mCameraImpl != null ? mCameraImpl.getPreviewSize() : null; return mCameraImpl != null ? mCameraImpl.getPreviewResolution() : null;
} }
public Size getCaptureSize() { public Size getCaptureSize() {
return mCameraImpl != null ? mCameraImpl.getCaptureSize() : null; return mCameraImpl != null ? mCameraImpl.getCaptureResolution() : null;
} }
private void requestCameraPermission() { private void requestCameraPermission() {
@ -405,10 +403,10 @@ public class CameraView extends FrameLayout {
public void onPictureTaken(byte[] jpeg) { public void onPictureTaken(byte[] jpeg) {
super.onPictureTaken(jpeg); super.onPictureTaken(jpeg);
if (mCropOutput) { if (mCropOutput) {
int width = mPictureMode == PICTURE_MODE_QUALITY ? mCameraImpl.getCaptureSize().getWidth() : mCameraImpl.getPreviewSize().getWidth(); int width = mCaptureMode == CAPTURE_MODE_STANDARD ? mCameraImpl.getCaptureResolution().getWidth() : mCameraImpl.getPreviewResolution().getWidth();
int height = mPictureMode == PICTURE_MODE_QUALITY ? mCameraImpl.getCaptureSize().getHeight() : mCameraImpl.getPreviewSize().getHeight(); int height = mCaptureMode == CAPTURE_MODE_STANDARD ? mCameraImpl.getCaptureResolution().getHeight() : mCameraImpl.getPreviewResolution().getHeight();
AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight()); AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight());
getCameraListener().onPictureTaken(new CenterCrop(jpeg, outputRatio).getJpeg()); getCameraListener().onPictureTaken(new CenterCrop(jpeg, outputRatio, mJpegCompression).getJpeg());
} else { } else {
getCameraListener().onPictureTaken(jpeg); getCameraListener().onPictureTaken(jpeg);
} }
@ -419,10 +417,10 @@ public class CameraView extends FrameLayout {
super.onPictureTaken(yuv); super.onPictureTaken(yuv);
if (mCropOutput) { if (mCropOutput) {
AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight()); AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight());
getCameraListener().onPictureTaken(new CenterCrop(yuv, outputRatio).getJpeg()); getCameraListener().onPictureTaken(new CenterCrop(yuv, outputRatio, mJpegCompression).getJpeg());
} else { } else {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
yuv.compressToJpeg(new Rect(0, 0, yuv.getWidth(), yuv.getHeight()), 50, out); yuv.compressToJpeg(new Rect(0, 0, yuv.getWidth(), yuv.getHeight()), mJpegCompression, out);
getCameraListener().onPictureTaken(out.toByteArray()); getCameraListener().onPictureTaken(out.toByteArray());
} }
} }

@ -1,14 +0,0 @@
package com.flurgle.camerakit.types;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static com.flurgle.camerakit.CameraKit.Constants.PICTURE_MODE_QUALITY;
import static com.flurgle.camerakit.CameraKit.Constants.PICTURE_MODE_SPEED;
@Retention(RetentionPolicy.SOURCE)
@IntDef({PICTURE_MODE_QUALITY, PICTURE_MODE_SPEED})
public @interface PictureMode {
}

@ -14,9 +14,9 @@
<enum name="auto" value="2" /> <enum name="auto" value="2" />
</attr> </attr>
<attr name="ckPictureMode" format="enum"> <attr name="ckCaptureMode" format="enum">
<enum name="quality" value="0" /> <enum name="standard" value="0" />
<enum name="speed" value="1" /> <enum name="still" value="1" />
<enum name="auto" value="2" /> <enum name="auto" value="2" />
</attr> </attr>
@ -32,6 +32,8 @@
<attr name="ckCaptureSize" format="float" /> <attr name="ckCaptureSize" format="float" />
<attr name="ckJpegCompression" format="integer" />
<attr name="android:adjustViewBounds" /> <attr name="android:adjustViewBounds" />
</declare-styleable> </declare-styleable>

@ -0,0 +1,14 @@
package com.flurgle.camerakit;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STANDARD;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STILL;
@Retention(RetentionPolicy.SOURCE)
@IntDef({CAPTURE_MODE_STANDARD, CAPTURE_MODE_STILL})
public @interface CaptureMode {
}

@ -1,4 +1,4 @@
package com.flurgle.camerakit.types; package com.flurgle.camerakit;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;

@ -1,4 +1,4 @@
package com.flurgle.camerakit.types; package com.flurgle.camerakit;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;

@ -1,4 +1,4 @@
package com.flurgle.camerakit.types; package com.flurgle.camerakit;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;

@ -1,4 +1,4 @@
package com.flurgle.camerakit.utils; package com.flurgle.camerakit;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;

@ -1,4 +1,4 @@
package com.flurgle.camerakit.utils; package com.flurgle.camerakit;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
@ -14,14 +14,14 @@ public class CenterCrop {
private byte[] croppedJpeg; private byte[] croppedJpeg;
public CenterCrop(YuvImage yuv, AspectRatio targetRatio) { public CenterCrop(YuvImage yuv, AspectRatio targetRatio, int jpegCompression) {
Rect crop = getCrop(yuv.getWidth(), yuv.getHeight(), targetRatio); Rect crop = getCrop(yuv.getWidth(), yuv.getHeight(), targetRatio);
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
yuv.compressToJpeg(crop, 100, out); yuv.compressToJpeg(crop, 100, out);
this.croppedJpeg = out.toByteArray(); this.croppedJpeg = out.toByteArray();
} }
public CenterCrop(byte[] jpeg, AspectRatio targetRatio) { public CenterCrop(byte[] jpeg, AspectRatio targetRatio, int jpegCompression) {
BitmapFactory.Options options = new BitmapFactory.Options(); BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options);

@ -1,4 +1,4 @@
package com.flurgle.camerakit.utils; package com.flurgle.camerakit;
import android.content.Context; import android.content.Context;
import android.util.SparseIntArray; import android.util.SparseIntArray;

@ -1,4 +1,4 @@
package com.flurgle.camerakit.utils; package com.flurgle.camerakit;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;

@ -1,6 +1,7 @@
package com.flurgle.camerakit.utils; package com.flurgle.camerakit;
import android.media.Image; import android.media.Image;
import android.util.Log;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@ -27,7 +28,7 @@ public class YuvUtils {
outputStream.write(v); outputStream.write(v);
outputStream.write(u); outputStream.write(u);
} catch (IOException e) { } catch (IOException e) {
Log.e("CameraKit", e.toString());
} }
return outputStream.toByteArray(); return outputStream.toByteArray();
} }

@ -193,8 +193,8 @@ public class MainActivity extends AppCompatActivity {
public void onCheckedChanged(RadioGroup group, int checkedId) { public void onCheckedChanged(RadioGroup group, int checkedId) {
camera.setPictureMode( camera.setPictureMode(
checkedId == R.id.modeCaptureQuality ? checkedId == R.id.modeCaptureQuality ?
CameraKit.Constants.PICTURE_MODE_QUALITY : CameraKit.Constants.CAPTURE_MODE_STANDARD :
CameraKit.Constants.PICTURE_MODE_SPEED CameraKit.Constants.CAPTURE_MODE_STILL
); );
Toast.makeText(MainActivity.this, "Picture capture set to" + (checkedId == R.id.modeCaptureQuality ? " quality!" : " speed!"), Toast.LENGTH_SHORT).show(); Toast.makeText(MainActivity.this, "Picture capture set to" + (checkedId == R.id.modeCaptureQuality ? " quality!" : " speed!"), Toast.LENGTH_SHORT).show();

@ -7,8 +7,8 @@ import android.support.annotation.Nullable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.flurgle.camerakit.utils.AspectRatio; import com.flurgle.camerakit.AspectRatio;
import com.flurgle.camerakit.utils.Size; import com.flurgle.camerakit.Size;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;

@ -3,7 +3,7 @@ package com.flurgle.camerakit.demo;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.flurgle.camerakit.utils.Size; import com.flurgle.camerakit.Size;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;

@ -21,7 +21,7 @@
app:ckCropOutput="false" app:ckCropOutput="false"
app:ckFacing="back" app:ckFacing="back"
app:ckFlash="off" app:ckFlash="off"
app:ckPictureMode="quality" app:ckCaptureMode="standard"
app:ckTapToFocus="visible" /> app:ckTapToFocus="visible" />
<LinearLayout <LinearLayout

Loading…
Cancel
Save