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.
Ş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:
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ünellenmiş seç-izle video oynatma, AudioTrack
oynatma 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
parametresini1
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ç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'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 iletenC2PortTunneledModeTuning
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 bileC2_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ızfalse
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, ¶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 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.
Şekil 2. HWC donanım (veya çekirdek veya sürücü) senkronizasyon aracı