Added a maximum file size for videos

pull/104/head
Raghav Petluru 8 years ago
parent 9e6c4c0919
commit cd715cf3fd
  1. 9
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewCallbacksTest.java
  2. 12
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/IntegrationTest.java
  3. 10
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/MockCameraController.java
  4. 42
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
  5. 21
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera2.java
  6. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java
  7. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraListener.java
  8. 26
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  9. 13
      demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java

@ -19,16 +19,13 @@ import org.mockito.stubbing.Stubber;
import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyFloat; import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -137,11 +134,11 @@ public class CameraViewCallbacksTest extends BaseTest {
@Test @Test
public void testDispatchOnVideoTaken() { public void testDispatchOnVideoTaken() {
completeTask().when(listener).onVideoTaken(null); completeTask().when(listener).onVideoTaken(null, false);
camera.mCameraCallbacks.dispatchOnVideoTaken(null); camera.mCameraCallbacks.dispatchOnVideoTaken(null, false);
assertNotNull(task.await(200)); assertNotNull(task.await(200));
verify(listener, times(1)).onVideoTaken(null); verify(listener, times(1)).onVideoTaken(null, false);
} }
@Test @Test

@ -3,7 +3,6 @@ package com.otaliastudios.cameraview;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.PointF; import android.graphics.PointF;
import android.media.MediaRecorder;
import android.support.test.filters.MediumTest; import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule; import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
@ -20,8 +19,13 @@ import java.io.File;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.mockito.Mockito.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
/** /**
@ -120,7 +124,7 @@ public class IntegrationTest extends BaseTest {
private void waitForVideoEnd(boolean expectSuccess) { private void waitForVideoEnd(boolean expectSuccess) {
final Task<Boolean> video = new Task<>(true); final Task<Boolean> video = new Task<>(true);
doEndTask(video, true).when(listener).onVideoTaken(any(File.class)); doEndTask(video, true).when(listener).onVideoTaken(any(File.class), false);
Boolean result = video.await(8000); Boolean result = video.await(8000);
if (expectSuccess) { if (expectSuccess) {
assertNotNull("Can take video", result); assertNotNull("Can take video", result);

@ -131,4 +131,14 @@ public class MockCameraController extends CameraController {
@Override @Override
public void onBufferAvailable(byte[] buffer) { public void onBufferAvailable(byte[] buffer) {
} }
@Override
void setMaxFileSize(long maxFileSizeInBytes) {
}
@Override
boolean isRecordingVideo() {
return false;
}
} }

@ -9,7 +9,6 @@ import android.hardware.Camera;
import android.location.Location; import android.location.Location;
import android.media.CamcorderProfile; import android.media.CamcorderProfile;
import android.media.MediaRecorder; import android.media.MediaRecorder;
import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread; import android.support.annotation.WorkerThread;
@ -18,7 +17,6 @@ import android.view.SurfaceHolder;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
@ -52,6 +50,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
private boolean mIsBound = false; private boolean mIsBound = false;
private boolean mIsCapturingImage = false; private boolean mIsCapturingImage = false;
private boolean mIsCapturingVideo = false; private boolean mIsCapturingVideo = false;
private long mMaxFileSizeInBytes = 0;
private boolean mHasReachedMaxSize = false;
Camera1(CameraView.CameraCallbacks callback) { Camera1(CameraView.CameraCallbacks callback) {
super(callback); super(callback);
@ -700,9 +700,11 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
mMediaRecorder = null; mMediaRecorder = null;
} }
if (mVideoFile != null) { if (mVideoFile != null) {
mCameraCallbacks.dispatchOnVideoTaken(mVideoFile); mCameraCallbacks.dispatchOnVideoTaken(mVideoFile, mHasReachedMaxSize);
mVideoFile = null; mVideoFile = null;
} }
mHasReachedMaxSize = false;
} }
@WorkerThread @WorkerThread
@ -736,6 +738,26 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
mMediaRecorder.setOutputFile(mVideoFile.getAbsolutePath()); mMediaRecorder.setOutputFile(mVideoFile.getAbsolutePath());
mMediaRecorder.setOrientationHint(computeExifRotation()); mMediaRecorder.setOrientationHint(computeExifRotation());
//If the user sets a max file size, set it to the max file size
if(mMaxFileSizeInBytes > 0) {
mMediaRecorder.setMaxFileSize(mMaxFileSizeInBytes);
//Attach a listener to the media recorder to listen for file size notifications
mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mediaRecorder, int i, int i1) {
switch (i){
case MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED:{
mHasReachedMaxSize = true;
endVideo();
break;
}
}
}
});
}
// Not needed. mMediaRecorder.setPreviewDisplay(mPreview.getSurface()); // Not needed. mMediaRecorder.setPreviewDisplay(mPreview.getSurface());
} }
@ -893,4 +915,18 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
LOG.i("size:", "sizesFromList:", result); LOG.i("size:", "sizesFromList:", result);
return result; return result;
} }
@Override
void setMaxFileSize(long maxFileSizeInBytes) {
mMaxFileSizeInBytes = maxFileSizeInBytes;
}
// -----------------
// Additional helper info
@Override
boolean isRecordingVideo() {
return mIsCapturingVideo;
}
} }

@ -1,23 +1,12 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.PointF; import android.graphics.PointF;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.location.Location; import android.location.Location;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@TargetApi(21) @TargetApi(21)
class Camera2 extends CameraController { class Camera2 extends CameraController {
@ -130,4 +119,14 @@ class Camera2 extends CameraController {
public void onBufferAvailable(byte[] buffer) { public void onBufferAvailable(byte[] buffer) {
} }
@Override
void setMaxFileSize(long maxFileSizeInBytes) {
}
@Override
boolean isRecordingVideo() {
return false;
}
} }

@ -315,6 +315,10 @@ abstract class CameraController implements
abstract void startAutoFocus(@Nullable Gesture gesture, PointF point); abstract void startAutoFocus(@Nullable Gesture gesture, PointF point);
abstract void setMaxFileSize(long maxFileSizeInBytes);
abstract boolean isRecordingVideo();
//endregion //endregion
//region final getters //region final getters

@ -73,9 +73,11 @@ public abstract class CameraListener {
* </code> * </code>
* *
* @param video file hosting the mp4 video * @param video file hosting the mp4 video
* @param hasReachedMaxFileSize returns true if the user has set a max file size for videos and
* if the video ended because of the file size limit.
*/ */
@UiThread @UiThread
public void onVideoTaken(File video) { public void onVideoTaken(File video, boolean hasReachedMaxFileSize) {
} }

@ -1232,7 +1232,7 @@ public class CameraView extends FrameLayout {
/** /**
* Stops capturing video, if there was a video record going on. * Stops capturing video, if there was a video record going on.
* This will fire {@link CameraListener#onVideoTaken(File)}. * This will fire {@link CameraListener#onVideoTaken(File, boolean)}.
*/ */
public void stopCapturingVideo() { public void stopCapturingVideo() {
mCameraController.endVideo(); mCameraController.endVideo();
@ -1334,6 +1334,24 @@ public class CameraView extends FrameLayout {
return mPlaySounds; return mPlaySounds;
} }
/**
* Set a max file size (in bytes) for a video recording. There is no file size limit by default
* unless set by the user.
*
* @param maxFileSizeInBytes The maximum size of videos in bytes
*/
public void setMaxFileSize(long maxFileSizeInBytes){
mCameraController.setMaxFileSize(maxFileSizeInBytes);
}
/**
* Returns true if the camera is currently recording a video
* @return boolean indicating if the camera is recording a video
*/
public boolean isRecordingVideo(){
return mCameraController.isRecordingVideo();
}
//endregion //endregion
//region Callbacks and dispatching //region Callbacks and dispatching
@ -1345,7 +1363,7 @@ public class CameraView extends FrameLayout {
void onShutter(boolean shouldPlaySound); void onShutter(boolean shouldPlaySound);
void processImage(byte[] jpeg, boolean consistentWithView, boolean flipHorizontally); void processImage(byte[] jpeg, boolean consistentWithView, boolean flipHorizontally);
void processSnapshot(YuvImage image, boolean consistentWithView, boolean flipHorizontally); void processSnapshot(YuvImage image, boolean consistentWithView, boolean flipHorizontally);
void dispatchOnVideoTaken(File file); void dispatchOnVideoTaken(File file, boolean hasReachedMaxFileSize);
void dispatchOnFocusStart(@Nullable Gesture trigger, PointF where); void dispatchOnFocusStart(@Nullable Gesture trigger, PointF where);
void dispatchOnFocusEnd(@Nullable Gesture trigger, boolean success, PointF where); void dispatchOnFocusEnd(@Nullable Gesture trigger, boolean success, PointF where);
void dispatchOnZoomChanged(final float newValue, final PointF[] fingers); void dispatchOnZoomChanged(final float newValue, final PointF[] fingers);
@ -1492,13 +1510,13 @@ public class CameraView extends FrameLayout {
} }
@Override @Override
public void dispatchOnVideoTaken(final File video) { public void dispatchOnVideoTaken(final File video, final boolean hasReachedMaxFileSize) {
mLogger.i("dispatchOnVideoTaken", video); mLogger.i("dispatchOnVideoTaken", video);
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
for (CameraListener listener : mListeners) { for (CameraListener listener : mListeners) {
listener.onVideoTaken(video); listener.onVideoTaken(video, hasReachedMaxFileSize);
} }
} }
}); });

@ -7,24 +7,18 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.BottomSheetBehavior;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Toast; import android.widget.Toast;
import com.otaliastudios.cameraview.Audio;
import com.otaliastudios.cameraview.CameraListener; import com.otaliastudios.cameraview.CameraListener;
import com.otaliastudios.cameraview.CameraLogger; import com.otaliastudios.cameraview.CameraLogger;
import com.otaliastudios.cameraview.CameraOptions; import com.otaliastudios.cameraview.CameraOptions;
import com.otaliastudios.cameraview.CameraView; import com.otaliastudios.cameraview.CameraView;
import com.otaliastudios.cameraview.Flash;
import com.otaliastudios.cameraview.Grid;
import com.otaliastudios.cameraview.SessionType; import com.otaliastudios.cameraview.SessionType;
import com.otaliastudios.cameraview.Size; import com.otaliastudios.cameraview.Size;
import com.otaliastudios.cameraview.VideoQuality;
import com.otaliastudios.cameraview.WhiteBalance;
import java.io.File; import java.io.File;
@ -53,7 +47,12 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
camera.addCameraListener(new CameraListener() { camera.addCameraListener(new CameraListener() {
public void onCameraOpened(CameraOptions options) { onOpened(); } public void onCameraOpened(CameraOptions options) { onOpened(); }
public void onPictureTaken(byte[] jpeg) { onPicture(jpeg); } public void onPictureTaken(byte[] jpeg) { onPicture(jpeg); }
public void onVideoTaken(File video) { onVideo(video); }
@Override
public void onVideoTaken(File video, boolean hasReachedMaxFileSize) {
super.onVideoTaken(video, hasReachedMaxFileSize);
onVideo(video);
}
}); });
findViewById(R.id.edit).setOnClickListener(this); findViewById(R.id.edit).setOnClickListener(this);

Loading…
Cancel
Save