Commit 732e1a65 authored by Simon Morlat's avatar Simon Morlat

Merge branch 'master' of git://git.linphone.org/mediastreamer2

parents 759628cf af7bb8b2
......@@ -31,3 +31,4 @@ stamp-h1
java/bin/
java/libs/
java/gen/
libs
......@@ -22,6 +22,7 @@
LOCAL_PATH:= $(call my-dir)/../../src
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm
MEDIASTREAMER2_INCLUDES := \
......@@ -38,14 +39,8 @@ MEDIASTREAMER2_INCLUDES := \
$(LOCAL_PATH)/../../../externals/libvpx/
## $(LOCAL_PATH)/../../../externals/openmax-dl/api \
## $(LOCAL_PATH)/../../../externals/openmax-dl/ip/api
LOCAL_MODULE := libmediastreamer2
#LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES = \
audiomixer.c \
audioconference.c \
......@@ -86,33 +81,19 @@ else
LOCAL_SRC_FILES += msresample.c
endif
##if BUILD_ALSA
ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
LOCAL_SRC_FILES += alsa.c
LOCAL_CFLAGS += -D__ALSA_ENABLED__
endif
##if BUILD_OSS
#LOCAL_SRC_FILES += oss.c
##if BUILD_ARTS
#LOCAL_SRC_FILES += arts.c
##if BUILD_PORTAUDIO
#LOCAL_SRC_FILES += pasnd.c
##if BUILD_MACSND
#LOCAL_SRC_FILES += macsnd.c
##if BUILD_MACAQSND
#LOCAL_SRC_FILES += aqsnd.c
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
ifeq ($(LINPHONE_VIDEO),1)
LOCAL_ARM_NEON := true
LOCAL_CFLAGS += -DVIDEO_ENABLED -DHAVE_NEON=1 -D__ARM_NEON__
LOCAL_SRC_FILES += \
videostream.c \
videoenc.c \
videodec.c \
pixconv.c \
......@@ -122,7 +103,6 @@ LOCAL_SRC_FILES += \
h264dec.c \
rfc3984.c \
mire.c \
videostream.c \
layouts.c \
android-display.c \
android-display-bad.cpp \
......@@ -134,6 +114,7 @@ LOCAL_SRC_FILES += \
opengles_display.c \
android-opengl-display.c
endif
endif
#LOCAL_SRC_FILES += videostream.c
#
......
......@@ -53,6 +53,7 @@ public class MediastreamerActivity extends Activity {
Thread msThread;
int cameraId = 0;
String videoCodec = VP8_MIME_TYPE;
AndroidVideoWindowImpl mVideoWindow;
static String VP8_MIME_TYPE = "VP8-DRAFT-0-3-2";
static String H264_MIME_TYPE = "H264";
......@@ -64,7 +65,7 @@ public class MediastreamerActivity extends Activity {
loadOptionalLibrary("swscale");
loadOptionalLibrary("avcore");
loadOptionalLibrary("avcodec");
// Main library
System.loadLibrary("mediastreamer2");
}
......@@ -93,7 +94,7 @@ public class MediastreamerActivity extends Activity {
previewSurface.setZOrderOnTop(true);
/* instanciate object responsible of video rendering */
AndroidVideoWindowImpl mVideoWindow = new AndroidVideoWindowImpl(this, view, previewSurface);
mVideoWindow = new AndroidVideoWindowImpl(view, previewSurface);
mVideoWindow
.setListener(new AndroidVideoWindowImpl.VideoWindowListener() {
......@@ -114,13 +115,9 @@ public class MediastreamerActivity extends Activity {
setDeviceRotation(rotationToAngle(getWindowManager().getDefaultDisplay()
.getRotation()));
}
@Override
public void onDeviceOrientationChanged(
int rotationDegrees) {
setDeviceRotation(rotationDegrees);
}
});
mVideoWindow.init();
final List<String> args = new ArrayList<String>();
args.add("prog_name");
......@@ -157,6 +154,7 @@ public class MediastreamerActivity extends Activity {
@Override
protected void onDestroy() {
mVideoWindow.release();
stopMediaStream();
try {
msThread.join(100000);
......
......@@ -39,7 +39,7 @@ import android.view.SurfaceView;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceHolder.Callback;
public class AndroidVideoWindowImpl {
public class AndroidVideoWindowImpl {
private SurfaceView mVideoRenderingView;
private SurfaceView mVideoPreviewView;
......@@ -60,15 +60,13 @@ public class AndroidVideoWindowImpl {
void onVideoPreviewSurfaceReady(AndroidVideoWindowImpl vw);
void onVideoPreviewSurfaceDestroyed(AndroidVideoWindowImpl vw);
void onDeviceOrientationChanged(int newRotationDegrees);
};
/**
* @param renderingSurface Surface created by the application that will be used to render decoded video stream
* @param previewSurface Surface created by the application used by Android's Camera preview framework
*/
public AndroidVideoWindowImpl(final Activity activity, SurfaceView renderingSurface, SurfaceView previewSurface) {
public AndroidVideoWindowImpl(SurfaceView renderingSurface, SurfaceView previewSurface) {
mVideoRenderingView = renderingSurface;
mVideoPreviewView = previewSurface;
......@@ -77,7 +75,9 @@ public class AndroidVideoWindowImpl {
mBitmap = null;
mSurface = null;
mListener = null;
}
public void init() {
// register callback for rendering surface events
mVideoRenderingView.getHolder().addCallback(new Callback(){
public void surfaceChanged(SurfaceHolder holder, int format,
......@@ -130,30 +130,16 @@ public class AndroidVideoWindowImpl {
}
});
// register for orientation event
SensorManager sensorMgr = (SensorManager) activity.getSystemService(Activity.SENSOR_SERVICE);
Sensor mAccelerometer = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMgr.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
int rot = rotationToAngle(activity.getWindowManager().getDefaultDisplay()
.getRotation());
// Returning rotation FROM ITS NATURAL ORIENTATION
if (mListener != null)
mListener.onDeviceOrientationChanged(rot);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
}, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
if (useGLrendering) {
renderer = new Renderer();
((GLSurfaceView)mVideoRenderingView).setRenderer(renderer);
((GLSurfaceView)mVideoRenderingView).setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
}
public void release() {
//mSensorMgr.unregisterListener(this);
}
public void setListener(VideoWindowListener l){
mListener=l;
......@@ -233,7 +219,7 @@ public class AndroidVideoWindowImpl {
}
}
static int rotationToAngle(int r) {
public static int rotationToAngle(int r) {
switch (r) {
case Surface.ROTATION_0:
return 0;
......
......@@ -20,6 +20,9 @@ package org.linphone.mediastream.video.capture;
import java.util.List;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
......@@ -38,13 +41,21 @@ public class AndroidVideoApi5JniWrapper {
static public int detectCameras(int[] indexes, int[] frontFacing, int[] orientation) {
Log.d("mediastreamer", "detectCameras\n");
int count = 1;
indexes[0] = 0;
frontFacing[0] = 0;
orientation[0] = 90;
AndroidCamera[] cameras = AndroidCameraConfiguration.retrieveCameras();
return count;
int nextIndex = 0;
for (AndroidCamera androidCamera : cameras) {
if (nextIndex == 2) {
Log.w("mediastreamer", "Returning only the 2 first cameras (increase buffer size to retrieve all)");
break;
}
// skip already added cameras
indexes[nextIndex] = androidCamera.id;
frontFacing[nextIndex] = androidCamera.frontFacing?1:0;
orientation[nextIndex] = androidCamera.orientation;
nextIndex++;
}
return cameras.length;
}
/**
......@@ -124,29 +135,20 @@ public class AndroidVideoApi5JniWrapper {
int rH = Math.min(requestedW, requestedH);
try {
// look for exact match
// look for nearest size
Size result = null;
int req = rW * rH;
int minDist = Integer.MAX_VALUE;
for(Size s: supportedSizes) {
int dist = Math.abs(req - s.width * s.height);
if (dist < minDist) {
minDist = dist;
result = s;
}
if (s.width == rW && s.height == rH)
return new int[] {s.width, s.height};
}
// look for just above match (120%)
for(Size s: supportedSizes) {
if (s.width < rW || s.height < rH)
continue;
if (s.width <= rW * 1.2 && s.height <= rH * 1.2)
return new int[] {s.width, s.height};
}
// return nearest smaller (or the 1st one, if no smaller is found)
Size n = supportedSizes.get(0);
for(Size s: supportedSizes) {
if (s.width > rW || s.height > rH)
continue;
if (n == null)
n = s;
else if (s.width > n.width && s.height > n.height)
n = s;
}
return new int[] {n.width, n.height};
return new int[] {result.width, result.height};
} catch (Exception exc) {
exc.printStackTrace();
return null;
......
......@@ -22,30 +22,12 @@ import java.util.List;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.util.Log;
public class AndroidVideoApi9JniWrapper {
static public int detectCameras(int[] indexes, int[] frontFacing, int[] orientation) {
Log.d("mediastreamer", "detectCameras\n");
/* SDK >= 9 */
int count = Camera.getNumberOfCameras();
if (count > indexes.length) {
Log.w("mediastreamer", "Returning only the " + indexes.length + " first cameras (increase buffer size to retrieve all)");
count = indexes.length;
}
CameraInfo cameraInfo = new CameraInfo();
for(int i=0; i<count; i++) {
Camera.getCameraInfo(i, cameraInfo);
indexes[i] = i;
frontFacing[i] = (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT)?1:0;
orientation[i] = cameraInfo.orientation;
}
return count;
return AndroidVideoApi5JniWrapper.detectCameras(indexes, frontFacing, orientation);
}
/**
......
/*
AndroidCameraConf.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.mediastream.video.capture.hwconf;
import android.os.Build;
/**
* Entry point for accessing hardware cameras configuration.
* Different SDK implementations are delegated to specific AndroidCameraConfN versions.
*
*/
public class AndroidCameraConfiguration {
public static AndroidCamera[] retrieveCameras() {
initCamerasCache();
return camerasCache;
}
public static boolean hasSeveralCameras() {
initCamerasCache();
return camerasCache.length > 1;
}
public static boolean hasFrontCamera() {
initCamerasCache();
for (AndroidCamera cam: camerasCache) {
if (cam.frontFacing)
return true;
}
return false;
}
private static AndroidCameraConfiguration.AndroidCamera[] camerasCache;
private static void initCamerasCache() {
// cache already filled ?
if (camerasCache != null)
return;
if (Build.VERSION.SDK_INT < 9)
camerasCache = AndroidCameraConfiguration.probeCamerasSDK5();
else
camerasCache = AndroidCameraConfiguration.probeCamerasSDK9();
}
static AndroidCamera[] probeCamerasSDK5() {
return AndroidCameraConfigurationReader5.probeCameras();
}
static AndroidCamera[] probeCamerasSDK9() {
return AndroidCameraConfigurationReader9.probeCameras();
}
/**
* Default: no front; rear=0; default=rear
* @author Guillaume Beraudo
*
*/
static public class AndroidCamera {
public AndroidCamera(int i, boolean f, int o) {
this.id = i;
this.frontFacing = f;
this.orientation = o;
}
public int id;
public boolean frontFacing; // false => rear facing
public int orientation;
}
}
\ No newline at end of file
/*
AndroidCameraConf.java
Copyright (C) 2010 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.mediastream.video.capture.hwconf;
import java.util.ArrayList;
import java.util.List;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera;
import android.util.Log;
/**
* Android cameras detection, using SDK < 9
*
*/
class AndroidCameraConfigurationReader5 {
static public AndroidCamera[] probeCameras() {
List<AndroidCamera> cam = new ArrayList<AndroidCamera>(1);
// Defaults
if (Hacks.isGalaxySOrTab()) {
Log.d("mediastreamer", "Hack Galaxy S : has one or more cameras");
if (Hacks.isGalaxySOrTabWithFrontCamera()) {
Log.d("mediastreamer", "Hack Galaxy S : HAS a front camera with id=2");
cam.add(new AndroidCamera(2, true, 90));
} else {
Log.d("mediastreamer", "Hack Galaxy S : NO front camera");
}
Log.d("mediastreamer", "Hack Galaxy S : HAS a rear camera with id=1");
cam.add(new AndroidCamera(1, false, 90));
} else {
cam.add(new AndroidCamera(0, false, 90));
if (Hacks.hasTwoCamerasRear0Front1()) {
Log.d("mediastreamer", "Hack SPHD700 has 2 cameras a rear with id=0 and a front with id=1");
cam.add(new AndroidCamera(1, true, 90));
}
}
AndroidCamera[] result = new AndroidCamera[cam.size()];
result = cam.toArray(result);
return result;
}
}
/*
AndroidCameraConf9.java
Copyright (C) 2010 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.mediastream.video.capture.hwconf;
import java.util.ArrayList;
import java.util.List;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
/**
* Android cameras detection, using SDK >= 9
*
*/
class AndroidCameraConfigurationReader9 {
static public AndroidCamera[] probeCameras() {
List<AndroidCamera> cam = new ArrayList<AndroidCamera>(Camera.getNumberOfCameras());
for(int i=0; i<Camera.getNumberOfCameras(); i++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(i, info);
cam.add(new AndroidCamera(i, info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT, info.orientation));
}
AndroidCamera[] result = new AndroidCamera[cam.size()];
result = cam.toArray(result);
return result;
}
}
/*
Hacks.java
Copyright (C) 2010 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.mediastream.video.capture.hwconf;
import android.hardware.Camera;
import android.media.AudioManager;
import android.os.Build;
import android.util.Log;
public final class Hacks {
private Hacks() {}
public static boolean isGalaxySOrTabWithFrontCamera() {
return isGalaxySOrTab() && !isGalaxySOrTabWithoutFrontCamera();
}
private static boolean isGalaxySOrTabWithoutFrontCamera() {
return isSC02B() || isSGHI896();
}
public static boolean isGalaxySOrTab() {
return isGalaxyS() || isGalaxyTab();
}
public static boolean isGalaxyTab() {
return isGTP1000();
}
private static boolean isGalaxyS() {
return isGT9000() || isSC02B() || isSGHI896() || isSPHD700();
}
public static final boolean hasTwoCamerasRear0Front1() {
return isSPHD700() || isADR6400();
}
// HTC
private static final boolean isADR6400() {
return Build.MODEL.startsWith("ADR6400") || Build.DEVICE.startsWith("ADR6400");
} // HTC Thunderbolt
// Galaxy S variants
private static final boolean isSPHD700() {return Build.DEVICE.startsWith("SPH-D700");} // Epic
private static boolean isSGHI896() {return Build.DEVICE.startsWith("SGH-I896");} // Captivate
private static boolean isGT9000() {return Build.DEVICE.startsWith("GT-I9000");} // Galaxy S
private static boolean isSC02B() {return Build.DEVICE.startsWith("SC-02B");} // Docomo
private static boolean isGTP1000() {return Build.DEVICE.startsWith("GT-P1000");} // Tab
/* private static final boolean log(final String msg) {
Log.d(msg);
return true;
}*/
/* Not working as now
* Calling from Galaxy S to PC is "usable" even with no hack; other side is not even with this one*/
public static void galaxySSwitchToCallStreamUnMuteLowerVolume(AudioManager am) {
// Switch to call audio channel (Galaxy S)
am.setSpeakerphoneOn(false);
sleep(200);
// Lower volume
am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, 1, 0);
// Another way to select call channel
am.setMode(AudioManager.MODE_NORMAL);
sleep(200);
// Mic is muted if not doing this
am.setMicrophoneMute(true);
sleep(200);
am.setMicrophoneMute(false);
sleep(200);
}
public static final void sleep(int time) {
try {
Thread.sleep(time);
} catch(InterruptedException ie){}
}
public static void dumpDeviceInformation() {
StringBuilder sb = new StringBuilder(" ==== Phone information dump ====\n");
sb.append("DEVICE=").append(Build.DEVICE).append("\n");
sb.append("MODEL=").append(Build.MODEL).append("\n");
//MANUFACTURER doesn't exist in android 1.5.
//sb.append("MANUFACTURER=").append(Build.MANUFACTURER).append("\n");
sb.append("SDK=").append(Build.VERSION.SDK);
Log.i("mediastreamer", sb.toString());
}
public static boolean needSoftvolume() {
return isGalaxySOrTab();
}
public static boolean needRoutingAPI() {
return Build.VERSION.SDK_INT < 5;
}
public static boolean needGalaxySAudioHack() {
return isGalaxySOrTab() && !isSC02B();
}
public static boolean needPausingCallForSpeakers() {
// return false;
return isGalaxySOrTab() && !isSC02B();
}
public static boolean hasTwoCameras() {
return isSPHD700() || isGalaxySOrTabWithFrontCamera();
}
public static boolean hasCamera() {
if (Build.VERSION.SDK_INT >= 9) {
int nb = 0;
try {
nb = (Integer) Camera.class.getMethod("getNumberOfCameras", (Class[])null).invoke(null);
} catch (Exception e) {
Log.e("mediastreamer", "Error getting number of cameras");
}
return nb > 0;
}
Log.i("mediastreamer", "Hack: considering there IS a camera.\n"
+ "If it is not the case, report DEVICE and MODEL to linphone-users@nongnu.org");
return true;
}
}
APP_PROJECT_PATH := $(call my-dir)/../
APP_MODULES :=libspeex libgsm libortp libavutil libavcore libavcodec libswscale libvpx libmediastreamer2
APP_STL := stlport_static
# define linphone-root-dir to linphone base dir
BUILD_MS2 := 1
linphone-root-dir:=$(APP_PROJECT_PATH)/../../../
APP_BUILD_SCRIPT:=$(linphone-root-dir)/jni/Android.mk
APP_PLATFORM := android-8
APP_ABI := armeabi-v7a
APP_CFLAGS:=-DDISABLE_NEON
......@@ -80,6 +80,7 @@ static void android_display_process(MSFilter *f){
mblk_t *m;
ms_filter_lock(f);
#if 1
if (ad->android_video_window){
if ((m=ms_queue_peek_last(f->inputs[0]))!=NULL){
if (ms_yuv_buf_init_from_mblk (&pic,m)==0){
......@@ -92,6 +93,7 @@ static void android_display_process(MSFilter *f){
}
}
}
#endif
ms_filter_unlock(f);
ms_queue_flush(f->inputs[0]);
......
......@@ -145,7 +145,9 @@ static int video_capture_set_vsize(MSFilter *f, void* data){
}
// is phone held |_ to cam orientation ?
if (d->rotation != UNDEFINED_ROTATION && compute_image_rotation_correction(d) % 180 != 0) {
if (d->rotation == UNDEFINED_ROTATION || compute_image_rotation_correction(d) % 180 != 0) {
if (d->rotation == UNDEFINED_ROTATION)
ms_warning("Capture filter do not know yet about device's orientation.\nCurrent assumption: device is held perpendicular to its webcam (ie: portrait mode for a phone)\n");