I'm developing an Android application, and I'm using OpenCV4Android in the development, in the version 2.4.9.
I have opened a video stream using the JavaCameraView class. My problem is the bad orientation of the Camera compared to the position of the device. I'm using a Samsung Galaxy S4, and the default orientation of OpenCV camera seems to be landscape left.
To solve this problem, I've used this solution. I've extended the JavaCameraView class, adding to the new class this methods:
private void getScreenRotationOnPhone() {
final Display display = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation()) {
case Surface.ROTATION_0:
System.out.println("SCREEN_ORIENTATION_PORTRAIT");
setDisplayOrientation(mCamera, 90);
try {
mCamera.setPreviewDisplay(getHolder());
} catch (IOException e) {
e.printStackTrace();
}
break;
case Surface.ROTATION_90:
System.out.println("SCREEN_ORIENTATION_LANDSCAPE");
break;
case Surface.ROTATION_180:
System.out.println("SCREEN_ORIENTATION_REVERSE_PORTRAIT");
break;
case Surface.ROTATION_270:
System.out.println("SCREEN_ORIENTATION_REVERSE_LANDSCAPE");
setDisplayOrientation(mCamera, 180);
try {
mCamera.setPreviewDisplay(getHolder());
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
private void getScreenRotationOnTablet() {
final Display display = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation()) {
case Surface.ROTATION_0:
System.out.println("SCREEN_ORIENTATION_LANDSCAPE");
break;
case Surface.ROTATION_90:
System.out.println("SCREEN_ORIENTATION_REVERSE_PORTRAIT");
break;
case Surface.ROTATION_180:
System.out.println("SCREEN_ORIENTATION_REVERSE_LANDSCAPE");
break;
case Surface.ROTATION_270:
System.out.println("SCREEN_ORIENTATION_PORTRAIT");
break;
}
}
public static boolean isTablet(Context ctx){
return (ctx.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
So, in the initializeCamera method, before the mCamera.startPreview(), I've added the following code:
if(isTablet(getContext()) == Boolean.FALSE){
this.getScreenRotationOnPhone();
}else{
this.getScreenRotationOnTablet();
}
This code works, and the application is not slowed (I could use also the flip method, or rotation matrix, in the onCameraFrame method of my activity, ma in this way my performances get worse).
The only problem is when my orientation of device changes from landscape right to landscape left and vice-versa, without going through portrait mode. After this change, my Camera is turned 180 degrees with respect to natural position.
Here there are two images that show the problem.
This 180° rotation issue is either a bug or a feature of Android platform. One obvious workaround is to declare your activity only to use one landscape and one portrait orientation (not full-sensor).
The other approach is to employ OrientationEventListener: see Rotating phone quickly 180 degrees, camera preview turns upside down
Related
I have posted an issue to grafika, but it seems there is nobody to maintain the project now.
I want to use the CameraCaptureActivity which implemented by GLSurfaceView to switch front/back camera, as following:
public boolean switchCamera() {
releaseCamera();
mGLView.onPause();
if (mReqCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
mReqCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
} else {
mReqCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
openCamera(mReqCameraId);
mGLView.onResume();
mGLView.queueEvent(new Runnable() {
#Override
public void run() {
mRenderer.setCameraPreviewSize(mCameraPreviewWidth, mCameraPreviewHeight);
}
});
return true;
}
It can work, but the FOV has been changed when I back to the camera which first time launched. It seems the frame has been clipped.
So where did i miss when switch the front-back camera?
Thanks.
PS: I have googled, but there is little information about Android Camera with GLSurfaceView.
As #fadden's comment, i remove the setRecordingHint(true), and it works fine.
Not switching back to the mode what user have used.
I mean when phone is in silent and i used to ring for some selected numbers but it does not
switch back to normal mode when phone state is idle.
here's my piece of code.........
if(IncomingNumber.equals(WhitelistedNumbers)){
am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
System.out.println("Number Matches......!");
System.out.println("WhitelistedNumber(s): "+WhitelistedNumbers);
}else{
System.out.println("No Match(s) found.....!");
}
and to switch back to normal mode i m using........
case TelephonyManager.CALL_STATE_IDLE:
am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
System.out.println("Set to Default Ringer Mode....!");
break;
Thanks in advance if any suggestion to sort the problem........
You need to save the previous ringer mode in a variable, and then restore it from that variable.
int previousMode;
if(IncomingNumber.equals(WhitelistedNumbers))
{
previousMode = am.getRingerMode();
am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
....
}
and to restore:
am.setRingerMode(previousMode);
I have an application that I only want to run in landscape mode (e.g. landscape or reverse landscape) so I am using sensorLandscape in the manifest.
My problem is here:
I also have a video recorder working (eg using the camera). Now I set the display orientation when i prepare the camera, but the problem is that if I change orientation that change stays (preview is upside down). When using sensor landscape how do I know when the UI is changed. I have tried using onConfigurationCanged() but unfortunately I need to have the app run on both pre honeycomb devices (mainly gingerbread) and post honeycomb devices (jelly bean).
Since in order to properly have onConfigurationChanged called i need to set target api to like 8, but sensor landscape is only available 9+. I need to set it to 8 because in the older api's you need to add screenSize to your "configChanges" otherwise it will not be called. So these calls have alot of incompatabilities between eachother.
Now that the background is done and you guys know what I have tried already. My question is
How can I find out when my orientation changes (callback, or something else) so that I can change my camera display orientation?
Thank you in advance.
I have figured out how to get this done. It is a round about way but here it is:
Set up a sensor manager and an oreitnation senosr
public class ActivityRecordVideo extends ActivityBase implements SensorEventListener
{
private SensorManager mSensorManager;
private Sensor mOrientation;
#Override
public void onCreate(Bundle savedInstanceState)
{
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
}
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
public void onSensorChanged(SensorEvent event) {
int rotation = getWindowManager().getDefaultDisplay().getRotation();
if(camId != -1 && currentDisplayRotation != rotation)
{
if(!isRecording)
setCameraOrientation(camId, cameraRecorder);
}
}
I also set the listeners in onResume() and remove them in onPause().
This allows for a camera orientation to flip with everything else (e.g. when in reverse landscape all views are in reverse landscape along with the camera preview)
Also decided to show setCameraOrientation code, it is a stipped down version of the android developers code
private void setCameraOrientation(int camId, Camera camera)
{
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(camId, info);
currentDisplayRotation = getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch(currentDisplayRotation)
{
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
int result;
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; //compensate for mirror effect
if(Build.VERSION.SDK_INT < 14)
camera.stopPreview();
camera.setDisplayOrientation(result);
if(Build.VERSION.SDK_INT < 14)
camera.startPreview();
}
Hopefully this will help others
i m trying to implement camera in my app but i found that the orientation preview is all time in landscape but my app is in portrait so i need it in to portrait mode i found some solutions about that like
mCamera.setDisplayOrientation(90);
its working good with Galaxy tab2 and htc but when i test it in sony xperia sola it display strange hear i add image screen of it
u can see that the preview of camera its display of right side of screen only
but when i take picture from this app it display ok. i don't no what is the problem
can anyone help me in this .
You can try to force the surface size (and position) - I followed this path to compensate a similar bug in 2.2 version of Samsung Galaxy S. The bug was fixed when the device upgraded to 2.3.
I solved this using the following code:
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
[...]
public void show(){
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
if (!showing) {
showing=true;
try {
mCamera = Camera.open();
aspectRatio();
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
mCamera.setDisplayOrientation(90);
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), R.string.text_camera_open_error, Toast.LENGTH_SHORT).show();
}
}
}
private void aspectRatio(){
if (!aspect_radio_corrected){
aspect_radio_corrected=true;
Display default_disp=((Activity)getContext()).getWindowManager().getDefaultDisplay();
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size optimalPreviewSize=parameters.getPreviewSize();
FrameLayout.LayoutParams l_params=(FrameLayout.LayoutParams)getLayoutParams();
float ratio = (float) optimalPreviewSize.height / optimalPreviewSize.width;
l_params.width=default_disp.getWidth();
l_params.height=Math.round(l_params.width / ratio);
setLayoutParams(l_params);
requestLayout();
}
}
[...]
}
And on the layout file I have:
<com.socialcoaster.utils.CameraPreview
android:id="#+id/cameraView"
android:background="#android:color/transparent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Seems that this is a bug related with the aspect ratio of the current preview size setup on camera and the surfaceView area to show it. You can see that by simply changing the values of aspectRatio() to some fixed values like 100.
After some Googling it appears this is a common problem but I have yet to find an actual solution. I haven't tested on an actual device, but the emulator is cutting off my sound clips at around 80% done. I am playing back .wav files.
Does anyone know a programmatic solution to these problems?
edit:
public void play(Context context){
if (soundPlayer != null){
soundPlayer.release();
}
int rId = 0;
switch(aIndex){
case 0: rId = R.raw.c0; break;
case 1: rId = R.raw.c1; break;
case 2: rId = R.raw.c2; break;
case 3: rId = R.raw.c3; break;
case 4: rId = R.raw.c4; break;
case 5: rId = R.raw.c5; break;
case 6: rId = R.raw.c6; break;
case 7: rId = R.raw.c7; break;
case 8: rId = R.raw.c8; break;
case 9: rId = R.raw.c9; break;
case 10: rId = R.raw.c10; break;
case 11: rId = R.raw.c11; break;
case 12: rId = R.raw.c12; break;
case 13: rId = R.raw.c13; break;
case 14: rId = R.raw.v14; break;
case 15: rId = R.raw.v15; break;
case 16: rId = R.raw.v16; break;
case 17: rId = R.raw.v17; break;
case 18: rId = R.raw.v18; break;
case 19: rId = R.raw.v19; break;
case 20: rId = R.raw.v20; break;
case 21: rId = R.raw.v21; break;
case 22: rId = R.raw.v22; break;
case 23: rId = R.raw.v23; break;
default: rId = R.raw.error; break;
}
soundPlayer = MediaPlayer.create(context, rId);
if (soundPlayer != null){
soundPlayer.start();
}
}
Just discovered this question after having the same problem. The simple answer in my case was to make MediaPlayer a class variable. If you make it local to your method the garbage collector apparently sweeps it up and kills the sound play.
Well for starters, I would try to make sure MediaPlayer.create() function is called prior to the start(). If it's a game, load the sounds when they start a new game (creating a new media player for each sound). The reason why is because the create function will effectively load the sound file there and then, ready for smooth playback when you call start. If you load the file every time before running it, not only are you doing more work than you need to, but it may have undesired effects on the emulator. I'm not sure if you've noticed, but the emulator isn't exact the quickest tool out the shed compared to virtually any actual physical device. As a result, what I think may be happening is the emulator is 'playing' the sound and thinks that it is complete before the sound actually plays, mainly due to the emulator's slow speed.
Try it out on an actual device and I think you won't have any problems.
I think you need to do a release before to start ... example
if( mPlayer!= null ) mPlayer.release();
mPlayer = MediaPlayer.create(this, listaMP3[contador]);
mPlayer.start();
for soem reason if I define the mediaPlayer outside of the method I use to play a song, it works.
Even though I only call the playSong() method once;
mediaPlayer = MediaPlayer.create(mContext, R.raw.overworld);
mediaPlayer.setVolume(musicVolume, musicVolume);
playSong();
playSong Method:
private void playSong() {
if (!mediaPlayer.isPlaying())
mediaPlayer.start(); // no need to call prepare(); create() does that for you
}