괴도군의 블로그

[Android]SurfaceView Camera Preview(카메라 프리뷰) 본문

#프로그래밍/Android

[Android]SurfaceView Camera Preview(카메라 프리뷰)

괴도군 2016. 4. 12. 13:14
반응형



예제를 많이 찾아보다가 소스 짜집기해서 적당히 쓸만해서 올려봅니다.


서피스뷰가 작동을 잘 안하길래 엄청 고생했네요..


레이아웃에 addView하는식으로 작성하게되면..


onMeasure()에서 크기가 0으로만 나옵니다.


무조건 FrameLayout 에만 addView하세요.


xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="utf-8"?>
 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <com.jyp.ttt.view.CameraPreview
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
    </com.jyp.ttt.view.CameraPreview>
 
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#55FFFFFF"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="찍기" />
 
</RelativeLayout>
 
 
 
cs


메인 액티비티입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class MainActivity extends AppCompatActivity {
 
    Button cameraButton;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout_test);
 
        final CameraPreview surfaceView = (CameraPreview) findViewById(R.id.main);
        SurfaceHolder holder = surfaceView.getHolder();
        holder.addCallback(surfaceView);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
 
        cameraButton = (Button) findViewById(R.id.button);
        cameraButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                surfaceView.takePhoto(new Camera.PictureCallback() {
                    @Override
                    public void onPictureTaken(byte[] data, Camera camera) {
                        Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
                        Log.v("","");
                    }
                });
            }
        });
    }
}
 
 
 
cs


카메라 뷰


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private Camera mCamera;
    public List<Camera.Size> prSupportedPreviewSizes;
    private Camera.Size prPreviewSize;
 
    public CameraPreview(Context context) {
        super(context);
        Log.v("jyp@@@","CameraPreview(Context context) 생성자호출");
    }
 
    public CameraPreview(Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.v("jyp@@@""CameraPreview(Context context, AttributeSet attrs) 생성자호출");
        mCamera = Camera.open();
        prSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
    }
 
    public boolean takePhoto(Camera.PictureCallback handler){
        if(mCamera != null){
            mCamera.takePicture(null,null,handler);
            return true;
        }else{
            return false;
        }
    }
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.v("jyp@@@","surfaceCreated ");
        // Surface가 생성되었으니 프리뷰를 어디에 띄울지 지정해준다. (holder 로 받은 SurfaceHolder에 뿌려준다.
        try {
 
            Camera.Parameters parameters = mCamera.getParameters();
            if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
                parameters.set("orientation""portrait");
                mCamera.setDisplayOrientation(90);
                parameters.setRotation(90);
            } else {
                parameters.set("orientation""landscape");
                mCamera.setDisplayOrientation(0);
                parameters.setRotation(0);
            }
            mCamera.setParameters(parameters);
 
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }
 
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.v("jyp@@@","surfaceDestroyed ");
        // 프리뷰 제거시 카메라 사용도 끝났다고 간주하여 리소스를 전부 반환한다
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
 
 
    private Camera.Size getBestPreviewSize(int width, int height)
    {
        Camera.Size result=null;
        Camera.Parameters p = mCamera.getParameters();
        for (Camera.Size size : p.getSupportedPreviewSizes()) {
            if (size.width<=width && size.height<=height) {
                if (result==null) {
                    result=size;
                } else {
                    int resultArea=result.width*result.height;
                    int newArea=size.width*size.height;
 
                    if (newArea>resultArea) {
                        result=size;
                    }
                }
            }
        }
        return result;
    }
 
    @Override
    public void surfaceChanged(SurfaceHolder holder, int formatint w, int h) {
        Log.v("jyp@@@","surfaceChanged ");
        // 프리뷰를 회전시키거나 변경시 처리를 여기서 해준다.
        // 프리뷰 변경시에는 먼저 프리뷰를 멈춘다음 변경해야한다.
        if (holder.getSurface() == null){
            // 프리뷰가 존재하지 않을때
            return;
        }
 
        // 우선 멈춘다
        try {
            mCamera.stopPreview();
        } catch (Exception e){
            // 프리뷰가 존재조차 하지 않는 경우다
        }
 
        // 프리뷰 변경, 처리 등을 여기서 해준다.
        Camera.Parameters parameters = mCamera.getParameters();
        List<String> focusModes = parameters.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        }
//
//        Camera.Size size = getBestPreviewSize(w, h);
        Log.v("jyp@@@","surfaceChanged  width: "+prPreviewSize.width);
        Log.v("jyp@@@","surfaceChanged  height: "+prPreviewSize.height);
 
        parameters.setPreviewSize(prPreviewSize.width, prPreviewSize.height);
        mCamera.setParameters(parameters);
        // 새로 변경된 설정으로 프리뷰를 재생성한다
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
 
        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
 
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.v("jyp@@@","onMeasure()");
 
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        Log.v("jyp@@@","width: "+width);
        Log.v("jyp@@@","height: "+height);
        setMeasuredDimension(width, height);
 
        if (prSupportedPreviewSizes != null) {
            prPreviewSize = getOptimalPreviewSize(prSupportedPreviewSizes, width, height);
            Log.v("jyp@@@","prPreviewSize.width: "+prPreviewSize.width);
            Log.v("jyp@@@","prPreviewSize.height: "+prPreviewSize.height);
        }
    }
 
    public Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
 
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) h / w;
 
        if (sizes == null)
            return null;
 
        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;
 
        int targetHeight = h;
 
        for (Camera.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 (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
 
        return optimalSize;
    }
 
}
 
 
 
 
 
 
cs


매니페스트 파일에는 

<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme">

요정도 해주세요

세로고정


반응형
Comments