Skip to content

Commit

Permalink
Merge 0bea443 into 0f211c2
Browse files Browse the repository at this point in the history
  • Loading branch information
galenlynch committed Aug 19, 2020
2 parents 0f211c2 + 0bea443 commit 6edaac3
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 3 deletions.
37 changes: 35 additions & 2 deletions docs/src/reading.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ video frames from a supported video file (or from a camera device, shown later).
```julia
using VideoIO

#io = VideoIO.open(video_file)
# Construct a AVInput object to access the video and audio streams in a video container
# io = VideoIO.open(video_file)
io = VideoIO.testvideo("annie_oakley") # for testing purposes

f = VideoIO.openvideo(io)
# Access the video stream in an AVInput, and return a VideoReader object:
f = VideoIO.openvideo(io) # you can also use a file name, instead of a AVInput

img = read(f)

Expand All @@ -23,6 +25,37 @@ end
close(f)
```

Alternatively, you can open the video stream in a file directly with
`VideoIO.openvideo(filename)`, without making an intermediate `AVInput`
object, if you only need the video.

VideoIO also provides an iterator interface for [`VideoReader`](@ref), which
behaves like other mutable iterators in Julia (e.g. Channels). If iteration is
stopped early, for example with a `break` statement, then it can be resumed in
the same spot by iterating on the same `VideoReader` object. Consequently, if
you have already iterated over all the frames of a `VideoReader` object, then it
will be empty for further iteration unless its position in the video is changed
with `seek`.

```julia
using VideoIO


io = VideoIO.testvideo("annie_oakley")
f = VideoIO.openvideo(io)

for img in f
# Do something with img
end

# You can also use collect(f) to get all of the frames

# Further iteration will show that f is now empty!

close(f)
```


Seeking through the video can be achieved via `seek(f, seconds::Float64)` and `seekstart(f)` to return to the start.
```@docs
VideoIO.seek
Expand Down
2 changes: 2 additions & 0 deletions src/VideoIO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ using ImageCore: permuteddimsview, channelview, rawview #0.723065 seconds
using ColorTypes: RGB, Gray, N0f8, YCbCr #0.529263 seconds
using ImageTransformations: restrict #3.156594 seconds!!

import Base: iterate, IteratorSize, IteratorEltype

include("init.jl")
include("util.jl")
include(joinpath(av_load_path, "AVUtil", "src", "AVUtil.jl"))
Expand Down
9 changes: 9 additions & 0 deletions src/avio.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ end

show(io::IO, vr::VideoReader) = print(io, "VideoReader(...)")

function iterate(r::VideoReader, state = 0)
eof(r) && return
return read(r), state + 1
end

IteratorSize(::Type{<:VideoReader}) = Base.SizeUnknown()

IteratorEltype(::Type{<:VideoReader}) = Base.EltypeUnknown()

# Pump input for data
function pump(c::AVInput)
pFormatContext = c.apFormatContext[1]
Expand Down
29 changes: 28 additions & 1 deletion test/avio.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ end
first_frame = load(first_frame_file)

filename = joinpath(videodir, name)
v = VideoIO.openvideo(open(filename))
v = VideoIO.openvideo(VideoIO.open(filename))

if size(first_frame, 1) > v.height
first_frame = first_frame[1+size(first_frame,1)-v.height:end,:]
Expand All @@ -147,13 +147,40 @@ end
while !eof(v)
read!(v, img)
end

# Iterator interface
VT = typeof(v)
@test Base.IteratorSize(VT) === Base.SizeUnknown()
@test Base.IteratorEltype(VT) === Base.EltypeUnknown()

VideoIO.seekstart(v)
i = 0
local first_frame
local last_frame
for frame in v
i += 1
if i == 1
first_frame = frame
end
last_frame = frame
end
@test i == VideoIO.TestVideos.videofiles[name].numframes
# test that the frames returned by the iterator have distinct storage
if i > 1
@test first_frame !== last_frame
end

## Test that iterator is mutable, and continues where iteration last
## stopped.
@test iterate(v) === nothing
end
end

VideoIO.testvideo("ladybird") # coverage testing
@test_throws ErrorException VideoIO.testvideo("rickroll")
@test_throws ErrorException VideoIO.testvideo("")
end

@testset "Reading video metadata" begin
@testset "Reading Storage Aspect Ratio: SAR" begin
# currently, the SAR of all the test videos is 1, we should get another video with a valid SAR that is not equal to 1
Expand Down

0 comments on commit 6edaac3

Please sign in to comment.