Se você chegou até aqui, já está familiarizado com a arquitetura orientada a eventos e o parser M3U8 que construímos anteriormente. Agora, vamos elevar o nível conectando o elemento <video>
ao nosso player HLS. Essa etapa é fundamental para transformar o código em um player funcional. Para acompanhar o projeto do início você pode ver a parte 1 e a parte 2 e o repositório.
Como vincular o elemento <video>
ao código
Vamos começar adicionando o método attachMedia
à classe Hls
. Ele será responsável por conectar o elemento <video>
ao nosso player. Confira o código:
export default class Hls {
// ...
attachMedia(media) {
this.trigger(Events.MEDIA_ATTACHING, { media });
}
}
Este método recebe o elemento <video>
e dispara um evento. Para que isso funcione, precisamos incluir o evento no arquivo events.js
:
export const Events = {
MEDIA_ATTACHING: 'hlsMediaAttaching',
// ...
};
Agora, basta capturar o elemento <video>
no DOM e utilizar o método attachMedia
no arquivo main.js
:
import Hls from './hls';
const video = document.querySelector('#video');
const videoSrc = '/video/index.m3u8';
const hls = new Hls();
hls.loadSource(videoSrc);
hls.attachMedia(video);
Com isso, nosso player já está vinculado ao elemento de vídeo. Mas o que acontece por trás dessa conexão? Vamos explorar na próxima etapa.
Criando a classe MSEMediaController
Para gerenciar a interação entre o player e o Media Source Extensions API (MSE), criamos a classe MSEMediaController
. Sua estrutura é similar à do PlaylistLoader
:
export default class MSEMediaController {
constructor(hls) {
this.hls = hls;
this.registerListeners();
}
registerListeners() {
this.hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
}
}
Esse código escuta o evento MEDIA_ATTACHING
e executa o método onMediaAttaching
. Antes de seguir, vamos criar o arquivo utils.js
com a função waitForEvent
. Ela será essencial para lidar com eventos de maneira assíncrona, como veremos a seguir.
export function waitForEvent(
target,
types,
signal
) {
types = Array.isArray(types) ? types : [types];
return new Promise((resolve, reject) => {
if (signal?.aborted) {
return reject(signal.reason);
}
const listener = (event) => {
for (const type of types) {
target.removeEventListener(type, listener);
}
signal?.removeEventListener("abort", abortListener);
resolve(event);
};
const abortListener = () => {
reject(signal.reason);
};
for (const type of types) {
target.addEventListener(type, listener, { once: true, signal });
}
signal?.addEventListener("abort", abortListener, { once: true });
});
}
O método onMediaAttaching
O método onMediaAttaching
é o coração da integração com o MSE. Ele instância a API e prepara o player para o streaming de mídia:
async onMediaAttaching(event, data) {
if (!data.media) return;
const media = data.media;
const mediaSource = new MediaSource();
media.src = URL.createObjectURL(mediaSource);
await waitForEvent(mediaSource, "sourceopen");
this.hls.trigger(Events.MEDIA_ATTACHED, { media, mediaSource });
}
O que esse código faz?
- Validação inicial: Verifica se
data.media
está presente. Caso contrário, interrompe a execução. - Criação do MediaSource: Instancia a API MSE e cria um novo
MediaSource
. - Vinculação ao elemento
<video>
: Associa oMediaSource
ao vídeo usando um Object URL. - Espera pelo evento
sourceopen
: Garante que oMediaSource
esteja pronto para receber dados. - Dispara o evento
MEDIA_ATTACHED
: Indica que a mídia foi anexada com sucesso, permitindo que outras partes do player continuem o processamento.
Conclusão
A API Media Source Extensions é o que permite ao navegador fazer streaming de vídeo adaptativo, fundamental para lidar com formatos como HLS. Essa etapa é o primeiro passo para tornar o player HLS dinâmico e pronto para exibir vídeos em diferentes condições de rede.
Fique ligado e acompanhe os próximos capítulos dessa jornada!