Modifying a DOM Property in html.Video - Dash Video Component


#1

I want to add a video player that is time synchronised with my data. Ideally (and currently) I have an html.Video element which plays as expected. Is there anyway to set the video player’s property currentTime = X?

Thanks for any help.


#2

From what google tells me, you need to do this using the Javascript API to the video component. Unfortunately there’s not really a convenient way at the moment to run arbitrary javascript from a callback. (That’s my understanding anyway) For example, inserting an html.Script tag does nothing since you can’t add scripts to a page in this way after the page has loaded.

I’ve been thinking that there could be some merit in creating component whose express purpose is to evaluate Javascript that it is fed. Until someone created such a component, I think you’d need to create you’re own Dash component that exposes the necessary parts of the javascript API as props.


#3

This would be a good candidate for a custom Dash component (https://plot.ly/dash/plugins) (which you can build if you know React.js or you can contract Plotly to build for you, see https://plot.ly/dash/pricing).

For example, here are some React components that already exist that control Videos that could be relatively easily ported into Dash:


Pan & Zoom two images at the same time
#4

Great and immediate feedback - I’ll try and build a custom player.

Your responsiveness is awesome and appreciated.


#5

Great! Feel free to open a new thread if you need any help working through this, happy to help :+1:


#6

I’m working on building the same concept, syncing timestamped CSV Data with video! Would love to know how your going about this :slight_smile:


#7

I’ve made a JavaScript video player component (I’ve actually made 4 - such is the weakness of my JavaScript skills) - but right now - in proof of concept mode - I have:

A JavaScript video playing component that takes a time cursor parameter and “cleverly” advances or slows that video speed - or jumps (depending on the lag) to the cursor time. This allows you vary playback speed, single frame step or jump to a new location. This component can run in your main window or as a separate window reading cursor time regularly from disk or a memcache.

A interval timer in my main window that updates and displays the cursor time and writes it to disk so all my data/video windows can have access to slightly lagged cursor time.

You need to manage the video start wall time and then it can be synced with data wall time.

Let me know if you would like to discuss. I plan to tidy it up in a week or two and would be happy to share it.

Ian


#8

That’s awesome, If you want to talk via discord feel free to add me. ether#9458
I would love to try It out.
I’m working right now to add video-react.js component into dash I’ll let you know how that goes, it exposes current time and seeking time in the state which seem quite useful.


#9

I have a video-react component built with marginal results on the speed variation. I had better luck with react-player. I reached out on discord - chat soon.


#10

Great, I hit you back up on discord. I’m new to react so currently just binge watching and absorbing all information I can on the topic. I’ll check out react-player also :slight_smile:


#11

I’ve got the Data and Video to sync with this code.

import dash
import datetime
from dash.dependencies import Input, Output, State, Event
import dash_core_components as dcc
import dash_html_components as html
import plotly.plotly as py
from plotly import graph_objs as go

from plotly.graph_objs import *
from flask import Flask
import pandas as pd
from collections import deque

import video_engine as rpd

app = dash.Dash()

app.scripts.config.serve_locally = True 
X = deque(maxlen=1)
Y = deque(maxlen=1)
X.append(1)
Y.append(1)

newtime = deque(maxlen=0)

df = pd.read_csv('CleanData.csv') #Reads CSV Data


app.layout = html.Div(children=[
    html.H1(children='the best fucking data analyzer ever',
            style={
                'textAlign': 'center'
                    }),
    dcc.Graph(
        id='sens1',
        style={
            'width': '50%',
            'height': '50%',
            'lineHeight': '60px',
            'borderWidth': '10px',
            'borderStyle': 'solid',
            'borderRadius': '20px',
            'textAlign': 'center',
            'margin': 'left',
        }),
 #   html.H2(id = 'time_counter',
     #    children='''NO TIME YET''',
   #      style={
  #              'textAlign': 'center'
   #                 }),
    html.Div(children=rpd.my_Player(
        id = 'video_player',
        url = 'http://127.0.0.1:8080/testvideo.mp4',
        width = 900,
        height = 720,
        controls = True,
        playing = False,
        seekTo = 0,
        volume = 1 ),
        style={'textAlign': 'center',
                'margin': 'auto'}
    ),
dcc.Slider(id = 'time-slider', value=0, min=0, max=120, step=0.00001,
           marks={0: 'Start', 120: 'End'}),

    
    ])


@app.callback( ##Graph 1
    dash.dependencies.Output('sens1', 'figure'),
    [dash.dependencies.Input('video_player', 'currTime')])
def update_time(newtime):
    X.append(newtime)
    data = go.Scatter(
                x = df['timestamp'],
                y = df['sens1'],
                name = 'EEG 1',
                mode = 'lines'
        )
    data2 = go.Scatter(
                x = df['timestamp'],
                y = df['sens2'],
                name = 'EEG 2',
                mode = 'lines'
    )
    data3 = go.Scatter(
                x = df['timestamp'],
                y = df['sens3'],
                name = 'EEG 3',
                mode = 'lines'
    )
    data4 = go.Scatter(
                x = df['timestamp'],
                y = df['sens4'],
                name = 'EEG 4',
                mode = 'lines'
    )
    
    return {'data': [data, data2, data3], 'layout': go.Layout(xaxis = dict(range=[min(X), max(X)], fixedrange='true'),
                                                              yaxis=dict(range=[min(df['sens3']),max(df['sens3'])]),)}


# TESTING
#  Tested
#   Playing (True or False)
#   Volume (between 0 and 1)
#   seekTo
#   muted
#   playbackRate
#  To BE Tested
#   getCurrentTime
#   ![itworks|600x338]
#   controls (volume only)
#   styles
#   playsInline
#   config


app.css.append_css({
    'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'})

app.css.append_css({
    'external_url': 'https://unpkg.com/video-react@0.9.4/dist/video-react.css'})

if __name__ == '__main__':
    app.run_server(debug=True)

Now I want to update 4 different graphs, when I set this code up using 4 different callback functions, they seem to update at different times and it’s super super laggy, Also If i add 4 go.Scatter data sets to the one graph it won’t work at all, 3 seems to be the max for some reason.

Another problem is in the javascript when I change the interval at which data is sent out to dash anything lower that a half of a second and the application doesn’t work.

Is there a way to improve the functionality of this script and have it update quicker/faster?

Maybe create a slider component and have the value be the input for callback functions that update the video/data?

@chriddyp I know your the GOAT on this stuff, I finally succeeded in getting this thing to work after 100+ attempts working roughly 12 hrs a day on it, I’m not much of a programmer but I feel I’ve learned a lot. If you see any obvious improvements that I’m missing to increase the functionality of this please let me know, I think having data synced to video is awesome and could be very useful.
itworks


Add Webcam feed embedded
Show and Tell - Community Thread :tada:
Show and Tell - Community Thread :tada:
#12

Awesome stuff @Beyond_EEG! I’m happy to take a look. Is your video_engine code on GitHub somewhere?


#13

It’s @freshwuzhere 's original code for the react module, I couldn’t of done this without his help. I just built ontop of it to get it to work with dash in the way I needed to update the graph to make it like a timeline sort of view. There’s some issues going on getting access to all the variables however.


#14

@freshwuzhere or @Beyond_EEG - Where is this code published? I’m happy to take a look if the code is published on GitHub


#15

Code is published here, let me know if you have any questions :slight_smile: I’ll be available any time of day for the next week as I work to develop this


#16

Embarrassing - it is really just a dev/proof of concept code - I was going to tidy up next week and publish then.


#17

I’ve published a component called react_player_dash on npm and pypi.

It will allow a component to be loaded and play a video in Dash

It gives sufficient control for videos from a number of sources (react-player supports a lot - files, youtube, Vimeo etc).

It is alpha version and my javascript skills are rudimentary but it appears to be working.

I will upload some dcoumentation and sufficient Dash examples to get any intrepid users going.


#18

Updated react-player-dash to fix a number of bugs in the component - all functions tested OK in current version 1.0.9 - have included video_demo.py to give live examples of usage in Dash.