Multimedya tünelleme

Multimedya tünelleme, sıkıştırılmış video verilerinin bir donanım video kod çözücüsü aracılığıyla uygulama kodu veya Android çerçeve kodu tarafından işlenmeden doğrudan bir ekrana geçirilmesini sağlar. Android yığınının altındaki cihaza özgü kod, video karesi sunumu zaman damgalarını aşağıdaki dahili saat türlerinden biriyle karşılaştırarak hangi video karelerinin ekrana ve ne zaman gönderileceğini belirler:

  • Android 5 veya sonraki sürümlerde isteğe bağlı video oynatma için uygulama tarafından aktarılan sesli sunu zaman damgalarıyla senkronize edilen AudioTrack saati

  • Android 11 veya sonraki sürümlerde canlı yayın oynatma için tuner tarafından çalıştırılan bir program referans saati (PCR) veya sistem saati (STC)

Arka plan

Android'de geleneksel video oynatma özelliği, sıkıştırılmış bir video karesinin kodu çözüldüğünde uygulamayı bildirir. Ardından uygulama, kod çözülmüş video karesini, ilgili ses karesiyle aynı sistem saatinde oluşturulması için ekrana yayınlar. Doğru zamanlamayı hesaplamak için geçmiş AudioTimestamps öğelerini alır.

Tünelli video oynatma, uygulama kodunu atlayıp videoyu etkileyen işlemlerin sayısını azalttığı için OEM uygulamasına bağlı olarak daha verimli video oluşturma sağlayabilir. Ayrıca, Android'in video oluşturma isteklerinin zamanlaması ile gerçek donanım vsync'lerinin zamanlaması arasındaki olası sapmaların oluşturduğu zamanlama sorunlarını ortadan kaldırarak seçilen saatle (PRC, STC veya ses) daha doğru video ritmi ve senkronizasyon sağlayabilir. Bununla birlikte, arabellekler Android grafik grubunu atladığı için tünelleme, pencere içinde pencere (PiP) pencerelerinde bulanıklaştırma veya yuvarlatılmış köşeler gibi GPU efektlerine yönelik desteği de azaltabilir.

Aşağıdaki şemada, tünel oluşturmanın video oynatma sürecini nasıl basitleştirdiği gösterilmektedir.

Geleneksel ve tünel modlarının karşılaştırması

Şekil 1. Geleneksel ve tünellenmiş video oynatma işlemlerinin karşılaştırması

Uygulama geliştiriciler için

Çoğu uygulama geliştirici, oynatma uygulaması için bir kitaplıkla entegre olduğundan çoğu durumda uygulama, tünelli oynatma için bu kitaplığın yeniden yapılandırılmasını gerektirir. Tünelli video oynatıcının alt düzey uygulaması için aşağıdaki talimatları kullanın.

Android 5 veya sonraki sürümlerde isteğe bağlı video oynatma için:

  1. SurfaceView örneği oluşturun.

  2. audioSessionId örneği oluşturun.

  3. 2. adımda oluşturulan audioSessionId örneğiyle AudioTrack ve MediaCodec örnekleri oluşturun.

  4. Ses verilerindeki ilk ses karesinin sunu zaman damgasıyla ses verilerini AudioTrack'e sıraya ekleyin.

Android 11 veya sonraki sürümlerde canlı yayın oynatma için:

  1. SurfaceView örneği oluşturun.

  2. Tuner'dan bir avSyncHwId örneği alın.

  3. 2. adımda oluşturulan avSyncHwId örneğiyle AudioTrack ve MediaCodec örnekleri oluşturun.

API çağrı akışı aşağıdaki kod snippet'lerinde gösterilmektedir:

aab.setContentType(AudioAttributes.CONTENT_TYPE_MOVIE);

// configure for audio clock sync
aab.setFlag(AudioAttributes.FLAG_HW_AV_SYNC);
// or, for tuner clock sync (Android 11 or higher)
new tunerConfig = TunerConfiguration(0, avSyncId);
aab.setTunerConfiguration(tunerConfig);
if (codecName == null) {
  return FAILURE;
}

// configure for audio clock sync
mf.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, audioSessionId);
// or, for tuner clock sync (Android 11 or higher)
mf.setInteger(MediaFormat.KEY_HARDWARE_AV_SYNC_ID, avSyncId);

İsteğe bağlı video oynatma davranışı

Tünelli isteğe bağlı video oynatma özelliği, AudioTrack oynatmayla dolaylı olarak bağlantılı olduğundan tünelli video oynatmanın davranışı ses oynatmanın davranışına bağlı olabilir.

  • Çoğu cihazda, varsayılan olarak ses oynatma başlayana kadar video karesi oluşturulmaz. Bununla birlikte, uygulamanın ses çalmaya başlamadan önce bir video karesi oluşturması gerekebilir (örneğin, video izlerken kullanıcıya geçerli videonun konumunu göstermek için).

    • Sıraya alınan ilk video karesinin kodu çözülür olmaz oluşturulması gerektiğini belirtmek için PARAMETER_KEY_TUNNEL_PEEK parametresini 1 olarak ayarlayın. Sıkıştırılmış video kareleri sırada yeniden sıralandığında (ör. B kareler olduğunda) bu, gösterilen ilk video karesinin her zaman bir iç kare olması gerektiği anlamına gelir.

    • Ses oynatma başlayana kadar sıraya alınan ilk video karesinin oluşturulmasını istemiyorsanız bu parametreyi 0 olarak ayarlayın.

    • Bu parametre ayarlanmazsa cihazın davranışını OEM belirler.

  • AudioTrack için ses verileri sağlanmadığında ve arabellekler boş olduğunda (ses eksikliği), ses saati artık ilerlemediği için daha fazla ses verisi yazılana kadar video oynatma duraklar.

  • Oynatma sırasında, uygulamanın düzeltemediği kesintiler ses sunumu zaman damgalarında görülebilir. Bu durumda OEM, mevcut video karesini durdurarak negatif boşlukları, OEM uygulamasına bağlı olarak video karelerini bırakarak veya sessiz ses kareleri ekleyerek pozitif boşlukları düzeltir. Eklenen sessiz ses çerçeveleri için AudioTimestamp kare konumu artmaz.

Cihaz üreticileri için

Yapılandırma

OEM'ler, tünellenmiş video oynatmayı desteklemek için ayrı bir video kod çözücü oluşturmalıdır. Bu kod çözücü, media_codecs.xml dosyasında tünel oynatma yapabildiğini belirtmelidir:

<Feature name="tunneled-playback" required="true"/>

Tünelli MediaCodec örneği, ses oturum kimliğiyle yapılandırıldığında şu HW_AV_SYNC kimliği için AudioFlinger değerini sorgular:

if (entry.getKey().equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
    int sessionId = 0;
    try {
        sessionId = (Integer)entry.getValue();
    }
    catch (Exception e) {
        throw new IllegalArgumentException("Wrong Session ID Parameter!");
    }
    keys[i] = "audio-hw-sync";
    values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
}

Bu sorgu sırasında AudioFlinger, birincil ses cihazından HW_AV_SYNC kimliğini alır ve bunu sesli oturum kimliğiyle dahili olarak ilişkilendirir:

audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
char *reply = dev->get_parameters(dev, AUDIO_PARAMETER_HW_AV_SYNC);
AudioParameter param = AudioParameter(String8(reply));
int hwAVSyncId;
param.getInt(String8(AUDIO_PARAMETER_HW_AV_SYNC), hwAVSyncId);

Önceden bir AudioTrack örneği oluşturulduysa HW_AV_SYNC kimliği, aynı ses oturum kimliğiyle çıkış akışına iletilir. Henüz oluşturulmadıysa HW_AV_SYNC kimliği, AudioTrack oluşturma sırasında çıkış akışına iletilir. Bu işlem, oynatma mesaj dizisi tarafından yapılır:

mOutput->stream->common.set_parameters(&mOutput->stream->common, AUDIO_PARAMETER_STREAM_HW_AV_SYNC, hwAVSyncId);

Ses çıkış akışına veya Tuner yapılandırmasına karşılık gelen HW_AV_SYNC kimliği, OEM kodunun codec'i ilgili ses çıkış akışıyla veya tuner akışıyla ilişkilendirebilmesi için OMX veya Codec2 bileşenine iletilir.

OMX veya Codec2 bileşeni, bileşen yapılandırması sırasında codec'i bir donanım derleyici (HWC) katmanıyla ilişkilendirmek için kullanılabilecek bir yan bant tutamacını döndürmelidir. Uygulama bir yüzeyi MediaCodec ile ilişkilendirdiğinde bu yan bant tutamaç, SurfaceFlinger aracılığıyla HWC'ye iletilir. Bu işlem, katmanı yan bant katmanı olarak yapılandırır.

err = native_window_set_sideband_stream(nativeWindow.get(), sidebandHandle);
if (err != OK) {
  ALOGE("native_window_set_sideband_stream(%p) failed! (err %d).", sidebandHandle, err);
  return err;
}

HWC, codec çıkışından uygun zamanda yeni görüntü arabellekleri almaktan, ilişkili ses çıkış akışıyla veya kanal ayarlayıcı programı referans saatiyle senkronize etmekten, arabellekleri diğer katmanların geçerli içerikleriyle birleştirip ortaya çıkan görüntüyü görüntülemekten sorumludur. Bu, normal hazırlama ve ayarlama döngüsünden bağımsız olarak gerçekleşir. prepare ve set çağrıları yalnızca diğer katmanlar değiştiğinde veya yan bant katmanının özellikleri (konum veya boyut gibi) değiştiğinde gerçekleşir.

OMX

Tünellenmiş kod çözücü bileşeni aşağıdakileri desteklemelidir:

  • Ses çıkış cihazıyla ilişkili HW_AV_SYNC kimliğini iletmek için ConfigureVideoTunnelModeParams yapısını kullanan OMX.google.android.index.configureVideoTunnelMode genişletilmiş parametresini ayarlama.

  • Ses oynatmanın başlatılıp başlatılmadığına bakılmaksızın codec'a kodu çözülmüş ilk video karesini oluşturma veya oluşturmama talimatı veren OMX_IndexConfigAndroidTunnelPeek parametresini yapılandırma.

  • Tünelli ilk video karesinin kodu çözüldüğünde ve oluşturulmaya hazır olduğunda OMX_EventOnFirstTunnelFrameReady etkinliği gönderilir.

AOSP uygulaması, aşağıdaki kod snippet'inde gösterildiği gibi OMXNodeInstance aracılığıyla ACodec'te tünel modunu yapılandırır:

OMX_INDEXTYPE index;
OMX_STRING name = const_cast<OMX_STRING>(
        "OMX.google.android.index.configureVideoTunnelMode");

OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);

ConfigureVideoTunnelModeParams tunnelParams;
InitOMXParams(&tunnelParams);
tunnelParams.nPortIndex = portIndex;
tunnelParams.bTunneled = tunneled;
tunnelParams.nAudioHwSync = audioHwSync;
err = OMX_SetParameter(mHandle, index, &tunnelParams);
err = OMX_GetParameter(mHandle, index, &tunnelParams);
sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;

Bileşen bu yapılandırmayı destekliyorsa HWC'nin ilişkili codec'i tanımlayabilmesi için bu codec'e bir yan bant tutma yeri ayırması ve bunu pSidebandWindow üyesine geri göndermesi gerekir. Bileşen bu yapılandırmayı desteklemiyorsa bileşen bTunneled değerini OMX_FALSE olarak ayarlamalıdır.

Codec2

Android 11 veya sonraki sürümlerde Codec2, tünellenmiş oynatmayı destekler. Kod çözücü bileşen aşağıdakileri desteklemelidir:

  • Tünel modunu yapılandıran ve ses çıkış cihazından veya kanal ayarlayıcı yapılandırmasından alınan HW_AV_SYNC içinde iletilen C2PortTunneledModeTuning yapılandırması.

  • HWC için yan bant tutma yerini ayırmak ve almak amacıyla C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE sorgusu sorgulanıyor.

  • 1) codec'ten daha sonra onu oluşturması talimatı verilene veya 2) ses çalma işlemi başlayana kadar, codec'e kodu çözmesini ve işin tamamlandığını belirten bir çıkış arabelleğini oluşturmamasını bildiren bir C2Work öğesine eklendiğinde C2_PARAMKEY_TUNNEL_HOLD_RENDER işleme alınır.

  • Ses oynatma başlamasa bile codec'e C2_PARAMKEY_TUNNEL_HOLD_RENDER ile işaretlenen kareyi hemen oluşturması talimatını veren C2_PARAMKEY_TUNNEL_START_RENDER kullanımı.

  • debug.stagefright.ccodec_delayed_params yapılandırmasız bırakın (önerilir). Yapılandırırsanız false olarak ayarlayın.

AOSP uygulaması, aşağıdaki kod snippet'inde gösterildiği gibi tünel modunu C2PortTunnelModeTuning aracılığıyla CCodec içinde yapılandırır:

if (msg->findInt32("audio-hw-sync", &tunneledPlayback->m.syncId[0])) {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::AUDIO_HW_SYNC;
} else if (msg->findInt32("hw-av-sync-id", &tunneledPlayback->m.syncId[0])) {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::HW_AV_SYNC;
} else {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::REALTIME;
    tunneledPlayback->setFlexCount(0);
}
c2_status_t c2err = comp->config({ tunneledPlayback.get() }, C2_MAY_BLOCK,
        failures);
std::vector<std::unique_ptr<C2Param>> params;
c2err = comp->query({}, {C2PortTunnelHandleTuning::output::PARAM_TYPE},
        C2_DONT_BLOCK, &params);
if (c2err == C2_OK && params.size() == 1u) {
    C2PortTunnelHandleTuning::output *videoTunnelSideband =
            C2PortTunnelHandleTuning::output::From(params[0].get());
    return OK;
}

Bileşen bu yapılandırmayı destekliyorsa HWC'nin ilişkili codec'i tanımlayabilmesi için bu codec'e bir yan bant tutma yeri ayırması ve onu C2PortTunnelHandlingTuning üzerinden geri iletmesi gerekir.

Ses HAL'si

İsteğe bağlı video oynatma için Audio HAL, uygulamanın yazdığı her ses verisi bloğunun başında bulunan bir başlıktaki ses verilerine paralel olarak ses sunumu zaman damgalarını büyük endian biçiminde alır:

struct TunnelModeSyncHeader {
  // The 32-bit data to identify the sync header (0x55550002)
  int32 syncWord;
  // The size of the audio data following the sync header before the next sync
  // header might be found.
  int32 sizeInBytes;
  // The presentation timestamp of the first audio sample following the sync
  // header.
  int64 presentationTimestamp;
  // The number of bytes to skip after the beginning of the sync header to find the
  // first audio sample (20 bytes for compressed audio, or larger for PCM, aligned
  // to the channel count and sample size).
  int32 offset;
}

HWC'nin video karelerini karşılık gelen ses kareleriyle senkronize olarak oluşturması için Ses HAL'nin senkronizasyon başlığını ayrıştırması ve oynatma saatini ses oluşturma ile yeniden senkronize etmek üzere sunu zaman damgasını kullanması gerekir. Sıkıştırılmış ses oynatılırken yeniden senkronize etmek için Audio HAL'in, oynatma süresini belirlemek üzere sıkıştırılmış ses verilerindeki meta verileri ayrıştırması gerekebilir.

Desteği duraklat

Android 5 veya önceki sürümlerde duraklatma desteği yoktur. Tünelli oynatmayı yalnızca A/V açılarak duraklatabilirsiniz, ancak videonun dahili arabelleği büyükse (örneğin, OMX bileşeninde bir saniyelik veri varsa) duraklatmanın yanıt vermediği anlamına gelir.

Android 5.1 veya sonraki sürümlerde AudioFlinger, doğrudan (tünelli) ses çıkışları için duraklatma ve devam ettirmeyi destekler. HAL duraklatma ve devam ettirme özelliğini uygularsa parça duraklatma ve devam ettirme işlemi HAL'e yönlendirilir.

Duraklatma, boşaltma ve devam ettirme çağrısının sırasına, oynatma iş parçacığında HAL çağrıları yürütülerek (yükleme kaldırmayla aynı) uyulur.

Uygulama önerileri

Ses HAL'si

Android 11'de A/V senkronizasyonu için PCR veya STC'den alınan HW senkronizasyon kimliği kullanılabilir. Bu nedenle yalnızca video akışı desteklenir.

Android 10 veya önceki sürümler için tünelli video oynatmayı destekleyen cihazların audio_policy.conf dosyasında FLAG_HW_AV_SYNC ve AUDIO_OUTPUT_FLAG_DIRECT işaretleri bulunan en az bir ses çıkışı akış profili olmalıdır. Bu işaretler, sistem saatini ses saatinden ayarlamak için kullanılır.

OMX

Cihaz üreticileri, tünelli video oynatma için ayrı bir OMX bileşenine sahip olmalıdır (üreticiler, güvenli oynatma gibi diğer ses ve video oynatma türleri için ek OMX bileşenlerine sahip olabilir). Tünelli bileşen şun yapmalıdır:

  • Çıkış bağlantı noktasında 0 arabellek (nBufferCountMin, nBufferCountActual) belirtin.

  • OMX.google.android.index.prepareForAdaptivePlayback setParameter uzantısını uygulayın.

  • media_codecs.xml dosyasında özelliklerini belirtin ve tünellenmiş oynatma özelliğini beyan edin. Ayrıca, kare boyutu, hizalama veya bit hızı ile ilgili sınırlamalar da açıkça belirtilmelidir. Aşağıda bir örnek verilmiştir:

    <MediaCodec name="OMX.OEM_NAME.VIDEO.DECODER.AVC.tunneled"
    type="video/avc" >
        <Feature name="adaptive-playback" />
        <Feature name="tunneled-playback" required=true />
        <Limit name="size" min="32x32" max="3840x2160" />
        <Limit name="alignment" value="2x2" />
        <Limit name="bitrate" range="1-20000000" />
            ...
    </MediaCodec>
    

Tünellenmiş ve tünellenmemiş kod çözmeyi desteklemek için aynı OMX bileşeni kullanılıyorsa tünellenmiş oynatma özelliği zorunlu olarak ayarlanmamalıdır. Daha sonra hem tünelli hem de tünelsiz kod çözücüler aynı kapasite sınırlamalarına sahiptir. Aşağıda bir örnek verilmiştir:

<MediaCodec name="OMX._OEM\_NAME_.VIDEO.DECODER.AVC" type="video/avc" >
    <Feature name="adaptive-playback" />
    <Feature name="tunneled-playback" />
    <Limit name="size" min="32x32" max="3840x2160" />
    <Limit name="alignment" value="2x2" />
    <Limit name="bitrate" range="1-20000000" />
        ...
</MediaCodec>

Donanım Oluşturucu (HWC)

Bir ekranda tünelli bir katman (HWC_SIDEBAND compositionType içeren katman) olduğunda katmanın sidebandStream öğesi, OMX video bileşeni tarafından ayrılan yan bant tutamacıdır.

HWC, kodu çözülmüş video karelerini (tünelli OMX bileşeninden) ilişkili ses parçasına (audio-hw-sync kimliği ile) senkronize eder. Yeni bir video karesi mevcut olduğunda, HWC bunu son hazırlama veya ayarlanan çağrı sırasında alınan tüm katmanların mevcut içeriğiyle birleştirir ve ortaya çıkan görüntüyü gösterir. Hazırlama veya ayarlama çağrıları yalnızca diğer katmanlar değiştiğinde veya yan bant katmanının özellikleri (ör. konum veya boyut) değiştiğinde gerçekleşir.

Aşağıdaki şekilde, sese (7c) göre video karelerini (7b) en son besteyle (7a) doğru zamanda birleştirmek için donanım (veya çekirdek ya da sürücü) senkronize ediciyle çalışan HWC gösterilmiştir.

Sese göre video karelerini birleştiren HWC

Şekil 2. HWC donanımı (veya çekirdek ya da sürücü) senkronize edici