دوربین API

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

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

ملاحظات

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

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

اصول اولیه

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

android.hardware.camera2
این بسته API اصلی برای کنترل دوربین های دستگاه است. هنگامی که در حال ساخت یک برنامه دوربین هستید، می توان از آن برای گرفتن عکس یا فیلم استفاده کرد.
Camera
این کلاس API قدیمی‌تر منسوخ برای کنترل دوربین‌های دستگاه است.
SurfaceView
این کلاس برای ارائه پیش نمایش دوربین زنده به کاربر استفاده می شود.
MediaRecorder
این کلاس برای ضبط فیلم از دوربین استفاده می شود.
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" />
    

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

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

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

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • مجوز ذخیره‌سازی - اگر برنامه شما Android 10 (سطح API 29) یا پایین‌تر را هدف قرار دهد و موارد زیر را در مانیفست مشخص کند، می‌تواند تصاویر یا ویدیوها را در حافظه خارجی دستگاه (کارت SD) ذخیره کند.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • مجوز ضبط صدا - برای ضبط صدا با ضبط ویدیو، برنامه شما باید مجوز ضبط صدا را درخواست کند.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • مجوز مکان - اگر برنامه شما تصاویر را با اطلاعات موقعیت مکانی GPS برچسب گذاری می کند، باید مجوز ACCESS_FINE_LOCATION را درخواست کنید. توجه داشته باشید که اگر برنامه شما Android 5.0 (سطح API 21) یا بالاتر را هدف قرار می دهد، باید اعلام کنید که برنامه شما از 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 برای فراخوانی یک برنامه دوربین اندروید موجود است. جزئیات در درس های آموزش عکس گرفتن به سادگی و ضبط فیلم به سادگی توضیح داده شده است.

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

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

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

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

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

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

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

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

اگر برنامه شما به طور خاص به دوربینی با استفاده از اعلان مانیفست نیاز ندارد، باید بررسی کنید که آیا دوربین در زمان اجرا در دسترس است یا خیر. برای انجام این بررسی، از متد 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;
    }
}

دستگاه های اندرویدی می توانند چندین دوربین داشته باشند، به عنوان مثال یک دوربین پشتی برای عکاسی و یک دوربین جلو برای تماس های ویدیویی. Android 2.3 (API Level 9) و جدیدتر به شما امکان می دهد با استفاده از روش Camera.getNumberOfCameras() تعداد دوربین های موجود در دستگاه را بررسی کنید.

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

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

برای دسترسی به دوربین اصلی، از روش 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() همیشه استثناها را بررسی کنید. اگر دوربین در حال استفاده باشد یا وجود نداشته باشد، بررسی نکردن استثنائات باعث می‌شود برنامه شما توسط سیستم خاموش شود.

در دستگاه‌های دارای Android 2.3 (API سطح 9) یا بالاتر، می‌توانید با استفاده از Camera.open(int) به دوربین‌های خاصی دسترسی داشته باشید. کد مثال بالا به اولین دوربین پشت دستگاهی با بیش از یک دوربین دسترسی خواهد داشت.

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

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

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

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

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

کاتلین

/** 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 در اندروید 7.0 (سطح 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>

توجه: لازم نیست پیش نمایش دوربین در حالت افقی باشد. با شروع Android 2.2 (API Level 8)، می‌توانید از متد 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() در مثال بالا به روش مثال نشان داده شده در دسترسی به دوربین ها اشاره دارد.

گرفتن عکس

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

برای بازیابی تصویر، از متد 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.release() شی Camera را آزاد کنید! برای اطلاعات در مورد نحوه آزاد کردن دوربین، رها کردن دوربین را ببینید.

فیلم برداری

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

توجه: با شروع Android 4.0 (سطح API 14)، تماس‌های Camera.lock() و Camera.unlock() بطور خودکار برای شما مدیریت می‌شوند.

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

  1. Open Camera - از 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. فرمت خروجی ویدیو و رمزگذاری را تنظیم کنید. برای Android 2.2 (API Level 8) و بالاتر، از روش MediaRecorder.setProfile استفاده کنید و یک نمونه نمایه را با استفاده از CamcorderProfile.get() دریافت کنید. برای نسخه‌های Android قبل از 2.2، باید فرمت خروجی ویدیو و پارامترهای رمزگذاری را تنظیم کنید:
        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() از روش مثال در بخش Saving Media Files استفاده کنید.
      6. setPreviewDisplay() - عنصر طرح بندی پیش نمایش SurfaceView را برای برنامه خود مشخص کنید. از همان شیئی که برای Connect Preview مشخص کرده اید استفاده کنید.

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

    3. آماده سازی MediaRecorder - MediaRecorder با تنظیمات پیکربندی ارائه شده با فراخوانی MediaRecorder.prepare() آماده کنید.
    4. شروع MediaRecorder - ضبط ویدیو را با فراخوانی MediaRecorder.start() شروع کنید.
  5. توقف ضبط ویدیو - برای تکمیل موفقیت آمیز ضبط ویدیو، روش های زیر را به ترتیب فراخوانی کنید:
    1. توقف MediaRecorder - با فراخوانی MediaRecorder.stop() ضبط ویدیو را متوقف کنید.
    2. بازنشانی MediaRecorder - در صورت تمایل، با فراخوانی MediaRecorder.reset() تنظیمات پیکربندی را از ضبط کننده حذف کنید.
    3. Release MediaRecorder - MediaRecorder با فراخوانی MediaRecorder.release() رها کنید.
    4. قفل کردن دوربین - دوربین را قفل کنید تا جلسات بعدی MediaRecorder با فراخوانی Camera.lock() از آن استفاده کنند. با شروع Android 4.0 (سطح API 14)، این تماس مورد نیاز نیست مگر اینکه فراخوانی MediaRecorder.prepare() ناموفق باشد.
  6. توقف پیش‌نمایش - وقتی فعالیت شما با استفاده از دوربین تمام شد، پیش‌نمایش را با استفاده از Camera.stopPreview() متوقف کنید.
  7. Release Camera - دوربین را رها کنید تا سایر برنامه ها بتوانند با فراخوانی 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;
}

قبل از Android 2.2 (API Level 8)، به جای استفاده از 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() به کد مثال نشان داده شده در Configuring MediaRecorder اشاره دارد. این روش از قفل کردن دوربین، پیکربندی و آماده سازی نمونه MediaRecorder مراقبت می کند.

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

دوربین ها منبعی هستند که توسط برنامه های کاربردی روی یک دستگاه به اشتراک گذاشته می شود. برنامه شما می تواند پس از دریافت نمونه Camera از 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) ذخیره شوند تا فضای سیستم حفظ شود و کاربران بتوانند بدون دستگاه خود به این فایل‌ها دسترسی داشته باشند. مکان های دایرکتوری زیادی برای ذخیره فایل های رسانه ای در دستگاه وجود دارد، با این حال تنها دو مکان استاندارد وجود دارد که باید به عنوان یک توسعه دهنده در نظر بگیرید:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) - این روش مکان استاندارد، مشترک و توصیه شده را برای ذخیره تصاویر و ویدیوها برمی گرداند. این دایرکتوری به اشتراک گذاشته شده است (عمومی)، بنابراین سایر برنامه ها می توانند به راحتی فایل های ذخیره شده در این مکان را کشف، خواندن، تغییر و حذف کنند. اگر برنامه شما توسط کاربر حذف نصب شود، فایل های رسانه ای ذخیره شده در این مکان حذف نخواهند شد. برای جلوگیری از تداخل با تصاویر و ویدیوهای موجود کاربران، باید یک دایرکتوری فرعی برای فایل های رسانه ای برنامه خود در این فهرست ایجاد کنید، همانطور که در نمونه کد زیر نشان داده شده است. این روش در Android 2.2 (سطح API 8) موجود است، برای تماس‌های مشابه در نسخه‌های قبلی 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() در اندروید 2.2 (سطح API 8) یا بالاتر موجود است. اگر دستگاه‌های دارای نسخه‌های قبلی اندروید را هدف قرار می‌دهید، به جای آن از Environment.getExternalStorageDirectory() استفاده کنید. برای اطلاعات بیشتر، به ذخیره فایل‌های مشترک مراجعه کنید.

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

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

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

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

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

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

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

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

بررسی در دسترس بودن ویژگی

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

می‌توانید با دریافت نمونه‌ای از شی پارامترهای دوربین و بررسی روش‌های مربوطه، در دسترس بودن ویژگی‌های دوربین را بررسی کنید. نمونه کد زیر به شما نشان می دهد که چگونه یک شی 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...() برای تعیین اینکه آیا (و تا چه حد) یک ویژگی پشتیبانی می شود ارائه می دهد.

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

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

اکثر ویژگی های دوربین با استفاده از یک شی 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 ، تغییر داد. تغییرات پارامترها معمولاً بلافاصله در پیش نمایش دوربین برنامه برای کاربر قابل مشاهده است. در سمت نرم افزار، تغییرات پارامتر ممکن است چندین فریم طول بکشد تا عملاً اعمال شود زیرا سخت افزار دوربین دستورالعمل های جدید را پردازش می کند و سپس داده های تصویر به روز شده را ارسال می کند.

مهم: برخی از ویژگی های دوربین را نمی توان به دلخواه تغییر داد. به ویژه، تغییر اندازه یا جهت پیش‌نمایش دوربین مستلزم آن است که ابتدا پیش‌نمایش را متوقف کنید، اندازه پیش‌نمایش را تغییر دهید و سپس پیش‌نمایش را مجدداً راه‌اندازی کنید. با شروع با Android 4.0 (API Level 14) جهت پیش‌نمایش را می‌توان بدون راه‌اندازی مجدد پیش‌نمایش تغییر داد.

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

  • مناطق اندازه گیری و فوکوس
  • تشخیص چهره
  • ویدیوی تایم لپس

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

مناطق اندازه گیری و فوکوس

در برخی از سناریوهای عکاسی، فوکوس خودکار و نورسنجی ممکن است نتایج دلخواه را به همراه نداشته باشد. با شروع Android 4.0 (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 یک شکل مستطیلی را توصیف می کند که روی یک شبکه 2000 x 2000 واحد نگاشت شده است. مختصات 1000-، 1000- نمایانگر گوشه بالا و سمت چپ تصویر دوربین و مختصات 1000، 1000 نمایانگر گوشه پایین و سمت راست تصویر دوربین است، همانطور که در تصویر زیر نشان داده شده است.

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

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

تشخیص چهره

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

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

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

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

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

برای اطلاع و پاسخ به تشخیص چهره، برنامه دوربین شما باید شنونده ای را برای رویدادهای تشخیص چهره تنظیم کند. برای انجام این کار، باید یک کلاس 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();
    }
}

هر بار که پیش‌نمایش دوربین را شروع (یا راه‌اندازی مجدد) می‌کنید، باید تشخیص چهره را شروع کنید. اگر از کلاس پیش نمایش نشان داده شده در ایجاد یک کلاس پیش نمایش استفاده می کنید ، روش startFaceDetection() خود را به هر دو روش surfaceCreated() و surfaceChanged() در کلاس پیش نمایش خود اضافه کنید ، همانطور که در کد نمونه زیر نشان داده شده است.

کاتلین

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());
    }
}

توجه: به یاد داشته باشید پس از تماس با startPreview() با این روش تماس بگیرید. سعی نکنید در روش onCreate() فعالیت اصلی برنامه دوربین خود ، تشخیص چهره را شروع کنید ، زیرا پیش نمایش تا این مرحله در اجرای برنامه شما در دسترس نیست.

ویدیوی با گذشت زمان

Time Lapse Video به کاربران امکان می دهد کلیپ های ویدیویی ایجاد کنند که تصاویر چند ثانیه یا چند دقیقه از هم جدا می شوند. این ویژگی از MediaRecorder برای ضبط تصاویر برای یک دنباله گذشت زمان استفاده می کند.

برای ضبط یک فیلم با گذشت زمان با MediaRecorder ، شما باید شیء ضبط را پیکربندی کنید که گویی در حال ضبط یک فیلم معمولی هستید ، قاب های ضبط شده در هر ثانیه را به تعداد کم تنظیم می کنید و از یکی از تنظیمات کیفیت با گذشت زمان استفاده می کنید ، همانطور که در مثال کد نشان داده شده است. زیر

کاتلین

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

این تنظیمات باید به عنوان بخشی از یک روش پیکربندی بزرگتر برای MediaRecorder انجام شود. برای مثال کد پیکربندی کامل ، به پیکربندی MediarEcorder مراجعه کنید. پس از اتمام پیکربندی ، ضبط ویدیو را شروع می کنید که انگار یک کلیپ ویدیویی معمولی را ضبط می کنید. برای کسب اطلاعات بیشتر در مورد پیکربندی و اجرای MediaRecorder ، به ضبط فیلم ها مراجعه کنید.

نمونه های Camera2Video و HDRViewFinder بیشتر استفاده از API های تحت پوشش در این صفحه را نشان می دهند.

زمینه های دوربین که نیاز به اجازه دارند

برنامه هایی که Android 10 (API سطح 29) یا بالاتر را اجرا می کنند ، برای دسترسی به مقادیر قسمتهای زیر که روش getCameraCharacteristics() باز می گردد ، باید از دوربین مجوز CAMERA داشته باشند:

  • 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

کد نمونه اضافی

برای بارگیری برنامه های نمونه ، به برنامه نمونه Camera2Basic و برنامه رسمی نمونه Camerax مراجعه کنید.

،

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

توجه: این صفحه کلاس Camera را توصیف می کند ، که کاهش یافته است. توصیه می کنیم از کتابخانه jetpack camerax یا برای موارد استفاده خاص ، camera2 ، کلاس استفاده کنید. هر دو Camerax و Camera2 در Android 5.0 (API سطح 21) و بالاتر کار می کنند.

به منابع مرتبط زیر مراجعه کنید:

ملاحظات

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

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

اصول اولیه

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

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

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

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

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

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

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

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

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

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

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • مجوز ذخیره سازی - برنامه شما می تواند تصاویر یا فیلم ها را در ذخیره خارجی دستگاه (کارت SD) ذخیره کند اگر Android 10 (API سطح 29) را هدف قرار دهد یا پایین تر باشد و موارد زیر را در مانیفست مشخص کند.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • مجوز ضبط صوتی - برای ضبط صدا با ضبط ویدیو ، برنامه شما باید مجوز ضبط صوتی را درخواست کند.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • مجوز موقعیت مکانی - اگر برنامه شما تصاویر را با اطلاعات موقعیت مکانی GPS برچسب گذاری می کند ، باید مجوز ACCESS_FINE_LOCATION را درخواست کنید. توجه داشته باشید که اگر برنامه شما Android 5.0 (API سطح 21) یا بالاتر را هدف قرار دهد ، باید اعلام کنید که برنامه شما از 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 فراخوانی یک برنامه دوربین موجود در Android است. جزئیات در دروس آموزش گرفتن عکس به سادگی و ضبط فیلم به سادگی شرح داده شده است.

ساختن یک برنامه دوربین

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

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

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

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

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

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

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

اگر برنامه شما به طور خاص به دوربین با استفاده از اعلامیه مانیفست احتیاج ندارد ، باید بررسی کنید که آیا یک دوربین در زمان اجرا در دسترس است یا خیر. برای انجام این بررسی ، از روش 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;
    }
}

دستگاه های Android می توانند چندین دوربین داشته باشند ، به عنوان مثال یک دوربین پشتی برای عکاسی و یک دوربین جلوی آن برای تماس های ویدیویی. Android 2.3 (API سطح 9) و بعداً به شما امکان می دهد تعداد دوربین های موجود در یک دستگاه را با استفاده از Camera.getNumberOfCameras() بررسی کنید.

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

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

برای دسترسی به دوربین اصلی ، از روش 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() استثنائات را بررسی کنید. عدم بررسی استثنائات در صورت استفاده از دوربین یا وجود ندارد ، باعث می شود که برنامه شما توسط سیستم خاموش شود.

در دستگاه هایی که Android 2.3 (API سطح 9) یا بالاتر را اجرا می کنند ، می توانید با استفاده از Camera.open(int) به دوربین های خاص دسترسی پیدا کنید. کد مثال در بالا به دوربین اول و پشتی در دستگاهی با بیش از یک دوربین دسترسی پیدا می کند.

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

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

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

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

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

کاتلین

/** 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 در Android 7.0 (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>

توجه: پیش نمایش دوربین لازم نیست در حالت چشم انداز باشد. با شروع از Android 2.2 (API سطح 8) ، می توانید از روش 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() در مثال بالا به روش مثال نشان داده شده در دسترسی به دوربین ها اشاره دارد.

ضبط تصاویر

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

برای بازیابی یک تصویر ، از روش 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());
        }
    }
};

Trigger با استفاده از روش 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.release() شیء Camera را آزاد کنید. وقتی برنامه شما با استفاده از آن انجام می شود! برای اطلاعات در مورد نحوه انتشار دوربین ، به انتشار دوربین مراجعه کنید.

ضبط فیلم

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

توجه: شروع با Android 4.0 (API سطح 14) ، تماس های Camera.lock() و Camera.unlock() برای شما به طور خودکار مدیریت می شوند.

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

  1. دوربین باز - از Camera.open() استفاده کنید تا نمونه ای از شیء دوربین را بدست آورید.
  2. اتصال پیش نمایش - پیش نمایش تصویر دوربین زنده را با اتصال یک SurfaceView به دوربین با استفاده از Camera.setPreviewDisplay() تهیه کنید.
  3. پیش نمایش را شروع کنید - Camera.startPreview() برای شروع نمایش تصاویر دوربین زنده.
  4. ضبط ویدیو را شروع کنید - مراحل زیر باید برای ضبط موفقیت آمیز فیلم انجام شود:
    1. قفل دوربین را باز کنید - دوربین را برای استفاده توسط MediaRecorder با تماس با Camera.unlock() باز کنید.
    2. پیکربندی MediarEcorder - به این ترتیب با روش های MediaRecorder زیر تماس بگیرید. برای اطلاعات بیشتر ، به مستندات مرجع MediaRecorder مراجعه کنید.
      1. setCamera() - دوربین را برای ضبط ویدیو تنظیم کنید ، از نمونه فعلی Camera برنامه خود استفاده کنید.
      2. setAudioSource() - منبع صوتی را تنظیم کنید ، از MediaRecorder.AudioSource.CAMCORDER استفاده کنید.
      3. setVideoSource() - منبع ویدیو را تنظیم کنید ، از MediaRecorder.VideoSource.CAMERA استفاده کنید.
      4. فرمت خروجی ویدیو و رمزگذاری را تنظیم کنید. برای Android 2.2 (API سطح 8) و بالاتر ، از روش MediaRecorder.setProfile استفاده کنید و با استفاده از CamcorderProfile.get() یک نمونه مشخصات دریافت کنید. برای نسخه های Android قبل از 2.2 ، باید فرمت خروجی ویدیو و پارامترهای رمزگذاری را تنظیم کنید:
        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 را برای برنامه خود مشخص کنید. از همان شیئی که برای پیش نمایش اتصال مشخص کرده اید استفاده کنید.

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

    3. آماده سازی MediarEcorder - با فراخوانی MediaRecorder.prepare() ، MediaRecorder با تنظیمات پیکربندی ارائه شده آماده کنید.
    4. MediarEcorder را شروع کنید - با تماس با MediaRecorder.start() ضبط ویدیو را شروع کنید.
  5. ضبط ویدیو را متوقف کنید - به ترتیب با روش های زیر تماس بگیرید تا با موفقیت یک ضبط ویدیو را انجام دهید:
    1. Stop MediarEcorder - ضبط فیلم را با تماس با MediaRecorder.stop() متوقف کنید.
    2. RESET MEDIARECORDER - به صورت اختیاری ، تنظیمات پیکربندی را از ضبط کننده با فراخوانی MediaRecorder.reset() حذف کنید.
    3. Release MediarEcorder - با فراخوانی MediaRecorder.release() MediaRecorder آزاد کنید.
    4. دوربین را قفل کنید - دوربین را قفل کنید تا جلسات آینده MediaRecorder بتواند با فراخوانی Camera.lock() از آن استفاده کند. با شروع Android 4.0 (API سطح 14) ، این تماس لازم نیست مگر اینکه تماس 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;
}

قبل از Android 2.2 (API سطح 8) ، باید به جای استفاده از 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) ذخیره شوند تا فضای سیستم را حفظ کنند و به کاربران امکان دسترسی به این پرونده ها را بدون دستگاه خود بدهند. بسیاری از مکان های دایرکتوری ممکن برای ذخیره پرونده های رسانه ای در یک دستگاه وجود دارد ، اما فقط دو مکان استاندارد وجود دارد که باید به عنوان یک توسعه دهنده در نظر بگیرید:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) - این روش مکان استاندارد ، به اشتراک گذاشته شده و توصیه شده را برای ذخیره تصاویر و فیلم ها برمی گرداند. این فهرست به اشتراک گذاشته می شود (عمومی) ، بنابراین سایر برنامه ها می توانند به راحتی پرونده های ذخیره شده در این مکان را کشف ، خواندن ، تغییر و حذف کنند. اگر برنامه شما توسط کاربر حذف نشده باشد ، پرونده های رسانه ای ذخیره شده در این مکان حذف نمی شوند. برای جلوگیری از دخالت در تصاویر و فیلم های موجود در کاربران ، باید همانطور که در نمونه کد زیر نشان داده شده است ، برای پرونده های رسانه ای برنامه خود در این فهرست ، یک کارگردانی ایجاد کنید. این روش در Android 2.2 (API سطح 8) در دسترس است ، برای تماس های معادل در نسخه های قبلی 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() در Android 2.2 (سطح API 8) یا بالاتر موجود است. اگر دستگاه هایی را با نسخه های قبلی Android هدف قرار می دهید ، به جای آن Environment.getExternalStorageDirectory() استفاده کنید. برای اطلاعات بیشتر ، به ذخیره فایلهای مشترک مراجعه کنید.

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

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

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

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

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

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

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

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

بررسی در دسترس بودن ویژگی

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

می توانید با دریافت نمونه ای از شیء پارامترهای دوربین و بررسی روشهای مربوطه ، در دسترس بودن ویژگی های دوربین را بررسی کنید. نمونه کد زیر به شما نشان می دهد که چگونه یک 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...() برای تعیین اینکه آیا (و تا چه حد) یک ویژگی پشتیبانی می شود.

اگر برنامه شما برای عملکرد صحیح به ویژگی های دوربین خاصی نیاز دارد ، می توانید از طریق موارد اضافی در آشکار برنامه خود به آنها نیاز داشته باشید. هنگامی که شما استفاده از ویژگی های دوربین خاص مانند Flash و Auto-Focus را اعلام می کنید ، Google Play برنامه شما را از نصب در دستگاه هایی که از این ویژگی ها پشتیبانی نمی کنند ، محدود می کند. برای لیستی از ویژگی های دوربین که می توان در برنامه شما را مانیفست اعلام کرد ، به مرجع ویژگی های مانیفست مراجعه کنید.

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

بیشتر ویژگی های دوربین با استفاده از یک شیء 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 ، می توانند در هر زمان تغییر کنند. تغییرات در پارامترها معمولاً در پیش نمایش دوربین برنامه بلافاصله برای کاربر قابل مشاهده است. از طرف نرم افزار ، تغییرات پارامترها ممکن است چندین فریم را به خود اختصاص دهند تا در واقع به عنوان سخت افزار دوربین دستورالعمل های جدید را پردازش می کند و سپس داده های تصویر به روز شده را ارسال می کند.

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

سایر ویژگی های دوربین برای اجرای ، از جمله:

  • مناطق اندازه گیری و تمرکز
  • تشخیص چهره
  • ویدیوی با گذشت زمان

طرح کلی سریع از نحوه اجرای این ویژگی ها در بخش های زیر ارائه شده است.

مناطق اندازه گیری و تمرکز

در برخی از سناریوهای عکاسی ، تمرکز اتوماتیک و اندازه گیری نور ممکن است نتایج مطلوب را به همراه نکند. با شروع Android 4.0 (API سطح 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 AREA یک شکل مستطیل شکل نقشه برداری شده بر روی یک شبکه واحد 2000 2000 2000 را توصیف می کند. مختصات -1000 ، -1000 گوشه بالا ، سمت چپ تصویر دوربین را نشان می دهد و مختصات 1000 ، 1000 گوشه پایین ، سمت راست تصویر دوربین را نشان می دهد ، همانطور که در تصویر زیر نشان داده شده است.

شکل 1. خطوط قرمز سیستم مختصات را برای مشخص کردن Camera.Area نشان می دهد. در یک پیش نمایش دوربین. جعبه آبی مکان و شکل یک منطقه دوربین را با مقادیر Rect 333،333،667،667 نشان می دهد.

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

تشخیص چهره

For pictures that include people, faces are usually the most important part of the picture, and should be used for determining both focus and white balance when capturing an image. The Android 4.0 (API Level 14) framework provides APIs for identifying faces and calculating picture settings using face recognition technology.

Note: While the face detection feature is running, setWhiteBalance(String) , setFocusAreas(List<Camera.Area>) and setMeteringAreas(List<Camera.Area>) have no effect.

Using the face detection feature in your camera application requires a few general steps:

  • Check that face detection is supported on the device
  • Create a face detection listener
  • Add the face detection listener to your camera object
  • Start face detection after preview (and after every preview restart)

The face detection feature is not supported on all devices. You can check that this feature is supported by calling getMaxNumDetectedFaces() . An example of this check is shown in the startFaceDetection() sample method below.

In order to be notified and respond to the detection of a face, your camera application must set a listener for face detection events. In order to do this, you must create a listener class that implements the Camera.FaceDetectionListener interface as shown in the example code below.

کاتلین

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() );
        }
    }
}

After creating this class, you then set it into your application's Camera object, as shown in the example code below:

کاتلین

camera?.setFaceDetectionListener(MyFaceDetectionListener())

جاوا

camera.setFaceDetectionListener(new MyFaceDetectionListener());

Your application must start the face detection function each time you start (or restart) the camera preview. Create a method for starting face detection so you can call it as needed, as shown in the example code below.

کاتلین

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 زیر

کاتلین

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 .

،

The Android framework includes support for various cameras and camera features available on devices, allowing you to capture pictures and videos in your applications. This document discusses a quick, simple approach to image and video capture and outlines an advanced approach for creating custom camera experiences for your users.

Note: This page describes the Camera class, which has been deprecated. We recommend using the CameraX Jetpack library or, for specific use cases, the camera2 , class. Both CameraX and Camera2 work on Android 5.0 (API level 21) and higher.

Refer to the following related resources:

ملاحظات

Before enabling your application to use cameras on Android devices, you should consider a few questions about how your app intends to use this hardware feature.

  • Camera Requirement - Is the use of a camera so important to your application that you do not want your application installed on a device that does not have a camera? If so, you should declare the camera requirement in your manifest .
  • Quick Picture or Customized Camera - How will your application use the camera? Are you just interested in snapping a quick picture or video clip, or will your application provide a new way to use cameras? For getting a quick snap or clip, consider Using Existing Camera Apps . For developing a customized camera feature, check out the Building a Camera App section.
  • Foreground Services Requirement - When does your app interact with the camera? On Android 9 (API level 28) and later, apps running in the background cannot access the camera. Therefore, you should use the camera either when your app is in the foreground or as part of a foreground service .
  • Storage - Are the images or videos your application generates intended to be only visible to your application or shared so that other applications such as Gallery or other media and social apps can use them? Do you want the pictures and videos to be available even if your application is uninstalled? Check out the Saving Media Files section to see how to implement these options.

اصول اولیه

The Android framework supports capturing images and video through the android.hardware.camera2 API or camera Intent . Here are the relevant classes:

android.hardware.camera2
This package is the primary API for controlling device cameras. It can be used to take pictures or videos when you are building a camera application.
Camera
This class is the older deprecated API for controlling device cameras.
SurfaceView
This class is used to present a live camera preview to the user.
MediaRecorder
این کلاس برای ضبط فیلم از دوربین استفاده می شود.
Intent
An intent action type of MediaStore.ACTION_IMAGE_CAPTURE or MediaStore.ACTION_VIDEO_CAPTURE can be used to capture images or videos without directly using the Camera object.

Manifest declarations

Before starting development on your application with the Camera API, you should make sure your manifest has the appropriate declarations to allow use of camera hardware and other related features.

  • Camera Permission - Your application must request permission to use a device camera.
    <uses-permission android:name="android.permission.CAMERA" />
    

    Note: If you are using the camera by invoking an existing camera app , your application does not need to request this permission.

  • Camera Features - Your application must also declare use of camera features, for example:
    <uses-feature android:name="android.hardware.camera" />
    

    For a list of camera features, see the manifest Features Reference .

    Adding camera features to your manifest causes Google Play to prevent your application from being installed to devices that do not include a camera or do not support the camera features you specify. For more information about using feature-based filtering with Google Play, see Google Play and Feature-Based Filtering .

    If your application can use a camera or camera feature for proper operation, but does not require it, you should specify this in the manifest by including the android:required attribute, and setting it to false :

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • Storage Permission - Your application can save images or videos to the device's external storage (SD Card) if it targets Android 10 (API level 29) or lower and specifies the following in the manifest.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Audio Recording Permission - For recording audio with video capture, your application must request the audio capture permission.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • Location Permission - If your application tags images with GPS location information, you must request the ACCESS_FINE_LOCATION permission. Note that, if your app targets Android 5.0 (API level 21) or higher, you also need to declare that your app uses the device's 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" />
    

    For more information about getting user location, see Location Strategies .

Using existing camera apps

A quick way to enable taking pictures or videos in your application without a lot of extra code is to use an Intent to invoke an existing Android camera application. The details are described in the training lessons Taking Photos Simply and Recording Videos Simply .

Building a camera app

Some developers may require a camera user interface that is customized to the look of their application or provides special features. Writing your own picture-taking code can provide a more compelling experience for your users.

Note: The following guide is for the older, deprecated Camera API. For new or advanced camera applications, the newer android.hardware.camera2 API is recommended.

The general steps for creating a custom camera interface for your application are as follows:

  • Detect and Access Camera - Create code to check for the existence of cameras and request access.
  • Create a Preview Class - Create a camera preview class that extends SurfaceView and implements the SurfaceHolder interface. This class previews the live images from the camera.
  • Build a Preview Layout - Once you have the camera preview class, create a view layout that incorporates the preview and the user interface controls you want.
  • Setup Listeners for Capture - Connect listeners for your interface controls to start image or video capture in response to user actions, such as pressing a button.
  • Capture and Save Files - Setup the code for capturing pictures or videos and saving the output.
  • Release the Camera - After using the camera, your application must properly release it for use by other applications.

Camera hardware is a shared resource that must be carefully managed so your application does not collide with other applications that may also want to use it. The following sections discusses how to detect camera hardware, how to request access to a camera, how to capture pictures or video and how to release the camera when your application is done using it.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

Detecting camera hardware

If your application does not specifically require a camera using a manifest declaration, you should check to see if a camera is available at runtime. To perform this check, use the PackageManager.hasSystemFeature() method, as shown in the example code below:

کاتلین

/** 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;
    }
}

Android devices can have multiple cameras, for example a back-facing camera for photography and a front-facing camera for video calls. Android 2.3 (API Level 9) and later allows you to check the number of cameras available on a device using the Camera.getNumberOfCameras() method.

Accessing cameras

If you have determined that the device on which your application is running has a camera, you must request to access it by getting an instance of Camera (unless you are using an intent to access the camera ).

To access the primary camera, use the Camera.open() method and be sure to catch any exceptions, as shown in the code below:

کاتلین

/** 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
}

Caution: Always check for exceptions when using Camera.open() . Failing to check for exceptions if the camera is in use or does not exist will cause your application to be shut down by the system.

On devices running Android 2.3 (API Level 9) or higher, you can access specific cameras using Camera.open(int) . The example code above will access the first, back-facing camera on a device with more than one camera.

Checking camera features

Once you obtain access to a camera, you can get further information about its capabilities using the Camera.getParameters() method and checking the returned Camera.Parameters object for supported capabilities. When using API Level 9 or higher, use the Camera.getCameraInfo() to determine if a camera is on the front or back of the device, and the orientation of the image.

Creating a preview class

For users to effectively take pictures or video, they must be able to see what the device camera sees. A camera preview class is a SurfaceView that can display the live image data coming from a camera, so users can frame and capture a picture or video.

The following example code demonstrates how to create a basic camera preview class that can be included in a View layout. This class implements SurfaceHolder.Callback in order to capture the callback events for creating and destroying the view, which are needed for assigning the camera preview input.

کاتلین

/** 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());
        }
    }
}

If you want to set a specific size for your camera preview, set this in the surfaceChanged() method as noted in the comments above. When setting preview size, you must use values from getSupportedPreviewSizes() . Do not set arbitrary values in the setPreviewSize() method.

Note: With the introduction of the Multi-Window feature in Android 7.0 (API level 24) and higher, you can no longer assume the aspect ratio of the preview is the same as your activity even after calling setDisplayOrientation() . Depending on the window size and aspect ratio, you may may have to fit a wide camera preview into a portrait-orientated layout, or vice versa, using a letterbox layout.

Placing preview in a layout

A camera preview class, such as the example shown in the previous section, must be placed in the layout of an activity along with other user interface controls for taking a picture or video. This section shows you how to build a basic layout and activity for the preview.

The following layout code provides a very basic view that can be used to display a camera preview. In this example, the FrameLayout element is meant to be the container for the camera preview class. This layout type is used so that additional picture information or controls can be overlaid on the live camera preview images.

<?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>

On most devices, the default orientation of the camera preview is landscape. This example layout specifies a horizontal (landscape) layout and the code below fixes the orientation of the application to landscape. For simplicity in rendering a camera preview, you should change your application's preview activity orientation to landscape by adding the following to your manifest.

<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>

Note: A camera preview does not have to be in landscape mode. Starting in Android 2.2 (API Level 8), you can use the setDisplayOrientation() method to set the rotation of the preview image. In order to change preview orientation as the user re-orients the phone, within the surfaceChanged() method of your preview class, first stop the preview with Camera.stopPreview() change the orientation and then start the preview again with Camera.startPreview() .

In the activity for your camera view, add your preview class to the FrameLayout element shown in the example above. Your camera activity must also ensure that it releases the camera when it is paused or shut down. The following example shows how to modify a camera activity to attach the preview class shown in Creating a preview class .

کاتلین

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);
    }
}

Note: The getCameraInstance() method in the example above refers to the example method shown in Accessing cameras .

Capturing pictures

Once you have built a preview class and a view layout in which to display it, you are ready to start capturing images with your application. In your application code, you must set up listeners for your user interface controls to respond to a user action by taking a picture.

In order to retrieve a picture, use the Camera.takePicture() method. This method takes three parameters which receive data from the camera. In order to receive data in a JPEG format, you must implement an Camera.PictureCallback interface to receive the image data and write it to a file. The following code shows a basic implementation of the Camera.PictureCallback interface to save an image received from the camera.

کاتلین

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());
        }
    }
};

Trigger capturing an image by calling the Camera.takePicture() method. The following example code shows how to call this method from a button 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);
        }
    }
);

Note: The mPicture member in the following example refers to the example code above.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! For information about how to release the camera, see Releasing the camera .

Capturing videos

Video capture using the Android framework requires careful management of the Camera object and coordination with the MediaRecorder class. When recording video with Camera , you must manage the Camera.lock() and Camera.unlock() calls to allow MediaRecorder access to the camera hardware, in addition to the Camera.open() and Camera.release() calls.

Note: Starting with Android 4.0 (API level 14), the Camera.lock() and Camera.unlock() calls are managed for you automatically.

Unlike taking pictures with a device camera, capturing video requires a very particular call order. You must follow a specific order of execution to successfully prepare for and capture video with your application, as detailed below.

  1. Open Camera - Use the Camera.open() to get an instance of the camera object.
  2. Connect Preview - Prepare a live camera image preview by connecting a SurfaceView to the camera using Camera.setPreviewDisplay() .
  3. Start Preview - Call Camera.startPreview() to begin displaying the live camera images.
  4. Start Recording Video - The following steps must be completed in order to successfully record video:
    1. Unlock the Camera - Unlock the camera for use by MediaRecorder by calling Camera.unlock() .
    2. Configure MediaRecorder - Call in the following MediaRecorder methods in this order . For more information, see the MediaRecorder reference documentation.
      1. setCamera() - Set the camera to be used for video capture, use your application's current instance of Camera .
      2. setAudioSource() - Set the audio source, use MediaRecorder.AudioSource.CAMCORDER .
      3. setVideoSource() - Set the video source, use MediaRecorder.VideoSource.CAMERA .
      4. Set the video output format and encoding. For Android 2.2 (API Level 8) and higher, use the MediaRecorder.setProfile method, and get a profile instance using CamcorderProfile.get() . For versions of Android prior to 2.2, you must set the video output format and encoding parameters:
        1. setOutputFormat() - Set the output format, specify the default setting or MediaRecorder.OutputFormat.MPEG_4 .
        2. setAudioEncoder() - Set the sound encoding type, specify the default setting or MediaRecorder.AudioEncoder.AMR_NB .
        3. setVideoEncoder() - Set the video encoding type, specify the default setting or MediaRecorder.VideoEncoder.MPEG_4_SP .
      5. setOutputFile() - Set the output file, use getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() from the example method in the Saving Media Files section.
      6. setPreviewDisplay() - Specify the SurfaceView preview layout element for your application. Use the same object you specified for Connect Preview .

      Caution: You must call these MediaRecorder configuration methods in this order , otherwise your application will encounter errors and the recording will fail.

    3. Prepare MediaRecorder - Prepare the MediaRecorder with provided configuration settings by calling MediaRecorder.prepare() .
    4. Start MediaRecorder - Start recording video by calling MediaRecorder.start() .
  5. Stop Recording Video - Call the following methods in order , to successfully complete a video recording:
    1. Stop MediaRecorder - Stop recording video by calling MediaRecorder.stop() .
    2. Reset MediaRecorder - Optionally, remove the configuration settings from the recorder by calling MediaRecorder.reset() .
    3. Release MediaRecorder - Release the MediaRecorder by calling MediaRecorder.release() .
    4. Lock the Camera - Lock the camera so that future MediaRecorder sessions can use it by calling Camera.lock() . Starting with Android 4.0 (API level 14), this call is not required unless the MediaRecorder.prepare() call fails.
  6. Stop the Preview - When your activity has finished using the camera, stop the preview using Camera.stopPreview() .
  7. Release Camera - Release the camera so that other applications can use it by calling Camera.release() .

Note: It is possible to use MediaRecorder without creating a camera preview first and skip the first few steps of this process. However, since users typically prefer to see a preview before starting a recording, that process is not discussed here.

Tip: If your application is typically used for recording video, set setRecordingHint(boolean) to true prior to starting your preview. This setting can help reduce the time it takes to start recording.

Configuring MediaRecorder

When using the MediaRecorder class to record video, you must perform configuration steps in a specific order and then call the MediaRecorder.prepare() method to check and implement the configuration. The following example code demonstrates how to properly configure and prepare the MediaRecorder class for video recording.

کاتلین

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;
}

Prior to Android 2.2 (API Level 8), you must set the output format and encoding formats parameters directly, instead of using CamcorderProfile . This approach is demonstrated in the following code:

کاتلین

    // 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);

The following video recording parameters for MediaRecorder are given default settings, however, you may want to adjust these settings for your application:

Starting and stopping MediaRecorder

When starting and stopping video recording using the MediaRecorder class, you must follow a specific order, as listed below.

  1. Unlock the camera with Camera.unlock()
  2. Configure MediaRecorder as shown in the code example above
  3. Start recording using MediaRecorder.start()
  4. Record the video
  5. Stop recording using MediaRecorder.stop()
  6. Release the media recorder with MediaRecorder.release()
  7. Lock the camera using Camera.lock()

The following example code demonstrates how to wire up a button to properly start and stop video recording using the camera and the MediaRecorder class.

Note: When completing a video recording, do not release the camera or else your preview will be stopped.

کاتلین

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
                }
            }
        }
    }
);

Note: In the above example, the prepareVideoRecorder() method refers to the example code shown in Configuring MediaRecorder . This method takes care of locking the camera, configuring and preparing the MediaRecorder instance.

Releasing the camera

Cameras are a resource that is shared by applications on a device. Your application can make use of the camera after getting an instance of Camera , and you must be particularly careful to release the camera object when your application stops using it, and as soon as your application is paused ( Activity.onPause() ). If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

To release an instance of the Camera object, use the Camera.release() method, as shown in the example code below.

کاتلین

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;
        }
    }
}

Caution: If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

Saving media files

Media files created by users such as pictures and videos should be saved to a device's external storage directory (SD Card) to conserve system space and to allow users to access these files without their device. There are many possible directory locations to save media files on a device, however there are only two standard locations you should consider as a developer:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) - This method returns the standard, shared and recommended location for saving pictures and videos. This directory is shared (public), so other applications can easily discover, read, change and delete files saved in this location. If your application is uninstalled by the user, media files saved to this location will not be removed. To avoid interfering with users existing pictures and videos, you should create a sub-directory for your application's media files within this directory, as shown in the code sample below. This method is available in Android 2.2 (API Level 8), for equivalent calls in earlier API versions, see Saving Shared Files .
  • Context.getExternalFilesDir ( Environment.DIRECTORY_PICTURES ) - This method returns a standard location for saving pictures and videos which are associated with your application. If your application is uninstalled, any files saved in this location are removed. Security is not enforced for files in this location and other applications may read, change and delete them.

The following example code demonstrates how to create a File or Uri location for a media file that can be used when invoking a device's camera with an Intent or as part of a Building a Camera App .

کاتلین

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;
}

Note: Environment.getExternalStoragePublicDirectory() is available in Android 2.2 (API Level 8) or higher. If you are targeting devices with earlier versions of Android, use Environment.getExternalStorageDirectory() instead. For more information, see Saving Shared Files .

To make the URI support work profiles, first convert the file URI to a content URI . Then, add the content URI to EXTRA_OUTPUT of an Intent .

For more information about saving files on an Android device, see Data Storage .

Camera features

Android supports a wide array of camera features you can control with your camera application, such as picture format, flash mode, focus settings, and many more. This section lists the common camera features, and briefly discusses how to use them. Most camera features can be accessed and set using the through Camera.Parameters object. However, there are several important features that require more than simple settings in Camera.Parameters . These features are covered in the following sections:

For general information about how to use features that are controlled through Camera.Parameters , review the Using camera features section. For more detailed information about how to use features controlled through the camera parameters object, follow the links in the feature list below to the API reference documentation.

Table 1. Common camera features sorted by the Android API Level in which they were introduced.

ویژگی API Level توضیحات
تشخیص چهره 14 Identify human faces within a picture and use them for focus, metering and white balance
Metering Areas 14 Specify one or more areas within an image for calculating white balance
Focus Areas 14 Set one or more areas within an image to use for focus
White Balance Lock 14 Stop or start automatic white balance adjustments
Exposure Lock 14 Stop or start automatic exposure adjustments
Video Snapshot 14 Take a picture while shooting video (frame grab)
Time Lapse Video 11 Record frames with set delays to record a time lapse video
Multiple Cameras 9 Support for more than one camera on a device, including front-facing and back-facing cameras
Focus Distance 9 Reports distances between the camera and objects that appear to be in focus
Zoom 8 Set image magnification
Exposure Compensation 8 Increase or decrease the light exposure level
GPS Data 5 Include or omit geographic location data with the image
White Balance 5 Set the white balance mode, which affects color values in the captured image
Focus Mode 5 Set how the camera focuses on a subject such as automatic, fixed, macro or infinity
Scene Mode 5 Apply a preset mode for specific types of photography situations such as night, beach, snow or candlelight scenes
JPEG Quality 5 Set the compression level for a JPEG image, which increases or decreases image output file quality and size
Flash Mode 5 Turn flash on, off, or use automatic setting
Color Effects 5 Apply a color effect to the captured image such as black and white, sepia tone or negative.
Anti-Banding 5 Reduces the effect of banding in color gradients due to JPEG compression
Picture Format 1 Specify the file format for the picture
Picture Size 1 Specify the pixel dimensions of the saved picture

Note: These features are not supported on all devices due to hardware differences and software implementation. For information on checking the availability of features on the device where your application is running, see Checking feature availability .

Checking feature availability

The first thing to understand when setting out to use camera features on Android devices is that not all camera features are supported on all devices. In addition, devices that support a particular feature may support them to different levels or with different options. Therefore, part of your decision process as you develop a camera application is to decide what camera features you want to support and to what level. After making that decision, you should plan on including code in your camera application that checks to see if device hardware supports those features and fails gracefully if a feature is not available.

You can check the availability of camera features by getting an instance of a camera's parameters object, and checking the relevant methods. The following code sample shows you how to obtain a Camera.Parameters object and check if the camera supports the autofocus feature:

کاتلین

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
}

You can use the technique shown above for most camera features. The Camera.Parameters object provides a getSupported...() , is...Supported() or getMax...() method to determine if (and to what extent) a feature is supported.

If your application requires certain camera features in order to function properly, you can require them through additions to your application manifest. When you declare the use of specific camera features, such as flash and auto-focus, Google Play restricts your application from being installed on devices which do not support these features. For a list of camera features that can be declared in your app manifest, see the manifest Features Reference .

Using camera features

Most camera features are activated and controlled using a Camera.Parameters object. You obtain this object by first getting an instance of the Camera object, calling the getParameters() method, changing the returned parameter object and then setting it back into the camera object, as demonstrated in the following example code:

کاتلین

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);

This technique works for nearly all camera features, and most parameters can be changed at any time after you have obtained an instance of the Camera object. Changes to parameters are typically visible to the user immediately in the application's camera preview. On the software side, parameter changes may take several frames to actually take effect as the camera hardware processes the new instructions and then sends updated image data.

Important: Some camera features cannot be changed at will. In particular, changing the size or orientation of the camera preview requires that you first stop the preview, change the preview size, and then restart the preview. Starting with Android 4.0 (API Level 14) preview orientation can be changed without restarting the preview.

Other camera features require more code in order to implement, including:

  • Metering and focus areas
  • تشخیص چهره
  • Time lapse video

A quick outline of how to implement these features is provided in the following sections.

Metering and focus areas

In some photographic scenarios, automatic focusing and light metering may not produce the desired results. Starting with Android 4.0 (API Level 14), your camera application can provide additional controls to allow your app or users to specify areas in an image to use for determining focus or light level settings and pass these values to the camera hardware for use in capturing images or video.

Areas for metering and focus work very similarly to other camera features, in that you control them through methods in the Camera.Parameters object. The following code demonstrates setting two light metering areas for an instance of 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);

The Camera.Area object contains two data parameters: A Rect object for specifying an area within the camera's field of view and a weight value, which tells the camera what level of importance this area should be given in light metering or focus calculations.

The Rect field in a Camera.Area object describes a rectangular shape mapped on a 2000 x 2000 unit grid. The coordinates -1000, -1000 represent the top, left corner of the camera image, and coordinates 1000, 1000 represent the bottom, right corner of the camera image, as shown in the illustration below.

Figure 1. The red lines illustrate the coordinate system for specifying a Camera.Area within a camera preview. The blue box shows the location and shape of an camera area with the Rect values 333,333,667,667.

The bounds of this coordinate system always correspond to the outer edge of the image visible in the camera preview and do not shrink or expand with the zoom level. Similarly, rotation of the image preview using Camera.setDisplayOrientation() does not remap the coordinate system.

تشخیص چهره

For pictures that include people, faces are usually the most important part of the picture, and should be used for determining both focus and white balance when capturing an image. The Android 4.0 (API Level 14) framework provides APIs for identifying faces and calculating picture settings using face recognition technology.

Note: While the face detection feature is running, setWhiteBalance(String) , setFocusAreas(List<Camera.Area>) and setMeteringAreas(List<Camera.Area>) have no effect.

Using the face detection feature in your camera application requires a few general steps:

  • Check that face detection is supported on the device
  • Create a face detection listener
  • Add the face detection listener to your camera object
  • Start face detection after preview (and after every preview restart)

The face detection feature is not supported on all devices. You can check that this feature is supported by calling getMaxNumDetectedFaces() . An example of this check is shown in the startFaceDetection() sample method below.

In order to be notified and respond to the detection of a face, your camera application must set a listener for face detection events. In order to do this, you must create a listener class that implements the Camera.FaceDetectionListener interface as shown in the example code below.

کاتلین

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() );
        }
    }
}

After creating this class, you then set it into your application's Camera object, as shown in the example code below:

کاتلین

camera?.setFaceDetectionListener(MyFaceDetectionListener())

جاوا

camera.setFaceDetectionListener(new MyFaceDetectionListener());

Your application must start the face detection function each time you start (or restart) the camera preview. Create a method for starting face detection so you can call it as needed, as shown in the example code below.

کاتلین

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 زیر

کاتلین

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 .

،

The Android framework includes support for various cameras and camera features available on devices, allowing you to capture pictures and videos in your applications. This document discusses a quick, simple approach to image and video capture and outlines an advanced approach for creating custom camera experiences for your users.

Note: This page describes the Camera class, which has been deprecated. We recommend using the CameraX Jetpack library or, for specific use cases, the camera2 , class. Both CameraX and Camera2 work on Android 5.0 (API level 21) and higher.

Refer to the following related resources:

ملاحظات

Before enabling your application to use cameras on Android devices, you should consider a few questions about how your app intends to use this hardware feature.

  • Camera Requirement - Is the use of a camera so important to your application that you do not want your application installed on a device that does not have a camera? If so, you should declare the camera requirement in your manifest .
  • Quick Picture or Customized Camera - How will your application use the camera? Are you just interested in snapping a quick picture or video clip, or will your application provide a new way to use cameras? For getting a quick snap or clip, consider Using Existing Camera Apps . For developing a customized camera feature, check out the Building a Camera App section.
  • Foreground Services Requirement - When does your app interact with the camera? On Android 9 (API level 28) and later, apps running in the background cannot access the camera. Therefore, you should use the camera either when your app is in the foreground or as part of a foreground service .
  • Storage - Are the images or videos your application generates intended to be only visible to your application or shared so that other applications such as Gallery or other media and social apps can use them? Do you want the pictures and videos to be available even if your application is uninstalled? Check out the Saving Media Files section to see how to implement these options.

اصول اولیه

The Android framework supports capturing images and video through the android.hardware.camera2 API or camera Intent . Here are the relevant classes:

android.hardware.camera2
This package is the primary API for controlling device cameras. It can be used to take pictures or videos when you are building a camera application.
Camera
This class is the older deprecated API for controlling device cameras.
SurfaceView
This class is used to present a live camera preview to the user.
MediaRecorder
این کلاس برای ضبط فیلم از دوربین استفاده می شود.
Intent
An intent action type of MediaStore.ACTION_IMAGE_CAPTURE or MediaStore.ACTION_VIDEO_CAPTURE can be used to capture images or videos without directly using the Camera object.

Manifest declarations

Before starting development on your application with the Camera API, you should make sure your manifest has the appropriate declarations to allow use of camera hardware and other related features.

  • Camera Permission - Your application must request permission to use a device camera.
    <uses-permission android:name="android.permission.CAMERA" />
    

    Note: If you are using the camera by invoking an existing camera app , your application does not need to request this permission.

  • Camera Features - Your application must also declare use of camera features, for example:
    <uses-feature android:name="android.hardware.camera" />
    

    For a list of camera features, see the manifest Features Reference .

    Adding camera features to your manifest causes Google Play to prevent your application from being installed to devices that do not include a camera or do not support the camera features you specify. For more information about using feature-based filtering with Google Play, see Google Play and Feature-Based Filtering .

    If your application can use a camera or camera feature for proper operation, but does not require it, you should specify this in the manifest by including the android:required attribute, and setting it to false :

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • Storage Permission - Your application can save images or videos to the device's external storage (SD Card) if it targets Android 10 (API level 29) or lower and specifies the following in the manifest.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Audio Recording Permission - For recording audio with video capture, your application must request the audio capture permission.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • Location Permission - If your application tags images with GPS location information, you must request the ACCESS_FINE_LOCATION permission. Note that, if your app targets Android 5.0 (API level 21) or higher, you also need to declare that your app uses the device's 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" />
    

    For more information about getting user location, see Location Strategies .

Using existing camera apps

A quick way to enable taking pictures or videos in your application without a lot of extra code is to use an Intent to invoke an existing Android camera application. The details are described in the training lessons Taking Photos Simply and Recording Videos Simply .

Building a camera app

Some developers may require a camera user interface that is customized to the look of their application or provides special features. Writing your own picture-taking code can provide a more compelling experience for your users.

Note: The following guide is for the older, deprecated Camera API. For new or advanced camera applications, the newer android.hardware.camera2 API is recommended.

The general steps for creating a custom camera interface for your application are as follows:

  • Detect and Access Camera - Create code to check for the existence of cameras and request access.
  • Create a Preview Class - Create a camera preview class that extends SurfaceView and implements the SurfaceHolder interface. This class previews the live images from the camera.
  • Build a Preview Layout - Once you have the camera preview class, create a view layout that incorporates the preview and the user interface controls you want.
  • Setup Listeners for Capture - Connect listeners for your interface controls to start image or video capture in response to user actions, such as pressing a button.
  • Capture and Save Files - Setup the code for capturing pictures or videos and saving the output.
  • Release the Camera - After using the camera, your application must properly release it for use by other applications.

Camera hardware is a shared resource that must be carefully managed so your application does not collide with other applications that may also want to use it. The following sections discusses how to detect camera hardware, how to request access to a camera, how to capture pictures or video and how to release the camera when your application is done using it.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

Detecting camera hardware

If your application does not specifically require a camera using a manifest declaration, you should check to see if a camera is available at runtime. To perform this check, use the PackageManager.hasSystemFeature() method, as shown in the example code below:

کاتلین

/** 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;
    }
}

Android devices can have multiple cameras, for example a back-facing camera for photography and a front-facing camera for video calls. Android 2.3 (API Level 9) and later allows you to check the number of cameras available on a device using the Camera.getNumberOfCameras() method.

Accessing cameras

If you have determined that the device on which your application is running has a camera, you must request to access it by getting an instance of Camera (unless you are using an intent to access the camera ).

To access the primary camera, use the Camera.open() method and be sure to catch any exceptions, as shown in the code below:

کاتلین

/** 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
}

Caution: Always check for exceptions when using Camera.open() . Failing to check for exceptions if the camera is in use or does not exist will cause your application to be shut down by the system.

On devices running Android 2.3 (API Level 9) or higher, you can access specific cameras using Camera.open(int) . The example code above will access the first, back-facing camera on a device with more than one camera.

Checking camera features

Once you obtain access to a camera, you can get further information about its capabilities using the Camera.getParameters() method and checking the returned Camera.Parameters object for supported capabilities. When using API Level 9 or higher, use the Camera.getCameraInfo() to determine if a camera is on the front or back of the device, and the orientation of the image.

Creating a preview class

For users to effectively take pictures or video, they must be able to see what the device camera sees. A camera preview class is a SurfaceView that can display the live image data coming from a camera, so users can frame and capture a picture or video.

The following example code demonstrates how to create a basic camera preview class that can be included in a View layout. This class implements SurfaceHolder.Callback in order to capture the callback events for creating and destroying the view, which are needed for assigning the camera preview input.

کاتلین

/** 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());
        }
    }
}

If you want to set a specific size for your camera preview, set this in the surfaceChanged() method as noted in the comments above. When setting preview size, you must use values from getSupportedPreviewSizes() . Do not set arbitrary values in the setPreviewSize() method.

Note: With the introduction of the Multi-Window feature in Android 7.0 (API level 24) and higher, you can no longer assume the aspect ratio of the preview is the same as your activity even after calling setDisplayOrientation() . Depending on the window size and aspect ratio, you may may have to fit a wide camera preview into a portrait-orientated layout, or vice versa, using a letterbox layout.

Placing preview in a layout

A camera preview class, such as the example shown in the previous section, must be placed in the layout of an activity along with other user interface controls for taking a picture or video. This section shows you how to build a basic layout and activity for the preview.

The following layout code provides a very basic view that can be used to display a camera preview. In this example, the FrameLayout element is meant to be the container for the camera preview class. This layout type is used so that additional picture information or controls can be overlaid on the live camera preview images.

<?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>

On most devices, the default orientation of the camera preview is landscape. This example layout specifies a horizontal (landscape) layout and the code below fixes the orientation of the application to landscape. For simplicity in rendering a camera preview, you should change your application's preview activity orientation to landscape by adding the following to your manifest.

<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>

Note: A camera preview does not have to be in landscape mode. Starting in Android 2.2 (API Level 8), you can use the setDisplayOrientation() method to set the rotation of the preview image. In order to change preview orientation as the user re-orients the phone, within the surfaceChanged() method of your preview class, first stop the preview with Camera.stopPreview() change the orientation and then start the preview again with Camera.startPreview() .

In the activity for your camera view, add your preview class to the FrameLayout element shown in the example above. Your camera activity must also ensure that it releases the camera when it is paused or shut down. The following example shows how to modify a camera activity to attach the preview class shown in Creating a preview class .

کاتلین

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);
    }
}

Note: The getCameraInstance() method in the example above refers to the example method shown in Accessing cameras .

Capturing pictures

Once you have built a preview class and a view layout in which to display it, you are ready to start capturing images with your application. In your application code, you must set up listeners for your user interface controls to respond to a user action by taking a picture.

In order to retrieve a picture, use the Camera.takePicture() method. This method takes three parameters which receive data from the camera. In order to receive data in a JPEG format, you must implement an Camera.PictureCallback interface to receive the image data and write it to a file. The following code shows a basic implementation of the Camera.PictureCallback interface to save an image received from the camera.

کاتلین

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());
        }
    }
};

Trigger capturing an image by calling the Camera.takePicture() method. The following example code shows how to call this method from a button 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);
        }
    }
);

Note: The mPicture member in the following example refers to the example code above.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! For information about how to release the camera, see Releasing the camera .

Capturing videos

Video capture using the Android framework requires careful management of the Camera object and coordination with the MediaRecorder class. When recording video with Camera , you must manage the Camera.lock() and Camera.unlock() calls to allow MediaRecorder access to the camera hardware, in addition to the Camera.open() and Camera.release() calls.

Note: Starting with Android 4.0 (API level 14), the Camera.lock() and Camera.unlock() calls are managed for you automatically.

Unlike taking pictures with a device camera, capturing video requires a very particular call order. You must follow a specific order of execution to successfully prepare for and capture video with your application, as detailed below.

  1. Open Camera - Use the Camera.open() to get an instance of the camera object.
  2. Connect Preview - Prepare a live camera image preview by connecting a SurfaceView to the camera using Camera.setPreviewDisplay() .
  3. Start Preview - Call Camera.startPreview() to begin displaying the live camera images.
  4. Start Recording Video - The following steps must be completed in order to successfully record video:
    1. Unlock the Camera - Unlock the camera for use by MediaRecorder by calling Camera.unlock() .
    2. Configure MediaRecorder - Call in the following MediaRecorder methods in this order . For more information, see the MediaRecorder reference documentation.
      1. setCamera() - Set the camera to be used for video capture, use your application's current instance of Camera .
      2. setAudioSource() - Set the audio source, use MediaRecorder.AudioSource.CAMCORDER .
      3. setVideoSource() - Set the video source, use MediaRecorder.VideoSource.CAMERA .
      4. Set the video output format and encoding. For Android 2.2 (API Level 8) and higher, use the MediaRecorder.setProfile method, and get a profile instance using CamcorderProfile.get() . For versions of Android prior to 2.2, you must set the video output format and encoding parameters:
        1. setOutputFormat() - Set the output format, specify the default setting or MediaRecorder.OutputFormat.MPEG_4 .
        2. setAudioEncoder() - Set the sound encoding type, specify the default setting or MediaRecorder.AudioEncoder.AMR_NB .
        3. setVideoEncoder() - Set the video encoding type, specify the default setting or MediaRecorder.VideoEncoder.MPEG_4_SP .
      5. setOutputFile() - Set the output file, use getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() from the example method in the Saving Media Files section.
      6. setPreviewDisplay() - Specify the SurfaceView preview layout element for your application. Use the same object you specified for Connect Preview .

      Caution: You must call these MediaRecorder configuration methods in this order , otherwise your application will encounter errors and the recording will fail.

    3. Prepare MediaRecorder - Prepare the MediaRecorder with provided configuration settings by calling MediaRecorder.prepare() .
    4. Start MediaRecorder - Start recording video by calling MediaRecorder.start() .
  5. Stop Recording Video - Call the following methods in order , to successfully complete a video recording:
    1. Stop MediaRecorder - Stop recording video by calling MediaRecorder.stop() .
    2. Reset MediaRecorder - Optionally, remove the configuration settings from the recorder by calling MediaRecorder.reset() .
    3. Release MediaRecorder - Release the MediaRecorder by calling MediaRecorder.release() .
    4. Lock the Camera - Lock the camera so that future MediaRecorder sessions can use it by calling Camera.lock() . Starting with Android 4.0 (API level 14), this call is not required unless the MediaRecorder.prepare() call fails.
  6. Stop the Preview - When your activity has finished using the camera, stop the preview using Camera.stopPreview() .
  7. Release Camera - Release the camera so that other applications can use it by calling Camera.release() .

Note: It is possible to use MediaRecorder without creating a camera preview first and skip the first few steps of this process. However, since users typically prefer to see a preview before starting a recording, that process is not discussed here.

Tip: If your application is typically used for recording video, set setRecordingHint(boolean) to true prior to starting your preview. This setting can help reduce the time it takes to start recording.

Configuring MediaRecorder

When using the MediaRecorder class to record video, you must perform configuration steps in a specific order and then call the MediaRecorder.prepare() method to check and implement the configuration. The following example code demonstrates how to properly configure and prepare the MediaRecorder class for video recording.

کاتلین

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;
}

Prior to Android 2.2 (API Level 8), you must set the output format and encoding formats parameters directly, instead of using CamcorderProfile . This approach is demonstrated in the following code:

کاتلین

    // 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);

The following video recording parameters for MediaRecorder are given default settings, however, you may want to adjust these settings for your application:

Starting and stopping MediaRecorder

When starting and stopping video recording using the MediaRecorder class, you must follow a specific order, as listed below.

  1. Unlock the camera with Camera.unlock()
  2. Configure MediaRecorder as shown in the code example above
  3. Start recording using MediaRecorder.start()
  4. Record the video
  5. Stop recording using MediaRecorder.stop()
  6. Release the media recorder with MediaRecorder.release()
  7. Lock the camera using Camera.lock()

The following example code demonstrates how to wire up a button to properly start and stop video recording using the camera and the MediaRecorder class.

Note: When completing a video recording, do not release the camera or else your preview will be stopped.

کاتلین

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
                }
            }
        }
    }
);

Note: In the above example, the prepareVideoRecorder() method refers to the example code shown in Configuring MediaRecorder . This method takes care of locking the camera, configuring and preparing the MediaRecorder instance.

Releasing the camera

Cameras are a resource that is shared by applications on a device. Your application can make use of the camera after getting an instance of Camera , and you must be particularly careful to release the camera object when your application stops using it, and as soon as your application is paused ( Activity.onPause() ). If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

To release an instance of the Camera object, use the Camera.release() method, as shown in the example code below.

کاتلین

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;
        }
    }
}

Caution: If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

Saving media files

Media files created by users such as pictures and videos should be saved to a device's external storage directory (SD Card) to conserve system space and to allow users to access these files without their device. There are many possible directory locations to save media files on a device, however there are only two standard locations you should consider as a developer:

  • Environment.getExternalStoragePublicDirectory ( Environment.DIRECTORY_PICTURES ) - This method returns the standard, shared and recommended location for saving pictures and videos. This directory is shared (public), so other applications can easily discover, read, change and delete files saved in this location. If your application is uninstalled by the user, media files saved to this location will not be removed. To avoid interfering with users existing pictures and videos, you should create a sub-directory for your application's media files within this directory, as shown in the code sample below. This method is available in Android 2.2 (API Level 8), for equivalent calls in earlier API versions, see Saving Shared Files .
  • Context.getExternalFilesDir ( Environment.DIRECTORY_PICTURES ) - This method returns a standard location for saving pictures and videos which are associated with your application. If your application is uninstalled, any files saved in this location are removed. Security is not enforced for files in this location and other applications may read, change and delete them.

The following example code demonstrates how to create a File or Uri location for a media file that can be used when invoking a device's camera with an Intent or as part of a Building a Camera App .

کاتلین

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;
}

Note: Environment.getExternalStoragePublicDirectory() is available in Android 2.2 (API Level 8) or higher. If you are targeting devices with earlier versions of Android, use Environment.getExternalStorageDirectory() instead. For more information, see Saving Shared Files .

To make the URI support work profiles, first convert the file URI to a content URI . Then, add the content URI to EXTRA_OUTPUT of an Intent .

For more information about saving files on an Android device, see Data Storage .

Camera features

Android supports a wide array of camera features you can control with your camera application, such as picture format, flash mode, focus settings, and many more. This section lists the common camera features, and briefly discusses how to use them. Most camera features can be accessed and set using the through Camera.Parameters object. However, there are several important features that require more than simple settings in Camera.Parameters . These features are covered in the following sections:

For general information about how to use features that are controlled through Camera.Parameters , review the Using camera features section. For more detailed information about how to use features controlled through the camera parameters object, follow the links in the feature list below to the API reference documentation.

Table 1. Common camera features sorted by the Android API Level in which they were introduced.

ویژگی API Level توضیحات
تشخیص چهره 14 Identify human faces within a picture and use them for focus, metering and white balance
Metering Areas 14 Specify one or more areas within an image for calculating white balance
Focus Areas 14 Set one or more areas within an image to use for focus
White Balance Lock 14 Stop or start automatic white balance adjustments
Exposure Lock 14 Stop or start automatic exposure adjustments
Video Snapshot 14 Take a picture while shooting video (frame grab)
Time Lapse Video 11 Record frames with set delays to record a time lapse video
Multiple Cameras 9 Support for more than one camera on a device, including front-facing and back-facing cameras
Focus Distance 9 Reports distances between the camera and objects that appear to be in focus
Zoom 8 Set image magnification
Exposure Compensation 8 Increase or decrease the light exposure level
GPS Data 5 Include or omit geographic location data with the image
White Balance 5 Set the white balance mode, which affects color values in the captured image
Focus Mode 5 Set how the camera focuses on a subject such as automatic, fixed, macro or infinity
Scene Mode 5 Apply a preset mode for specific types of photography situations such as night, beach, snow or candlelight scenes
JPEG Quality 5 Set the compression level for a JPEG image, which increases or decreases image output file quality and size
Flash Mode 5 Turn flash on, off, or use automatic setting
Color Effects 5 Apply a color effect to the captured image such as black and white, sepia tone or negative.
Anti-Banding 5 Reduces the effect of banding in color gradients due to JPEG compression
Picture Format 1 Specify the file format for the picture
Picture Size 1 Specify the pixel dimensions of the saved picture

Note: These features are not supported on all devices due to hardware differences and software implementation. For information on checking the availability of features on the device where your application is running, see Checking feature availability .

Checking feature availability

The first thing to understand when setting out to use camera features on Android devices is that not all camera features are supported on all devices. In addition, devices that support a particular feature may support them to different levels or with different options. Therefore, part of your decision process as you develop a camera application is to decide what camera features you want to support and to what level. After making that decision, you should plan on including code in your camera application that checks to see if device hardware supports those features and fails gracefully if a feature is not available.

You can check the availability of camera features by getting an instance of a camera's parameters object, and checking the relevant methods. The following code sample shows you how to obtain a Camera.Parameters object and check if the camera supports the autofocus feature:

کاتلین

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
}

You can use the technique shown above for most camera features. The Camera.Parameters object provides a getSupported...() , is...Supported() or getMax...() method to determine if (and to what extent) a feature is supported.

If your application requires certain camera features in order to function properly, you can require them through additions to your application manifest. When you declare the use of specific camera features, such as flash and auto-focus, Google Play restricts your application from being installed on devices which do not support these features. For a list of camera features that can be declared in your app manifest, see the manifest Features Reference .

Using camera features

Most camera features are activated and controlled using a Camera.Parameters object. You obtain this object by first getting an instance of the Camera object, calling the getParameters() method, changing the returned parameter object and then setting it back into the camera object, as demonstrated in the following example code:

کاتلین

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);

This technique works for nearly all camera features, and most parameters can be changed at any time after you have obtained an instance of the Camera object. Changes to parameters are typically visible to the user immediately in the application's camera preview. On the software side, parameter changes may take several frames to actually take effect as the camera hardware processes the new instructions and then sends updated image data.

Important: Some camera features cannot be changed at will. In particular, changing the size or orientation of the camera preview requires that you first stop the preview, change the preview size, and then restart the preview. Starting with Android 4.0 (API Level 14) preview orientation can be changed without restarting the preview.

Other camera features require more code in order to implement, including:

  • Metering and focus areas
  • تشخیص چهره
  • Time lapse video

A quick outline of how to implement these features is provided in the following sections.

Metering and focus areas

In some photographic scenarios, automatic focusing and light metering may not produce the desired results. Starting with Android 4.0 (API Level 14), your camera application can provide additional controls to allow your app or users to specify areas in an image to use for determining focus or light level settings and pass these values to the camera hardware for use in capturing images or video.

Areas for metering and focus work very similarly to other camera features, in that you control them through methods in the Camera.Parameters object. The following code demonstrates setting two light metering areas for an instance of 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);

The Camera.Area object contains two data parameters: A Rect object for specifying an area within the camera's field of view and a weight value, which tells the camera what level of importance this area should be given in light metering or focus calculations.

The Rect field in a Camera.Area object describes a rectangular shape mapped on a 2000 x 2000 unit grid. The coordinates -1000, -1000 represent the top, left corner of the camera image, and coordinates 1000, 1000 represent the bottom, right corner of the camera image, as shown in the illustration below.

Figure 1. The red lines illustrate the coordinate system for specifying a Camera.Area within a camera preview. The blue box shows the location and shape of an camera area with the Rect values 333,333,667,667.

The bounds of this coordinate system always correspond to the outer edge of the image visible in the camera preview and do not shrink or expand with the zoom level. Similarly, rotation of the image preview using Camera.setDisplayOrientation() does not remap the coordinate system.

تشخیص چهره

For pictures that include people, faces are usually the most important part of the picture, and should be used for determining both focus and white balance when capturing an image. The Android 4.0 (API Level 14) framework provides APIs for identifying faces and calculating picture settings using face recognition technology.

Note: While the face detection feature is running, setWhiteBalance(String) , setFocusAreas(List<Camera.Area>) and setMeteringAreas(List<Camera.Area>) have no effect.

Using the face detection feature in your camera application requires a few general steps:

  • Check that face detection is supported on the device
  • Create a face detection listener
  • Add the face detection listener to your camera object
  • Start face detection after preview (and after every preview restart)

The face detection feature is not supported on all devices. You can check that this feature is supported by calling getMaxNumDetectedFaces() . An example of this check is shown in the startFaceDetection() sample method below.

In order to be notified and respond to the detection of a face, your camera application must set a listener for face detection events. In order to do this, you must create a listener class that implements the Camera.FaceDetectionListener interface as shown in the example code below.

کاتلین

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() );
        }
    }
}

After creating this class, you then set it into your application's Camera object, as shown in the example code below:

کاتلین

camera?.setFaceDetectionListener(MyFaceDetectionListener())

جاوا

camera.setFaceDetectionListener(new MyFaceDetectionListener());

Your application must start the face detection function each time you start (or restart) the camera preview. Create a method for starting face detection so you can call it as needed, as shown in the example code below.

کاتلین

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 زیر

کاتلین

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 .