Video recording App doesn't get destroyed properly. When i press Back button, the Camera App is onPause(). On starting a new instance of APP the video recording fails. If i manually kill previous instance and re-run APP it works perfect. According to my assumption, all life cycle to kill and release camera are implemented. But the integration or Calls are perhaps creating problem. Need help to sort it out, please.
CameraPreview Class
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private MyDrawing md;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
// create the surface and start camera preview
if (mCamera == null) {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
} catch (IOException e) {
Log.d(VIEW_LOG_TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void refreshCamera(Camera camera) {
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
setCamera(camera);
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
//startFaceDetection();
} catch (Exception e) {
Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
refreshCamera(mCamera);
}
public void setCamera(Camera camera) {
//method to set a camera instance
mCamera = camera;
mCamera.setFaceDetectionListener(faceDetectionListener);
startFaceDetection();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
mCamera.release();
}
private Camera.FaceDetectionListener faceDetectionListener = new Camera.FaceDetectionListener() {
#Override
public void onFaceDetection(Camera.Face[] faces, Camera c) {
if (faces.length > 0) {
Log.d("FaceDetection", "face detected X and Y are as: " + faces.length +
" Face 1 Location X: " + faces[0].rect.centerX() +
"Y: " + faces[0].rect.centerY() +" LIES IN "+(MyDrawing.w-MyDrawing.radius) +"--"+(MyDrawing.w+MyDrawing.radius));
if(faces[0].rect.centerX()>=0 && faces[0].rect.centerX()<115 )
{
Log.d("ALERT = ", "Detection Started" );
AndroidVideoCaptureExample.capture.setText("Recording/ stopNsave ");
AndroidVideoCaptureExample.faceDetect();
}
} else {
Log.d("FaceDetection", "circle cordinates are as: " + (MyDrawing.w-MyDrawing.radius) +"cX"+ MyDrawing.radius+"cY");
}
}
};
public void startFaceDetection(){
// Try starting Face Detection
Camera.Parameters params = mCamera.getParameters();
// start face detection only *after* preview has started
if (params.getMaxNumDetectedFaces() > 0){
// camera supports face detection, so can start it:
mCamera.startFaceDetection();
}
}
}
Main
public class AndroidVideoCaptureExample extends Activity {
private static Camera mCamera;
private static int vWidth,vHeight;
private CameraPreview mPreview;
public static MediaRecorder mediaRecorder;
public static Button capture, switchCamera;
private Context myContext;
private FrameLayout cameraPreview;
private boolean cameraFront = false;
private static int desiredwidth=640, desiredheight=360;
private MyDrawing md;
public static boolean vRecording = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
myContext = this;
initialize();
Log.d("FaceDetection", "face detected BASEER" );
}
private int findFrontFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
cameraId = i;
cameraFront = true;
break;
}
}
return cameraId;
}
public void onResume() {
super.onResume();
if (!hasCamera(myContext)) {
Toast toast = Toast.makeText(myContext, "Sorry, your phone does not have a camera!", Toast.LENGTH_LONG);
toast.show();
finish();
}
if (mCamera == null) {
// if the front facing camera does not exist
if (findFrontFacingCamera() < 0) {
Toast.makeText(this, "No front facing camera found.", Toast.LENGTH_LONG).show();
switchCamera.setVisibility(View.GONE);
}
mCamera = Camera.open(findFrontFacingCamera());
mCamera.setDisplayOrientation(90);
mPreview.refreshCamera(mCamera);
}
}
public void initialize() {
cameraPreview = (FrameLayout) findViewById(R.id.camera_preview);
mPreview = new CameraPreview(myContext, mCamera);
cameraPreview.addView(mPreview);
capture = (Button) findViewById(R.id.button_capture);
capture.setOnClickListener(captrureListener);
}
#Override
protected void onPause() {
super.onPause();
// when on Pause, release camera in order to be used from other
// applications
releaseCamera();
}
private boolean hasCamera(Context context) {
// check if the device has camera
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true;
} else {
return false;
}
}
static boolean recording = false;
OnClickListener captrureListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (recording) {
// stop recording and release camera
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
Toast.makeText(AndroidVideoCaptureExample.this, "Video captured!", Toast.LENGTH_LONG).show();
Toast.makeText(AndroidVideoCaptureExample.this, vWidth+"BY"+vHeight, Toast.LENGTH_LONG).show();
recording = false;
}
}
};
public static void faceDetect()
{
prepareMediaRecorder();
recording = true;
mediaRecorder.start();
}
private static void releaseMediaRecorder() {
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = null;
mCamera.lock(); // lock camera for later use
}
}
private static boolean prepareMediaRecorder() {
List<Camera.Size> videosizes = mCamera.getParameters().getSupportedVideoSizes();
Camera.Size videosize = videosizes.get(1);
Camera.Size optimalVideoSize = getOptimalPreviewSize(videosize, desiredwidth, desiredheight);
vWidth = optimalVideoSize.width;//mCamera.getParameters().getPreviewSize().width;
vHeight = optimalVideoSize.height;//mCamera.getParameters().getPreviewSize().height;
mediaRecorder = new MediaRecorder();
mCamera.unlock();
mediaRecorder.setCamera(mCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
mediaRecorder.setVideoEncodingBitRate(512* 1000);
mediaRecorder.setVideoFrameRate(15);
mediaRecorder.setVideoSize(optimalVideoSize.width, optimalVideoSize.height);
mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
mediaRecorder.setMaxDuration(600000); // Set max duration 60 sec.
mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
return true;
}
private void releaseCamera() {
// stop and release camera
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
private static Camera.Size getOptimalPreviewSize(Camera.Size sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.2;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
Camera.Size size = sizes;
Log.d("Camera", "Checking size " + size.width + "w " + size.height
+ "h");
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) <= ASPECT_TOLERANCE)
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
// Cannot find the one match the aspect ratio, ignore the
// requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
return optimalSize;
}
}
ErrorLog
Error/Crash:If App goes to foreground and reopens, As soon as face is detected (video recording starts on this detection)App crashes with following Error.
E/MediaRecorder: start failed: -38
D/AndroidRuntime: Shutting down VM
W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x42230c08)
E/AndroidRuntime: FATAL EXCEPTION: main
E/AndroidRuntime: Process: com.javacodegeeks.androidvideocaptureexample, PID: 8350
E/AndroidRuntime: java.lang.IllegalStateException
E/AndroidRuntime: at android.media.MediaRecorder.start(Native Method)
E/AndroidRuntime: at com.javacodegeeks.androidvideocaptureexample.AndroidVideoCaptureExample.faceDetect(AndroidVideoCaptureExample.java:141)
E/AndroidRuntime: at com.javacodegeeks.androidvideocaptureexample.CameraPreview$1.onFaceDetection(CameraPreview.java:105)
E/AndroidRuntime: at android.hardware.Camera$EventHandler.handleMessage(Camera.java:1015)
E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime: at android.os.Looper.loop(Looper.java:146)
E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5635)
E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
CameraPreview.surfaceDestroyed() release the camera, but does not set mCamera = null;. When the app is recalled from background, AndroidVideoCaptureExample.onCreate() may be skipped, so the mPreview object with an old mCamera reference will be used. Now if surfaceChanged() is executed before AndroidVideoCaptureExample.onResume() calls mPreview.refreshCamera(mCamera);, you are screwed.
The easy fix would be to add mCamera = null; to CameraPreview.surfaceDestroyed(), and check if (camera == null) { return; } in the beginning of CameraPreview.refreshCamera(Camera camera).
BTW, CameraPreview.surfaceCreated() has some broken code:
if (mCamera == null) {
mCamera.setPreviewDisplay(holder);
…
You can simply delete all this block, these operations will be performed in refreshCamera() called from surfaceChanged().
You can also remove the second parameter from CameraPreview constructor.
Get rid of those static variables and see if that solves your problem. When your last activity is finished, the Android framework may keep the process and VM alive to reduce the startup overhead the next time you launch the app. When that happens, all your static variables will retain their old values. (Your Application instance may also be retained, so beware of putting any data there, and never count on Application#onCreate(...) being called when your app is launched.)
Related
I have the some of the following code to use the camera:
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (mCamera == null) {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void resetCamera() {
if (!videoReset) {
if (videoStarted && !videoStopped) {
mMediaRecorder.stop();
}
MediaScannerConnection.scanFile(TherapistActivity.this, new String[]{videoFile.getAbsolutePath()}, null, null);
mMediaRecorder.reset();
mMediaRecorder.release();
mCamera.release();
mCamera = null;
mMediaRecorder = null;
videoReset = true;
initSuccess = false;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
surfaceWidth = width;
surfaceHeight = height;
try {
if (!initSuccess)
startPreview(mHolder.getSurface());
} catch (IOException e) {
e.printStackTrace();
}
}
private void initRecorder(Surface surface) throws IOException {
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size previewSize = getOptimalPreviewSize(surfaceWidth, surfaceHeight);
if (previewSize != null) {
parameters.setPreviewSize(previewSize.width, previewSize.height);
}
parameters.setVideoStabilization(false);
mCamera.setParameters(parameters);
mCamera.startPreview();
mCamera.unlock();
if (mMediaRecorder == null) mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setVideoEncodingBitRate(3072 * 1000);
mMediaRecorder.setVideoFrameRate(60);
mMediaRecorder.setVideoSize(1280, 720);
mMediaRecorder.setOutputFile(videoFile.getAbsolutePath());
if (!mApp.videoTime) {
mMediaRecorder.setMaxDuration(30000);
} else {
mMediaRecorder.setMaxDuration(Integer.MAX_VALUE);
}
mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
#Override
public void onInfo(MediaRecorder mr, int what, int extra) {
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
mCameraWrapper.setBackgroundColor(Color.TRANSPARENT);
try {
mCamera.stopPreview();
videoRecorded = true;
} catch (RuntimeException re) {
Log.e("Error", "Could not stop camera!");
} finally {
videoPreviewStarted = false;
}
btRecord.setTag("stop");
btRecord.setBackgroundResource(R.drawable.stop_nobkgrnd_gray);
tvVideoCountdown.setVisibility(View.GONE);
initSuccess = false;
}
}
});
try {
mMediaRecorder.prepare();
videoPreviewStarted = true;
} catch (IllegalStateException e) {
e.printStackTrace();
}
initSuccess = true;
}
}
private Camera.Size getOptimalPreviewSize(int w, int h) {
Camera.Size result = null;
Camera.Parameters p = mCamera.getParameters();
for (Camera.Size size : p.getSupportedPreviewSizes()) {
if (size.width <= w && size.height <= h) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return result;
}
On the Astro Tab A10 running Marshmallow, apparently the Camera isn't being released properly when being run the second time, since the camera fails to open until the device is rebooted. I am pretty sure this isn't a permissions problem, since I granted the app permissions to the camera at runtime as well as including camera permissions in the manifest.
Does anyone know what might be the problem?
EDIT: Here is the stack trace:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mobilityresearch.treadmill3, PID: 4144
java.lang.RuntimeException: Fail to connect to camera service
at android.hardware.Camera.<init>(Camera.java:495)
at android.hardware.Camera.open(Camera.java:341)
at com.mobilityresearch.treadmill3.TherapistActivity.surfaceCreated(TherapistActivity.java:8260)
at android.view.SurfaceView.updateWindow(SurfaceView.java:583)
at android.view.SurfaceView.setVisibility(SurfaceView.java:257)
at com.mobilityresearch.treadmill3.TherapistActivity$26.onClick(TherapistActivity.java:1701)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21153)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:742)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:632)
This doesn't happen on any of our other tablets. In fact, it doesn't happen on the older version of the Astro Tab A10 running Android 5.1 Lollipop. I tried calling resetCamera the camera both in surfaceCreated before opening the preview, and surfacedDestroyed after closing the preview, and it doesn't work.
EDIT 2: I just found out that if I actually record video, it works fine, but if I don't record video and only display the preview, it doesn't work.
EDIT 3: Added surfaceChanged and initRecorder. Updated resetCamera.
You are missing call to stopPreview() which stops capturing and drawing preview frames to the surface and setPreviewDisplay(null) which releases the preview display.
Update your resetCamera() as follows:
private void resetCamera() {
...
mCamera.stopPreview();
mCamera.setPreviewDisplay(null);
mCamera.release();
...
}
}
I have used, FFMPEG & OpenCV for integrating the Video Player into Android Application.
Build Gradle:-
compile('org.bytedeco:javacv-platform:1.4') {
exclude group: 'org.bytedeco.javacpp-presets'
}
compile group: 'org.bytedeco.javacpp-presets', name: 'opencv', version: '3.4.0-1.4'
compile group: 'org.bytedeco.javacpp-presets', name: 'ffmpeg', version: '3.4.1-1.4'
compile files('libs/ffmpeg-android-arm.jar')
compile files('libs/ffmpeg-android-x86.jar')
compile files('libs/opencv-android-arm.jar')
compile files('libs/opencv-android-x86.jar')
I have included 'jniLibs' in the 'main' folder with 'armeabi,amreabi-v7a, x86' folder's.
I am able to open Camera and record the video.
The O/P of the video is not coming as expected, audio quality is fine. Please see the Image below.
The code I used for integration: https://github.com/CrazyOrr/FFmpegRecorder
Thanks in advance!!
I got the workaround using the SurfaceView. Check my Working code.
public class SurfaceViewVideo extends Activity implements MediaPlayer.OnPreparedListener{
private Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;
private int currentCameraId=1;
ImageView myButton,switchCamera;
SurfaceHolder surfaceHolder;
boolean recording;
boolean isVideoStopped;
private MediaPlayer mediaPlayer;
private SurfaceView playSurfaceView;
private SurfaceHolder playSurfaceHolder;
private FrameLayout videoView;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
recording = false;
isVideoStopped = false;
setContentView(R.layout.activity_surface_view_video);
switchCamera = (ImageView)findViewById(R.id.switchCamera);
playSurfaceView = (SurfaceView)findViewById(R.id.playSurface);
playSurfaceHolder = playSurfaceView.getHolder();
videoView = (FrameLayout)findViewById(R.id.videoview);
//Get Camera for preview
myCamera = getCameraInstance();
if(myCamera == null){
Toast.makeText(this,
"Fail to get Camera",
Toast.LENGTH_LONG).show();
}
myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
FrameLayout myCameraPreview = (FrameLayout)findViewById(R.id.videoview);
myCameraPreview.addView(myCameraSurfaceView);
myButton = (ImageView)findViewById(R.id.mybutton);
myButton.setOnClickListener(myButtonOnClickListener);
switchCamera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onCameraChange();
}
});
}
Button.OnClickListener myButtonOnClickListener
= new Button.OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(!isVideoStopped) {
if (recording) {
// stop recording and release camera
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
myButton.setImageResource(R.drawable.ic_play);
isVideoStopped = true;
videoView.setVisibility(View.GONE);
myCameraSurfaceView.setVisibility(View.GONE);
playSurfaceView.setVisibility(View.VISIBLE);
} else {
//Release Camera before MediaRecorder start
releaseCamera();
if (!prepareMediaRecorder()) {
Toast.makeText(SurfaceViewVideo.this,
"Fail in prepareMediaRecorder()!\n - Ended -",
Toast.LENGTH_LONG).show();
}
mediaRecorder.start();
recording = true;
myButton.setImageResource(R.drawable.ic_stop_white_24px);
}
}else{
if(mediaPlayer==null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDisplay(playSurfaceHolder);
mediaPlayer.setDataSource("/sdcard/myvideo.mp4");
mediaPlayer.prepare();
mediaPlayer.setOnPreparedListener(SurfaceViewVideo.this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
} catch (Exception e) {
e.printStackTrace();
}
}else{
mediaPlayer.start();
}
}
}};
private Camera getCameraInstance(){
// TODO Auto-generated method stub
Camera c = null;
try {
c = Camera.open(1); // attempt to get a Camera instance
c.setDisplayOrientation(90);
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
public void onCameraChange() {
myCamera.stopPreview();
myCamera.release();
if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
myCamera = Camera.open(currentCameraId);
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break; //Natural orientation
case Surface.ROTATION_90: degrees = 90; break; //Landscape left
case Surface.ROTATION_180: degrees = 180; break;//Upside down
case Surface.ROTATION_270: degrees = 270; break;//Landscape right
}
int rotate = (info.orientation - degrees + 360) % 360;
//STEP #2: Set the 'rotation' parameter
Camera.Parameters params = myCamera.getParameters();
params.setRotation(rotate);
try {
myCamera.setPreviewDisplay(myCameraSurfaceView.getHolder());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myCamera.setParameters(params);
myCamera.setDisplayOrientation(90);
myCamera.startPreview();
}
private boolean prepareMediaRecorder(){
myCamera = getCameraInstance();
mediaRecorder = new MediaRecorder();
myCamera.unlock();
mediaRecorder.setCamera(myCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
mediaRecorder.setMaxFileSize(5000000); // Set max file size 5M
mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface());
mediaRecorder.setOrientationHint(270);
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
return true;
}
#Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
releaseMediaPlayer();
}
private void releaseMediaRecorder(){
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = null;
myCamera.lock(); // lock camera for later use
}
}
private void releaseCamera(){
if (myCamera != null){
myCamera.release(); // release the camera for other applications
myCamera = null;
}
}
public void releaseMediaPlayer(){
if(mediaPlayer!=null){
mediaPlayer.release();
mediaPlayer = null;
}
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mHolder;
private Camera mCamera;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = myCamera.getParameters().getSupportedPreviewSizes();
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int weight,
int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
So I have a dialogue where I want to show the front and back camera previews sequentially, say after 2 seconds delay. Problem is, I can always set 1 camera view to the frame, how to I change it on the fly, automatically?
Here is where I want to change it on the fly:
public class CameraExample extends AnimatedViewContainer {
private final static String TAG = "CameraExample";
private Camera mCamera;
private CameraPreview mPreview;
private Context mContext;
public CameraExample(Context context, int i) {
super(context, i);
mPreview = null;
mContext = context;
initCamera(mContext);
}
// A safe way to get an instance of the Camera object.
public static Camera getCameraInstance(int cameraId) {
Camera c = null;
try {
// attempt to get a Camera instance
c = Camera.open(cameraId);
} catch (Exception e) {
// Camera is not available (in use or does not exist)
Log.e(TAG, "CameraExample: " + "camera not available (in use or does not exist); " + e.getMessage());
}
return c; // returns null if camera is unavailable
}
private void initCamera(Context context) {
// Check if this device has a camera
if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// no camera on this device
Log.e(TAG, "CameraExample: " + "this device has no camera");
} else {
// this device has a camera
int numCameras = Camera.getNumberOfCameras();
if (numCameras >= 0) {
for (int cameraId = 0; cameraId < numCameras; cameraId++) {
mCamera = getCameraInstance(cameraId);
if (mCamera != null) {
CameraInfo cameraInfo = new CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
try {
//Create our Preview view and set it as the content of this LinearLayout View
mPreview = new CameraPreview(context, mCamera, cameraId);
} catch (RuntimeException e) {
Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
}
}
if (createView() == false) {
break;
}
}
}
}
}
}
#Override
public void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index) {
containerViews[index] = layoutInflater.inflate(R.layout.example_camera, parentGroup, false);
FrameLayout previewFrame = (FrameLayout) containerViews[index].findViewById(R.id.preview);
// Add preview for inflation
previewFrame.addView(mPreview);
}
#Override
public void cleanup() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
The CameraPreview class:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private int mCameraId;
public CameraPreview(Context context, Camera camera, int cameraId) {
super(context);
mContext = context;
mCamera = camera;
mCameraId = cameraId;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.e(TAG, "CameraExample: " + "Error setting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
}
}
I set my view here:
#Override
public void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index) {
containerViews[index] = layoutInflater.inflate(R.layout.example_camera, parentGroup, false);
FrameLayout previewFrame = (FrameLayout) containerViews[index].findViewById(R.id.preview);
previewFrame.addView(mPreview);
}
Problem is, I don't see how I can have 2 instances of the 2 different cameras that a device generally has and change them automatically after certain seconds so that my frame displays the front and back camera preview one after other after every certain amount of seconds. Any solution is highly appreciated! I think I have to handle it in the surfaceChanged() method, but I really don't know how!
As asked, here is the, AnimatedViewContainer class:
public abstract class AnimatedViewContainer extends Example {
Context mContext;
int mAnimationDuration;
int mAnimationDurationShort;
LayoutInflater mLayoutInflater;
ViewGroup mParentGroup;
View[] mContainerViews;
boolean hasBeenClicked = false;
int mCurrentIndex;
int mMaxNumItems;
int mIndexVisibleItem;
public AnimatedViewContainer(Context context, int maxNumItems) {
super(context);
mContext = context;
mMaxNumItems = maxNumItems;
mContainerViews = new View[mMaxNumItems];
// Retrieve and cache the system's default "medium" animation time
mAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
// and "short"
mAnimationDurationShort = getResources().getInteger(android.R.integer.config_shortAnimTime);
mCurrentIndex = 0;
mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//TODO: shouldn't be null, should be any ViewGroup with the right LayoutParams
mParentGroup = null;
}
public abstract void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index);
public boolean createView() {
if (mCurrentIndex >= mMaxNumItems) {
return false; // indicates to terminate the loop
}
// handle/execute the concrete definition of the view content defined by the child class
onCreateViewContent(mLayoutInflater, mParentGroup, mContainerViews, mCurrentIndex);
// only the first container view should be visible
if (mCurrentIndex == 0) {
mContainerViews[mCurrentIndex].setVisibility(View.VISIBLE);
mIndexVisibleItem = mCurrentIndex;
} else {
mContainerViews[mCurrentIndex].setVisibility(View.GONE);
}
// if you click on the container view, show next container view with a crossfade animation
mContainerViews[mCurrentIndex].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
crossfade(true);
hasBeenClicked = true;
}
});
// add the container view to the FrameLayout
addView(mContainerViews[mCurrentIndex]);
mCurrentIndex++;
return true;
}
public void crossfade(boolean manuallyClicked) {
//only rotate when example is actually shown and at least one content item was created. This may also prevent NPEs due to incompletely loaded views.
if(!this.isShown() || mCurrentIndex == 0)
return;
//when example was previously clicked, don't do anything
if(!manuallyClicked && hasBeenClicked){
hasBeenClicked = false;
return;
}
int numTotalItems = mCurrentIndex;
final int indexVisibleItem = mIndexVisibleItem;
int nextIndex = indexVisibleItem + 1;
if (nextIndex >= numTotalItems) {
nextIndex = 0;
}
final boolean hasOnlyOneItem;
if (numTotalItems == 1) {
hasOnlyOneItem = true;
} else {
hasOnlyOneItem = false;
}
if (hasOnlyOneItem) { //there is only one item in the mContainerViews
mContainerViews[indexVisibleItem].animate().alpha(0.5f).setDuration(mAnimationDurationShort).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mContainerViews[indexVisibleItem].animate().alpha(1f).setDuration(mAnimationDurationShort).setListener(null);
}
});
} else {
// Set the next view to 0% opacity but visible, so that it is visible (but fully transparent) during the animation.
mContainerViews[nextIndex].setAlpha(0f);
mContainerViews[nextIndex].setVisibility(View.VISIBLE);
// Animate the next view to 100% opacity, and clear any animation
// listener set on the view.
mContainerViews[nextIndex].animate().alpha(1f).setDuration(mAnimationDuration).setListener(null);
// Animate the current view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't participate in layout passes, etc.)
mContainerViews[indexVisibleItem].animate().alpha(0f).setDuration(mAnimationDuration).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mContainerViews[indexVisibleItem].setVisibility(View.GONE);
}
});
}
mIndexVisibleItem = nextIndex;
}
#Override
public void cleanup() {
}
}
I could find a solution to change camera in some seconds(But keep in mind as Alex Cohn said you can't change the camera in 2 seconds because, normally it takes more than 2 seconds to start preview and it depends on the device) by changing your code a little bit. please use below code and check.
Note: I have not implemented any orientation changes and taking picture functions, I Hope you have already developed those functions, in fact you have only asked for changing the camera automatically in some seconds.
I used dialog fragment to show the preview in a dialog. Here is the code for CameraExample
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
/**
* Created by Admin on 6/26/2017.
*/
public class CameraExample extends DialogFragment {
private final static String TAG = "CameraExample";
private Camera mCamera;
private CameraPreview mPreview;
private Context mContext;
private View view;
private int mCamId = 0;
public CameraExample() {
mPreview = null;
mContext = getContext();
}
// A safe way to get an instance of the Camera object.
public static Camera getCameraInstance(int cameraId) {
Camera c = null;
try {
// attempt to get a Camera instance
c = Camera.open(cameraId);
} catch (Exception e) {
// Camera is not available (in use or does not exist)
Log.e(TAG, "CameraExample: " + "camera not available (in use or does not exist); " + e.getMessage());
}
return c; // returns null if camera is unavailable
}
private void initCamera(Context context, int cameraId) {
// Check if this device has a camera
if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// no camera on this device
Log.e(TAG, "CameraExample: " + "this device has no camera");
} else {
// this device has a camera
int numCameras = Camera.getNumberOfCameras();
if (numCameras >= 0) {
mCamera = getCameraInstance(cameraId);
if (mCamera != null) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
try {
//Create our Preview view and set it as the content of this LinearLayout View
mPreview = new CameraPreview(context, mCamera, cameraId);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mPreview.setLayoutParams(layoutParams);
} catch (RuntimeException e) {
Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
}
}
}
}
}
private CountDownTimer countDownTimer;
private void switchCam() {
//10 seconds
countDownTimer = new CountDownTimer(10000, 1000) {
#Override
public void onTick(long l) {
System.out.println(l + " left");
}
#Override
public void onFinish() {
cleanup();
startCam();
}
}.start();
}
private void startCam() {
initCamera(getContext(), mCamId);
FrameLayout previewFrame = (FrameLayout) view.findViewById(R.id.preview);
previewFrame.removeAllViews();
// Add preview for inflation
previewFrame.addView(mPreview);
mCamId = mCamId == 0 ? 1 : 0;
switchCam();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
getDialog().getWindow().setGravity(Gravity.CENTER);
// getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);
view = inflater.inflate(R.layout.camera_fragment, container, false);
startCam();
return view;
}
#Override
public void onPause() {
super.onPause();
cleanup();
if (countDownTimer != null)
countDownTimer.cancel();
}
#Override
public void onStart() {
super.onStart();
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
public void cleanup() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
And also I had to change your preview class also. See below for the code.
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
/**
* Created by Admin on 6/26/2017.
*/
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private int mCameraId;
public CameraPreview(Context context, Camera camera, int cameraId) {
super(context);
mContext = context;
mCamera = camera;
mCameraId = cameraId;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.e(TAG, "CameraExample: " + "Error setting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
}
}
There is a double init bug in your class. I could have it running and see the camera switch from 0 to 1 and back, after 10 sec, after the following fix:
I removed call to initCamera() from the CameraExample constructor. Instead, I put there call to CreateView(). Alternatively, you can call CreateView(), which is a public method, from the place where you create new CameraExample(context, i).
Note that this refers to the code in dropbox, not what is posted in the question.
You have to stop the camera, switch the facing and then start it again:
Use a timer and call switchFacing() periodically every 2 seconds.
But be aware of:
This class was deprecated in API level 21.
We recommend using the new android.hardware.camera2 API for new
applications.
edit2: Here is the complete class ready to use.
//This class uses Camera1 API to be backwards compatible.
private static String TAG = "CameraManager";
private Context mContext = null;
private SurfaceView mPreview = null;
private SurfaceHolder mHolder = null;
private Camera mCamera = null;
private int mFrontFaceID = -1;
private int mBackFaceID = -1;
private int mActualFacingID = -1;
public CameraManager(Context context, SurfaceView preview) {
mContext = context;
mPreview = preview;
mHolder = mPreview.getHolder();
mHolder.addCallback(this);
}
//called in onCreate
public void init() {
Camera.CameraInfo info = new Camera.CameraInfo();
for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
mFrontFaceID = i;
}
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
mBackFaceID = i;
}
}
if (mActualFacingID == -1) {
if (mFrontFaceID != -1) {
mActualFacingID = mFrontFaceID;
} else {
mActualFacingID = mBackFaceID;
}
}
//At least one one camera will be available because of manifest declaration
}
//called first on surface created
public void start() {
Log.i(TAG, "startCamera()");
if (mCamera == null) {
mCamera = getCameraInstance(mActualFacingID);
}
if (mCamera == null) {
Log.i(TAG, "can't get camera instance");
return;
}
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
setCameraDisplayOrientation();
setBestSupportedSizes();
mCamera.startPreview();
}
public void stop() {
Log.i(TAG, "stopCamera()");
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
public void switchFacing() {
if (mFrontFaceID == -1 || mBackFaceID == -1) {
return;
}
stop();
if (mActualFacingID == mFrontFaceID) {
mActualFacingID = mBackFaceID;
} else {
mActualFacingID = mFrontFaceID;
}
start();
}
public Camera getCameraInstance(int cameraID) {
Camera c = null;
if (cameraID != -1) {
try {
c = Camera.open(cameraID);
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "error opening camera: " + cameraID);
}
}
return c;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated()");
start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged()");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed()");
stop();
}
private void setBestSupportedSizes() {
if (mCamera == null) {
return;
}
Camera.Parameters parameters = mCamera.getParameters();
List<Point> pictureSizes=getSortedSizes(parameters.getSupportedPictureSizes());
List<Point> previewSizes=getSortedSizes(parameters.getSupportedPreviewSizes());
Point previewResult=null;
for (Point size:previewSizes){
float ratio = (float) size.y / size.x;
if(Math.abs(ratio-4/(float)3)<0.05){ //Aspect ratio of 4/3 because otherwise the image scales to much.
previewResult=size;
break;
}
}
Log.i(TAG,"preview: "+previewResult.x+"x"+previewResult.y);
Point pictureResult=null;
if(previewResult!=null){
float previewRatio=(float)previewResult.y/previewResult.x;
for (Point size:pictureSizes){
float ratio = (float) size.y / size.x;
if(Math.abs(previewRatio-ratio)<0.05){
pictureResult=size;
break;
}
}
}
Log.i(TAG,"preview: "+pictureResult.x+"x"+pictureResult.y);
if(previewResult!=null && pictureResult!=null){
Log.i(TAG,"best preview: "+previewResult.x+"x"+previewResult.y);
Log.i(TAG, "best picture: " + pictureResult.x + "x" + pictureResult.y);
parameters.setPreviewSize(previewResult.y, previewResult.x);
parameters.setPictureSize(pictureResult.y, pictureResult.x);
mCamera.setParameters(parameters);
mPreview.setBackgroundColor(Color.TRANSPARENT); //in the case of errors needed
}else{
mCamera.stopPreview();
mPreview.setBackgroundColor(Color.BLACK);
}
}
private List<Point> getSortedSizes(List<Camera.Size> sizes) {
ArrayList<Point> list = new ArrayList<>();
for (Camera.Size size : sizes) {
int height;
int width;
if (size.width > size.height) {
height = size.width;
width = size.height;
} else {
height = size.height;
width = size.width;
}
list.add(new Point(width, height));
}
Collections.sort(list, new Comparator<Point>() {
#Override
public int compare(Point lhs, Point rhs) {
long lhsCount = lhs.x * (long) lhs.y;
long rhsCount = rhs.x * (long) rhs.y;
if (lhsCount < rhsCount) {
return 1;
}
if (lhsCount > rhsCount) {
return -1;
}
return 0;
}
});
return list;
}
//TAKE PICTURE
public void takePhoto() {
if (mCamera != null) {
mCamera.takePicture(null, null, this);
}
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
//do something with your picture
}
//ROTATION
private void setCameraDisplayOrientation() {
if (mCamera != null) {
mCamera.setDisplayOrientation(getRotation());
}
}
public int getRotation() {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(mActualFacingID, info);
int rotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
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;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
In some class call:
SurfaceView preview = (SurfaceView) findViewById(R.id.surfaceView);
CameraManager mgr = new CameraManager(MainActivity.this, MainActivity.this, preview);
mgr.init();
...
mgr.takePhoto(); //surface must already be created
mgr.switchFacing();
mgr.takePhoto();
This code should support almost all devices. The most supported aspect ratio is 4:3, the code takes care of that.
edit3: The surface view must be in the xml of course
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/surfaceView" />
There is no way to switch the camera quickly. The time it takes to stop the camera, close it, open another camera, and start preview depends on the device, but in many cases (and sometimes on powerful modern devices) it will be more than 2 seconds that you put as your goal.
On the other hand, some Android devices support simultaneous operation of two cameras, see Is it possible to use front and back Camera at same time in Android and Android, Open Front and Back Cameras Simultaneously. So, on some Snapdragon 801 based devices, you can keep both cameras 'ready' and switch the video flow up to 30 times per second.
i think You should use this
mCamera= Camera.open(cameraId);
0 for CAMERA_FACING_BACK
1 for CAMERA_FACING_FRONT
for more reference flow this:-
https://developer.android.com/reference/android/hardware/Camera.html#open(int)
https://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#CAMERA_FACING_BACK
We can use threads to keep one camera active and let it stay for certain time. Swap camera and repaeat the same for infinite time.
private boolean isActive;
public void onStart(){
super.onStart();
isActive = true;
continuousCameraChange(your_camera)
}
public void onResume(){
super.onResume();
isActive = true;
continuousCameraChange(your_camera)
}
public void onPause(){
super.onPause();
isActive = false;
}
public void onDestroy(){
super.onDestroy();
isActive = false;
}
public void onStop(){
super.onStop();
isActive = false;
}
private void continuousCameraChange(Camera camera){
do{
switchCamera(camera);
}while(isActive);
}
private void switchCamera(Camera camera){
if (Camera.CameraInfo.facing == CAMERA_FACING_BACK){
try{
Thread.sleep(2000);
camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
}catch(InterruptedException ex){
Thread.currentThread().interrupt();
}
//change your camera
Camera.CameraInfo.facing == CAMERA_FACING_FRONT;
}else{
try{//change 2000 to change the time for which your camera stays available
Thread.sleep(2000);
camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
}catch(InterruptedException ex){
Thread.currentThread().interrupt();
}
//change your camera
Camera.CameraInfo.facing == CAMERA_FACING_BACK;
}
}
I guess this is what you are looking for:
ImageButton useOtherCamera = (ImageButton) findViewById(R.id.useOtherCamera);
//if phone has only one camera, hide "switch camera" button
if(Camera.getNumberOfCameras() == 1){
useOtherCamera.setVisibility(View.INVISIBLE);
}
else {
useOtherCamera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (inPreview) {
camera.stopPreview();
}
//NB: if you don't release the current camera before switching, you app will crash
camera.release();
//swap the id of the camera to be used
if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
camera = Camera.open(currentCameraId);
//Code snippet for this method from somewhere on android developers, i forget where
setCameraDisplayOrientation(CameraActivity.this, currentCameraId, camera);
try {
//this step is critical or preview on new camera will no know where to render to
camera.setPreviewDisplay(previewHolder);
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
}
This is a sample code where I am switching between front and back camera on the fly. Hope it will help.
I am creating a camera app but I have problems on startPreview, it sends me:
java.lang.RuntimeException: startPreview failed
here is my camera Activity:
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
private Target_Frame targetFrame;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_layout);
mCamera=getCameraInstance();
mPreview=new CameraPreview(this, mCamera);
FrameLayout preview=(FrameLayout)findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
/** Check if this device has a camera only if not specified in the manifest */
public boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
/**Check if the device has flash*/
public boolean checkFlash(Context context){
if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)){
//the device has flash
return true;
}else{
//no flash
return false;
}
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
releaseCamera();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
releaseCamera();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
//Test if i have to put all this code like in onCreate
if(mCamera!=null){
return;
}
mCamera=getCameraInstance();
if(mPreview!=null){
return;
}
mPreview=new CameraPreview(this, mCamera);
FrameLayout preview=(FrameLayout)findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}}
And here is my SurfaceView code:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
Parameters parameters= mCamera.getParameters();
parameters.setPreviewSize(w, h);
mCamera.setParameters(parameters);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
And here is my error log:
12-01 13:17:01.135: E/AndroidRuntime(1161): FATAL EXCEPTION: main
12-01 13:17:01.135: E/AndroidRuntime(1161): java.lang.RuntimeException: startPreview
12-01 13:17:01.135: E/AndroidRuntime(1161): at com.example.prueba.CameraPreview.surfaceCreated(CameraPreview.java:36)
I have solved deleting some lines in surfaceChanged
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
Log.d("Function", "surfaceChanged iniciado");
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
So the error must be in i one of these lines:
Parameters parameters= mCamera.getParameters();
parameters.setPreviewSize(w, h);
mCamera.setParameters(parameters);
Someone could explain me what was wrong in those lines?
Is (w, h) a valid preview size for your camera?
You can use mCamera.getParameters().getSupportedPreviewSizes() to get all of the valid preview sizes.
Its late, but if someones looking for the answer
The variables w and h are not the optimal preview sizes . You can get optimal preview sizes using the function
public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
and you can call the function using
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
..
size=getOptimalPreviewSize(parameters.getSupportedPreviewSizes(), w, h);
parameters.setPreviewSize(size.getWidth(), size.getHeight());
..
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.getParameters().getSupportedPreviewSizes();
mCamera.startPreview();
Log.d(TAG, "Camera preview started.");
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
I had this error, and it's because I didn't call releaseCamera on the onPause the first time I start my app.
After a reboot, everything works fine ^^
I worked with VIDEO ONLY. No pictures.
Noticed, that setDisplayOrientation does affect right display orientation only during preview.
But if to play any video captured either in landscape mode or portrait mode it is always in landscape mode.
I set in AndroidManifest.xml
But used to debug in 4.0.1 device. Maybe that is a problem.
However i noticed that default camera app works fine and capture portrait movies in portrait mode.
What do I miss?...
**CameraRecorder.java
public class CameraRecorder extends Activity {
private CameraPreview mPreview;
private Camera mCamera;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_surface);
// Create an instance of Camera
mCamera = getCameraInstance();
if (mCamera == null) {
Log.e(TAG, "Camera is not available");
finish();
}
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
mPreview.setOnClickListener(startStopListener);
}
private void changeOrientation(int what) {
if (what != orientation) {
setRequestedOrientation(orientation = what);
}
}
OnClickListener startStopListener = new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (isRecording) {
mMediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
mCamera.lock(); // take camera access back from MediaRecorder
// inform the user that recording has stopped
setCaptureButtonText("Capture");
isRecording = false;
} else {
// initialize video camera
if (prepareVideoRecorder()) {
// Camera is available and unlocked, MediaRecorder is
// prepared, now you can start recording
mMediaRecorder.start();
// inform the user that recording has started
isRecording = true;
} else {
// prepare didn't work, release the camera
releaseMediaRecorder();
}
}
}
};
File tempFile;
#Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
} catch (Exception e) {
// Camera is not available (in use or does not exist)
Log.d(TAG, "Fail to connect to camera service. Is it locked?");
}
}
return c; // returns null if camera is unavailable
}
private boolean prepareVideoRecorder() {
if (mCamera == null)
mCamera = getCameraInstance();
if (mMediaRecorder == null)
mMediaRecorder = new MediaRecorder();
Camera.Parameters p = mCamera.getParameters();
// Step 1: Unlock and set camera to MediaRecorder
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
// Step 2: Set sources
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
CamcorderProfile profile = mPreview.getProfile();// CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
Size previewSize = mPreview.getPreviewSize();
if (previewSize != null) {
profile.videoFrameWidth = previewSize.width;
profile.videoFrameHeight = previewSize.height;
}
mMediaRecorder.setProfile(profile);
// Step 4: Set output file
mMediaRecorder.setOutputFile(MediaFile.getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
// Step 5: Set the preview output
mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
// Step 6: Prepare configured MediaRecorder
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
return true;
}
private void releaseMediaRecorder() {
if (mMediaRecorder != null) {
mMediaRecorder.reset(); // clear recorder configuration
mMediaRecorder.release(); // release the recorder object
mMediaRecorder = null;
mCamera.lock(); // lock camera for later use
}
}
private void releaseCamera() {
if (mPreview != null) {
mPreview.surfaceDestroyed(null);
}
if (mCamera != null) {
mCamera.release(); // release the camera for other applications
mCamera = null;
Log.d(TAG, "Camera released");
}
}
}
CameraPreview.java
/** A basic Camera preview class */
public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private SurfaceView mSurfaceView;
private Context mContext;
private final String TAG = "CameraPreview";
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
setCamera(mCamera);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView, 0);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mHolder.setKeepScreenOn(true);
}
public SurfaceHolder getHolder() {
return mSurfaceView.getHolder();
}
private Size mPreviewSize;
private List<Size> mSupportedPreviewSizes;
private List<String> mSupportedFlashModes;
public Camera getCamera() {
return mCamera;
}
private CamcorderProfile mProfile;
public CamcorderProfile getProfile() {
return mProfile;
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
mCamera.setParameters(parameters);
}
}
requestLayout();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
// mCamera.startPreview();
}
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, mProfile.videoFrameWidth, mProfile.videoFrameHeight);
}
setMeasuredDimension(width, height);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed) {
final View cameraView = getChildAt(0);
final int width = right - left;
final int height = bottom - top;
Camera.Parameters p = mCamera.getParameters();
#SuppressWarnings("unused")
int previewWidth = width;
#SuppressWarnings("unused")
int previewHeight = height;
if (mPreviewSize != null) {
Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation()) {
case Surface.ROTATION_0:
mCamera.setDisplayOrientation(90);
break;
case Surface.ROTATION_90:
case Surface.ROTATION_180:
break;
case Surface.ROTATION_270:
mCamera.setDisplayOrientation(180);
break;
}
}
cameraView.layout(0, 0, width, height);
}
}
public void setSupportedPreviewSizes(List<Size> supportedPreviewSizes) {
mSupportedPreviewSizes = supportedPreviewSizes;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
// Because the CameraDevice object is not a shared resource, it's very
// important to release it when the activity is paused.
try {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
// mCamera.release();
mCamera = null;
Log.d(TAG, "Preview destroyed");
}
} catch (Exception e) {
Log.e(TAG, "Camera release failure.");
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
Camera.Parameters parameters = mCamera.getParameters();
Size previewSize = getPreviewSize();
if (previewSize != null)
parameters.setPreviewSize(previewSize.width, previewSize.height);
mCamera.setParameters(parameters);
// start preview with new settings
try {
previewCamera();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
public Size getPreviewSize() {
return mPreviewSize;
}
public static Size getOptimalPreviewSize(List<Size> sizes, int width, int height) {
double aspectTolerance = 0.05;
double targetRatio = (double) width / height;
if (sizes == null) {
return null;
}
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = height;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > aspectTolerance)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public void previewCamera() {
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Cannot start preview.", e);
}
}
}
Manifest.xml
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:name=".client.andi"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".activity.CameraRecorder"
android:label="#string/title_activity_main"
android:screenOrientation="landscape"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
** layout.xml**
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="bottom"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
</FrameLayout>
</RelativeLayout>
You should change android:screenOrientation="landscape" into android:screenOrientation="portrait"
Not sure if you encounter exactly the same problem with mine.
I've stuck with this problem before, too. I found that you can use the function setOrientationHint (API 9). Call this function before you call MediaRecorder.prepare(). You can setup the orientation degree for your output video.
Hope it helps, good luck!