4
4
* Supported pixel formats: :I420 | :I422 | :I444
5
5
* Unsupported pixel formats: :RGB | :BGRA | :RGBA | :NV12 | :NV21 | :YV12 | :AYUV
6
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 ;
7
+ int format_to_tjsamp (char * format ) {
12
8
if (strcmp (format , "I420" ) == 0 ) {
13
- state -> format = TJSAMP_420 ;
9
+ return TJSAMP_420 ;
14
10
} else if (strcmp (format , "I422" ) == 0 ) {
15
- state -> format = TJSAMP_422 ;
11
+ return TJSAMP_422 ;
16
12
} else if (strcmp (format , "I444" ) == 0 ) {
17
- state -> format = TJSAMP_444 ;
13
+ return TJSAMP_444 ;
18
14
} else {
19
- res = create_result_error (env , "unsupported_format" );
20
- unifex_release_state (env , state );
21
- return (res );
15
+ return -1 ;
22
16
}
23
- res = create_result_ok (env , state );
24
- unifex_release_state (env , state );
25
- return (res );
17
+ }
18
+
19
+ /**
20
+ * Supported pixel formats: :I420 | :I422 | :I444
21
+ * Unsupported pixel formats: :RGB | :BGRA | :RGBA | :NV12 | :NV21 | :YV12 | :AYUV
22
+ */
23
+ const char * tjsamp_to_format (enum TJSAMP tjsamp ) {
24
+ switch (tjsamp ) {
25
+ case (TJSAMP_420 ):
26
+ return ("I420" );
27
+ case (TJSAMP_422 ):
28
+ return ("I422" );
29
+ case (TJSAMP_444 ):
30
+ return ("I444" );
31
+ default :
32
+ return ("unknown_format" );
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Returns %{height: int, width: int, format: atom}
38
+ */
39
+ UNIFEX_TERM get_jpeg_header (UnifexEnv * env , UnifexPayload * payload ) {
40
+ tjhandle tjh ;
41
+ enum TJSAMP tjsamp ;
42
+ enum TJCS cspace ;
43
+ int res , width , height ;
44
+ ERL_NIF_TERM map_out , ret ;
45
+
46
+ tjh = tjInitDecompress ();
47
+ if (!tjh )
48
+ return get_jpeg_header_result_error (env , tjGetErrorStr ());
49
+
50
+ res = tjDecompressHeader3 (
51
+ tjh ,
52
+ payload -> data ,
53
+ payload -> size ,
54
+ & width , & height ,
55
+ (int * )& tjsamp , (int * )& cspace
56
+ );
57
+ if (res < 0 ) {
58
+ ret = get_jpeg_header_result_error (env , tjGetErrorStr2 (tjh ));
59
+ goto cleanup ;
60
+ }
61
+
62
+ // unifex does not support maps yes.
63
+ // See https://github.com/membraneframework/unifex/issues/32
64
+ if (!enif_make_map_from_arrays (
65
+ env ,
66
+ (ERL_NIF_TERM []) {
67
+ enif_make_atom (env , "width" ),
68
+ enif_make_atom (env , "height" ),
69
+ enif_make_atom (env , "format" ),
70
+
71
+ },
72
+ (ERL_NIF_TERM []) {
73
+ enif_make_int (env , width ),
74
+ enif_make_int (env , height ),
75
+ enif_make_atom (env , tjsamp_to_format (tjsamp ))
76
+ },
77
+ 3 , & map_out
78
+ )) {
79
+ ret = get_jpeg_header_result_error (env , "make_map" );
80
+ goto cleanup ;
81
+ } else {
82
+ // Generated code does not support maps currently.
83
+ ret = enif_make_tuple_from_array (env , (ERL_NIF_TERM []) {enif_make_atom (env , "ok" ), map_out }, 2 );
84
+ goto cleanup ;
85
+ }
86
+ cleanup :
87
+ if (tjh ) tjDestroy (tjh );
88
+ return ret ;
26
89
}
27
90
28
91
/**
29
92
* Convert a binary h264 payload into a jpeg encoded payload
30
93
*/
31
- UNIFEX_TERM to_jpeg (UnifexEnv * env , UnifexPayload * payload , State * state ) {
32
- state -> tjh = tjInitCompress () ;
33
-
94
+ UNIFEX_TERM yuv_to_jpeg (UnifexEnv * env , UnifexPayload * payload , int width , int height , int quality , char * format ) {
95
+ tjhandle tjh = NULL ;
96
+ enum TJSAMP tjsamp ;
34
97
unsigned char * jpegBuf = NULL ;
35
98
unsigned long jpegSize ;
99
+ int res ;
100
+ UnifexPayload * jpegFrame ;
101
+ UNIFEX_TERM ret ;
36
102
37
- int res = tjCompressFromYUV (
38
- state -> tjh ,
103
+ res = format_to_tjsamp (format );
104
+ if (res < 0 ) {
105
+ return (yuv_to_jpeg_result_error (env , "unsupported_format" ));
106
+ } else {
107
+ tjsamp = (enum TJSAMP )res ;
108
+ }
109
+
110
+ tjh = tjInitCompress ();
111
+ if (!tjh )
112
+ return yuv_to_jpeg_result_error (env , tjGetErrorStr ());
113
+
114
+ res = tjCompressFromYUV (
115
+ tjh ,
39
116
payload -> data ,
40
- state -> width , 4 , state -> height , state -> format ,
117
+ width , 4 , height , tjsamp ,
41
118
& jpegBuf , & jpegSize ,
42
- state -> quality , state -> flags
119
+ quality , 0
43
120
);
44
121
45
- if (res ) {
46
- return to_jpeg_result_error (env , tjGetErrorStr ());
122
+ if (res < 0 ) {
123
+ ret = yuv_to_jpeg_result_error (env , tjGetErrorStr2 (tjh ));
124
+ goto cleanup ;
47
125
} 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 );
126
+ jpegFrame = unifex_payload_alloc (env , UNIFEX_PAYLOAD_SHM , jpegSize );
127
+ if (!jpegFrame ) {
128
+ ret = yuv_to_jpeg_result_error (env , "payload_alloc" );
129
+ } else {
130
+ memcpy (jpegFrame -> data , jpegBuf , jpegSize );
131
+ ret = yuv_to_jpeg_result_ok (env , jpegFrame );
132
+ }
133
+ goto cleanup ;
52
134
}
135
+
136
+ cleanup :
137
+ if (jpegBuf ) tjFree (jpegBuf );
138
+ if (tjh ) tjDestroy (tjh );
139
+ return ret ;
140
+ }
141
+
142
+ /**
143
+ * Convert a binary jpeg payload into a yuv encoded payload
144
+ */
145
+ UNIFEX_TERM jpeg_to_yuv (UnifexEnv * env , UnifexPayload * payload ) {
146
+ tjhandle tjh ;
147
+ enum TJSAMP tjsamp ;
148
+ enum TJCS cspace ;
149
+ unsigned long yuvBufSize ;
150
+ UnifexPayload * yuvFrame ;
151
+ int res , width , height ;
152
+ UNIFEX_TERM ret ;
153
+
154
+ tjh = tjInitDecompress ();
155
+ if (!tjh )
156
+ return jpeg_to_yuv_result_error (env , tjGetErrorStr ());
157
+
158
+ res = tjDecompressHeader3 (
159
+ tjh ,
160
+ payload -> data ,
161
+ payload -> size ,
162
+ & width , & height ,
163
+ (int * )& tjsamp , (int * )& cspace
164
+ );
165
+ if (res < 0 ) {
166
+ ret = jpeg_to_yuv_result_error (env , tjGetErrorStr2 (tjh ));
167
+ goto cleanup ;
168
+ }
169
+
170
+ yuvBufSize = tjBufSizeYUV2 (width , 4 , height , tjsamp );
171
+ yuvFrame = unifex_payload_alloc (env , UNIFEX_PAYLOAD_SHM , yuvBufSize );
172
+ if (!yuvFrame ) {
173
+ ret = jpeg_to_yuv_result_error (env , "could not allocate frame" );
174
+ goto cleanup ;
175
+ }
176
+
177
+ res = tjDecompressToYUV2 (
178
+ tjh ,
179
+ payload -> data ,
180
+ payload -> size ,
181
+ yuvFrame -> data ,
182
+ width , 4 , height ,
183
+ 0
184
+ );
185
+
186
+ if (res < 0 ) {
187
+ ret = jpeg_to_yuv_result_error (env , tjGetErrorStr2 (tjh ));
188
+ goto cleanup ;
189
+ } else {
190
+ ret = jpeg_to_yuv_result_ok (env , yuvFrame );
191
+ goto cleanup ;
192
+ }
193
+
194
+ cleanup :
195
+ if (tjh ) tjDestroy (tjh );
196
+ return ret ;
53
197
}
54
198
55
199
void handle_destroy_state (UnifexEnv * env , State * state ) {
56
200
UNIFEX_UNUSED (env );
57
- if (state -> tjh ) { tjDestroy ( state -> tjh ); }
201
+ UNIFEX_UNUSED (state );
58
202
}
0 commit comments