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 kod çözücü aracılığıyla doğrudan bir ekrana tünellenmesine olanak tanır. 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 bunların ne zaman gönderileceğini belirler:

  • Android 5 veya üzeri sürümlerde isteğe bağlı video oynatmak için, uygulama tarafından iletilen ses sunumu zaman damgalarıyla senkronize edilmiş bir AudioTrack saati

  • Android 11 veya sonraki sürümlerde canlı yayın oynatımı için, bir ayarlayıcı tarafından çalıştırılan bir program referans saati (PCR) veya sistem zaman saati (STC)

Arka plan

Android'de geleneksel video oynatma, sıkıştırılmış bir video karesinin kodu çözüldüğünde uygulamayı bilgilendirir . Uygulama daha sonra kodu çözülmüş video karesini, karşılık gelen ses karesiyle aynı sistem saat saatinde oluşturulmak üzere ekrana yayınlar ve doğru zamanlamayı hesaplamak için geçmiş AudioTimestamps örneklerini alır .

Tünellenmiş video oynatma, uygulama kodunu atladığından ve video üzerinde etkili olan işlem sayısını azalttığından, OEM uygulamasına bağlı olarak daha verimli video oluşturma sağlayabilir. Ayrıca, Android'in video işleme isteklerinin zamanlaması ile gerçek donanım vsync'lerinin zamanlaması arasındaki olası çarpıklığın yol açtığı zamanlama sorunlarından kaçınarak, seçilen saate (PRC, STC veya ses) daha doğru video temposu ve senkronizasyonu sağlayabilir. Ancak tünel oluşturma, arabelleklerin Android grafik yığınını atlaması nedeniyle, resim içinde resim (PiP) pencerelerinde bulanıklık veya köşelerin yuvarlanması 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.

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

Şekil 1. Geleneksel ve tünelli video oynatma işlemlerinin karşılaştırılması

Uygulama geliştiricileri için

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

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

  1. Bir SurfaceView örneği oluşturun.

  2. Bir 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 karesi için sunum zaman damgasıyla ses verilerini AudioTrack sıraya alın.

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

  1. Bir SurfaceView örneği oluşturun.

  2. Tuner 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 parçacıklarında 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ş isteğe bağlı video oynatmanın AudioTrack oynatmaya dolaylı olarak bağlı olması nedeniyle, tünellenmiş video oynatmanın davranışı ses oynatmanın davranışına bağlı olabilir.

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

    • Sıraya 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 (örneğin, 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 oynatımı başlayana kadar işlenmesini istemiyorsanız bu parametreyi 0 olarak ayarlayın.

    • Bu parametre ayarlanmazsa OEM, aygıtın davranışını belirler.

  • AudioTrack ses verileri sağlanmadığında ve arabellekler boş olduğunda (ses yetersiz çalıştığında), ses saati artık ilerlemediğinden video oynatma daha fazla ses verisi yazılana kadar durur.

  • Oynatma sırasında, uygulamanın düzeltemediği süreksizlikler ses sunumu zaman damgalarında görünebilir. Bu olduğunda, OEM, mevcut video karesini durdurarak negatif boşlukları düzeltir ve video karelerini bırakarak veya sessiz ses çerçeveleri ekleyerek (OEM uygulamasına bağlı olarak) pozitif boşlukları düzeltir. AudioTimestamp çerçeve konumu, eklenen sessiz ses çerçeveleri için artmaz.

Cihaz üreticileri için

Yapılandırma

OEM'ler, tünelli video oynatmayı desteklemek için ayrı bir video kod çözücü oluşturmalıdır. Bu kod çözücünün media_codecs.xml dosyasında tünelli oynatma yeteneğine sahip olduğunu duyurması gerekir:

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

Tünellenmiş bir MediaCodec örneği bir sesli oturum kimliğiyle yapılandırıldığında, bu HW_AV_SYNC kimliği için AudioFlinger 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 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);

Bir AudioTrack örneği zaten oluşturulmuşsa HW_AV_SYNC kimliği, aynı ses oturumu kimliğiyle çıkış akışına aktarılır. Henüz oluşturulmamışsa HW_AV_SYNC ID, AudioTrack oluşturulması sırasında çıkış akışına aktarılır. Bu, oynatma iş parçacığı 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, ister bir ses çıkış akışına ister bir Tuner yapılandırmasına karşılık gelsin, OMX veya Codec2 bileşenine aktarılır, böylece OEM kodu codec bileşenini karşılık gelen ses çıkış akışı veya ayarlayıcı akışıyla ilişkilendirebilir.

Bileşen yapılandırması sırasında, OMX veya Codec2 bileşeninin, codec bileşenini bir Donanım Oluşturucu (HWC) katmanıyla ilişkilendirmek için kullanılabilecek bir yan bant tanıtıcısı döndürmesi gerekir. Uygulama bir yüzeyi MediaCodec ile ilişkilendirdiğinde, bu yan bant tutamacı, katmanı bir yan bant katmanı olarak yapılandıran SurfaceFlinger aracılığıyla HWC'ye aktarılı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, ilgili ses çıkış akışıyla veya ayarlayıcı program referans saatiyle senkronize edilmiş olarak codec çıkışından uygun zamanda yeni görüntü arabelleklerinin alınmasından, arabelleklerin diğer katmanların geçerli içerikleriyle birleştirilmesinden ve ortaya çıkan görüntünün görüntülenmesinden sorumludur. Bu, normal hazırlama ve ayarlama döngüsünden bağımsız olarak gerçekleşir. Hazırlık ve 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.

OMX

Tünel 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 bileşenine kodu çözülen ilk video karesini oluşturmasını veya oluşturmamasını söyleyen OMX_IndexConfigAndroidTunnelPeek parametresini yapılandırma.

  • İlk tünelli video karesinin kodu çözüldüğünde ve oluşturulmaya hazır olduğunda OMX_EventOnFirstTunnelFrameReady olayının gönderilmesi.

AOSP uygulaması, aşağıdaki kod parçacığında gösterildiği gibi ACodec tünel modunu OMXNodeInstance aracılığıyla 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 bileşenine bir yan bant tanıtıcısı tahsis etmeli ve HWC'nin ilgili codec bileşenini tanımlayabilmesi için bunu pSidebandWindow üyesi aracılığıyla geri iletmelidir. Bileşen bu yapılandırmayı desteklemiyorsa bTunneled 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ış aygıtından veya tuner yapılandırmasından alınan HW_AV_SYNC aktaran C2PortTunneledModeTuning yapılandırılması.

  • HWC için yan bant tanıtıcısını tahsis etmek ve almak için C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE sorgusu yapılıyor.

  • Bir C2Work bağlandığında C2_PARAMKEY_TUNNEL_HOLD_RENDER kullanılması; codec'e kodu çözmesi ve işin tamamlandığının sinyalini vermesi talimatını verir, ancak 1) codec'e daha sonra bunu oluşturması talimatı verilene veya 2) ses oynatma başlayana kadar çıkış arabelleğini oluşturmaz.

  • Codec'e, ses oynatma başlatılmamış olsa bile C2_PARAMKEY_TUNNEL_HOLD_RENDER ile işaretlenen kareyi hemen oluşturması talimatını veren C2_PARAMKEY_TUNNEL_START_RENDER işlevinin kullanılması.

  • debug.stagefright.ccodec_delayed_params yapılandırılmamış halde bırakın (önerilir). Yapılandırmanız durumunda false olarak ayarlayın.

AOSP uygulaması, aşağıdaki kod parçacığında gösterildiği gibi CCodec tünel modunu C2PortTunnelModeTuning aracılığıyla 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 bileşenine bir yan bant tanıtıcısı tahsis etmeli ve HWC'nin ilgili codec bileşenini tanımlayabilmesi için bunu C2PortTunnelHandlingTuning aracılığıyla geri iletmelidir.

Ses HAL'i

İsteğe bağlı video oynatımı için Audio HAL, ses sunumu zaman damgalarını, uygulamanın yazdığı her ses verisi bloğunun başlangıcında bulunan bir başlığın içindeki big-endian formatındaki ses verileriyle aynı satırda 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 işlemesi için, Ses HAL'in senkronizasyon başlığını ayrıştırması ve oynatma saatini ses işlemeyle yeniden senkronize etmek için sunum zaman damgasını kullanması gerekir. Sıkıştırılmış ses oynatılırken yeniden senkronizasyon yapmak için Ses HAL'in, oynatma süresini belirlemek amacıyla sıkıştırılmış ses verileri içindeki meta verileri ayrıştırması gerekebilir.

Desteği duraklat

Android 5 veya daha düşük sürümlerde duraklatma desteği bulunmaz. Tünellenmiş oynatmayı yalnızca A/V yetersizliği nedeniyle duraklatabilirsiniz, ancak video için dahili arabellek büyükse (örneğin, OMX bileşeninde bir saniyelik veri varsa), duraklatmanın yanıt vermiyor gibi görünmesine neden olur.

Android 5.1 veya üzeri sürümlerde AudioFlinger , doğrudan (tünellenmiş) ses çıkışları için duraklatmayı ve devam ettirmeyi destekler. HAL duraklatma ve devam ettirmeyi uyguluyorsa parça duraklatma ve devam etme HAL'e iletilir.

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

Uygulama önerileri

Ses HAL'i

Android 11 için PCR veya STC'den gelen HW senkronizasyon kimliği A/V senkronizasyonu için kullanılabilir, böylece yalnızca video akışı desteklenir.

Android 10 veya daha düşük 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 bayraklarıyla en az bir ses çıkış akışı profiline sahip olması gerekir. Bu bayraklar 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ünellenmiş bileşen şunları 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 yeteneklerini belirtin ve tünelli oynatma özelliğini bildirin. Ayrıca çerçeve boyutu, hizalama veya bit hızıyla ilgili sınırlamaları da açıklığa kavuşturmalıdır. Aşağıda bir örnek gösterilmiş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ünelli ve tünelsiz kod çözmeyi desteklemek için aynı OMX bileşeni kullanılıyorsa, tünelli oynatma özelliğini gerekli değil olarak bırakmalıdır. Hem tünelli hem de tünelsiz kod çözücüler aynı yetenek sınırlamalarına sahiptir. 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 Oluşturucusu (HWC)

Ekranda tünellenmiş bir katman ( HWC_SIDEBAND compositionType içeren bir katman) olduğunda, katmanın sidebandStream OMX video bileşeni tarafından tahsis edilen yan bant tanıtıcısıdır.

HWC, kodu çözülmüş video karelerini (tünellenmiş OMX bileşeninden) ilgili ses parçasına ( audio-hw-sync ID ile) senkronize eder. Yeni bir video karesi geçerli hale geldiğinde, HWC bunu son hazırlama veya ayarlama çağrısı sırasında alınan tüm katmanların geçerli içerikleriyle birleştirir ve ortaya çıkan görüntüyü görüntüler. Hazırlık 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, sese (7c) dayalı olarak doğru zamanda görüntülenmek üzere video karelerini (7b) en son kompozisyonla (7a) birleştirmek için donanım (veya çekirdek veya sürücü) senkronize ediciyle çalışan HWC'yi temsil etmektedir.

HWC sese dayalı video karelerini birleştiriyor

Şekil 2. HWC donanım (veya çekirdek veya sürücü) eşitleyici