API กล้องถ่ายรูป

หน้านี้อ้างอิงถึงคลาส Camera ซึ่งเลิกใช้งานแล้ว เราขอแนะนำให้ใช้ CameraX หรือ Camera2 สำหรับกรณีการใช้งานที่เฉพาะเจาะจง ทั้ง CameraX และ Camera2 รองรับ Android 5.0 (API ระดับ 21) ขึ้นไป

หากต้องการดูวิธีย้ายข้อมูลจาก Camera1 ไปยัง CameraX โปรดดูหัวข้อย้ายข้อมูล Camera1 ไปยัง CameraX หรือจะใช้ทักษะแบบ Agentic สำหรับการย้ายข้อมูลจาก Camera1 ไปยัง CameraX ก็ได้

เฟรมเวิร์ก Android รองรับกล้องและฟีเจอร์กล้องต่างๆ ที่มีในอุปกรณ์ ซึ่งช่วยให้คุณถ่ายภาพและวิดีโอในแอปพลิเคชันได้ เอกสารนี้จะกล่าวถึงแนวทางที่รวดเร็วและง่ายดายในการจับภาพและวิดีโอ รวมถึงสรุปแนวทางขั้นสูงในการสร้างประสบการณ์การใช้งานกล้องที่กำหนดเองสำหรับผู้ใช้

โปรดดูแหล่งข้อมูลที่เกี่ยวข้องต่อไปนี้

ข้อควรพิจารณา

ก่อนเปิดใช้แอปพลิเคชันเพื่อใช้กล้องในอุปกรณ์ Android คุณควรพิจารณาคำถามบางข้อเกี่ยวกับวิธีที่แอปของคุณตั้งใจจะใช้ฟีเจอร์ฮาร์ดแวร์นี้

  • ข้อกำหนดเกี่ยวกับกล้อง - การใช้กล้องมีความสำคัญต่อแอปพลิเคชันของคุณมากจนคุณไม่ต้องการให้ติดตั้งแอปพลิเคชันในอุปกรณ์ที่ไม่มีกล้องใช่ไหม หากเป็นเช่นนั้น คุณควรประกาศข้อกำหนดของกล้องในไฟล์ Manifest
  • รูปภาพด่วนหรือกล้องที่ปรับแต่งเอง - แอปพลิเคชันของคุณจะใช้กล้องอย่างไร คุณสนใจแค่การถ่ายภาพหรือวิดีโอคลิปสั้นๆ หรือแอปพลิเคชันของคุณจะมอบวิธีใหม่ในการใช้กล้อง หากต้องการถ่ายภาพหรือคลิปสั้นๆ ให้พิจารณาการใช้แอปกล้องที่มีอยู่ หากต้องการพัฒนาฟีเจอร์กล้องที่ปรับแต่งเอง โปรดดูส่วนการสร้างแอปกล้อง
  • ข้อกำหนดของบริการที่ทำงานอยู่เบื้องหน้า - แอปของคุณโต้ตอบกับกล้องเมื่อใด ใน Android 9 (ระดับ API 28) ขึ้นไป แอปที่ทำงานอยู่เบื้องหลังจะเข้าถึงกล้องไม่ได้ ดังนั้น คุณควรใช้กล้องเมื่อแอปอยู่เบื้องหน้าหรือเป็นส่วนหนึ่งของบริการที่ทำงานอยู่เบื้องหน้า
  • พื้นที่เก็บข้อมูล - รูปภาพหรือวิดีโอที่แอปพลิเคชันของคุณสร้างขึ้นมีไว้เพื่อให้แอปพลิเคชันของคุณมองเห็นได้เท่านั้น หรือแชร์เพื่อให้แอปพลิเคชันอื่นๆ เช่น แกลเลอรีหรือแอปสื่อและแอปโซเชียลอื่นๆ สามารถใช้ได้หรือไม่ คุณต้องการให้รูปภาพและวิดีโอพร้อมใช้งานแม้ว่าจะถอนการติดตั้งแอปพลิเคชันแล้วใช่ไหม ดูวิธีใช้ตัวเลือกเหล่านี้ได้ในส่วนการบันทึกไฟล์สื่อ

ข้อมูลเบื้องต้น

เฟรมเวิร์ก Android รองรับการจับภาพและวิดีโอผ่าน android.hardware.camera2 API หรือ Intent ของกล้อง คลาสที่เกี่ยวข้องมีดังนี้

android.hardware.camera2
แพ็กเกจนี้เป็น API หลักสำหรับควบคุมกล้องของอุปกรณ์ ซึ่งสามารถใช้เพื่อถ่ายภาพหรือวิดีโอเมื่อคุณสร้างแอปพลิเคชันกล้อง
Camera
คลาสนี้เป็น API ที่เลิกใช้งานแล้วซึ่งใช้สำหรับควบคุมกล้องของอุปกรณ์
SurfaceView
คลาสนี้ใช้เพื่อแสดงตัวอย่างกล้องแบบเรียลไทม์แก่ผู้ใช้
MediaRecorder
คลาสนี้ใช้เพื่อบันทึกวิดีโอจากกล้อง
Intent
คุณสามารถใช้ประเภทการดำเนินการ Intent MediaStore.ACTION_IMAGE_CAPTURE หรือ MediaStore.ACTION_VIDEO_CAPTURE เพื่อจับภาพหรือวิดีโอโดยไม่ต้องใช้ ออบเจ็กต์ Camera โดยตรง

การประกาศไฟล์ Manifest

ก่อนเริ่มพัฒนาแอปพลิเคชันด้วย Camera API คุณควรตรวจสอบว่าไฟล์ Manifest มีการประกาศที่เหมาะสมเพื่ออนุญาตให้ใช้ฮาร์ดแวร์กล้องและฟีเจอร์อื่นๆ ที่เกี่ยวข้อง

  • สิทธิ์เข้าถึงกล้อง - แอปพลิเคชันของคุณต้องขอสิทธิ์ใช้กล้องของอุปกรณ์
    <uses-permission android:name="android.permission.CAMERA" />

    หมายเหตุ: หากคุณใช้กล้องโดยเรียกใช้แอปกล้องที่มีอยู่ แอปพลิเคชันของคุณไม่จำเป็นต้องขอสิทธิ์นี้

  • ฟีเจอร์กล้อง - แอปพลิเคชันของคุณต้องประกาศการใช้ฟีเจอร์กล้องด้วย เช่น
    <uses-feature android:name="android.hardware.camera" />

    ดูรายการฟีเจอร์ของกล้องได้ที่ข้อมูลอ้างอิงฟีเจอร์ของไฟล์ Manifest

    การเพิ่มฟีเจอร์กล้องลงในไฟล์ Manifest จะทำให้ Google Play ป้องกันไม่ให้ติดตั้งแอปพลิเคชันในอุปกรณ์ที่ไม่มีกล้องหรือไม่รองรับฟีเจอร์กล้องที่คุณระบุ ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้การกรองตามฟีเจอร์กับ Google Play ได้ที่ Google Play และการกรองตามฟีเจอร์

    หากแอปพลิเคชันของคุณสามารถใช้กล้องหรือฟีเจอร์กล้องเพื่อให้ทำงานได้อย่างถูกต้อง แต่ไม่ได้กำหนดให้ต้องมี คุณควรระบุสิ่งนี้ในไฟล์ Manifest โดยใส่แอตทริบิวต์ android:required และตั้งค่าเป็น false ดังนี้

    <uses-feature android:name="android.hardware.camera" android:required="false" />
  • สิทธิ์เข้าถึงพื้นที่เก็บข้อมูล - แอปพลิเคชันของคุณสามารถบันทึกรูปภาพหรือวิดีโอลงในที่จัดเก็บข้อมูลภายนอก (การ์ด SD) ของอุปกรณ์ได้หากกำหนดเป้าหมายเป็น Android 10 (ระดับ API 29) หรือต่ำกว่า และระบุสิ่งต่อไปนี้ในไฟล์ Manifest
    <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 ที่มีอยู่ รายละเอียดอธิบายไว้ในบทเรียนการฝึกอบรมการถ่ายภาพอย่างง่ายและการบันทึกวิดีโออย่างง่าย

การสร้างแอปกล้องถ่ายรูป

นักพัฒนาแอปบางรายอาจต้องการอินเทอร์เฟซผู้ใช้ของกล้องที่ปรับแต่งให้เข้ากับรูปลักษณ์ของแอปพลิเคชันหรือมีฟีเจอร์พิเศษ การเขียนโค้ดถ่ายภาพของคุณเอง จะช่วยมอบประสบการณ์ที่น่าสนใจยิ่งขึ้นให้แก่ผู้ใช้

หมายเหตุ: คู่มือต่อไปนี้มีไว้สำหรับ Camera API เวอร์ชันเก่าที่เลิกใช้งานแล้ว สำหรับแอปพลิเคชันกล้องใหม่หรือขั้นสูง ขอแนะนำให้ใช้ android.hardware.camera2 API เวอร์ชันใหม่กว่า

ขั้นตอนทั่วไปในการสร้างอินเทอร์เฟซกล้องที่กำหนดเองสำหรับแอปพลิเคชันมีดังนี้

  • ตรวจจับและเข้าถึงกล้อง - สร้างโค้ดเพื่อตรวจสอบว่ามีกล้องอยู่หรือไม่และขอสิทธิ์เข้าถึง
  • สร้างคลาสแสดงตัวอย่าง - สร้างคลาสแสดงตัวอย่างจากกล้องที่ขยาย SurfaceView และใช้อินเทอร์เฟซ SurfaceHolder คลาสนี้จะแสดงตัวอย่างรูปภาพสดจากกล้อง
  • สร้างเลย์เอาต์ตัวอย่าง - เมื่อมีคลาสตัวอย่างกล้องแล้ว ให้สร้างเลย์เอาต์มุมมองที่รวมตัวอย่างและการควบคุมอินเทอร์เฟซผู้ใช้ที่คุณต้องการ
  • ตั้งค่า Listener สำหรับการจับภาพ - เชื่อมต่อ Listener สำหรับการควบคุมอินเทอร์เฟซเพื่อเริ่มจับภาพหรือวิดีโอเพื่อตอบสนองต่อการดำเนินการของผู้ใช้ เช่น การกดปุ่ม
  • จับภาพและบันทึกไฟล์ - ตั้งค่าโค้ดสำหรับการจับภาพหรือวิดีโอและบันทึกเอาต์พุต
  • ปล่อยกล้อง - หลังจากใช้กล้องแล้ว แอปพลิเคชันของคุณต้องปล่อยกล้องอย่างเหมาะสมเพื่อให้แอปพลิเคชันอื่นๆ ใช้งานได้

ฮาร์ดแวร์กล้องเป็นทรัพยากรที่ใช้ร่วมกันซึ่งต้องได้รับการจัดการอย่างรอบคอบ เพื่อไม่ให้แอปพลิเคชันของคุณขัดแย้งกับแอปพลิเคชันอื่นๆ ที่อาจต้องการใช้ฮาร์ดแวร์กล้องเช่นกัน ส่วนต่อไปนี้จะอธิบายวิธีตรวจหาฮาร์ดแวร์กล้อง วิธีขอสิทธิ์เข้าถึงกล้อง วิธีจับภาพหรือวิดีโอ และวิธีปล่อยกล้องเมื่อแอปพลิเคชันใช้งานเสร็จแล้ว

ข้อควรระวัง: อย่าลืมปล่อยออบเจ็กต์ Camera โดยเรียกใช้ Camera.release() เมื่อแอปพลิเคชันของคุณใช้เสร็จแล้ว หากแอปพลิเคชันของคุณไม่ปล่อยกล้องอย่างถูกต้อง ความพยายามทั้งหมดในการเข้าถึงกล้องในภายหลัง รวมถึงความพยายามของแอปพลิเคชันของคุณเอง จะล้มเหลวและอาจทำให้แอปพลิเคชันของคุณหรือแอปพลิเคชันอื่นๆ ปิดลง

กำลังตรวจหาฮาร์ดแวร์กล้อง

หากแอปพลิเคชันของคุณไม่ได้กำหนดให้ใช้กล้องโดยเฉพาะโดยใช้การประกาศไฟล์ Manifest คุณควรตรวจสอบว่ากล้องพร้อมใช้งานขณะรันไทม์หรือไม่ หากต้องการตรวจสอบ ให้ใช้เมธอด PackageManager.hasSystemFeature() ดังที่แสดงในโค้ดตัวอย่างด้านล่าง

Kotlin

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

Java

/** 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 (เว้นแต่คุณจะใช้ Intent เพื่อเข้าถึงกล้อง)

หากต้องการเข้าถึงกล้องหลัก ให้ใช้เมธอด Camera.open() และอย่าลืมตรวจจับข้อยกเว้นตามที่แสดงในโค้ดด้านล่าง

Kotlin

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

Java

/** 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) โค้ดตัวอย่างด้านบนจะเข้าถึงกล้องหลังตัวแรกในอุปกรณ์ที่มีกล้องมากกว่า 1 ตัว

กำลังตรวจสอบฟีเจอร์ของกล้อง

เมื่อได้รับสิทธิ์เข้าถึงกล้องแล้ว คุณจะดูข้อมูลเพิ่มเติมเกี่ยวกับความสามารถของกล้องได้โดยใช้เมธอด Camera.getParameters() และตรวจสอบออบเจ็กต์ Camera.Parameters ที่แสดงผลเพื่อดูความสามารถที่รองรับ เมื่อใช้ระดับ API 9 ขึ้นไป ให้ใช้ Camera.getCameraInfo() เพื่อระบุว่ากล้องอยู่ด้านหน้าหรือด้านหลังของอุปกรณ์ และการวางแนวของรูปภาพ

การสร้างชั้นเรียนตัวอย่าง

ผู้ใช้ต้องเห็นสิ่งที่กล้องของอุปกรณ์เห็นจึงจะถ่ายภาพหรือวิดีโอได้อย่างมีประสิทธิภาพ คลาสตัวอย่างกล้องคือ SurfaceView ที่สามารถแสดงข้อมูลภาพสดที่มาจากกล้อง เพื่อให้ผู้ใช้จัดเฟรมและจับภาพหรือวิดีโอได้

โค้ดตัวอย่างต่อไปนี้แสดงวิธีสร้างคลาสตัวอย่างกล้องพื้นฐานที่รวมไว้ในเลย์เอาต์ View ได้ คลาสนี้ใช้ SurfaceHolder.Callback เพื่อบันทึกเหตุการณ์ Callback สำหรับการสร้างและทำลายมุมมอง ซึ่งจำเป็นสำหรับการกำหนดอินพุตตัวอย่างกล้อง

Kotlin

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

Java

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

หมายเหตุ: เมื่อมีการเปิดตัวฟีเจอร์หลายหน้าต่างใน Android 7.0 (API ระดับ 24) ขึ้นไป คุณจะไม่สามารถถือว่าสัดส่วนภาพของตัวอย่างเหมือนกับกิจกรรมของคุณได้อีกต่อไป แม้ว่าจะเรียกใช้ setDisplayOrientation() แล้วก็ตาม คุณอาจต้องปรับตัวอย่างภาพจากกล้องแบบกว้างให้พอดีกับเลย์เอาต์แนวตั้งหรือในทางกลับกันโดยใช้เลย์เอาต์แบบ Letterbox ทั้งนี้ขึ้นอยู่กับขนาดหน้าต่างและสัดส่วนภาพ

การวางตัวอย่างในเลย์เอาต์

ต้องวางคลาสตัวอย่างภาพจากกล้อง เช่น ตัวอย่างที่แสดงในส่วนก่อนหน้าไว้ในเลย์เอาต์ของกิจกรรมพร้อมกับตัวควบคุมอินเทอร์เฟซผู้ใช้อื่นๆ สำหรับการถ่ายภาพหรือวิดีโอ ส่วนนี้จะแสดงวิธีสร้างเลย์เอาต์และกิจกรรมพื้นฐานสำหรับตัวอย่าง

โค้ดเลย์เอาต์ต่อไปนี้แสดงมุมมองพื้นฐานที่ใช้แสดงตัวอย่างกล้องได้ ในตัวอย่างนี้ องค์ประกอบ 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>

ในอุปกรณ์ส่วนใหญ่ การวางแนวเริ่มต้นของตัวอย่างภาพจากกล้องจะเป็นแนวนอน เลย์เอาต์ตัวอย่างนี้ระบุเลย์เอาต์แนวนอน (Landscape) และโค้ดด้านล่างจะกำหนดการวางแนวของแอปพลิเคชันเป็นแนวนอน เพื่อให้แสดงตัวอย่างกล้องได้ง่ายขึ้น คุณควรเปลี่ยนการวางแนวของกิจกรรมตัวอย่างของแอปพลิเคชันเป็นแนวนอนโดยเพิ่มข้อมูลต่อไปนี้ลงในไฟล์ 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>

หมายเหตุ: ตัวอย่างภาพจากกล้องไม่จำเป็นต้องอยู่ในโหมดแนวนอน ตั้งแต่ Android 2.2 (ระดับ API 8) เป็นต้นไป คุณสามารถใช้เมธอด setDisplayOrientation() เพื่อตั้งค่าการหมุนของรูปภาพตัวอย่างได้ หากต้องการเปลี่ยนการวางแนวตัวอย่างเมื่อผู้ใช้เปลี่ยนการวางแนวโทรศัพท์ ภายในเมธอด surfaceChanged() ของคลาสตัวอย่าง ให้หยุดตัวอย่างด้วย Camera.stopPreview() เปลี่ยนการวางแนว แล้วเริ่มตัวอย่างอีกครั้งด้วย Camera.startPreview()

ในกิจกรรมสำหรับมุมมองกล้อง ให้เพิ่มคลาสตัวอย่างลงในองค์ประกอบ FrameLayout ที่แสดงในตัวอย่างด้านบน กิจกรรมของกล้องต้องตรวจสอบด้วยว่าได้ปล่อยกล้องเมื่อหยุดชั่วคราวหรือปิดเครื่อง ตัวอย่างต่อไปนี้แสดงวิธีแก้ไขกิจกรรมของกล้องเพื่อแนบคลาสตัวอย่างที่แสดงในการสร้างคลาสตัวอย่าง

Kotlin

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

Java

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() ในตัวอย่างด้านบนหมายถึงเมธอดตัวอย่างที่แสดงในการเข้าถึงกล้อง

การจับภาพ

เมื่อสร้างคลาสแสดงตัวอย่างและเลย์เอาต์มุมมองที่จะแสดงแล้ว คุณก็พร้อมที่จะเริ่มจับภาพด้วยแอปพลิเคชัน ในโค้ดของแอปพลิเคชัน คุณต้องตั้งค่า Listener สำหรับการควบคุมอินเทอร์เฟซผู้ใช้เพื่อตอบสนองต่อการดำเนินการของผู้ใช้ด้วยการถ่ายภาพ

หากต้องการเรียกดูรูปภาพ ให้ใช้เมธอด Camera.takePicture() เมธอดนี้ใช้พารามิเตอร์ 3 รายการซึ่งรับข้อมูลจากกล้อง หากต้องการรับข้อมูลในรูปแบบ JPEG คุณต้องใช้อินเทอร์เฟซ Camera.PictureCallback เพื่อรับข้อมูลรูปภาพและเขียนลงในไฟล์ โค้ดต่อไปนี้แสดงการใช้งานพื้นฐานของอินเทอร์เฟซ Camera.PictureCallback เพื่อบันทึกรูปภาพที่ได้รับจากกล้อง

Kotlin

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

Java

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

Kotlin

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

Java

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

หมายเหตุ: สมาชิก mPicture ในตัวอย่างต่อไปนี้หมายถึงโค้ดตัวอย่างด้านบน

ข้อควรระวัง: อย่าลืมปล่อยออบเจ็กต์ Camera โดยเรียกใช้ Camera.release() เมื่อแอปพลิเคชันของคุณใช้เสร็จแล้ว ดูข้อมูลเกี่ยวกับวิธีปล่อยกล้องได้ที่หัวข้อการปล่อยกล้อง

การจับภาพวิดีโอ

การจับภาพวิดีโอโดยใช้เฟรมเวิร์ก 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. Connect Preview - เตรียมตัวอย่างรูปภาพจากกล้องแบบสดโดยเชื่อมต่อ SurfaceView กับกล้องโดยใช้ Camera.setPreviewDisplay()
  3. Start Preview - เรียกใช้ 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 ด้วยการตั้งค่าที่ให้มาโดยเรียกใช้ 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 อย่างเหมาะสมสำหรับการบันทึกวิดีโอ

Kotlin

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
}

Java

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 แนวทางนี้แสดงอยู่ในโค้ดต่อไปนี้

Kotlin

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

Java

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

หมายเหตุ: เมื่อบันทึกวิดีโอเสร็จแล้ว อย่าปล่อยกล้อง มิฉะนั้นตัวอย่างจะหยุดทำงาน

Kotlin

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

Java

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() ดังที่แสดงในโค้ดตัวอย่างด้านล่าง

Kotlin

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

Java

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) เพื่อประหยัดพื้นที่ของระบบและอนุญาตให้ผู้ใช้เข้าถึงไฟล์เหล่านี้ได้โดยไม่ต้องใช้อุปกรณ์ มีตำแหน่งไดเรกทอรีที่เป็นไปได้หลายตำแหน่งสำหรับบันทึกไฟล์สื่อในอุปกรณ์ อย่างไรก็ตาม มีตำแหน่งมาตรฐานเพียง 2 ตำแหน่งที่คุณควรพิจารณาในฐานะนักพัฒนาแอป ดังนี้

  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) - เมธอดนี้จะแสดงตำแหน่งมาตรฐาน ตำแหน่งที่แชร์ และตำแหน่งที่แนะนำสำหรับการบันทึกรูปภาพและวิดีโอ ไดเรกทอรีนี้มีการแชร์ (สาธารณะ) ดังนั้นแอปพลิเคชันอื่นๆ จึงสามารถค้นหา อ่าน เปลี่ยนแปลง และลบไฟล์ที่บันทึกไว้ในตำแหน่งนี้ได้อย่างง่ายดาย หากผู้ใช้ถอนการติดตั้งแอปพลิเคชันของคุณ ระบบจะไม่นำไฟล์สื่อที่บันทึกไว้ในตำแหน่งนี้ออก เพื่อหลีกเลี่ยงการรบกวนรูปภาพและวิดีโอที่มีอยู่ของผู้ใช้ คุณควรสร้างไดเรกทอรีย่อยสำหรับไฟล์สื่อของแอปพลิเคชันภายในไดเรกทอรีนี้ ดังที่แสดงในตัวอย่างโค้ดด้านล่าง เมธอดนี้ใช้ได้ใน Android 2.2 (ระดับ API 8) สำหรับการเรียกที่เทียบเท่าใน API เวอร์ชันก่อนหน้า โปรดดูการบันทึกไฟล์ที่แชร์
  • Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) - เมธอดนี้จะแสดงผลตำแหน่งมาตรฐานสำหรับการบันทึกรูปภาพและวิดีโอที่เชื่อมโยงกับแอปพลิเคชันของคุณ หากถอนการติดตั้งแอปพลิเคชัน ระบบจะนำไฟล์ที่บันทึกไว้ในตำแหน่งนี้ออก ไม่มีการบังคับใช้การรักษาความปลอดภัยสำหรับไฟล์ในตำแหน่งนี้ และแอปพลิเคชันอื่นๆ อาจอ่าน เปลี่ยนแปลง และลบไฟล์ได้

โค้ดตัวอย่างต่อไปนี้แสดงวิธีสร้างตำแหน่ง File หรือ Uri สำหรับไฟล์สื่อที่ใช้ได้เมื่อเรียกใช้กล้องของอุปกรณ์ด้วย Intent หรือเป็นส่วนหนึ่งของการสร้างแอปกล้อง

Kotlin

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

Java

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 ระบุพื้นที่อย่างน้อย 1 พื้นที่ภายในรูปภาพเพื่อคำนวณสมดุลแสงขาว
จุดที่ควรให้ความสำคัญ 14 กำหนดพื้นที่อย่างน้อย 1 จุดภายในรูปภาพเพื่อใช้เป็นจุดโฟกัส
White Balance Lock 14 หยุดหรือเริ่มการปรับสมดุลแสงขาวอัตโนมัติ
Exposure Lock 14 หยุดหรือเริ่มการปรับการรับแสงอัตโนมัติ
Video Snapshot 14 ถ่ายภาพขณะถ่ายวิดีโอ (จับภาพเฟรม)
วิดีโอไทม์แลปส์ 11 บันทึกเฟรมโดยตั้งค่าการหน่วงเวลาเพื่อบันทึกวิดีโอไทม์แลปส์
Multiple Cameras 9 รองรับกล้องมากกว่า 1 ตัวในอุปกรณ์ ซึ่งรวมถึงกล้องหน้าและกล้องหลัง
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 และตรวจสอบว่ากล้องรองรับฟีเจอร์โฟกัสอัตโนมัติหรือไม่

Kotlin

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
}

Java

// 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...() เพื่อระบุว่าระบบรองรับฟีเจอร์หรือไม่ (และรองรับในระดับใด)

หากแอปพลิเคชันของคุณต้องใช้ฟีเจอร์กล้องบางอย่างเพื่อให้ทำงานได้อย่างถูกต้อง คุณสามารถกำหนดให้ต้องใช้ฟีเจอร์เหล่านั้นได้โดยเพิ่มลงในไฟล์ Manifest ของแอปพลิเคชัน เมื่อคุณประกาศการใช้ฟีเจอร์กล้องที่เฉพาะเจาะจง เช่น แฟลชและโฟกัสอัตโนมัติ Google Play จะจำกัดไม่ให้ติดตั้งแอปพลิเคชันของคุณในอุปกรณ์ที่ไม่รองรับฟีเจอร์เหล่านี้ ดูรายการฟีเจอร์กล้องที่ประกาศได้ในไฟล์ Manifest ของแอปได้ที่ข้อมูลอ้างอิงฟีเจอร์ของไฟล์ Manifest

การใช้ฟีเจอร์กล้อง

ฟีเจอร์ส่วนใหญ่ของกล้องจะเปิดใช้งานและควบคุมโดยใช้ออบเจ็กต์ Camera.Parameters คุณจะได้รับออบเจ็กต์นี้โดยการรับอินสแตนซ์ของออบเจ็กต์ Camera ก่อน จากนั้นเรียกใช้เมธอด getParameters() เปลี่ยนออบเจ็กต์พารามิเตอร์ที่แสดงผล แล้วตั้งค่ากลับเป็นออบเจ็กต์กล้อง ดังที่แสดงในโค้ดตัวอย่างต่อไปนี้

Kotlin

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

Java

// 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 โค้ดต่อไปนี้แสดงการตั้งค่าพื้นที่วัดแสง 2 แห่งสำหรับอินสแตนซ์ของ Camera

Kotlin

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

Java

// 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 มีพารามิเตอร์ข้อมูล 2 รายการ ได้แก่ ออบเจ็กต์ 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 14) มี API สำหรับระบุใบหน้าและคำนวณการตั้งค่าภาพโดยใช้เทคโนโลยีการจดจำใบหน้า

หมายเหตุ: ขณะที่ฟีเจอร์การตรวจจับใบหน้าทำงานอยู่ setWhiteBalance(String), setFocusAreas(List<Camera.Area>) และ setMeteringAreas(List<Camera.Area>) จะไม่มีผล

การใช้ฟีเจอร์การตรวจจับใบหน้าในแอปพลิเคชันกล้องมีขั้นตอนทั่วไปดังนี้

  • ตรวจสอบว่าอุปกรณ์รองรับการตรวจจับใบหน้า
  • สร้าง Listener การตรวจจับใบหน้า
  • เพิ่ม Listener การตรวจจับใบหน้าลงในออบเจ็กต์กล้อง
  • เริ่มการตรวจจับใบหน้าหลังจากการแสดงตัวอย่าง (และหลังจากรีสตาร์ทการแสดงตัวอย่างทุกครั้ง)

อุปกรณ์บางรุ่นไม่รองรับฟีเจอร์การตรวจจับใบหน้า คุณตรวจสอบได้ว่าฟีเจอร์นี้รองรับหรือไม่โดยโทรไปที่ getMaxNumDetectedFaces() ตัวอย่างการตรวจสอบนี้แสดงอยู่ในเมธอดตัวอย่าง startFaceDetection() ด้านล่าง

หากต้องการรับการแจ้งเตือนและตอบสนองต่อการตรวจจับใบหน้า แอปพลิเคชันกล้องของคุณต้องตั้งค่า Listener สำหรับเหตุการณ์การตรวจจับใบหน้า ในการดำเนินการนี้ คุณต้องสร้างคลาส Listener ที่ใช้อินเทอร์เฟซ Camera.FaceDetectionListener ดังที่แสดงในโค้ดตัวอย่างด้านล่าง

Kotlin

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

Java

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 ของแอปพลิเคชัน ดังที่แสดงในโค้ดตัวอย่างด้านล่าง

Kotlin

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Java

camera.setFaceDetectionListener(new MyFaceDetectionListener());

แอปพลิเคชันของคุณต้องเริ่มฟังก์ชันการตรวจจับใบหน้าทุกครั้งที่คุณเริ่ม (หรือรีสตาร์ท) ตัวอย่างภาพจากกล้อง สร้างเมธอดสำหรับการเริ่มการตรวจจับใบหน้าเพื่อให้คุณเรียกใช้ได้ตามต้องการ ดังที่แสดงในโค้ดตัวอย่างด้านล่าง

Kotlin

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

Java

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() ในคลาสตัวอย่าง ดังที่แสดงในโค้ดตัวอย่างด้านล่าง

Kotlin

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

Java

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() ของกิจกรรมหลักของแอปกล้อง เนื่องจากตัวอย่างจะไม่พร้อมใช้งาน ณ จุดนี้ในการดำเนินการของแอปพลิเคชัน

วิดีโอไทม์แลปส์

วิดีโอไทม์แลปส์ช่วยให้ผู้ใช้สร้างวิดีโอคลิปที่รวมรูปภาพที่ถ่ายห่างกันไม่กี่วินาทีหรือนาทีได้ ฟีเจอร์นี้ใช้ MediaRecorder เพื่อบันทึกรูปภาพสำหรับลำดับไทม์แลปส์

หากต้องการบันทึกวิดีโอไทม์แลปส์ด้วย MediaRecorder คุณต้องกำหนดค่าออบเจ็กต์โปรแกรมบันทึกเหมือนกับว่าคุณกำลังบันทึกวิดีโอปกติ โดยตั้งค่าเฟรมต่อวินาทีที่บันทึกเป็นตัวเลขต่ำๆ และใช้การตั้งค่าคุณภาพไทม์แลปส์อย่างใดอย่างหนึ่ง ดังที่แสดงในตัวอย่างโค้ดด้านล่าง

Kotlin

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

Java

// 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) ขึ้นไปต้องมีสิทธิ์ CAMERA เพื่อเข้าถึงค่าของช่องต่อไปนี้ที่เมธอด getCameraCharacteristics() แสดงผล

  • 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 อย่างเป็นทางการ