Skip to content

Commit 5d1be1f

Browse files
author
Connor Rigby
committed
Initial commit
0 parents  commit 5d1be1f

File tree

17 files changed

+397
-0
lines changed

17 files changed

+397
-0
lines changed

.formatter.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter,bundlex}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]

.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where third-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# Ignore .fetch files in case you like to edit your project deps locally.
14+
/.fetch
15+
16+
# If the VM crashes, it generates a dump, let's ignore it too.
17+
erl_crash.dump
18+
19+
# Also ignore archive artifacts (built via "mix archive.build").
20+
*.ez
21+
22+
# Ignore package tarball (built via "mix hex.build").
23+
turbojpeg-*.tar
24+

LICENSE

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2020 BinaryNoggin
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# TurboJPEG
2+
3+
Fast JPEG encoding from raw YUV data using [libjpeg-turbo](https://libjpeg-turbo.org/)
4+
5+
## Installation
6+
7+
This library requires libjpeg-turbo to be installed
8+
9+
### Arch linux
10+
11+
sudo pacman -S libjpeg-turbo
12+
13+
### Ubuntu/Debian
14+
15+
sudo apt-get install libjpeg-turbo
16+
17+
### OSX
18+
19+
brew install libjpeg-turbo
20+
21+
If [available in Hex](https://hex.pm/turbojpeg/), the package can be installed
22+
by adding `turbojpeg` to your list of dependencies in `mix.exs`:
23+
24+
```elixir
25+
def deps do
26+
[
27+
{:shmex, "~> 0.2.0"},
28+
{:turbojpeg, "~> 0.1.0"}
29+
]
30+
end
31+
```
32+
33+
## Basic Usage
34+
35+
```elixir
36+
iex(1)> {:ok, native} = Turbojpeg.Native.create(1920, 1080, 90, :I420)
37+
{:ok, #Reference<0.938325095.2990669826.234059>}
38+
iex(2)> frame = File.read!("fixture/i420.yuv")
39+
<<0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40+
0, 0, 0, 2, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...>>
41+
iex(3)> Turbojpeg.Native.to_jpeg(Shmex.new(frame), native)
42+
{:ok,
43+
%Shmex{
44+
capacity: 203783,
45+
guard: #Reference<0.938325095.2990669827.232440>,
46+
name: "/shmex-00000005607042890133#000",
47+
size: 203783
48+
}}
49+
iex(4)> Shmex.to_binary(jpeg)
50+
<<255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255,
51+
219, 0, 67, 0, 3, 2, 2, 3, 2, 2, 3, 3, 3, 3, 4, 3, 3, 4, 5, 8, 5, 5, 4, 4, 5,
52+
10, 7, 7, 6, ...>>
53+
iex(5)> File.write!("test.jpg", Shmex.to_binary(jpeg))
54+
:ok
55+
```
56+
57+
## Membrane Sink Usage
58+
59+
Pleas See [the membrane guide](https://membraneframework.org/guide/v0.5/pipeline.html#content)
60+
before using this.
61+
62+
```elixir
63+
defmodule Your.Module.Pipeline do
64+
use Membrane.Pipeline
65+
66+
@impl true
67+
def handle_init(location) do
68+
children = %{
69+
source: %SomeMembraneSourceModule{location: location},
70+
decoder: Membrane.Element.FFmpeg.H264.Decoder,
71+
jpeg_converter: %Turbojpeg.Sink{filename: "/tmp/frame.jpeg", quality: 100},
72+
}
73+
74+
links = [
75+
link(:source)
76+
|> to(:decoder)
77+
|> to(:jpeg_converter)
78+
]
79+
80+
spec = %ParentSpec{
81+
children: children,
82+
links: links
83+
}
84+
85+
{{:ok, spec: spec}, %{}}
86+
end
87+
88+
end
89+
```
90+
91+
# Copyright and License
92+
93+
Copyright 2020, Binary Noggin

bundlex.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
defmodule Turbojpeg.BundlexProject do
2+
use Bundlex.Project
3+
4+
def project() do
5+
[
6+
nifs: nifs(Bundlex.platform())
7+
]
8+
end
9+
10+
def nifs(_platform) do
11+
[
12+
turbojpeg_native: [
13+
deps: [unifex: :unifex, shmex: :lib],
14+
src_base: "turbojpeg_native",
15+
sources: ["_generated/turbojpeg_native.c", "turbojpeg_native.c"],
16+
pkg_configs: ["libturbojpeg"]
17+
]
18+
]
19+
end
20+
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.c
2+
*.h
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include "turbojpeg_native.h"
2+
3+
/**
4+
* Supported pixel formats: :I420 | :I422 | :I444
5+
* Unsupported pixel formats: :RGB | :BGRA | :RGBA | :NV12 | :NV21 | :YV12 | :AYUV
6+
*/
7+
UNIFEX_TERM create(UnifexEnv *env, int width, int height, int jpegQuality, char *format) {
8+
UNIFEX_TERM res;
9+
State *state = unifex_alloc_state(env);
10+
state->width = width; state->height = height;
11+
state->flags = 0; state->quality = jpegQuality;
12+
if(strcmp(format, "I420") == 0) {
13+
state->format = TJSAMP_420;
14+
} else if(strcmp(format, "I422") == 0) {
15+
state->format = TJSAMP_422;
16+
} else if(strcmp(format, "I444") == 0) {
17+
state->format = TJSAMP_444;
18+
} else {
19+
res = create_result_error(env, "unsupported_format");
20+
unifex_release_state(env, state);
21+
return(res);
22+
}
23+
res = create_result_ok(env, state);
24+
unifex_release_state(env, state);
25+
return(res);
26+
}
27+
28+
/**
29+
* Convert a binary h264 payload into a jpeg encoded payload
30+
*/
31+
UNIFEX_TERM to_jpeg(UnifexEnv* env, UnifexPayload *payload, State *state) {
32+
state->tjh = tjInitCompress();
33+
34+
unsigned char *jpegBuf = NULL;
35+
unsigned long jpegSize;
36+
37+
int res = tjCompressFromYUV(
38+
state->tjh,
39+
payload->data,
40+
state->width, 4, state->height, state->format,
41+
&jpegBuf, &jpegSize,
42+
state->quality, state->flags
43+
);
44+
45+
if(res) {
46+
return to_jpeg_result_error(env, tjGetErrorStr());
47+
} else {
48+
UnifexPayload *jpegFrame = unifex_payload_alloc(env, UNIFEX_PAYLOAD_SHM, jpegSize);
49+
memcpy(jpegFrame->data, jpegBuf, jpegSize);
50+
tjFree(jpegBuf);
51+
return to_jpeg_result_ok(env, jpegFrame);
52+
}
53+
}
54+
55+
void handle_destroy_state(UnifexEnv* env, State* state) {
56+
UNIFEX_UNUSED(env);
57+
if(state->tjh) { tjDestroy(state->tjh); }
58+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#pragma once
2+
3+
#include <erl_nif.h>
4+
#include <turbojpeg.h>
5+
6+
/** NIF State */
7+
typedef struct _h264_parser_state {
8+
/** Handle to turbojpeg */
9+
tjhandle tjh;
10+
enum TJSAMP format;
11+
int flags;
12+
int width; int height; int quality;
13+
} UnifexNifState;
14+
15+
/** NIF State */
16+
typedef UnifexNifState State;
17+
18+
#include "_generated/turbojpeg_native.h"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module Turbojpeg.Native
2+
3+
spec create(width::int, height::int, quality::int, format::atom) :: {:ok :: label, state} | {:error :: label, reason :: atom}
4+
spec to_jpeg(payload, state) :: {:ok :: label, payload} | {:error :: label, reason :: atom}

fixture/i420.yuv

2.97 MB
Binary file not shown.

0 commit comments

Comments
 (0)