Tunelowanie multimedialne umożliwia tunelowanie skompresowanych danych wideo za pomocą sprzętu z dekodera wideo bezpośrednio na wyświetlacz, bez przetwarzania przez kod aplikacji Kod platformy Androida. Kod urządzenia poniżej stosu Androida określa, które klatki wideo mają być wysyłane na wyświetlacz i kiedy. porównując sygnatury czasowe prezentacji klatki wideo z jednym z poniższych: typy zegara wewnętrznego:
W przypadku odtwarzania filmów na żądanie w Androidzie 5 lub nowszym
AudioTrack
zegar zsynchronizowany z sygnaturami czasowymi prezentacji audio Zaliczono w aplikacjiNa potrzeby odtwarzania transmisji na żywo w Androidzie 11 lub nowszym: zegar referencyjny programu (PCR) lub zegara systemowego (STC) napędzanego przez tuner
Tło
w przypadku tradycyjnego odtwarzania filmów na Androidzie powiadomienia;
w aplikacji po zdekodowaniu skompresowanej klatki wideo. Następnie aplikacja
wersje
zdekodowana klatka wideo na wyświetlacz, która będzie renderowana z tym samym zegarem systemowym.
jako odpowiednią klatkę audio,
pobieram dane historyczne
AudioTimestamps
aby obliczyć prawidłowy czas.
Ponieważ tunelowane odtwarzanie wideo omija kod aplikacji i zmniejsza liczbę przetwarzania wideo, może zapewnić efektywniejsze renderowanie filmu w zależności od wdrożenia OEM. Może też dostarczać dokładniejszych filmów częstotliwość i synchronizację z wybranym zegarem (PRC, STC lub audio) przez problemy z czasem działania spowodowane potencjalnym odchyleniem czasu wczytywania Androida żądań renderowania wideo i czasu prawdziwych sprzętowych vsync. Pamiętaj jednak: tunelowanie może też ograniczyć obsługę efektów GPU, takich jak: rozmycie lub zaokrąglonych rogów okna obrazu w obrazie, ponieważ ominąć stos graficzny Androida.
Na diagramie poniżej widać, jak tunelowanie upraszcza proces odtwarzania filmu.
Rysunek 1. Porównanie tradycyjnych i tunelowanych procesów odtwarzania wideo
Dla deweloperów aplikacji
Większość deweloperów aplikacji integruje się z biblioteką do odtwarzania lub implementacja, w większości przypadków wymaga jedynie ponownego skonfigurowania do odtwarzania tunelowego. Na potrzeby niskopoziomowej implementacji wideo tunelowanego postępuj zgodnie z poniższymi instrukcjami.
Aby odtwarzać filmy na żądanie w Androidzie 5 lub nowszym:
Utwórz instancję
SurfaceView
.Utwórz instancję
audioSessionId
.Utwórz instancje
AudioTrack
iMediaCodec
za pomocą interfejsuaudioSessionId
utworzonej w kroku 2.Dodawaj dane audio do kolejki
AudioTrack
z sygnaturą czasową prezentacji dla pierwszej klatki audio w danych audio.
Aby odtwarzać transmisję na żywo w Androidzie 11 lub nowszym:
Utwórz instancję
SurfaceView
.Pobrać instancję
avSyncHwId
z usługiTuner
.Tworzenie instancji
AudioTrack
iMediaCodec
za pomocą instancjiavSyncHwId
utworzonych w kroku 2.
Przepływ wywołań interfejsu API jest widoczny w tych fragmentach kodu:
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);
Działanie odtwarzania filmów na żądanie
Ponieważ odtwarzanie wideo na żądanie jest domyślnie powiązane z funkcją AudioTrack
działanie tunelowanego odtwarzania wideo może zależeć od jego działania
w odtwarzaniu dźwięku.
Na większości urządzeń klatka wideo jest domyślnie renderowana dopiero po wyświetleniu dźwięku. rozpocznie się odtwarzanie. Możliwe jednak, że aplikacja będzie musiała wyrenderować klatkę wideo, rozpoczynanie odtwarzania dźwięku, na przykład w celu pokazania użytkownikowi bieżącego filmu pozycji podczas przewijania.
Żeby zasygnalizować, że pierwsza klatka filmu w kolejce powinna zostać wyrenderowana, gdy tylko zostanie wyrenderowana zostanie odkodowany, ustaw
PARAMETER_KEY_TUNNEL_PEEK
do1
. Gdy skompresowane klatki filmu są zmieniane w kolejce (na przykład podczas Klatki B są obecne). Oznacza to, że pierwsza wyświetlana klatka wideo powinna zawsze być iFrame.Jeśli nie chcesz, by pierwsza klatka filmu znajdująca się w kolejce była renderowana do momentu pojawienia się dźwięku rozpocznie się odtwarzanie, ustaw ten parametr na
0
.Jeśli ten parametr nie jest skonfigurowany, sposób działania urządzenia określa producent OEM.
Gdy usługa
AudioTrack
nie otrzymuje danych audio, a bufory są puste (dźwięk niedostatecznie emitowany) odtwarzanie filmu się zatrzymuje do czasu zapisania kolejnych danych dźwiękowych. bo zegar audio przestał działać.Podczas odtwarzania nieciągłości, których aplikacja nie może poprawić, mogą pojawić się sygnatury czasowe prezentacji audio. W takim przypadku OEM koryguje wartość ujemną. w postaci przerw w odtwarzaniu filmu, a także jako luki dodatnie, klatki wideo lub wstawianie cichych klatek audio (w zależności od modelu OEM implementacji). Położenie klatki na obrazie z
AudioTimestamp
nie zwiększa się w przypadku: wstawiono wyciszone klatki audio.
Producenci urządzeń
Konfiguracja
OEM powinien utworzyć oddzielny dekoder wideo do obsługi odtwarzania treści wideo tunelowanego.
Taki dekoder powinien informować, że może on odtwarzać tunelowane
Plik media_codecs.xml
:
<Feature name="tunneled-playback" required="true"/>
Gdy tunelowana instancja MediaCodec
zostanie skonfigurowana z identyfikatorem sesji audio,
zapytanie AudioFlinger
dla tego identyfikatora HW_AV_SYNC
:
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);
}
Podczas tego zapytania
AudioFlinger
pobiera identyfikator HW_AV_SYNC
z głównego urządzenia audio i wewnętrznie kojarzy je z dźwiękiem.
identyfikator sesji:
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);
Jeśli instancja AudioTrack
została już utworzona, identyfikator HW_AV_SYNC
to
przekazywane do strumienia wyjściowego z tym samym identyfikatorem sesji audio. Jeśli nie został
nie został jeszcze utworzony, to identyfikator HW_AV_SYNC
jest przekazywany do strumienia wyjściowego podczas
Kompozycja AudioTrack
. Odbywa się to podczas odtwarzania
wątek:
mOutput->stream->common.set_parameters(&mOutput->stream->common, AUDIO_PARAMETER_STREAM_HW_AV_SYNC, hwAVSyncId);
Identyfikator HW_AV_SYNC
, niezależnie od tego, czy odpowiada on strumieniowi wyjściowemu audio czy
Tuner
, jest przekazywana do komponentu OMX lub Codec2, tak aby
Kod OEM może powiązać kodek z odpowiednim strumieniem wyjściowym audio lub
z tunera.
Podczas konfiguracji komponent OMX lub Codec2 powinien zwrócić błąd
uchwyt boczny umożliwiający powiązanie kodeka z narzędziem Hardware Composer
(HWC). Gdy aplikacja powiąże powierzchnię z elementem MediaCodec
, ta opaska boczna
jest przekazywany do HWC przez SurfaceFlinger
, który konfiguruje
jako
pasek boczny.
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 odpowiada za odbiór nowych buforów obrazu z danych wyjściowych kodeka odpowiedni czas synchronizacji z powiązanym strumieniem wyjścia audio lub zegar referencyjny programu dostrajania, komponując bufory z bieżącym czasem zawartości innych warstw i wyświetlając wynikowy obraz. Dzieje się tak niezależnie od normalnego cyklu przygotowań i stawek. Przygotowanie i ustawianie rozmów zachodzi tylko wtedy, gdy zmienią się inne warstwy lub właściwości warstwy paska bocznego (np. pozycji lub rozmiaru).
OMX,
Komponent dekodera tunelowego powinien obsługiwać:
Ustawiam:
OMX.google.android.index.configureVideoTunnelMode
który wykorzystuje strukturęConfigureVideoTunnelModeParams
do przekazywania w identyfikatorzeHW_AV_SYNC
powiązanym z urządzeniem wyjściowym audio.Skonfigurowanie parametru
OMX_IndexConfigAndroidTunnelPeek
, który informuje kodek ma być renderowany lub nie renderować pierwszej zdekodowanej klatki wideo, niezależnie od czy rozpoczęło się odtwarzanie dźwięku.Wysyłam zdarzenie
OMX_EventOnFirstTunnelFrameReady
po pierwszym tunelowaniu klatka wideo została zdekodowana i jest gotowa do renderowania.
Implementacja AOSP konfiguruje tryb tunelu w
ACodec
Przez
OMXNodeInstance
Jak widać w tym fragmencie kodu:
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;
Jeśli komponent obsługuje tę konfigurację, powinien przydzielić pasek boczny
w tym kodeku i przekazać go elementowi pSidebandWindow
,
że HWC może zidentyfikować powiązany kodek. Jeśli komponent nie
obsługuje tę konfigurację, ustaw wartość bTunneled
na OMX_FALSE
.
Kodek2
W Androidzie 11 lub nowszym Codec2
obsługuje odtwarzanie tunelowane. Dekoder
powinien obsługiwać te komponenty:
Konfiguruję instancję
C2PortTunneledModeTuning
, która konfiguruje tryb tunelu przechodzi wHW_AV_SYNC
pobranym z urządzenia wyjściowego audio lub konfiguracji tunera.Wysłanie zapytania do funkcji
C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE
w celu przydzielenia i pobrania uchwytu paska bocznego dla urządzeń HWC.Obsługa
C2_PARAMKEY_TUNNEL_HOLD_RENDER
po podłączeniu doC2Work
, które instruuje kodek, aby dekodował i sygnalizował zakończenie pracy, ale nie renderował w buforze wyjściowym do momentu 1) kodeka zostanie później zlecona lub 2) rozpocznie się odtwarzanie dźwięku.Obsługa metody
C2_PARAMKEY_TUNNEL_START_RENDER
, która instruuje kodek natychmiast wyrenderuj ramkę oznaczoną znakiemC2_PARAMKEY_TUNNEL_HOLD_RENDER
, nawet jeśli odtwarzanie dźwięku jeszcze się nie rozpoczęło.Pozostaw usługę
debug.stagefright.ccodec_delayed_params
nieskonfigurowaną (zalecane). Jeśli go skonfigurować, ustaw wartośćfalse
.
Implementacja AOSP konfiguruje tryb tunelu w
CCodec
do C2PortTunnelModeTuning
, jak widać w tym fragmencie kodu:
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;
}
Jeśli komponent obsługuje tę konfigurację, powinien przydzielić pasek boczny
do tego kodeka i przekazać go za pomocą C2PortTunnelHandlingTuning
,
że HWC może zidentyfikować powiązany kodek.
HAL audio
W przypadku odtwarzania filmów na żądanie HAL audio odbiera prezentację audio. Znaleziono sygnatury czasowe w nagłówku wewnątrz danych audio w formacie big-endian na początku każdego bloku danych dźwiękowych, które aplikacja zapisuje:
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;
}
Aby HWC renderowało klatki wideo zsynchronizowane z odpowiednimi klatkami audio, HAL audio powinien przeanalizować nagłówek synchronizacji i użyć sygnatury czasowej prezentacji do zsynchronizować zegar odtwarzania z renderowaniem dźwięku. Aby przeprowadzić ponowną synchronizację, gdy W trakcie odtwarzania skompresowanego dźwięku może być konieczne przeanalizowanie metadanych przez HAL audio w skompresowanych danych audio, aby określić czas odtwarzania.
Wstrzymaj pomoc
Android 5 i starsze wersje nie obsługują wstrzymywania. Możesz wstrzymać tunelowanie z powodu braku sygnału audio, ale jeśli wewnętrzny bufor dla filmu jest duży (na przykład w komponencie OMX jest jedna sekunda danych), powoduje wstrzymanie nie odpowiada.
W Androidzie 5.1 lub nowszym aplikacja AudioFlinger
obsługuje wstrzymywanie i wznawianie przesyłania bezpośredniego
(tunelowanych) wyjść audio. Jeśli HAL stosuje wstrzymywanie i wznawianie, śledź wstrzymanie
a CV jest przekazywane do HAL.
Sekwencja wstrzymywania, opróżniania i wznowienia jest respektowana przez wykonywanie wywołań HAL. w wątku odtwarzania (tak samo jak w przypadku odciążania).
Sugestie dotyczące implementacji
HAL audio
W Androidzie 11 identyfikator synchronizacji sprzętu z PCR lub STC może być używany do synchronizacji audio/wideo, jest obsługiwany tylko strumień wideo.
W przypadku Androida 10 lub starszego urządzenia obsługujące odtwarzanie filmów z tunelem powinny mieć
co najmniej 1 profil strumienia wyjściowego audio z parametrami FLAG_HW_AV_SYNC
i
AUDIO_OUTPUT_FLAG_DIRECT
w pliku audio_policy.conf
. Te flagi
służą do ustawiania zegara systemowego na poziomie zegara audio.
OMX,
Producenci urządzeń powinni mieć osobny komponent OMX dla wideo tunelowanego na potrzeby innych typów systemów uczących się (producenci mogą mieć dodatkowe komponenty OMX dla innych typów odtwarzania dźwięku i wideo, np. bezpieczne odtwarzanie). Komponent tunelowany powinien:
Określ 0 buforów (
nBufferCountMin
,nBufferCountActual
) na danych wyjściowych portu.Zaimplementuj rozszerzenie
OMX.google.android.index.prepareForAdaptivePlayback setParameter
.Określ jej możliwości w pliku
media_codecs.xml
i zadeklaruj komponent dzięki funkcji odtwarzania tunelowanego. Powinny również zawierać informacje o ograniczeniach dotyczących ramki. rozmiar, wyrównanie czy szybkość transmisji bitów. Przykład poniżej:<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>
Jeśli do obsługi dekodowania tunelowanego i nietunelu używany jest ten sam komponent OMX, funkcja odtwarzania tunelowanego powinna pozostać niewymagana. Zarówno tunelowane, dekodery nietunele mają te same ograniczenia możliwości. Na przykład: poniżej:
<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>
Hardware Composer (HWC)
Gdy włączona jest warstwa tunelowa (warstwa z atrybutem HWC_SIDEBAND
compositionType
)
wyświetlacza, sidebandStream
warstwy to uchwyt paska bocznego przydzielony przez
Komponent wideo OMX.
HWC synchronizuje zdekodowane klatki wideo (z tunelowanego komponentu OMX) z
powiązana ścieżka audio (z identyfikatorem audio-hw-sync
). Gdy nowa klatka wideo jest wyświetlana
staje się aktualny, HWC łączy go z bieżącą zawartością wszystkich warstw
podczas ostatniego przygotowania lub ustawionej rozmowy, i wyświetla wynikowy obraz.
Wywołania przygotowujące lub ustawione następują tylko wtedy, gdy zmienią się inne warstwy albo
właściwości warstwy paska bocznego (takie jak pozycja i rozmiar).
Poniższy rysunek przedstawia kod HWC współpracujący ze sprzętem (lub jądrem sterownika) w celu połączenia klatek wideo (7b) z najnowszą kompozycją (7a) do wyświetlania w odpowiednim momencie na podstawie dźwięku (7c).
Rysunek 2. Synchronizator sprzętu HWC (lub jądra lub sterownika)