philomena/lib/philomena_media/processors/gif.ex

159 lines
3.5 KiB
Elixir
Raw Permalink Normal View History

defmodule PhilomenaMedia.Processors.Gif do
@moduledoc false
2019-11-26 01:06:40 +01:00
alias PhilomenaMedia.Intensities
alias PhilomenaMedia.Analyzers.Result
alias PhilomenaMedia.Processors.Processor
alias PhilomenaMedia.Processors
@behaviour Processor
@spec versions(Processors.version_list()) :: [Processors.version_filename()]
def versions(sizes) do
sizes
|> Enum.map(fn {name, _} -> "#{name}.gif" end)
|> Kernel.++(["full.webm", "full.mp4", "rendered.png"])
end
@spec process(Result.t(), Path.t(), Processors.version_list()) :: Processors.edit_script()
2019-11-26 03:57:47 +01:00
def process(analysis, file, versions) do
duration = analysis.duration
preview = preview(duration, file)
palette = palette(file)
2019-11-26 01:06:40 +01:00
2019-11-26 03:57:47 +01:00
{:ok, intensities} = Intensities.file(preview)
scaled = Enum.flat_map(versions, &scale(palette, file, &1))
videos = generate_videos(file)
2019-11-26 03:57:47 +01:00
[
2019-11-26 03:57:47 +01:00
intensities: intensities,
thumbnails: scaled ++ videos ++ [{:copy, preview, "rendered.png"}]
]
2019-11-26 01:06:40 +01:00
end
@spec post_process(Result.t(), Path.t()) :: Processors.edit_script()
2019-11-26 03:57:47 +01:00
def post_process(_analysis, file) do
[replace_original: optimize(file)]
2019-11-26 01:06:40 +01:00
end
@spec intensities(Result.t(), Path.t()) :: Intensities.t()
2019-11-29 01:11:05 +01:00
def intensities(analysis, file) do
{:ok, intensities} = Intensities.file(preview(analysis.duration, file))
intensities
end
2019-11-26 03:57:47 +01:00
defp optimize(file) do
optimized = Briefly.create!(extname: ".gif")
2020-01-11 05:20:19 +01:00
{_output, 0} = System.cmd("gifsicle", ["--careful", "-O2", file, "-o", optimized])
2019-11-26 03:57:47 +01:00
optimized
end
defp preview(duration, file) do
2019-11-26 01:06:40 +01:00
preview = Briefly.create!(extname: ".png")
{_output, 0} = System.cmd("mediathumb", [file, to_string(duration / 2), preview])
2019-11-26 01:06:40 +01:00
2019-11-26 03:57:47 +01:00
preview
2019-11-26 01:06:40 +01:00
end
2019-11-26 03:57:47 +01:00
defp palette(file) do
palette = Briefly.create!(extname: ".png")
2019-11-26 01:06:40 +01:00
{_output, 0} =
2020-01-11 05:20:19 +01:00
System.cmd("ffmpeg", [
"-loglevel",
"0",
"-y",
"-i",
file,
"-vf",
"palettegen=stats_mode=diff",
palette
])
2019-11-26 03:57:47 +01:00
palette
end
2019-11-26 01:06:40 +01:00
defp scale(palette, file, {thumb_name, {width, height}}) do
2019-11-26 03:57:47 +01:00
scaled = Briefly.create!(extname: ".gif")
2019-11-26 01:06:40 +01:00
2020-01-11 05:20:19 +01:00
scale_filter = "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease"
2020-09-10 04:37:07 +02:00
palette_filter =
"paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle:alpha_threshold=255"
2020-05-20 01:19:53 +02:00
filter_graph = "[0:v]#{scale_filter}[x];[x][1:v]#{palette_filter}"
2019-11-26 01:06:40 +01:00
{_output, 0} =
2020-01-11 05:20:19 +01:00
System.cmd("ffmpeg", [
"-loglevel",
"0",
"-y",
"-i",
file,
"-i",
palette,
"-lavfi",
filter_graph,
scaled
])
2019-11-26 01:06:40 +01:00
[{:copy, scaled, "#{thumb_name}.gif"}]
2019-11-26 01:06:40 +01:00
end
2019-11-26 03:57:47 +01:00
defp generate_videos(file) do
webm = Briefly.create!(extname: ".webm")
2020-01-11 05:20:19 +01:00
mp4 = Briefly.create!(extname: ".mp4")
2019-11-26 01:06:40 +01:00
{_output, 0} =
2020-01-11 05:20:19 +01:00
System.cmd("ffmpeg", [
"-loglevel",
"0",
"-y",
"-i",
file,
"-pix_fmt",
"yuv420p",
"-c:v",
"libvpx",
"-deadline",
2020-01-11 05:20:19 +01:00
"good",
"-b:v",
"5M",
webm
])
2019-11-26 03:57:47 +01:00
{_output, 0} =
2020-01-11 05:20:19 +01:00
System.cmd("ffmpeg", [
"-loglevel",
"0",
"-y",
"-i",
file,
"-vf",
"scale=ceil(iw/2)*2:ceil(ih/2)*2",
"-c:v",
"libx264",
"-preset",
"medium",
"-pix_fmt",
"yuv420p",
"-profile:v",
"main",
"-crf",
"18",
"-b:v",
"5M",
mp4
])
2019-11-26 03:57:47 +01:00
[
{:copy, webm, "full.webm"},
{:copy, mp4, "full.mp4"}
]
2019-11-26 01:06:40 +01:00
end
2019-12-22 05:57:59 +01:00
end