how can i show iframe from m3u8, when user hover the player’s timeline

i was able to open m3u8 format using hls.js, but i have problem, i need to show preview images from m3u8 when user hover the timeline, how to do this, thanks in advance for your answers)

 <div
          className="timeline-container"
          onMouseMove={handleTimeLineUpdate}
          onMouseDown={toggleScrubbing}
          ref={timelineContainer}
        >
          <div className="timeline">
            <img className="preview-img" ref={previewImgRef} alt="previewImg" />
            <div className="thumb-indicator"></div>
          </div>
        </div>

there is my functions for getting iframe from m3u8:

const getIframePlaylistUrlsFromM3U8 = async () => {
    try {
      const response = await fetch(movie.transcode_file);
      const m3u8Content = await response.text();

     
      const iframePlaylistUrls = extractIframePlaylistUrls(m3u8Content);

 
      return iframePlaylistUrls;
    } catch (error) {
      console.error("Error fetching or parsing M3U8 file", error);
      return [];
    }
  };

there i have problem, when i log iframePlaylistUrls it has values, but when another function receives it it shows empty

  const extractIframePlaylistUrls = (m3u8Content) => {
    const iframePlaylistUrls = parseM3U8(m3u8Content);
    return iframePlaylistUrls;
  };

  const parseM3U8 = (m3u8Content) => {
    const regex = /EXT-X-I-FRAME-STREAM-INF:.*URI="(.+)"/g;
    const matches = m3u8Content.matchAll(regex);
    return Array.from(matches, (match) => match[1]);
  };
  const updatePreviewImageOnHover = async (e) => {
    const rect = timelineContainer.current.getBoundingClientRect();
    const percent =
      Math.min(Math.max(0, e.clientX - rect.x), rect.width) / rect.width;

    const iframePlaylistUrls = await getIframePlaylistUrlsFromM3U8();
   
    const iframeIndex = Math.max(
      0,
      Math.floor(percent * iframePlaylistUrls.length)
    );
   
    const thumbnailImageUrl = await extractThumbnailImageUrl(
      iframePlaylistUrls[iframeIndex]
    );
    previewImgRef.current.src = thumbnailImageUrl;
   
  };
  const extractThumbnailImageUrl = async (iframePlaylistUrl) => {
    try {
      const response = await fetch(iframePlaylistUrl);
      const iframePlaylistContent = await response.text();

      const thumbnailImageUrl = parseIframePlaylist(iframePlaylistContent);

      return thumbnailImageUrl;
    } catch (error) {
      console.error("Error fetching or parsing iframe playlist", error);
      return "";
    }
  };
  const parseIframePlaylist = (iframePlaylistContent) => {
    const thumbnailImageUrl = parseIframePlaylistUrl(iframePlaylistContent);
    return thumbnailImageUrl;
  };
  const parseIframePlaylistUrl = (iframePlaylistContent) => {
    const regex = /#EXT-X-IMAGE:(.+)/;
    const match = iframePlaylistContent.match(regex);
    return match ? match[1] : "";
  };

when i hover timeline this function runs

  const handleTimeLineUpdate = (e) => {
    const rect = timelineContainer.current.getBoundingClientRect();
    const percent =
      Math.min(Math.max(0, e.clientX - rect.x), rect.width) / rect.width;


    updatePreviewImageOnHover(e);

    timelineContainer.current.style.setProperty("--preview-position", percent);

    if (isScrubbing.current) {
      e.preventDefault();
      // thumbnailImgRef.current.src = previewImgSrc;
      timelineContainer.current.style.setProperty(
        "--progress-position",
        percent
      );
    }
  };

  • I’m not sure you can, or whether this is a good idea. I think all video scrubbers out there don’t actually get frames from the video element, but from a spritesheet generated on the server. This is because it would mean you need to download the entire video before you can even display them anyway, in which case you might as well just display the frame as you scrub, but that’s slow. I think it’s probably even less possible with a streaming format like HLS, which doesn’t ever really know about the “entire” video.

    – 

Leave a Comment