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

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

หมายเหตุ: หน้านี้อธิบายคลาส Camera ซึ่งเลิกใช้งานแล้ว เราขอแนะนำให้ใช้ไลบรารี CameraX ของ Jetpack หรือคลาส 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 คลาสนี้จะแสดงตัวอย่างภาพสดจากกล้อง
  • สร้างเลย์เอาต์ตัวอย่าง - เมื่อคุณมีคลาสตัวอย่างจากกล้องแล้ว ให้สร้างเลย์เอาต์มุมมองที่รวมตัวอย่างและการควบคุมอินเทอร์เฟซผู้ใช้ที่ต้องการ
  • ตั้งค่า Listeners สําหรับการจับภาพ - เชื่อมต่อ Listeners สําหรับตัวควบคุมอินเทอร์เฟซเพื่อเริ่มการจับภาพรูปภาพหรือวิดีโอเมื่อผู้ใช้ดำเนินการต่างๆ เช่น การกดปุ่ม
  • จับภาพและบันทึกไฟล์ - ตั้งค่าโค้ดสําหรับจับภาพหรือวิดีโอและบันทึกเอาต์พุต
  • ปล่อยกล้อง - หลังจากใช้กล้องแล้ว แอปพลิเคชันของคุณต้องปล่อยกล้องอย่างเหมาะสมเพื่อให้แอปพลิเคชันอื่นๆ ใช้

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

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

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

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

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

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

การถ่ายภาพ

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

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

หากต้องการให้ 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อธิบายรูปสี่เหลี่ยมผืนผ้าที่แมปบนตารางกริด 2,000 x 2,000 หน่วย พิกัด -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>) จะไม่มีผล

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

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

วิดีโอไทม์แลปส์ช่วยให้ผู้ใช้สร้างวิดีโอคลิปที่รวมรูปภาพที่ถ่ายห่างกัน 2-3 วินาทีหรือ 2-3 นาที ฟีเจอร์นี้ใช้ 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 อย่างเป็นทางการ