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() { void stop() {
mFocusHandler.removeCallbacksAndMessages(null); mFocusHandler.removeCallbacksAndMessages(null);
if (isCameraOpened()) { if (isCameraOpened()) {
if (mIsCapturingVideo) endVideo();
mCamera.stopPreview(); mCamera.stopPreview();
mCamera.release(); mCamera.release();
mCameraListener.dispatchOnCameraClosed(); mCameraListener.dispatchOnCameraClosed();
@ -361,9 +362,9 @@ class Camera1 extends CameraImpl {
void captureImage() { void captureImage() {
if (mIsCapturingImage) return; if (mIsCapturingImage) return;
if (!isCameraOpened()) return; if (!isCameraOpened()) return;
if (mIsCapturingVideo || mSessionType == SESSION_TYPE_VIDEO) { if (mSessionType == SESSION_TYPE_VIDEO && mIsCapturingVideo) {
captureSnapshot(); Camera.Parameters parameters = mCamera.getParameters();
return; if (!parameters.isVideoSnapshotSupported()) return;
} }
// Set boolean to wait for image callback // Set boolean to wait for image callback
@ -395,9 +396,14 @@ class Camera1 extends CameraImpl {
@Override @Override
void captureSnapshot() { void captureSnapshot() {
if (mIsCapturingImage) return;
if (!isCameraOpened()) 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; mIsCapturingImage = true;
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() { mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override @Override
@ -539,6 +545,8 @@ class Camera1 extends CameraImpl {
mVideoFile = videoFile; mVideoFile = videoFile;
if (mIsCapturingVideo) return; if (mIsCapturingVideo) return;
if (!isCameraOpened()) return; if (!isCameraOpened()) return;
Camera.Parameters params = mCamera.getParameters();
params.setVideoStabilization(false);
if (mSessionType == SESSION_TYPE_VIDEO) { if (mSessionType == SESSION_TYPE_VIDEO) {
mIsCapturingVideo = true; mIsCapturingVideo = true;
initMediaRecorder(); initMediaRecorder();
@ -558,6 +566,7 @@ class Camera1 extends CameraImpl {
@Override @Override
void endVideo() { void endVideo() {
if (mIsCapturingVideo) {
mIsCapturingVideo = false; mIsCapturingVideo = false;
mMediaRecorder.stop(); mMediaRecorder.stop();
mMediaRecorder.release(); mMediaRecorder.release();
@ -567,12 +576,12 @@ class Camera1 extends CameraImpl {
mVideoFile = null; mVideoFile = null;
} }
} }
}
private void initMediaRecorder() { private void initMediaRecorder() {
mMediaRecorder = new MediaRecorder(); mMediaRecorder = new MediaRecorder();
mCamera.unlock(); mCamera.unlock();
mMediaRecorder.setCamera(mCamera); mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

@ -804,16 +804,12 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* was registered. * was registered.
* *
* Note that if sessionType is {@link CameraKit.Constants#SESSION_TYPE_VIDEO}, this * 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() * @see #captureSnapshot()
*/ */
public void captureImage() { public void captureImage() {
if (mSessionType == CameraKit.Constants.SESSION_TYPE_PICTURE) {
mCameraImpl.captureImage(); 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 * This eventually triggers {@link CameraListener#onPictureTaken(byte[])} if a listener
* was registered. * was registered.
* *
* The difference with {@link #captureImage()} is that: * The difference with {@link #captureImage()} is that this capture is faster, so it might be
* - this capture is faster, so it might be better on slower cameras, though the result can be * better on slower cameras, though the result can be generally blurry or low quality.
* generally blurry or low quality
* - this can be called even if sessionType is {@link CameraKit.Constants#SESSION_TYPE_VIDEO}
* *
* @see #captureImage() * @see #captureImage()
*/ */

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

Loading…
Cancel
Save