Support for pics while recording videos

pull/1/head
Mattia Iavarone 7 years ago
parent 4f554a5184
commit 51147e88ef
  1. 21
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  2. 12
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  3. 118
      demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java

@ -175,6 +175,7 @@ class Camera1 extends CameraImpl {
void stop() {
mFocusHandler.removeCallbacksAndMessages(null);
if (isCameraOpened()) {
if (mIsCapturingVideo) endVideo();
mCamera.stopPreview();
mCamera.release();
mCameraListener.dispatchOnCameraClosed();
@ -361,9 +362,9 @@ class Camera1 extends CameraImpl {
void captureImage() {
if (mIsCapturingImage) return;
if (!isCameraOpened()) return;
if (mIsCapturingVideo || mSessionType == SESSION_TYPE_VIDEO) {
captureSnapshot();
return;
if (mSessionType == SESSION_TYPE_VIDEO && mIsCapturingVideo) {
Camera.Parameters parameters = mCamera.getParameters();
if (!parameters.isVideoSnapshotSupported()) return;
}
// Set boolean to wait for image callback
@ -395,9 +396,14 @@ class Camera1 extends CameraImpl {
@Override
void captureSnapshot() {
if (mIsCapturingImage) return;
if (!isCameraOpened()) return;
// TODO: will this work while recording a video? test...
if (mIsCapturingImage) return;
// This won't work while capturing a video.
// Switch to captureImage.
if (mIsCapturingVideo) {
captureImage();
return;
}
mIsCapturingImage = true;
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override
@ -539,6 +545,8 @@ class Camera1 extends CameraImpl {
mVideoFile = videoFile;
if (mIsCapturingVideo) return;
if (!isCameraOpened()) return;
Camera.Parameters params = mCamera.getParameters();
params.setVideoStabilization(false);
if (mSessionType == SESSION_TYPE_VIDEO) {
mIsCapturingVideo = true;
initMediaRecorder();
@ -558,6 +566,7 @@ class Camera1 extends CameraImpl {
@Override
void endVideo() {
if (mIsCapturingVideo) {
mIsCapturingVideo = false;
mMediaRecorder.stop();
mMediaRecorder.release();
@ -567,12 +576,12 @@ class Camera1 extends CameraImpl {
mVideoFile = null;
}
}
}
private void initMediaRecorder() {
mMediaRecorder = new MediaRecorder();
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

@ -804,16 +804,12 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* was registered.
*
* Note that if sessionType is {@link CameraKit.Constants#SESSION_TYPE_VIDEO}, this
* falls back to {@link #captureSnapshot()} (that is, we will capture a preview frame).
* might fall back to {@link #captureSnapshot()} (that is, we might capture a preview frame).
*
* @see #captureSnapshot()
*/
public void captureImage() {
if (mSessionType == CameraKit.Constants.SESSION_TYPE_PICTURE) {
mCameraImpl.captureImage();
} else {
captureSnapshot();
}
}
@ -822,10 +818,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* This eventually triggers {@link CameraListener#onPictureTaken(byte[])} if a listener
* was registered.
*
* The difference with {@link #captureImage()} is that:
* - this capture is faster, so it might be better on slower cameras, though the result can be
* generally blurry or low quality
* - this can be called even if sessionType is {@link CameraKit.Constants#SESSION_TYPE_VIDEO}
* The difference with {@link #captureImage()} is that this capture is faster, so it might be
* better on slower cameras, though the result can be generally blurry or low quality.
*
* @see #captureImage()
*/

@ -1,8 +1,6 @@
package com.flurgle.camerakit.demo;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
@ -35,17 +33,14 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
CameraView camera;
// Capture Mode:
@BindView(R.id.sessionTypeRadioGroup)
RadioGroup sessionTypeRadioGroup;
// Crop Mode:
@BindView(R.id.cropModeRadioGroup)
RadioGroup cropModeRadioGroup;
// Width:
@BindView(R.id.screenWidth)
TextView screenWidth;
@BindView(R.id.width)
@ -56,7 +51,6 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
RadioGroup widthModeRadioGroup;
// Height:
@BindView(R.id.screenHeight)
TextView screenHeight;
@BindView(R.id.height)
@ -66,9 +60,11 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
@BindView(R.id.heightModeRadioGroup)
RadioGroup heightModeRadioGroup;
private int mCameraWidth;
private int mCameraHeight;
private boolean mCapturing;
private boolean mCapturingPicture;
private boolean mCapturingVideo;
private CameraListener mPictureListener;
private CameraListener mVideoListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -92,6 +88,11 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
heightModeRadioGroup.setOnCheckedChangeListener(heightModeChangedListener);
}
private void message(String content, boolean important) {
int length = important ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT;
Toast.makeText(this, content, length).show();
}
@Override
protected void onResume() {
super.onResume();
@ -112,18 +113,23 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
@OnClick(R.id.capturePhoto)
void capturePhoto() {
if (mCapturing) return;
mCapturing = true;
if (mCapturingPicture) return;
mCapturingPicture = true;
final long startTime = System.currentTimeMillis();
final Size nativeSize = camera.getSessionType() == CameraKit.Constants.SESSION_TYPE_PICTURE ?
camera.getCaptureSize() : camera.getSnapshotSize();
camera.clearCameraListeners();
camera.addCameraListener(new CameraListener() {
final boolean snapshot = camera.getSessionType() != CameraKit.Constants.SESSION_TYPE_PICTURE;
final Size nativeSize = snapshot ? camera.getSnapshotSize() : camera.getCaptureSize();
message(snapshot ? "Capturing snapshot..." : "Capturing picture...", false);
camera.removeCameraListener(mPictureListener);
mPictureListener = new CameraListener() {
@Override
public void onPictureTaken(byte[] jpeg) {
super.onPictureTaken(jpeg);
mCapturing = false;
mCapturingPicture = false;
long callbackTime = System.currentTimeMillis();
if (mCapturingVideo) {
message("Captured while taking video. Size="+nativeSize, false);
return;
}
PicturePreviewActivity.setImage(jpeg);
Intent intent = new Intent(MainActivity.this, PicturePreviewActivity.class);
intent.putExtra("delay", callbackTime-startTime);
@ -131,30 +137,32 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
intent.putExtra("nativeHeight", nativeSize.getHeight());
startActivity(intent);
}
});
};
camera.addCameraListener(mPictureListener);
camera.captureImage();
}
@OnClick(R.id.captureVideo)
void captureVideo() {
if (camera.getSessionType() != CameraKit.Constants.SESSION_TYPE_VIDEO) {
Toast.makeText(this, "Can't record video while session type is 'picture'.", Toast.LENGTH_SHORT).show();
message("Can't record video while session type is 'picture'.", false);
return;
}
if (mCapturing) return;
mCapturing = true;
camera.clearCameraListeners();
camera.addCameraListener(new CameraListener() {
if (mCapturingPicture || mCapturingVideo) return;
mCapturingVideo = true;
camera.removeCameraListener(mVideoListener);
mVideoListener = new CameraListener() {
@Override
public void onVideoTaken(File video) {
super.onVideoTaken(video);
mCapturing = false;
mCapturingVideo = false;
Intent intent = new Intent(MainActivity.this, VideoPreviewActivity.class);
intent.putExtra("video", Uri.fromFile(video));
startActivity(intent);
}
});
Toast.makeText(this, "Recording for 8 seconds...", Toast.LENGTH_LONG).show();
};
camera.addCameraListener(mVideoListener);
message("Recording for 8 seconds...", true);
camera.startCapturingVideo(null);
camera.postDelayed(new Runnable() {
@Override
@ -166,32 +174,32 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
@OnClick(R.id.toggleCamera)
void toggleCamera() {
if (mCapturing) return;
if (mCapturingPicture) return;
switch (camera.toggleFacing()) {
case CameraKit.Constants.FACING_BACK:
Toast.makeText(this, "Switched to back camera!", Toast.LENGTH_SHORT).show();
message("Switched to back camera!", false);
break;
case CameraKit.Constants.FACING_FRONT:
Toast.makeText(this, "Switched to front camera!", Toast.LENGTH_SHORT).show();
message("Switched to front camera!", false);
break;
}
}
@OnClick(R.id.toggleFlash)
void toggleFlash() {
if (mCapturing) return;
if (mCapturingPicture) return;
switch (camera.toggleFlash()) {
case CameraKit.Constants.FLASH_ON:
Toast.makeText(this, "Flash on!", Toast.LENGTH_SHORT).show();
message("Flash on!", false);
break;
case CameraKit.Constants.FLASH_OFF:
Toast.makeText(this, "Flash off!", Toast.LENGTH_SHORT).show();
message("Flash off!", false);
break;
case CameraKit.Constants.FLASH_AUTO:
Toast.makeText(this, "Flash auto!", Toast.LENGTH_SHORT).show();
message("Flash auto!", false);
break;
}
}
@ -199,28 +207,28 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
RadioGroup.OnCheckedChangeListener sessionTypeChangedListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (mCapturing) return;
if (mCapturingPicture) return;
camera.setSessionType(
checkedId == R.id.sessionTypePicture ?
CameraKit.Constants.SESSION_TYPE_PICTURE :
CameraKit.Constants.SESSION_TYPE_VIDEO
);
Toast.makeText(MainActivity.this, "Session type set to" + (checkedId == R.id.sessionTypePicture ? " picture!" : " video!"), Toast.LENGTH_SHORT).show();
message("Session type set to" + (checkedId == R.id.sessionTypePicture ? " picture!" : " video!"), true);
}
};
RadioGroup.OnCheckedChangeListener cropModeChangedListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (mCapturing) return;
if (mCapturingPicture) return;
camera.setCropOutput(checkedId == R.id.modeCropVisible);
Toast.makeText(MainActivity.this, "Picture cropping is" + (checkedId == R.id.modeCropVisible ? " on!" : " off!"), Toast.LENGTH_SHORT).show();
message("Picture cropping is" + (checkedId == R.id.modeCropVisible ? " on!" : " off!"), false);
}
};
@OnClick(R.id.widthUpdate)
void widthUpdateClicked() {
if (mCapturing) return;
if (mCapturingPicture) return;
if (widthUpdate.getAlpha() >= 1) {
updateCamera(true, false);
}
@ -229,7 +237,7 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
RadioGroup.OnCheckedChangeListener widthModeChangedListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (mCapturing) return;
if (mCapturingPicture) return;
widthUpdate.setEnabled(checkedId == R.id.widthCustom);
widthUpdate.setAlpha(checkedId == R.id.widthCustom ? 1f : 0.3f);
width.clearFocus();
@ -242,7 +250,7 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
@OnClick(R.id.heightUpdate)
void heightUpdateClicked() {
if (mCapturing) return;
if (mCapturingPicture) return;
if (heightUpdate.getAlpha() >= 1) {
updateCamera(false, true);
}
@ -251,7 +259,7 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
RadioGroup.OnCheckedChangeListener heightModeChangedListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (mCapturing) return;
if (mCapturingPicture) return;
heightUpdate.setEnabled(checkedId == R.id.heightCustom);
heightUpdate.setAlpha(checkedId == R.id.heightCustom ? 1f : 0.3f);
height.clearFocus();
@ -263,7 +271,7 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
};
private void updateCamera(boolean updateWidth, boolean updateHeight) {
if (mCapturing) return;
if (mCapturingPicture) return;
ViewGroup.LayoutParams cameraLayoutParams = camera.getLayoutParams();
int width = cameraLayoutParams.width;
int height = cameraLayoutParams.height;
@ -272,20 +280,11 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
switch (widthModeRadioGroup.getCheckedRadioButtonId()) {
case R.id.widthCustom:
String widthInput = this.width.getText().toString();
if (widthInput.length() > 0) {
try {
width = Integer.valueOf(widthInput);
} catch (Exception e) {
}
}
try { width = Integer.valueOf(widthInput); } catch (Exception e) {}
break;
case R.id.widthWrapContent:
width = ViewGroup.LayoutParams.WRAP_CONTENT;
break;
case R.id.widthMatchParent:
width = ViewGroup.LayoutParams.MATCH_PARENT;
break;
@ -296,19 +295,11 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
switch (heightModeRadioGroup.getCheckedRadioButtonId()) {
case R.id.heightCustom:
String heightInput = this.height.getText().toString();
if (heightInput.length() > 0) {
try {
height = Integer.valueOf(heightInput);
} catch (Exception e) {
}
}
try { height = Integer.valueOf(heightInput); } catch (Exception e) {}
break;
case R.id.heightWrapContent:
height = ViewGroup.LayoutParams.WRAP_CONTENT;
break;
case R.id.heightMatchParent:
// We are in a vertically scrolling container, match parent would not work at all.
height = parent.getHeight();
@ -321,13 +312,14 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
camera.addOnLayoutChangeListener(this);
camera.setLayoutParams(cameraLayoutParams);
Toast.makeText(this, (updateWidth && updateHeight ? "Width and height" : updateWidth ? "Width" : "Height") + " updated!", Toast.LENGTH_SHORT).show();
String what = (updateWidth && updateHeight ? "Width and height" : updateWidth ? "Width" : "Height");
message(what + " updated! Internal preview size: " + camera.getPreviewSize(), false);
}
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
mCameraWidth = right - left;
mCameraHeight = bottom - top;
int mCameraWidth = right - left;
int mCameraHeight = bottom - top;
width.setText(String.valueOf(mCameraWidth));
height.setText(String.valueOf(mCameraHeight));
camera.removeOnLayoutChangeListener(this);

Loading…
Cancel
Save