Streamlit videos play automatically (as slideshow) one after the other

Continuing from the discussion from Automatic slideshow

Summary

I’ve about 5 short videos (60 seconds each) and I’m using the code from TomJohn using streamlit.components.v1 . The code shown in the example absolutely works work.
However, I want to play the short videos like in a slideshow shown in the above above link for images.
All the 6 videos exist in my local project folder path.
From the above shown code for “image” I’ve substituted with “video” tags.
The problem is video is not loading.
Note: There is no problem with the mp4 video files. i’m able to individually play the video files.

Steps to reproduce

Code snippet:

import streamlit as st
import streamlit.components.v1 as components

components.html(
    """
        <!DOCTYPE html>
        <html>
        <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
        * {box-sizing: border-box;}
        body {font-family: Verdana, sans-serif;}
        .mySlides {display: none;}
        img {vertical-align: middle;}
        
        /* Slideshow container */
        .slideshow-container {
          max-width: 1000px;
          position: relative;
          margin: auto;
        }
        
        /* Caption text */
        .text {
          color: #f2f2f2;
          font-size: 15px;
          padding: 8px 12px;
          position: absolute;
          bottom: 8px;
          width: 100%;
          text-align: center;
        }
        
        /* Number text (1/3 etc) */
        .numbertext {
          color: #f2f2f2;
          font-size: 12px;
          padding: 8px 12px;
          position: absolute;
          top: 0;
        }
        
        /* The dots/bullets/indicators */
        .dot {
          height: 15px;
          width: 15px;
          margin: 0 2px;
          background-color: #bbb;
          border-radius: 50%;
          display: inline-block;
          transition: background-color 0.6s ease;
        }
        
        .active {
          background-color: #717171;
        }
        
        /* Fading animation */
        .fade {
          animation-name: fade;
          animation-duration: 1.5s;
        }
        
        @keyframes fade {
          from {opacity: .4} 
          to {opacity: 1}
        }
        
        /* On smaller screens, decrease text size */
        @media only screen and (max-width: 300px) {
          .text {font-size: 11px}
        }
        </style>
        </head>
        <body>
        
        <h2>Automatic Slideshow</h2>
        <p>Change image every 45 seconds:</p>
        
        <div class="slideshow-container">
        
        <div class="mySlides fade">
          <div class="numbertext">1 / 5</div>
          <video  controls autoplay>
            <source src="../video/part_clip_1.mp4" type="video/mp4" />
          </video>
          <div class="text">Caption Text</div>
        </div>
        
        <div class="mySlides fade">
          <div class="numbertext">2 / 5</div>
          <video  controls autoplay>
            <source src="../video/part_clip_2.mp4" type="video/mp4" />
          </video>
          <div class="text">Caption Two</div>
        </div>
        
        <div class="mySlides fade">
          <div class="numbertext">3 / 5</div>
          <video  controls autoplay>
            <source src="../video/part_clip_3.mp4" type="video/mp4" />
          </video>
          <div class="text">Caption Three</div>
        </div>
        
        <div class="mySlides fade">
          <div class="numbertext">4 / 5</div>
          <video  controls autoplay>
            <source src="../video/part_clip_4.mp4" type="video/mp4" />
          </video>
          <div class="text">Caption Four</div>
        </div>
        
        <div class="mySlides fade">
          <div class="numbertext">5 / 5</div>
          <video  controls autoplay>
            <source src="../video/part_clip_5.mp4" type="video/mp4" />
          </video>
          <div class="text">Caption Five</div>
        </div>
      
        </div>
        <br>
        
        <div style="text-align:center">
          <span class="dot"></span> 
          <span class="dot"></span> 
          <span class="dot"></span> 
          <span class="dot"></span> 
          <span class="dot"></span> 
        </div>
        
        <script>
        let slideIndex = 0;
        showSlides();
        
        function showSlides() {
          let i;
          let slides = document.getElementsByClassName("mySlides");
          let dots = document.getElementsByClassName("dot");
          for (i = 0; i < slides.length; i++) {
            slides[i].style.display = "none";  
          }
          slideIndex++;
          if (slideIndex > slides.length) {slideIndex = 1}    
          for (i = 0; i < dots.length; i++) {
            dots[i].className = dots[i].className.replace(" active", "");
          }
          slides[slideIndex-1].style.display = "block";  
          dots[slideIndex-1].className += " active";
          setTimeout(showSlides, 45000); // Change image every 2 seconds
        }
        </script>
        
        </body>
        </html> 

    """,
    height=600,
)

Expected behavior:

I want to play the short videos like in a slideshow shown in the link for images.

Actual behavior:

Please see the screenshot attached. Blank video are showing. Videos are mp4 formatted.

Debug info

  • Streamlit version: Streamlit, version 1.27.2
  • Python version: Python 3.10.12
  • Using Conda? PipEnv? PyEnv? Pex?
  • OS version:Ubuntu 22.04.3 LTS
  • Browser version:

Requirements file

Using Conda? PipEnv? PyEnv? Pex? Share the contents of your requirements file here.
Not sure what a requirements file is? Check out this doc and add a requirements file to your app.

Links

Additional information

Other options I tried as below. However, with the below option I could not make it like a slideshow, as I describe above. Hence I resorted to the answer posted by TomJohn

video_file = open(f'../video//part_clip_1.mp4', 'rb')
 video_bytes = video_file.read()
 st.video(video_bytes)

Hi @MDS I am quite sure that the problem you are encountering happens becouse of the video path.

If you would make a html file:

   <div class="mySlides fade">
      <div class="numbertext">5 / 5</div>
    <video  controls autoplay>
      <source src="../video/part_clip_5.mp4" type="video/mp4" />
    </video>
    <div class="text">Caption Five</div>
  </div>

it will display as below:

5 / 5
Caption Five

Hi @TomJohn: Thank you for your reply. Yes, per your reply , I made a separate HTML file and opened the HTML file and the video played (though did not auto-play the first video, rest of the videos auto-played).
However, since I’m using streamlit.components.v1 and invoking from within components.html( , how to invoke a HTML file, as you mentioned in your reply. Appreciate your help.

Hi @MDS

Perhaps you can take a different approach and use the image carousel component from @jrieke called streamlit-image-select (see the links below). You can allow users to select an image of interest (where the image can be a screen capture of the video), then use the selected image name to dynamically display the via via the native st.video method.

Links:

Hope this helps!

1 Like

I am quite sure that solution to your problem is using static content serving: Static file serving - Streamlit Docs

You are trying to provide components.html with ‘…/video//part_clip_1.mp4’ path which does not point to your video from your browser perspective.

Thank you @dataprofessor and @TomJohn. Appreciate both your timely responses.
I was able to proceed with the Static file serving - Streamlit Docs. Using this , all the 5 videos are autoplaying one after the other.
One last step I’m stuck , though the videos autoplay, the videos are “muted”. How to automatically play them "unmuted " ( that is with sound).
Please note, now my video tag looks like this:

<video  controls muted autoplay>
      <source src="./app/static//video/part_clip_1.mp4" type="video/mp4" />
</video>