Skip to content

Commit de2c9df

Browse files
authored
Merge pull request #6 from BinaryNoggin/feature/documentation
Document types in Turbojpeg
2 parents a174534 + 7f8994a commit de2c9df

File tree

6 files changed

+136
-56
lines changed

6 files changed

+136
-56
lines changed

dialyzer.ignore-warnings.exs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[
2+
{"lib/turbojpeg/native.ex"}
3+
]

lib/turbojpeg.ex

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,86 @@
11
defmodule Turbojpeg do
22
@moduledoc File.read!("README.md")
3+
alias Turbojpeg.Native
4+
5+
@type width :: dimension
6+
@type height :: dimension
7+
@type dimension :: pos_integer()
8+
@type quality :: 0..100
9+
@type format ::
10+
:I420
11+
| :I422
12+
| :I444
13+
| :GRAY
14+
@type error ::
15+
{:error, atom()}
16+
| {:error, struct}
17+
@type jpeg_header :: %{
18+
format: format(),
19+
width: width(),
20+
height: height()
21+
}
22+
23+
@doc """
24+
Converts yuv to jpeg images
25+
26+
27+
iex> {:ok, jpeg} = Turbojpeg.yuv_to_jpeg(Shmex.new(frame), 1920, 1080, 90, :I420)
28+
{:ok,
29+
%Shmex{
30+
capacity: 203783,
31+
guard: #Reference<0.938325095.2990669827.232440>,
32+
name: "/shmex-00000005607042890133#000",
33+
size: 203783
34+
}}
35+
"""
36+
@spec yuv_to_jpeg(Shmex.t(), width, height, quality, format) ::
37+
{:ok, Shmex.t()} | error()
38+
def yuv_to_jpeg(yuv, width, height, quality, format) do
39+
Native.yuv_to_jpeg(yuv, width, height, quality, format)
40+
rescue
41+
error ->
42+
{:error, error}
43+
end
44+
45+
@doc """
46+
Converts jpeg to yuv
47+
48+
49+
iex> {:ok, yuv} = Turbojpeg.jpeg_to_yuv(Shmex.new(jpeg))
50+
{:ok,
51+
%Shmex{
52+
capacity: 203783,
53+
guard: #Reference<0.938325095.2990669827.232440>,
54+
name: "/shmex-00000005607042890133#000",
55+
size: 203783
56+
}}
57+
"""
58+
@spec jpeg_to_yuv(Shmex.t()) ::
59+
{:ok, Shmex.t()} | error()
60+
def jpeg_to_yuv(jpeg) do
61+
Native.jpeg_to_yuv(jpeg)
62+
rescue
63+
error ->
64+
{:error, error}
65+
end
66+
67+
@doc """
68+
Gets the header from a jpegv
69+
70+
iex> {:ok, header} = Turbojpeg.get_jpeg_header(Shmex.new(jpeg))
71+
{:ok,
72+
%{
73+
format: :I422,
74+
width: 192,
75+
height: 192
76+
}
77+
}
78+
"""
79+
@spec get_jpeg_header(Shmex.t()) :: {:ok, jpeg_header} | error()
80+
def get_jpeg_header(jpeg) do
81+
Native.get_jpeg_header(jpeg)
82+
rescue
83+
error ->
84+
{:error, error}
85+
end
386
end

lib/turbojpeg/sink.ex

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
defmodule Turbojpeg.Sink do
2-
alias Turbojpeg.Native
32
use Membrane.Sink
43
alias Membrane.{Buffer, Time}
54
alias Membrane.Caps.Video.Raw
@@ -48,12 +47,12 @@ defmodule Turbojpeg.Sink do
4847
@impl true
4948
def handle_write(:input, %Buffer{payload: payload}, _ctx, state) do
5049
with {:ok, data} <-
51-
Native.yuv_to_jpeg(payload, state.width, state.height, state.quality, state.format),
50+
Turbojpeg.yuv_to_jpeg(payload, state.width, state.height, state.quality, state.format),
5251
:ok <- File.write(state.filename, Shmex.to_binary(data)) do
5352
{:ok, state}
5453
else
55-
{:error, reason} ->
56-
{{:error, reason}, state}
54+
{:error, _} = error ->
55+
{error, state}
5756
end
5857
end
5958

mix.exs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ defmodule Turbojpeg.MixProject do
1616
homepage_url: @github_link,
1717
package: package(),
1818
docs: docs(),
19-
deps: deps()
19+
deps: deps(),
20+
dialyzer: [
21+
ignore_warnings: "dialyzer.ignore-warnings.exs"
22+
]
2023
]
2124
end
2225

@@ -36,7 +39,8 @@ defmodule Turbojpeg.MixProject do
3639
{:membrane_core, "~> 0.5.0"},
3740
{:ex_doc, "~> 0.21.3", only: [:dev], runtime: false},
3841
{:propcheck, "~> 1.2.0", only: [:test]},
39-
{:mogrify, github: "ConnorRigby/mogrify", branch: "master", only: [:test, :dev]}
42+
{:mogrify, github: "ConnorRigby/mogrify", branch: "master", only: [:test, :dev]},
43+
{:dialyxir, "~> 1.0.0-rc.7", only: [:dev], runtime: false}
4044
]
4145
end
4246

mix.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"bunch_native": {:hex, :bunch_native, "0.2.1", "0227d2a751a32f8c0b77dfec57c8dc7216351720c9c755c467e6d9387467fd1f", [:mix], [{:bundlex, "~> 0.2.7", [hex: :bundlex, repo: "hexpm", optional: false]}], "hexpm", "f0819b2f9f78086447ac7459a8e7b6e25ad535b9d3a4f9469253c552137de6b4"},
44
"bundlex": {:hex, :bundlex, "0.2.7", "8f46199bf4cf84a60cdfc142edeafbab37040167acc35dda8aa70433f2ff8162", [:mix], [{:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:qex, "~> 0.5", [hex: :qex, repo: "hexpm", optional: false]}, {:secure_random, "~> 0.5", [hex: :secure_random, repo: "hexpm", optional: false]}], "hexpm", "5751b4bb5dd0576ca70519239e2ee7b495b17e4bbfbe3ef1f60ae0c12c0e4fe9"},
55
"coerce": {:hex, :coerce, "1.0.1", "211c27386315dc2894ac11bc1f413a0e38505d808153367bd5c6e75a4003d096", [:mix], [], "hexpm", "b44a691700f7a1a15b4b7e2ff1fa30bebd669929ac8aa43cffe9e2f8bf051cf1"},
6+
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.7", "6287f8f2cb45df8584317a4be1075b8c9b8a69de8eeb82b4d9e6c761cf2664cd", [:mix], [{:erlex, ">= 0.2.5", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "506294d6c543e4e5282d4852aead19ace8a35bedeb043f9256a06a6336827122"},
67
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
8+
"erlex": {:hex, :erlex, "0.2.5", "e51132f2f472e13d606d808f0574508eeea2030d487fc002b46ad97e738b0510", [:mix], [], "hexpm", "756d3e19b056339af674b715fdd752c5dac468cf9d0e2d1a03abf4574e99fbf8"},
79
"ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"},
810
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"},
911
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"},

test/turbojpeg_test.exs

Lines changed: 39 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
defmodule TurbojpegTest do
22
use ExUnit.Case
3-
use PropCheck, default_opts: [numtests: 10]
3+
use PropCheck, numtests: 10
44
use Mogrify.Options
55

66
@jpeg_header <<255, 216, 255>>
@@ -10,52 +10,52 @@ defmodule TurbojpegTest do
1010
test "Converts an i420 frame into a jpeg" do
1111
frame = File.read!(@i420_fixture)
1212
shmex = Shmex.new(frame)
13-
{:ok, jpeg} = Turbojpeg.Native.yuv_to_jpeg(shmex, 1920, 1080, 100, :I420)
13+
{:ok, jpeg} = Turbojpeg.yuv_to_jpeg(shmex, 1920, 1080, 100, :I420)
1414
assert match?(@jpeg_header <> _, Shmex.to_binary(jpeg))
1515
end
1616

1717
test "extracts i444 frame from jpeg" do
1818
jpeg = Shmex.new(File.read!(@ff0000_fixture))
19-
{:ok, yuv} = Turbojpeg.Native.jpeg_to_yuv(jpeg)
20-
{:ok, new_jpeg} = Turbojpeg.Native.yuv_to_jpeg(yuv, 64, 64, 100, :I444)
19+
{:ok, yuv} = Turbojpeg.jpeg_to_yuv(jpeg)
20+
{:ok, new_jpeg} = Turbojpeg.yuv_to_jpeg(yuv, 64, 64, 100, :I444)
2121
assert Shmex.to_binary(jpeg) == Shmex.to_binary(new_jpeg)
2222
end
2323

2424
test "get jpeg header" do
2525
jpeg = Shmex.new(File.read!(@ff0000_fixture))
26-
{:ok, result} = Turbojpeg.Native.get_jpeg_header(jpeg)
26+
{:ok, result} = Turbojpeg.get_jpeg_header(jpeg)
2727
assert result.width == 64
2828
assert result.height == 64
2929
assert result.format == :I444
3030
end
3131

32-
@tag [timeout: :infinity]
33-
property "encoding an image is fast", numtests: 8 do
32+
@tag [timeout: :timer.minutes(2)]
33+
property "encoding an image is fast", numtests: 5 do
3434
forall [width, height] <- [
3535
width(100),
3636
height(100)
3737
] do
38-
{jpeg_creation_micros, jpeg} =
39-
:timer.tc(fn ->
40-
jpeg =
41-
%Mogrify.Image{}
42-
|> Mogrify.custom("size", "#{width}x#{height}")
43-
|> Mogrify.custom("seed", 43)
44-
|> Mogrify.custom("plasma", "fractal")
45-
|> Mogrify.custom("sampling-factor", "4:4:4")
46-
|> Mogrify.custom("stdout", "jpg:-")
47-
|> Mogrify.create(buffer: true)
48-
49-
Shmex.new(jpeg.buffer)
50-
end)
51-
52-
{native_micros, ret} =
53-
:timer.tc(fn ->
54-
Turbojpeg.Native.jpeg_to_yuv(jpeg)
55-
end)
38+
jpeg =
39+
%Mogrify.Image{}
40+
|> Mogrify.custom("size", "#{width}x#{height}")
41+
|> Mogrify.custom("seed", 43)
42+
|> Mogrify.custom("plasma", "fractal")
43+
|> Mogrify.custom("sampling-factor", "4:4:4")
44+
|> Mogrify.custom("stdout", "jpg:-")
45+
|> Mogrify.create(buffer: true)
5646

47+
Shmex.new(jpeg.buffer)
48+
49+
ret = Turbojpeg.jpeg_to_yuv(jpeg)
50+
51+
# Only for local runs
52+
# {time_micros, ret} =
53+
# :timer.tc(fn ->
54+
# Turbojpeg.jpeg_to_yuv(jpeg)
55+
# end)
56+
57+
# assert time_micros / 1000 <= 5000
5758
assert match?({:ok, _}, ret)
58-
aggregate(true, result: {to_range(10, jpeg_creation_micros), to_range(1024, jpeg.size)})
5959
end
6060
end
6161

@@ -79,31 +79,25 @@ defmodule TurbojpegTest do
7979
|> Mogrify.create(buffer: true)
8080

8181
jpeg = Shmex.new(jpeg.buffer)
82-
{:ok, yuv} = Turbojpeg.Native.jpeg_to_yuv(jpeg)
82+
{:ok, yuv} = Turbojpeg.jpeg_to_yuv(jpeg)
8383

84-
{:ok, original_header} = Turbojpeg.Native.get_jpeg_header(jpeg)
84+
{:ok, original_header} = Turbojpeg.get_jpeg_header(jpeg)
8585

86-
{:ok, new_jpeg} =
87-
Turbojpeg.Native.yuv_to_jpeg(yuv, width, height, 100, original_header.format)
86+
{:ok, new_jpeg} = Turbojpeg.yuv_to_jpeg(yuv, width, height, 100, original_header.format)
8887

89-
{:ok, new_header} = Turbojpeg.Native.get_jpeg_header(new_jpeg)
88+
{:ok, new_header} = Turbojpeg.get_jpeg_header(new_jpeg)
9089

9190
assert original_header == new_header
92-
93-
aggregate(true,
94-
r: to_range(51, r),
95-
g: to_range(51, g),
96-
b: to_range(51, b)
97-
)
9891
end
9992
end
10093

10194
property "jpeg and yuv conversion are complementary after running through the tool once" do
102-
forall [width, height, seed, {sampling_factor, format}] <- [
95+
forall [width, height, seed, {sampling_factor, format}, quality] <- [
10396
width(),
10497
height(),
10598
seed(),
106-
format()
99+
format(),
100+
integer(0, 100)
107101
] do
108102
jpeg =
109103
%Mogrify.Image{}
@@ -115,16 +109,11 @@ defmodule TurbojpegTest do
115109
|> Mogrify.create(buffer: true)
116110

117111
jpeg = Shmex.new(jpeg.buffer)
118-
{:ok, yuv} = Turbojpeg.Native.jpeg_to_yuv(jpeg)
119-
{:ok, new_jpeg} = Turbojpeg.Native.yuv_to_jpeg(yuv, width, height, 100, format)
120-
{:ok, original_header} = Turbojpeg.Native.get_jpeg_header(jpeg)
121-
{:ok, new_header} = Turbojpeg.Native.get_jpeg_header(new_jpeg)
112+
{:ok, yuv} = Turbojpeg.jpeg_to_yuv(jpeg)
113+
{:ok, new_jpeg} = Turbojpeg.yuv_to_jpeg(yuv, width, height, quality, format)
114+
{:ok, original_header} = Turbojpeg.get_jpeg_header(jpeg)
115+
{:ok, new_header} = Turbojpeg.get_jpeg_header(new_jpeg)
122116
assert original_header == new_header
123-
124-
aggregate(true,
125-
size: to_range(10_000, width * height) |> as_bytes(1024),
126-
width: to_range(10, width)
127-
)
128117
end
129118
end
130119

@@ -137,11 +126,11 @@ defmodule TurbojpegTest do
137126
{div(min, size), div(max, size)}
138127
end
139128

140-
def width(multiplier \\ 50) do
129+
def width(multiplier \\ 10) do
141130
dimension(multiplier)
142131
end
143132

144-
def height(multiplier \\ 50) do
133+
def height(multiplier \\ 10) do
145134
dimension(multiplier)
146135
end
147136

0 commit comments

Comments
 (0)