我正在尝试在Android中以正确的方向录制视频。我已经构建了我的Activity,它工作正常,唯一的事情是录制后保存的视频是旋转的。相机预览正常,所以我无法理解原因。要修复轮播,我使用此代码(我在Google Developers上找到的方法):
mMediaRecorder.setOrientationHint(getCameraDisplayOrientation());
private int getCameraDisplayOrientation()
{
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(CameraInfo.CAMERA_FACING_BACK,
info);
int rotation = getWindowManager().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;
活动在清单中定义如下:
<activity android:name="pages.CameraPage"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:screenOrientation="landscape"
>
</activity>
问题是getCameraDisplayOrientation总是返回0度,无论我如何定位屏幕。
我在记录开始之前调用该方法,所以如果我能够根据默认格局获得屏幕旋转,我就可以了。
感谢您的帮助!
答案 0 :(得分:2)
最后,我能够成功构建自己的相机应用,没有任何方向问题。关键是看着surfaceView进行旋转。我认为这可能有助于将所有代码发布在此处,只需复制并启动活动!
CameraPage.java
package pages;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import model.CameraView;
import com.controller.R;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.Toast;
public class CameraPage extends Activity
{
private Camera mCamera;
private CameraView mPreview;
private MediaRecorder mMediaRecorder;
private FrameLayout preview;
private ImageButton buttonRecordStop;
private boolean isRecording = false;
private String fileName;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d("CameraPage-onCreate", "Called onCreate()");
setContentView(R.layout.camera_surface);
buttonRecordStop = (ImageButton) findViewById(R.id.camera_surface_buttonRecordStop);
buttonRecordStop.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_MOVE)
{
AlphaAnimation alpha = new AlphaAnimation(1.0F, 0.3F);
alpha.setDuration(100);
alpha.setFillAfter(true); // Tell it to persist after the animation ends
buttonRecordStop.startAnimation(alpha);
} else if (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL)
{
AlphaAnimation alpha = new AlphaAnimation(0.3F, 1.0F);
alpha.setDuration(100);
alpha.setFillAfter(true); // Tell it to persist after the animation ends
buttonRecordStop.startAnimation(alpha);
}
return false;
}
});
buttonRecordStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
if (!isRecording)
{
Log.d("CameraPage-buttonRecordStop-onClick", "Start Record");
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// initialize video camera
if (prepareVideoRecorder())
{
v.setVisibility(View.GONE);
((ImageButton) v)
.setImageResource(R.drawable.iconapause);
v.setVisibility(View.VISIBLE);
isRecording = true;
// Camera is available and unlocked, MediaRecorder is prepared,
// now you can start recording
mMediaRecorder.start();
} else
{
// prepare didn't work, release the camera
releaseMediaRecorder();
// inform user
}
} else
{
Log.d("CameraPage-buttonRecordStop-onClick", "Stop Record");
getWindow().clearFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
v.setVisibility(View.GONE);
((ImageButton) v).setImageResource(R.drawable.iconarecord);
v.setVisibility(View.VISIBLE);
isRecording = false;
stopRecording();
sendBroadcast(new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
}
}// end onClick
});
mCamera = getCameraInstance();
preview = (FrameLayout) findViewById(R.id.camera_preview);
}// end onCreate
@Override
protected void onResume()
{
super.onResume();
Log.d("CameraPage-onResume",
"Chiamato onResume ripristino le risorse se necessario");
if (mCamera == null)
{
// Create an instance of Camera
mCamera = getCameraInstance();
}
if (mPreview == null)
{
mPreview = new CameraView(getApplicationContext(), mCamera, this);
preview.addView(mPreview);
}
}
@Override
protected void onPause()
{
super.onPause();
Log.d("CameraPage-onPause", "Vado in onPause e rilascio le risorse");
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
preview.removeView(mPreview);
mPreview = null;
}
private void stopRecording()
{
mMediaRecorder.stop();
releaseMediaRecorder();
// Restarto la preview della camera
mCamera.startPreview();
// mCamera.lock();
}
private boolean prepareVideoRecorder()
{
// mCamera = getCameraInstance();
mMediaRecorder = new MediaRecorder();
// Stop preview because I have to start the preview for the video
mCamera.stopPreview();
// 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)
mMediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_HIGH));
// Step 4: Set output file
setOutputFile();
mMediaRecorder.setOutputFile(getOutputFile());
// Step 5: Set the preview output
mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
mMediaRecorder.setOrientationHint(CameraPage
.getCameraDisplayOrientation(this,
Camera.CameraInfo.CAMERA_FACING_BACK, mCamera));
// Step 6: Prepare configured MediaRecorder
try
{
mMediaRecorder.prepare();
} catch (IllegalStateException e)
{
Log.d("CameraPage-prepareVideoRecorder",
"IllegalStateException preparing MediaRecorder: "
+ e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e)
{
Log.d("CameraPage-prepareVideoRecorder",
"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 (mCamera != null)
{
mCamera.release(); // release the camera for other applications
mCamera = null;
}
if (mPreview != null)
mPreview.getHolder().removeCallback(mPreview);
}
/** A safe way to get an instance of the Camera object. */
private Camera getCameraInstance()
{
Camera c = null;
try
{
Log.d("CameraPage-getCameraInstance", "Prendo istanza camera");
c = Camera.open(); // attempt to get a Camera instance
} catch (Exception e)
{
// Camera is not available (in use or does not exist)
Log.d("CameraPage-getCameraInstance",
"Eccezione durante retrieve istanza camera " + e);
}
return c; // returns null if camera is unavailable
}
@SuppressLint("SimpleDateFormat")
private void setOutputFile()
{
String folderPath = Environment.getExternalStorageDirectory().getPath();
File vims = new File(folderPath + "/ViMS");
if (!vims.exists())
vims.mkdir();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd---HH-mm-ss");
Date date = new Date();
String timestamp = "/" + dateFormat.format(date) + ".mp4";
Log.d("CameraPage-getOutputFile", Environment
.getExternalStorageDirectory().getPath());
fileName = vims.getPath() + timestamp;
}
private String getOutputFile()
{
return fileName;
}
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera)
{
int result = CameraPage.getCameraDisplayOrientation(activity, cameraId,
camera);
if (android.os.Build.VERSION.SDK_INT <= 14)
{
camera.stopPreview();
camera.setDisplayOrientation(result);
camera.startPreview();
} else
{
camera.setDisplayOrientation(result);
}
}// end setCameraDisplayOrientation
public static int getCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera)
{
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().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;
}
@Override
public void onDestroy()
{
super.onDestroy();
Log.d("CameraPage-onDestroy", "Called onDestroy");
}
}// end CameraPage
CameraView.java
package model;
import java.io.IOException;
import pages.CameraPage;
import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/** A basic Camera preview class */
public class CameraView extends SurfaceView implements SurfaceHolder.Callback
{
private SurfaceHolder mHolder;
private Camera mCamera;
private Activity activity;
public CameraView(Context context)
{
super(context);
Log.d("CameraView-default constructor",
"Chiamato uno dei due default constructors");
}
public CameraView(Context context, AttributeSet attrs)
{
super(context, attrs);
Log.d("CameraView-default constructor",
"Chiamato uno dei due default constructors");
}
public CameraView(Context context, Camera camera, Activity activity)
{
super(context);
Log.d("CameraView-constructor",
"Inizializzo la classe con la camera e il context");
this.activity = activity;
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)
{
Log.d("CameraView-surfaceCreated",
"La superfice è stata creata, setto la preview della camera sulla superficie");
// 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("CameraView-surfaceCreated", "Error setting camera preview: "
+ e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder)
{
Log.d("CameraView-surfaceDestroyed",
"Distrutta superficie della preview");
// Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
{
Log.d("CameraView-surfaceChanged",
"Gestisco i cambiamenti nella superficie che ospita la camera");
// 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
Log.d("CameraView-surfaceChanged", "Preview surface doesn't exist");
return;
}
try
{
CameraPage.setCameraDisplayOrientation(activity,
Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
} catch (Exception e)
{
Log.d("CameraView-surfaceChanged",
"Exception reorienting the camera " + e);
}
}// end surfaceChanged
}// end CameraView
camera_surface.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</FrameLayout>
<ImageButton
android:id="@+id/camera_surface_buttonRecordStop"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:adjustViewBounds="true"
android:background="@null"
android:contentDescription="@string/action"
android:scaleType="fitCenter"
android:src="@drawable/iconarecord" />
</RelativeLayout>
活动已经过Android 2.3.6到4.3的测试。如果您发现任何问题或有任何建议,请告诉我们!
答案 1 :(得分:0)
如果您的问题与轮换变量相关联,您可以考虑查看this link。离开该链接的主要区别是创建了WindowManager
对象,然后用于获取旋转。这个看似很小的差异是我的代码工作和不工作之间的差异。
您可以简单地说Camera.CameraInfo info = new Camera.CameraInfo();
和Camera.getCameraInfo(...);
。
我很好奇您在CameraInfo.CAMERA_FACING_BACK
中指定android.hardware.Camera.getCameraInfo(CameraInfo.CAMERA_FACING_BACK, info);
的原因我觉得您可以致电info.facing
来取代int
。
我希望在链接和我的建议/查询之间找到正确的答案!