我使用以下代码录制视频,并且录制完美,但是当播放视频时,它会上下颠倒。
我在mrec.setOrientationHint(180)
之前尝试了设置mrec.prepare();
,但它没用。任何提示?
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Activity;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
/**
* @author SANA HASSAN
*/
public class CameraSurfaceView extends Activity {
private Preview mPreview;
private MediaRecorder mrec = new MediaRecorder();
private int cameraId = 0;
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mPreview = new Preview(this);
setContentView(mPreview);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 0, 0, "Start");
menu.add(0, 1, 0, "Stop");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 0:
try {
startRecording();
}
catch (Exception e) {
e.printStackTrace();
mrec.release();
}
break;
case 1:
mrec.stop();
mrec.release();
mrec = null;
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
protected void startRecording() throws IOException {
mrec = new MediaRecorder();
mrec.setCamera(mCamera);
mCamera.unlock();
File directory = new File(Environment.getExternalStorageDirectory()+"/NICUVideos");
directory.mkdirs();
mrec.setAudioSource( MediaRecorder.AudioSource.MIC);
mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mrec.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mrec.setOutputFile(Environment.getExternalStorageDirectory()+"/NICUVideos/"+System.currentTimeMillis()+".mp4");
mrec.setPreviewDisplay(mPreview.getHolder().getSurface());
mrec.setVideoSize(640, 480);
Method[] methods = mrec.getClass().getMethods();
for (Method method: methods){
try{
if(method.getName().equals("setAudioEncodingBitRate")){
method.invoke(mrec, 12200);
}
else if(method.getName().equals("setVideoEncodingBitRate")){
method.invoke(mrec, 800000);
}
else if(method.getName().equals("setAudioSamplingRate")){
method.invoke(mrec, 8000);
}
else if(method.getName().equals("setVideoFrameRate")){
method.invoke(mrec, 20);
}
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
}
mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mrec.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mrec.setMaxDuration(60000); // 60 seconds
mrec.setMaxFileSize(10000000); // Approximately 10 megabytes
mrec.prepare();
mrec.start();
}
protected void stopRecording() {
mrec.stop();
mrec.release();
mCamera.release();
}
class Preview extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder mHolder;
Activity activity;
Preview(Activity activity) {
super(activity);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
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) {
mCamera=Camera.open(i);
cameraId = i;
}
}
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
setCameraDisplayOrientation(mCamera);
mCamera.startPreview();
}
public void setCameraDisplayOrientation(Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = CameraSurfaceView.this.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;
}
Log.d(Vars.TAG, "Result = "+result);
camera.setDisplayOrientation(result);
}
}
}
答案 0 :(得分:15)
这个问题是由于Android通过设置一些元数据而不是实际旋转视频来处理轮换,而某些播放软件则忽略了该设置。
如the docs中所述:
请注意,某些视频播放器可能会在播放过程中选择忽略视频中的构图矩阵。
您可以选择使用能够理解所设置元数据的不同播放软件,或者在将视频录制到正确方向后重新编码视频。从您的描述中不清楚哪些是您的情况下更好的解决方案。
答案 1 :(得分:7)
这应该在mrec.prepare();
方法之前调用
setOrientationHint(degrees);
编辑:
试试mCamera.setDisplayOrientation(degrees);
0 for landscape
90 for portrait
180 & 270 don't work very well and give weird results.
一些较老的播放器和编码器不会解释此标志,这就是视频颠倒的原因。
答案 2 :(得分:2)
我有同样的问题,我注意到相机预览方向角和录制视频角度不一样。 所以我使用这种方法来改变视频录制的方向:
public static int getVideoOrientationAngle(Activity activity, int cameraId) { //The param cameraId is the number of the camera.
int angle;
Display display = activity.getWindowManager().getDefaultDisplay();
int degrees = display.getRotation();
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
switch (degrees) {
case Surface.ROTATION_0:
angle = 90;
break;
case Surface.ROTATION_90:
angle = 0;
break;
case Surface.ROTATION_180:
angle = 270;
break;
case Surface.ROTATION_270:
angle = 180;
break;
default:
angle = 90;
break;
}
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
angle = (angle + 180) % 360;
return angle;
}
对于相机预览的更改方向:
public static int setCameraDisplayOrientation(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;
}
camera.setDisplayOrientation(result);
return result;
}
请注意,了解相机是正面还是背面非常重要。
答案 3 :(得分:1)
我知道你的问题,
来自Media Recorder
的视频使用Camera
,因此您需要rotate Media Recorder
。使用以下代码应解决您的问题。
/**
*
* @param mMediaRecorder
* @return
*/
public static MediaRecorder rotateBackVideo(MediaRecorder mMediaRecorder) {
/**
* Define Orientation of video in here,
* if in portrait mode, use value = 90,
* if in landscape mode, use value = 0
*/
switch (CustomCamera.current_orientation) {
case 0:
mMediaRecorder.setOrientationHint(90);
break;
case 90:
mMediaRecorder.setOrientationHint(180);
break;
case 180:
mMediaRecorder.setOrientationHint(270);
break;
case 270:
mMediaRecorder.setOrientationHint(0);
break;
}
return mMediaRecorder;
}
应在prepare()
方法之前添加:
// Step 5: Set the preview output
/**
* Define Orientation of image in here,
* if in portrait mode, use value = 90,
* if in landscape mode, use value = 0
*/
CustomCamera.mMediaRecorder = Utils.rotateBackVideo(CustomCamera.mMediaRecorder);
CustomCamera.mMediaRecorder.setPreviewDisplay(mCameraPreview.getHolder().getSurface());
谢谢
答案 4 :(得分:1)
使用OrientationEventListener并在设备旋转code here时跟踪旋转值。此代码将旋转应用于相机,但对于录制,您需要将旋转应用于MediaRecorder
。当您开始录制mMediaRecorder.setOrientationHint(rotation)
时1 {}在mMediaRecorder.prepare()
之前。这解决了我的问题。
答案 5 :(得分:0)
最后我发现摩托罗拉手机在播放以纵向模式录制的视频时出现问题。
为了克服视频的轮换,我采用的最佳解决方案是将视频上传到服务器并使用ffmpeg -i input.mp4 -c:v mpeg4 -c:a copy -c:s copy -vf "transpose=2" output.mp4
如果您觉得还有其他方式,请告诉我。
答案 6 :(得分:0)
另一个解决方案是旋转您的活动,使其方向与传感器方向相同。也就是说,后置摄像头的景观和前置摄像头的倒置肖像。这个btw不会修复前置摄像头的镜面效果。另一个难点是,您必须以遵循活动方向的方式在这些轮换活动中实施您的UI。
答案 7 :(得分:0)
旋转您的MediaRecorder,如下所示,对应您在前置摄像头视频录制的摄像头显示方向中使用的度数
Display display = ((WindowManager)getContext().getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
parameters.setPreviewSize(height, width);
if(display.getRotation() == Surface.ROTATION_0)
{
mCamera.setDisplayOrientation(90);
mMediaRecorder.setOrientationHint(270);
}
if(display.getRotation() == Surface.ROTATION_90)
{
mMediaRecorder.setOrientationHint(180);
}
if(display.getRotation() == Surface.ROTATION_180)
{
mMediaRecorder.setOrientationHint(270);
}
if(display.getRotation() == Surface.ROTATION_270)
{
mCamera.setDisplayOrientation(180);
mMediaRecorder.setOrientationHint(0);
}
答案 8 :(得分:0)
以下是自定义人像摄像头的代码,将设置正确的图片和视频旋转:
private OrientationEventListener orientationEventListener;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
orientationEventListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
flashButton.setRotation(-(orientation));
cameraButton.setRotation(-(orientation));
if (camera != null) {
Parameters parameters = camera.getParameters();
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(selectedCamera, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
parameters.setRotation(rotation);
if (!isRecording) {
mediaRecorder.setOrientationHint(rotation);
}
camera.setParameters(parameters);
}
}
};
}
@Override
protected void onResume() {
super.onResume();
//...
orientationEventListener.enable();
}
@Override
protected void onPause() {
super.onPause();
orientationEventListener.disable();
//...
}
具有纵向的Teste。记得把它放在你的清单中来测试代码。我不知道是否在风景中工作。
<activity android:name=".activities.CameraActivity"
android:screenOrientation="portrait">
答案 9 :(得分:0)
用于纵向模式设置mediaRecorder.setOrientationHint(90);度数与相机方向相同myCamera.setDisplayOrientation(90);