इस लेसन में, हम फ़्रेमवर्क एपीआई का इस्तेमाल करके, कैमरे के हार्डवेयर को सीधे तौर पर कंट्रोल करने का तरीका बताएंगे.
इस पेज पर, Camera क्लास के बारे में बताया गया है. यह क्लास अब काम नहीं करती. हमारा सुझाव है कि आप CameraX का इस्तेमाल करें. इसके अलावा, कुछ खास मामलों में Camera2 का इस्तेमाल भी किया जा सकता है. CameraX और Camera2, दोनों ही Android 5.0 (एपीआई लेवल 21) और इसके बाद के वर्शन पर काम करते हैं.
Camera1 से CameraX पर माइग्रेट करने का तरीका जानने के लिए, Camera1 से CameraX पर माइग्रेट करना लेख पढ़ें. इसके अलावा, Camera1 से CameraX पर माइग्रेट करने के लिए, एजेंटिक स्किल का इस्तेमाल किया जा सकता है.
डिवाइस के कैमरे को सीधे तौर पर कंट्रोल करने के लिए, मौजूदा कैमरा ऐप्लिकेशन से फ़ोटो या वीडियो का अनुरोध करने की तुलना में, ज़्यादा कोड की ज़रूरत होती है. हालांकि, अगर आपको कोई खास कैमरा ऐप्लिकेशन बनाना है या अपने ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में पूरी तरह से इंटिग्रेट किया गया कोई ऐप्लिकेशन बनाना है, तो इस लेसन में आपको इसका तरीका बताया गया है.
इसी विषय से जुड़े लिंक पढ़ें:
कैमरा ऑब्जेक्ट खोलें
Camera ऑब्जेक्ट का इंस्टेंस पाना, कैमरे को सीधे तौर पर कंट्रोल करने की प्रोसेस का पहला चरण है. Android के Camera ऐप्लिकेशन की तरह ही, कैमरे को ऐक्सेस करने का सुझाया गया तरीका यह है कि Camera को एक अलग थ्रेड पर खोला जाए, जिसे onCreate() से लॉन्च किया गया हो. यह तरीका सही है, क्योंकि इसमें कुछ समय लग सकता है और यूज़र इंटरफ़ेस (यूआई) थ्रेड धीमा हो सकता है. बेसिक तरीके से लागू करने पर, कैमरा खोलने की प्रोसेस को onResume() तरीके तक टाला जा सकता है. इससे कोड को फिर से इस्तेमाल करने में मदद मिलती है और कंट्रोल का फ़्लो आसान बना रहता है.
अगर कैमरा पहले से ही किसी दूसरे ऐप्लिकेशन में इस्तेमाल किया जा रहा है, तो Camera.open() को कॉल करने पर एक अपवाद दिखता है. इसलिए, हम इसे try ब्लॉक में रैप करते हैं.
Kotlin
private fun safeCameraOpen(id: Int): Boolean { return try { releaseCameraAndPreview() mCamera = Camera.open(id) true } catch (e: Exception) { Log.e(getString(R.string.app_name), "failed to open Camera") e.printStackTrace() false } } private fun releaseCameraAndPreview() { preview?.setCamera(null) mCamera?.also { camera -> camera.release() mCamera = null } }
Java
private boolean safeCameraOpen(int id) { boolean qOpened = false; try { releaseCameraAndPreview(); camera = Camera.open(id); qOpened = (camera != null); } catch (Exception e) { Log.e(getString(R.string.app_name), "failed to open Camera"); e.printStackTrace(); } return qOpened; } private void releaseCameraAndPreview() { preview.setCamera(null); if (camera != null) { camera.release(); camera = null; } }
एपीआई लेवल 9 के बाद से, कैमरा फ़्रेमवर्क में कई कैमरे इस्तेमाल किए जा सकते हैं. अगर लेगसी एपीआई का इस्तेमाल किया जाता है और बिना किसी आर्ग्युमेंट के open() को कॉल किया जाता है, तो आपको पीछे की ओर मौजूद पहला कैमरा मिलता है.
कैमरे की झलक देखना
आम तौर पर, फ़ोटो लेने के लिए यह ज़रूरी है कि शटर पर क्लिक करने से पहले, उपयोगकर्ताओं को अपने सब्जेक्ट की झलक दिखे. इसके लिए, SurfaceView का इस्तेमाल करके, कैमरा सेंसर से कैप्चर की जा रही इमेज की झलक देखी जा सकती है.
झलक दिखाने वाली क्लास
झलक दिखाने के लिए, आपको झलक दिखाने वाली क्लास की ज़रूरत होगी. झलक दिखाने के लिए, android.view.SurfaceHolder.Callback इंटरफ़ेस को लागू करना ज़रूरी है. इसका इस्तेमाल, कैमरे के हार्डवेयर से ऐप्लिकेशन में इमेज डेटा भेजने के लिए किया जाता है.
Kotlin
class Preview( context: Context, val surfaceView: SurfaceView = SurfaceView(context) ) : ViewGroup(context), SurfaceHolder.Callback { var mHolder: SurfaceHolder = surfaceView.holder.apply { addCallback(this@Preview) setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } ... }
Java
class Preview extends ViewGroup implements SurfaceHolder.Callback { SurfaceView surfaceView; SurfaceHolder holder; Preview(Context context) { super(context); surfaceView = new SurfaceView(context); addView(surfaceView); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. holder = surfaceView.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } ... }
लाइव इमेज की झलक शुरू करने से पहले, झलक वाली क्लास को Camera ऑब्जेक्ट को पास करना होगा. इसके बारे में अगले सेक्शन में बताया गया है.
झलक सेट करना और उसे शुरू करना
कैमरे का इंस्टेंस और उससे जुड़ी झलक, एक खास क्रम में बनाई जानी चाहिए. इसमें कैमरे का ऑब्जेक्ट सबसे पहले होना चाहिए. यहां दिए गए स्निपेट में, कैमरे को शुरू करने की प्रोसेस को एनकैप्सुलेट किया गया है. इससे, जब भी उपयोगकर्ता कैमरे में बदलाव करने के लिए कुछ करता है, तो setCamera() तरीके से Camera.startPreview() को कॉल किया जाता है. झलक को surfaceChanged() कॉलबैक के तरीके में भी रीस्टार्ट किया जाना चाहिए.
Kotlin
fun setCamera(camera: Camera?) { if (mCamera == camera) { return } stopPreviewAndFreeCamera() mCamera = camera mCamera?.apply { mSupportedPreviewSizes = parameters.supportedPreviewSizes requestLayout() try { setPreviewDisplay(holder) } catch (e: IOException) { e.printStackTrace() } // Important: Call startPreview() to start updating the preview // surface. Preview must be started before you can take a picture. startPreview() } }
Java
public void setCamera(Camera camera) { if (mCamera == camera) { return; } stopPreviewAndFreeCamera(); mCamera = camera; if (mCamera != null) { List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes(); supportedPreviewSizes = localSizes; requestLayout(); try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } // Important: Call startPreview() to start updating the preview // surface. Preview must be started before you can take a picture. mCamera.startPreview(); } }
कैमरे की सेटिंग में बदलाव करना
कैमरे की सेटिंग से, फ़ोटो लेने के तरीके में बदलाव किया जा सकता है. जैसे, ज़ूम करने के लेवल से लेकर एक्सपोज़र कंपंसेशन तक. इस उदाहरण में, सिर्फ़ झलक का साइज़ बदला गया है. ज़्यादा जानकारी के लिए, कैमरा ऐप्लिकेशन का सोर्स कोड देखें.
Kotlin
override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { mCamera?.apply { // Now that the size is known, set up the camera parameters and begin // the preview. parameters?.also { params -> params.setPreviewSize(previewSize.width, previewSize.height) requestLayout() parameters = params } // Important: Call startPreview() to start updating the preview surface. // Preview must be started before you can take a picture. startPreview() } }
Java
@Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(previewSize.width, previewSize.height); requestLayout(); mCamera.setParameters(parameters); // Important: Call startPreview() to start updating the preview surface. // Preview must be started before you can take a picture. mCamera.startPreview(); }
झलक का ओरिएंटेशन सेट करना
ज़्यादातर कैमरा ऐप्लिकेशन, डिसप्ले को लैंडस्केप मोड में लॉक कर देते हैं. ऐसा इसलिए, क्योंकि यह कैमरा सेंसर का नैचुरल ओरिएंटेशन होता है. इस सेटिंग से, आपको पोर्ट्रेट मोड में फ़ोटो लेने से नहीं रोका जाता. ऐसा इसलिए, क्योंकि डिवाइस का ओरिएंटेशन, EXIF हेडर में रिकॉर्ड किया जाता है. setCameraDisplayOrientation() तरीके से, झलक दिखाने के तरीके में बदलाव किया जा सकता है. इससे इमेज रिकॉर्ड करने के तरीके पर कोई असर नहीं पड़ता. हालांकि, एपीआई लेवल 14 से पहले के Android वर्शन में, ओरिएंटेशन बदलने से पहले आपको झलक को रोकना होगा. इसके बाद, उसे फिर से चालू करना होगा.
फ़ोटो खींचना
झलक दिखने के बाद, फ़ोटो लेने के लिए Camera.takePicture()
मेथड का इस्तेमाल करें. Camera.PictureCallback और Camera.ShutterCallback ऑब्जेक्ट बनाए जा सकते हैं और उन्हें Camera.takePicture() में पास किया जा सकता है.
अगर आपको लगातार इमेज कैप्चर करनी हैं, तो ऐसा Camera.PreviewCallback बनाएं जो onPreviewFrame() को लागू करता हो. इन दोनों के बीच की स्थिति के लिए, सिर्फ़ चुने गए झलक वाले फ़्रेम कैप्चर किए जा सकते हैं या takePicture() को कॉल करने के लिए, देरी से होने वाली कार्रवाई सेट अप की जा सकती है.
झलक को फिर से शुरू करना
फ़ोटो लेने के बाद, आपको झलक को फिर से चालू करना होगा. इसके बाद ही, उपयोगकर्ता दूसरी फ़ोटो ले सकता है. इस उदाहरण में, शटर बटन को ओवरलोड करके रीस्टार्ट किया गया है.
Kotlin
fun onClick(v: View) { previewState = if (previewState == K_STATE_FROZEN) { camera?.startPreview() K_STATE_PREVIEW } else { camera?.takePicture(null, rawCallback, null) K_STATE_BUSY } shutterBtnConfig() }
Java
@Override public void onClick(View v) { switch(previewState) { case K_STATE_FROZEN: camera.startPreview(); previewState = K_STATE_PREVIEW; break; default: camera.takePicture( null, rawCallback, null); previewState = K_STATE_BUSY; } // switch shutterBtnConfig(); }
झलक देखना बंद करना और कैमरे को रिलीज़ करना
ऐप्लिकेशन में कैमरे का इस्तेमाल करने के बाद, उसे बंद करना ज़रूरी है. खास तौर पर, आपको Camera ऑब्जेक्ट को रिलीज़ करना होगा. ऐसा न करने पर, अन्य ऐप्लिकेशन क्रैश हो सकते हैं. इनमें आपके ऐप्लिकेशन के नए इंस्टेंस भी शामिल हैं.
आपको झलक दिखाना कब बंद करना चाहिए और कैमरे को कब रिलीज़ करना चाहिए? प्रीव्यू सरफ़ेस का खत्म होना, इस बात का संकेत है कि अब प्रीव्यू को बंद करके कैमरे को रिलीज़ कर देना चाहिए. जैसा कि Preview क्लास के इन तरीकों में दिखाया गया है.
Kotlin
override fun surfaceDestroyed(holder: SurfaceHolder) { // Surface will be destroyed when we return, so stop the preview. // Call stopPreview() to stop updating the preview surface. mCamera?.stopPreview() } /** * When this function returns, mCamera will be null. */ private fun stopPreviewAndFreeCamera() { mCamera?.apply { // Call stopPreview() to stop updating the preview surface. stopPreview() // Important: Call release() to release the camera for use by other // applications. Applications should release the camera immediately // during onPause() and re-open() it during onResume()). release() mCamera = null } }
Java
@Override public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. if (mCamera != null) { // Call stopPreview() to stop updating the preview surface. mCamera.stopPreview(); } } /** * When this function returns, mCamera will be null. */ private void stopPreviewAndFreeCamera() { if (mCamera != null) { // Call stopPreview() to stop updating the preview surface. mCamera.stopPreview(); // Important: Call release() to release the camera for use by other // applications. Applications should release the camera immediately // during onPause() and re-open() it during onResume()). mCamera.release(); mCamera = null; } }
इस लेसन में पहले, यह प्रोसेस setCamera() मेथड का भी हिस्सा थी. इसलिए, कैमरे को शुरू करने की प्रोसेस हमेशा झलक को रोकने से शुरू होती है.