تشغيل فيديوهات بتنسيق HDR

توفّر تكنولوجيا النطاق العالي الديناميكية (HDR) نطاقًا أوسع من الألوان وتباينًا أكبر بين درجات اللون الأبيض الأكثر سطوعًا والظلال الأكثر قتامة، ما ينتج عنه جودة فيديو تشبه إلى حد كبير ما تراه العين المجرّدة.

يمكنك إعداد تشغيل فيديوهات HDR في تطبيقك لمعاينة محتوى فيديوهات HDR وتشغيلها.

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

المتطلبات الأساسية للأجهزة

لا تتيح بعض أجهزة Android تشغيل فيديوهات بتقنية HDR. قبل تشغيل محتوى فيديو بتقنية النطاق العالي الديناميكية (HDR) في تطبيقك، تأكَّد من أنّ جهازك يستوفي المتطلبات الأساسية التالية:

  • يستهدف الإصدار 7.0 من نظام التشغيل Android أو الإصدارات الأحدث (المستوى 24 من واجهة برمجة التطبيقات).
  • أن يتوفّر فيه برنامج فك ترميز متوافق مع تقنية HDR وإمكانية الوصول إلى شاشة متوافقة مع هذه التقنية

التحقّق من إمكانية تشغيل الفيديوهات بنطاق عالي الديناميكية (HDR)

استخدِم Display.getHdrCapabilities() للاستعلام عن إمكانات النطاق العالي الديناميكية (HDR) للشاشة. تعرض هذه الطريقة معلومات حول ملفات HDR الشخصية المتوافقة ونطاق الإضاءة للشاشة.

يتحقّق الرمز التالي مما إذا كان الجهاز يتيح تشغيل HLG10. بدءًا من الإصدار Android 13، أصبح HLG10 هو الحد الأدنى من المعايير التي يجب أن تتوافق معها الأجهزة التي يصنّعها صانعو الأجهزة إذا كان الجهاز قادرًا على تشغيل محتوى HDR:

Kotlin

// Check if display supports the HDR type
val capabilities = display?.hdrCapabilities?.supportedHdrTypes ?: intArrayOf()
if (!capabilities.contains(HDR_TYPE_HLG)) {
  throw RuntimeException("Display does not support desired HDR type");
}

Java

// Check if display supports the HDR type
int[] list = getDisplay().getHdrCapabilities().getSupportedHdrTypes();
List capabilities = Arrays.stream(list).boxed().collect(Collectors.toList());
if (!capabilities.contains(HDR_TYPE_HLG)) {
 throw new RuntimeException("Display does not support desired HDR type");
}

إعداد تشغيل HDR في تطبيقك

إذا كان تطبيقك يستخدم ExoPlayer، فهو يتيح تشغيل الفيديوهات بنطاق عالي الديناميكية (HDR) تلقائيًا. يُرجى الاطّلاع على مقالة التحقّق من إمكانية تشغيل الفيديوهات بنطاق عالي الديناميكية (HDR) لمعرفة الخطوات التالية.

إذا كان تطبيقك لا يستخدم ExoPlayer، يمكنك إعداد تشغيل HDR باستخدام MediaCodec من خلال SurfaceView.

إعداد MediaCodec باستخدام SurfaceView

إعداد مسار تشغيل عادي لـ MediaCodec باستخدام SurfaceView يتيح لك ذلك عرض محتوى فيديو بنطاق عالي الديناميكية بدون أي معالجة خاصة لتشغيل هذا النطاق:

  • ‫MediaCodec: لفك ترميز محتوى الفيديو بنطاق عالي الديناميكية (HDR)
  • ‫SurfaceView: يعرض محتوى فيديو بنطاق عالي الديناميكية (HDR).

يتحقّق الرمز التالي مما إذا كان برنامج الترميز متوافقًا مع ملف تعريف النطاق العالي الديناميكية، ثم يضبط MediaCodec باستخدام SurfaceView:

Kotlin

// Check if there's a codec that supports the specific HDR profile
val list = MediaCodecList(MediaCodecList.REGULAR_CODECS) var format = MediaFormat() /* media format from the container */;
format.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10)
val codecName = list.findDecoderForFormat (format) ?: throw RuntimeException ("No codec supports the format")

// Here is a standard MediaCodec playback flow
val codec: MediaCodec = MediaCodec.createByCodecName(codecName);
val surface: Surface = surfaceView.holder.surface
val callback: MediaCodec.Callback = (object : MediaCodec.Callback() {
   override fun onInputBufferAvailable(codec: MediaCodec, index: Int) {
      queue.offer(index)
   }

   override fun onOutputBufferAvailable(
      codec: MediaCodec,
      index: Int,
      info: MediaCodec.BufferInfo
   ) {
      codec.releaseOutputBuffer(index, timestamp)
   }

   override fun onError(codec: MediaCodec, e: MediaCodec.CodecException) {
      // handle error
   }

   override fun onOutputFormatChanged(
      codec: MediaCodec, format: MediaFormat
   ) {
      // handle format change
   }
})

codec.setCallback(callback)
codec.configure(format, surface, crypto, 0 /* flags */)
codec.start()
while (/* until EOS */) {
   val index = queue.poll()
   val buffer = codec.getInputBuffer(index)
   buffer?.put(/* write bitstream */)
   codec.queueInputBuffer(index, offset, size, timestamp, flags)
}
codec.stop()
codec.release()

Java

// Check if there's a codec that supports the specific HDR profile
MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
MediaFormat format = /* media format from the container */;
format.setInteger(
    MediaFormat.KEY_PROFILE, CodecProfileLevel.AV1ProfileMain10);
String codecName = list.findDecoderForFormat(format);
if (codecName == null) {
    throw new RuntimeException("No codec supports the format");
}

// Below is a standard MediaCodec playback flow
MediaCodec codec = MediaCodec.getCodecByName(codecName);
Surface surface = surfaceView.getHolder().getSurface();
MediaCodec.Callback callback = new MediaCodec.Callback() {
    @Override
    void onInputBufferAvailable(MediaCodec codec, int index) {
        queue.offer(index);
    }

    @Override
    void onOutputBufferAvailable(MediaCodec codec, int index) {
        // release the buffer for render
        codec.releaseOutputBuffer(index, timestamp);
    }

    @Override
    void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
        // handle format change
    }

    @Override
    void onError(MediaCodec codec, MediaCodec.CodecException ex) {
        // handle error
    }

};
codec.setCallback(callback);
codec.configure(format, surface, crypto, 0 /* flags */);
codec.start();
while (/* until EOS */) {
    int index = queue.poll();
    ByteBuffer buffer = codec.getInputBuffer(index);
    buffer.put(/* write bitstream */);
    codec.queueInputBuffer(index, offset, size, timestamp, flags);
}
codec.stop();
codec.release();

لمزيد من عمليات تنفيذ MediaCodec باستخدام SurfaceView، يُرجى الاطّلاع على نماذج كاميرا Android.

الموارد

لمزيد من المعلومات حول تشغيل فيديوهات HDR، يُرجى الاطّلاع على المراجع التالية:

نطاق عالي الديناميكية

الوسائط