]> sjero.net Git - linphone/commitdiff
Fix video on Nexus S.
authorGuillaume Beraudo <guillaume.beraudo@belledonne-communications.com>
Thu, 4 Aug 2011 09:26:19 +0000 (11:26 +0200)
committerGuillaume Beraudo <guillaume.beraudo@belledonne-communications.com>
Thu, 4 Aug 2011 09:26:19 +0000 (11:26 +0200)
video/AndroidCameraConf.java
video/AndroidCameraConf5.java
video/AndroidCameraConf9.java
video/AndroidCameraRecord.java
video/AndroidCameraRecord5.java
video/AndroidCameraRecordManager.java
video/VideoUtil.java [new file with mode: 0644]

index 9796ba12bd7c8913bb05f02209a799a71b38beb9..874a6d2da22fdb0d1a047d25951edb586d843815 100644 (file)
@@ -18,6 +18,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 package org.linphone.core.video;
 
+import java.util.List;
+
+import org.linphone.core.VideoSize;
+
 
 /**
  * @author Guillaume Beraudo
@@ -33,6 +37,8 @@ interface AndroidCameraConf {
 
        boolean isFrontCamera(int cameraId);
 
+       List<VideoSize> getSupportedPreviewSizes(int cameraId);
+
        /**
         * Default: no front; rear=0; default=rear
         * @author Guillaume Beraudo
index c9c3a1ade8cad255c8f0b2595e8f24ee73f3f0a9..06c266d7a50b297dea3d8be1a5ebab422bc97290 100644 (file)
@@ -18,8 +18,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 package org.linphone.core.video;
 
+import java.util.List;
+
 import org.linphone.core.Hacks;
 import org.linphone.core.Log;
+import org.linphone.core.VideoSize;
+
+import android.hardware.Camera;
 
 
 class AndroidCameraConf5 implements AndroidCameraConf {
@@ -90,6 +95,18 @@ class AndroidCameraConf5 implements AndroidCameraConf {
 
                return false;
        }
+
+       public List<VideoSize> getSupportedPreviewSizes(int cameraId) {
+               if (getNumberOfCameras() >1) {
+                       Log.w("Hack: on older devices, using video formats supported by default camera");
+               }
+               Log.i("Opening camera to retrieve supported video sizes");
+               Camera c = Camera.open();
+               List<VideoSize> sizes=VideoUtil.createList(c.getParameters().getSupportedPreviewSizes());
+               c.release();
+               Log.i("Camera opened to retrieve supported video sizes released");
+               return sizes;
+       }
        
        
 
index d0ef0faa56fe2951f637c7d2a08be5b2fc8e1710..02e9098951e798cb77fb281e1cd16bc67a4dd300 100644 (file)
@@ -18,12 +18,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 package org.linphone.core.video;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.linphone.core.Log;
+import org.linphone.core.VideoSize;
 
 import android.hardware.Camera;
 
 class AndroidCameraConf9 implements AndroidCameraConf {
        private AndroidCameras foundCameras;
+       private Map<Integer,List<VideoSize>> supportedSizes = new HashMap<Integer, List<VideoSize>>();
        public AndroidCameras getFoundCameras() {return foundCameras;}
 
        public AndroidCameraConf9() {
@@ -38,9 +44,19 @@ class AndroidCameraConf9 implements AndroidCameraConf {
                        } else {
                                foundCameras.rear = id;
                        }
+                       supportedSizes.put(id, findSupportedVideoSizes(id));
                }
        }
        
+       private List<VideoSize> findSupportedVideoSizes(int id) {
+               Log.i("Opening camera ",id," to retrieve supported video sizes");
+               Camera c = Camera.open(id);
+               List<VideoSize> sizes=VideoUtil.createList(c.getParameters().getSupportedPreviewSizes());
+               c.release();
+               Log.i("Camera ",id," opened to retrieve supported video sizes released");
+               return sizes;
+       }
+
        public int getNumberOfCameras() {
                return Camera.getNumberOfCameras();
        }
@@ -58,4 +74,8 @@ class AndroidCameraConf9 implements AndroidCameraConf {
                return info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT ? true : false;
        }
 
+       public List<VideoSize> getSupportedPreviewSizes(int cameraId) {
+               return supportedSizes.get(cameraId);
+       }
+
 }
index dec9338b2269fb4d043bc577a8c8c346878b3963..bb9fd9786f098c8b9ef50a73bc74f0368128d087 100644 (file)
@@ -18,12 +18,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 package org.linphone.core.video;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import org.linphone.core.Log;
 import org.linphone.core.Version;
+import org.linphone.core.VideoSize;
 
 import android.hardware.Camera;
 import android.hardware.Camera.AutoFocusCallback;
@@ -44,7 +44,7 @@ public abstract class AndroidCameraRecord implements AutoFocusCallback {
 
        private PreviewCallback storedPreviewCallback;
        private boolean previewStarted;
-       private List <Size> supportedVideoSizes;
+       private List <VideoSize> supportedVideoSizes;
        private Size currentPreviewSize;
        
        public AndroidCameraRecord(RecorderParams parameters) {
@@ -55,6 +55,23 @@ public abstract class AndroidCameraRecord implements AutoFocusCallback {
                return Collections.emptyList();
        }
        
+       private int[] findClosestFpsRange(int expectedFps, List<int[]> fpsRanges) {
+               Log.d("Searching for closest fps range from ",expectedFps);
+               int measure = Integer.MAX_VALUE;
+               int[] closestRange = {expectedFps,expectedFps};
+               for (int[] curRange : fpsRanges) {
+                       if (curRange[0] > expectedFps || curRange[1] < expectedFps) continue;
+                       int curMeasure = Math.abs(curRange[0] - expectedFps)
+                                       + Math.abs(curRange[1] - expectedFps);
+                       if (curMeasure < measure) {
+                               closestRange=curRange;
+                               Log.d("a better range has been found: w=",closestRange[0],",h=",closestRange[1]);
+                       }
+               }
+               Log.d("The closest fps range is w=",closestRange[0],",h=",closestRange[1]);
+               return closestRange;
+       }
+
        public synchronized void startPreview() { // FIXME throws exception?
                if (previewStarted) {
                        Log.w("Already started");
@@ -83,12 +100,12 @@ public abstract class AndroidCameraRecord implements AutoFocusCallback {
                
                
                Camera.Parameters parameters=camera.getParameters();
-               if (Version.sdkStrictlyBelow(9)) {
+               if (Version.sdkStrictlyBelow(Version.API09_GINGERBREAD_23)) {
                        parameters.set("camera-id",params.cameraId);
                }
                
                if (supportedVideoSizes == null) {
-                       supportedVideoSizes = new ArrayList<Size>(getSupportedPreviewSizes(parameters));
+                       supportedVideoSizes = VideoUtil.createList(getSupportedPreviewSizes(parameters));
                }
 
 
@@ -101,7 +118,13 @@ public abstract class AndroidCameraRecord implements AutoFocusCallback {
                // should setParameters and get again to have the real one??
                currentPreviewSize = parameters.getPreviewSize(); 
 
-               parameters.setPreviewFrameRate(Math.round(params.fps));
+               // Frame rate
+               if (Version.sdkStrictlyBelow(Version.API09_GINGERBREAD_23)) {
+                       parameters.setPreviewFrameRate(Math.round(params.fps));
+               } else {
+                       int[] range=findClosestFpsRange((int)(1000*params.fps), parameters.getSupportedPreviewFpsRange());
+                       parameters.setPreviewFpsRange(range[0], range[1]);
+               }
 
 
                onSettingCameraParameters(parameters);
@@ -223,8 +246,8 @@ public abstract class AndroidCameraRecord implements AutoFocusCallback {
                return previewStarted;
        }
 
-       public List<Size> getSupportedVideoSizes() {
-               return new ArrayList<Size>(supportedVideoSizes);
+       public List<VideoSize> getSupportedVideoSizes() {
+               return supportedVideoSizes;
        }
        
        
index 03f9123db9f8e6e9b95c992f200b20b365ca522a..45f94cd29d54f5bdb676ab093314468ac1499ea9 100644 (file)
@@ -135,4 +135,5 @@ class AndroidCameraRecord5 extends AndroidCameraRecord implements PreviewCallbac
                camera.setPreviewCallback(cb);
        }
 
+
 }
index 86d12fffaf2dded8c2b3044ffa9d452a78b104fb..22f437d2166e493bf1e5cd22a06e6c6c4feb0681 100644 (file)
@@ -20,14 +20,13 @@ package org.linphone.core.video;
 
 import java.util.List;
 
-
 import org.linphone.core.LinphoneCore;
 import org.linphone.core.Log;
 import org.linphone.core.Version;
+import org.linphone.core.VideoSize;
 import org.linphone.core.video.AndroidCameraRecord.RecorderParams;
 
 import android.content.Context;
-import android.hardware.Camera.Size;
 import android.view.OrientationEventListener;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
@@ -63,7 +62,6 @@ public class AndroidCameraRecordManager {
        private int cameraId;
 
        private AndroidCameraRecord recorder;
-       private List<Size> supportedVideoSizes;
        private int mAlwaysChangingPhoneOrientation=0;
 
 
@@ -126,11 +124,14 @@ public class AndroidCameraRecordManager {
                p.cameraId = cameraId;
                p.isFrontCamera = isUseFrontCamera();
                parameters = p;
-               
+
+               // Mirror the sent frames in order to make them readable
+               // (otherwise it is mirrored and thus unreadable)
                if (p.isFrontCamera) {
-                       if (!isCameraOrientationPortrait()) {
-                               // Code for Nexus S: to be tested
-                               p.mirror = RecorderParams.MirrorType.CENTRAL;
+                       if (!isCameraMountedPortrait()) {
+                               // Code for Nexus S
+                               if (isFrameToBeShownPortrait())
+                                       p.mirror = RecorderParams.MirrorType.CENTRAL;
                        } else {
                                // Code for Galaxy S like: camera mounted landscape when phone hold portrait
                                p.mirror = RecorderParams.MirrorType.HORIZONTAL;
@@ -236,20 +237,9 @@ public class AndroidCameraRecordManager {
 
        
        
-       /**
-        * FIXME select right camera
-        */
-       public List<Size> supportedVideoSizes() {
-               if (supportedVideoSizes != null) {
-                       return supportedVideoSizes;
-               }
-
-               if (recorder != null) {
-                       supportedVideoSizes = recorder.getSupportedVideoSizes();
-                       if (supportedVideoSizes != null) return supportedVideoSizes;
-               }
-
-               return supportedVideoSizes;
+       public List<VideoSize> supportedVideoSizes() {
+               Log.d("Using supportedVideoSizes of camera ",cameraId);
+               return cc.getSupportedPreviewSizes(cameraId);
        }
 
 
@@ -267,20 +257,28 @@ public class AndroidCameraRecordManager {
                parameters = null;
        }
 
-       public boolean isOutputPortraitDependingOnCameraAndPhoneOrientations() {
+       /** Depends on currently selected camera, camera mounted portrait/landscape, current phone orientation */
+       public boolean isFrameToBeShownPortrait() {
                final int rotation = bufferRotationToCompensateCameraAndPhoneOrientations();
-               final boolean isPortrait = (rotation % 180) == 90;
-               
-               Log.d("Camera sensor in ", isPortrait? "portrait":"landscape"," orientation.");
+
+               boolean isPortrait;
+               if (isCameraMountedPortrait()) {
+                       // Nexus S
+                       isPortrait = (rotation % 180) == 0;
+               } else {
+                       isPortrait = (rotation % 180) == 90;
+               }
+
+               Log.d("The frame to be shown and sent to remote is ", isPortrait? "portrait":"landscape"," orientation.");
                return isPortrait;
        }
 
        
-       
-       
 
 
-       public boolean isCameraOrientationPortrait() {
+
+
+       public boolean isCameraMountedPortrait() {
                return (cc.getCameraOrientation(cameraId) % 180) == 0;
        }
 
@@ -296,8 +294,10 @@ public class AndroidCameraRecordManager {
                final int phoneOrientation = mAlwaysChangingPhoneOrientation;
                final int cameraOrientation = cc.getCameraOrientation(cameraId);
                int frontCameraCorrection = 0;
-               if (cc.isFrontCamera(cameraId)) // TODO: check with other phones (Nexus S, ...)
-                       frontCameraCorrection=180; // hack that "just works" on Galaxy S.
+               if (cc.isFrontCamera(cameraId)) {
+                       frontCameraCorrection=180; // hack that "just works" on Galaxy S and Nexus S.
+                       // See also magic with mirrors in setParametersFromFilter
+               }
                final int rotation = (cameraOrientation + phoneOrientation + frontCameraCorrection) % 360;
                Log.d("Capture video buffer of cameraId=",cameraId,
                                " will need a rotation of ",rotation,
@@ -342,7 +342,7 @@ public class AndroidCameraRecordManager {
         */
        public boolean isOutputOrientationMismatch(LinphoneCore lc) {
                final boolean currentlyPortrait = lc.getPreferredVideoSize().isPortrait();
-               final boolean shouldBePortrait = isOutputPortraitDependingOnCameraAndPhoneOrientations();
+               final boolean shouldBePortrait = isFrameToBeShownPortrait();
                return currentlyPortrait ^ shouldBePortrait;
        }
 
diff --git a/video/VideoUtil.java b/video/VideoUtil.java
new file mode 100644 (file)
index 0000000..065557b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+VideoUtil.java
+Copyright (C) 2011  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core.video;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.linphone.core.VideoSize;
+
+import android.hardware.Camera.Size;
+
+/**
+ * @author Guillaume Beraudo
+ */
+final class VideoUtil {
+
+       private VideoUtil() {}
+
+       public static List<VideoSize> createList(List<Size> supportedVideoSizes) {
+               List<VideoSize> converted = new ArrayList<VideoSize>(supportedVideoSizes.size());
+               for (Size s : supportedVideoSizes) {
+                       converted.add(new VideoSize(s.width, s.height));
+               }
+               return converted;
+       }
+}