0

Minimal example (non-working) to play a video from a local file in a bokeh app is below. The app uses a Div object with an html <video> tag. The expected behavior would be to play the video in the app immediately. The non-working part is the reference to the local video file.

from bokeh.models import Div
from bokeh.io import curdoc


div = Div(text="""
    <video width="300px" height="150px" controls autoplay>
    <source src="movie.mp4" type="video/mp4"></video>
    """)

curdoc().add_root(div)

The app is so.py and video is movie.mp4, both in the same directory.

enter image description here

Running the app from the command line indicates a 404 error when looking for movie.mp4

enter image description here

Screenshot of the app in the browser indicates the video player did load just could not find the video.

enter image description here

Have also tried <source src="file:///C:/so/movie.mp4" type="video/mp4"> which references the full path of the video file, also non-working.

Russell Burdt
  • 2,391
  • 2
  • 19
  • 30

3 Answers3

2

I don't think auto-loading video files from a local directory at page opening is supported in Bokeh. You need to place the video on a web server and load it using HTTP protocol. As @Doug Sillars noted in his post you should replace your src="movie.mp4" with src="http://localhost:5006/so/sample.mp4" and eliminate the need for running external Mongoose web server. So you code would simply become like the code below (it's tested and it's working!) Run it with bokeh serve --show so

main.py

from bokeh.models import Div
from bokeh.io import curdoc


div = Div(text="""
    <video width="300px" height="150px" controls autoplay>
    <source src="http://localhost:5006/so/static/movie.mp4" type="video/mp4"></video>
    """)

curdoc().add_root(div)

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    {{ bokeh_css }}
    {{ bokeh_js }}
  </head>
  <body>
    {{ plot_div|indent(8) }}
    {{ plot_script|indent(8) }}
  </body>
</html>

directory structure:

so
   |
   +---main.py
   +---static
      +---movie.mp4
   +---templates
        +---index.html

Another option is to use FileInput widget and give user the possibility to select the file from the local file system like in this example below (tested on Bokeh v2.2.1):

from bokeh.plotting import show
from bokeh.models import Div, Column, FileInput, CustomJS

code = '''  const file = document.getElementsByTagName('input')[0].files[0]
            var URL = window.URL || window.webkitURL 
            var fileURL = URL.createObjectURL(file)
            var videoNode = document.querySelector('video')
            videoNode.src = fileURL '''

div = Div(text="""<video width="500px" height="250px" controls><source src="" type="video/mp4"></video>""")
fileinput = FileInput(accept=".mp4,.mpg,.mov", visible = True, width = 250, name = 'fileinput')  
fileinput.js_on_change('value', CustomJS(args={'fileinput': fileinput}, code = code))

show(Column(div, fileinput))
Tony
  • 7,767
  • 2
  • 22
  • 51
  • In my case the user would not need to select a video because the right video to play is known based on other selections in the app. In my case using a local webserver and referencing the local files using http protocol worked. – Russell Burdt Jun 03 '21 at 17:43
  • I am glad my answer helped – Tony Jun 04 '21 at 11:09
  • Thanks for the additional info. Got it working without the external mongoose webserver. Keys were to (1) deploy the app using a [Directory format](https://docs.bokeh.org/en/latest/docs/user_guide/server.html#directory-format), (2) create a 'static' folder and move videos there, and (3) update the source in the video tag. I did **not** need to create an index.html file as in your solution. – Russell Burdt Jun 04 '21 at 17:21
  • Yes, only `main.py` is required, the rest is optional. I included `index.html` because I was adding `jquery` but I removed that line. – Tony Jun 04 '21 at 19:34
2

Your page is at localhost:5006/so, but you are requesting the video at localhost:5006/movie.mp4. I think you want localhost:5006/so/movie.mp4.

Doug Sillars
  • 1,625
  • 5
  • 7
0

Does not seem possible to play a video as a local file because of security issues. Creating a very quick webserver using mongoose.ws worked. The code above then becomes

from bokeh.models import Div
from bokeh.io import curdoc


div = Div(text="""
    <video width="300px" height="150px" controls autoplay>
    <source src="http://192.168.1.197:8000/movie.mp4" type="video/mp4"></video>
    """)

curdoc().add_root(div)

where the URL is created by the mongoose application.

Russell Burdt
  • 2,391
  • 2
  • 19
  • 30
  • 2
    This is not the best solution. Why creating a new Mongoose webserver if Bokeh always creates one for you each time you run the app? It is much better and easier to reference the video file using the Bokeh webserver like recommended in other posts. – Tony Jun 04 '21 at 15:00