دوربین API

چارچوب اندروید شامل پشتیبانی از دوربین‌های مختلف و ویژگی‌های دوربین موجود در دستگاه‌ها است که به شما امکان می‌دهد در برنامه‌های خود عکس و فیلم ضبط کنید. این سند یک رویکرد سریع و ساده برای ضبط تصویر و فیلم را مورد بحث قرار می‌دهد و یک رویکرد پیشرفته برای ایجاد تجربیات دوربین سفارشی برای کاربران شما را تشریح می‌کند.

توجه: این صفحه کلاس Camera را شرح می‌دهد که منسوخ شده است. ما استفاده از کتابخانه CameraX Jetpack یا برای موارد استفاده خاص، کلاس camera2 را توصیه می‌کنیم. هر دو CameraX و Camera2 روی اندروید ۵.۰ (سطح API ۲۱) و بالاتر کار می‌کنند.

ملاحظات

قبل از اینکه برنامه خود را برای استفاده از دوربین‌های دستگاه‌های اندروید فعال کنید، باید چند سوال در مورد نحوه استفاده برنامه خود از این ویژگی سخت‌افزاری در نظر بگیرید.

  • الزامات دوربین - آیا استفاده از دوربین برای برنامه شما آنقدر مهم است که نمی‌خواهید برنامه شما روی دستگاهی که دوربین ندارد نصب شود؟ در این صورت، باید الزامات دوربین را در مانیفست خود اعلام کنید.
  • دوربین عکاسی سریع یا سفارشی - برنامه شما چگونه از دوربین استفاده خواهد کرد؟ آیا فقط به گرفتن یک عکس یا کلیپ ویدیویی سریع علاقه دارید یا برنامه شما روش جدیدی برای استفاده از دوربین‌ها ارائه می‌دهد؟ برای گرفتن یک عکس یا کلیپ سریع، استفاده از برنامه‌های دوربین موجود را در نظر بگیرید. برای توسعه یک ویژگی دوربین سفارشی، به بخش ساخت یک برنامه دوربین مراجعه کنید.
  • الزامات سرویس‌های پیش‌زمینه - چه زمانی برنامه شما با دوربین تعامل دارد؟ در اندروید ۹ (سطح API 28) و بالاتر، برنامه‌هایی که در پس‌زمینه اجرا می‌شوند نمی‌توانند به دوربین دسترسی داشته باشند. بنابراین، شما باید یا زمانی که برنامه شما در پیش‌زمینه است یا به عنوان بخشی از یک سرویس پیش‌زمینه از دوربین استفاده کنید.
  • ذخیره‌سازی - آیا تصاویر یا ویدیوهایی که برنامه شما تولید می‌کند، قرار است فقط برای برنامه خودتان قابل مشاهده باشند یا به اشتراک گذاشته شوند تا برنامه‌های دیگر مانند گالری یا سایر برنامه‌های رسانه‌ای و اجتماعی نیز بتوانند از آنها استفاده کنند؟ آیا می‌خواهید تصاویر و ویدیوها حتی در صورت حذف نصب برنامه شما نیز در دسترس باشند؟ برای آشنایی با نحوه پیاده‌سازی این گزینه‌ها، به بخش ذخیره‌سازی فایل‌های رسانه‌ای مراجعه کنید.

اصول اولیه

فریم‌ورک اندروید از ضبط تصاویر و ویدیو از طریق API مربوط android.hardware.camera2 یا camera Intent پشتیبانی می‌کند. در اینجا کلاس‌های مربوطه آمده است:

android.hardware.camera2
این بسته، API اصلی برای کنترل دوربین‌های دستگاه است. می‌توان از آن برای گرفتن عکس یا فیلم هنگام ساخت یک برنامه دوربین استفاده کرد.
Camera
این کلاس، API قدیمی و منسوخ‌شده برای کنترل دوربین‌های دستگاه است.
SurfaceView
این کلاس برای نمایش پیش‌نمایش زنده دوربین به کاربر استفاده می‌شود.
MediaRecorder
این کلاس برای ضبط ویدیو از دوربین استفاده می‌شود.
Intent
یک نوع اکشن intent از نوع MediaStore.ACTION_IMAGE_CAPTURE یا MediaStore.ACTION_VIDEO_CAPTURE می‌تواند برای ضبط تصاویر یا ویدیوها بدون استفاده مستقیم از شیء Camera استفاده شود.

اعلامیه‌های آشکار

قبل از شروع توسعه برنامه خود با Camera API، باید مطمئن شوید که فایل مانیفست شما دارای اعلان‌های مناسب برای اجازه استفاده از سخت‌افزار دوربین و سایر ویژگی‌های مرتبط است.

  • مجوز دوربین - برنامه شما باید برای استفاده از دوربین دستگاه درخواست مجوز کند.
    <uses-permission android:name="android.permission.CAMERA" />

    توجه: اگر با فراخوانی یک برنامه دوربین موجود از دوربین استفاده می‌کنید، برنامه شما نیازی به درخواست این مجوز ندارد.

  • ویژگی‌های دوربین - برنامه شما همچنین باید استفاده از ویژگی‌های دوربین را اعلام کند، برای مثال:
    <uses-feature android:name="android.hardware.camera" />

    برای فهرستی از ویژگی‌های دوربین، به مرجع ویژگی‌های مانیفست مراجعه کنید.

    افزودن ویژگی‌های دوربین به مانیفست شما باعث می‌شود گوگل پلی از نصب برنامه شما روی دستگاه‌هایی که دوربین ندارند یا از ویژگی‌های دوربینی که شما مشخص کرده‌اید پشتیبانی نمی‌کنند، جلوگیری کند. برای اطلاعات بیشتر در مورد استفاده از فیلترینگ مبتنی بر ویژگی با گوگل پلی، به بخش «گوگل پلی و فیلترینگ مبتنی بر ویژگی» مراجعه کنید.

    اگر برنامه شما می‌تواند از دوربین یا ویژگی دوربین برای عملکرد صحیح استفاده کند ، اما به آن نیازی ندارد، باید این مورد را در مانیفست با گنجاندن ویژگی android:required و تنظیم آن روی false مشخص کنید:

    <uses-feature android:name="android.hardware.camera" android:required="false" />
  • مجوز ذخیره‌سازی - اگر برنامه شما اندروید ۱۰ (سطح API ۲۹) یا پایین‌تر را هدف قرار داده و موارد زیر را در مانیفست مشخص کند، می‌تواند تصاویر یا ویدیوها را در حافظه خارجی دستگاه (کارت SD) ذخیره کند.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • مجوز ضبط صدا - برای ضبط صدا همراه با ضبط ویدیو، برنامه شما باید مجوز ضبط صدا را درخواست کند.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
  • مجوز موقعیت مکانی - اگر برنامه شما تصاویر را با اطلاعات موقعیت مکانی GPS برچسب‌گذاری می‌کند، باید مجوز ACCESS_FINE_LOCATION را درخواست کنید. توجه داشته باشید که اگر برنامه شما اندروید ۵.۰ (سطح API ۲۱) یا بالاتر را هدف قرار می‌دهد، باید اعلام کنید که برنامه شما از GPS دستگاه نیز استفاده می‌کند:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ...
    <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
    <uses-feature android:name="android.hardware.location.gps" />

    برای اطلاعات بیشتر در مورد دریافت موقعیت مکانی کاربر، به «استراتژی‌های موقعیت مکانی» مراجعه کنید.

استفاده از برنامه‌های دوربین موجود

یک راه سریع برای فعال کردن گرفتن عکس یا فیلم در برنامه شما بدون کد اضافی زیاد، استفاده از یک Intent برای فراخوانی یک برنامه دوربین اندروید موجود است. جزئیات در درس‌های آموزشی Taking Photos Simply و Recording Videos Simply توضیح داده شده است.

ساخت اپلیکیشن دوربین

برخی از توسعه‌دهندگان ممکن است به رابط کاربری دوربینی نیاز داشته باشند که با ظاهر برنامه‌ی آن‌ها سازگار باشد یا ویژگی‌های خاصی را ارائه دهد. نوشتن کد عکس‌برداری خودتان می‌تواند تجربه‌ی جذاب‌تری را برای کاربران شما فراهم کند.

نکته: راهنمای زیر برای API Camera قدیمی و منسوخ شده است. برای برنامه‌های دوربین جدید یا پیشرفته، API جدیدتر android.hardware.camera2 توصیه می‌شود.

مراحل کلی برای ایجاد یک رابط دوربین سفارشی برای برنامه شما به شرح زیر است:

  • تشخیص و دسترسی به دوربین - کدی ایجاد کنید تا وجود دوربین‌ها را بررسی کرده و درخواست دسترسی دهد.
  • ایجاد یک کلاس پیش‌نمایش - یک کلاس پیش‌نمایش دوربین ایجاد کنید که SurfaceView بسط داده و رابط SurfaceHolder را پیاده‌سازی کند. این کلاس تصاویر زنده دوربین را پیش‌نمایش می‌دهد.
  • ساخت طرح‌بندی پیش‌نمایش - وقتی کلاس پیش‌نمایش دوربین را ایجاد کردید، یک طرح‌بندی نما ایجاد کنید که پیش‌نمایش و کنترل‌های رابط کاربری مورد نظر شما را در بر بگیرد.
  • تنظیم شنونده‌ها برای ضبط - شنونده‌ها را برای کنترل‌های رابط خود متصل کنید تا ضبط تصویر یا ویدیو در پاسخ به اقدامات کاربر، مانند فشار دادن یک دکمه، آغاز شود.
  • ضبط و ذخیره فایل‌ها - کد مربوط به ضبط تصاویر یا ویدیوها و ذخیره خروجی را تنظیم کنید.
  • رها کردن دوربین - پس از استفاده از دوربین، برنامه شما باید آن را به درستی برای استفاده توسط سایر برنامه‌ها رها کند.

سخت‌افزار دوربین یک منبع مشترک است که باید با دقت مدیریت شود تا برنامه شما با برنامه‌های دیگری که ممکن است بخواهند از آن استفاده کنند، تداخل نداشته باشد. بخش‌های بعدی نحوه تشخیص سخت‌افزار دوربین، نحوه درخواست دسترسی به دوربین، نحوه ضبط عکس یا فیلم و نحوه رها کردن دوربین پس از اتمام استفاده برنامه شما از آن را مورد بحث قرار می‌دهند.

احتیاط: به یاد داشته باشید که پس از اتمام استفاده از برنامه، شیء Camera با فراخوانی Camera.release() آزاد کنید! اگر برنامه شما به درستی دوربین را آزاد نکند، تمام تلاش‌های بعدی برای دسترسی به دوربین، از جمله تلاش‌های برنامه خودتان، با شکست مواجه خواهد شد و ممکن است باعث خاموش شدن برنامه‌های شما یا سایر برنامه‌ها شود.

تشخیص سخت‌افزار دوربین

اگر برنامه شما به طور خاص با استفاده از اعلان مانیفست به دوربین نیاز ندارد، باید بررسی کنید که آیا دوربین در زمان اجرا در دسترس است یا خیر. برای انجام این بررسی، از متد PackageManager.hasSystemFeature() استفاده کنید، همانطور که در کد مثال زیر نشان داده شده است:

کاتلین

/** Check if this device has a camera */
private fun checkCameraHardware(context: Context): Boolean {
    if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        // this device has a camera
        return true
    } else {
        // no camera on this device
        return false
    }
}

جاوا

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}

دستگاه‌های اندروید می‌توانند چندین دوربین داشته باشند، برای مثال یک دوربین پشتی برای عکاسی و یک دوربین جلویی برای تماس‌های ویدیویی. اندروید ۲.۳ (API سطح ۹) و بالاتر به شما امکان می‌دهد تعداد دوربین‌های موجود در یک دستگاه را با استفاده از متد Camera.getNumberOfCameras() بررسی کنید.

دسترسی به دوربین‌ها

اگر تشخیص داده‌اید که دستگاهی که برنامه شما روی آن اجرا می‌شود دارای دوربین است، باید با دریافت نمونه‌ای از Camera درخواست دسترسی به آن را بدهید (مگر اینکه از یک intent برای دسترسی به دوربین استفاده کنید).

برای دسترسی به دوربین اصلی، از متد Camera.open() استفاده کنید و مطمئن شوید که هرگونه استثنا را دریافت می‌کنید، همانطور که در کد زیر نشان داده شده است:

کاتلین

/** A safe way to get an instance of the Camera object. */
fun getCameraInstance(): Camera? {
    return try {
        Camera.open() // attempt to get a Camera instance
    } catch (e: Exception) {
        // Camera is not available (in use or does not exist)
        null // returns null if camera is unavailable
    }
}

جاوا

/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

احتیاط: همیشه هنگام استفاده از Camera.open() استثنائات را بررسی کنید. عدم بررسی استثنائات در صورت استفاده از دوربین یا عدم وجود آن، باعث می‌شود برنامه شما توسط سیستم خاموش شود.

در دستگاه‌هایی که اندروید ۲.۳ (API Level 9) یا بالاتر را اجرا می‌کنند، می‌توانید با استفاده از Camera.open(int) به دوربین‌های خاص دسترسی پیدا کنید. کد مثال بالا به اولین دوربین پشتی در دستگاهی با بیش از یک دوربین دسترسی پیدا می‌کند.

بررسی ویژگی‌های دوربین

پس از دسترسی به یک دوربین، می‌توانید با استفاده از متد Camera.getParameters() و بررسی شیء Camera.Parameters برگردانده شده برای قابلیت‌های پشتیبانی‌شده، اطلاعات بیشتری در مورد قابلیت‌های آن به دست آورید. هنگام استفاده از API سطح ۹ یا بالاتر، از Camera.getCameraInfo() برای تعیین اینکه آیا دوربین در جلو یا عقب دستگاه قرار دارد و جهت تصویر، استفاده کنید.

ایجاد کلاس پیش‌نمایش

برای اینکه کاربران بتوانند به طور مؤثر عکس یا فیلم بگیرند، باید بتوانند آنچه را که دوربین دستگاه می‌بیند، ببینند. کلاس پیش‌نمایش دوربین، یک SurfaceView است که می‌تواند داده‌های تصویر زنده از دوربین را نمایش دهد، بنابراین کاربران می‌توانند یک عکس یا فیلم را قاب‌بندی و ضبط کنند.

کد مثال زیر نحوه ایجاد یک کلاس پیش‌نمایش دوربین پایه را نشان می‌دهد که می‌تواند در یک طرح‌بندی View گنجانده شود. این کلاس SurfaceHolder.Callback پیاده‌سازی می‌کند تا رویدادهای فراخوانی برای ایجاد و از بین بردن View را که برای اختصاص ورودی پیش‌نمایش دوربین مورد نیاز هستند، ضبط کند.

کاتلین

/** A basic Camera preview class */
class CameraPreview(
        context: Context,
        private val mCamera: Camera
) : SurfaceView(context), SurfaceHolder.Callback {

    private val mHolder: SurfaceHolder = holder.apply {
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        addCallback(this@CameraPreview)
        // deprecated setting, but required on Android versions prior to 3.0
        setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        mCamera.apply {
            try {
                setPreviewDisplay(holder)
                startPreview()
            } catch (e: IOException) {
                Log.d(TAG, "Error setting camera preview: ${e.message}")
            }
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (mHolder.surface == null) {
            // preview surface does not exist
            return
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview()
        } catch (e: Exception) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        mCamera.apply {
            try {
                setPreviewDisplay(mHolder)
                startPreview()
            } catch (e: Exception) {
                Log.d(TAG, "Error starting camera preview: ${e.message}")
            }
        }
    }
}

جاوا

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

اگر می‌خواهید اندازه خاصی را برای پیش‌نمایش دوربین خود تنظیم کنید، این را در متد surfaceChanged() همانطور که در توضیحات بالا ذکر شد، تنظیم کنید. هنگام تنظیم اندازه پیش‌نمایش، باید از مقادیر getSupportedPreviewSizes() استفاده کنید . مقادیر دلخواه را در متد setPreviewSize() تنظیم نکنید .

توجه: با معرفی ویژگی چند پنجره‌ای (Multi-Window) در اندروید ۷.۰ (سطح API 24) و بالاتر، دیگر نمی‌توانید فرض کنید که نسبت ابعاد پیش‌نمایش با نسبت ابعاد اکتیویتی شما یکسان است، حتی پس از فراخوانی setDisplayOrientation() . بسته به اندازه پنجره و نسبت ابعاد، ممکن است مجبور شوید پیش‌نمایش دوربین عریض را در یک طرح‌بندی عمودی قرار دهید، یا برعکس، از طرح‌بندی جعبه‌ای استفاده کنید.

قرار دادن پیش‌نمایش در یک طرح‌بندی

یک کلاس پیش‌نمایش دوربین، مانند مثالی که در بخش قبل نشان داده شد، باید در طرح‌بندی یک فعالیت به همراه سایر کنترل‌های رابط کاربری برای گرفتن عکس یا فیلم قرار گیرد. این بخش به شما نشان می‌دهد که چگونه یک طرح‌بندی و فعالیت اولیه برای پیش‌نمایش بسازید.

کد طرح‌بندی زیر یک نمای بسیار ابتدایی ارائه می‌دهد که می‌تواند برای نمایش پیش‌نمایش دوربین استفاده شود. در این مثال، عنصر FrameLayout به عنوان ظرفی برای کلاس پیش‌نمایش دوربین در نظر گرفته شده است. این نوع طرح‌بندی به گونه‌ای استفاده می‌شود که اطلاعات یا کنترل‌های تصویر اضافی بتوانند روی تصاویر پیش‌نمایش دوربین زنده قرار گیرند.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
  <FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    />

  <Button
    android:id="@+id/button_capture"
    android:text="Capture"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    />
</LinearLayout>

در اکثر دستگاه‌ها، جهت پیش‌فرض پیش‌نمایش دوربین افقی است. این طرح‌بندی نمونه، یک طرح‌بندی افقی (افقی) را مشخص می‌کند و کد زیر جهت‌گیری برنامه را به افقی ثابت می‌کند. برای سادگی در رندر پیش‌نمایش دوربین، باید جهت‌گیری فعالیت پیش‌نمایش برنامه خود را با افزودن موارد زیر به مانیفست خود به افقی تغییر دهید.

<activity android:name=".CameraActivity"
          android:label="@string/app_name"

          android:screenOrientation="landscape">
          <!-- configure this activity to use landscape orientation -->

          <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

نکته: پیش‌نمایش دوربین لازم نیست در حالت افقی باشد. از اندروید ۲.۲ (API سطح ۸)، می‌توانید از متد setDisplayOrientation() برای تنظیم چرخش تصویر پیش‌نمایش استفاده کنید. برای تغییر جهت پیش‌نمایش هنگام تغییر جهت گوشی توسط کاربر، در متد surfaceChanged() از کلاس پیش‌نمایش خود، ابتدا پیش‌نمایش را با Camera.stopPreview() متوقف کنید تا جهت را تغییر دهید و سپس با Camera.startPreview() دوباره پیش‌نمایش را شروع کنید.

در اکتیویتی مربوط به نمای دوربین خود، کلاس پیش‌نمایش خود را به عنصر FrameLayout نشان داده شده در مثال بالا اضافه کنید. اکتیویتی دوربین شما همچنین باید اطمینان حاصل کند که هنگام مکث یا خاموش شدن، دوربین را آزاد می‌کند. مثال زیر نحوه تغییر یک اکتیویتی دوربین را برای اتصال کلاس پیش‌نمایش نشان داده شده در بخش «ایجاد یک کلاس پیش‌نمایش» نشان می‌دهد.

کاتلین

class CameraActivity : Activity() {

    private var mCamera: Camera? = null
    private var mPreview: CameraPreview? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Create an instance of Camera
        mCamera = getCameraInstance()

        mPreview = mCamera?.let {
            // Create our Preview view
            CameraPreview(this, it)
        }

        // Set the Preview view as the content of our activity.
        mPreview?.also {
            val preview: FrameLayout = findViewById(R.id.camera_preview)
            preview.addView(it)
        }
    }
}

جاوا

public class CameraActivity extends Activity {

    private Camera mCamera;
    private CameraPreview mPreview;

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

        // Create an instance of Camera
        mCamera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mPreview);
    }
}

نکته: متد getCameraInstance() در مثال بالا به متد مثالی که در Accessing cameras نشان داده شده است، اشاره دارد.

گرفتن تصاویر

پس از ساخت کلاس پیش‌نمایش و طرح‌بندی نمای نمایش، آماده‌اید تا با برنامه خود شروع به گرفتن تصاویر کنید. در کد برنامه خود، باید شنونده‌هایی را برای کنترل‌های رابط کاربری خود تنظیم کنید تا با گرفتن عکس به یک اقدام کاربر پاسخ دهند.

برای بازیابی یک عکس، از متد Camera.takePicture() استفاده کنید. این متد سه پارامتر می‌گیرد که داده‌ها را از دوربین دریافت می‌کنند. برای دریافت داده‌ها با فرمت JPEG، باید یک رابط Camera.PictureCallback پیاده‌سازی کنید تا داده‌های تصویر را دریافت کرده و آن را در یک فایل بنویسید. کد زیر پیاده‌سازی اولیه رابط Camera.PictureCallback را برای ذخیره تصویر دریافتی از دوربین نشان می‌دهد.

کاتلین

private val mPicture = Camera.PictureCallback { data, _ ->
    val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run {
        Log.d(TAG, ("Error creating media file, check storage permissions"))
        return@PictureCallback
    }

    try {
        val fos = FileOutputStream(pictureFile)
        fos.write(data)
        fos.close()
    } catch (e: FileNotFoundException) {
        Log.d(TAG, "File not found: ${e.message}")
    } catch (e: IOException) {
        Log.d(TAG, "Error accessing file: ${e.message}")
    }
}

جاوا

private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d(TAG, "Error creating media file, check storage permissions");
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
};

با فراخوانی متد Camera.takePicture() ‎، گرفتن تصویر را فعال کنید. کد مثال زیر نحوه فراخوانی این متد را از یک دکمه View.OnClickListener نشان می‌دهد.

کاتلین

val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    // get an image from the camera
    mCamera?.takePicture(null, null, picture)
}

جاوا

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // get an image from the camera
            mCamera.takePicture(null, null, picture);
        }
    }
);

نکته: عضو mPicture در مثال زیر به کد مثال بالا اشاره دارد.

احتیاط: به یاد داشته باشید که وقتی برنامه شما با استفاده از آن کار خود را تمام کرد، شیء Camera را با فراخوانی Camera.release() آزاد کنید! برای اطلاعات بیشتر در مورد نحوه آزاد کردن دوربین، به بخش آزاد کردن دوربین مراجعه کنید.

ضبط ویدیوها

ضبط ویدیو با استفاده از چارچوب اندروید نیازمند مدیریت دقیق شیء Camera و هماهنگی با کلاس MediaRecorder است. هنگام ضبط ویدیو با Camera ، باید علاوه بر فراخوانی‌های Camera.open() و Camera.release() ، فراخوانی‌های Camera.lock() و Camera.unlock() را نیز مدیریت کنید تا به MediaRecorder اجازه دسترسی به سخت‌افزار دوربین داده شود.

نکته: از اندروید ۴.۰ (سطح API ۱۴)، فراخوانی‌های Camera.lock() و Camera.unlock() به صورت خودکار برای شما مدیریت می‌شوند.

برخلاف گرفتن عکس با دوربین دستگاه، ضبط ویدیو نیاز به یک دستور فراخوانی بسیار خاص دارد. برای آماده شدن و ضبط موفقیت‌آمیز ویدیو با برنامه خود، باید از یک دستور اجرای خاص پیروی کنید، همانطور که در زیر توضیح داده شده است.

  1. باز کردن دوربین - از Camera.open() برای دریافت نمونه‌ای از شیء دوربین استفاده کنید.
  2. پیش‌نمایش اتصال - با اتصال یک SurfaceView به دوربین با استفاده از Camera.setPreviewDisplay() پیش‌نمایش تصویر دوربین را به صورت زنده آماده کنید.
  3. شروع پیش‌نمایش - برای شروع نمایش تصاویر زنده دوربین، تابع Camera.startPreview() را فراخوانی کنید.
  4. شروع ضبط ویدیو - برای ضبط موفقیت‌آمیز ویدیو، مراحل زیر باید انجام شود:
    1. باز کردن قفل دوربین - با فراخوانی Camera.unlock() قفل دوربین را برای استفاده توسط MediaRecorder باز کنید.
    2. پیکربندی MediaRecorder - متدهای MediaRecorder زیر را به ترتیب فراخوانی کنید. برای اطلاعات بیشتر، به مستندات مرجع MediaRecorder مراجعه کنید.
      1. setCamera() - دوربینی را که برای ضبط ویدیو استفاده می‌شود، تنظیم می‌کند، از نمونه فعلی Camera برنامه شما استفاده می‌کند.
      2. setAudioSource() - منبع صدا را تنظیم می‌کند، از MediaRecorder.AudioSource.CAMCORDER استفاده می‌کند.
      3. setVideoSource() - منبع ویدیو را تنظیم می‌کند، از MediaRecorder.VideoSource.CAMERA استفاده می‌کند.
      4. فرمت و کدگذاری خروجی ویدیو را تنظیم کنید. برای اندروید ۲.۲ (API Level 8) و بالاتر، از متد MediaRecorder.setProfile استفاده کنید و با استفاده از CamcorderProfile.get() یک نمونه پروفایل دریافت کنید. برای نسخه‌های اندروید قبل از ۲.۲، باید پارامترهای فرمت و کدگذاری خروجی ویدیو را تنظیم کنید:
        1. setOutputFormat() - فرمت خروجی را تنظیم می‌کند، تنظیمات پیش‌فرض یا MediaRecorder.OutputFormat.MPEG_4 را مشخص می‌کند.
        2. setAudioEncoder() - نوع رمزگذاری صدا را تنظیم می‌کند، تنظیمات پیش‌فرض یا MediaRecorder.AudioEncoder.AMR_NB را مشخص می‌کند.
        3. setVideoEncoder() - نوع رمزگذاری ویدئو را تنظیم می‌کند، تنظیمات پیش‌فرض یا MediaRecorder.VideoEncoder.MPEG_4_SP را مشخص می‌کند.
      5. setOutputFile() - فایل خروجی را تنظیم کنید، از getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() از متد مثال در بخش ذخیره فایل‌های رسانه‌ای استفاده کنید.
      6. setPreviewDisplay() - عنصر طرح‌بندی پیش‌نمایش SurfaceView را برای برنامه خود مشخص کنید. از همان شیء که برای Connect Preview مشخص کردید، استفاده کنید.

      احتیاط: شما باید این متدهای پیکربندی MediaRecorder را به همین ترتیب فراخوانی کنید، در غیر این صورت برنامه شما با خطا مواجه می‌شود و ضبط با شکست مواجه می‌شود.

    3. آماده‌سازی MediaRecorder - با فراخوانی MediaRecorder.prepare() MediaRecorder با تنظیمات پیکربندی ارائه شده آماده کنید.
    4. شروع ضبط ویدیو - با فراخوانی MediaRecorder.start() ضبط ویدیو را شروع کنید.
  5. توقف ضبط ویدیو - برای تکمیل موفقیت‌آمیز ضبط ویدیو، متدهای زیر را به ترتیب فراخوانی کنید:
    1. توقف ضبط رسانه - با فراخوانی MediaRecorder.stop() ضبط ویدیو را متوقف کنید.
    2. تنظیم مجدد MediaRecorder - به صورت اختیاری، تنظیمات پیکربندی را با فراخوانی MediaRecorder.reset() از ضبط کننده حذف کنید.
    3. رهاسازی MediaRecorder - با فراخوانی MediaRecorder.release() MediaRecorder را رها کنید.
    4. قفل کردن دوربین - با فراخوانی Camera.lock() دوربین را قفل کنید تا جلسات آینده MediaRecorder بتوانند از آن استفاده کنند. از اندروید ۴.۰ (سطح API ۱۴)، این فراخوانی لازم نیست مگر اینکه فراخوانی MediaRecorder.prepare() با شکست مواجه شود.
  6. توقف پیش‌نمایش - وقتی فعالیت شما استفاده از دوربین را تمام کرد، پیش‌نمایش را با استفاده از Camera.stopPreview() متوقف کنید.
  7. رها کردن دوربین - دوربین را رها کنید تا سایر برنامه‌ها بتوانند با فراخوانی Camera.release() از آن استفاده کنند.

نکته: می‌توان از MediaRecorder بدون ایجاد پیش‌نمایش دوربین استفاده کرد و از چند مرحله اول این فرآیند صرف‌نظر کرد. با این حال، از آنجایی که کاربران معمولاً ترجیح می‌دهند قبل از شروع ضبط، پیش‌نمایش را ببینند، این فرآیند در اینجا مورد بحث قرار نمی‌گیرد.

نکته: اگر برنامه شما معمولاً برای ضبط ویدیو استفاده می‌شود، قبل از شروع پیش‌نمایش، setRecordingHint(boolean) را روی true تنظیم کنید. این تنظیم می‌تواند به کاهش زمان لازم برای شروع ضبط کمک کند.

پیکربندی MediaRecorder

هنگام استفاده از کلاس MediaRecorder برای ضبط ویدیو، باید مراحل پیکربندی را به ترتیب خاصی انجام دهید و سپس متد MediaRecorder.prepare() را برای بررسی و پیاده‌سازی پیکربندی فراخوانی کنید. کد مثال زیر نحوه پیکربندی و آماده‌سازی صحیح کلاس MediaRecorder برای ضبط ویدیو را نشان می‌دهد.

کاتلین

private fun prepareVideoRecorder(): Boolean {
    mediaRecorder = MediaRecorder()

    mCamera?.let { camera ->
        // Step 1: Unlock and set camera to MediaRecorder
        camera?.unlock()

        mediaRecorder?.run {
            setCamera(camera)

            // Step 2: Set sources
            setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
            setVideoSource(MediaRecorder.VideoSource.CAMERA)

            // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
            setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH))

            // Step 4: Set output file
            setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString())

            // Step 5: Set the preview output
            setPreviewDisplay(mPreview?.holder?.surface)

            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
            setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)


            // Step 6: Prepare configured MediaRecorder
            return try {
                prepare()
                true
            } catch (e: IllegalStateException) {
                Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}")
                releaseMediaRecorder()
                false
            } catch (e: IOException) {
                Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}")
                releaseMediaRecorder()
                false
            }
        }

    }
    return false
}

جاوا

private boolean prepareVideoRecorder(){

    mCamera = getCameraInstance();
    mediaRecorder = new MediaRecorder();

    // Step 1: Unlock and set camera to MediaRecorder
    mCamera.unlock();
    mediaRecorder.setCamera(mCamera);

    // Step 2: Set sources
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

    // Step 4: Set output file
    mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

    // Step 5: Set the preview output
    mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

    // Step 6: Prepare configured MediaRecorder
    try {
        mediaRecorder.prepare();
    } catch (IllegalStateException e) {
        Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    } catch (IOException e) {
        Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    }
    return true;
}

قبل از اندروید ۲.۲ (API سطح ۸)، شما باید پارامترهای فرمت خروجی و فرمت‌های کدگذاری را مستقیماً تنظیم می‌کردید، به جای اینکه از CamcorderProfile استفاده کنید. این رویکرد در کد زیر نشان داده شده است:

کاتلین

    // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mediaRecorder?.apply {
        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
        setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)
    }

جاوا

    // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

پارامترهای ضبط ویدیوی زیر برای MediaRecorder تنظیمات پیش‌فرض هستند، با این حال، ممکن است بخواهید این تنظیمات را برای برنامه خود تنظیم کنید:

شروع و توقف MediaRecorder

هنگام شروع و توقف ضبط ویدیو با استفاده از کلاس MediaRecorder ، باید ترتیب خاصی را که در زیر آمده است، دنبال کنید.

  1. باز کردن قفل دوربین با استفاده از Camera.unlock()
  2. MediaRecorder همانطور که در مثال کد بالا نشان داده شده است، پیکربندی کنید.
  3. شروع ضبط با استفاده از MediaRecorder.start()
  4. ویدیو را ضبط کنید
  5. توقف ضبط با استفاده از MediaRecorder.stop()
  6. ضبط کننده رسانه را با MediaRecorder.release() آزاد کنید
  7. قفل کردن دوربین با استفاده از Camera.lock()

کد مثال زیر نحوه اتصال یک دکمه برای شروع و توقف صحیح ضبط ویدیو با استفاده از دوربین و کلاس MediaRecorder را نشان می‌دهد.

توجه: هنگام ضبط ویدیو، دوربین را رها نکنید، در غیر این صورت پیش‌نمایش شما متوقف خواهد شد.

کاتلین

var isRecording = false
val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    if (isRecording) {
        // stop recording and release camera
        mediaRecorder?.stop() // stop the recording
        releaseMediaRecorder() // release the MediaRecorder object
        mCamera?.lock() // take camera access back from MediaRecorder

        // inform the user that recording has stopped
        setCaptureButtonText("Capture")
        isRecording = false
    } else {
        // initialize video camera
        if (prepareVideoRecorder()) {
            // Camera is available and unlocked, MediaRecorder is prepared,
            // now you can start recording
            mediaRecorder?.start()

            // inform the user that recording has started
            setCaptureButtonText("Stop")
            isRecording = true
        } else {
            // prepare didn't work, release the camera
            releaseMediaRecorder()
            // inform user
        }
    }
}

جاوا

private boolean isRecording = false;

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (isRecording) {
                // stop recording and release camera
                mediaRecorder.stop();  // stop the recording
                releaseMediaRecorder(); // release the MediaRecorder object
                mCamera.lock();         // take camera access back from MediaRecorder

                // inform the user that recording has stopped
                setCaptureButtonText("Capture");
                isRecording = false;
            } else {
                // initialize video camera
                if (prepareVideoRecorder()) {
                    // Camera is available and unlocked, MediaRecorder is prepared,
                    // now you can start recording
                    mediaRecorder.start();

                    // inform the user that recording has started
                    setCaptureButtonText("Stop");
                    isRecording = true;
                } else {
                    // prepare didn't work, release the camera
                    releaseMediaRecorder();
                    // inform user
                }
            }
        }
    }
);

نکته: در مثال بالا، متد prepareVideoRecorder() به کد نمونه‌ای که در پیکربندی MediaRecorder نشان داده شده است، اشاره دارد. این متد قفل کردن دوربین، پیکربندی و آماده‌سازی نمونه MediaRecorder را بر عهده دارد.

رها کردن دوربین

دوربین‌ها منبعی هستند که توسط برنامه‌های روی یک دستگاه به اشتراک گذاشته می‌شوند. برنامه شما می‌تواند پس از دریافت نمونه‌ای از Camera از دوربین استفاده کند و شما باید به ویژه مراقب باشید که شیء دوربین را هنگامی که برنامه شما استفاده از آن را متوقف می‌کند، و به محض اینکه برنامه شما متوقف می‌شود ( Activity.onPause() )، رها کنید. اگر برنامه شما به درستی دوربین را رها نکند، تمام تلاش‌های بعدی برای دسترسی به دوربین، از جمله تلاش‌های برنامه خودتان، با شکست مواجه می‌شود و ممکن است باعث خاموش شدن برنامه‌های شما یا سایر برنامه‌ها شود.

برای آزاد کردن یک نمونه از شیء Camera ، از متد Camera.release() استفاده کنید، همانطور که در کد مثال زیر نشان داده شده است.

کاتلین

class CameraActivity : Activity() {
    private var mCamera: Camera?
    private var preview: SurfaceView?
    private var mediaRecorder: MediaRecorder?

    override fun onPause() {
        super.onPause()
        releaseMediaRecorder() // if you are using MediaRecorder, release it first
        releaseCamera() // release the camera immediately on pause event
    }

    private fun releaseMediaRecorder() {
        mediaRecorder?.reset() // clear recorder configuration
        mediaRecorder?.release() // release the recorder object
        mediaRecorder = null
        mCamera?.lock() // lock camera for later use
    }

    private fun releaseCamera() {
        mCamera?.release() // release the camera for other applications
        mCamera = null
    }
}

جاوا

public class CameraActivity extends Activity {
    private Camera mCamera;
    private SurfaceView preview;
    private MediaRecorder mediaRecorder;

    ...

    @Override
    protected void onPause() {
        super.onPause();
        releaseMediaRecorder();       // if you are using MediaRecorder, release it first
        releaseCamera();              // release the camera immediately on pause event
    }

    private void releaseMediaRecorder(){
        if (mediaRecorder != null) {
            mediaRecorder.reset();   // clear recorder configuration
            mediaRecorder.release(); // release the recorder object
            mediaRecorder = null;
            mCamera.lock();           // lock camera for later use
        }
    }

    private void releaseCamera(){
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
    }
}

احتیاط: اگر برنامه شما به درستی دوربین را آزاد نکند، تمام تلاش‌های بعدی برای دسترسی به دوربین، از جمله تلاش‌های برنامه خودتان، با شکست مواجه خواهد شد و ممکن است باعث بسته شدن برنامه‌های شما یا سایر برنامه‌ها شود.

ذخیره فایل‌های رسانه‌ای

فایل‌های رسانه‌ای ایجاد شده توسط کاربران مانند تصاویر و ویدیوها باید در دایرکتوری حافظه خارجی دستگاه (SD Card) ذخیره شوند تا فضای سیستم حفظ شود و کاربران بتوانند بدون دستگاه خود به این فایل‌ها دسترسی داشته باشند. مکان‌های دایرکتوری زیادی برای ذخیره فایل‌های رسانه‌ای در یک دستگاه وجود دارد، با این حال فقط دو مکان استاندارد وجود دارد که شما به عنوان یک توسعه‌دهنده باید در نظر بگیرید:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) - این متد، مکان استاندارد، مشترک و توصیه‌شده برای ذخیره تصاویر و ویدیوها را برمی‌گرداند. این دایرکتوری به صورت اشتراکی (عمومی) است، بنابراین سایر برنامه‌ها می‌توانند به راحتی فایل‌های ذخیره‌شده در این مکان را کشف، خوانده، تغییر و حذف کنند. اگر برنامه شما توسط کاربر حذف نصب شود، فایل‌های رسانه‌ای ذخیره‌شده در این مکان حذف نخواهند شد. برای جلوگیری از تداخل با تصاویر و ویدیوهای موجود کاربران، باید یک زیردایرکتوری برای فایل‌های رسانه‌ای برنامه خود در این دایرکتوری ایجاد کنید، همانطور که در نمونه کد زیر نشان داده شده است. این متد در اندروید ۲.۲ (API سطح ۸) موجود است، برای فراخوانی‌های معادل در نسخه‌های قبلی API، به بخش «ذخیره فایل‌های اشتراکی» مراجعه کنید.
  • Context.getExternalFilesDir ( Environment.DIRECTORY_PICTURES ) - این متد یک مکان استاندارد برای ذخیره تصاویر و ویدیوهای مرتبط با برنامه شما را برمی‌گرداند. اگر برنامه شما حذف نصب شود، هر فایل ذخیره شده در این مکان حذف می‌شود. امنیت برای فایل‌های موجود در این مکان اعمال نمی‌شود و سایر برنامه‌ها ممکن است آنها را بخوانند، تغییر دهند و حذف کنند.

کد مثال زیر نحوه ایجاد یک File یا آدرس Uri برای یک فایل رسانه‌ای را نشان می‌دهد که می‌تواند هنگام فراخوانی دوربین دستگاه با یک Intent یا به عنوان بخشی از ساخت یک برنامه دوربین استفاده شود.

کاتلین

val MEDIA_TYPE_IMAGE = 1
val MEDIA_TYPE_VIDEO = 2

/** Create a file Uri for saving an image or video */
private fun getOutputMediaFileUri(type: Int): Uri {
    return Uri.fromFile(getOutputMediaFile(type))
}

/** Create a File for saving an image or video */
private fun getOutputMediaFile(type: Int): File? {
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    val mediaStorageDir = File(
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "MyCameraApp"
    )
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    mediaStorageDir.apply {
        if (!exists()) {
            if (!mkdirs()) {
                Log.d("MyCameraApp", "failed to create directory")
                return null
            }
        }
    }

    // Create a media file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
    return when (type) {
        MEDIA_TYPE_IMAGE -> {
            File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg")
        }
        MEDIA_TYPE_VIDEO -> {
            File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4")
        }
        else -> null
    }
}

جاوا

public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
      return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
              Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}

نکته: Environment.getExternalStoragePublicDirectory() در اندروید ۲.۲ (API Level 8) یا بالاتر موجود است. اگر دستگاه‌هایی با نسخه‌های قدیمی‌تر اندروید را هدف قرار می‌دهید، به جای آن از Environment.getExternalStorageDirectory() استفاده کنید. برای اطلاعات بیشتر، به بخش «ذخیره فایل‌های اشتراکی » مراجعه کنید.

برای اینکه URI از پروفایل‌های کاری پشتیبانی کند، ابتدا URI فایل را به URI محتوا تبدیل کنید . سپس، URI محتوا را به EXTRA_OUTPUT یک Intent اضافه کنید.

برای اطلاعات بیشتر در مورد ذخیره فایل‌ها در دستگاه اندروید، به بخش ذخیره‌سازی داده‌ها مراجعه کنید.

ویژگی‌های دوربین

اندروید از طیف گسترده‌ای از ویژگی‌های دوربین پشتیبانی می‌کند که می‌توانید با برنامه دوربین خود کنترل کنید، مانند فرمت تصویر، حالت فلاش، تنظیمات فوکوس و موارد دیگر. این بخش ویژگی‌های رایج دوربین را فهرست می‌کند و به طور خلاصه نحوه استفاده از آنها را مورد بحث قرار می‌دهد. اکثر ویژگی‌های دوربین را می‌توان با استفاده از شیء Camera.Parameters دسترسی و تنظیم کرد. با این حال، چندین ویژگی مهم وجود دارد که به تنظیماتی بیش از تنظیمات ساده در Camera.Parameters نیاز دارند. این ویژگی‌ها در بخش‌های زیر پوشش داده شده‌اند:

برای اطلاعات کلی در مورد نحوه استفاده از ویژگی‌هایی که از طریق Camera.Parameters کنترل می‌شوند، بخش «استفاده از ویژگی‌های دوربین» را مرور کنید. برای اطلاعات دقیق‌تر در مورد نحوه استفاده از ویژگی‌های کنترل‌شده از طریق شیء پارامترهای دوربین، پیوندهای موجود در لیست ویژگی‌ها در زیر را به مستندات مرجع API دنبال کنید.

جدول 1. ویژگی‌های رایج دوربین، مرتب‌شده بر اساس سطح API اندروید که در آن معرفی شده‌اند.

ویژگی سطح API توضیحات
تشخیص چهره ۱۴ چهره‌های انسان را در یک تصویر شناسایی کنید و از آنها برای فوکوس، اندازه‌گیری و تراز سفیدی استفاده کنید
مناطق اندازه‌گیری ۱۴ یک یا چند ناحیه را در یک تصویر برای محاسبه تراز سفیدی مشخص کنید
حوزه‌های تمرکز ۱۴ یک یا چند ناحیه را در یک تصویر برای استفاده به عنوان فوکوس تنظیم کنید
White Balance Lock ۱۴ تنظیمات خودکار تراز سفیدی را متوقف یا شروع کنید
Exposure Lock ۱۴ تنظیمات نوردهی خودکار را متوقف یا شروع کنید
Video Snapshot ۱۴ هنگام فیلمبرداری عکس بگیرید (فریم گراب)
ویدیوی تایم لپس ۱۱ فریم‌ها را با تأخیرهای تنظیم‌شده ضبط کنید تا یک ویدیوی تایم‌لپس ضبط کنید
Multiple Cameras ۹ پشتیبانی از بیش از یک دوربین در یک دستگاه، شامل دوربین‌های جلو و عقب
Focus Distance ۹ فاصله بین دوربین و اشیایی که به نظر می‌رسد در فوکوس هستند را گزارش می‌دهد
Zoom ۸ تنظیم بزرگنمایی تصویر
Exposure Compensation ۸ افزایش یا کاهش سطح نوردهی
GPS Data ۵ داده‌های موقعیت جغرافیایی را به تصویر اضافه یا حذف کنید
White Balance ۵ حالت تراز سفیدی را تنظیم کنید، که بر مقادیر رنگ در تصویر گرفته شده تأثیر می‌گذارد.
Focus Mode ۵ نحوه فوکوس دوربین روی سوژه را تنظیم کنید، مثلاً خودکار، ثابت، ماکرو یا بی‌نهایت
Scene Mode ۵ برای انواع خاصی از موقعیت‌های عکاسی مانند شب، ساحل، برف یا صحنه‌های نور شمع، یک حالت از پیش تعیین‌شده اعمال کنید
JPEG Quality ۵ سطح فشرده‌سازی را برای یک تصویر JPEG تنظیم کنید، که کیفیت و اندازه فایل خروجی تصویر را افزایش یا کاهش می‌دهد
Flash Mode ۵ روشن، خاموش کردن فلاش یا استفاده از تنظیم خودکار
Color Effects ۵ یک جلوه رنگی مانند سیاه و سفید، تُن قهوه‌ای یا نگاتیو به تصویر گرفته شده اعمال کنید.
Anti-Banding ۵ اثر نواربندی در گرادیان‌های رنگی ناشی از فشرده‌سازی JPEG را کاهش می‌دهد.
Picture Format ۱ فرمت فایل تصویر را مشخص کنید
Picture Size ۱ ابعاد پیکسلی تصویر ذخیره شده را مشخص کنید

توجه: این ویژگی‌ها به دلیل تفاوت‌های سخت‌افزاری و پیاده‌سازی نرم‌افزاری، در همه دستگاه‌ها پشتیبانی نمی‌شوند. برای اطلاعات بیشتر در مورد بررسی در دسترس بودن ویژگی‌ها در دستگاهی که برنامه شما در آن اجرا می‌شود، به بررسی در دسترس بودن ویژگی مراجعه کنید.

بررسی در دسترس بودن ویژگی‌ها

اولین چیزی که هنگام استفاده از ویژگی‌های دوربین در دستگاه‌های اندروید باید بدانید این است که همه ویژگی‌های دوربین در همه دستگاه‌ها پشتیبانی نمی‌شوند. علاوه بر این، دستگاه‌هایی که از یک ویژگی خاص پشتیبانی می‌کنند، ممکن است آن ویژگی‌ها را در سطوح مختلف یا با گزینه‌های مختلف پشتیبانی کنند. بنابراین، بخشی از فرآیند تصمیم‌گیری شما هنگام توسعه یک برنامه دوربین، تصمیم‌گیری در مورد ویژگی‌های دوربینی است که می‌خواهید از آنها پشتیبانی کنید و تا چه سطحی. پس از تصمیم‌گیری، باید کدی را در برنامه دوربین خود بگنجانید که بررسی کند آیا سخت‌افزار دستگاه از آن ویژگی‌ها پشتیبانی می‌کند یا خیر و اگر یک ویژگی در دسترس نباشد، به درستی کار نمی‌کند.

شما می‌توانید با دریافت نمونه‌ای از شیء پارامترهای دوربین و بررسی متدهای مربوطه، در دسترس بودن ویژگی‌های دوربین را بررسی کنید. نمونه کد زیر نحوه دریافت شیء Camera.Parameters و بررسی پشتیبانی دوربین از ویژگی فوکوس خودکار را نشان می‌دهد:

کاتلین

val params: Camera.Parameters? = camera?.parameters
val focusModes: List<String>? = params?.supportedFocusModes
if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) {
    // Autofocus mode is supported
}

جاوا

// get Camera parameters
Camera.Parameters params = camera.getParameters();

List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
  // Autofocus mode is supported
}

شما می‌توانید از تکنیک نشان داده شده در بالا برای اکثر ویژگی‌های دوربین استفاده کنید. شیء Camera.Parameters متدهای getSupported...() ، is...Supported() یا getMax...() را برای تعیین اینکه آیا (و تا چه حد) یک ویژگی پشتیبانی می‌شود، ارائه می‌دهد.

اگر برنامه شما برای عملکرد صحیح به ویژگی‌های خاصی از دوربین نیاز دارد، می‌توانید آنها را از طریق افزودن به مانیفست برنامه خود الزامی کنید. وقتی استفاده از ویژگی‌های خاص دوربین، مانند فلش و فوکوس خودکار را اعلام می‌کنید، گوگل پلی نصب برنامه شما را روی دستگاه‌هایی که از این ویژگی‌ها پشتیبانی نمی‌کنند، محدود می‌کند. برای مشاهده لیستی از ویژگی‌های دوربین که می‌توان در مانیفست برنامه خود اعلام کرد، به مرجع ویژگی‌های مانیفست مراجعه کنید.

استفاده از ویژگی‌های دوربین

اکثر ویژگی‌های دوربین با استفاده از شیء Camera.Parameters فعال و کنترل می‌شوند. شما این شیء را ابتدا با دریافت یک نمونه از شیء Camera ، فراخوانی متد getParameters() ، تغییر شیء پارامتر برگشتی و سپس تنظیم مجدد آن در شیء دوربین، همانطور که در کد مثال زیر نشان داده شده است، به دست می‌آورید:

کاتلین

val params: Camera.Parameters? = camera?.parameters
params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
camera?.parameters = params

جاوا

// get Camera parameters
Camera.Parameters params = camera.getParameters();
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
camera.setParameters(params);

این تکنیک تقریباً برای همه ویژگی‌های دوربین کار می‌کند و اکثر پارامترها را می‌توان در هر زمانی پس از دریافت نمونه‌ای از شیء Camera تغییر داد. تغییرات در پارامترها معمولاً بلافاصله در پیش‌نمایش دوربین برنامه برای کاربر قابل مشاهده است. در سمت نرم‌افزار، تغییرات پارامترها ممکن است چندین فریم طول بکشد تا واقعاً اعمال شوند، زیرا سخت‌افزار دوربین دستورالعمل‌های جدید را پردازش می‌کند و سپس داده‌های تصویر به‌روز شده را ارسال می‌کند.

مهم: برخی از ویژگی‌های دوربین را نمی‌توان به دلخواه تغییر داد. به طور خاص، تغییر اندازه یا جهت پیش‌نمایش دوربین مستلزم آن است که ابتدا پیش‌نمایش را متوقف کنید، اندازه پیش‌نمایش را تغییر دهید و سپس پیش‌نمایش را مجدداً راه‌اندازی کنید. از اندروید ۴.۰ (API سطح ۱۴) به بعد، جهت پیش‌نمایش را می‌توان بدون راه‌اندازی مجدد پیش‌نمایش تغییر داد.

سایر ویژگی‌های دوربین برای پیاده‌سازی به کد بیشتری نیاز دارند، از جمله:

  • نورسنجی و نواحی فوکوس
  • تشخیص چهره
  • ویدیوی تایم لپس

خلاصه‌ای از نحوه پیاده‌سازی این ویژگی‌ها در بخش‌های بعدی ارائه شده است.

نورسنجی و نواحی فوکوس

در برخی از سناریوهای عکاسی، فوکوس خودکار و نورسنجی ممکن است نتایج مطلوب را به همراه نداشته باشند. با شروع از اندروید ۴.۰ (API Level 14)، برنامه دوربین شما می‌تواند کنترل‌های اضافی را ارائه دهد تا به برنامه یا کاربران شما اجازه دهد مناطقی را در یک تصویر مشخص کنند تا برای تعیین تنظیمات فوکوس یا سطح نور استفاده شوند و این مقادیر را برای استفاده در ضبط تصاویر یا ویدیو به سخت‌افزار دوربین منتقل کنند.

نواحی مربوط به نورسنجی و فوکوس بسیار شبیه به سایر ویژگی‌های دوربین کار می‌کنند، به این صورت که شما آنها را از طریق متدهایی در شیء Camera.Parameters کنترل می‌کنید. کد زیر تنظیم دو ناحیه نورسنجی برای نمونه‌ای از Camera را نشان می‌دهد:

کاتلین

// Create an instance of Camera
camera = getCameraInstance()

// set Camera parameters
val params: Camera.Parameters? = camera?.parameters

params?.apply {
    if (maxNumMeteringAreas > 0) { // check that metering areas are supported
        meteringAreas = ArrayList<Camera.Area>().apply {
            val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image
            add(Camera.Area(areaRect1, 600)) // set weight to 60%
            val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image
            add(Camera.Area(areaRect2, 400)) // set weight to 40%
        }
    }
    camera?.parameters = this
}

جاوا

// Create an instance of Camera
camera = getCameraInstance();

// set Camera parameters
Camera.Parameters params = camera.getParameters();

if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
    List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

    Rect areaRect1 = new Rect(-100, -100, 100, 100);    // specify an area in center of image
    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
    Rect areaRect2 = new Rect(800, -1000, 1000, -800);  // specify an area in upper right of image
    meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
    params.setMeteringAreas(meteringAreas);
}

camera.setParameters(params);

شیء Camera.Area شامل دو پارامتر داده است: یک شیء Rect برای مشخص کردن یک ناحیه در میدان دید دوربین و یک مقدار وزنی، که به دوربین می‌گوید این ناحیه باید در اندازه‌گیری نور یا محاسبات فوکوس چه میزان اهمیت داشته باشد.

فیلد Rect در شیء Camera.Area یک شکل مستطیلی را توصیف می‌کند که روی یک شبکه واحد ۲۰۰۰ در ۲۰۰۰ نگاشت شده است. مختصات -۱۰۰۰، -۱۰۰۰ نشان دهنده گوشه بالا و سمت چپ تصویر دوربین و مختصات ۱۰۰۰، ۱۰۰۰ نشان دهنده گوشه پایین و سمت راست تصویر دوربین هستند، همانطور که در تصویر زیر نشان داده شده است.

شکل ۱. خطوط قرمز سیستم مختصات برای مشخص کردن یک Camera.Area را در پیش‌نمایش دوربین نشان می‌دهند. کادر آبی مکان و شکل یک ناحیه دوربین را با مقادیر Rect 333,333,667,667 نشان می‌دهد.

مرزهای این سیستم مختصات همیشه با لبه بیرونی تصویر قابل مشاهده در پیش‌نمایش دوربین مطابقت دارند و با سطح بزرگنمایی کوچک یا بزرگ نمی‌شوند. به طور مشابه، چرخش پیش‌نمایش تصویر با استفاده از Camera.setDisplayOrientation() سیستم مختصات را تغییر نمی‌دهد.

تشخیص چهره

برای تصاویری که شامل افراد هستند، چهره‌ها معمولاً مهم‌ترین بخش تصویر هستند و باید هنگام ثبت تصویر برای تعیین فوکوس و تراز سفیدی استفاده شوند. چارچوب اندروید ۴.۰ (API Level 14) APIهایی را برای شناسایی چهره‌ها و محاسبه تنظیمات تصویر با استفاده از فناوری تشخیص چهره ارائه می‌دهد.

نکته: در حالی که ویژگی تشخیص چهره در حال اجرا است، setWhiteBalance(String) ، setFocusAreas(List<Camera.Area>) و setMeteringAreas(List<Camera.Area>) هیچ تاثیری ندارند.

استفاده از قابلیت تشخیص چهره در برنامه دوربین شما نیاز به چند مرحله کلی دارد:

  • بررسی کنید که آیا تشخیص چهره در دستگاه پشتیبانی می‌شود یا خیر
  • ایجاد یک شنونده تشخیص چهره
  • شنونده تشخیص چهره را به شیء دوربین خود اضافه کنید
  • شروع تشخیص چهره پس از پیش‌نمایش (و پس از هر بار شروع مجدد پیش‌نمایش)

ویژگی تشخیص چهره در همه دستگاه‌ها پشتیبانی نمی‌شود. می‌توانید با فراخوانی getMaxNumDetectedFaces() از پشتیبانی این ویژگی اطمینان حاصل کنید. نمونه‌ای از این بررسی در متد نمونه startFaceDetection() در زیر نشان داده شده است.

برای اینکه برنامه دوربین شما از تشخیص چهره مطلع شود و به آن پاسخ دهد، باید یک شنونده (listener) برای رویدادهای تشخیص چهره تنظیم کند. برای انجام این کار، باید یک کلاس شنونده (listener) ایجاد کنید که رابط Camera.FaceDetectionListener را همانطور که در کد مثال زیر نشان داده شده است، پیاده‌سازی کند.

کاتلین

internal class MyFaceDetectionListener : Camera.FaceDetectionListener {

    override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) {
        if (faces.isNotEmpty()) {
            Log.d("FaceDetection", ("face detected: ${faces.size}" +
                    " Face 1 Location X: ${faces[0].rect.centerX()}" +
                    "Y: ${faces[0].rect.centerY()}"))
        }
    }
}

جاوا

class MyFaceDetectionListener implements Camera.FaceDetectionListener {

    @Override
    public void onFaceDetection(Face[] faces, Camera camera) {
        if (faces.length > 0){
            Log.d("FaceDetection", "face detected: "+ faces.length +
                    " Face 1 Location X: " + faces[0].rect.centerX() +
                    "Y: " + faces[0].rect.centerY() );
        }
    }
}

پس از ایجاد این کلاس، آن را در شیء Camera برنامه خود قرار می‌دهید، همانطور که در کد مثال زیر نشان داده شده است:

کاتلین

camera?.setFaceDetectionListener(MyFaceDetectionListener())

جاوا

camera.setFaceDetectionListener(new MyFaceDetectionListener());

برنامه شما باید هر بار که پیش‌نمایش دوربین را شروع می‌کنید (یا مجدداً راه‌اندازی می‌کنید)، تابع تشخیص چهره را اجرا کند. یک متد برای شروع تشخیص چهره ایجاد کنید تا بتوانید در صورت نیاز آن را فراخوانی کنید، همانطور که در کد نمونه زیر نشان داده شده است.

کاتلین

fun startFaceDetection() {
    // Try starting Face Detection
    val params = mCamera?.parameters
    // start face detection only *after* preview has started

    params?.apply {
        if (maxNumDetectedFaces > 0) {
            // camera supports face detection, so can start it:
            mCamera?.startFaceDetection()
        }
    }
}

جاوا

public void startFaceDetection(){
    // Try starting Face Detection
    Camera.Parameters params = mCamera.getParameters();

    // start face detection only *after* preview has started
    if (params.getMaxNumDetectedFaces() > 0){
        // camera supports face detection, so can start it:
        mCamera.startFaceDetection();
    }
}

You must start face detection each time you start (or restart) the camera preview. If you use the preview class shown in Creating a preview class , add your startFaceDetection() method to both the surfaceCreated() and surfaceChanged() methods in your preview class, as shown in the sample code below.

کاتلین

override fun surfaceCreated(holder: SurfaceHolder) {
    try {
        mCamera.setPreviewDisplay(holder)
        mCamera.startPreview()

        startFaceDetection() // start face detection feature
    } catch (e: IOException) {
        Log.d(TAG, "Error setting camera preview: ${e.message}")
    }
}

override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
    if (holder.surface == null) {
        // preview surface does not exist
        Log.d(TAG, "holder.getSurface() == null")
        return
    }
    try {
        mCamera.stopPreview()
    } catch (e: Exception) {
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: ${e.message}")
    }
    try {
        mCamera.setPreviewDisplay(holder)
        mCamera.startPreview()

        startFaceDetection() // re-start face detection feature
    } catch (e: Exception) {
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: ${e.message}")
    }
}

جاوا

public void surfaceCreated(SurfaceHolder holder) {
    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // start face detection feature

    } catch (IOException e) {
        Log.d(TAG, "Error setting camera preview: " + e.getMessage());
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

    if (holder.getSurface() == null){
        // preview surface does not exist
        Log.d(TAG, "holder.getSurface() == null");
        return;
    }

    try {
        mCamera.stopPreview();

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: " + e.getMessage());
    }

    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // re-start face detection feature

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

Note: Remember to call this method after calling startPreview() . Do not attempt to start face detection in the onCreate() method of your camera app's main activity, as the preview is not available by this point in your application's the execution.

Time lapse video

Time lapse video allows users to create video clips that combine pictures taken a few seconds or minutes apart. This feature uses MediaRecorder to record the images for a time lapse sequence.

To record a time lapse video with MediaRecorder , you must configure the recorder object as if you are recording a normal video, setting the captured frames per second to a low number and using one of the time lapse quality settings, as shown in the code example below.

کاتلین

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH))
mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds

جاوا

// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH));
...
// Step 5.5: Set the video capture rate to a low number
mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds

These settings must be done as part of a larger configuration procedure for MediaRecorder . For a full configuration code example, see Configuring MediaRecorder . Once the configuration is complete, you start the video recording as if you were recording a normal video clip. For more information about configuring and running MediaRecorder , see Capturing videos .

The Camera2Video and HdrViewfinder samples further demonstrate the use of the APIs covered on this page.

Camera fields that require permission

Apps running Android 10 (API level 29) or higher must have the CAMERA permission in order to access the values of the following fields that the getCameraCharacteristics() method returns:

  • LENS_POSE_ROTATION
  • LENS_POSE_TRANSLATION
  • LENS_INTRINSIC_CALIBRATION
  • LENS_RADIAL_DISTORTION
  • LENS_POSE_REFERENCE
  • LENS_DISTORTION
  • LENS_INFO_HYPERFOCAL_DISTANCE
  • LENS_INFO_MINIMUM_FOCUS_DISTANCE
  • SENSOR_REFERENCE_ILLUMINANT1
  • SENSOR_REFERENCE_ILLUMINANT2
  • SENSOR_CALIBRATION_TRANSFORM1
  • SENSOR_CALIBRATION_TRANSFORM2
  • SENSOR_COLOR_TRANSFORM1
  • SENSOR_COLOR_TRANSFORM2
  • SENSOR_FORWARD_MATRIX1
  • SENSOR_FORWARD_MATRIX2

Additional sample code

To download sample apps, see the Camera2Basic sample and Official CameraX sample app .