Почему в Google Chrome возникают проблемы с воспроизведением HLS (HTTP Live Streaming)?

Пытаюсь запустить трансляцию .m3u8 в браузерном плеере с помощью библиотеки <b>hls.js</b>. <br/> В Firefox воспроизводится корректно, а в Chrome видео не стартует — бесконечная загрузка. <br/> <br/> <b>Источник потока</b> : <br/> Поток получаю из локального Ace Stream engine: <br/> <pre><code class="javascript">http://127.0.0.1:6878/ace/manifest.m3u8?content_id=...</code></pre> <br/> <br/> Внутри .m3u8 есть ссылки на .ts-сегменты вида: <br/> <pre><code class="javascript">http://127.0.0.1:6878/ace/c/.../0.ts
  • 20 марта 2026 г. 16:01
Ответы на вопрос 2
Коротко — это почти всегда не проблема hls.js как такового, а политика браузера / заголовки от Ace Stream. В Chrome стримы не стартуют обычно из‑за блокировки запросов (CORS / mixed content / отсутствие crossOrigin / и т.п.). Firefox в ряде случаев «проще» или ведёт себя иначе, поэтому там может работать.

Что проверить и как исправить

1) Откройте DevTools → Console / Network и посмотрите ошибки
- Если увидите что-то вроде
  - "Access to XMLHttpRequest at 'http://127.0.0.1:6878/...' from origin 'https://…' has been blocked by CORS policy" — проблема в CORS.
  - "Mixed Content: The page at 'https://…' was loaded over HTTPS, but requested an insecure resource 'http://127.0.0.1:6878/…'." — проблема смешанного контента (HTTPS-страница запрашивает HTTP).
  - Другие ошибки тоже важны (404, 500, long pending).

2) CORS (самая частая причина)
- hls.js делает XHR/fetch за плейлистами и сегментами, Chrome строго требует Access-Control-Allow-Origin на ответах сервера.
- Проверьте в Network для manifest.m3u8 и .ts: есть ли заголовок Access-Control-Allow-Origin: * или ваш origin.
- Решение:
  - Настройте Ace Stream / локальный сервер так, чтобы отдавал Access-Control-Allow-Origin: * (или ваш origin).
  - Если у вас нет возможности изменить Ace Stream — поставьте локальный прокси (nginx, node) который проксирует запросы к 127.0.0.1:6878 и добавляет CORS‑заголовки.
  - Тестово можно запустить Chrome с --disable-web-security (только для разработки, небезопасно).

3) Mixed content (HTTPS страница → HTTP локальный поток)
- Если страница у вас загружена по HTTPS, Chrome блокирует HTTP‑ресурсы.
- Решения:
  - Поднимаете локальный прокси/сервер с HTTPS (self-signed для локалки) и проксируете туда поток.
  - Или запустить страницу по HTTP (локально) при тестировании.

4) Убедитесь, что video.crossOrigin = 'anonymous'
- Перед подключением hls.js установите:
  video.crossOrigin = 'anonymous';
  Это необходимо, чтобы корретно работать с CORS и MSE в некоторых сценариях.

5) Кодеки / MSE поддержка
- Проверьте, что кодеки/формат в плейлисте поддерживаются Chrome (обычно H.264 + AAC в MPEG-TS поддерживаются).
- В консоли hls.js пишет детально — посмотрите, есть ли ошибки типа "no supported tracks" или "no supported codecs".

6) Диагностика, если всё ещё не работает
- Скопируйте URL .m3u8 и откройте в Postman/curl/браузере — посмотрите заголовки и тело.
- В DevTools Network проверьте статус .ts запросов: идут ли вообще, возвращается ли 200, висит ли в pending.
- Включите логирование hls.js (debug) — он подскажет на каком шаге висит.

Примеры быстрых обходов
- Прокси на Node (express) добавляющий CORS:
  const express = require('express');
  const { createProxyMiddleware } = require('http-proxy-middleware');
  const app = express();
  app.use('/ace', createProxyMiddleware({ target: 'http://127.0.0.1:6878', changeOrigin: true, onProxyRes: (proxyRes) => { proxyRes.headers['Access-Control-Allow-Origin'] = '*'; }}));
  app.listen(3000);

- nginx конфиг:
  location /ace/ {
    proxy_pass http://127.0.0.1:6878/ace/;
    add_header 'Access-Control-Allow-Origin' '*';
  }

Итог
Скорее всего Chrome блокирует запросы к локальному Ace Stream из‑за CORS или mixed content. Проверьте консоль, добавьте Access-Control-Allow-Origin и выставьте video.crossOrigin='anonymous' или проксируйте поток через сервер с корректными заголовками — после этого hls.js должен нормально стартовать в Chrome.
а play() вызываешь? хромиум явно требует это делать! <br/> попробуй так <br/> <pre><code class="javascript">useEffect(() =&gt; {
  if (!url || !videoRef.current) return;

  let hls;

  if (Hls.isSupported()) {
    hls = new Hls({
      lowLatencyMode: false,
      enableWorker: false,
      maxBufferLength: 15,
    });

    hls.loadSource(url);
    hls.attachMedia(videoRef.current);

    hls.on(Hls.Events.MANIFEST_PARSED, () =&gt; {
      console.log('manifest parsed');
      videoRef.current.play().catch(console.error);
    });

    hls.on(Hls.Events.ERROR, (event, data) =&gt; {
      console.error("HLS error:", data);
      if (data.fatal) {
        hls.recoverMediaError();
      }
    });
  }

  return () =&gt; hls.destroy();
}, [url]);</code></pre>
Похожие вопросы