Android - obsługa kamery
Pierwszą czynnością, jaką wykonałem rozpoczynając mój projekt, było napisanie kodu odpowiedzialnego za obsługę kamery na urządzeniu. Konkretniej mówiąc, chodzi o przechwytywanie obrazu z kamery i wyświetlanie go na ekranie urządzenia. W przpadku Androida zadanie to okazało się trywialne (przynajmniej na chwilę obecną tak mi się wydaje) - nieocenionym źródłem pomocy okazał się serwis StackOverflow. Poniżej znajduje się mały tutorial "jak obsłużyć kamerę".
Po pierwsze: model zastosowany w systemie wymaga od nas, abyśmy do pliku AndroidManifest dodali odpowiedni kod umożliwiający korzystanie z kamery. Jest to jedna linijka:
<uses-permission android:name="android.permission.CAMERA" />
Jeżeli nie dodamy powyższego uprawnienia i spróbujemy użyć kamery w naszej aplikacji lub dodamy, lecz użytkownik podczas instalacji nie wyrazi zgody na wykorzystanie kamery przez aplikację, wyrzucony zostanie wyjątek SecurityException
Należy także dodać tag <uses-feature>, które będą informować inne aplikacje co wykorzystujemy:
<uses-feature android:name="android.hardware.camera" />Teraz możemy spokojnie "wyciągnąć" obraz z kamery. Ja, wzorując się na poście ze StackOverflow, zrobiłem to w następujący sposób. Najpierw zaimplementowałem klasę CameraManager dziedziczącą po SurfaceView, która dostarcza "powierzchni" do rysowania i zapewnia, że jest ona odpowiednio usytuowana w hierarchii widoków.
CameraManager jest swojego rodzaju łącznikiem pomiędzy kodem Activity a kamerą. Składa się ona tylko z konstruktora w którym zapewniamy sobie dostęp SurfaceHolder odpowiedzialnego za aktualizację bufora wide(?) i rejestrujemy na nim funkcję zwrotną, która zajmować się będzie aktualizacją obiektu Surface. Poniżej kod klasy:
public class CameraManager extends SurfaceView { private SurfaceHolder mSurfaceHolder; public CameraManager (Context pContext) { super (pContext); mSurfaceHolder = this.getHolder(); mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); SurfaceHolderCallback lSurfaceHolderListener = new SurfaceHolderCallback (); mSurfaceHolder.addCallback (lSurfaceHolderListener); } }
Szkielet obsługi został więc napisany, teraz czas na jego serce, czyli implementację interfejsu SurfaceHolder.Callback, który otrzymuje informacje na temat zachowania powierzchni do rysowania i pozwala przeprowadzać na różnego rodzaju akcje/manipulacje. Interfejs ten dostarcza trzy publiczne metody:
- surfaceCreated, która jest wywoływana, kiedy powierzchnia jest tworzona po raz pierwszy
- surfaceChanged, która jest wywoływana, kiedy powierzchnia zostanie w jakiś sposób zmieniona
- surfaceDestroyed, wywoływana, kiedy powierzchnia zostanie zniszczona
Ja postanowiłem, że klasa SurfaceHolderCallback przechowywać będzie referencję do obiektu kamery. W metodzie surfaceCreated umieściłem kod, który tworzy nowy obiekt klasy Camera oraz ustawiłem dla niej powierzchnie na której będzie wyrysowany obraz z kamery. Następnie w metodzie surfaceChanged umieściłem kod odpowiedzialny za "przetwarzanie" obrazu a w metodzie surfaceDestroyed kod odpowiedzialny za zwolnienie kamery. Kod klasy znajduje się poniżej:
class SurfaceHolderCallback implements SurfaceHolder.Callback { private Camera mCamera; public void surfaceCreated (SurfaceHolder pSurfaceHolder) { mCamera = Camera.open(); try { mCamera.setPreviewDisplay(pSurfaceHolder); } catch (Exception ex) { ex.printStackTrace(); } } public void surfaceChanged (SurfaceHolder pSurfaceHolder, int pFormat, int pWidth, int pHeight) { Parameters lCameraParams = mCamera.getParameters(); lCameraParams.setPreviewSize (pWidth, pHeight); lCameraParams.setPictureFormat (PixelFormat.JPEG); mCamera.setParameters (lCameraParams); mCamera.startPreview(); } public void surfaceDestroyed (SurfaceHolder pSurfaceHolder) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } }
Z pewnością kod ten trzeba poprawić: jeszcze nie wiem, czy surfaceDestroyed jest wywoływana podczas wywoływania metody onPause i czy surfaceCreated jest wywoływana przy wywoływaniu onResume. Nie doczytałem się tego w dokumentacji a nie miałem jeszcze okazji przetestować kodu na urządzeniu
Zainteresowanych zachęcam do pobrania kodu z repozytoriun i przetestowania kodu a tych, którzy już pisali na Androida zachęcam do konstruktywnej krytyki oraz zgłaszania błędów w Issue trackerze!
edit: polecam przeczytać mały update do tegopostu
Komentarze do wpisu
Możesz śledzić odpowiedzi poprzez kanał RSS. Możesz dodać komentarz lub zostawić ślad (trackback) ze swojego bloga.
Jeszcze nie ma żadnych komentarzy. Twój może być pierwszy.
Dodaj komentarz