Mobile

[안드로이드] (9)안드로이드 Camera

OSS 2013-01-04 16:49:13 37020
임베디드월드

글: 라영호 | ratharn@naver.com / 2012-12-03


[연재 차례]

1. 안드로이드 시스템의 역사 및 동향
2. 안드로이드 시스템과 리눅스
3. 안드로이드 플랫폼의 이해
4. 안드로이드 바인더(Binder)의 이해
5. 안드로이드 서비스
6. 안드로이드 SurfaceFlinger와 프레임버퍼 드라이버
7. 안드로이드 User Interface와 ADK2012
8. Linux Sound Device와 안드로이드 사운드 시스템
9. 안드로이드 카메라 시스템
10. 안드로이드 카메라와 멀티미디어 프레임워크
11. 안드로이드 카메라와 멀티미디어 프레임워크 ②
12. 안드로이드 시스템 디버깅 및 기타



안드로이드 시스템 개발자를 위한 안드로이드 시스템의 분석 및 이해 ⑨
안드로이드 Camera 시스템

12월호에서는 안드로이드에서 시스템의 카메라를 어떻게 처리하는지에 대해 확인해 보도록 하겠다. 현재 카메라는 스마트폰 및 임베디드 시스템에 장착된 필수적인 시스템으로 사진뿐만 아니라 동영상을 촬영하는데 있어 필수 장치로 포함되고 있다. 다른 장치와 달리 하드웨어적인 도움을 많이 받는 장치이기 때문에 단순히 카메라뿐만 아니라 카메라로부터 넘겨받은 영상정보를 JPEG과 같은 이미지 파일 형식으로 압축을 하고 MPEG4와 같은 동영상 형식으로 압축을 하는 코덱과 밀접한 관계를 가지고 있다. 현재 출시되고 있는 임베디드 프로세서의 대부분의 구조는 이러한 멀티미디어를 처리할 수 있는 멀티미디어 코덱을 포함하고 있기 때문에 카메라로부터 어떻게 코덱으로 압축하는 과정을 구현할 것인가가 카메라를 포함한 멀티미디어 시스템을 이해하는데 있어 중요한 역할을 한다.

리눅스에서 카메라
일반적인 리눅스와 Embedded Linux 시스템에서의 카메라는 크게 두 가지 카테고리로 분류된다. USB 카메라 형태이다. USB라는 만능 디바이스를 통해 카메라를 연결해 사용하는 형태를 말한다. 이 형태는 과거 리눅스가 PC기반으로 탄생되었음에 기인한다. 그래서 PC에서는 카메라 서브시스템이 따로 존재하지 않았고, USB 형태로 연결하여 사용하는 형태로 구성되었다.

ARM 등 임베디드 프로세서를 사용하는 모바일 디바이스에 사용되는 SoC(System on Chip) 기반의 카메라 인터페이스이다. 모바일 CPU들은 작은 면적 안에 많은 디바이스들을 컨트롤 할 수 있어야 활용성이 크기 때문에 코어 이외에 부가장치들을 SoC로 붙여서 만들어 놓고 있다. 따라서 다양한 부가 디바이스들을 하드웨어적으로 컨트롤하기 쉽다. 우리가 사용하는 핸드폰/PDA/스마트폰 등에 들어있는 CPU는 주로 ARM 계열로 핸드폰에 사용되는 카메라들은 주로 프로세서나 모뎀에서 제공하는 SoC 형태의 카메라 인터페이스를 사용한다.

일반적인 PC용 USB 카메라와 모바일에서의 SoC 형태의 카메라 인터페이스 모두 공통된 API를 통해 유저 스페이스에서 카메라를 컨트롤하게 되어 있으며 리눅스에서 이러한 표준은 Video for linux 부분에서 정의되어 있다.

V4L2(Video for Linux 2)
: audio/video capture 및 overlay 장치와 FM 라디오를 지원

V4L 리눅스 커널이 제공하는 비디오 캡쳐/오버레이 API의 오리지널 버전
리눅스 커널 2.1.x 부터 추가
V4L2 V4L의 설계상의 버그를 수정
리눅스 커널 2.5.x 부터 추가

Video For Linux(V4L)은 TV튜너나 USB웹 카메라 같은 다양한 비디오 캡처 디바이스에 접근을 가능하게 해주는 하나의 API이다.

Android Camera의 전체 구조


[그림1]은 안드로이드 시스템 중 카메라 시스템의 구조 및 역할을 보여주는 그림이다.

Application Layer
최상위단의 Application이다. 이 부분에 카메라를 사용하기 위해 카메라를 오픈 하고 관리 하는 부분이 들어있다.

Android Runtime
JNI 인터페이스를 담당한다. JNI method를 Android Runtime에 등록 하고, 등록된 매소드를 실제 Android Library의 실제 camera client 코드와 연결하는 부분으로 구성되어 있다.

Library Layer
두 개의 모듈로 camera interface가 분리되어있다.

● Camera service Camera의 실제 코드를 동작시키며, Camera client로부터의 입력에 대한 camera service를 담당한다.
● Camera client JAVA app에서 JNI를 통해서 내려온 Camera interface에 대한 동작을 처리하며 이 동작에 대한 service를 Camera service daemon으로 요청한다.

Camera Hardware Abstraction Layer(HAL)
Android입장에서 바라본 실제 카메라 인터페이스의 추상화 계층이다. 실제 camera device driver의 바로 위에 올라가는 Camera hardware 제어 모듈이다. Camera device driver는 기존의 V4L2를 지원하는 디바이스이거나 해당 SoC 혹은 target board에 알맞은 전용 드라이버를 지원할 수 있도록 구성되어 있다.

Camera device driver
Chip vendor의 지원에 따라 camera device driver의 구현은 여러 가지 방법으로 이루어 질 수 있다. 근래 대부분의 chip vendor에서는 Video for Linux 2 형태의 device driver를 제공한다. SoC쪽 device driver만 제공하는 경우가 많고, 실제 target에 장착되는 camera의 경우 다양한 종류의 camera일 수 있기 때문에 적절한 방법으로 camera driver를 포팅해야 한다. 즉, 실제 장착되는 카메라 모듈에 따라 카메라에 대한 제어, 관리 등의 코드를 구현해야 하는 영역이다.


Android Camera Framework
Android Camera는 복잡한 구성으로 되어있다. JAVA를 이용한 응용프로그램이고, 실제코드는 C/C++로 이루어졌다. 그 인터페이스가 여러 모듈로 분산되어 있어 복잡하다.
카메라 관련 Class간의 구성은 다음과 같다.


Android camera 전체 구조에서 볼 수 있듯이 Android의 경우는 JAVA와 C/C++이 섞여 있는 구조로 되어 있다. 이러한 구조 때문에 전체 framework는 여러 가지 부분으로 분리될 수 있다.

Camera 전체 Framework
JAVA Program이 최상위 Application으로 동작한다. 이 Application은 Android용 JAVA VM인 Dalvik VM 에 의해 해석된다. (SDK에서 Dalvik bytecode로 만들 수 있게 되어 있다.) Android Runtime 에 의해 Camera 관련 Library가 호출되고 Library 에서는 복잡한 Binder 통신을 통해 HAL 계층과 연결된다. 그리고 결국 실제 Camera 단에 이르러 Camera를 작동시킬 수 있다

Application
/packages/apps/Camera/src/com/android/camera/Camera.java.는 기본적으로 Android 소스에 포함되어 있는 카메라 응용 프로그램의 소스다.

Application Framework
frameworks/base/core/java/android/hardware/Camera.java.는 카메라 객체를 생성 해서 돌려준다(JAVA). (생성하는 부분에 JNI interface 호출코드가 있다.)

Android Runtime
frameworks/base/core/jni/android_hardware_Camera.cpp.는 JNI에 관련된 부분이다. JAVA와 C++을 연결한다. framworks/base/core/jni/AndroidRuntime.cpp에서 Android 의 VM에 등록해준다.

Library Layer
frameworks/base/media/mediaserver/main_mediaserver.cpp.는 오디오, 미디어플레이어, 카메라 등을 초기화시킨다. frameworks/base/camera/libcameraservice/ CameraService.cpp

ServiceManager에 media.camera를 등록시킨다. connect 를 함으로써 카메라에 연결할 수 있는 카메라 인스턴스를 생성한다. Client 함수에서 실제 하드웨어를 오픈 한다. frameworks/base/libs/ui/Camera.cpp에서는 connect() 호출함으로써 3개의 Binder 연결이 생성된다. 가장 기초적인 기능을 담당하는 역할을 한다. libandroid _runtime.so 의 Camera Class에 의해서 호출되는 인터페이스 부분을 담당하게 된다. android.hardware.camera category의 실현부분을 담당하게 된다.(즉, 보여지는 부분을 담당하게 된다.)

Hardware Abstraction Layer
frameworks/base/camera/libcameraservice/CameraHardwareStub.cpp CameraHardwareStub.cpp의 method들이 호출되면서 커널의 실제 camera device driver 부분에 대한 요청이 이루어진다. frameworks/base/camera/libcameraservice/FakeCamera.cpp기본적인 camera hardware를 emulation한 camera interface 이다. 실제 hardware에 대한 부분은 없지만, 필요한 기능은 들어있으므로 실제 하드웨어 구현에 대한 참고용으로 아주 유용하다.


Camera Library의 내부 동작


Camera Library 내부는 [그림5]와 같이 Client와 Server 두 부분으로 되어 있다. Android Process 간 Binder라는 Interface 이용해 통신하게 된다. Camera 프로그램은 Server의 함수를 호출하기 위하여 Client의 인터페이스를 호출한다. 이 동작은 실제로 Client가 Server의 함수를 직접 호출하는 것처럼 보여지고, IPC 통신 (Binder)부분은 보이지 않는다.

Android Camera Class의 구조도


Camera의 전체 구조에서 Camera category는 전체 시스템의 핵심이다. ICameraClient Class는 Interface의 메인을 담당하며 Client 영역에서 호출된다. Camera Service는 실제 Camera의 동작을 시키기 위한 하드웨어 인터페이스를 담당하는 서비스이다. 경계선이 빨간 점선으로 되어 있는 부분이 Camera Framework이다. 이 부분은 Binder를 이용하여 전체가 구성되며, 하나의 Framework으로 이루어지게 된다. 파란색으로 되어 있는 부분은 적절한 하드웨어 인터페이스를 호출함으로써 Camera Service 기능을 담당한다. 연두색 부분의 ICameraService는 Camera class에 의해서 호출되며 Camera class는 java program으로부터 호출되는 JNI 인터페이스를 제공하게 된다. 왼쪽 부분의 전체 구조는 Client처럼 보이며 오른쪽은 서버로 동작한다. 이 두 부분은 Binder를 통해서 동작하게 되어 있다.
안드로이드 소스의 java로 작성된 Camera 코드 예제는 다음에 있다.

▶ packages/apps/Camera/src/com/android/camera/
▶ Camera.java -> Main 코드 부분(camera java part class)
JAVA local call(JNI)의 Camera Part는 다음과 같고, 이 소스는 libandroid_runtime.so 의 일부가 된다.
▶ Frameworks/base/core/jni/android_hardware_
Camera.cpp
Camera에 대한 class에 대한 정의
▶ Frameworks/base/include/ui/
Camera Class코드
▶ Frameworks/base/libs/ui/는 후에 libui.so 의 일부분이 된다.
Camera Service 부분
▶ Frameworks/base/camera/libcameraservice/는 후에 libcameraservice.so 를 이루게 된다.
Camera관련 함수를 얻으려면 밑단의 Hardware 관련 Camera 라이브러리가 필요하다. (예를 들어 V4L 드라이버 혹은 JPEG encoding program). 이 라이브러리는 libcameraservice.so 라이브러리의 Camera service call 부분이 된다. (HAL이 된다.)
Camera 관련 메인 헤더 파일들은 다음과 같다.
▶ Camera.h - Camera.h는 최상위 인터페이스를 제공한다.
▶ ICameraService.h, ICameraClient.h
▶ ICamera.h - ICameraService.h, ICameraClient.h, ICamera.h
세 개의 Class는 Binder Interface를 위해 사용되는 것이며, ICameraService.cpp 와 Camera.cpp는 Camera의 구현에 관련된 코드이다.
▶ CameraHardwareInterface.h - Camera에 연관된 하위단의 hardware 관련 부분은 CameraHardware Interface Class를 통해서 이루어진다.

ICameraClient.h

namespace android {
class ICameraClient: public Iinterface // Iinterface를 상속받는 ICameraClient 를 만들게 된다.
{public:
DECLARE_META_INTERFACE(CameraClient);
virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
virtual void dataCallback(int32_t msgType, const sp<IMemory>& data) = 0;
virtual void dataCallbackTimestamp (nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) = 0;
};
//
class BnCameraClient: public BnInterface <ICameraClient> //이곳은 ICameraClient와 BnInterfac를 상속받는 BnCameraClient 를 만든다.
{public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0); };

위의 Class에서 ICameraClient는 IInterface에서 상속받은 형태이며, Camera Interface의 Client를 담당하게 된다. BnCameraClient는 BnInterface <ICameraClient>로부터 상속받은 형태이며, 이것은 Android의 기반인 Binder 메커니즘을 이용하는 통신의 기반이 된다. BnInterface class는 BnInterface <ICameraClient> 템플릿을 이용한 것으로, 이것은 두 개(BnInterface와 ICameraClient)로부터 상속받은 것과 동일한 것이 된다. ICameraClient의 메인 인터페이스는 몇 개의 Callback 함수들로 이루어 진다. "Client"로서의 Camera는 필요할 때 이와 같은 Callback 함수를 호출함으로써 이루어지고, Server 프로그램은 “간접적”으로 함수를 호출하게 된다 (Server측의 Callback 관련함수들).

Camera.h

class Camera : public BnCameraClient, public IBinder::DeathRecipient {
public:
// construct a camera client from an existing remote
Camera(const sp<ICamera>& camera);
static sp<Camera> connect();
~Camera();
void init();
status_t reconnect();
void disconnect();
status_t lock();
status_t unlock();
status_t getStatus() { return mStatus; }
// pass the buffered ISurface to the camera service
status_t setPreviewDisplay(const sp<Surface>& surface);
status_t setPreviewDisplay(const sp<ISurface>& surface);
status_t startPreview(); // start preview mode, must call setPreviewDisplay first
void stopPreview(); // stop preview mode
bool previewEnabled(); // get preview state
// ICameraClient interface
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);

sp<ICamera> remote();
Camera 외부 인터페이스는 Camera.h를 통해서 이루어진다. 이것은 android_hardware_Camera.cpp에 의해 호출된다. Camera.h는 Camera를 다루는데 있어서 가장 중요한 부분이다. Camera Class에서의 Camera 기본조작은 player (startPreview), stop (stopPreview), suspended (takePicture)등과 같은 기본적인 동작을 획득함으로써 이루어진다.
Camera class의 connect() 함수는 static이며 camera를 실현하는데 사용이 된다.(connect를 호출하면서 camera가 동작하게 된다) 위 클래스에서 몇 개의 함수들을 셋업하게 되어 있다.
notifyCallback, dataCallback, dataCallback Timestamp 이 함수들은 상위단으로 기능을 제공되는데 사용된다. 상위 단의 몇 개의 세팅은 이 콜백함수를 이용하여 이루어지게 되어 있다.

ICamera.h

class ICamera: public IInterface {
public:
DECLARE_META_INTERFACE(Camera);
virtual void disconnect() = 0;
// connect new client with existing camera remote
virtual status_t connect(const sp<ICameraClient>& client) = 0;
virtual void setPreviewCallbackFlag(int flag) = 0; // preview are handled.
virtual status_t startPreview() = 0; // start preview mode, must call setPreviewDisplay first
virtual void stopPreview() = 0; // stop preview mode
-
-
-
virtual void releaseRecordingFrame (const sp<IMemory>& mem) = 0; // release a recording frame
virtual status_t autoFocus() = 0; // auto focus
virtual status_t takePicture() = 0; // take a picture
// set preview/capture parameters - key/value pairs
virtual status_t setParameters(const String8& params) = 0;
// get preview/capture parameters - key/value pairs
virtual String8 getParameters() const = 0; };

class BnCamera: public BnInterface<ICamera> {
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0); };

ICamera.h는 Camera 인터페이스의 구현을 담당한다. Camera 계열의 Class중 Camera Interface의 메인 함수를 담당한다. 이 Class 는 사용하기 위해서 반드시 상속되어야 한다. Interface 는 항상 Bn과 Bp 쌍으로 만들어야 한다. 이 Interface는 위에서 설명한 Camera interface와 다소 비슷하지만 직접적으로 연관은 없다. ICamera category를 호출함으로써 Camera 구현이 완성 되게 된다

ICameraService.h

class ICameraService : public Iinterface // Iinterface를 상속받는 ICameraService를 만들게 된다.
{
public:
enum {
CONNECT = IBinder::FIRST_CALL_TRANSACTION,
};
public:
DECLARE_META_INTERFACE(CameraService);

virtual sp<ICamera> connect(const sp<ICamera Client> & cameraClient) = 0;
};
//

class BnCameraService: public BnInterface <ICameraService>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0); };

Camera에서 사용되는 ICameraService.h 인터페이스는 위와 같다. 앞서 본 ICameraClient와 거의 같은 구조로 되어 있다. ICameraService.h 는 Camera의 service를 제공하는데 사용된다. Virtual 함수 때문에 ICameraService와 BnCameraService 는 반드시 상속되어야 한다. ICameraService를 보면 오직 connect() interface 만 존재하고, 이것의 return 값은 sp <ICamera> 타입이다. 이 함수의 실제 구현은 ICamera interface에서 제공이 된다. ICameraService는 오직 connect() 함수만 존재한다. 하지만 여기에는 disconnect() 함수가 없다. disconnect()는 ICamera interface에서 제공 된다.

CameraHardwareInterface.h

class CameraHardwareInterface : public virtual RefBase {
public:
virtual ~CameraHardwareInterface() { }
/** Return the IMemoryHeap for the preview image heap */
virtual sp<IMemoryHeap> getPreviewHeap() const = 0;
/** Return the IMemoryHeap for the raw image heap */
virtual sp<IMemoryHeap> getRawHeap() const = 0;
virtual status_t startPreview(preview_callback cb, void* user) = 0;
virtual bool useOverlay() {return false;}
virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
virtual void stopPreview() = 0;
-
-
virtual status_t autoFocus(autofocus_callback, void* user) = 0;
virtual status_t takePicture(shutter_callback, raw_callback, jpeg_callback, void* user) = 0;
virtual status_t cancelPicture(bool cancel_shutter, bool cancel_raw, bool cancel_jpeg) = 0;
virtual status_t setParameters(const CameraParameters& params) = 0;
virtual CameraParameters getParameters() const = 0;
//Release the hardware resources owned by this object.
//Note that this is *not* done in the destructor.
virtual void release() = 0;
virtual status_t dump(int fd, const Vector<String16>& args) const = 0; };
extern "C" sp<CameraHardwareInterface> openCameraHardware(); };

CameraHardwareInterface.h는 Camera Interface에서의 가장 밑의 계층을 나타낸다. 이 class의 구현은 Camera의 실제 구현이다. C 언어를 사용하기 위해서는 symbol을 export한다. extern "C" sp<Camera HardwareInterface> openCameraHardware()라는 형태로 정의된다. openCameraHardware()의 사용은 CameraHardwareInterface의 사용의 시작이다.
실제 Camera의 HAL인 CameraHardwareInterface의 함수들을 구성해야만 Camera Interface에 대한 완벽한 호출을 처리할 수 있다.

App - Camera.java

import android.hardware.Camera.PictureCallback;
이것은 내부적으로 android.hardware.Camera를 포함하고 있다.
private android.hardware.Camera.Parameters mParameters;
private android.hardware.Camera mCameraDevice;
Camera.java 내부에 위와 같이 선언한다.
그리고 다음과 같이 android.hardware.Camera 에서 인터페이스로 되어 있는 것들을 상속 받아서 구현한다.
// Use OneShotPreviewCallback to measure the time between
// JpegPictureCallback and preview.
private final OneShotPreviewCallback mOneShotPreviewCallback =
new OneShotPreviewCallback();
private final ShutterCallback mShutterCallback = new ShutterCallback();
private final PostViewPictureCallback mPostViewPictureCallback =
new PostViewPictureCallback();
private final RawPictureCallback mRawPictureCallback =
new RawPictureCallback();
private final AutoFocusCallback mAutoFocusCallback =
new AutoFocusCallback();
private final ZoomCallback mZoomCallback = new ZoomCallback();
// Use the ErrorCallback to capture the crash count
// on the mediaserver
private final ErrorCallback mErrorCallback = new ErrorCallback();

파일에서는 android.hardware.Camera.* 의 인터페이스를 상속받아 실체를 구현한다. frameworks/base /core/java/android/hardware/Camera.java 에서는 native 코드와 연결이 되는데 실제 native 코드는 JAVA Application단에서 건드릴 수 없도록 final 로 선언되어 있다.

private native final void native_setup(Object camera_this);
private native final void native_release();
public native final int lock();
private native final void setPreviewDisplay(Surface surface);
public native final void startPreview();
public native final void stopPreview();

Appication framework - Camera.java

public interface PreviewCallback {
/* The callback that delivers the preview frames.
* @param data The contents of the preview frame in getPreviewFormat() format.
* @param camera The Camera service object. */
void onPreviewFrame(byte[] data, Camera camera);
};
public interface ShutterCallback {
/** Can be used to play a shutter sound as soon as the image has been captured, but before
* the data is available. */
void onShutter();
}
/** Handles the callback for the camera auto focus.*/
public interface AutoFocusCallback {
/** Callback for the camera auto focus.
* @param success true if focus was successful, false if otherwise
* @param camera the Camera service object*/
void onAutoFocus(boolean success, Camera camera);
};

위에서 interface로 선언된 것의 native 코드는 다음 코드에 있다.

typedef void (*notify_callback)(int32_t msgType,
int32_t ext1,
int32_t ext2,
void* user);
typedef void (*data_callback)(int32_t msgType,
const sp<IMemory>& dataPtr,
void* user);
typedef void (*data_callback_timestamp)(nsecs_t timestamp,
int32_t msgType,
const sp<IMemory>& dataPtr,
void* user);

Camera JNI
Camera의 JAVA 단과 C++단을 연결해주는 부분은 frameworks/base/core/jni/android_hardware_Camera.cpp 에 구현되어 있다. JNI 규격에 맞추어 구성되었다. 첫 번째 필드가 JAVA단의 함수명, 두 번째 필드는 함수의 형식, 세 번째 필드는 C++단의 함수명이다.

frameworks/base/core/jni/android_hardware_Camera.cpp 에서 JNI interface method는 다음과 같이 구현되어 있다
static JNINativeMethod camMethods[] = {
{ "native_setup",
"(Ljava/lang/Object;)V",
(void*)android_hardware_Camera_native_setup },
{ "native_release",
"()V",
(void*)android_hardware_Camera_release },
(중략)
{ "lock",
"()I",
(void*)android_hardware_Camera_lock },
{ "unlock",
"()I",
(void*)android_hardware_Camera_unlock },
};

frameworks/base/core/jni/android_hardware_Camera.cpp register_android_hardware_Camera() 함수에서 gMethods class로서 “android/hardware/Camera”를 등록하게 된다.
"android/hardware/Camera"는 JAVA의 패키지 명과 일치하도록 맞춰줘야 한다.

// Get all the required offsets in java class and register native functions
int register_android_hardware_Camera(JNIEnv *env)
{
....
// Register native functions
return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
camMethods,
NELEM(camMethods)); // ==> 여기서 JNI method가 등록됨
}
Camera local library - libui.so

frameworks/base/libs/ui/Camera.cpp파일에 Camera.h에 대한 기능 구현을 해 놓은 코드가 있다.
아래 코드 중 가장 중요한 포인트는 binder = sm->getService(String16("media.camera")); 부분이다. 이 것은 “media.camera' service를 얻기 위하여 호출되고, return type은 IBinder 형태이다. Camera::get CameraService() 코드는 ICameraService의 해당 코드의 type과 일치하는 것을 알 수 있다.

sp<ICameraService> Camera::mCameraService;
const sp<ICameraService>& Camera::getCameraService() {
Mutex::Autolock _l(mLock);
if (mCameraService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.camera"));
if (binder != 0) break;
LOGW("CameraService not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (mDeathNotifier == NULL) {
mDeathNotifier = new DeathNotifier(); }
binder->linkToDeath(mDeathNotifier);
mCameraService = interface_cast<ICameraService>(binder);
}
LOGE_IF(mCameraService==0, "no CameraService!?");
return mCameraService;
}

connect에 대한 실제 구현코드는 다음과 같다. 여기에서는 한번에 3개의 Binder 가 열리게 된다.
Camera를 생성하면서 하나가 자동으로 생성된다. 둘째로 getCameraService()를 호출함으로써 ICameraService를 connect하게 되고 이것이 또한 Binder이다. 세 번째 바로 밑의 코드인 cs->connec(c); 에서는 ICamera pointer를 return하게 된다. 여기서 한번 더 Binder가 만들어지는 것이다. connect()호출은 camera의 시작에 대한 기초가 된다.

frameworks/base/libs/ui/Camera.cpp 에서 발췌
sp<Camera> Camera::connect() {
sp<Camera> c = new Camera();
const sp<ICameraService>& cs = getCameraService();
if (cs != 0) {
c->mCamera = cs->connect(c); }
if (c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR; }
return c; }
Camera 의 멤버 변수에 다음과 같이 mCamera 가 sp<ICamera> 로 되어있다.
class Camera : public BnCameraClient, public IBinder::DeathRecipient {
public:
// construct a camera client from an existing remote
static sp<Camera> create(const sp<ICamera>& camera);
static sp<Camera> connect();
~Camera();
void init();
sp<ICamera> mCamera;
startPreview()는 아래와 같다. mCamera의 타입이 sp<ICamera> 이기 때문에 이것은 Binder를 통한 함수 호출이 된다.
sp <ICamera> c = mCamera;
return c->startPreview();

이 두 줄은 실제로는 Binder를 통해서 Bn쪽의 함수를 실행하는 것이다.
libmedia.so 에 있는 setDataSource 와 같은 다른 함수들의 구현은 다음과 같은 파일들에 존재하게 된다.

frameworks/base/libs/ui/ICameraClient.cpp
frameworks/base/libs/ui/ICamera.cpp
frameworks/base/libs/ui/ICameraService.cpp

frameworks/base/libs/ui/Camera.cpp 에서 발췌
// start preview mode
status_t Camera::startPreview()
{
LOGV("startPreview");
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->startPreview();
}

// stop preview mode
void Camera::stopPreview()
{
LOGV("stopPreview");
sp <ICamera> c = mCamera;
if (c == 0) return;
c->stopPreview();
}

ICameraClient.cpp, ICamera.cpp, ICamera Service.cpp의 BnCameraClient와 BnCameraService class는 onTransact() 함수를 이용해서 실제로 구현된다. 하지만, onTransact()에서 실제 virtual 함수를 구현하는 것은 아니다. 그리고 이 class들은 초기화 되지 않는다. BnCameraClient와 BnCameraService Class들은 실제로 각각 ICameraClient.cpp와 ICameraService.cpp에서 실제 구현되지 않고, Camera의 특정함수를 지원하기 위하여 계승자가 있을 때 실제로 구현된다.

frameworks/base/libs/ui/ICameraClient.cpp
status_t BnCameraClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
switch(code) {
case NOTIFY_CALLBACK: { . . . } break;
case DATA_CALLBACK: { . . . } break;
case DATA_CALLBACK_TIMESTAMP: { . . . } break;
default:
return BBinder::onTransact(code, data, reply, flags); } }
frameworks/base/libs/ui/ICamera.cpp
status_t BnCamera::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
switch(code) {
case DISCONNECT: { . . . } break;
case SET_PREVIEW_DISPLAY: {. . . } break;
case SET_PREVIEW_CALLBACK_FLAG: {. . . } break;
case START_PREVIEW: { . . .} break;
case START_RECORDING: {. . . } break;
. . . 이하 생략.
frameworks/base/libs/ui/ICameraService.cpp 에도 onTransact() 함수가 있음

끝으로
지금까지 안드로이드 시스템에서 사용하는 카메라 시스템에서 살펴봤다. 다음 호에서는 카메라 서비스 부분에 대해서 살펴보고 안드로이드 시스템에서 카메라와 밀접한 관계가 있는 멀티미디어 프레임웍에 대해 살펴 보도록 하겠다.



/필/자/소/개/

필자

라영호

국내 스마트폰의 초창기인 Cellvic에서부터 스마트폰을 개발하였고 윈도 모바일 및 다양한 임베디드 시스템을 개발하고 있다. 현재는 안드로이드 시스템 포팅 및 임베디드 시스템 개발, 컨설팅, 교육 등을 진행하는 회사를 운영하고 있다. 개인 블로그(www.embeddedce.com)를 통해 임베디드 시스템개발에 대한 다양한 생각과 방법론을 함께 생각해 보고자 노력 중이다.

※ 본 내용은 (주)테크월드(http://www.embeddedworld.co.kr)의 저작권 동의에 의해 공유되고 있습니다.
    Copyright ⓒ Techworld, Inc. 무단전재 및 재배포 금지

맨 위로
맨 위로