Skip to content

Commit 0040b4d

Browse files
gBillalConnorRigby
authored andcommitted
Refactor code to use membrane core 0.12
1 parent 2695bb1 commit 0040b4d

File tree

8 files changed

+161
-153
lines changed

8 files changed

+161
-153
lines changed

c_src/turbojpeg/turbojpeg_native.c

Lines changed: 27 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ UNIFEX_TERM get_jpeg_header(UnifexEnv* env, UnifexPayload *payload) {
4545
enum TJSAMP tjsamp;
4646
enum TJCS cspace;
4747
int res, width, height;
48-
ERL_NIF_TERM map_out, ret;
48+
UNIFEX_TERM ret;
4949

5050
tjh = tjInitDecompress();
5151
if(!tjh)
@@ -63,45 +63,24 @@ UNIFEX_TERM get_jpeg_header(UnifexEnv* env, UnifexPayload *payload) {
6363
goto cleanup;
6464
}
6565

66-
// unifex does not support maps yes.
67-
// See https://github.com/membraneframework/unifex/issues/32
68-
if(!enif_make_map_from_arrays(
69-
env,
70-
(ERL_NIF_TERM []) {
71-
enif_make_atom(env, "width"),
72-
enif_make_atom(env, "height"),
73-
enif_make_atom(env, "format"),
74-
75-
},
76-
(ERL_NIF_TERM []) {
77-
enif_make_int(env, width),
78-
enif_make_int(env, height),
79-
enif_make_atom(env, tjsamp_to_format(tjsamp))
80-
},
81-
3, &map_out
82-
)) {
83-
ret = get_jpeg_header_result_error(env, "make_map");
84-
goto cleanup;
85-
} else {
86-
// Generated code does not support maps currently.
87-
ret = enif_make_tuple_from_array(env, (ERL_NIF_TERM []) {enif_make_atom(env, "ok"), map_out}, 2);
88-
goto cleanup;
89-
}
66+
jpeg_header header = {(char*)tjsamp_to_format(tjsamp), width, height};
67+
ret = get_jpeg_header_result_ok(env, header);
68+
9069
cleanup:
9170
if(tjh) tjDestroy(tjh);
9271
return ret;
9372
}
9473

9574
/**
96-
* Convert a binary h264 payload into a jpeg encoded payload
75+
* Convert a yuv binary payload into a jpeg encoded payload
9776
*/
9877
UNIFEX_TERM yuv_to_jpeg(UnifexEnv* env, UnifexPayload *payload, int width, int height, int quality, char* format) {
9978
tjhandle tjh = NULL;
10079
enum TJSAMP tjsamp;
10180
unsigned char *jpegBuf = NULL;
10281
unsigned long jpegSize;
10382
int res;
104-
UnifexPayload *jpegFrame;
83+
UnifexPayload *jpegFrame = NULL;
10584
UNIFEX_TERM ret;
10685

10786
res = format_to_tjsamp(format);
@@ -126,18 +105,19 @@ UNIFEX_TERM yuv_to_jpeg(UnifexEnv* env, UnifexPayload *payload, int width, int h
126105
if(res < 0) {
127106
ret = yuv_to_jpeg_result_error(env, tjGetErrorStr2(tjh));
128107
goto cleanup;
129-
} else {
130-
jpegFrame = unifex_payload_alloc(env, UNIFEX_PAYLOAD_BINARY, jpegSize);
131-
if(!jpegFrame) {
132-
ret = yuv_to_jpeg_result_error(env, "payload_alloc");
133-
} else {
134-
memcpy(jpegFrame->data, jpegBuf, jpegSize);
135-
ret = yuv_to_jpeg_result_ok(env, jpegFrame);
136-
}
137-
goto cleanup;
138108
}
139109

110+
jpegFrame = unifex_alloc(sizeof(*jpegFrame));
111+
unifex_payload_alloc(env, UNIFEX_PAYLOAD_BINARY, jpegSize, jpegFrame);
112+
memcpy(jpegFrame->data, jpegBuf, jpegSize);
113+
ret = yuv_to_jpeg_result_ok(env, jpegFrame);
114+
140115
cleanup:
116+
if(jpegFrame != NULL) {
117+
unifex_payload_release(jpegFrame);
118+
unifex_free(jpegFrame);
119+
}
120+
141121
if(jpegBuf) tjFree(jpegBuf);
142122
if(tjh) tjDestroy(tjh);
143123
return ret;
@@ -151,7 +131,7 @@ UNIFEX_TERM jpeg_to_yuv(UnifexEnv* env, UnifexPayload *payload) {
151131
enum TJSAMP tjsamp;
152132
enum TJCS cspace;
153133
unsigned long yuvBufSize;
154-
UnifexPayload *yuvFrame;
134+
UnifexPayload *yuvFrame = NULL;
155135
int res, width, height;
156136
UNIFEX_TERM ret;
157137

@@ -166,17 +146,15 @@ UNIFEX_TERM jpeg_to_yuv(UnifexEnv* env, UnifexPayload *payload) {
166146
&width, &height,
167147
(int*)&tjsamp, (int*)&cspace
168148
);
149+
169150
if(res < 0) {
170151
ret = jpeg_to_yuv_result_error(env, tjGetErrorStr2(tjh));
171152
goto cleanup;
172153
}
173154

174155
yuvBufSize = tjBufSizeYUV2(width, 4, height, tjsamp);
175-
yuvFrame = unifex_payload_alloc(env, UNIFEX_PAYLOAD_BINARY, yuvBufSize);
176-
if(!yuvFrame) {
177-
ret = jpeg_to_yuv_result_error(env, "could not allocate frame");
178-
goto cleanup;
179-
}
156+
yuvFrame = unifex_alloc(sizeof(*yuvFrame));
157+
unifex_payload_alloc(env, UNIFEX_PAYLOAD_BINARY, yuvBufSize, yuvFrame);
180158

181159
res = tjDecompressToYUV2(
182160
tjh,
@@ -190,12 +168,16 @@ UNIFEX_TERM jpeg_to_yuv(UnifexEnv* env, UnifexPayload *payload) {
190168
if(res < 0) {
191169
ret = jpeg_to_yuv_result_error(env, tjGetErrorStr2(tjh));
192170
goto cleanup;
193-
} else {
194-
ret = jpeg_to_yuv_result_ok(env, yuvFrame);
195-
goto cleanup;
196171
}
172+
173+
ret = jpeg_to_yuv_result_ok(env, yuvFrame);
197174

198175
cleanup:
176+
if(yuvFrame != NULL) {
177+
unifex_payload_release(yuvFrame);
178+
unifex_free(yuvFrame);
179+
}
180+
199181
if(tjh) tjDestroy(tjh);
200182
return ret;
201183
}
Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
module Turbojpeg.Native
22

3-
spec yuv_to_jpeg(payload, width::int, height::int, quality::int, format::atom) :: {:ok :: label, payload} | {:error :: label, reason :: atom}
4-
spec jpeg_to_yuv(payload) :: {:ok :: label, payload} | {:error :: label, reason :: atom}
5-
spec get_jpeg_header(payload) :: {:ok :: label, data::int} | {:error::label, reason::atom}
6-
dirty :cpu, yuv_to_jpeg: 5, jpeg_to_yuv: 1, get_jpeg_header: 1
3+
type jpeg_header :: %Turbojpeg.JpegHeader{
4+
format: atom,
5+
width: int,
6+
height: int
7+
}
8+
9+
spec yuv_to_jpeg(payload, width::int, height::int, quality::int, format::atom) :: {:ok :: label, payload} | {:error :: label, reason :: string}
10+
spec jpeg_to_yuv(payload) :: {:ok :: label, payload} | {:error :: label, reason :: string}
11+
spec get_jpeg_header(payload) :: {:ok :: label, jpeg_header} | {:error::label, reason :: string}
12+
13+
dirty :cpu, yuv_to_jpeg: 5, jpeg_to_yuv: 1, get_jpeg_header: 1

lib/turbojpeg.ex

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
defmodule Turbojpeg do
22
@moduledoc File.read!("README.md")
3-
alias Turbojpeg.Native
3+
4+
alias Turbojpeg.{JpegHeader, Native}
45

56
@type width :: dimension
67
@type height :: dimension
@@ -11,14 +12,7 @@ defmodule Turbojpeg do
1112
| :I422
1213
| :I444
1314
| :GRAY
14-
@type error ::
15-
{:error, atom()}
16-
| {:error, struct}
17-
@type jpeg_header :: %{
18-
format: format(),
19-
width: width(),
20-
height: height()
21-
}
15+
@type error :: {:error, atom()} | {:error, struct}
2216

2317
@doc """
2418
Converts yuv to jpeg images
@@ -31,9 +25,6 @@ defmodule Turbojpeg do
3125
{:ok, binary()} | error()
3226
def yuv_to_jpeg(yuv, width, height, quality, format) do
3327
Native.yuv_to_jpeg(yuv, width, height, quality, format)
34-
rescue
35-
error ->
36-
{:error, error}
3728
end
3829

3930
@doc """
@@ -43,32 +34,30 @@ defmodule Turbojpeg do
4334
iex> {:ok, yuv} = Turbojpeg.jpeg_to_yuv(jpeg)
4435
{:ok,<<..>>}
4536
"""
46-
@spec jpeg_to_yuv(binary()) ::
47-
{:ok, binary()} | error()
37+
@spec jpeg_to_yuv(binary()) :: {:ok, binary()} | error()
4838
def jpeg_to_yuv(jpeg) do
4939
Native.jpeg_to_yuv(jpeg)
50-
rescue
51-
error ->
52-
{:error, error}
5340
end
5441

5542
@doc """
56-
Gets the header from a jpegv
43+
Gets the header from a jpeg binary
5744
58-
iex> {:ok, header} = Turbojpeg.get_jpeg_header(jpeg)
45+
## Examples
46+
47+
iex> {:ok, header} = Turbojpeg.get_jpeg_header(jpeg)
5948
{:ok,
60-
%{
49+
%Turbojpeg.JpegHeader{
6150
format: :I422,
6251
width: 192,
6352
height: 192
6453
}
6554
}
55+
56+
iex> Turbojpeg.get_jpeg_header(<<45, 48, 44, 41, 11>>)
57+
{:error, "Not a JPEG file: starts with 0x2d 0x30"}
6658
"""
67-
@spec get_jpeg_header(binary()) :: {:ok, jpeg_header} | error()
59+
@spec get_jpeg_header(binary()) :: {:ok, JpegHeader.t()} | error()
6860
def get_jpeg_header(jpeg) do
6961
Native.get_jpeg_header(jpeg)
70-
rescue
71-
error ->
72-
{:error, error}
7362
end
7463
end

lib/turbojpeg/filter.ex

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,49 @@ defmodule Turbojpeg.Filter do
33
Membrane filter converting raw video frames to JPEG.
44
"""
55
use Membrane.Filter
6+
67
alias Membrane.Buffer
8+
alias Membrane.RawVideo
9+
alias Membrane.RemoteStream
10+
11+
def_input_pad :input,
12+
flow_control: :auto,
13+
demand_unit: :buffers,
14+
accepted_format: %RawVideo{pixel_format: pix_fmt} when pix_fmt in [:I420, :I422, :I444]
715

8-
def_input_pad :input, demand_unit: :buffers, caps: Membrane.Caps.Video.Raw
9-
# TODO: implement JPEG caps
10-
def_output_pad :output, caps: :any
16+
# TODO: implement JPEG stream format
17+
def_output_pad :output, accepted_format: RemoteStream
1118

1219
def_options quality: [
13-
type: :integer,
1420
spec: Turbojpeg.quality(),
15-
default: 100,
21+
default: 75,
1622
description: "Jpeg encoding quality"
1723
]
1824

1925
@impl true
20-
def handle_demand(:output, size, :buffers, _ctx, state) do
21-
{{:ok, demand: {:input, size}}, state}
26+
def handle_init(_ctx, options) do
27+
{[], Map.from_struct(options)}
2228
end
2329

2430
@impl true
25-
def handle_caps(:input, _caps, _ctx, state) do
26-
{:ok, state}
31+
def handle_stream_format(:input, _stream_format, _ctx, state) do
32+
{[stream_format: {:output, %RemoteStream{type: :bytestream}}], state}
2733
end
2834

2935
@impl true
30-
def handle_process(:input, buffer, ctx, state) do
31-
%{caps: caps} = ctx.pads.input
32-
33-
with {:ok, payload} <-
34-
Turbojpeg.yuv_to_jpeg(
35-
buffer.payload,
36-
caps.width,
37-
caps.height,
38-
state.quality,
39-
caps.format
40-
) do
41-
buffer = %Buffer{buffer | payload: payload}
42-
{{:ok, buffer: {:output, buffer}}, state}
43-
else
44-
{:error, _} = error -> {error, state}
36+
def handle_process(:input, %Buffer{payload: payload} = buffer, ctx, state) do
37+
%{stream_format: stream_format} = ctx.pads.input
38+
%{width: width, height: height, pixel_format: pix_fmt} = stream_format
39+
40+
case Turbojpeg.yuv_to_jpeg(payload, width, height, state.quality, pix_fmt) do
41+
{:ok, jpeg} ->
42+
{[buffer: {:output, %Buffer{buffer | payload: jpeg}}], state}
43+
44+
error ->
45+
raise """
46+
could not create JPEG image
47+
#{inspect(error)}
48+
"""
4549
end
4650
end
4751
end

lib/turbojpeg/jpeg_header.ex

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
defmodule Turbojpeg.JpegHeader do
2+
@moduledoc false
3+
4+
@type t :: %__MODULE__{
5+
width: Turbojpeg.dimension(),
6+
height: Turbojpeg.dimension(),
7+
format: Turbojpeg.format()
8+
}
9+
10+
defstruct [:width, :height, :format]
11+
end

0 commit comments

Comments
 (0)