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

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

หมายเหตุ: หน้านี้อธิบายเกี่ยวกับคลาส Camera ซึ่งเลิกใช้งานแล้ว เราขอแนะนำให้ใช้ไลบรารี Jetpack CameraX หรือคลาส camera2 สำหรับ Use Case ที่เฉพาะเจาะจง ทั้ง CameraX และ Camera2 ทำงานใน Android 5.0 (API ระดับ 21) ขึ้นไป

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

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

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

  • ข้อกำหนดของกล้อง - การใช้กล้องมีความสำคัญต่อแอปพลิเคชันของคุณมากจนคุณไม่ต้องการติดตั้งแอปพลิเคชันในอุปกรณ์ที่ไม่มีกล้องใช่ไหม หากเป็นเช่นนั้น คุณควรประกาศข้อกำหนดของกล้องใน 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 สำหรับ Capture - เชื่อมต่อ 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 เพื่อบันทึกเหตุการณ์เรียกกลับ สำหรับการสร้างและทำลายมุมมอง ซึ่งจำเป็นต่อการกำหนดอินพุตตัวอย่างกล้อง

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 element มีไว้เพื่อเป็น คอนเทนเนอร์สำหรับคลาสตัวอย่างกล้อง เลย์เอาต์ประเภทนี้ใช้เพื่อให้สามารถวางซ้อนข้อมูลหรือการควบคุมรูปภาพเพิ่มเติมบนรูปภาพตัวอย่างกล้องสดได้

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

ในอุปกรณ์ส่วนใหญ่ การวางแนวเริ่มต้นของตัวอย่างกล้องคือแนวนอน เลย์เอาต์ตัวอย่างนี้ ระบุเลย์เอาต์แนวนอน (แนวนอน) และโค้ดด้านล่างจะแก้ไขการวางแนวของ แอปพลิเคชันเป็นแนวนอน เพื่อความสะดวกในการแสดงตัวอย่างกล้อง คุณควรเปลี่ยนการวางแนวของกิจกรรมตัวอย่างของแอปพลิเคชันเป็นแนวนอนโดยเพิ่มข้อมูลต่อไปนี้ลงในไฟล์ 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() เพื่อตั้งค่าการหมุนของรูปภาพตัวอย่างได้ หากต้องการเปลี่ยนการวางแนวของตัวอย่างเมื่อผู้ใช้เปลี่ยนการวางแนวของโทรศัพท์ ให้หยุดตัวอย่างด้วย Camera.stopPreview() ภายในเมธอด surfaceChanged() ของคลาสตัวอย่างของคุณก่อน จากนั้นเปลี่ยนการวางแนว แล้วเริ่มตัวอย่างอีกครั้งด้วย 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. เริ่มแสดงตัวอย่าง - เรียกใช้ 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. Start MediaRecorder - เริ่มบันทึกวิดีโอโดยเรียกใช้ MediaRecorder.start()
  5. หยุดบันทึกวิดีโอ - เรียกใช้เมธอดต่อไปนี้ตามลำดับเพื่อบันทึกวิดีโอให้เสร็จสมบูรณ์
    1. Stop MediaRecorder - หยุดบันทึกวิดีโอโดยเรียกใช้ MediaRecorder.stop()
    2. รีเซ็ต MediaRecorder - คุณจะนำการตั้งค่าออกจากเครื่องบันทึกได้โดยเรียกใช้ MediaRecorder.reset() (ไม่บังคับ)
    3. Release MediaRecorder - Release the MediaRecorder by calling MediaRecorder.release().
    4. ล็อกกล้อง - ล็อกกล้องเพื่อให้เซสชัน MediaRecorder ในอนาคตใช้กล้องได้โดยการเรียกใช้ Camera.lock() เริ่มตั้งแต่ Android 4.0 (API ระดับ 14) เป็นต้นไป ไม่จำเป็นต้องโทรนี้ เว้นแต่การโทร MediaRecorder.prepare() จะล้มเหลว
  6. หยุดการแสดงตัวอย่าง - เมื่อกิจกรรมที่ใช้กล้องเสร็จสิ้นแล้ว ให้หยุด การแสดงตัวอย่างโดยใช้ Camera.stopPreview()
  7. ปล่อยกล้อง - ปล่อยกล้องเพื่อให้แอปพลิเคชันอื่นๆ ใช้กล้องได้โดยการเรียก Camera.release()

หมายเหตุ: คุณสามารถใช้ MediaRecorder โดยไม่ต้องสร้างตัวอย่างกล้องก่อนและข้าม 2-3 ขั้นตอนแรกของกระบวนการนี้ได้ อย่างไรก็ตาม เนื่องจากโดยปกติแล้วผู้ใช้มักจะต้องการดูตัวอย่างก่อนเริ่มบันทึก เราจึงจะไม่กล่าวถึงกระบวนการดังกล่าวในที่นี้

เคล็ดลับ: หากปกติคุณใช้แอปพลิเคชันเพื่อบันทึกวิดีโอ ให้ตั้งค่า 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() method หมายถึงโค้ดตัวอย่างที่แสดงในการกำหนดค่า 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 พื้นที่ภายในรูปภาพเพื่อคำนวณไวต์บาลานซ์
Focus Areas 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 เส้นสีแดงแสดงระบบพิกัดสำหรับการระบุ a 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>) จะไม่มีผล

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

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

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

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