4444import java .lang .annotation .RetentionPolicy ;
4545import java .nio .ByteBuffer ;
4646import java .util .ArrayList ;
47+ import java .util .Collections ;
48+ import java .util .Comparator ;
4749import java .util .HashMap ;
4850import java .util .List ;
4951import java .util .Map ;
@@ -129,15 +131,13 @@ public class CameraSource {
129131 * See {@link Frame.Metadata#getRotation()}.
130132 */
131133 private int mRotation ;
134+ private int mCameraId ;
132135
133136 private Size mPreviewSize ;
134137
135138 // These values may be requested by the caller. Due to hardware limitations, we may need to
136139 // select close, but not exactly the same values for these.
137140 private float mRequestedFps = 30.0f ;
138- private int mRequestedPreviewWidth = 1024 ;
139- private int mRequestedPreviewHeight = 768 ;
140-
141141
142142 private String mFocusMode = null ;
143143 private String mFlashMode = null ;
@@ -155,6 +155,8 @@ public class CameraSource {
155155 private Thread mProcessingThread ;
156156 private FrameProcessingRunnable mFrameProcessor ;
157157
158+ private boolean isSafeToTakePicture = false ;
159+
158160 /**
159161 * Map to convert between a byte array, received from the camera, and its associated byte
160162 * buffer. We use byte buffers internally because this is a more efficient way to call into
@@ -211,25 +213,6 @@ public Builder setFlashMode(@FlashMode String mode) {
211213 return this ;
212214 }
213215
214- /**
215- * Sets the desired width and height of the camera frames in pixels. If the exact desired
216- * values are not available options, the best matching available options are selected.
217- * Also, we try to select a preview size which corresponds to the aspect ratio of an
218- * associated full picture size, if applicable. Default: 1024x768.
219- */
220- public Builder setRequestedPreviewSize (int width , int height ) {
221- // Restrict the requested range to something within the realm of possibility. The
222- // choice of 1000000 is a bit arbitrary -- intended to be well beyond resolutions that
223- // devices can support. We bound this to avoid int overflow in the code later.
224- final int MAX = 1000000 ;
225- if ((width <= 0 ) || (width > MAX ) || (height <= 0 ) || (height > MAX )) {
226- throw new IllegalArgumentException ("Invalid preview size: " + width + "x" + height );
227- }
228- mCameraSource .mRequestedPreviewWidth = width ;
229- mCameraSource .mRequestedPreviewHeight = height ;
230- return this ;
231- }
232-
233216 /**
234217 * Sets the camera to use (either {@link #CAMERA_FACING_BACK} or
235218 * {@link #CAMERA_FACING_FRONT}). Default: back facing.
@@ -353,6 +336,7 @@ public CameraSource start() throws IOException {
353336 mCamera .setPreviewDisplay (mDummySurfaceView .getHolder ());
354337 }
355338 mCamera .startPreview ();
339+ isSafeToTakePicture = true ;
356340
357341 mProcessingThread = new Thread (mFrameProcessor );
358342 mFrameProcessor .setActive (true );
@@ -378,6 +362,7 @@ public CameraSource start(SurfaceHolder surfaceHolder) throws IOException {
378362 mCamera = createCamera ();
379363 mCamera .setPreviewDisplay (surfaceHolder );
380364 mCamera .startPreview ();
365+ isSafeToTakePicture = true ;
381366
382367 mProcessingThread = new Thread (mFrameProcessor );
383368 mFrameProcessor .setActive (true );
@@ -412,6 +397,7 @@ public void stop() {
412397
413398 // clear the buffer to prevent oom exceptions
414399 mBytesToByteBuffer .clear ();
400+ isSafeToTakePicture = false ;
415401
416402 if (mCamera != null ) {
417403 mCamera .stopPreview ();
@@ -496,7 +482,8 @@ public int doZoom(float scale) {
496482 */
497483 public void takePicture (ShutterCallback shutter , PictureCallback jpeg ) {
498484 synchronized (mCameraLock ) {
499- if (mCamera != null ) {
485+ if (mCamera != null && isSafeToTakePicture ) {
486+ isSafeToTakePicture = false ;
500487 PictureStartCallback startCallback = new PictureStartCallback ();
501488 startCallback .mDelegate = shutter ;
502489 PictureDoneCallback doneCallback = new PictureDoneCallback ();
@@ -701,6 +688,7 @@ public void onPictureTaken(byte[] data, Camera camera) {
701688 synchronized (mCameraLock ) {
702689 if (mCamera != null ) {
703690 mCamera .startPreview ();
691+ isSafeToTakePicture = true ;
704692 }
705693 }
706694 }
@@ -742,13 +730,13 @@ public void onAutoFocusMoving(boolean start, Camera camera) {
742730 */
743731 @ SuppressLint ("InlinedApi" )
744732 private Camera createCamera () {
745- int requestedCameraId = getIdForRequestedCamera (mFacing );
746- if (requestedCameraId == -1 ) {
733+ mCameraId = getIdForRequestedCamera (mFacing );
734+ if (mCameraId == -1 ) {
747735 throw new RuntimeException ("Could not find requested camera." );
748736 }
749- Camera camera = Camera .open (requestedCameraId );
737+ Camera camera = Camera .open (mCameraId );
750738
751- SizePair sizePair = selectSizePair (camera , mRequestedPreviewWidth , mRequestedPreviewHeight );
739+ SizePair sizePair = selectSizePair (camera );
752740 if (sizePair == null ) {
753741 throw new RuntimeException ("Could not find suitable preview size." );
754742 }
@@ -772,7 +760,7 @@ private Camera createCamera() {
772760 previewFpsRange [Camera .Parameters .PREVIEW_FPS_MAX_INDEX ]);
773761 parameters .setPreviewFormat (ImageFormat .NV21 );
774762
775- setRotation (camera , parameters , requestedCameraId );
763+ setRotation (camera , parameters , mCameraId );
776764
777765 if (mFocusMode != null ) {
778766 if (parameters .getSupportedFocusModes ().contains (
@@ -842,29 +830,22 @@ private static int getIdForRequestedCamera(int facing) {
842830 * image.
843831 *
844832 * @param camera the camera to select a preview size from
845- * @param desiredWidth the desired width of the camera preview frames
846- * @param desiredHeight the desired height of the camera preview frames
847833 * @return the selected preview and picture size pair
848834 */
849- private static SizePair selectSizePair (Camera camera , int desiredWidth , int desiredHeight ) {
835+ private static SizePair selectSizePair (Camera camera ) {
850836 List <SizePair > validPreviewSizes = generateValidPreviewSizeList (camera );
851837
852- // The method for selecting the best size is to minimize the sum of the differences between
853- // the desired values and the actual values for width and height. This is certainly not the
854- // only way to select the best size, but it provides a decent tradeoff between using the
855- // closest aspect ratio vs. using the closest pixel area.
856- SizePair selectedPair = null ;
857- int minDiff = Integer .MAX_VALUE ;
858- for (SizePair sizePair : validPreviewSizes ) {
859- Size size = sizePair .previewSize ();
860- int diff = Math .abs (size .getWidth () - desiredWidth ) +
861- Math .abs (size .getHeight () - desiredHeight );
862- if (diff < minDiff ) {
863- selectedPair = sizePair ;
864- minDiff = diff ;
838+ Collections .sort (validPreviewSizes , new Comparator <SizePair >() {
839+ @ Override
840+ public int compare (SizePair lhs , SizePair rhs ) {
841+ return (rhs .previewSize ().getHeight () * rhs .previewSize ().getWidth ())
842+ - (lhs .previewSize ().getHeight () * lhs .previewSize ().getWidth ());
865843 }
866- }
844+ });
867845
846+ SizePair selectedPair = validPreviewSizes .get (0 );
847+ Log .d (TAG , "selected preview size: w:" + selectedPair .previewSize ().getWidth ()
848+ + ", h:" + selectedPair .previewSize ().getHeight ());
868849 return selectedPair ;
869850 }
870851
@@ -907,18 +888,18 @@ public Size pictureSize() {
907888 */
908889 private static List <SizePair > generateValidPreviewSizeList (Camera camera ) {
909890 Camera .Parameters parameters = camera .getParameters ();
910- List <Camera .Size > supportedPreviewSizes =
891+ List <android . hardware . Camera .Size > supportedPreviewSizes =
911892 parameters .getSupportedPreviewSizes ();
912- List <Camera .Size > supportedPictureSizes =
893+ List <android . hardware . Camera .Size > supportedPictureSizes =
913894 parameters .getSupportedPictureSizes ();
914895 List <SizePair > validPreviewSizes = new ArrayList <>();
915- for (Camera .Size previewSize : supportedPreviewSizes ) {
896+ for (android . hardware . Camera .Size previewSize : supportedPreviewSizes ) {
916897 float previewAspectRatio = (float ) previewSize .width / (float ) previewSize .height ;
917898
918899 // By looping through the picture sizes in order, we favor the higher resolutions.
919900 // We choose the highest resolution in order to support taking the full resolution
920901 // picture later.
921- for (Camera .Size pictureSize : supportedPictureSizes ) {
902+ for (android . hardware . Camera .Size pictureSize : supportedPictureSizes ) {
922903 float pictureAspectRatio = (float ) pictureSize .width / (float ) pictureSize .height ;
923904 if (Math .abs (previewAspectRatio - pictureAspectRatio ) < ASPECT_RATIO_TOLERANCE ) {
924905 validPreviewSizes .add (new SizePair (previewSize , pictureSize ));
@@ -932,7 +913,7 @@ private static List<SizePair> generateValidPreviewSizeList(Camera camera) {
932913 // still account for it.
933914 if (validPreviewSizes .size () == 0 ) {
934915 Log .w (TAG , "No preview sizes have a corresponding same-aspect-ratio picture size" );
935- for (Camera .Size previewSize : supportedPreviewSizes ) {
916+ for (android . hardware . Camera .Size previewSize : supportedPreviewSizes ) {
936917 // The null picture size will let us know that we shouldn't set a picture size.
937918 validPreviewSizes .add (new SizePair (previewSize , null ));
938919 }
@@ -974,6 +955,12 @@ private int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) {
974955 return selectedFpsRange ;
975956 }
976957
958+ public void updateRotation () {
959+ if (mCamera != null ) {
960+ setRotation (mCamera , mCamera .getParameters (), mCameraId );
961+ }
962+ }
963+
977964 /**
978965 * Calculates the correct rotation for the given camera id and sets the rotation in the
979966 * parameters. It also sets the camera's display orientation and rotation.
0 commit comments