Multimedya tünelleme

Multimedya tünelleme, sıkıştırılmış video verilerinin uygulama kodu veya Android çerçeve kodu tarafından işlenmeden bir donanım video kodlayıcısı üzerinden doğrudan ekrana tünelemesini sağlar. Android yığınının altındaki cihaza özel kod, video karesi sunum zaman damgalarını aşağıdaki dahili saat türlerinden biriyle karşılaştırarak ekrana hangi video karelerinin gönderileceğini 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 ses sunumu zaman damgalarıyla senkronize edilen bir AudioTrack saati iletilir.

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

Arka plan

Android'de geleneksel video oynatma, sıkıştırılmış bir video karesi kod çözüldüğünde uygulamayı bilgilendirir. 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ünellenmiş video oynatma, uygulama kodunu atlar ve video üzerinde işlem yapan işlemlerin sayısını azalttığından 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 nedeniyle ortaya çıkan zamanlama sorunlarını önleyerek seçilen saate (PRC, STC veya ses) göre daha doğru video ritmi ve senkronizasyon sağlayabilir. Ancak tünel oluşturma, arabellekler Android grafik yığınını atladığı için bulanıklaştırma veya pencere içinde pencere (PiP) pencerelerindeki yuvarlatılmış köşeler gibi GPU efektleri için 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 süreçlerinin karşılaştırması

Uygulama geliştiriciler için

Çoğu uygulama geliştirici, oynatma uygulamak için bir kitaplıkla entegrasyon yaptığından, çoğu durumda uygulama için yalnızca bu kitaplığın tünel oynatma için yeniden yapılandırılması gerekir. Tünellenmiş video oynatıcının düşük düzeyde uygulanması 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ünellenmiş seç-izle video oynatma, AudioTrackoynatma işlemine dolaylı olarak bağlı olduğundan, tünellenmiş video oynatma işleminin davranışı ses oynatma işleminin davranışına bağlı olabilir.

  • Çoğu cihazda, ses oynatılmaya başlayana kadar video karesi varsayılan olarak oluşturulmaz. Ancak uygulamanın, ses oynatmaya başlamadan önce bir video karesi oluşturması gerekebilir. Örneğin, kullanıcıya arama yaparken mevcut video konumunu göstermek için.

    • Sırada bekleyen ilk video karesinin, kod çözme işlemi tamamlanır tamamlanmaz 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 kareleri mevcut olduğunda), ilk görüntülenen video karesi her zaman bir I karesi olmalıdır.

    • Ses oynatılmaya başlayana kadar sıraya eklenen 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üzeltmeye çalıştığı kesintiler ses sunumu zaman damgalarında görünebilir. Bu durumda OEM, mevcut video karesini duraklatarak negatif boşlukları ve video karelerini atlayarak veya sessiz ses kareleri ekleyerek (OEM uygulamasına bağlı olarak) pozitif boşlukları düzeltir. Eklenen sessiz ses çerçeveleri için AudioTimestamp çerçeve 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ünellenmiş bir MediaCodec örneği ses oturumu kimliğiyle yapılandırıldığında, bu HW_AV_SYNC kimliği için AudioFlinger'den sorgu alır:

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 ses oturumu 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);

Halihazırda bir AudioTrack örneği oluşturulduysa HW_AV_SYNC kimliği, aynı ses oturumu kimliğiyle çıkış akışına iletilir. Henüz oluşturulmamışsa HW_AV_SYNC kimliği, AudioTrack oluşturulurken çı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 resim arabelleklerini almak (ilgili ses çıkış akışıyla veya tuner program referans saatiyle senkronize olarak), arabellekleri diğer katmanların mevcut içerikleriyle birleştirmek ve ortaya çıkan resmi görüntülemekle sorumludur. Bu işlem, 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'e ilk kod çözülmüş video karesini oluşturmasını veya oluşturmamasını söyleyen OMX_IndexConfigAndroidTunnelPeek parametresini yapılandırma.

  • İlk tünellenmiş 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 mülkü ayırmalı ve pSidebandWindow üyesi aracılığıyla geri iletmelidir. Bileşen bu yapılandırmayı desteklemiyorsa 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 tuner yapılandırmasından alınan HW_AV_SYNC değerini ileten C2PortTunneledModeTuning değerini yapılandırma.

  • HWC için yan bant tutamacını ayırmak ve almak üzere C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE sorgulanmaktadır.

  • C2_PARAMKEY_TUNNEL_HOLD_RENDER, C2Work'e eklendiğinde işlenir. Bu işlem, codec'e kod çözme ve çalışmanın tamamlandığını bildirme talimatı verir ancak 1) codec'e daha sonra oluşturma talimatı verilene veya 2) ses oynatmaya başlanana kadar çıkış arabelleğini oluşturmamasını sağlar.

  • C2_PARAMKEY_TUNNEL_START_RENDER değerini işleyen codec'e, ses oynatılmamış olsa bile C2_PARAMKEY_TUNNEL_HOLD_RENDER ile işaretlenen kareyi hemen oluşturmasını talimat verir.

  • 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 C2PortTunnelModeTuning aracılığıyla CCodec'te tünel modunu 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 mülkü ayırmalı ve C2PortTunnelHandlingTuning üzerinden geri iletmelidir.

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 ilgili ses kareleriyle senkronize olarak oluşturması için Audio HAL'in senkronizasyon üstbilgisini ayrıştırması ve oynatma saatini ses oluşturmayla yeniden senkronize etmek için sunma zaman damgasını kullanması gerekir. Sıkıştırılmış ses çalarken 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 duraklatma

Android 5 veya daha eski sürümlerde duraklatma desteği yoktur. Tünellenmiş oynatmayı yalnızca A/V açlığıyla duraklatabilirsiniz. Ancak videonun dahili arabelleği büyükse (ör. OMX bileşeninde bir saniyelik veri varsa) duraklatma işlemi yanıt vermiyormuş gibi görünür.

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

HAL çağrıları oynatma iş parçacığında çalıştırılarak duraklatma, temizleme, devam ettirme çağrı sırasına uyulur (aktarmayla aynı).

Uygulama önerileri

Ses HAL'si

Android 11 için PCR veya STC'den alınan donanım senkronizasyon kimliği A/V senkronizasyonu için kullanılabilir. Bu nedenle, yalnızca video aktarımı desteklenir.

Android 10 veya önceki sürümlerde, tünellenmiş 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 sesli saatten ayarlamak için kullanılır.

OMX

Cihaz üreticileri, tünellenmiş 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ünellenmiş bileşen:

  • Çı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 olmayan olarak bırakılmalıdır. Bu durumda, hem tünellenmiş hem de tünellenmemiş kod çözücüler aynı özellik 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 Bestecisi (HWC)

Bir ekranda tünellenmiş katman (HWC_SIDEBAND compositionType içeren bir katman) varsa katmanın sidebandStream değeri, OMX video bileşeni tarafından ayrılan yan bant tutamacıdır.

HWC, kod çözülmüş video karelerini (tünellenmiş OMX bileşeninden) ilişkili ses parçasıyla (audio-hw-sync kimliğiyle) senkronize eder. Yeni bir video karesi geçerli hale geldiğinde HWC, bu kareyi son hazırlama veya ayarlama çağrısı sırasında alınan tüm katmanların mevcut içerikleriyle 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 (konum veya boyut gibi) değiştiğinde gerçekleşir.

Aşağıdaki şekil, video karelerini (7b) ses (7c) temel alınarak doğru zamanda görüntülemek için donanım (veya çekirdek veya sürücü) senkronizörüyle çalışan HWC'yi temsil etmektedir.

Seslere göre video karelerini birleştiren HWC

Şekil 2. HWC donanım (veya çekirdek veya sürücü) senkronizasyon aracı