جلسات وجلسات تصوير للكاميرا

ملاحظة: تشير هذه الصفحة إلى حزمة Camera2. ننصحك باستخدام الكاميراX ما لم يكن تطبيقك يتطلب ميزات محدَّدة منخفضة المستوى من تطبيق Camera2. يتوافق كل من CameraX و Camera2 مع نظام التشغيل Android 5.0 (المستوى 21 لواجهة برمجة التطبيقات) والإصدارات الأحدث.

يمكن أن يتضمّن جهاز واحد يعمل بنظام التشغيل Android عدة كاميرات. كل كاميرا عبارة عن CameraDevice, ويمكن لـ CameraDevice إخراج أكثر من مصدر بيانات واحد في الوقت نفسه.

إنّ السبب الوحيد لإجراء ذلك هو إطلاق بث واحد وإطارات الكاميرا المتسلسلة. من CameraDevice، محسّنة لمهمة محدّدة، مثل عرض عدسة الكاميرا، بينما يمكن استخدام الآخرين لالتقاط صورة أو إنشاء فيديو التسجيل.تعمل مجموعات البث كمسارات متوازية تعالج الإطارات الأولية تخرج من الكاميرا، لقطة واحدة في كل مرة:

الشكل 1. صورة توضيحية من إنشاء تطبيق كاميرا عالمية (مؤتمر Google I/O لعام 2018)

تشير المعالجة المتوازية إلى إمكانية وضع حدود للأداء استنادًا إلى طاقة المعالجة المتاحة من وحدة المعالجة المركزية (CPU) أو وحدة معالجة الرسومات (GPU) أو معالج آخر. إذا مسار الإطارات الشبكية الواردة، فقد بدأ في إسقاطها.

لكل مسار تنسيق الإخراج الخاص به. البيانات الأولية الواردة هي يتم تحويلها تلقائيًا إلى الطريقة المناسبة تنسيق الناتج من خلال المنطق الضمني المرتبطة بكل مسار. إنّ CameraDevice المستخدمة في هذه الصفحة نماذج التعليمات البرمجية غير محددة، لذلك عليك أولاً تعداد جميع الكاميرات المتاحة قبل المتابعة.

يمكنك استخدام CameraDevice لإنشاء CameraCaptureSession, الخاص بـ CameraDevice. يجب أن يتلقّى CameraDevice إعدادات الإطار لكل إطار أولي باستخدام CameraCaptureSession. تشير رسالة الأشكال البيانية سمات الكاميرا مثل التركيز التلقائي وفتحة العدسة والتأثيرات ومدى التعرّض للأصوات. وبسبب قيود الأجهزة، لا يتم إجراء سوى تهيئة واحدة نشطًا في أداة استشعار الكاميرا في أي وقت، وهو ما يسمى نشط.

مع ذلك، تساعد حالات استخدام البث في تحسين الطرق السابقة لاستخدام CameraDevice وتوسيع نطاقها. لبث جلسات التصوير، ما يتيح لك تحسين بث الكاميرا في حالة استخدام معينة. على سبيل المثال، يمكنها تحسين عمر البطارية عند التحسين مكالمات فيديو.

تصف السمة CameraCaptureSession جميع المسارات المحتملة المرتبطة بنموذج CameraDevice عند إنشاء جلسة، لا يمكنك إضافة مسارات التعلّم أو إزالتها. يحتفظ CameraCaptureSession بقائمة انتظار CaptureRequest، والتي تصبح هي التهيئة النشطة.

يضيف CaptureRequest إعدادًا إلى قائمة الانتظار ويختار إعدادًا، أكثر من واحد، أو كل المسارات المتاحة لتلقي إطار من CameraDevice يمكنك إرسال العديد من طلبات الالتقاط طوال فترة التقاط الصورة. جلسة المراجعة. يمكن لكل طلب تغيير الإعداد النشط ومجموعة النتائج الممرات التي تتلقى الصورة الأولية.

الاستفادة من حالات الاستخدام في البث لتحقيق أداء أفضل

"حالات استخدام البث" هي وسيلة لتحسين أداء التقاط الصور بالكاميرا 2. الجلسات. فهي تعطي الجهاز المزيد من المعلومات لضبط المعاملات، التي تقدّم تجربة أفضل للكاميرا لإنجاز مهمتك المحدّدة.

هذا النمط تسمح لجهاز الكاميرا بتحسين أجهزة الكاميرا ومسارات البرامج. استنادًا إلى سيناريوهات كل بث مباشر لمزيد من المعلومات حول استخدام البث الطلبات، يُرجى الاطّلاع على setStreamUseCase.

تتيح لك حالات الاستخدام للبث المباشر تحديد كيفية استخدام بث كاميرا معيّن في بمزيد من التفصيل، بالإضافة إلى إعداد قالب في CameraDevice.createCaptureRequest() يسمح هذا الإجراء لأجهزة الكاميرا بتحسين مثل الضبط أو وضع أداة الاستشعار أو إعدادات أداة استشعار الكاميرا، بناءً على مفاضلات الجودة ووقت الاستجابة مناسبة لحالات استخدام معيّنة.

تشمل حالات الاستخدام لساحة المشاركات ما يلي:

  • DEFAULT: تشمل هذه السياسة جميع سلوكيات التطبيقات الحالية. تعادل عدم وإعداد أي حالة استخدام للبث.

  • PREVIEW: يُنصح به لتحليل عدسة الكاميرا أو الصور داخل التطبيق.

  • STILL_CAPTURE: محسَّنة لالتقاط صور عالية الجودة عالية الجودة، بدلاً من من المتوقع الحفاظ على عدد اللقطات في الثانية الذي يشبه المعاينة.

  • VIDEO_RECORD: خيار محسَّن لتسجيل الفيديو بجودة عالية، بما في ذلك الجودة العالية تثبيت الصورة، إذا كان الجهاز متوافقًا مع الميزة وفعّلها التطبيق. قد يؤدي هذا الخيار إلى إنتاج إطارات مُخرجة مع تأخُّر كبير عن الوقت الفعلي، للسماح بالتثبيت بأعلى جودة أو المعالجة الأخرى.

  • VIDEO_CALL: يُنصح به لاستخدامات الكاميرا لفترات طويلة حيث يتم استنزاف الطاقة المشكلة.

  • PREVIEW_VIDEO_STILL: يُنصح بهذا الخيار لتطبيقات وسائل التواصل الاجتماعي أو للاستخدام في بث واحد. الحالات. إنّه بث متعدد الأغراض.

  • VENDOR_START: يُستخدَم في حالات الاستخدام التي يحدّدها المصنّع الأصلي للجهاز.

إنشاء جلسة تسجيل الكاميرا

لإنشاء جلسة كاميرا، عليك تزويدها بمورد احتياطي واحد أو أكثر للمخرجات. لتطبيقك كتابة إطارات الإخراج. يمثل كل مورد احتياطي خطًا. يجب القيام بذلك قبل البدء في استخدام الكاميرا حتى يمكن لإطار العمل تهيئة المسارات الداخلية للجهاز وتخصيص مخازن مؤقتة لإرسال الإطارات إلى أهداف المخرجات المطلوبة.

يوضح مقتطف الرمز التالي كيفية تحضير جلسة كاميرا مع اثنين الموارد الاحتياطية للمخرجات التي تنتمي إلى SurfaceView وآخر إلى ImageReader جارٍ إضافة حالة استخدام مصدر البيانات PREVIEW إلى previewSurface و STILL_CAPTURE استخدام ساحة المشاركات إنّ حافظة imReaderSurface تتيح لأجهزة الجهاز تحسين عمليات البث هذه أيضًا. أكثر.

Kotlin


// Retrieve the target surfaces, which might be coming from a number of places:
// 1. SurfaceView, if you want to display the image directly to the user
// 2. ImageReader, if you want to read each frame or perform frame-by-frame
// analysis
// 3. OpenGL Texture or TextureView, although discouraged for maintainability
      reasons
// 4. RenderScript.Allocation, if you want to do parallel processing
val surfaceView = findViewById<SurfaceView>(...)
val imageReader = ImageReader.newInstance(...)

// Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated()
val previewSurface = surfaceView.holder.surface
val imReaderSurface = imageReader.surface
val targets = listOf(previewSurface, imReaderSurface)

// Create a capture session using the predefined targets; this also involves
// defining the session state callback to be notified of when the session is
// ready
// Setup Stream Use Case while setting up your Output Configuration.
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun configureSession(device: CameraDevice, targets: List<Surface>){
    val configs = mutableListOf<OutputConfiguration>()
    val streamUseCase = CameraMetadata
        .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL

    targets.forEach {
        val config = OutputConfiguration(it)
        config.streamUseCase = streamUseCase.toLong()
        configs.add(config)
    }
    ...
    device.createCaptureSession(session)
}

Java


// Retrieve the target surfaces, which might be coming from a number of places:
// 1. SurfaceView, if you want to display the image directly to the user
// 2. ImageReader, if you want to read each frame or perform frame-by-frame
      analysis
// 3. RenderScript.Allocation, if you want to do parallel processing
// 4. OpenGL Texture or TextureView, although discouraged for maintainability
      reasons
Surface surfaceView = findViewById<SurfaceView>(...);
ImageReader imageReader = ImageReader.newInstance(...);

// Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated()
Surface previewSurface = surfaceView.getHolder().getSurface();
Surface imageSurface = imageReader.getSurface();
List<Surface> targets = Arrays.asList(previewSurface, imageSurface);

// Create a capture session using the predefined targets; this also involves defining the
// session state callback to be notified of when the session is ready
private void configureSession(CameraDevice device, List<Surface> targets){
    ArrayList<OutputConfiguration> configs= new ArrayList()
    String streamUseCase=  CameraMetadata
        .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL

    for(Surface s : targets){
        OutputConfiguration config = new OutputConfiguration(s)
        config.setStreamUseCase(String.toLong(streamUseCase))
        configs.add(config)
}

device.createCaptureSession(session)
}

في هذه المرحلة، لم يتم تحديد الإعدادات النشطة للكاميرا. عندما يتم إعداد الجلسة، يمكنك إنشاء لقطة وإرسالها المستخدم للقيام بذلك.

ويحدث التحويل المطبق على المدخلات عند كتابتها في المورد الاحتياطي الخاص بها يحدده نوع كل هدف، وهو ما يجب أن يكون Surface يعرف إطار عمل Android كيفية تحويل الصورة الأولية في التهيئة النشطة إلى تنسيق مناسب لكل هدف. ويتم التحكم في التحويل من خلال تنسيق البكسل وحجم Surface بالتحديد.

يبذل إطار العمل قصارى جهده، إلا أنّ بعض Surface قد لا تعمل مجموعات الضبط، ما يتسبّب في حدوث مشاكل مثل الجلسة عدم الإنشاء، أو عرض خطأ في بيئة التشغيل عند إرسال الطلب، أو وتدهور الأداء. ويوفر إطار العمل ضمانات مجموعات معلمات الجهاز ومساحة العرض والطلب. الوثائق الخاصة createCaptureSession() يوفر لك المزيد من المعلومات.

طلبات التقاط فردية

يتم ترميز الإعدادات المستخدمة لكل إطار في CaptureRequest، وهو إرسال إلى الكاميرا. لإنشاء طلب تسجيل، يمكنك استخدام أحد محدّدة مسبقًا templates أو يمكنك استخدام TEMPLATE_MANUAL للتحكّم بشكل كامل. عند اختيار تحتاج إلى توفير واحد أو أكثر من الموارد الاحتياطية للمخرجات لاستخدامها مع الطلب. يمكنك فقط استخدام الموارد الاحتياطية التي تم تحديدها بالفعل عند الالتقاط الجلسة التي تنوي استخدامها.

تستخدم طلبات الالتقاط نمط منصة الإنشاء ومنح المطورين الفرصة لتحديد العديد من القيم الخيارات بما في ذلك التعرض التلقائي التركيز التلقائي أو فتحة العدسة قبل تعيين حقل، تأكد من أن الخيار المحدد متاح الجهاز من خلال طلب CameraCharacteristics.getAvailableCaptureRequestKeys() وأن القيمة المطلوبة مدعومة من خلال تحديد الكاميرا المناسبة مثل الإضاءة التلقائية للتعرض للضوء .

لإنشاء طلب تسجيل محتوى SurfaceView باستخدام النموذج المصممة للمعاينة دون أي تعديلات، استخدم CameraDevice.TEMPLATE_PREVIEW:

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequest.addTarget(previewSurface)

Java

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest.Builder captureRequest =
    session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequest.addTarget(previewSurface);

مع تحديد طلب الالتقاط، يمكنك الآن إرسال إلى جلسة الكاميرا:

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest: CaptureRequest = ...  // from CameraDevice.createCaptureRequest()

// The first null argument corresponds to the capture callback, which you
// provide if you want to retrieve frame metadata or keep track of failed capture
// requests that can indicate dropped frames; the second null argument
// corresponds to the Handler used by the asynchronous callback, which falls
// back to the current thread's looper if null
session.capture(captureRequest.build(), null, null)

Java

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest captureRequest = ...;  // from CameraDevice.createCaptureRequest()

// The first null argument corresponds to the capture callback, which you
// provide if you want to retrieve frame metadata or keep track of failed
// capture
// requests that can indicate dropped frames; the second null argument
// corresponds to the Handler used by the asynchronous callback, which falls
// back to the current thread's looper if null
session.capture(captureRequest.build(), null, null);

عندما يتم وضع إطار إخراج في المخزن المؤقت المحدد، فإن التقاط معاودة الاتصال . في كثير من الحالات، تعد طلبات معاودة الاتصال الإضافية، مثل ImageReader.OnImageAvailableListener, يتم تشغيله عند معالجة الإطار الذي يحتوي عليه. الساعة يمكنك عندئذ استرداد بيانات الصور من المخزن المؤقت المحدد.

تكرار طلبات الالتقاط

من السهل تنفيذ الطلبات باستخدام كاميرا واحدة، ولكنها تهدف إلى عرض بث مباشر أو المعاينة أو الفيديو، فلن تكون مفيدة للغاية. في هذه الحالة، تحتاج إلى استلام بثًا مستمرًا للإطارات، وليس لقطة واحدة فقط. مقتطف الرمز التالي كيفية إضافة طلب مكرّر إلى الجلسة:

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest: CaptureRequest = ...  // from CameraDevice.createCaptureRequest()

// This keeps sending the capture request as frequently as possible until
// the
// session is torn down or session.stopRepeating() is called
// session.setRepeatingRequest(captureRequest.build(), null, null)

Java

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest captureRequest = ...;  // from CameraDevice.createCaptureRequest()

// This keeps sending the capture request as frequently as possible until the
// session is torn down or session.stopRepeating() is called
// session.setRepeatingRequest(captureRequest.build(), null, null);

يؤدي طلب الالتقاط المتكرر إلى جعل جهاز الكاميرا يلتقط الالتقاط باستمرار الصور باستخدام الإعدادات المتوفّرة في CaptureRequest. واجهة برمجة التطبيقات Camera2 أيضًا للمستخدمين بالتقاط الفيديو من الكاميرا عن طريق إرسال تكرار CaptureRequests كما هو موضّح في ذلك نموذج Camera2 على جيت هب. ويمكنها أيضًا عرض فيديو بالتصوير البطيء من خلال التقاط فيديو عالي السرعة (تصوير بطيء) باستخدام صور متسلسلة متكررة CaptureRequests كما هو موضّح في نموذج تطبيق فيديو بالتصوير البطيء Camera2 على GitHub.

طلبات الحصول على محتوى متداخل

لإرسال طلب التقاط ثانٍ عندما يكون طلب الالتقاط المتكرر نشطًا، مثل عرض عدسة الكاميرا والسماح للمستخدمين بالتقاط صورة، لا تحتاج إلى إيقاف الطلب المتكرّر الجاري. بدلاً من ذلك، يمكنك إنشاء تسجيل غير متكرر الطلب أثناء تشغيل الطلب المتكرر.

يجب إعداد أي مخزن مؤقت للمخرجات تم استخدامها كجزء من جلسة الكاميرا عند إنشاء الجلسة لأول مرة. تكون الطلبات المتكررة لها أولوية أقل من طلبات الإطار الواحد أو الصور المتسلسلة، والتي تمكّن النموذج التالي من العمل:

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback

// Create the repeating request and dispatch it
val repeatingRequest = session.device.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW)
repeatingRequest.addTarget(previewSurface)
session.setRepeatingRequest(repeatingRequest.build(), null, null)

// Some time later...

// Create the single request and dispatch it
// NOTE: This can disrupt the ongoing repeating request momentarily
val singleRequest = session.device.createCaptureRequest(
CameraDevice.TEMPLATE_STILL_CAPTURE)
singleRequest.addTarget(imReaderSurface)
session.capture(singleRequest.build(), null, null)

Java

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback

// Create the repeating request and dispatch it
CaptureRequest.Builder repeatingRequest =
session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
repeatingRequest.addTarget(previewSurface);
session.setRepeatingRequest(repeatingRequest.build(), null, null);

// Some time later...

// Create the single request and dispatch it
// NOTE: This can disrupt the ongoing repeating request momentarily
CaptureRequest.Builder singleRequest =
session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
singleRequest.addTarget(imReaderSurface);
session.capture(singleRequest.build(), null, null);

ومع ذلك، هناك عيب في هذا المنهج، وهو أنك لا تعرف بالضبط متى حدوث طلب فردي. في الشكل التالي، إذا كان A هو التكرار طلب التسجيل وB هو طلب التقاط لقطة واحدة، وهذه هي الطريقة التي تعالج الجلسة قائمة انتظار الطلبات:

الشكل 2. صورة توضيحية لقائمة انتظار طلبات لجلسة الكاميرا الجارية

ليس هناك أي ضمانات بشأن وقت الاستجابة بين آخر طلب متكرر من أ قبل تفعيل الطلب ب وفي المرة التالية التي يتم فيها استخدام الحرف أ مرة أخرى، لذلك قد تواجه بعض الإطارات التي تم تخطيها. هناك بعض الأشياء التي يمكنك فعله للتخفيف من هذه المشكلة:

  • أضِف استهدافات الناتج من الطلب أ إلى الطلب ب. بهذه الطريقة، عندما إطار B جاهز، ويتم نسخه إلى استهدافات الإخراج A. على سبيل المثال، يُعد هذا أمرًا ضروريًا عند تصوير لقطات فيديو للحفاظ على عدد ثابت للقطات في الثانية. في التعليمة البرمجية السابقة، يمكنك إضافة singleRequest.addTarget(previewSurface) قبل إنشاء الطلب.

  • استخدم مجموعة من القوالب المصممة للعمل لهذا السيناريو المحدد، مثل عدم الفاصل الإعلاني