2

我正在尝试在 Android 中以正确的方向录制视频。我已经建立了我的活动,它工作正常,唯一的事情是在录制后保存的视频被旋转。相机的预览工作正常,所以我不明白为什么。要修复轮换,我使用此代码(我在 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 度。

我在记录开始之前调用该方法,所以如果我能够获得屏幕相对于默认景观的旋转,我就可以了。

谢谢你的帮助!

4

2 回答 2

2

最后,我能够成功构建自己的相机应用程序,而没有任何方向问题。关键是查看surfaceView 的旋转。我认为将所有代码发布在这里可能会对某人有所帮助,只需复制它并启动 Activity!

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>

Activity 已经从 Android 2.3.6 到 4.3 进行了测试。如果您发现任何问题或有任何建议,请告诉我!

于 2013-10-11T07:06:58.513 回答
0

如果您的问题与轮换变量有关,您可以考虑查看此链接。脱离该链接的主要区别WindowManager是创建了一个对象,然后用于获取旋转。这个看似很小的差异一直是我的一段代码工作与不工作之间的差异制造者。

你可以简单地说Camera.CameraInfo info = new Camera.CameraInfo();Camera.getCameraInfo(...);

我很好奇你为什么要指定CameraInfo.CAMERA_FACING_BACKandroid.hardware.Camera.getCameraInfo(CameraInfo.CAMERA_FACING_BACK, info);我觉得你可以打电话info.facingint代替。

我希望在链接和我的建议/查询之间能激发出正确的答案!

于 2013-10-09T16:42:47.587 回答