Trazendo experiências ricas para dispositivos de TV com restrição de memória

Blog da Tecnologia Netflix em Netflix TechBlog Segue 2 de jul · 13 min ler

Por Jason Munning, Archana Kumar, Kris Range

A Netflix tem mais de 148 milhões de membros pagos transmitindo mais de meio bilhão de dispositivos, abrangendo mais de 1.900 diferentes tipos. Somente no espaço da TV, existem centenas de tipos de dispositivos que executam o aplicativo Netflix. Precisamos dar suporte à mesma rica experiência da Netflix não apenas em dispositivos de ponta, como o PS4, mas também em dispositivos eletrônicos de consumo restritos à memória e ao processador que executam um chipset semelhante ao usado em um iPhone 3G.

Em um post anterior , descrevemos como nosso aplicativo de TV consiste em um SDK de C ++ instalado nativamente no dispositivo, uma camada de interface de usuário JavaScript (IU) atualizável e uma camada de renderização personalizada conhecida como Gibbon. Fornecemos a mesma interface para milhares de dispositivos diferentes para oferecer uma experiência de usuário consistente. Como engenheiros de interface do usuário, estamos empolgados em fornecer experiências criativas e envolventes que ajudem os membros a escolher o conteúdo que eles adoram, por isso estamos sempre tentando superar os limites de nossa interface do usuário.

Neste post, discutiremos o desenvolvimento da linha Rich Collection e as iterações pelas quais passamos para dar suporte a essa experiência na maior parte do ecossistema de TV.

Linha Rich Collection

Um dos nossos projetos de interface do usuário mais ambiciosos até o momento no aplicativo de TV é o Rich Collection Row animado. O objetivo dessa experiência a partir de uma perspectiva de design UX foi reunir um conjunto estreitamente relacionado de títulos originais que, embora entidades distintas por si só, também compartilham um universo conectado. Nossa hipótese é que esse design teria um impacto visual muito maior do que se os títulos fossem distribuídos individualmente ao longo da página. Queríamos que a experiência se sentisse menos como percorrer uma fileira e mais como explorar um mundo conectado de histórias.

Para as coleções abaixo, a linha é composta de caracteres representando cada título em um universo coletado sobreposto a uma imagem de plano de fundo compartilhada e com sangramento total que representa o tema compartilhado para a coleção. Quando o usuário rola pela primeira vez até a linha, os caracteres são agrupados em uma linha de quatro. O nome da coleção anima junto com os logotipos de cada título, enquanto um clipe de som é reproduzido, evocando o clima do mundo compartilhado. Os caracteres deslizam para fora da tela para indicar que o primeiro título está selecionado. Conforme o usuário rola horizontalmente, os caracteres deslizam pela tela e o pano de fundo compartilhado rola com um efeito de paralaxe. Para algumas das coleções, as próprias imagens dos personagens são animadas e uma tonalidade de tela cheia é aplicada usando uma cor que é representativa do criativo do programa (veja “Imagens de Personagem” abaixo).

Quando o usuário faz uma pausa em um título por mais de dois segundos, o trailer desse título se desvanece com a imagem de fundo e começa a ser reproduzido.

Desenvolvimento

Como parte do desenvolvimento desse tipo de experiência de interface do usuário em qualquer plataforma, sabíamos que precisaríamos pensar em criar animações uniformes e de alto desempenho, com equilíbrio entre qualidade e tamanho de download das imagens e visualizações de vídeo, sem degradar o desempenho do aplicativo. Algumas das métricas que usamos para medir o desempenho no aplicativo de TV da Netflix incluem quadros de animação por segundo (FPS), capacidade de resposta de entrada (a quantidade de tempo antes que uma tecla de um membro processa uma alteração na interface), velocidade de reprodução de vídeo e aplicativo tempo de inicialização.

Os desenvolvedores de interface do usuário no aplicativo de TV da Netflix também precisam considerar alguns desafios que os desenvolvedores em outras plataformas geralmente aceitam. Uma dessas áreas é o nosso gerenciamento de memória gráfica. Embora os navegadores da web e os telefones celulares tenham gigabytes de memória disponíveis para gráficos, nossos dispositivos são restritos a meros MBs. Nossa interface do usuário é executada sobre um mecanismo de renderização personalizado que usa o que chamamos de "cache de superfície" para otimizar nosso uso da memória gráfica.

Cache de Superfície

O cache de superfície é um conjunto reservado na memória principal (ou memória gráfica separada em uma minoria de sistemas) que o aplicativo Netflix usa para armazenar texturas (imagens decodificadas e recursos em cache). Isso beneficia o desempenho, pois esses recursos não precisam ser decodificados em cada quadro, economizando tempo de CPU e proporcionando uma taxa de quadros maior para animações.

Cada dispositivo que executa o aplicativo de TV Netflix tem um pool de cache de superfície limitado disponível para que o mecanismo de renderização tente maximizar o uso do cache o máximo possível. Isso é positivo para a experiência final, porque significa que mais texturas estão prontas para reutilização enquanto um cliente navega pelo aplicativo.

A quantidade de espaço que uma textura requer no cache de superfície é calculada como:

largura * altura * 4 bytes / pixel (para rgba)

A maioria dos dispositivos atualmente executa uma interface do usuário Netflix de 1280 x 720. Uma imagem de tela inteira nesta resolução usará 1280 * 720 * 4 = 3,5 MB de cache de superfície. A maioria dos dispositivos legados é executada em 28 MB de cache de superfície. Nesse tamanho, você pode ajustar o equivalente a 8 imagens de tela inteira no cache. A reserva dessa quantidade de memória nos permite usar efeitos de transição entre telas, efeitos de paralelismo / paralaxe e pré-renderizar imagens para títulos que estão fora da janela de visualização para permitir a rolagem em qualquer direção sem imagens. Dispositivos no ecossistema Netflix TVUI Temos uma gama de capacidade de cache de superfície, de 20MB a 96MB e somos capazes de ativar / desativar recursos avançados com base nessa capacidade.

Quando o limite desse pool de memória é aproximado ou excedido, o aplicativo de TV Netflix tenta liberar espaço com recursos que ele acredita que pode eliminar (ou seja, imagens que não estão mais na viewport). Se o cache estiver acima do orçamento com superfícies que não podem ser eliminadas, os dispositivos poderão se comportar de maneiras imprevisíveis, desde falhas no aplicativo, exibição de lixo na tela ou redução drástica das animações.

Cache de superfície e a linha Rich Collection

A partir do desenvolvimento de recursos avançados de interface do usuário, sabíamos que o uso do cache de superfície era algo a considerar com o design de imagem pesada para a linha Rich Collection. Certificámo-nos de que testamos a utilização da memória desde o início durante o teste manual e não detectámos quaisquer excedentes, pelo que verificámos essa caixa e prosseguimos com o desenvolvimento. Quando nos aproximamos do código completo e nos preparamos para distribuir essa experiência para todos os usuários, executamos nosso novo código em relação ao nosso conjunto de automação de uso de memória como uma verificação de integridade.

O gráfico abaixo mostra um teste automatizado de ponta a ponta que navega no aplicativo Netflix, acionando reproduções, pesquisas, etc. para simular uma sessão de usuário. Nesse caso, o teste estava medindo o cache de superfície após cada etapa. A linha vermelha mostra uma execução de teste com a linha Rich Collection e a linha amarela mostra uma execução sem. A linha vermelha pontilhada é colocada em 28MB, que é a quantidade de memória reservada para o cache de superfície no dispositivo de teste.

Execução de automação mostrando o tamanho do cache de superfície em comparação com a etapa de teste

Uh oh! Encontramos alguns picos massivos (marcados em vermelho) no cache de superfície que excederam o uso máximo de cache de superfície recomendado de 28MB e indicaram que tivemos um problema. Exceder o limite de cache de superfície pode ter uma variedade de impactos (dependendo da implementação do dispositivo) para o usuário, desde imagens ausentes até falhas de memória insuficiente. Hora de colocar os freios no lançamento e depuração!

Avaliando o problema

O primeiro passo para avaliar o problema foi detalhar os resultados de automação para garantir que eles fossem válidos. Nós reexecutamos os testes de automação e descobrimos que os resultados eram reproduzíveis. Poderíamos ver os picos ocorrendo na tela inicial, onde a linha Rich Collection estava sendo exibida. Era estranho que não tivéssemos visto os erros do cache de superfície acima do orçamento (SCOB) durante o teste manual.

Para fechar a lacuna, demos uma olhada nas configurações que estávamos usando em nossa automação e as ajustamos para corresponder às configurações que usamos na produção para dispositivos reais. Em seguida, voltamos a executar a automação e ainda vimos os picos, mas no processo descobrimos que o problema parecia se apresentar apenas em dispositivos que executam uma versão do nosso SDK a partir de 2015. O teste manual não detectou porque só tínhamos sido teste manualmente o cache de superfície em versões mais recentes do SDK. Depois que fizemos o teste manual em nossa versão mais antiga do SDK, conseguimos reproduzir o problema em nosso ambiente de desenvolvimento.

Um exemplo de saída do console mostrando o cache de superfície sobre erros de orçamento

Durante o brainstorming com nossa equipe de plataformas, nos deparamos com um relatório de bug interno de 2017 que descrevia um problema semelhante ao que víamos: superfícies que foram marcadas como purgeable no cache de superfície não estavam sendo totalmente eliminadas nessa versão anterior de nosso SDK. A partir do ticket, poderíamos ver que a ineficiência foi corrigida na próxima versão do nosso SDK, mas como nem todos os dispositivos recebem atualizações do SDK da Netflix, a correção não pôde ser transferida para a versão 2015 que tinha esse problema. Considerando que uma parte significativa de nossos dispositivos de TV ativamente usados estão executando essa versão de 2015 e não serão atualizados para um SDK mais recente, sabíamos que precisávamos encontrar uma correção que funcionasse para essa versão específica – uma situação semelhante à anterior. -2000 mundo antes de navegadores atualizados automaticamente e os desenvolvedores tinham que codificar para versões específicas do navegador.

Encontrando uma Solução

O primeiro passo foi dar uma olhada em quais texturas estavam no cache de superfície (especialmente aquelas marcadas como não expurgáveis) no momento do excesso e ver onde poderíamos obter ganhos reduzindo o tamanho das imagens. Para isso, temos uma porta de depuração que nos permite inspecionar quais imagens estão no cache. Isso nos mostra informações sobre as imagens no cache de superfície, incluindo url. Os links podem ser exibidos para mostrar uma pequena miniatura da imagem.

A partir de instantâneos como este, pudemos ver que apenas a linha Rich Collection preencheu cerca de 15,3 MB de cache de superfície, que é> 50% da memória gráfica total de 28 MB disponível em dispositivos que executam o SDK de 2015.

As maiores imagens não-purgantes que encontramos foram:

  • Imagens de personagens (6 * 1MB)
  • Imagens de fundo para o fundo paralaxe (2 * 2,9MB)
  • Desconhecido – um retângulo branco em branco de tela inteira (3,5 MB)

Imagens de Personagem

Algumas de nossas ricas coleções apresentavam o uso de recursos de personagens animados para proporcionar uma experiência ainda mais rica. Criamos esses ativos usando um formato de animação proprietário da Netflix chamado de Scriptable Network Graphic (SNG), que foi suportado pela primeira vez em 2017 e é semelhante a um PNG animado. Os arquivos SNG têm um tamanho de download relativamente grande de ~ 1,5 MB cada. Para garantir que esses recursos estejam disponíveis no momento em que a linha rich collection entrar na viewport, pré-carregamos os SNGs durante a inicialização do aplicativo e os salvamos no disco. Se o usuário relança o aplicativo no futuro e recebe a mesma linha de coleta, os arquivos SNG podem ser lidos do cache de disco, evitando a necessidade de baixá-los novamente. Dispositivos que executam uma versão mais antiga do fallback do SDK para uma imagem de caractere estática.

Fileira da Marvel Collection com imagens de personagens animados

Na época do excedente, descobrimos que imagens de seis caracteres estavam presentes no cache – quatro na tela e duas pré-carregadas na tela. Nossa primeira economia veio apenas do pré-carregamento de uma imagem para um total de cinco caracteres no cache. Logo de cara, isso nos salvou quase 7% no cache de superfície, sem impacto observável na experiência.

Em seguida, criamos versões cortadas das imagens de caracteres estáticos que eliminaram os pixels transparentes extras (que ainda contam para o uso do cache de superfície!). Isso exigia modificações no pipeline de imagem para aparar o espaço em branco, mas ainda manter o tamanho relativo dos caracteres – portanto, as alturas relativas dos caracteres na programação ainda seriam preservadas. Os recursos de caracteres cortados usavam apenas metade da memória cache de superfície das imagens em tamanho normal e, novamente, não tinham impacto visível na experiência.

Imagem de personagem cortada em tamanho real

Fundo de paralaxe

Para obter a ilusão de um plano de fundo de paralaxe com rolagem contínua, estávamos usando duas imagens de plano de fundo em tela cheia, colocadas lado a lado, que juntas representavam ~ 38% do uso do cache de superfície da experiência. Trabalhamos com design para criar uma nova imagem de fundo em tela cheia que poderia ser usada para uma experiência de fallback (sem paralaxe) em dispositivos que não podiam suportar o carregamento de ambas as imagens de fundo para o efeito paralaxe. Usando apenas uma imagem de fundo, economizamos 19% em cache de superfície para a experiência de fallback.

Widget desconhecido

Após a tentativa e erro de remover os componentes React da nossa compilação local e inspecionar o cache de superfície, descobrimos que o widget desconhecido exibido como retângulo branco em branco em tela cheia em nossa ferramenta de depuração foi adicionado pelo efeito de matiz em tela cheia que estávamos usando. Para aplicar a tonalidade, a camada de gráficos cria essencialmente uma textura de tela cheia que é colorida dinamicamente e sobreposta à janela de visualização visível. Remover a sobreposição de matiz nos salvou 23% no cache de superfície.

Remover a sobreposição de tonalidade e usar uma única imagem de plano de fundo nos deu uma experiência de recuo que usou 42% menos cache de superfície do que a experiência completa.

Experiência de fallback de fileira da Marvel Collection com caracteres estáticos, sem matiz de tela cheia e plano de fundo único

Quando tudo foi dito e feito, o uso de cache de superfície da experiência de fallback (incluindo menos caracteres pré-carregados, imagens de personagens cortadas, um único plano de fundo e nenhuma sobreposição de tom) registrou cerca de 5MB, o que nos proporcionou uma economia total de quase 67% nossa implementação inicial.

Conseguimos segmentar essa experiência de fallback para dispositivos que executam o SDK de 2015 e mais antigo, enquanto ainda veiculamos a experiência completa (23% de uso de cache de superfície menor do que a implementação original) para dispositivos que executam os novos SDKs.

Sair da cama

Neste ponto, nossa automação estava passando, então começamos a lançar lentamente essa experiência para todos os membros. Como parte de qualquer implementação, temos um painel de métricas quase em tempo real que monitoramos. Para nossa decepção, vimos que outra classe de dispositivos – aqueles que executam o SDK de 2017 – também relatavam erros mais altos de SCOB do que o controle.

Número total de erros do SCOB em relação ao tempo

Graças ao nosso trabalho sobre a experiência de fallback, fomos capazes de mudar a configuração para esta classe de dispositivos rapidamente para servir a experiência de fallback (sem fundo e matiz de paralaxe). Descobrimos que se usássemos a experiência de fallback, poderíamos continuar usando os personagens animados. Então, outro sabor da experiência nasceu.

Melhorias e Takeaways

Na Netflix, nos esforçamos para avançar rapidamente na inovação e aprender com todos os projetos, sejam eles sucessos ou fracassos. A partir desse projeto, aprendemos que havia lacunas em nossa compreensão de como nossa memória gráfica subjacente funcionava e no ferramental que usamos para monitorar essa memória. Iniciamos um esforço para entender esse espaço de memória gráfica em um nível baixo e compilamos um conjunto de práticas recomendadas para desenvolvedores que estão começando a trabalhar em um projeto. Também documentamos um conjunto de dicas e ferramentas para depuração e otimização de cache de superfície em caso de problemas.

Como parte desse esforço, expandimos nosso conjunto de testes automatizados de construção sobreposta para aumentar a cobertura em nossas diferentes versões do SDK em dispositivos reais e de referência para detectar picos / regressões no uso do cache de superfície.

Uso do cache de superfície por compilação

Começamos a registrar os erros do SCOB com mais detalhes na produção, para que possamos segmentar as áreas específicas do aplicativo que precisamos otimizar. Também estamos apresentando novos erros de cache de superfície como notificações no ambiente de desenvolvimento, para que os desenvolvedores possam detectá-los mais rapidamente.

E aprimoramos nossa ferramenta inspetor de cache de superfície para ser mais amigável e integrar com nosso depurador do Chrome DevTools:

Nova ferramenta interna para depuração de cache de superfície

Conclusão

Como engenheiros de interface do usuário na plataforma TVUI da Netflix, temos o desafio de fornecer experiências de interface do usuário ambiciosas para um ecossistema altamente fragmentado de dispositivos com uma ampla variedade de características de desempenho. É importante alcançarmos o maior número possível de dispositivos para oferecer aos nossos membros a melhor experiência possível.

As soluções que desenvolvemos ao escalar a linha Rich Collection ajudaram a informar como abordaremos os ambiciosos projetos de interface do usuário daqui para frente. Com nossas otimizações e experiências de fallback, conseguimos quase dobrar o número de dispositivos que conseguiram obter a linha Rich Collection.

Agora, estamos mais preocupados em projetar experiências de fallback que se degradam normalmente como parte da fase inicial do projeto, em vez de apenas como uma reação aos problemas que encontramos na fase de desenvolvimento. Isso nos coloca em uma posição de poder escalar uma experiência muito rapidamente com um conjunto de botões e alavancas que podem ser usados para ajustar uma experiência para uma classe específica de dispositivos.

Mais importante, recebemos comentários de que nossos membros aproveitaram nossa experiência em linha do Rich Collection – tanto as experiências completas quanto as de fallback – quando os lançamos globalmente no final de 2018.

Se isso lhe interessar e quiser ajudar a construir as futuras interfaces do usuário para descobrir e assistir a shows e filmes, junte-se à nossa equipe !

Texto original em inglês.