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

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

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

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

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

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

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

التحقّق من إمكانية تشغيل المحتوى بنطاق عالي الديناميكية

استخدِم Display.getHdrCapabilities() للاستعلام عن إمكانات النطاق العالي الديناميكية لشاشة. تعرض الطريقة معلومات عن ملفات تعريف 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");
}

إعداد ميزة "التشغيل باستخدام النطاق العالي الديناميكية" في تطبيقك

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

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

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

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

  • MediaCodec: لفك ترميز محتوى الفيديو بنطاق عالي الديناميكية
  • 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، يُرجى الاطّلاع على المراجع التالية:

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

الوسائط

  • مرجع Media API: تعرَّف على المزيد من المعلومات عن Media API.
  • ExoPlayer: تعرَّف على كيفية إعداد تطبيقك باستخدام مكتبة ExoPlayer.