Novidades sobre produtos

Media3 1.9.0: novidades

Leitura de 6 minutos
Acessar o perfil de Kristina Simakova
Kristina Simakova Gerente de engenharia

O Media3 1.9.0 já está disponível. Além das correções de bugs e melhorias de desempenho usuais, a versão mais recente também contém quatro módulos novos ou amplamente reescritos:

  • media3-inspector - extrai metadados e frames fora da reprodução
  • media3-ui-compose-material3: cria uma interface de mídia básica do Material3 Compose em apenas algumas etapas
  • media3-cast - processa automaticamente as transições entre transmissões e reproduções locais
  • media3-decoder-av1 - reprodução consistente de AV1 com o decodificador de extensão reescrito com base na biblioteca dav1d

Também adicionamos melhorias de armazenamento em cache e gerenciamento de memória ao PreloadManager e oferecemos várias novas simplificações de ExoPlayer, Transformer e MediaSession

Essa versão também oferece o primeiro acesso experimental ao CompositionPlayer para visualizar edições de mídia.  


Continue lendo para saber mais e, como sempre, confira as notas de versão completas para uma visão geral abrangente das mudanças nessa versão.

Extrair metadados e frames fora da reprodução

Há muitos casos em que você quer inspecionar a mídia sem iniciar uma reprodução. Por exemplo, talvez você queira detectar quais formatos ela contém ou qual é a duração ou recuperar miniaturas.

O novo módulo media3-inspector combina todos os utilitários para inspecionar a mídia sem reprodução em um só lugar:

  • MetadataRetriever para ler a duração, o formato e os metadados estáticos de um MediaItem.
  • FrameExtractor para receber frames ou miniaturas de um item.
  • MediaExtractorCompat como uma substituição direta da classe MediaExtractor da plataforma Android para receber informações detalhadas sobre amostras no arquivo.

MetadataRetriever e FrameExtractor seguem um padrão AutoCloseable simples. Confira nossas novas páginas de guia para mais detalhes.

suspend fun extractThumbnail(mediaItem: MediaItem) {

  FrameExtractor.Builder(context, mediaItem).build().use {

    val thumbnail = frameExtractor.getThumbnail().await()

  } 

}

Criar uma interface de mídia básica do Material3 Compose em apenas algumas etapas

Em versões anteriores, começamos a fornecer código de conector entre os elementos da interface do Compose e a instância do player. Com o Media3 1.9.0, adicionamos um novo módulo media3-ui-compose-material3 com botões e elementos de conteúdo do Material3 totalmente estilizados. Eles permitem criar uma interface de mídia em apenas algumas etapas, oferecendo toda a flexibilidade para personalizar o estilo. Se você preferir criar seu próprio estilo de interface, use os blocos de construção que cuidam de toda a lógica de atualização e conexão. Assim, você só precisa se concentrar no design do elemento da interface. Confira nossas páginas de guia estendidas para os módulos de interface do Compose.

Também estamos trabalhando em ainda mais componentes do Compose, como uma barra de busca pré-criada, uma substituição completa e pronta para uso do PlayerView, além de integração de legendas e anúncios.

@Composable
fun SimplePlayerUI(player: Player, modifier: Modifier = Modifier) {
  Column(modifier) {
    ContentFrame(player)  // Video surface and shutter logic
    Row (Modifier.align(Alignment.CenterHorizontally)) {                 
      SeekBackButton(player)   // Simple controls
      PlayPauseButton(player)
      SeekForwardButton(player)
    }
  }
}

 

image.png

Interface simples do player do Compose com elementos prontos para uso

Processar automaticamente as transições entre transmissões e reproduções locais

O CastPlayer no módulo media3-cast foi reescrito para processar automaticamente as transições entre a reprodução local (por exemplo, com ExoPlayer) e a reprodução remota de transmissão.

Ao configurar a MediaSession, basta criar um CastPlayer em torno do ExoPlayer e adicionar um MediaRouteButton à interface. Pronto!

// MediaSession setup with CastPlayer 

val exoPlayer = ExoPlayer.Builder(context).build()

val castPlayer = CastPlayer.Builder(context).setLocalPlayer(exoPlayer).build()

val session = MediaSession.Builder(context, castPlayer).build()

// MediaRouteButton in UI 

@Composable fun UIWithMediaRouteButton() {

  MediaRouteButton()

}
image.png

Nova integração do CastPlayer no app de demonstração da sessão do Media3

Reprodução consistente de AV1 com a extensão reescrita com base em dav1d

A versão 1.9.0 contém um módulo de extensão AV1 completamente reescrito com base na biblioteca dav1d popular. 

Como acontece com todos os módulos de decodificador de extensão, observe que ele exige a criação da origem para agrupar o código nativo relevante corretamente.  O agrupamento de um decodificador oferece consistência e suporte a formatos em todos os dispositivos, mas, como ele executa a decodificação no seu processo, é mais adequado para conteúdo confiável. 

Integrar o armazenamento em cache e o gerenciamento de memória ao PreloadManager

Também melhoramos o PreloadManager. Ele já permitia pré-carregar a mídia na memória fora da reprodução e, em seguida, entregá-la a um player quando necessário. Embora seja bastante eficiente, ainda era preciso ter cuidado para não exceder os limites de memória pré-carregando muito conteúdo por engano. Por isso, com o Media3 1.9.0, adicionamos dois recursos que tornam isso muito mais fácil e estável:

  1. Suporte ao armazenamento em cache : ao definir até onde pré-carregar, agora é possível escolher PreloadStatus.specifiedRangeCached(0, 5000) como um estado de destino para itens pré-carregados. Isso vai adicionar o intervalo especificado ao cache no disco em vez de carregar os dados na memória. Com isso, é possível fornecer um intervalo muito maior de itens para pré-carregamento, já que os itens mais distantes do atual não precisam mais ocupar memória. Isso exige a definição de um Cache em DefaultPreloadManager.Builder.
  2. Gerenciamento automático de memória : também atualizamos nossa interface LoadControl para processar melhor o caso de pré-carregamento. Agora é possível definir um limite máximo de memória explícito para todos os itens pré-carregados na memória. Ele é de 144 MB por padrão, e você pode configurar o limite em DefaultLoadControl.Builder. O DefaultPreloadManager vai interromper automaticamente o pré-carregamento quando o limite for atingido e liberar automaticamente a memória de itens de menor prioridade, se necessário.

Confiar em novos comportamentos padrão simplificados no ExoPlayer

Como sempre, também adicionamos muitas melhorias incrementais ao ExoPlayer. Para citar alguns exemplos:

  • Ativar e desativar o som : já tínhamos um método setVolume, mas agora adicionamos os métodos convenientes mute e unmute para restaurar facilmente o volume anterior sem precisar rastreá-lo.
  • Detecção de player travado : em alguns casos raros, o player pode ficar travado em um estado de buffer ou reprodução sem fazer nenhum progresso, por exemplo, devido a problemas de codec ou configurações incorretas. Seus usuários vão ficar irritados, mas você nunca verá esses problemas nas suas análises. Para tornar isso mais óbvio, o player agora informa uma StuckPlayerException quando detecta um estado travado.
  • Wakelock por padrão : o gerenciamento de wake lock era opcional, resultando em casos extremos difíceis de encontrar em que o progresso da reprodução pode ser muito atrasado ao ser executado em segundo plano. Agora, esse recurso é desativado por padrão. Assim, você não precisa se preocupar com ele e também pode remover todo o processamento manual de wake lock em torno da reprodução.
  • Configuração simplificada para a lógica do botão CC : mudar TrackSelectionParameters para dizer "ativar/desativar legendas" era surpreendentemente difícil de fazer corretamente. Por isso, adicionamos uma opção booleana simples selectTextByDefault para esse caso de uso.

Simplificar as preferências de botões de mídia na MediaSession

Até agora, definir suas preferências para quais botões deveriam aparecer na gaveta de notificações de mídia no Android Auto ou WearOS exigia a definição de comandos e botões personalizados, mesmo que você simplesmente quisesse acionar um método de player padrão.

O Media3 1.9.0 tem uma nova funcionalidade para simplificar muito isso. Agora é possível definir as preferências de botões de mídia com um comando de player padrão, sem exigir o processamento de comandos personalizados.

session.setMediaButtonPreferences(listOf(
    CommandButton.Builder(CommandButton.ICON_FAST_FORWARD) // choose an icon
      .setDisplayName(R.string.skip_forward)
      .setPlayerCommand(Player.COMMAND_SEEK_FORWARD) // choose an action 
      .build()
))
image.png

Preferências de botões de mídia com botão de avanço rápido

CompositionPlayer para visualização em tempo real

A versão 1.9.0 apresenta o CompositionPlayer em uma nova anotação @ExperimentalApi. A anotação indica que ela está disponível para testes, mas ainda está em desenvolvimento. 

CompositionPlayer é um novo componente nas APIs de edição do Media3 projetado para visualização em tempo real de edições de mídia. Criado na interface familiar do Media3 PlayerCompositionPlayer permite que os usuários vejam as mudanças em ação antes de confirmar o processo de exportação. Ele usa o mesmo objeto Composition que você transmitiria para Transformer para exportação, simplificando o fluxo de trabalho de edição ao unificar o modelo de dados para visualização e exportação.

Recomendamos que você comece a usar o CompositionPlayer e compartilhe seu feedback. Fique atento aos próximos posts e atualizações da documentação para mais detalhes.

InAppMuxer como um muxer padrão no Transformer

O Transformer agora usa InAppMp4Muxer como o muxer padrão para gravar arquivos de contêiner de mídia. Internamente, InAppMp4Muxer depende do módulo Muxer do Media3, fornecendo um comportamento consistente em todas as versões da API. 

Embora o Transformer não use mais o MediaMuxer da plataforma Android por padrão, ainda é possível fornecer FrameworkMuxer.Factory via setMuxerFactory se o caso de uso exigir.

Novas APIs de ajuste de velocidade

A versão 1.9.0 simplifica as APIs de ajuste de velocidade para edição de mídia. Introduzimos novos métodos diretamente no EditedMediaItem.Builder para controlar a velocidade, tornando a API mais intuitiva. Agora é possível mudar a velocidade de um clipe chamando setSpeed(SpeedProvider provider) no EditedMediaItem.Builder:

val speedProvider = object : SpeedProvider {
    override fun getSpeed(presentationTimeUs: Long): Float {
        return speed
    }

    override fun getNextSpeedChangeTimeUs(timeUs: Long): Long {
        return C.TIME_UNSET
    }
}

EditedMediaItem speedEffectItem = EditedMediaItem.Builder(mediaItem)
    .setSpeed(speedProvider)
    .build()

Essa nova abordagem substitui o método anterior de uso de Effects#createExperimentalSpeedChangingEffects(), que foi descontinuado e será removido em uma versão futura.

Introdução de tipos de faixa para EditedMediaItemSequence

Na versão 1.9.0, EditedMediaItemSequence exige a especificação dos tipos de faixa de saída desejados durante a criação da sequência. Essa mudança garante que o processamento de faixas seja mais explícito e robusto em toda a composição. 

Isso é feito por um novo EditedMediaItemSequence.Builder construtor que aceita um conjunto de tipos de faixa (por exemplo, C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO).

Para simplificar a criação, adicionamos novos métodos de conveniência estáticos:

  • EditedMediaItemSequence.withAudioFrom(List<EditedMediaItem>)
  • EditedMediaItemSequence.withVideoFrom(List<EditedMediaItem>)
  • EditedMediaItemSequence.withAudioAndVideoFrom(List<EditedMediaItem>)

Recomendamos migrar para o novo construtor ou para os métodos de conveniência para definições de sequência mais claras e confiáveis.

Exemplo de criação de uma sequência somente de vídeo:

EditedMediaItemSequence videoOnlySequence =
    EditedMediaItemSequence.Builder(setOf(C.TRACK_TYPE_VIDEO))
        .addItem(editedMediaItem)
        .build()

Entre em contato pelo Issue Tracker do Media3 se encontrar bugs ou tiver dúvidas ou solicitações de recursos. Esperamos você!

Escrito por:
Continuar lendo