Interactive video player in Makie

For anyone interested, here is my attempt on a simple interactive video player in Makie:

using GLMakie
using VideoIO

"""
    videoplayer(fig, vid; totalframes)

Create videoplayer
providing totalframes makes it start faster
"""
function videoplayer(fig, vid; totalframes = nothing)
    playing = Observable(false)
    frame = Observable(1)
    lastframe = 0
    isnothing(totalframes) && (totalframes = counttotalframes(vid))
    framerate = round(VideoIO.framerate(vid))

    # image
    img = read(vid)
    gl = GridLayout()
    gl[1,1] = vid_ax = Axis(fig, aspect = DataAspect())
    hidedecorations!(vid_ax)
    videonode = Observable(rotr90(img))
    image!(videonode)

    # controls
    gl[2,1] = controls = GridLayout()
    controls[1,1] = playbutton = Button(fig, label=lift(x -> x ? " ▌▌ " : " ▶ ", playing))
    controls[1,2] = progressbar = Slider(fig, range = 1:totalframes)
    controls[1,3] = timebutton = Button(fig, label=" F:1/$totalframes ")
    fig[1,1] = gl 
    
    on(playbutton.clicks) do _
        (frame[] == totalframes) && set_close_to!(progressbar, 1)
        playing[] = !playing[]
    end

    on(playing) do pl
        !pl && return
        @async begin  
            while playing[] && frame[]<totalframes
                frame[] = frame[] + 1
                sleep(1/framerate)
            end
            playing[] = false # stop
        end 
    end

    on(frame) do fr
        set_close_to!(progressbar, frame[])
        notify(progressbar.value)
    end

    on(progressbar.value) do wantedframe 
        if wantedframe != frame[]
            frame[] = wantedframe
        end
        if wantedframe != lastframe + 1     
            seek(vid, (wantedframe-1)/framerate)
        end
        timebutton.label = " F:$(frame[])/$totalframes "
        read!(vid, img)
        # image modification function may come here
        videonode[] = rotr90(img)
        lastframe = wantedframe
    end

    return gl
end

# __Main__

io = VideoIO.testvideo("annie_oakley") # test video
totalframes = nothing
# io = VideoIO.open(videofile)
# totalframes = VideoIO.get_number_frames(videofile)

vid = VideoIO.openvideo(io)
fig = Figure()
display(fig)

vp = videoplayer(fig[1,1], vid; totalframes)

6 Likes