android前置摄像头问题

时间:2012-03-06 16:46:16

标签: android android-camera android-2.2-froyo galaxy

好吧,我正在尝试开发一款采用前置摄像头拍摄的应用。 我有一个奇怪的错误。预览看起来很好,但输出视频出现了低分辨率的绿线和高分辨率的绿线

这是代码:

package feipeng.yacamcorder;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.VideoEncoder;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.Toast;

/***
 * TODO: 1. sound on/off 2. resolution change
 * 
 * @author roman10
 * 
 */

public class Main extends Activity implements SurfaceHolder.Callback {
    private SurfaceView prSurfaceView;
    private Button prStartBtn;
    private Button prSettingsBtn;
    private boolean prRecordInProcess;
    private SurfaceHolder prSurfaceHolder;
    private Camera prCamera;
    private final String cVideoFilePath = "/sdcard/r10videocam/";

    private Context prContext;
    private MediaRecorder prMediaRecorder;
    private CamcorderProfile mProfile;
    private final int cMaxRecordDurationInMs = 30000;

    private final long cMaxFileSizeInBytes = 5000000;

    private final int cFrameRate = 20;

    private File prRecordedFile;
    private static final int REQUEST_DECODING_OPTIONS = 0;
    private static final String TAG = "aaa";

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
            Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        switch (requestCode) {
        case REQUEST_DECODING_OPTIONS:
            if (resultCode == RESULT_OK) {
                updateEncodingOptions();
            }
            break;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        prContext = this.getApplicationContext();
        setContentView(R.layout.main);
        Utils.createDirIfNotExist(cVideoFilePath);
        prSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);
        prStartBtn = (Button) findViewById(R.id.main_btn1);
        prSettingsBtn = (Button) findViewById(R.id.main_btn2);
        prRecordInProcess = false;
        prStartBtn.setOnClickListener(new View.OnClickListener() {
            // @Override
            @Override
            public void onClick(View v) {
                if (prRecordInProcess == false) {
                    startRecording();
                } else {
                    stopRecording();
                }
            }
        });
        prSettingsBtn.setOnClickListener(new View.OnClickListener() {
            // @Override
            @Override
            public void onClick(View v) {
                Intent lIntent = new Intent();
                lIntent.setClass(prContext,
                        feipeng.yacamcorder.SettingsDialog.class);
                startActivityForResult(lIntent, REQUEST_DECODING_OPTIONS);
            }
        });
        prSurfaceHolder = prSurfaceView.getHolder();
        prSurfaceHolder.addCallback(this);
        prSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        prMediaRecorder = new MediaRecorder();
    }

    private Camera openFrontFacingCamera() {
        Camera camera = null;

        // Look for front-facing camera, using the Gingerbread API.
        // Java reflection is used for backwards compatibility with
        // pre-Gingerbread APIs.
        try {
            Class<?> cameraClass = Class.forName("android.hardware.Camera");
            Object cameraInfo = null;
            Field field = null;
            int cameraCount = 0;
            Method getNumberOfCamerasMethod = cameraClass
                    .getMethod("getNumberOfCameras");
            if (getNumberOfCamerasMethod != null) {
                cameraCount = (Integer) getNumberOfCamerasMethod.invoke(null,
                        (Object[]) null);
            }
            Class<?> cameraInfoClass = Class
                    .forName("android.hardware.Camera$CameraInfo");
            if (cameraInfoClass != null) {
                cameraInfo = cameraInfoClass.newInstance();
            }
            if (cameraInfo != null) {
                field = cameraInfo.getClass().getField("facing");
            }
            Method getCameraInfoMethod = cameraClass.getMethod("getCameraInfo",
                    Integer.TYPE, cameraInfoClass);
            if (getCameraInfoMethod != null && cameraInfoClass != null
                    && field != null) {
                for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
                    getCameraInfoMethod.invoke(null, camIdx, cameraInfo);
                    int facing = field.getInt(cameraInfo);
                    if (facing == 1) { // Camera.CameraInfo.CAMERA_FACING_FRONT
                        try {
                            Method cameraOpenMethod = cameraClass.getMethod(
                                    "open", Integer.TYPE);
                            if (cameraOpenMethod != null) {
                                camera = (Camera) cameraOpenMethod.invoke(null,
                                        camIdx);
                                mProfile = CamcorderProfile
                                        .get(CamcorderProfile.QUALITY_LOW);
                            }
                        } catch (RuntimeException e) {
                            Log.e(TAG,
                                    "Camera failed to open: "
                                            + e.getLocalizedMessage());
                        }
                    }
                }
            }
        }
        // Ignore the bevy of checked exceptions the Java Reflection API throws
        // - if it fails, who cares.
        catch (ClassNotFoundException e) {
            Log.e(TAG, "ClassNotFoundException" + e.getLocalizedMessage());
        } catch (NoSuchMethodException e) {
            Log.e(TAG, "NoSuchMethodException" + e.getLocalizedMessage());
        } catch (NoSuchFieldException e) {
            Log.e(TAG, "NoSuchFieldException" + e.getLocalizedMessage());
        } catch (IllegalAccessException e) {
            Log.e(TAG, "IllegalAccessException" + e.getLocalizedMessage());
        } catch (InvocationTargetException e) {
            Log.e(TAG, "InvocationTargetException" + e.getLocalizedMessage());
        } catch (InstantiationException e) {
            Log.e(TAG, "InstantiationException" + e.getLocalizedMessage());
        } catch (SecurityException e) {
            Log.e(TAG, "SecurityException" + e.getLocalizedMessage());
        }

        if (camera == null) {
            // Try using the pre-Gingerbread APIs to open the camera.
            try {
                camera = Camera.open();
            } catch (RuntimeException e) {
                Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
            }
        }

        return camera;
    }

    private boolean startRecording() {
        prCamera.stopPreview();
        try {
            prCamera.unlock();
            prMediaRecorder.setCamera(prCamera);

            // set audio source as Microphone, video source as camera
            // state: Initial=>Initialized
            prMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            prMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            // set the file output format: 3gp or mp4
            // state: Initialized=>DataSourceConfigured
            String lVideoFileFullPath;
            String lDisplayMsg = "Current container format: ";
            if (Utils.puContainerFormat == SettingsDialog.cpu3GP) {
                lDisplayMsg += "3GP\n";
                lVideoFileFullPath = ".3gp";
                prMediaRecorder
                        .setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            } else if (Utils.puContainerFormat == SettingsDialog.cpuMP4) {
                lDisplayMsg += "MP4\n";
                lVideoFileFullPath = ".mp4";
                prMediaRecorder
                        .setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            } else {
                lDisplayMsg += "3GP\n";
                lVideoFileFullPath = ".3gp";
                prMediaRecorder
                        .setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            }
            // the encoders:
            // audio: AMR-NB
            prMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);
            // video: H.263, MP4-SP, or H.264
            // prMediaRecorder.setVideoEncoder(VideoEncoder.H263);
            // prMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);
            lDisplayMsg += "Current encoding format: ";
            if (Utils.puEncodingFormat == SettingsDialog.cpuH263) {
                lDisplayMsg += "H263\n";
                prMediaRecorder.setVideoEncoder(VideoEncoder.H263);
            } else if (Utils.puEncodingFormat == SettingsDialog.cpuMP4_SP) {
                lDisplayMsg += "MPEG4-SP\n";
                prMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);
            } else if (Utils.puEncodingFormat == SettingsDialog.cpuH264) {
                lDisplayMsg += "H264\n";
                prMediaRecorder.setVideoEncoder(VideoEncoder.H264);
            } else {
                lDisplayMsg += "H263\n";
                prMediaRecorder.setVideoEncoder(VideoEncoder.H263);
            }
            lVideoFileFullPath = cVideoFilePath
                    + String.valueOf(System.currentTimeMillis())
                    + lVideoFileFullPath;
            prRecordedFile = new File(lVideoFileFullPath);
            prMediaRecorder.setOutputFile(prRecordedFile.getPath());
            if (Utils.puResolutionChoice == SettingsDialog.cpuRes176) {
                prMediaRecorder.setVideoSize(176, 144);
            } else if (Utils.puResolutionChoice == SettingsDialog.cpuRes320) {
                prMediaRecorder.setVideoSize(320, 240);
            } else if (Utils.puResolutionChoice == SettingsDialog.cpuRes720) {
                prMediaRecorder.setVideoSize(720, 480);
            }
            Toast.makeText(prContext, lDisplayMsg, Toast.LENGTH_LONG).show();
            prMediaRecorder.setVideoFrameRate(cFrameRate);
            prMediaRecorder.setPreviewDisplay(prSurfaceHolder.getSurface());
            prMediaRecorder.setMaxDuration(cMaxRecordDurationInMs);
            prMediaRecorder.setMaxFileSize(cMaxFileSizeInBytes);
            // prepare for capturing
            // state: DataSourceConfigured => prepared
            prMediaRecorder.prepare();
            // start recording
            // state: prepared => recording
            prMediaRecorder.start();
            prStartBtn.setText("Stop");
            prRecordInProcess = true;
            return true;
        } catch (IOException _le) {
            _le.printStackTrace();
            return false;
        }
    }

    private void stopRecording() {
        prMediaRecorder.stop();
        prMediaRecorder.reset();
        try {
            prCamera.reconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
        prStartBtn.setText("Start");
        prRecordInProcess = false;
        prCamera.startPreview();
    }

    // @Override
    @Override
    public void surfaceChanged(SurfaceHolder _holder, int _format, int _width,
            int _height) {
        Camera.Parameters lParam = prCamera.getParameters();
        // //lParam.setPreviewSize(_width, _height);
        // //lParam.setPreviewSize(320, 240);
        // lParam.setPreviewFormat(PixelFormat.JPEG);
        prCamera.setParameters(lParam);
        try {
            prCamera.setPreviewDisplay(_holder);
            prCamera.startPreview();
            // prPreviewRunning = true;
        } catch (IOException _le) {
            _le.printStackTrace();
        }
    }

    // @Override
    @Override
    public void surfaceCreated(SurfaceHolder arg0) {

        prCamera = openFrontFacingCamera();

        if (prCamera == null) {
            Toast.makeText(this.getApplicationContext(),
                    "Camera is not available!", Toast.LENGTH_SHORT).show();
            finish();
        }
    }

    // @Override
    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        if (prRecordInProcess) {
            stopRecording();
        } else {
            prCamera.stopPreview();
        }
        prMediaRecorder.release();
        prMediaRecorder = null;
        prCamera.release();
        prCamera = null;
    }

    private void updateEncodingOptions() {
        if (prRecordInProcess) {
            stopRecording();
            startRecording();
            Toast.makeText(prContext, "Recording restarted with new options!",
                    Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(prContext, "Recording options updated!",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

P.S。 使用galaxy s1。

任何想法?

1 个答案:

答案 0 :(得分:0)

我在4.0.4上运行的三星Nexus S上尝试了你的代码,效果很好。 MediaRecorder的设置如下:

private boolean startRecording() {
        ...
        prMediaRecorder.setCamera(prCamera);
        prMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        prMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        prMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        prMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        prMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        prMediaRecorder.setOutputFile("/sdcard/video.mp4");
        prMediaRecorder.setVideoSize(320, 240);//If higher produces error -19
        prMediaRecorder.setVideoFrameRate(15);//If higher produces error -19
        prMediaRecorder.setPreviewDisplay(prSurfaceHolder.getSurface());
        prMediaRecorder.setMaxDuration(cMaxRecordDurationInMs);
        prMediaRecorder.setMaxFileSize(cMaxFileSizeInBytes);
        prMediaRecorder.prepare();
        prMediaRecorder.start();
        ...
}//endOfStartRecording()

对于10秒的记录,它会产生大小约为300 KB的.mp4文件。质量不是很好,但它是我能得到的最高品质。请记住,前置摄像头不如后置摄像头那么强大。