Skip to content

Commit

Permalink
Fix some missing framerate/width/height funcs. Fix Makie playback vie…
Browse files Browse the repository at this point in the history
…wer (#330)
  • Loading branch information
IanButterworth authored Aug 4, 2021
1 parent 486a7bc commit 2860548
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 41 deletions.
34 changes: 17 additions & 17 deletions docs/src/reading.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ close(f)

## Video Playback

A trivial video player interface exists (no audio) through `Makie.jl`.
Note: `Makie` must be imported first to enable playback functionality.
A trivial video player interface exists (no audio) through `GLMakie.jl`.
Note: `GLMakie` must be imported first to enable playback functionality.

```julia
using Makie
using GLMakie
using VideoIO

f = VideoIO.testvideo("annie_oakley") # downloaded if not available
Expand All @@ -120,23 +120,23 @@ VideoIO.playvideo(f) # no sound
Customization of playback can be achieved by looking at the basic expanded version of this function:

```julia
import Makie
import GLMakie
import VideoIO

#io = VideoIO.open(video_file)
io = VideoIO.testvideo("annie_oakley") # for testing purposes
f = VideoIO.openvideo(io)

img = read(f)
scene = Makie.Scene(resolution = reverse(size(img)))
makieimg = Makie.image!(scene, img, show_axis = false, scale_plot = true)[end]
Makie.rotate!(scene, -0.5pi)
scene = GLMakie.Scene(resolution = reverse(size(img)))
makieimg = GLMakie.image!(scene, img, show_axis = false, scale_plot = true)
GLMakie.rotate!(scene, -0.5pi)
display(scene)

while !eof(f)
read!(f, img)
makieimg[1] = img
sleep(1/f.framerate)
makieimg.image = img
sleep(1/VideoIO.framerate(f))
end
```
This code is essentially the code in `playvideo`, and will read and
Expand All @@ -150,33 +150,33 @@ using VideoIO
cam = VideoIO.opencamera()
for i in 1:100
img = read(cam)
sleep(1/cam.framerate)
sleep(1/VideoIO.framerate(cam))
end
```
### Webcam playback
The default system webcam can be viewed directly
```julia
using Makie
using GLMakie
using VideoIO
VideoIO.viewcam()
```

An expanded version of this approach:
```julia
import Makie, VideoIO
import GLMakie, VideoIO

cam = VideoIO.opencamera()

img = read(cam)
scene = Makie.Scene(resolution = size(img'))
makieimg = Makie.image!(scene, img, show_axis = false, scale_plot = false)[end]
Makie.rotate!(scene, -0.5pi)
scene = GLMakie.Scene(resolution = size(img'))
makieimg = GLMakie.image!(scene, img, show_axis = false, scale_plot = false)
GLMakie.rotate!(scene, -0.5pi)
display(scene)

while isopen(scene)
read!(cam, img)
makieimg[1] = img
sleep(1/cam.framerate)
makieimg.image = img
sleep(1/VideoIO.framerate(cam))
end

close(cam)
Expand Down
36 changes: 18 additions & 18 deletions src/VideoIO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,15 @@ elseif Sys.isbsd()
end
end

#Helper functions to explain about Makie load order requirement
#Helper functions to explain about GLMakie load order requirement
function play(f; flipx=false, flipy=false)
error("Makie must be loaded before VideoIO to provide video playback functionality. Try a new session with `using Makie, VideoIO`")
error("GLMakie must be loaded before VideoIO to provide video playback functionality. Try a new session with `using GLMakie, VideoIO`")
end
function playvideo(video;flipx=false,flipy=false)
error("Makie must be loaded before VideoIO to provide video playback functionality. Try a new session with `using Makie, VideoIO`")
error("GLMakie must be loaded before VideoIO to provide video playback functionality. Try a new session with `using GLMakie, VideoIO`")
end
function viewcam(device=DEFAULT_CAMERA_DEVICE, format=DEFAULT_CAMERA_FORMAT)
error("Makie must be loaded before VideoIO to provide camera playback functionality. Try a new session with `using Makie, VideoIO`")
error("GLMakie must be loaded before VideoIO to provide camera playback functionality. Try a new session with `using GLMakie, VideoIO`")
end

## FileIO interface
Expand All @@ -131,31 +131,31 @@ function __init__()
init_camera_devices()
init_camera_settings()

@require Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" begin
@require GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" begin
# Define read and retrieve for Images
function play(f; flipx=false, flipy=false, pixelaspectratio=nothing)
eof(f) && error("VideoReader at end of file. Use `seekstart(f)` to rewind")
if pixelaspectratio nothing # if user did not specify the aspect ratio we'll try to use the one stored in the video file
pixelaspectratio = aspect_ratio(f)
end
h = f.height
w = round(typeof(h), f.width*pixelaspectratio) # has to be an integer
scene = Makie.Scene(resolution = (w, h))
h = height(f)
w = round(typeof(h), width(f) * pixelaspectratio) # has to be an integer
scene = GLMakie.Scene(resolution = (w, h))
buf = read(f)
makieimg = Makie.image!(scene, 1:h, 1:w, buf, show_axis = false, scale_plot = false)[end]
Makie.rotate!(scene, -0.5pi)
makieimg = GLMakie.image!(scene, 1:h, 1:w, buf, show_axis = false, scale_plot = false)
GLMakie.rotate!(scene, -0.5pi)
if flipx && flipy
Makie.scale!(scene, -1, -1, 1)
GLMakie.scale!(scene, -1, -1, 1)
else
flipx && Makie.scale!(scene, -1, 1, 1)
flipy && Makie.scale!(scene, 1, -1, 1)
flipx && GLMakie.scale!(scene, -1, 1, 1)
flipy && GLMakie.scale!(scene, 1, -1, 1)
end
display(scene)
while !eof(f) && isopen(scene)
while isopen(scene) && !eof(f)
read!(f, buf)
makieimg[3] = buf
sleep(1 / f.framerate)
makieimg.image = buf
sleep(1 / framerate(f))
end

end

function playvideo(video;flipx=false,flipy=false,pixelaspectratio=nothing)
Expand All @@ -166,7 +166,7 @@ function __init__()
function viewcam(device=DEFAULT_CAMERA_DEVICE, format=DEFAULT_CAMERA_FORMAT, pixelaspectratio=nothing)
init_camera_settings()
camera = opencamera(device[], format[])
play(camera, flipx=true, pixelaspectratio=pixelaspectratio)
play(camera; flipx=true, pixelaspectratio)
close(camera)
end

Expand Down
6 changes: 3 additions & 3 deletions src/avio.jl
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,9 @@ function aspect_ratio(f::VideoReader)
fixed_aspect
end

framerate(f::VideoReader) =
f.codec_context.time_base.den // f.codec_context.time_base.num

framerate(f::VideoReader) = f.codec_context.time_base.den // f.codec_context.time_base.num
height(f::VideoReader) = f.codec_context.height
width(f::VideoReader) = f.codec_context.width

# Does not check input size, meant for internal use only
function stash_graph_input!(imgbuf, r::VideoReader, align = VIO_ALIGN)
Expand Down
2 changes: 1 addition & 1 deletion src/testvideos.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const videofiles = Dict(
"https://upload.wikimedia.org/wikipedia/commons/8/87/Annie_Oakley_shooting_glass_balls%2C_1894.ogv",
726,
2,
5848,
167311096,
),

"crescent-moon.ogv" => VideoFile("crescent-moon.ogv",
Expand Down
16 changes: 14 additions & 2 deletions test/reading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
time_seconds = VideoIO.gettime(v)
@test time_seconds == 0
width, height = VideoIO.out_frame_size(v)
@test VideoIO.width(v) == width
@test VideoIO.height(v) == height
@test VideoIO.out_frame_eltype(v) == RGB{N0f8}
if size(comparison_frame, 1) > height
trimmed_comparison_frame =
Expand All @@ -20,6 +22,8 @@
trimmed_comparison_frame = comparison_frame
end

@test VideoIO.framerate(v) != 0

# Find the first non-trivial image
first_img = read(v)
first_time = VideoIO.gettime(v)
Expand Down Expand Up @@ -123,11 +127,19 @@
if occursin("annie_oakley", name)
framestack = VideoIO.load(testvid_path)
@test length(framestack) == VideoIO.TestVideos.videofiles[name].numframes
@test Base.summarysize(framestack) == VideoIO.TestVideos.videofiles[name].summarysize
if VERSION < v"1.7"
@test_broken Base.summarysize(framestack) == VideoIO.TestVideos.videofiles[name].summarysize
else
@test Base.summarysize(framestack) == VideoIO.TestVideos.videofiles[name].summarysize
end
f = File{DataFormat{:OGG}}(testvid_path)
framestack = VideoIO.fileio_load(f)
@test length(framestack) == VideoIO.TestVideos.videofiles[name].numframes
@test Base.summarysize(framestack) == VideoIO.TestVideos.videofiles[name].summarysize
if VERSION < v"1.7"
@test_broken Base.summarysize(framestack) == VideoIO.TestVideos.videofiles[name].summarysize
else
@test Base.summarysize(framestack) == VideoIO.TestVideos.videofiles[name].summarysize
end
path, io = mktemp()
f = File{DataFormat{:MP4}}(path * ".mp4")
VideoIO.fileio_save(f, framestack)
Expand Down

0 comments on commit 2860548

Please sign in to comment.