@lumen5/beamcoder 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/.circleci/config.yml +41 -0
  2. package/.circleci/images/testbeam10-4.1/Dockerfile +12 -0
  3. package/.circleci/test_image/Dockerfile +14 -0
  4. package/.circleci/test_image/build.md +13 -0
  5. package/.eslintrc.js +27 -0
  6. package/.github/workflows/publish-npm.yml +33 -0
  7. package/LICENSE +674 -0
  8. package/README.md +1221 -0
  9. package/beamstreams.js +692 -0
  10. package/binding.gyp +103 -0
  11. package/examples/encode_h264.js +92 -0
  12. package/examples/jpeg_app.js +55 -0
  13. package/examples/jpeg_filter_app.js +101 -0
  14. package/examples/make_mp4.js +123 -0
  15. package/images/beamcoder_small.jpg +0 -0
  16. package/index.d.ts +83 -0
  17. package/index.js +44 -0
  18. package/install_ffmpeg.js +240 -0
  19. package/package.json +45 -0
  20. package/scratch/decode_aac.js +38 -0
  21. package/scratch/decode_avci.js +50 -0
  22. package/scratch/decode_hevc.js +38 -0
  23. package/scratch/decode_pcm.js +39 -0
  24. package/scratch/make_a_mux.js +68 -0
  25. package/scratch/muxer.js +74 -0
  26. package/scratch/read_wav.js +35 -0
  27. package/scratch/simple_mux.js +39 -0
  28. package/scratch/stream_avci.js +127 -0
  29. package/scratch/stream_mp4.js +78 -0
  30. package/scratch/stream_mux.js +47 -0
  31. package/scratch/stream_pcm.js +82 -0
  32. package/scratch/stream_wav.js +62 -0
  33. package/scripts/install_beamcoder_dependencies.sh +25 -0
  34. package/src/adaptor.h +202 -0
  35. package/src/beamcoder.cc +937 -0
  36. package/src/beamcoder_util.cc +1129 -0
  37. package/src/beamcoder_util.h +206 -0
  38. package/src/codec.cc +7386 -0
  39. package/src/codec.h +44 -0
  40. package/src/codec_par.cc +1818 -0
  41. package/src/codec_par.h +40 -0
  42. package/src/decode.cc +569 -0
  43. package/src/decode.h +75 -0
  44. package/src/demux.cc +584 -0
  45. package/src/demux.h +88 -0
  46. package/src/encode.cc +496 -0
  47. package/src/encode.h +72 -0
  48. package/src/filter.cc +1888 -0
  49. package/src/filter.h +30 -0
  50. package/src/format.cc +5287 -0
  51. package/src/format.h +77 -0
  52. package/src/frame.cc +2681 -0
  53. package/src/frame.h +52 -0
  54. package/src/governor.cc +286 -0
  55. package/src/governor.h +30 -0
  56. package/src/hwcontext.cc +378 -0
  57. package/src/hwcontext.h +35 -0
  58. package/src/log.cc +186 -0
  59. package/src/log.h +20 -0
  60. package/src/mux.cc +834 -0
  61. package/src/mux.h +106 -0
  62. package/src/packet.cc +762 -0
  63. package/src/packet.h +49 -0
  64. package/test/codecParamsSpec.js +148 -0
  65. package/test/decoderSpec.js +56 -0
  66. package/test/demuxerSpec.js +41 -0
  67. package/test/encoderSpec.js +69 -0
  68. package/test/filtererSpec.js +47 -0
  69. package/test/formatSpec.js +343 -0
  70. package/test/frameSpec.js +145 -0
  71. package/test/introspectionSpec.js +73 -0
  72. package/test/muxerSpec.js +34 -0
  73. package/test/packetSpec.js +122 -0
  74. package/types/Beamstreams.d.ts +98 -0
  75. package/types/Codec.d.ts +123 -0
  76. package/types/CodecContext.d.ts +555 -0
  77. package/types/CodecPar.d.ts +108 -0
  78. package/types/Decoder.d.ts +137 -0
  79. package/types/Demuxer.d.ts +113 -0
  80. package/types/Encoder.d.ts +94 -0
  81. package/types/Filter.d.ts +324 -0
  82. package/types/FormatContext.d.ts +380 -0
  83. package/types/Frame.d.ts +295 -0
  84. package/types/HWContext.d.ts +62 -0
  85. package/types/Muxer.d.ts +121 -0
  86. package/types/Packet.d.ts +82 -0
  87. package/types/PrivClass.d.ts +25 -0
  88. package/types/Stream.d.ts +165 -0
@@ -0,0 +1,378 @@
1
+ /*
2
+ Aerostat Beam Coder - Node.js native bindings for FFmpeg.
3
+ Copyright (C) 2019 Streampunk Media Ltd.
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ https://www.streampunk.media/ mailto:furnace@streampunk.media
19
+ 14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
20
+ */
21
+
22
+ #include "hwcontext.h"
23
+
24
+ void hwContextFinalizer(napi_env env, void* data, void* hint) {
25
+ printf("Finalizing a hw context reference\n");
26
+ AVBufferRef* ctxRef = (AVBufferRef*) data;
27
+ av_buffer_unref(&ctxRef);
28
+ }
29
+
30
+ napi_value getHWDeviceCtxType(napi_env env, napi_callback_info info) {
31
+ napi_status status;
32
+ napi_value result;
33
+ AVHWDeviceContext* device_context;
34
+ const char* name;
35
+
36
+ status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &device_context);
37
+ CHECK_STATUS;
38
+
39
+ switch (device_context->type) {
40
+ case AV_HWDEVICE_TYPE_NONE:
41
+ name = "none";
42
+ break;
43
+ case AV_HWDEVICE_TYPE_VDPAU:
44
+ name = "vdpau";
45
+ break;
46
+ case AV_HWDEVICE_TYPE_CUDA:
47
+ name = "cuda";
48
+ break;
49
+ case AV_HWDEVICE_TYPE_VAAPI:
50
+ name = "vaapi";
51
+ break;
52
+ case AV_HWDEVICE_TYPE_DXVA2:
53
+ name = "dxva2";
54
+ break;
55
+ case AV_HWDEVICE_TYPE_QSV:
56
+ name = "qsv";
57
+ break;
58
+ case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
59
+ name = "videotoolbox";
60
+ break;
61
+ case AV_HWDEVICE_TYPE_D3D11VA:
62
+ name = "d3d11va";
63
+ break;
64
+ case AV_HWDEVICE_TYPE_DRM:
65
+ name = "drm";
66
+ break;
67
+ case AV_HWDEVICE_TYPE_OPENCL:
68
+ name = "opencl";
69
+ break;
70
+ case AV_HWDEVICE_TYPE_MEDIACODEC:
71
+ name = "mediacodec";
72
+ break;
73
+ // case AV_HWDEVICE_TYPE_VULKAN:
74
+ // name = "vulkan";
75
+ // break;
76
+ default:
77
+ name = nullptr;
78
+ break;
79
+ }
80
+
81
+ if (name == nullptr) {
82
+ status = napi_get_null(env, &result);
83
+ } else {
84
+ status = napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &result);
85
+ }
86
+ CHECK_STATUS;
87
+ return result;
88
+ }
89
+
90
+ napi_status fromHWDeviceContext(napi_env env, AVBufferRef* contextRef, napi_value* result) {
91
+ napi_status status;
92
+ napi_value jsHWDeviceContext, extContextRef, typeName;
93
+
94
+ status = napi_create_object(env, &jsHWDeviceContext);
95
+ PASS_STATUS;
96
+ status = napi_create_string_utf8(env, "HWDeviceContext", NAPI_AUTO_LENGTH, &typeName);
97
+ PASS_STATUS;
98
+ status = napi_create_external(env, (void*)av_buffer_ref(contextRef), hwContextFinalizer, nullptr, &extContextRef);
99
+ PASS_STATUS;
100
+
101
+ napi_property_descriptor desc[] = {
102
+ { "type", nullptr, nullptr, nullptr, nullptr, typeName, napi_enumerable, nullptr },
103
+ { "device_type", nullptr, nullptr, getHWDeviceCtxType, nullptr,
104
+ nullptr, napi_enumerable, (void*)contextRef->data },
105
+ { "_deviceContext", nullptr, nullptr, nullptr, nullptr, extContextRef, napi_default, nullptr }
106
+ };
107
+ status = napi_define_properties(env, jsHWDeviceContext, 3, desc);
108
+ PASS_STATUS;
109
+
110
+ *result = jsHWDeviceContext;
111
+ return napi_ok;
112
+ }
113
+
114
+ napi_value getHWFramesCtxHWDeviceCtx(napi_env env, napi_callback_info info) {
115
+ napi_status status;
116
+ napi_value result;
117
+ AVHWFramesContext* frames_context;
118
+
119
+ status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &frames_context);
120
+ CHECK_STATUS;
121
+
122
+ status = fromHWDeviceContext(env, frames_context->device_ref, &result);
123
+ CHECK_STATUS;
124
+
125
+ return result;
126
+ }
127
+
128
+ napi_value getHWFramesCtxInitialPoolSize(napi_env env, napi_callback_info info) {
129
+ napi_status status;
130
+ napi_value result;
131
+ AVHWFramesContext* frames_context;
132
+
133
+ status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &frames_context);
134
+ CHECK_STATUS;
135
+
136
+ status = napi_create_uint32(env, frames_context->initial_pool_size, &result);
137
+ CHECK_STATUS;
138
+
139
+ return result;
140
+ }
141
+
142
+ napi_value getHWFramesCtxPixFmt(napi_env env, napi_callback_info info) {
143
+ napi_status status;
144
+ napi_value result;
145
+ AVHWFramesContext* frames_context;
146
+
147
+ status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &frames_context);
148
+ CHECK_STATUS;
149
+
150
+ AVPixelFormat pixFmt = frames_context->format;
151
+ status = napi_create_string_utf8(env, av_get_pix_fmt_name(pixFmt), NAPI_AUTO_LENGTH, &result);
152
+ CHECK_STATUS;
153
+
154
+ return result;
155
+ }
156
+
157
+ napi_value setHWFramesCtxPixFmt(napi_env env, napi_callback_info info) {
158
+ napi_status status;
159
+ napi_value result;
160
+ napi_valuetype type;
161
+ AVHWFramesContext* frames_context;
162
+ char* name;
163
+ size_t strLen;
164
+ AVPixelFormat pixFmt;
165
+
166
+ size_t argc = 1;
167
+ napi_value args[1];
168
+ status = napi_get_cb_info(env, info, &argc, args, nullptr, (void**) &frames_context);
169
+ CHECK_STATUS;
170
+ if (argc < 1) {
171
+ NAPI_THROW_ERROR("A value is required to set the format property.");
172
+ }
173
+ status = napi_typeof(env, args[0], &type);
174
+ CHECK_STATUS;
175
+ if ((type == napi_null) || (type == napi_undefined)) {
176
+ frames_context->format = AV_PIX_FMT_NONE;
177
+ goto done;
178
+ }
179
+ if (type != napi_string) {
180
+ NAPI_THROW_ERROR("A string is required to set the format property.");
181
+ }
182
+ status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &strLen);
183
+ CHECK_STATUS;
184
+ name = (char*) malloc(sizeof(char) * (strLen + 1));
185
+ status = napi_get_value_string_utf8(env, args[0], name, strLen + 1, &strLen);
186
+ CHECK_STATUS;
187
+
188
+ pixFmt = av_get_pix_fmt((const char *) name);
189
+ free(name);
190
+ CHECK_STATUS;
191
+ if (pixFmt != AV_PIX_FMT_NONE) {
192
+ frames_context->format = pixFmt;
193
+ } else {
194
+ NAPI_THROW_ERROR("Pixel format name is not known.");
195
+ }
196
+
197
+ done:
198
+ status = napi_get_undefined(env, &result);
199
+ CHECK_STATUS;
200
+ return result;
201
+ }
202
+
203
+ napi_value getHWFramesCtxSwPixFmt(napi_env env, napi_callback_info info) {
204
+ napi_status status;
205
+ napi_value result;
206
+ AVHWFramesContext* frames_context;
207
+
208
+ status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &frames_context);
209
+ CHECK_STATUS;
210
+
211
+ AVPixelFormat pixFmt = frames_context->sw_format;
212
+ status = napi_create_string_utf8(env, av_get_pix_fmt_name(pixFmt), NAPI_AUTO_LENGTH, &result);
213
+ CHECK_STATUS;
214
+
215
+ return result;
216
+ }
217
+
218
+ napi_value setHWFramesCtxSwPixFmt(napi_env env, napi_callback_info info) {
219
+ napi_status status;
220
+ napi_value result;
221
+ napi_valuetype type;
222
+ AVHWFramesContext* frames_context;
223
+ char* name;
224
+ size_t strLen;
225
+ AVPixelFormat pixFmt;
226
+
227
+ size_t argc = 1;
228
+ napi_value args[1];
229
+ status = napi_get_cb_info(env, info, &argc, args, nullptr, (void**) &frames_context);
230
+ CHECK_STATUS;
231
+ if (argc < 1) {
232
+ NAPI_THROW_ERROR("A value is required to set the sw_format property.");
233
+ }
234
+ status = napi_typeof(env, args[0], &type);
235
+ CHECK_STATUS;
236
+ if ((type == napi_null) || (type == napi_undefined)) {
237
+ frames_context->sw_format = AV_PIX_FMT_NONE;
238
+ goto done;
239
+ }
240
+ if (type != napi_string) {
241
+ NAPI_THROW_ERROR("A string is required to set the sw_format property.");
242
+ }
243
+ status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &strLen);
244
+ CHECK_STATUS;
245
+ name = (char*) malloc(sizeof(char) * (strLen + 1));
246
+ status = napi_get_value_string_utf8(env, args[0], name, strLen + 1, &strLen);
247
+ CHECK_STATUS;
248
+
249
+ pixFmt = av_get_pix_fmt((const char *) name);
250
+ free(name);
251
+ CHECK_STATUS;
252
+ if (pixFmt != AV_PIX_FMT_NONE) {
253
+ frames_context->sw_format = pixFmt;
254
+ } else {
255
+ NAPI_THROW_ERROR("Pixel format name is not known.");
256
+ }
257
+
258
+ done:
259
+ status = napi_get_undefined(env, &result);
260
+ CHECK_STATUS;
261
+ return result;
262
+ }
263
+
264
+ napi_value getHWFramesCtxWidth(napi_env env, napi_callback_info info) {
265
+ napi_status status;
266
+ napi_value result;
267
+ AVHWFramesContext* frames_context;
268
+
269
+ status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &frames_context);
270
+ CHECK_STATUS;
271
+
272
+ status = napi_create_uint32(env, frames_context->width, &result);
273
+ CHECK_STATUS;
274
+
275
+ return result;
276
+ }
277
+
278
+ napi_value setHWFramesCtxWidth(napi_env env, napi_callback_info info) {
279
+ napi_status status;
280
+ napi_value result;
281
+ napi_valuetype type;
282
+ AVHWFramesContext* frames_context;
283
+
284
+ size_t argc = 1;
285
+ napi_value args[1];
286
+ status = napi_get_cb_info(env, info, &argc, args, nullptr, (void**) &frames_context);
287
+ CHECK_STATUS;
288
+ if (argc < 1) {
289
+ NAPI_THROW_ERROR("A value is required to set the width property.");
290
+ }
291
+ status = napi_typeof(env, args[0], &type);
292
+ CHECK_STATUS;
293
+ if (type != napi_number) {
294
+ NAPI_THROW_ERROR("A number is required to set the width property.");
295
+ }
296
+
297
+ status = napi_get_value_int32(env, args[0], &frames_context->width);
298
+ CHECK_STATUS;
299
+
300
+ status = napi_get_undefined(env, &result);
301
+ CHECK_STATUS;
302
+ return result;
303
+ }
304
+
305
+ napi_value getHWFramesCtxHeight(napi_env env, napi_callback_info info) {
306
+ napi_status status;
307
+ napi_value result;
308
+ AVHWFramesContext* frames_context;
309
+
310
+ status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &frames_context);
311
+ CHECK_STATUS;
312
+
313
+ status = napi_create_uint32(env, frames_context->height, &result);
314
+ CHECK_STATUS;
315
+
316
+ return result;
317
+ }
318
+
319
+ napi_value setHWFramesCtxHeight(napi_env env, napi_callback_info info) {
320
+ napi_status status;
321
+ napi_value result;
322
+ napi_valuetype type;
323
+ AVHWFramesContext* frames_context;
324
+
325
+ size_t argc = 1;
326
+ napi_value args[1];
327
+ status = napi_get_cb_info(env, info, &argc, args, nullptr, (void**) &frames_context);
328
+ CHECK_STATUS;
329
+ if (argc < 1) {
330
+ NAPI_THROW_ERROR("A value is required to set the height property.");
331
+ }
332
+ status = napi_typeof(env, args[0], &type);
333
+ CHECK_STATUS;
334
+ if (type != napi_number) {
335
+ NAPI_THROW_ERROR("A number is required to set the height property.");
336
+ }
337
+
338
+ status = napi_get_value_int32(env, args[0], &frames_context->height);
339
+ CHECK_STATUS;
340
+
341
+ status = napi_get_undefined(env, &result);
342
+ CHECK_STATUS;
343
+ return result;
344
+ }
345
+
346
+ napi_status fromHWFramesContext(napi_env env, AVBufferRef* contextRef, napi_value* result) {
347
+ napi_status status;
348
+ napi_value jsHWFramesContext, extContextRef, typeName;
349
+
350
+ status = napi_create_object(env, &jsHWFramesContext);
351
+ PASS_STATUS;
352
+ status = napi_create_string_utf8(env, "HWFramesContext", NAPI_AUTO_LENGTH, &typeName);
353
+ PASS_STATUS;
354
+ status = napi_create_external(env, (void*)av_buffer_ref(contextRef), hwContextFinalizer, nullptr, &extContextRef);
355
+ PASS_STATUS;
356
+
357
+ napi_property_descriptor desc[] = {
358
+ { "type", nullptr, nullptr, nullptr, nullptr, typeName, napi_enumerable, nullptr },
359
+ { "device_context", nullptr, nullptr, getHWFramesCtxHWDeviceCtx, nullptr, nullptr,
360
+ napi_enumerable, (void*)contextRef->data },
361
+ { "initial_pool_size", nullptr, nullptr, getHWFramesCtxInitialPoolSize, nullptr, nullptr,
362
+ napi_enumerable, (void*)contextRef->data },
363
+ { "pix_fmt", nullptr, nullptr, getHWFramesCtxPixFmt, setHWFramesCtxPixFmt, nullptr,
364
+ napi_enumerable, (void*)contextRef->data },
365
+ { "sw_pix_fmt", nullptr, nullptr, getHWFramesCtxSwPixFmt, setHWFramesCtxSwPixFmt, nullptr,
366
+ napi_enumerable, (void*)contextRef->data },
367
+ { "width", nullptr, nullptr, getHWFramesCtxWidth, setHWFramesCtxWidth, nullptr,
368
+ (napi_property_attributes) (napi_writable | napi_enumerable), (void*)contextRef->data },
369
+ { "height", nullptr, nullptr, getHWFramesCtxHeight, setHWFramesCtxHeight, nullptr,
370
+ (napi_property_attributes) (napi_writable | napi_enumerable), (void*)contextRef->data },
371
+ { "_framesContext", nullptr, nullptr, nullptr, nullptr, extContextRef, napi_default, nullptr }
372
+ };
373
+ status = napi_define_properties(env, jsHWFramesContext, 8, desc);
374
+ PASS_STATUS;
375
+
376
+ *result = jsHWFramesContext;
377
+ return napi_ok;
378
+ }
@@ -0,0 +1,35 @@
1
+ /*
2
+ Aerostat Beam Coder - Node.js native bindings for FFmpeg.
3
+ Copyright (C) 2019 Streampunk Media Ltd.
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ https://www.streampunk.media/ mailto:furnace@streampunk.media
19
+ 14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
20
+ */
21
+
22
+ #ifndef HWCONTEXT_H
23
+ #define HWCONTEXT_H
24
+
25
+ #include "node_api.h"
26
+ #include "beamcoder_util.h"
27
+
28
+ extern "C" {
29
+ #include <libavutil/hwcontext.h>
30
+ }
31
+
32
+ napi_status fromHWDeviceContext(napi_env env, AVBufferRef* contextRef, napi_value* result);
33
+ napi_status fromHWFramesContext(napi_env env, AVBufferRef* contextRef, napi_value* result);
34
+
35
+ #endif // HWCONTEXT_H
package/src/log.cc ADDED
@@ -0,0 +1,186 @@
1
+ #include "node_api.h"
2
+ #include <stdio.h>
3
+ #include "log.h"
4
+
5
+
6
+ extern "C" {
7
+ #include <libavutil/log.h>
8
+ #include <libavutil/bprint.h>
9
+ }
10
+
11
+ std::unordered_map<int, std::string> beam_logging_level_fmap = {
12
+ { AV_LOG_QUIET, "quiet" },
13
+ { AV_LOG_PANIC, "panic" },
14
+ { AV_LOG_FATAL, "fatal" },
15
+ { AV_LOG_ERROR, "error" },
16
+ { AV_LOG_WARNING, "warning" },
17
+ { AV_LOG_INFO, "info" },
18
+ { AV_LOG_VERBOSE, "verbose" },
19
+ { AV_LOG_DEBUG, "debug" },
20
+ { AV_LOG_TRACE, "trace" }
21
+ };
22
+
23
+ const beamEnum* beam_logging_level = new beamEnum(beam_logging_level_fmap);
24
+
25
+ napi_value logging(napi_env env, napi_callback_info info) {
26
+ napi_status status;
27
+ napi_value result;
28
+ int logLevel;
29
+ char* logLevelStr;
30
+ size_t strLen;
31
+
32
+ napi_value args[1];
33
+ size_t argc = 1;
34
+ status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
35
+ CHECK_STATUS;
36
+
37
+ if (argc == 0) {
38
+ logLevel = av_log_get_level();
39
+ status = napi_create_string_utf8(env,
40
+ (char*) beam_lookup_name(beam_logging_level->forward, logLevel),
41
+ NAPI_AUTO_LENGTH, &result);
42
+ CHECK_STATUS;
43
+ } else {
44
+ if (argc != 1) {
45
+ status = napi_throw_error(env, nullptr, "Wrong number of arguments to set log level.");
46
+ return nullptr;
47
+ }
48
+
49
+ napi_value params = args[0];
50
+ napi_valuetype t;
51
+ status = napi_typeof(env, params, &t);
52
+ CHECK_STATUS;
53
+ if (t != napi_string) {
54
+ status = napi_throw_type_error(env, nullptr, "Logging level parameter must be a string.");
55
+ return nullptr;
56
+ }
57
+
58
+ status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &strLen);
59
+ CHECK_STATUS;
60
+ logLevelStr = (char*) malloc(sizeof(char) * (strLen + 1));
61
+ CHECK_STATUS;
62
+ status = napi_get_value_string_utf8(env, args[0], logLevelStr, strLen + 1, &strLen);
63
+ CHECK_STATUS;
64
+
65
+ logLevel = beam_lookup_enum(beam_logging_level->inverse, logLevelStr);
66
+ if (logLevel == BEAM_ENUM_UNKNOWN) {
67
+ NAPI_THROW_ERROR("Logging level string unrecognised");
68
+ }
69
+ av_log_set_level(logLevel);
70
+
71
+ status = napi_get_undefined(env, &result);
72
+ CHECK_STATUS;
73
+ }
74
+
75
+ return result;
76
+ }
77
+
78
+ napi_threadsafe_function threadSafeFunction;
79
+
80
+ // Inspired from https://github.com/FFmpeg/FFmpeg/blob/321a3c244d0a89b2826c38611284cc403a9808fa/libavutil/log.c#L346
81
+ #define LINE_SZ 1024
82
+ void av_log_custom_callback(void* ptr, int level, const char* fmt, va_list vl)
83
+ {
84
+ int av_log_level = av_log_get_level();
85
+ static int print_prefix = 1;
86
+ static int count;
87
+ static char prev[LINE_SZ];
88
+ AVBPrint part[4];
89
+ char line[LINE_SZ];
90
+ static int is_atty;
91
+ int type[2];
92
+ unsigned tint = 0;
93
+
94
+ if (level >= 0) {
95
+ tint = level & 0xff00;
96
+ level &= 0xff;
97
+ }
98
+
99
+ if (level > av_log_level)
100
+ return;
101
+ av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);
102
+
103
+ logCarrier* c = new logCarrier;
104
+ c->msg = line;
105
+ c->level = level;
106
+ napi_status status;
107
+
108
+ status = napi_call_threadsafe_function(threadSafeFunction, c, napi_tsfn_nonblocking);
109
+
110
+ return;
111
+ }
112
+
113
+ static void callJsCb(
114
+ napi_env env,
115
+ napi_value jsCallback,
116
+ void* context,
117
+ void* data
118
+ ){
119
+
120
+ logCarrier* c = (logCarrier*) data;
121
+
122
+ napi_value jsThis;
123
+ napi_status status;
124
+
125
+ status = napi_create_object(env, &jsThis);
126
+ CHECK_STATUS_VOID;
127
+
128
+ napi_value jsStr;
129
+ status = napi_create_string_utf8(env, c->msg.c_str(), NAPI_AUTO_LENGTH, &jsStr);
130
+ CHECK_STATUS_VOID;
131
+
132
+ napi_value return_val;
133
+ status = napi_call_function(env, jsThis, jsCallback, 1, &jsStr, &return_val);
134
+ CHECK_STATUS_VOID;
135
+
136
+ return;
137
+ }
138
+
139
+ napi_value setLoggingCallback(napi_env env, napi_callback_info info){
140
+
141
+ napi_status status;
142
+
143
+ napi_value args[1];
144
+ size_t argc = 1;
145
+ status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
146
+ CHECK_STATUS;
147
+
148
+ if (argc != 1) {
149
+ status = napi_throw_error(env, nullptr, "One argument required to set logging callback.");
150
+ return nullptr;
151
+ }
152
+ napi_value callback = args[0];
153
+ napi_valuetype t;
154
+ status = napi_typeof(env, callback, &t);
155
+ CHECK_STATUS;
156
+
157
+ if (t != napi_function) {
158
+ status = napi_throw_type_error(env, nullptr, "Callback argument should be a function.");
159
+ return nullptr;
160
+ }
161
+
162
+ napi_value work_name;
163
+ status = napi_create_string_utf8(env, "Thread-safe Function For Libav Custom Logging", NAPI_AUTO_LENGTH, &work_name);
164
+ CHECK_STATUS;
165
+
166
+ status = napi_create_threadsafe_function(
167
+ env,
168
+ callback,
169
+ NULL,
170
+ work_name,
171
+ 0,
172
+ 1,
173
+ nullptr,
174
+ nullptr,
175
+ nullptr,
176
+ callJsCb,
177
+ &threadSafeFunction
178
+ );
179
+ CHECK_STATUS;
180
+
181
+ status = napi_unref_threadsafe_function(env, threadSafeFunction);
182
+ CHECK_STATUS;
183
+
184
+ av_log_set_callback(av_log_custom_callback);
185
+ return nullptr;
186
+ }
package/src/log.h ADDED
@@ -0,0 +1,20 @@
1
+ #ifndef BEAMCODER_LOG_H
2
+ #define BEAMCODER_LOG_H
3
+
4
+ #include "node_api.h"
5
+ #include "beamcoder_util.h"
6
+ #include <stdio.h>
7
+ #include <unordered_map>
8
+
9
+ #define CHECK_STATUS_VOID if (checkStatus(env, status, __FILE__, __LINE__ - 1) != napi_ok) return
10
+
11
+ extern const beamEnum* beam_logging_level;
12
+ napi_value logging(napi_env env, napi_callback_info info);
13
+ napi_value setLoggingCallback(napi_env env, napi_callback_info info);
14
+
15
+ struct logCarrier : carrier {
16
+ std::string msg;
17
+ int level;
18
+ };
19
+
20
+ #endif // BEAMCODER_LOG_H