相机的surfaceview在android棒棒糖操作系统中不起作用

Posted

技术标签:

【中文标题】相机的surfaceview在android棒棒糖操作系统中不起作用【英文标题】:surfaceview for camera is not working in android lollipop os 【发布时间】:2015-10-06 21:34:12 【问题描述】:

今天我在 android surfaceview for camera customization 中遇到了一个问题。 我尝试了下面的代码。

问题发生在我拍摄图像时,它会停止相机 预览并且不返回活动。

以下代码将在程序中实现。我从 *** 上的现有参考中获取了这段代码

    支持类。

    public class AndroidCameraSurfaceview extends Activity implements
        SurfaceHolder.Callback 
    TextView testView;
    
    Camera camera;
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;
    boolean preview;
    
    PictureCallback rawCallback;
    ShutterCallback shutterCallback;
    PictureCallback jpegCallback;
    int displayheight, displaywidth;
    Camera.PreviewCallback previewCallback;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.camerasurfaceview);
    
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        surfaceHolder = surfaceView.getHolder();
    
        surfaceHolder.addCallback(this);
    
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
        jpegCallback = new PictureCallback() 
            public void onPictureTaken(byte[] data, Camera camera) 
                Bundle b = new Bundle();
                b.putByteArray("Image", data);
                Intent intent = new Intent();
                intent.putExtras(b);
                setResult(RESULT_OK, intent);
                finish();
                // refreshCamera();
            
        ;
    
    
    
    
    public void captureImage(View v) throws IOException 
                // take the picture
                camera.takePicture(null, null, jpegCallback);
            
    
        public void refreshCamera() 
            if (surfaceHolder.getSurface() == null) 
                // preview surface does not exist
                return;
            
    
            try 
                camera.stopPreview();
             catch (Exception e) 
            
    
            try 
                camera.setDisplayOrientation(90);
                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();
             catch (Exception e) 
    
            
        
    
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) 
            if (preview) 
                camera.stopPreview();
            
    try
            Camera.Parameters parameters = camera.getParameters();
            List<Size> sizes = parameters.getSupportedPreviewSizes();
            Size optimalSize = getOptimalPreviewSize(sizes, width, height);
            parameters.setPreviewSize(optimalSize.width, optimalSize.height);
            camera.setParameters(parameters);
            try 
                camera.setDisplayOrientation(90);
                camera.setPreviewDisplay(holder);
                camera.startPreview();
                preview = true;
             catch (IOException e) 
                e.printStackTrace();
            
    catch(Exception e)
        System.out.println("Surface Exception---=>"+e);
    
        
    
        public void surfaceCreated(SurfaceHolder holder) 
            camera = Camera.open();
            if (camera != null) 
                Camera.Parameters params = camera.getParameters();
                camera.setDisplayOrientation(90);
                camera.setParameters(params);
    
            
        
    
        public void surfaceDestroyed(SurfaceHolder holder) 
            // stop preview and release camera
            camera.stopPreview();
            camera.release();
            camera = null;
        
    
        private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) 
            final double ASPECT_TOLERANCE = 1;
            double targetRatio = (double) w / h;
            if (sizes == null)
                return null;
            Size optimalSize = null;
            double minDiff = Double.MAX_VALUE;
            int targetHeight = h;
            for (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 (Size size : sizes) 
                    if (Math.abs(size.height - targetHeight) < minDiff) 
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    
                
            
            return optimalSize;
        
    
        
    

    2.在Activity中实现

    public void captureImage()

        Intent intentDriver = new Intent(AddNewDevice_Activity.this,
                AndroidCameraSurfaceview.class);
        startActivityForResult(intentDriver, 0);
        //
        // Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //
        // Uri fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
        //
        // intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
        //
        // // start the image capture Intent
        // startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
    
        // Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //
        // fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
        //
        // intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
        //
        // // start the image capture Intent
        // startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
    
    
    
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    
        super.onActivityResult(requestCode, resultCode, data);
    
        if (requestCode == 0) 
    
            System.out.println("Result Code: " + resultCode);
            if (resultCode == RESULT_OK && data != null) 
    
                Bundle bundle = data.getExtras();
                byte[] test = bundle.getByteArray("Image");
                Bitmap bpCamera = BitmapFactory.decodeByteArray(test, 0,
                        test.length);
                Matrix matrix = new Matrix();
                matrix.postRotate(90);
                bpCamera = Bitmap
                        .createBitmap(bpCamera, 0, 0, bpCamera.getWidth(),
                                bpCamera.getHeight(), matrix, true);
    
                imageView_camera.setImageBitmap(bpCamera);
                selectedImageStr = encodeTobase64(bpCamera);
            
    
         else 
            finish();
        
    
    
    

【问题讨论】:

你的意思是,onActivityResult() 不是在AndroidCameraSurfaceview.finish() 之后在onPictureTaken() 中调用的吗?您的日志是否显示 onPictureTaken() 被调用?也许,你的主要活动onCreate() 在那之后被调用了? onPictureTaken() 未显示在我的日志中,它仅显示 LogCat 中的 Failed Binder Transaction,并且 ErrorLog 显示未处理的事件循环异常。我仍然无法解决这个问题,请帮助我。 感谢 sudhAnsu 先生格式化。很抱歉这个错误。 为什么你的 AndroidCameraSurfaceview 扩展了 Activity? (不是SurfaceView吗?) 好吧,就像在 Google 文档中一样,Camera 类自 API 21 以来已被弃用,所以也许你将不得不用这个 developer.android.com/reference/android/hardware/camera2/… 重新实现你的代码 【参考方案1】:

您拥有拆分活动和表面视图。

public class AndroidCameraActivity extends Activity 
    AndroidCameraSurfaceview surfaceView;
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) 
        ...
        surfaceView = (AndroidCameraSurfaceview) findViewById(R.id.surfaceView);
    


class AndroidCameraSurfaceview extends SurfaceView implements SurfaceHolder.Callback 
    public AndroidCameraSurfaceview(Context context, AttributeSet attrs) 
        super(context, attrs);
        getHolder().addCallback(this);
        ...
    

    public void surfaceCreated(SurfaceHolder holder) 
        ...
    

    public void surfaceDestroyed(SurfaceHolder holder) 
        ...
    

    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) 
        ...
    

【讨论】:

Ecllipse Sdk 不支持此代码,所以我将我的代码迁移到 android studio。谢谢你的回答。 android.view.SurfaceView 无法转换为 com.xxxxxx.xxxxx.ui.ReadCardActivity$AndroidCameraSurfaceView 出现此错误【参考方案2】:

Google 已从 API 版本 21 中修改了相机 API,因此我们必须采用新的 camera2 包,并且在相机功能出现的情况下必须遵守。这是 google 发布的示例代码的链接,它使用表面视图实现,它在 Android 5.0 中完美运行。我相信它解决了一些谜团。

https://github.com/googlesamples/android-Camera2Basic

【讨论】:

感谢 arunkarthick,但是在我的开发环境中使用 ecllipse,而不是迁移 android studio,你有什么想法把这段代码转换成 ecllipse 项目。 有什么替代方案吗?【参考方案3】:
try this, I have made it from my self : 

package com.fragments;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Date;
import java.text.SimpleDateFormat;

import com.jsonparsing.JsonMainActivity;
import com.jsonparsing.MailFragment;
import com.mobehc.R;
import com.sendmail.main;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class CamImageCapture2 extends Fragment implements
        MediaRecorder.OnInfoListener 

    private Camera myCamera;
    private MyCameraSurfaceView myCameraSurfaceView;
    private MediaRecorder mediaRecorder;
    Camera c = null;
    ImageView myButton, myButton1, backcam;
    SurfaceHolder surfaceHolder;
    boolean recording;
    private Button startButton;
    private Button pauseButton;

    private TextView timerValue;

    private long startTime = 0L;

    private Handler customHandler = new Handler();

    long timeInMilliseconds = 0L;
    long timeSwapBuff = 0L;
    long updatedTime = 0L;
    String path = Environment.getExternalStorageDirectory().toString()
            + "/00 MHC/VID.MP4";

    /** Called when the activity is first created. */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) 
        View v = inflater.inflate(R.layout.activity_captureimage, container,
                false);

        recording = false;

        getActivity().getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        timerValue = (TextView) v.findViewById(R.id.timer);
        // Get Camera for preview
        myCamera = getCameraInstance();
        if (myCamera == null) 
            Toast.makeText(getActivity(), "Fail to get Camera",
                    Toast.LENGTH_LONG).show();
        

        myCameraSurfaceView = new MyCameraSurfaceView(getActivity(), myCamera);
        FrameLayout myCameraPreview = (FrameLayout) v
                .findViewById(R.id.videoview);
        myCameraPreview.addView(myCameraSurfaceView);

        myButton = (ImageView) v.findViewById(R.id.rec);
        myButton1 = (ImageView) v.findViewById(R.id.rec1);
        backcam = (ImageView) v.findViewById(R.id.backcamera);
        backcam.setOnClickListener(new OnClickListener() 

            @Override
            public void onClick(View v) 

                Intent ik = new Intent(getActivity(), Camrec2.class);
                startActivity(ik);
                // getActivity().finish();
                getActivity().getFragmentManager().popBackStack();
            
        );
        myButton1.setOnClickListener(new OnClickListener() 

            @Override
            public void onClick(View v) 
                myCamera.takePicture(null, null, mPicture);
            
        );

        myButton.setOnClickListener(new OnClickListener() 

            @Override
            public void onClick(View v) 

                File attachment1 = new File(Environment
                        .getExternalStorageDirectory(), "/00 MHC/image.jpg");
                if (attachment1.exists()) 
                    attachment1.delete();
                

                if (recording) 
                    mediaRecorder.stop(); // stop the recording
                    releaseMediaRecorder(); // release the MediaRecorder object

                    // Exit after saved
                    getActivity().finish();
                 else 

                    // Release Camera before MediaRecorder start
                    releaseCamera();

                    if (!prepareMediaRecorder()) 
                        Toast.makeText(getActivity(),
                                "Fail in prepareMediaRecorder()!\n - Ended -",
                                Toast.LENGTH_LONG).show();
                        getActivity().finish();
                    

                    mediaRecorder.start();
                    startTime = SystemClock.uptimeMillis();
                    customHandler.postDelayed(updateTimerThread, 0);

                    /*
                     * final TextView _tv = (TextView) findViewById(R.id.timer);
                     * _tv.setVisibility(View.VISIBLE); new
                     * CountDownTimer(60000, 1000) 
                     * 
                     * public void onTick(long millisUntilFinished) 
                     * _tv.setText(new SimpleDateFormat("00:ss") .format(new
                     * Date(millisUntilFinished))); 
                     * 
                     * public void onFinish()  _tv.setText("done!"); Intent ii
                     * = new Intent(Camrecord.this, Emailtry.class);
                     * startActivity(ii); finish();  .start();
                     */recording = true;
                    // myButton.setText("STOP");

                    Drawable myDrawable = getResources().getDrawable(
                            R.drawable.stp);
                    myButton.setImageDrawable(myDrawable);
                    backcam.setVisibility(View.INVISIBLE);

                

            
        );
        return v;
    

    PictureCallback mPicture = new PictureCallback() 
        @Override
        public void onPictureTaken(byte[] data, Camera camera) 
            File externalStorage = Environment.getExternalStorageDirectory();

            String sdcardPath = externalStorage.getAbsolutePath() + "/00 MHC/";
            File pictureFile = new File(sdcardPath + "/image" + ".jpg");

            try 
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();

                File attachment1 = new File(
                        Environment.getExternalStorageDirectory(),
                        "/00 MHC/VID.mp4");
                if (attachment1.exists()) 
                    attachment1.delete();
                
                Toast.makeText(getActivity(), "Captured Successfully...",
                        Toast.LENGTH_LONG).show();
                Fragment fr = new main();
                android.support.v4.app.FragmentTransaction fragmentTransaction = getFragmentManager()
                        .beginTransaction();
                fragmentTransaction.replace(R.id.fragment_place, fr);
                fragmentTransaction.commit();
                // getActivity().finish();
             catch (FileNotFoundException e) 

             catch (IOException e) 
            
        
    ;

    private Camera getCameraInstance() 
        // TODO Auto-generated method stub

        try 
            // c = Camera.open(); // attempt to get a Camera instance
            if (Camera.getNumberOfCameras() >= 2) 

                // backcam.setVisibility(View.VISIBLE);
                // if you want to open front facing camera use this line
                c = Camera.open(CameraInfo.CAMERA_FACING_FRONT);

                c = Camera.open(CameraInfo.CAMERA_FACING_BACK);

             else 
                c = Camera.open(CameraInfo.CAMERA_FACING_BACK);
            

            /*
             * c.setDisplayOrientation(90); c.setPreviewDisplay(surfaceHolder);
             * 
             * Camera.Parameters p = c.getParameters(); p.set("camera-id", 2);
             * c.setParameters(p);
             */
         catch (Exception e) 
            // Camera is not available (in use or does not exist)
        
        return c; // returns null if camera is unavailable
    

    private boolean prepareMediaRecorder() 
        myCamera = getCameraInstance();
        myCamera.setDisplayOrientation(90);
        mediaRecorder = new MediaRecorder();

        myCamera.unlock();
        mediaRecorder.setCamera(myCamera);

        mediaRecorder.setAudiosource(MediaRecorder.AudioSource.CAMCORDER);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

        mediaRecorder.setProfile(CamcorderProfile
                .get(CamcorderProfile.QUALITY_LOW));
        mediaRecorder.setOrientationHint(270);

        mediaRecorder.setOutputFile(path);
        mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
        mediaRecorder.setOnInfoListener(this);
        mediaRecorder.setMaxFileSize(2500000); // Set max file size 5M

        // mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
        mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder()
                .getSurface());

        try 
            mediaRecorder.prepare();
         catch (IllegalStateException e) 
            releaseMediaRecorder();
            return false;
         catch (IOException e) 
            releaseMediaRecorder();
            return false;
        
        return true;

    

    @Override
    public void onPause() 
        super.onPause();
        releaseMediaRecorder(); // if you are using MediaRecorder, release it
                                // first
        releaseCamera(); // release the camera immediately on pause event
    

    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 class MyCameraSurfaceView extends SurfaceView implements
            SurfaceHolder.Callback 

        private SurfaceHolder mHolder;
        private Camera mCamera;

        public MyCameraSurfaceView(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);
        

        @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 

                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.setDisplayOrientation(90);
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
             catch (IOException e) 
            
        

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) 

        
    

    private Runnable updateTimerThread = new Runnable() 

        public void run() 

            timeInMilliseconds = SystemClock.uptimeMillis() - startTime;

            updatedTime = timeSwapBuff + timeInMilliseconds;

            int secs = (int) (updatedTime / 1000);
            int mins = secs / 60;
            secs = secs % 60;
            int milliseconds = (int) (updatedTime % 1000);
            timerValue.setText("" + mins + ":" + String.format("%02d", secs)
                    + ":" + String.format("%03d", milliseconds));
            customHandler.postDelayed(this, 0);
        

    ;

    @Override
    public void onInfo(MediaRecorder mr, int what, int extra) 

        if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) 
            Log.v("VIDEOCAPTURE", "Maximum Duration Reached");
            mediaRecorder.stop(); // stop the recording
            releaseMediaRecorder(); // release the MediaRecorder object

            // Exit after saved
            // getActivity().finish();
            getActivity().getFragmentManager().popBackStack();
        
    


【讨论】:

感谢您的回答,Parik dhakan 先生。【参考方案4】:

我尝试了 Camera API 2,但我没有时间解决其中的问题 时间线。这就是我找到问题解决方案的方式 使用camera API 1. 当Multiple Views是Handle Single时 活动。请在相机处理的情况下尝试此代码。

protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        if (requestCode == CAPTURE_IMAGE_CAPTURE_CODE) 
            if (resultCode == RESULT_OK) 
                Bitmap bp = (Bitmap) data.getExtras().get("data");
                Bitmap resized = Bitmap.createScaledBitmap(bp,
                        (int) (bp.getWidth() * 0.8),
                        (int) (bp.getHeight() * 0.8), true);

                imageView_camera.setImageBitmap(resized);

                SharedPreferences value_1_Details = getSharedPreferences(
                        "Value_1_Key", MODE_PRIVATE);
                Value_1_SelectedPosId = Integer.parseInt(value_1_Details.getString(
                        "Value_1_ID", ""));
                String value_1_Name = value_1_Details.getString("Value_1_Data", "");
                btn_popup_value_1_Name.setText(value_1_Name);

                SharedPreferences value_2_Details = getSharedPreferences(
                        "Value_2_Key", MODE_PRIVATE);
                value_2_SelectedPosId = Integer.parseInt(value_2_Details.getString(
                        "Value_2_ID", ""));
                String value_2_Name = value_2_Details.getString("Value_2_Data", "");
                btn_dropdown_value_2_Name.setText(value_2_Name);

                SharedPreferences value_3_Details = getSharedPreferences(
                        "Value_3_Key", MODE_PRIVATE);
                value_3_PosId = Integer.parseInt(value_3_Details
                        .getString("Value_3_ID", ""));
                String value_3_Name = value_3_Details.getString("Value_3_Data",
                        "");
                btn_dropdown_value_3_Name.setText(value_3_Name);


                rL_include_ViewDetails.setVisibility(View.GONE);
                rL_include_AddNew.setVisibility(View.VISIBLE);
                rL_include_View.setVisibility(View.GONE);

                selectedImageStr = encodeTobase64(resized);

             else if (resultCode == RESULT_CANCELED) 
                Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
            
        
    

【讨论】:

以上是关于相机的surfaceview在android棒棒糖操作系统中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

相机中使用的Android模糊surfaceview

如何在surfaceview中将Android相机更改为人像?

android相机surfaceview方向

没有surfaceView的Android相机图像方向

android - 使用没有surfaceview或textureview的相机

Android相机教程(使用surfaceview)