Multimedya tünelleme

Multimedya tünelleme, sıkıştırılmış video verilerinin uygulama kodu veya Android çerçeve kodu tarafından işlenmeden doğrudan bir donanım video kod çözücüsü aracılığıyla bir ekrana tünellenmesini sağlar. Android yığınının altındaki cihaza özel kod, video çerçevesi sunum zaman damgalarını aşağıdaki dahili saat türlerinden biriyle karşılaştırarak hangi video çerçevelerinin ekrana 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, uygulamada geçirilen sesli sunum zaman damgalarıyla senkronize edilmiş bir AudioTrack saat

  • Android 11 veya sonraki sürümlerde canlı yayın oynatmak 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, sıkıştırılmış bir video karesinin kodu çözüldüğünde uygulamayı bildirir. Ardından uygulama, doğru zamanlamayı hesaplamak için geçmişteki AudioTimestamps örneklerini alarak kod çözümü yapılmış video karesini, karşılık gelen ses karesiyle aynı sistem saati zamanında oluşturulmak üzere ekrana yayınlar.

Tünellenmiş video oynatma, uygulama kodunu atlayıp video üzerinde işlem yapan süreçlerin 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 dikey senkronizasyonlarının zamanlaması arasındaki olası çarpıklığın neden olduğu zamanlama sorunlarını önleyerek seçilen saatle (PRC, STC veya ses) daha doğru video ritmi ve senkronizasyonu sağlayabilir. Ancak, arabellekler Android grafik yığınını atladığından tünel oluşturma, pencere içinde pencere (PiP) pencerelerinde bulanıklaştırma veya yuvarlak köşeler gibi GPU efektleri için desteği de azaltabilir.

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

geleneksel ve tünel modlarının karşılaştırılması

1. şekil. Geleneksel ve tünellenmiş video oynatma süreçlerinin karşılaştırması

Uygulama geliştiriciler için

Çoğu uygulama geliştirici, oynatma uygulaması için bir kitaplıkla entegrasyon yaptığından çoğu durumda uygulama için yalnızca bu kitaplığın tünellenmiş 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 örneklerini oluşturun.

  4. Ses verilerindeki ilk ses karesinin sunum zaman damgasıyla birlikte AudioTrack'ya ses verilerini sıraya alın.

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

  1. SurfaceView örneği oluşturun.

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

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

API çağrısı 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 oynatmanın davranışı

Tünellenmiş seç-izle video oynatma işlemi AudioTrack oynatma işlemine örtülü olarak bağlı olduğundan, tünellenmiş video oynatma işlemi ses oynatma işleminin davranışına bağlı olabilir.

  • Çoğu cihazda, varsayılan olarak ses oynatma başlayana kadar video karesi oluşturulmaz. Ancak uygulama, ses oynatmayı başlatmadan önce bir video karesi oluşturması gerekebilir. Örneğin, arama sırasında kullanıcının mevcut video konumunu göstermek için.

    • Kuyruğa alınan ilk video karesinin kodu çözülür çözülmez oluşturulması gerektiğini belirtmek için PARAMETER_KEY_TUNNEL_PEEK parametresini 1 olarak ayarlayın. Sıkıştırılmış video kareleri kuyrukta yeniden sıralandığında (ör. B kareleri mevcut olduğunda) bu, görüntülenen ilk video karesinin her zaman bir I karesi olması gerektiği anlamına gelir.

    • Sıraya alınan ilk video karesinin ses çalma işlemi başlayana kadar oluşturulmasını istemiyorsanız bu parametreyi 0 olarak ayarlayın.

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

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

  • Oynatma sırasında, uygulamanın düzeltemediği süreksizlikler ses sunumu zaman damgalarında görünebilir. Bu durumda OEM, geçerli video karesini duraklatarak negatif boşlukları, video karelerini bırakarak 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ünellenmiş oynatma özelliğine sahip olduğunu bildirmelidir:

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

Tünellenmiş bir MediaCodec örneği ses oturumu kimliğiyle yapılandırıldığında AudioFlinger, bu HW_AV_SYNC kimliği için sorgu gönderir:

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 dahili olarak ses oturumu kimliğiyle 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);

AudioTrack örneği zaten oluşturulmuşsa HW_AV_SYNC kimliği, aynı ses oturumu kimliğine sahip çı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, playback thread tarafından yapılır:

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

HW_AV_SYNC kimliği, ses çıkışı akışına veya Tuner yapılandırmasına karşılık gelip gelmediğine bakılmaksızın, OEM kodu codec'i ilgili ses çıkışı akışıyla veya tuner akışıyla ilişkilendirebilmesi için OMX ya da Codec2 bileşenine iletilir.

Bileşen yapılandırması sırasında, OMX veya Codec2 bileşeni, codec'i bir Hardware Composer (HWC) katmanıyla ilişkilendirmek için kullanılabilecek bir bant dışı işleyici döndürmelidir. Uygulama bir yüzeyi MediaCodec ile ilişkilendirdiğinde bu yan bant tutma yeri, SurfaceFlinger aracılığıyla HWC'ye aktarılır. HWC, 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, uygun zamanda codec çıkışından yeni görüntü arabellekleri almaktan (ilişkili ses çıkış akışıyla veya tuner programı referans saatiyle senkronize edilmiş), arabellekleri diğer katmanların mevcut içerikleriyle birleştirmekten ve ortaya çıkan görüntüyü göstermekten sorumludur. Bu işlem, normal hazırlama ve ayarlama döngüsünden bağımsız olarak gerçekleşir. Hazırlama ve 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.

OMX

Tünellenmiş bir kod çözücü bileşeni şunları desteklemelidir:

  • Ses çıkışı cihazıyla ilişkili HW_AV_SYNC kimliğini iletmek için OMX.google.android.index.configureVideoTunnelMode extended parametresini ayarlama. Bu parametre, ConfigureVideoTunnelModeParams yapısını kullanır.

  • Ses oynatma başlatılıp başlatılmadığına bakılmaksızın, codec'e ilk çözümlenen 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ğini gönderme.

AOSP uygulaması, aşağıdaki kod snippet'inde gösterildiği gibi ACodec üzerinden OMXNodeInstance aracılığıyla 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 bu codec'e bir yan bant tutma yeri ayırmalı ve HWC'nin ilişkili codec'i tanımlayabilmesi için 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şeni 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ğerlerini ileten C2PortTunneledModeTuning yapılandırılıyor.

  • HWC için bant dışı tutma yerini ayırmak ve almak üzere C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE sorgulanır.

  • C2_PARAMKEY_TUNNEL_HOLD_RENDER, C2Work öğesine eklendiğinde işleniyor. Bu durumda, codec'e kod çözme ve işin tamamlandığını bildirme talimatı veriliyor ancak 1) codec'e daha sonra oluşturma talimatı verilene veya 2) ses oynatma başlayana kadar çıkış arabelleğini oluşturma talimatı verilmiyor.

  • C2_PARAMKEY_TUNNEL_START_RENDER işleme: Bu, ses oynatma başlamamış olsa bile codec'e C2_PARAMKEY_TUNNEL_HOLD_RENDER ile işaretlenen kareyi hemen oluşturma talimatı verir.

  • debug.stagefright.ccodec_delayed_params yapılandırılmamış olarak 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 üzerinden CCodec içinde 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 bu codec'e bir yan bant tutma yeri ayırmalı ve HWC'nin ilişkili codec'i tanımlayabilmesi için C2PortTunnelHandlingTuning üzerinden geri geçirmelidir.

Ses HAL

İsteğe bağlı video oynatma için Audio HAL, uygulamanın yazdığı her ses verisi bloğunun başında bulunan bir başlıkta büyük endian biçiminde ses verileriyle birlikte ses sunumu zaman damgalarını 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 başlığını ayrıştırması ve oynatma saatini ses oluşturmayla yeniden senkronize etmek için sunum zaman damgasını kullanması gerekir. Sıkıştırılmış ses çalınırken yeniden senkronizasyon yapmak için Audio HAL'in, çalma 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 özelliği desteklenmez. Tünellenmiş oynatmayı yalnızca A/V yetersizliği nedeniyle duraklatabilirsiniz. Ancak videonun dahili arabelleği büyükse (ör. OMX bileşeninde bir saniyelik veri varsa) duraklatma yanıt vermiyormuş gibi görünür.

Android 5.1 veya sonraki sürümlerde AudioFlinger, doğrudan (tünellenmiş) ses çıkışlarında duraklatma ve devam ettirme işlemlerini destekler. HAL, duraklatma ve devam ettirme işlemlerini uyguluyorsa duraklatma ve devam ettirme isteği HAL'ye iletilir.

Duraklatma, temizleme, devam ettirme çağrı sırası, HAL çağrıları oynatma iş parçacığında (aynı boşaltma gibi) yürütülerek uygulanır.

Uygulama önerileri

Ses HAL

Android 11'de A/V senkronizasyonu için PCR veya STC'den alınan donanım senkronizasyon kimliği kullanılabilir. Bu nedenle, yalnızca video akışı 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şaretlerini içeren 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ü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ıyla ilgili sınırlamalar da açıklanmalıdır. Aşağıda bir örnek gösterilmektedir:

    <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ünel ve tünel dışı kod çözme işlemlerini desteklemek için aynı OMX bileşeni kullanılıyorsa tünel dışı oynatma özelliği gerekli olmayan olarak bırakılmalıdır. Bu durumda, tünellenmiş ve tünellenmemiş kod çözücüler aynı özellik sınırlamalarına sahip olur. Aşağıda bir örnek gösterilmiş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) olduğunda, katmanın sidebandStream değeri OMX video bileşeni tarafından ayrılan bant dışı tutamaçtır.

HWC, tünellenmiş OMX bileşeninden gelen kod çözülmüş video karelerini, 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 ya da yan bant katmanının özellikleri (ör. konum veya boyut) değiştiğinde gerçekleşir.

Aşağıdaki şekil, video karelerini (7b) ses (7c) temelinde doğru zamanda görüntülemek için en son kompozisyonla (7a) birleştirmek üzere donanım (veya çekirdek ya da sürücü) senkronizasyon cihazıyla birlikte çalışan HWC'yi gösterir.

HWC, video karelerini sese göre birleştirir.

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