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
saatiAndroid 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.
Ş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:
SurfaceView
örneği oluşturun.audioSessionId
örneği oluşturun.2. adımda oluşturulan
audioSessionId
örneğiyleAudioTrack
veMediaCodec
örnekleri oluşturun.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:
SurfaceView
örneği oluşturun.Tuner
'dan biravSyncHwId
örneği alın.2. adımda oluşturulan
avSyncHwId
örneğiyleAudioTrack
veMediaCodec
ö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
parametresini1
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çinConfigureVideoTunnelModeParams
yapısını kullananOMX.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 iletilenC2PortTunneledModeTuning
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ğindeC2_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ı verenC2_PARAMKEY_TUNNEL_START_RENDER
kullanımı.debug.stagefright.ccodec_delayed_params
yapılandırmasız bırakın (önerilir). Yapılandırırsanızfalse
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, ¶ms);
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.
Şekil 2. HWC donanımı (veya çekirdek ya da sürücü) senkronize edici