태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

카메라를 이용하자! - 카메라 프리뷰 띄우기

2009.12.28 10:19

강좌 작성환경
SDK Version : Android SDK 1.6, release 2
ADT Version : 0.9.5

추후 SDK업데이트로 인해 글의 내용과 최신 SDK 내용간 차이가 있을 수 있습니다.

지난 글에 이어서 이번 글에서는 카메라 프리뷰를 SurfaceView에 표시하는 방법에 대해 알아보도록 하겠습니다.
카메라 프리뷰 화면이 우리가 만든 SurfaceView에 표시되어야 하므로, SurfaceView를 완전하게 구현해 주어야 합니다.
아래는 우리가 만든 SurfaceView를 상속한 클래스, Preview 클래스의 전체 코드입니다.


class Preview extends SurfaceView implements SurfaceHolder.Callback {
    SurfaceHolder mHolder;
    Camera mCamera;
    
    Preview(Context context) {
        super(context);
        
        // SurfaceHolder.Callback을 설정함으로써 Surface가 생성/소멸되었음을
        // 알 수 있습니다.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // Surface가 생성되었다면, 카메라의 인스턴스를 받아온 후 카메라의
        // Preview 를 표시할 위치를 설정합니다.
        mCamera = Camera.open();
        try {
           mCamera.setPreviewDisplay(holder);
        } catch (IOException exception) {
            mCamera.release();
            mCamera = null;
            // TODO: add more exception handling logic here
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // 다른 화면으로 돌아가면, Surface가 소멸됩니다. 따라서 카메라의 Preview도 
        // 중지해야 합니다. 카메라는 공유할 수 있는 자원이 아니기에, 사용하지 않을
        // 경우 -액티비티가 일시정지 상태가 된 경우 등 - 자원을 반환해야합니다.
        mCamera.stopPreview();
        mCamera = null;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // 표시할 영역의 크기를 알았으므로 해당 크기로 Preview를 시작합니다.
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(w, h);
        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }

}

이전 글에서는 아직 surfaceCreated, surfaceDestroyed, surfaceChanged 메소드가 구현되어있지 않았는데, 여기에서 이 메소드들까지 구현되어 있는 것을 확인할 수 있습니다. 하나하나씩 차근차근 살펴보도록 하겠습니다.

class Preview extends SurfaceView implements SurfaceHolder.Callback {
    SurfaceHolder mHolder;
    Camera mCamera; // Camera객체 추가

우선, SurfaceView에 카메라에서 받은 영상을 표시하기 위해 Camera객체가 추가된 것을 확인할 수 있습니다.

    public void surfaceCreated(SurfaceHolder holder) {
        // Surface가 생성되었다면, 카메라의 인스턴스를 받아온 후 카메라의
        // Preview 를 표시할 위치를 설정합니다.
        mCamera = Camera.open();
        try {
           mCamera.setPreviewDisplay(holder);
        } catch (IOException exception) {
            mCamera.release();
            mCamera = null;
            // TODO: add more exception handling logic here
        }
    }
그 다음, surfaceCreated 메소드의 구현부입니다.
마치 액티비티의 생애주기 메소드 중 하나인 onCreate(Bundle)의 형태와 유사합니다. 이 메소드를 구현함으로써 SurfaceView가 생성되었을 때, 즉 "화면에 표시" 될 때 해야 할 동작을 처리할 수 있습니다.

여기에서는 카메라 객체를 받아와 카메라로부터 영상을 받을 수 있도록 초기화해주는 동작을 수행하고 있습니다. (Camera.open()) 그 다음, setPreviewDisplay(holder)메소드를 통해 카메라로부터 받은 프리뷰 영상을 어디에 표시해줄지 지정하고 있습니다.

앞의 글에서 SurfaceView는 SurfaceView 자체가 내용을 표시하는 것이 아니라 내부의 SurfaceHolder를 통해 최종적으로는 Surface라는 객체 위에 그 내용을 표시한다고 하였는데, 위의 경우는 아래와 같이 카메라의 영상이 처리된다고 볼 수 있습니다.


그 다음을 한번 보도록 하죠. 예외처리 부분이군요.

 } catch (IOException exception) {
            mCamera.release();
            mCamera = null;
            // TODO: add more exception handling logic here
        }

오류가 발생해서 프리뷰 화면을 제데로 표시하지 못했다면, release() 메소드를 사용하여 카메라의 자원을 다시 반환하는 것을 확인할 수 있습니다. 카메라는 여러 곳에서 공유할 수 있는 자원이 아니기에 카메라 객체의 사용이 끝났다면 위와 같이 release() 메소드를 사용하여 자원을 반환해야 합니다. 그렇지 않으면 다른 문제가 발생할 수 있습니다. :(

public void surfaceDestroyed(SurfaceHolder holder) {
        // 다른 화면으로 돌아가면, Surface가 소멸됩니다. 따라서 카메라의 Preview도 
        // 중지해야 합니다. 카메라는 공유할 수 있는 자원이 아니기에, 사용하지 않을
        // 경우 -액티비티가 일시정지 상태가 된 경우 등 - 자원을 반환해야합니다.
        mCamera.stopPreview();
        mCamera = null;
    }

그 다음, surfaceDestroyed 메소드 구현부입니다. 이 메소드는 SurfaceView가 더이상 화면에 표시되지 않을 때 호출됩니다. 일반적인 View는 액티비티가 일시정지 상태가 된 경우에도 계속 화면에 그 내용을 표시하지만, SurfaceVIew의 경우 표시하는 내용이 다른 뷰에 비해 복잡하기에 굳이 액티비티가 비활성 상태일때 그 내용을 표시할 이유가 없겠죠. 

따라서, stopPreview() 메소드를 사용하여 카메라의 프리뷰 영상을 표시하는 것을 중단하고, 카메라 객체를 소멸시킵니다.

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // 표시할 영역의 크기를 알았으므로 해당 크기로 Preview를 시작합니다.
        Camera.Parameters parameters = mCamera.getParameters(); // (1)
        parameters.setPreviewSize(w, h); // (2)
        mCamera.setParameters(parameters); // (3)
        mCamera.startPreview();
    }

다음은 surfaceChanged메소드입니다. 이 메소드는 surfaceCreated()메소드 호출 이후에 호출되는 메소드로, Surface의 크기에 따라 실질적으로 어떻게 내용을 표시할지를 처리해주는 메소드입니다.

여기에서는 카메라의 여러 설정값들을 담고 있는 parameters를 받아온 후(1), 프리뷰의 크기를 지정합니다.(2) 그 후, setParameters()에 방금 카메라 프리뷰 크기를 수정한 parameter 객체를 인자로 넘겨줌으로써 카메라 객체에서 프리뷰 영상을 표시할 영역의 크기를 설정해주게 됩니다. (3)

이 과정이 모두 끝났다면, startPreview() 메소드를 통해 최종적으로 카메라 프리뷰 영상을 표시해주게 됩니다.

여기까지 해서 SurfaceView 부분의 구현이 모두 끝났습니다. 실질적으로 카메라의 영상을 처리하는 부분은 여기에서 끝났으므로, 남은 것들은 액티비티를 구성하고, 이 뷰의 객체를 생성한 후 액티비티의 화면으로 표시해주는 과정이 남았습니다. 
액티비티 구현을 보도록 하죠.

public class CameraPreview extends Activity {    
    private Preview mPreview;
    
    @Override
	protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // Hide the window title.
        requestWindowFeature(Window.FEATURE_NO_TITLE);
    
        // Create our Preview view and set it as the content of our activity.
        mPreview = new Preview(this);
        setContentView(mPreview);
    }

}
다른 특이한 것들은 별로 없고, 액티비티의 이름을 표시해주는 타이틀바를 표시하지 않기 위해 requestWindowFeature(Window.FEATURE_NO_TITLE) 를 사용하는 것을 확인할 수 있습니다.

자 이제 거의 다 끝났습니다. 카메라를 사용하기 위해서는 권한이 필요하므로, 메니페스트 파일에 권한을 추가합니다.


위와 같이 메니페스트 파일의 Permission 탭으로 이동한 후, Add..버튼을 누릅니다.


Uses Permission을 선택한 후, OK 버튼을 클릭합니다.


새로 Uses Permission 항목에 카메라 사용 권한인 android.permission.CAMERA 를 선택해주면 권한 추가가 완료됩니다.

그리고, 메니페스트 파일을 열어 수동으로 <uses-feature android:name="android.hardware.camera"/> 를 추가합니다.

 
이 기능은 SDK버전을 선언하는 것과 비슷하게 카메라가 없는 장치에서는 아예 어플리케이션이 설치가 되지 않도록 하는 옵션입니다. 안드로이드를 사용하는 장치가 한두가지가 아니므로 이런 식으로 각 장치의 특성에 맞도록 적절히 조치를 해 주는 것이죠.

마지막으로, 액티비티를 landscape 모드로 표시하기 위해 메니페스트 파일을 열어 Application 탭으로 간후,


Screen orientation을 landscape로 바꾸어줍니다. 이렇게 하면 이 액티비티는 항상 landscape 모드로 표시되게 됩니다.


이 과정이 모두 끝났다면, 어플리케이션을 실행시켜봅시다. 카메라 미리보기가 잘 표시되는 것을 확인할 수 있습니다 :)



소스파일 첨부합니다.


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

커니 멀티미디어/Camera , , , , , , ,

  1. 이전 댓글 더보기
  2. Blog Icon
    케이

    커니님 쓰신 책보면서 공부 중인데, 에뮬에서만 해보다 오늘 드디어 실제 단말기에 돌려봤습니다.
    그런데 8장의 카메라 사용한 예제가 넥서스s 단말기에서 작동이 안되네요 ㅠ
    처음에 실행하려고 하면 "죄송합니다....예상치 않게 중지되었습니다. 다시 시도해 주세요." 메세지 뜨며 실패..
    안드로이드 2.3.3인데, 무엇이 문제인지 의심가는 점이라도 있으신가요??

    ----
    아 그리고 실행실패 후에, 원래 잘 되던 기본 카메라 사용하려고 하면 "카메라 오류. 카메라에 연결할 수 없습니다." 뜨네요ㅠ

  3. Blog Icon
    행인

    항상 커니님의 글 잘 보고 있습니다. 펍에서도 그렇구요 ^^
    카메라뷰 위에 이미지를 띄우려고 하던중
    RelativeLayout을 생성하고 서피스뷰와 카메라뷰를 애드 시켰습니다.
    그리고 onDraw()에서 이미지를 그려주려고 하는데 이미지는 잘 나옵니다만
    PorterDuffXfermode(PorterDuff.Mode.LIGHTEN);
    위와 같이 광원효과를 주려고 하면 뷰가 다르게 설정 되있어서 하나의 이미지만 먹힙니다.

    이 방법을 어찌해결 해야 할까요....

  4. 카메라 영상에도 관원 효과를 같이 주고 싶으신 것 같습니다. (이게 맞는건지 잘 모르겠네요 ^^) 카메라 프리뷰를 다르게 보여주려면 프리뷰 이미지 데이터 자체를 후처리 후에 SurfaceView에 띄워주는 식으로 해야 제대로 적용이 될 겁니다.

  5. Blog Icon
    퐁듀

    소스파일 그대로 옵티머스원 기기에서 실행시켜보았는데요,
    예기치 못한 오류가 발생했다면서 (즉, 런타임에러..)
    바로 죽어버리네요. 안드로이드사이드에서 어떤 분이 같은 증상에 대해
    넥서스원은 parameters.setPreviewsize(800,480);으로 고정시키면 된다기에
    그렇게도 해보고, 옵티머스원에 맞춰 320, 480로도 해보았는데 죽는건 여전하네요.
    혹시 답변해주실 수 없는지요?ㅜㅜ

  6. 로그캣 에러 내용을 확인해보는게 좋을듯 하네요. 단순히 런타임 에러 났다는 사실만으로는 해결방법을 알 수 없습니다 :)

  7. Blog Icon
    해본결과

    //mCamera.setParameters(parameters);
    파라미터를 set할 경우 runtime error가 발생합니다.
    저는 그냥 주석 처리했습니다.

    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): FATAL EXCEPTION: main
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): java.lang.RuntimeException: setParameters failed
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.hardware.Camera.native_setParameters(Native Method)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.hardware.Camera.setParameters(Camera.java:647)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at com.androidhuman.example.CameraPreview.Preview.surfaceChanged(CameraPreview.java:69)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.SurfaceView.updateWindow(SurfaceView.java:538)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.SurfaceView.dispatchDraw(SurfaceView.java:339)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.View.draw(View.java:6911)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.widget.FrameLayout.draw(FrameLayout.java:352)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.View.draw(View.java:6911)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.widget.FrameLayout.draw(FrameLayout.java:352)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1848)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.ViewRoot.draw(ViewRoot.java:1407)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.ViewRoot.performTraversals(ViewRoot.java:1163)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.view.ViewRoot.handleMessage(ViewRoot.java:1727)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.os.Handler.dispatchMessage(Handler.java:99)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.os.Looper.loop(Looper.java:123)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at android.app.ActivityThread.main(ActivityThread.java:4627)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at java.lang.reflect.Method.invokeNative(Native Method)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at java.lang.reflect.Method.invoke(Method.java:521)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:870)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
    04-25 13:47:03.481: ERROR/AndroidRuntime(14571): at dalvik.system.NativeStart.main(Native Method)
    04-25 13:47:03.489: WARN/ActivityManager(1715): Force finishing activity com.androidhuman.example.CameraPreview/.CameraPreview

    그리고 중간에 써주신 분처럼 mCamera.release(); 루틴이 들어가야 안정적인 app가 되는 것 같습니다.
    좋은 강좌 감사합니다 ^^

  8. 위 예제의 개선된 버전은 책 6장의 예제코드에 포함되어있습니다 :)

  9. Blog Icon
    홍텐

    카메라로 촬영 후 바로 저장하고, 촬영된 사진을 불러와서 이미지뷰에 띄어준 다음 전송버튼을 눌러서 웹서버로 전송하려는 액티비티를 만들고 있습니다. 현제 모든 기능이 정상 작동하나 문제가 하나 있습니다. 바로 이미지의 크기인데요
    애초에 촬영 후 저장된 사진을 불러올 때 썸네일 이미지를 불러오고 그 썸네일 이미지를 웹서버로 보냅니다. 이 부분에서 저는 썸네일 이미지가 아닌 실제 안드로이드 갤러리에 저장된 이미지를 가져와서 이미지뷰에 뿌리고 그걸 웹서버로 전송하고 싶은데 onActivityResult에서 썸네일이 아닌 실제 갤러리에 저장된 이미지를 받을려면 어떻게 해야할까요?

  10. 카메라로 사진을 촬영하거나 갤러리에서 이미지를 선택한 경우 인텐트의 데이터(Data)를 통해 이미지의 고유 주소(Uri)를 얻을 수 있습니다. (Intent.getData())

    이를 사용하면 원본 이미지에 접근하는 것이 가능합니다.

  11. 에서 저는 썸네일 이미지가 아닌 실제 안드로이드 갤러리에 저장된 이미지를 가져와서 이미지뷰에 뿌리고 그걸 웹서버로 전송하고 싶은데 onActivityResult에서 썸네일이 아닌 실제 갤러리에 저장된 이미지를 받을려면 어떻게 해

  12. http://developer.android.com/reference/android/provider/MediaStore.Images.Media.html

    참고하세요.

  13. Blog Icon
    유혈

    안녕하세요~ 커니님 !!
    강좌를 잘보고있습니다~
    여쭤보고싶은게 한가지있습니다
    AR기능처럼 카메라 위에 이미지를 띄우고싶은데 레이아웃을 만든다음 불러오면은되는건가요??!!
    또 AR기능은 어떤식으로 구현되는지도 궁금합니다

  14. FrameLayout을 사용해서 카메라 프리뷰와 AR 객체를 표시하는 뷰를 겹쳐 표시하면 됩니다 :)

    AR기능은... 유형에 따라 천차만별이여서 딱히 어떤식으로 구현되는지 말씀드리기가 어렵네요.

  15. Blog Icon
    아무거나냐

    커니님 카메라 프리뷰위에 FrameLayout 으로 ImageView 겹치게 해서 보여주고
    사진찍기 눌렀을때 함께저장하고 싶은데 어떻게 해야할까요?
    화면캡쳐기능으로 될까 해봤는데 안되더라구요..

  16. 카메라 프리뷰 화면이 표시되는 SurfaceView는 화면 캡쳐를 통해 캡쳐되지 않습니다. 사진을 촬영한 후 그림을 합성하는 방법 등을 사용해야 할 듯 합니다.

  17. Blog Icon
    ㅇㄹㅇㄹ

    커니님 궁금한게 잇는데
    카메라 뷰에 만약 프레임레이아웃으로 카메라 뷰 위에 버튼을 하나 만들어노면
    사진 찍엇을때 그 버튼부분이 검게 안나타나게 할 방법이 없을까요 ?
    사진 찍기 전에 autofocus전에 그 버튼을 안보이게 해도
    사진 찍을때의 파일을 보면 검은 부분이 없는데 딱 찍는게 끝나고 찍힌 사진보면 검은 부분이 나타나네요...
    왜이럴까요 ? 레이아웃을 게속 바꿔보면서 해봣는데..

  18. 잉???
    그런현상은 처음 들어보네요....

    보통 RelativeLayout을 사용하여 버튼 배치하곤 하는데, 촬영 결과물은 뷰 위에 뭐가 올라가느냐랑은 상관이 없습니다.

    <ViewGroup>
    <SurfaceView>.. </SurfaceView>
    <Button> .. </Button>
    </ViewGroup>

    이런식의 레이아웃이라면 전혀 문제가 없습니다.

  19. Blog Icon

    카메라어플을 구동시키는데, 카메라찍는화면위에 이미지하나를 가져와서 보이게 할수가 있나요??

  20. 강좌 정말 도움되고 재미지게 잘 보았습니다.

  21. Blog Icon
    쉼짱

    메일로 문의 드렸는데 아직 못보신거 같아요~!!
    카메라 관련된 앱을 만들고 있는데 질문사항이 있어서요^^

  22. 죄송합니다.최근 복학해서 정신이 없네요..ㅠㅠㅠ

  23. Blog Icon
    이재상

    질문 있습니다. 안드로이드 초보라서 허접한 질문인데요 ㅠㅠ
    저기 프리뷰 사이즈를 줄이고싶은데 어떤식으로 해야는지 좀 알려주실수 있을까요?
    파라미터의 사이즈를 적어도 별 달라지는거 없는거 같구요
    사이즈 줄이는것하고 그화면을 원하는 위치에 두는 방법좀 알려주시면 감사하겠습니다.

  24. Blog Icon
    김준범

    안녕하세요 커니님
    제가 실시간 영상처리를 해보려고하는데
    open CV를 사용하지 않고 안드로이드 안면인식 API를 써서하려고하는데
    가능할까요?ㅠㅠ 어떤식으로 하면 될까요?ㅠㅠ

  25. Blog Icon
    봄날의 곰

    항상 잘 보고있습니다..출처 남기고 퍼갑니다..^^*..

  26. 좋은자료 잘 보았습니다 ^^

  27. Blog Icon
    감사

    감사합니다.

  28. Blog Icon
    안드로이드 초보..

    앱을 만들고 있는 학생인데요... 카메라 프리뷰를 넣었는데요.. 화면에 그냥 검은 사각형으로만 나와서 어떤 방법을 써보아도... 카메라가 나오지 않아서 질문드립니다.. 저는 사각틀안에 프리뷰를 넣었는데 왜 나오지 않는 것인지 도무지 이해가 되지않습니다..ㅠㅠ

    package exam.androidfirst;

    import java.io.*;
    import java.util.*;

    import android.app.*;
    import android.content.*;
    import android.graphics.drawable.*;
    import android.hardware.*;
    import android.hardware.Camera.Parameters;
    import android.hardware.Camera.Size;
    import android.os.*;
    import android.util.*;
    import android.view.*;
    import android.view.View.OnClickListener;
    import android.widget.*;
    import android.os.CountDownTimer;

    public class Fun1Activity extends Activity {
    MyCameraSurface mSurface;
    Button mShutter;
    TextView mMainText;
    Parameters mParam;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.i1);

    mSurface = (MyCameraSurface)findViewById(R.id.preview);
    mMainText = (TextView)findViewById(R.id.mainvalue);

    new CountDownTimer(20000,1000){
    public void onTick(long millisUntilFinished) { //<타이머가 종료될때까지 동작하는 함수>
    mMainText.setText("남은 시간 : " + millisUntilFinished / 1000);
    //mParam.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
    }
    public void onFinish() { //<타이머가 종료될때 실행 동작하는 함수>
    Intent intent = new Intent(Fun1Activity.this, Fun1_1Activity.class);
    startActivity(intent);
    }
    }.start();


    Button pre_button = (Button)findViewById(R.id.pre_button);
    Drawable a4 = pre_button.getBackground();
    a4.setAlpha(400);


    pre_button.setOnClickListener(
    new OnClickListener(){
    public void onClick(View v){
    Log.i("Multi Activity", "Button click is occured..";);
    Intent intent = new Intent(Fun1Activity.this, MainActivity.class);
    startActivity(intent);
    }
    }
    );
    }

    }
    class MyCameraSurface extends SurfaceView implements SurfaceHolder.Callback {
    SurfaceHolder mHolder;
    Camera mCamera;

    public MyCameraSurface(Context context, AttributeSet attrs) {
    super(context, attrs);
    mHolder = getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    // 표면 생성시 카메라 오픈하고 미리보기 설정
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    mCamera = Camera.open();
    try {
    mCamera.setPreviewDisplay(mHolder);
    } catch (IOException e) {
    mCamera.release();
    mCamera = null;
    }
    }

    // 표면 파괴시 카메라도 파괴한다.
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    if (mCamera != null) {
    mCamera.stopPreview();
    mCamera.release();
    mCamera = null;
    }
    }

    // 표면의 크기가 결정될 때 최적의 미리보기 크기를 구해 설정한다.
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    Camera.Parameters params = mCamera.getParameters();
    List<Size> arSize = params.getSupportedPreviewSizes();
    if (arSize == null) {
    params.setPreviewSize(width, height);
    } else {
    int diff = 10000;
    Size opti = null;
    for (Size s : arSize) {
    if (Math.abs(s.height - height) < diff) {
    diff = Math.abs(s.height - height);
    opti = s;

    }
    }
    params.setPreviewSize(opti.width, opti.height);
    }
    mCamera.setParameters(params);
    mCamera.startPreview();
    }
    }


    이것은 xml입니다.
    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/home_root"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#111111">

    <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
    android:id="@+id/mainvalue"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="20dp" />

    </LinearLayout>

    <LinearLayout
    android:layout_width="300dip"
    android:layout_height="0dip">

    <exam.androidfirst.MyCameraSurface
    android:id="@+id/preview"
    android:layout_marginLeft="200dip"
    android:layout_width="100dip"
    android:layout_height="100dip"
    /></LinearLayout>

    <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:background="#00000000" >

    <ImageView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
    </LinearLayout>


    <LinearLayout

    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    </LinearLayout>

    <Button
    android:id="@+id/pre_button"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="360dip"
    android:background="@drawable/imgbutton2"
    android:text="@string/PrevString"
    android:textColor="#ffDDA0DD"
    android:textSize="20dp" />

    </LinearLayout>

  29. Blog Icon
    독학생

    고맙습니다!!!

  30. Blog Icon
    nova

    우앙 ㅋㅋㅋ 오랜만에 들어와봄