Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GSoC'21] Livestreaming v2 #387

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Javis.jl - Changelog

## Unreleased
- Make livestreaming faster
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean by faster? Is it live? 😉

- Allow specifying frames to livestream
- added `@Frames` macro for full power mode of defining frames
- bugfix in `@JLayer` when dimensions are not defined explicitly

Expand Down
8 changes: 5 additions & 3 deletions src/Javis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,11 @@ function render(
tempdirectory = mktempdir()
end

if streamconfig != nothing
Sov-trotter marked this conversation as resolved.
Show resolved Hide resolved
_livestream(streamconfig, framerate, video, objects, layers, frames, tempdirectory)
return
end

filecounter = 1
@showprogress 1 "Rendering frames..." for frame in frames
frame_image = convert.(RGB, get_javis_frame(video, objects, frame; layers = layers))
Expand Down Expand Up @@ -318,9 +323,6 @@ function render(
@error "Currently, only gif and mp4 creation is supported. Not a $ext."
end

# check if livestream is used and livestream if that's the case
_livestream(streamconfig, framerate, video.width, video.height, pathname)

# clear all CURRENT_* constants to not accidentally use a previous video when creating a new one
empty_CURRENT_constants()

Expand Down
45 changes: 27 additions & 18 deletions src/javis_viewer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,14 @@ Sets up the livestream configuration.
**NOTE:** Twitch not fully implemented, do not use.
"""
function setup_stream(
livestreamto::Symbol = :local;
livestreamto::Symbol = :local,
frames::Union{UnitRange{Int},Symbol} = :all;
protocol::String = "udp",
address::String = "0.0.0.0",
port::Int = 14015,
twitch_key::String = "",
)
StreamConfig(livestreamto, protocol, address, port, twitch_key)
StreamConfig(livestreamto, protocol, address, port, twitch_key, frames)
end

"""
Expand Down Expand Up @@ -332,7 +333,7 @@ function cancel_stream()
),
),
)
return "Livestream Cancelled!"
return @info "Livestream Cancelled!"
end

"""
Expand All @@ -342,20 +343,37 @@ Internal method for livestreaming
"""
function _livestream(
streamconfig::StreamConfig,
framerate::Int,
width::Int,
height::Int,
pathname::String,
framerate,
video,
objects,
layers,
frames,
tempdirectory,
)
# kill any existing stream
cancel_stream()

livestreamto = streamconfig.livestreamto
config_frames = streamconfig.frames
twitch_key = streamconfig.twitch_key

if livestreamto == :twitch && isempty(twitch_key)
return error("Please enter your twitch stream key")
end

stream_frames = config_frames == :all ? frames : config_frames
stream_filecounter = 1
for frame in stream_frames
frame_image = convert.(RGB, get_javis_frame(video, objects, frame; layers = layers))
if !isempty(tempdirectory)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if tempdirectory is empty? It just generates the frames but can't use it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah what I mean is: it should never be empty so we don't need the if. The problem is if we have an mp4 as the pathname without a temp directory but want to stream it will fail, right?

Images.save(
"$(tempdirectory)/$(lpad(stream_filecounter, 10, "0")).png",
frame_image,
)
end
stream_filecounter += 1
end

command = [
"-stream_loop", # loop the stream -1 times i.e. indefinitely
"-1",
Expand All @@ -366,15 +384,14 @@ function _livestream(
"error",
"-re", # read input at native frame rate
"-i", # input file
"$pathname",
"$(tempdirectory)/%10d.png",
]

if livestreamto == :twitch
if isempty(twitch_key)
error("Please enter your twitch api key")
error("Please enter your twitch stream key")
end

#
twitch_cmd = [
"-f",
"flv", # force the file to flv format
Expand All @@ -396,11 +413,3 @@ function _livestream(
ffmpeg_exe(`$command`)
end)
end

_livestream(
streamconfig::Nothing,
framerate::Int,
width::Int,
height::Int,
pathname::String,
) = return
2 changes: 2 additions & 0 deletions src/structs/Livestream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ Holds the conguration for livestream, defaults to `nothing`
- `address::String` The IP address for the `:local` stream(ignored in case of `:twitch`)
- `port::Int` The port for the `:local` stream(ignored in case of `:twitch`)
- `twitch_key::String` Twitch stream key for your account
- `frames::Union{UnitRange{Int}, Symbol}` The specific frames to be livestreamed. Defaults to `:all`
"""
struct StreamConfig
livestreamto::Symbol
protocol::String
address::String
port::Int
twitch_key::String
frames::Union{UnitRange{Int},Symbol}
end
Binary file added test/refs/livestream_frames56.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/refs/livestream_frames57.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/refs/livestream_frames58.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/refs/livestream_frames59.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/refs/livestream_frames60.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 16 additions & 2 deletions test/viewer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ end
@test conf_local.protocol == "udp"
@test conf_local.address == "0.0.0.0"
@test conf_local.port == 8081
@test conf_local.frames == :all

conf_twitch_err = setup_stream(:twitch)
conf_twitch = setup_stream(:twitch, twitch_key = "foo")
Expand All @@ -141,14 +142,27 @@ end
@test isempty(conf_twitch_err.twitch_key)
@test conf_twitch.twitch_key == "foo"

render(vid, pathname = "stream_local.gif", streamconfig = conf_local)
render(vid, pathname = "test_stream.gif", streamconfig = conf_local)

# errors with macos; a good test to have
# test_local = run(pipeline(`lsof -i -P -n`, `grep ffmpeg`))
# @test test_local isa Base.ProcessChain
# @test test_local.processes isa Vector{Base.Process}

cancel_stream()
# can't actually test the streamed frames but let's check if they're atleast created
conf_local = setup_stream(:local, 56:60)
render(vid, tempdirectory = "images", streamconfig = conf_local)

for i in 56:60
@test_reference "refs/livestream_frames$i.png" load(
"images/$(lpad((i-55), 10, "0")).png",
)
end

for i in 1:5
rm("images/$(lpad(i, 10, "0")).png")
end

@test_throws ProcessFailedException run(
pipeline(
`ps aux`,
Expand Down