@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.
- package/.circleci/config.yml +41 -0
- package/.circleci/images/testbeam10-4.1/Dockerfile +12 -0
- package/.circleci/test_image/Dockerfile +14 -0
- package/.circleci/test_image/build.md +13 -0
- package/.eslintrc.js +27 -0
- package/.github/workflows/publish-npm.yml +33 -0
- package/LICENSE +674 -0
- package/README.md +1221 -0
- package/beamstreams.js +692 -0
- package/binding.gyp +103 -0
- package/examples/encode_h264.js +92 -0
- package/examples/jpeg_app.js +55 -0
- package/examples/jpeg_filter_app.js +101 -0
- package/examples/make_mp4.js +123 -0
- package/images/beamcoder_small.jpg +0 -0
- package/index.d.ts +83 -0
- package/index.js +44 -0
- package/install_ffmpeg.js +240 -0
- package/package.json +45 -0
- package/scratch/decode_aac.js +38 -0
- package/scratch/decode_avci.js +50 -0
- package/scratch/decode_hevc.js +38 -0
- package/scratch/decode_pcm.js +39 -0
- package/scratch/make_a_mux.js +68 -0
- package/scratch/muxer.js +74 -0
- package/scratch/read_wav.js +35 -0
- package/scratch/simple_mux.js +39 -0
- package/scratch/stream_avci.js +127 -0
- package/scratch/stream_mp4.js +78 -0
- package/scratch/stream_mux.js +47 -0
- package/scratch/stream_pcm.js +82 -0
- package/scratch/stream_wav.js +62 -0
- package/scripts/install_beamcoder_dependencies.sh +25 -0
- package/src/adaptor.h +202 -0
- package/src/beamcoder.cc +937 -0
- package/src/beamcoder_util.cc +1129 -0
- package/src/beamcoder_util.h +206 -0
- package/src/codec.cc +7386 -0
- package/src/codec.h +44 -0
- package/src/codec_par.cc +1818 -0
- package/src/codec_par.h +40 -0
- package/src/decode.cc +569 -0
- package/src/decode.h +75 -0
- package/src/demux.cc +584 -0
- package/src/demux.h +88 -0
- package/src/encode.cc +496 -0
- package/src/encode.h +72 -0
- package/src/filter.cc +1888 -0
- package/src/filter.h +30 -0
- package/src/format.cc +5287 -0
- package/src/format.h +77 -0
- package/src/frame.cc +2681 -0
- package/src/frame.h +52 -0
- package/src/governor.cc +286 -0
- package/src/governor.h +30 -0
- package/src/hwcontext.cc +378 -0
- package/src/hwcontext.h +35 -0
- package/src/log.cc +186 -0
- package/src/log.h +20 -0
- package/src/mux.cc +834 -0
- package/src/mux.h +106 -0
- package/src/packet.cc +762 -0
- package/src/packet.h +49 -0
- package/test/codecParamsSpec.js +148 -0
- package/test/decoderSpec.js +56 -0
- package/test/demuxerSpec.js +41 -0
- package/test/encoderSpec.js +69 -0
- package/test/filtererSpec.js +47 -0
- package/test/formatSpec.js +343 -0
- package/test/frameSpec.js +145 -0
- package/test/introspectionSpec.js +73 -0
- package/test/muxerSpec.js +34 -0
- package/test/packetSpec.js +122 -0
- package/types/Beamstreams.d.ts +98 -0
- package/types/Codec.d.ts +123 -0
- package/types/CodecContext.d.ts +555 -0
- package/types/CodecPar.d.ts +108 -0
- package/types/Decoder.d.ts +137 -0
- package/types/Demuxer.d.ts +113 -0
- package/types/Encoder.d.ts +94 -0
- package/types/Filter.d.ts +324 -0
- package/types/FormatContext.d.ts +380 -0
- package/types/Frame.d.ts +295 -0
- package/types/HWContext.d.ts +62 -0
- package/types/Muxer.d.ts +121 -0
- package/types/Packet.d.ts +82 -0
- package/types/PrivClass.d.ts +25 -0
- package/types/Stream.d.ts +165 -0
package/src/encode.cc
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
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 "encode.h"
|
|
23
|
+
|
|
24
|
+
napi_value encoder(napi_env env, napi_callback_info info) {
|
|
25
|
+
napi_status status;
|
|
26
|
+
napi_value value, result, global, jsObject, assign, jsParams;
|
|
27
|
+
napi_valuetype type;
|
|
28
|
+
bool isArray, hasName, hasID, hasParams;
|
|
29
|
+
char* codecName = nullptr;
|
|
30
|
+
size_t codecNameLen = 0;
|
|
31
|
+
int32_t codecID = -1;
|
|
32
|
+
const AVCodec* codec = nullptr;
|
|
33
|
+
const AVCodecDescriptor* codecDesc = nullptr;
|
|
34
|
+
AVCodecContext* encoder;
|
|
35
|
+
AVCodecParameters* codecParams = nullptr;
|
|
36
|
+
int ret;
|
|
37
|
+
|
|
38
|
+
size_t argc = 1;
|
|
39
|
+
napi_value args[1];
|
|
40
|
+
|
|
41
|
+
status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
|
|
42
|
+
CHECK_STATUS;
|
|
43
|
+
|
|
44
|
+
if (argc != 1) {
|
|
45
|
+
NAPI_THROW_ERROR("Encoder requires a single options object.");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
status = napi_typeof(env, args[0], &type);
|
|
49
|
+
CHECK_STATUS;
|
|
50
|
+
status = napi_is_array(env, args[0], &isArray);
|
|
51
|
+
CHECK_STATUS;
|
|
52
|
+
if ((type != napi_object) || (isArray == true)) {
|
|
53
|
+
NAPI_THROW_ERROR("Encoder must be configured with a single parameter, an options object.");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
status = napi_has_named_property(env, args[0], "name", &hasName);
|
|
57
|
+
CHECK_STATUS;
|
|
58
|
+
status = napi_has_named_property(env, args[0], "codec_id", &hasID);
|
|
59
|
+
CHECK_STATUS;
|
|
60
|
+
status = napi_has_named_property(env, args[0], "params", &hasParams);
|
|
61
|
+
CHECK_STATUS;
|
|
62
|
+
|
|
63
|
+
if (!(hasName || hasID || hasParams)) {
|
|
64
|
+
NAPI_THROW_ERROR("Decoder must be identified with a 'codec_id', a 'name' or 'params'.");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (hasParams) {
|
|
68
|
+
status = napi_get_named_property(env, args[0], "params", &value);
|
|
69
|
+
CHECK_STATUS;
|
|
70
|
+
status = napi_get_named_property(env, value, "_codecPar", &jsParams);
|
|
71
|
+
CHECK_STATUS;
|
|
72
|
+
status = napi_typeof(env, jsParams, &type);
|
|
73
|
+
CHECK_STATUS;
|
|
74
|
+
if (type != napi_external) {
|
|
75
|
+
NAPI_THROW_ERROR("The provided parameters do not appear to be a valid codec parameters object.");
|
|
76
|
+
}
|
|
77
|
+
status = napi_get_value_external(env, jsParams, (void**) &codecParams);
|
|
78
|
+
CHECK_STATUS;
|
|
79
|
+
codecName = (char*) avcodec_get_name(codecParams->codec_id);
|
|
80
|
+
codecNameLen = strlen(codecName);
|
|
81
|
+
goto create;
|
|
82
|
+
}
|
|
83
|
+
if (hasName) {
|
|
84
|
+
status = napi_get_named_property(env, args[0], "name", &value);
|
|
85
|
+
CHECK_STATUS;
|
|
86
|
+
codecNameLen = 64;
|
|
87
|
+
codecName = (char*) malloc(sizeof(char) * (codecNameLen + 1));
|
|
88
|
+
status = napi_get_value_string_utf8(env, value, codecName,
|
|
89
|
+
codecNameLen, &codecNameLen);
|
|
90
|
+
CHECK_STATUS;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
status = napi_get_named_property(env, args[0], "codec_id", &value);
|
|
94
|
+
CHECK_STATUS;
|
|
95
|
+
status = napi_get_value_int32(env, value, &codecID);
|
|
96
|
+
CHECK_STATUS;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
create:
|
|
100
|
+
codec = ((codecID == -1) && (codecName != nullptr)) ?
|
|
101
|
+
avcodec_find_encoder_by_name(codecName) :
|
|
102
|
+
avcodec_find_encoder((AVCodecID) codecID);
|
|
103
|
+
if ((codec == nullptr) && (codecID == -1)) { // one more go via codec descriptor
|
|
104
|
+
codecDesc = avcodec_descriptor_get_by_name(codecName);
|
|
105
|
+
if (codecDesc != nullptr) {
|
|
106
|
+
codec = avcodec_find_encoder(codecDesc->id);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (codec == nullptr) {
|
|
110
|
+
NAPI_THROW_ERROR("Failed to find an encoder from it's name or ID.");
|
|
111
|
+
}
|
|
112
|
+
encoder = avcodec_alloc_context3(codec);
|
|
113
|
+
if (encoder == nullptr) {
|
|
114
|
+
NAPI_THROW_ERROR("Problem allocating encoder context.");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (codecParams != nullptr) {
|
|
118
|
+
if ((ret = avcodec_parameters_to_context(encoder, (const AVCodecParameters*) codecParams))) {
|
|
119
|
+
NAPI_THROW_ERROR(avErrorMsg("Failed to set encoder parameters from provided params: ", ret));
|
|
120
|
+
}
|
|
121
|
+
// printf("Params to context result: %i\n", ret);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
status = fromAVCodecContext(env, encoder, &result, true);
|
|
125
|
+
const napi_value fargs[] = { result, args[0] };
|
|
126
|
+
CHECK_BAIL;
|
|
127
|
+
|
|
128
|
+
status = napi_get_global(env, &global);
|
|
129
|
+
CHECK_BAIL;
|
|
130
|
+
status = napi_get_named_property(env, global, "Object", &jsObject);
|
|
131
|
+
CHECK_BAIL;
|
|
132
|
+
status = napi_get_named_property(env, jsObject, "assign", &assign);
|
|
133
|
+
CHECK_BAIL;
|
|
134
|
+
status = napi_call_function(env, result, assign, 2, fargs, &result);
|
|
135
|
+
CHECK_BAIL;
|
|
136
|
+
|
|
137
|
+
if ((encoder->sample_fmt != AV_SAMPLE_FMT_NONE) &&
|
|
138
|
+
(encoder->sample_rate > 0) && (encoder->channel_layout != 0)) {
|
|
139
|
+
// For audio encodes open the encoder if sufficient parameters have been provided
|
|
140
|
+
// Encoder specific parameters will then be set up and available before the first encode
|
|
141
|
+
ret = avcodec_open2(encoder, encoder->codec, nullptr);
|
|
142
|
+
if (ret) {
|
|
143
|
+
NAPI_THROW_ERROR(avErrorMsg("Failed to open audio encoder: ", ret));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (encoder != nullptr) return result;
|
|
148
|
+
|
|
149
|
+
bail:
|
|
150
|
+
if (encoder != nullptr) {
|
|
151
|
+
avcodec_close(encoder);
|
|
152
|
+
avcodec_free_context(&encoder);
|
|
153
|
+
}
|
|
154
|
+
return nullptr;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
void encoderFinalizer(napi_env env, void* data, void* hint) {
|
|
158
|
+
AVCodecContext* encoder = (AVCodecContext*) data;
|
|
159
|
+
avcodec_close(encoder);
|
|
160
|
+
avcodec_free_context(&encoder);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
void encodeExecute(napi_env env, void* data) {
|
|
164
|
+
encodeCarrier* c = (encodeCarrier*) data;
|
|
165
|
+
int ret = 0;
|
|
166
|
+
AVPacket* packet = nullptr;
|
|
167
|
+
HR_TIME_POINT encodeStart = NOW;
|
|
168
|
+
|
|
169
|
+
for ( auto it = c->frames.cbegin() ; it != c->frames.cend() ; it++ ) {
|
|
170
|
+
bump:
|
|
171
|
+
ret = avcodec_send_frame(c->encoder, *it);
|
|
172
|
+
switch (ret) {
|
|
173
|
+
case AVERROR(EAGAIN):
|
|
174
|
+
//printf("Input is not accepted in the current state - user must read output with avcodec_receive_frame().\n");
|
|
175
|
+
packet = av_packet_alloc();
|
|
176
|
+
avcodec_receive_packet(c->encoder, packet);
|
|
177
|
+
c->packets.push_back(packet);
|
|
178
|
+
goto bump;
|
|
179
|
+
case AVERROR_EOF:
|
|
180
|
+
c->status = BEAMCODER_ERROR_EOF;
|
|
181
|
+
c->errorMsg = "The encoder has been flushed, and no new frames can be sent to it.";
|
|
182
|
+
return;
|
|
183
|
+
case AVERROR(EINVAL):
|
|
184
|
+
if ((ret = avcodec_open2(c->encoder, c->encoder->codec, nullptr))) {
|
|
185
|
+
c->status = BEAMCODER_ERROR_ALLOC_ENCODER;
|
|
186
|
+
c->errorMsg = avErrorMsg("Problem opening encoder: ", ret);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
goto bump;
|
|
190
|
+
case AVERROR(ENOMEM):
|
|
191
|
+
c->status = BEAMCODER_ERROR_ENOMEM;
|
|
192
|
+
c->errorMsg = "Failed to add frame to internal queue.";
|
|
193
|
+
return;
|
|
194
|
+
case 0:
|
|
195
|
+
//printf("Successfully sent frame to codec.\n");
|
|
196
|
+
break;
|
|
197
|
+
default:
|
|
198
|
+
c->status = BEAMCODER_ERROR_ENCODE;
|
|
199
|
+
c->errorMsg = avErrorMsg("Error sending frame: ", ret);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
} // loop through input frames
|
|
203
|
+
|
|
204
|
+
do {
|
|
205
|
+
packet = av_packet_alloc();
|
|
206
|
+
ret = avcodec_receive_packet(c->encoder, packet);
|
|
207
|
+
if (ret == 0) {
|
|
208
|
+
c->packets.push_back(packet);
|
|
209
|
+
packet = av_packet_alloc();
|
|
210
|
+
} else {
|
|
211
|
+
//printf("Receive packet got status %i\n", ret);
|
|
212
|
+
}
|
|
213
|
+
} while (ret == 0);
|
|
214
|
+
av_packet_free(&packet);
|
|
215
|
+
|
|
216
|
+
c->totalTime = microTime(encodeStart);
|
|
217
|
+
/* if (!c->frames.empty()) {
|
|
218
|
+
printf("Finished encoding frame. First pts = %i\n", c->frames.front()->pts);
|
|
219
|
+
} else {
|
|
220
|
+
printf("Flushing complete.\n");
|
|
221
|
+
} */
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
void encodeComplete(napi_env env, napi_status asyncStatus, void* data) {
|
|
225
|
+
encodeCarrier* c = (encodeCarrier*) data;
|
|
226
|
+
napi_value result, packets, packet, value;
|
|
227
|
+
|
|
228
|
+
for ( auto it = c->frameRefs.cbegin() ; it != c->frameRefs.cend() ; it++ ) {
|
|
229
|
+
// printf("Deleting frame reference. First pts = %i\n", c->frames.front()->pts);
|
|
230
|
+
c->status = napi_delete_reference(env, *it);
|
|
231
|
+
REJECT_STATUS;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (asyncStatus != napi_ok) {
|
|
235
|
+
c->status = asyncStatus;
|
|
236
|
+
c->errorMsg = "Encode operation failed to complete.";
|
|
237
|
+
}
|
|
238
|
+
REJECT_STATUS;
|
|
239
|
+
|
|
240
|
+
c->status = napi_create_object(env, &result);
|
|
241
|
+
REJECT_STATUS;
|
|
242
|
+
c->status = beam_set_string_utf8(env, result, "type", "packets");
|
|
243
|
+
REJECT_STATUS;
|
|
244
|
+
|
|
245
|
+
c->status = napi_create_array(env, &packets);
|
|
246
|
+
REJECT_STATUS;
|
|
247
|
+
c->status = napi_set_named_property(env, result, "packets", packets);
|
|
248
|
+
REJECT_STATUS;
|
|
249
|
+
|
|
250
|
+
uint32_t packetCount = 0;
|
|
251
|
+
for ( auto it = c->packets.begin(); it != c->packets.end() ; it++ ) {
|
|
252
|
+
packetData* p = new packetData;
|
|
253
|
+
p->packet = *it;
|
|
254
|
+
|
|
255
|
+
c->status = fromAVPacket(env, p, &packet);
|
|
256
|
+
REJECT_STATUS;
|
|
257
|
+
|
|
258
|
+
c->status = napi_set_element(env, packets, packetCount++, packet);
|
|
259
|
+
REJECT_STATUS;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
c->status = napi_create_int64(env, c->totalTime, &value);
|
|
263
|
+
REJECT_STATUS;
|
|
264
|
+
c->status = napi_set_named_property(env, result, "total_time", value);
|
|
265
|
+
REJECT_STATUS;
|
|
266
|
+
|
|
267
|
+
napi_status status;
|
|
268
|
+
status = napi_resolve_deferred(env, c->_deferred, result);
|
|
269
|
+
FLOATING_STATUS;
|
|
270
|
+
|
|
271
|
+
tidyCarrier(env, c);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
napi_value encode(napi_env env, napi_callback_info info) {
|
|
275
|
+
napi_value resourceName, promise, encoderJS, encoderExt, value;
|
|
276
|
+
encodeCarrier* c = new encodeCarrier;
|
|
277
|
+
bool isArray;
|
|
278
|
+
uint32_t framesLength;
|
|
279
|
+
napi_ref frameRef;
|
|
280
|
+
|
|
281
|
+
c->status = napi_create_promise(env, &c->_deferred, &promise);
|
|
282
|
+
REJECT_RETURN;
|
|
283
|
+
|
|
284
|
+
size_t argc = 0;
|
|
285
|
+
napi_value* args = nullptr;
|
|
286
|
+
|
|
287
|
+
c->status = napi_get_cb_info(env, info, &argc, args, &encoderJS, nullptr);
|
|
288
|
+
REJECT_RETURN;
|
|
289
|
+
c->status = napi_get_named_property(env, encoderJS, "_CodecContext", &encoderExt);
|
|
290
|
+
REJECT_RETURN;
|
|
291
|
+
c->status = napi_get_value_external(env, encoderExt, (void**) &c->encoder);
|
|
292
|
+
REJECT_RETURN;
|
|
293
|
+
|
|
294
|
+
if (argc == 0) {
|
|
295
|
+
REJECT_ERROR_RETURN("Encode call requires one or more frames.",
|
|
296
|
+
BEAMCODER_INVALID_ARGS);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
args = (napi_value*) malloc(sizeof(napi_value) * argc);
|
|
300
|
+
c->status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
|
|
301
|
+
REJECT_RETURN;
|
|
302
|
+
|
|
303
|
+
c->status = napi_is_array(env, args[0], &isArray);
|
|
304
|
+
REJECT_RETURN;
|
|
305
|
+
if (isArray) {
|
|
306
|
+
c->status = napi_get_array_length(env, args[0], &framesLength);
|
|
307
|
+
REJECT_RETURN;
|
|
308
|
+
for ( uint32_t x = 0 ; x < framesLength ; x++ ) {
|
|
309
|
+
c->status = napi_get_element(env, args[0], x, &value);
|
|
310
|
+
REJECT_RETURN;
|
|
311
|
+
c->status = isFrame(env,value);
|
|
312
|
+
if (c->status != napi_ok) {
|
|
313
|
+
REJECT_ERROR_RETURN("Add passed values is an array whose elements must be of type frame.",
|
|
314
|
+
BEAMCODER_INVALID_ARGS);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
for ( uint32_t x = 0 ; x < framesLength ; x++ ) {
|
|
318
|
+
c->status = napi_get_element(env, args[0], x, &value);
|
|
319
|
+
REJECT_RETURN;
|
|
320
|
+
// printf("Creating a reference to a frame.\n");
|
|
321
|
+
c->status = napi_create_reference(env, value, 1, &frameRef);
|
|
322
|
+
REJECT_RETURN;
|
|
323
|
+
c->frameRefs.push_back(frameRef);
|
|
324
|
+
c->frames.push_back(getFrame(env, value));
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
for ( uint32_t x = 0 ; x < argc ; x++ ) {
|
|
328
|
+
c->status = isFrame(env, args[x]);
|
|
329
|
+
if (c->status != napi_ok) {
|
|
330
|
+
REJECT_ERROR_RETURN("All passed values as arguments must be of type frame.",
|
|
331
|
+
BEAMCODER_INVALID_ARGS);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
for ( uint32_t x = 0 ; x < argc ; x++ ) {
|
|
335
|
+
c->status = napi_create_reference(env, args[x], 1, &frameRef);
|
|
336
|
+
REJECT_RETURN;
|
|
337
|
+
c->frameRefs.push_back(frameRef);
|
|
338
|
+
c->frames.push_back(getFrame(env, args[x]));
|
|
339
|
+
// printf("Creating a reference to a frame. First pts = %i\n", c->frames.front()->pts);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
c->status = napi_create_string_utf8(env, "Encode", NAPI_AUTO_LENGTH, &resourceName);
|
|
344
|
+
REJECT_RETURN;
|
|
345
|
+
c->status = napi_create_async_work(env, nullptr, resourceName, encodeExecute,
|
|
346
|
+
encodeComplete, c, &c->_request);
|
|
347
|
+
REJECT_RETURN;
|
|
348
|
+
c->status = napi_queue_async_work(env, c->_request);
|
|
349
|
+
REJECT_RETURN;
|
|
350
|
+
|
|
351
|
+
free(args);
|
|
352
|
+
|
|
353
|
+
return promise;
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
/* napi_value getEncProperties(napi_env env, napi_callback_info info) {
|
|
357
|
+
napi_status status;
|
|
358
|
+
napi_value result, encoderJS, encoderExt;
|
|
359
|
+
AVCodecContext* encoder;
|
|
360
|
+
|
|
361
|
+
size_t argc = 0;
|
|
362
|
+
napi_value* args = nullptr;
|
|
363
|
+
|
|
364
|
+
status = napi_get_cb_info(env, info, &argc, args, &encoderJS, nullptr);
|
|
365
|
+
CHECK_STATUS;
|
|
366
|
+
status = napi_get_named_property(env, encoderJS, "_encoder", &encoderExt);
|
|
367
|
+
CHECK_STATUS;
|
|
368
|
+
status = napi_get_value_external(env, encoderExt, (void**) &encoder);
|
|
369
|
+
CHECK_STATUS;
|
|
370
|
+
|
|
371
|
+
status = napi_create_object(env, &result);
|
|
372
|
+
CHECK_STATUS;
|
|
373
|
+
status = beam_set_string_utf8(env, result, "type", "CodecContext");
|
|
374
|
+
CHECK_STATUS;
|
|
375
|
+
status = beam_set_bool(env, result, "encoding", true);
|
|
376
|
+
CHECK_STATUS;
|
|
377
|
+
status = getPropsFromCodec(env, result, encoder, true);
|
|
378
|
+
CHECK_STATUS;
|
|
379
|
+
|
|
380
|
+
return result;
|
|
381
|
+
}; */
|
|
382
|
+
|
|
383
|
+
/* napi_value setEncProperties(napi_env env, napi_callback_info info) {
|
|
384
|
+
napi_status status;
|
|
385
|
+
napi_value result, encoderJS, encoderExt;
|
|
386
|
+
napi_valuetype type;
|
|
387
|
+
AVCodecContext* encoder;
|
|
388
|
+
|
|
389
|
+
size_t argc = 1;
|
|
390
|
+
napi_value args[1];
|
|
391
|
+
|
|
392
|
+
status = napi_get_cb_info(env, info, &argc, args, &encoderJS, nullptr);
|
|
393
|
+
CHECK_STATUS;
|
|
394
|
+
status = napi_get_named_property(env, encoderJS, "_encoder", &encoderExt);
|
|
395
|
+
CHECK_STATUS;
|
|
396
|
+
status = napi_get_value_external(env, encoderExt, (void**) &encoder);
|
|
397
|
+
CHECK_STATUS;
|
|
398
|
+
|
|
399
|
+
if (argc < 1) {
|
|
400
|
+
NAPI_THROW_ERROR("Cannot set encoder properties with no values.");
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
status = napi_typeof(env, args[0], &type);
|
|
404
|
+
CHECK_STATUS;
|
|
405
|
+
if (type != napi_object) {
|
|
406
|
+
NAPI_THROW_ERROR("Set properties must be provided as a single object.");
|
|
407
|
+
}
|
|
408
|
+
setCodecFromProps(env, encoder, args[0], false);
|
|
409
|
+
|
|
410
|
+
status = napi_get_undefined(env, &result);
|
|
411
|
+
CHECK_STATUS;
|
|
412
|
+
return result;
|
|
413
|
+
}; */
|
|
414
|
+
|
|
415
|
+
napi_status isFrame(napi_env env, napi_value packet) {
|
|
416
|
+
napi_status status;
|
|
417
|
+
napi_value value;
|
|
418
|
+
bool result;
|
|
419
|
+
char objType[10];
|
|
420
|
+
size_t typeLen;
|
|
421
|
+
int cmp;
|
|
422
|
+
napi_valuetype type;
|
|
423
|
+
|
|
424
|
+
status = napi_typeof(env, packet, &type);
|
|
425
|
+
if ((status != napi_ok) || (type != napi_object)) return napi_invalid_arg;
|
|
426
|
+
status = napi_is_array(env, packet, &result);
|
|
427
|
+
if ((status != napi_ok) || (result == true)) return napi_invalid_arg;
|
|
428
|
+
|
|
429
|
+
status = napi_has_named_property(env, packet, "type", &result);
|
|
430
|
+
if ((status != napi_ok) || (result == false)) return napi_invalid_arg;
|
|
431
|
+
|
|
432
|
+
status = napi_has_named_property(env, packet, "_frame", &result);
|
|
433
|
+
if ((status != napi_ok) || (result == false)) return napi_invalid_arg;
|
|
434
|
+
|
|
435
|
+
status = napi_get_named_property(env, packet, "type", &value);
|
|
436
|
+
if (status != napi_ok) return status;
|
|
437
|
+
status = napi_get_value_string_utf8(env, value, objType, 10, &typeLen);
|
|
438
|
+
if (status != napi_ok) return status;
|
|
439
|
+
cmp = strcmp("Frame", objType);
|
|
440
|
+
if (cmp != 0) return napi_invalid_arg;
|
|
441
|
+
|
|
442
|
+
status = napi_get_named_property(env, packet, "_frame", &value);
|
|
443
|
+
if (status != napi_ok) return status;
|
|
444
|
+
status = napi_typeof(env, value, &type);
|
|
445
|
+
if (status != napi_ok) return status;
|
|
446
|
+
if (type != napi_external) return napi_invalid_arg;
|
|
447
|
+
|
|
448
|
+
return napi_ok;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
AVFrame* getFrame(napi_env env, napi_value packet) {
|
|
452
|
+
napi_status status;
|
|
453
|
+
napi_value value;
|
|
454
|
+
frameData* result = nullptr;
|
|
455
|
+
status = napi_get_named_property(env, packet, "_frame", &value);
|
|
456
|
+
if (status != napi_ok) return nullptr;
|
|
457
|
+
status = napi_get_value_external(env, value, (void**) &result);
|
|
458
|
+
if (status != napi_ok) return nullptr;
|
|
459
|
+
|
|
460
|
+
return result->frame;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
napi_value flushEnc(napi_env env, napi_callback_info info) {
|
|
464
|
+
encodeCarrier* c = new encodeCarrier;
|
|
465
|
+
napi_value encoderJS, encoderExt, promise, resourceName;
|
|
466
|
+
|
|
467
|
+
c->status = napi_create_promise(env, &c->_deferred, &promise);
|
|
468
|
+
REJECT_RETURN;
|
|
469
|
+
|
|
470
|
+
size_t argc = 0;
|
|
471
|
+
napi_value* args = nullptr;
|
|
472
|
+
|
|
473
|
+
c->status = napi_get_cb_info(env, info, &argc, args, &encoderJS, nullptr);
|
|
474
|
+
REJECT_RETURN;
|
|
475
|
+
c->status = napi_get_named_property(env, encoderJS, "_CodecContext", &encoderExt);
|
|
476
|
+
REJECT_RETURN;
|
|
477
|
+
c->status = napi_get_value_external(env, encoderExt, (void**) &c->encoder);
|
|
478
|
+
REJECT_RETURN;
|
|
479
|
+
|
|
480
|
+
if (argc != 0) {
|
|
481
|
+
REJECT_ERROR_RETURN("Encode flush takes no arguments.",
|
|
482
|
+
BEAMCODER_INVALID_ARGS);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
c->frames.push_back(nullptr);
|
|
486
|
+
|
|
487
|
+
c->status = napi_create_string_utf8(env, "EncodeFlush", NAPI_AUTO_LENGTH, &resourceName);
|
|
488
|
+
REJECT_RETURN;
|
|
489
|
+
c->status = napi_create_async_work(env, nullptr, resourceName, encodeExecute,
|
|
490
|
+
encodeComplete, c, &c->_request);
|
|
491
|
+
REJECT_RETURN;
|
|
492
|
+
c->status = napi_queue_async_work(env, c->_request);
|
|
493
|
+
REJECT_RETURN;
|
|
494
|
+
|
|
495
|
+
return promise;
|
|
496
|
+
}
|
package/src/encode.h
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
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 ENCODE_H
|
|
23
|
+
#define ENCODE_H
|
|
24
|
+
|
|
25
|
+
#include "beamcoder_util.h"
|
|
26
|
+
#include "frame.h"
|
|
27
|
+
#include "packet.h"
|
|
28
|
+
#include "codec.h"
|
|
29
|
+
#include <vector>
|
|
30
|
+
|
|
31
|
+
extern "C" {
|
|
32
|
+
#include <libavcodec/avcodec.h>
|
|
33
|
+
#include <libavutil/pixdesc.h>
|
|
34
|
+
#include <libavformat/avformat.h>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
napi_value encoder(napi_env env, napi_callback_info info);
|
|
38
|
+
|
|
39
|
+
void encodeExecute(napi_env env, void* data);
|
|
40
|
+
void encodeComplete(napi_env env, napi_status asyncStatus, void* data);
|
|
41
|
+
napi_value encode(napi_env env, napi_callback_info info);
|
|
42
|
+
napi_value flushEnc(napi_env env, napi_callback_info info);
|
|
43
|
+
|
|
44
|
+
void encoderFinalizer(napi_env env, void* data, void* hint);
|
|
45
|
+
|
|
46
|
+
/* struct encoderCarrier : carrier {
|
|
47
|
+
AVCodecContext* encoder;
|
|
48
|
+
// AVCodecParameters* params = nullptr;
|
|
49
|
+
const AVCodec* codec = nullptr;
|
|
50
|
+
char* codecName;
|
|
51
|
+
size_t codecNameLen = 0;
|
|
52
|
+
int32_t codecID = -1;
|
|
53
|
+
~encoderCarrier() {
|
|
54
|
+
if (encoder != nullptr) {
|
|
55
|
+
avcodec_close(encoder);
|
|
56
|
+
avcodec_free_context(&encoder);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}; */
|
|
60
|
+
|
|
61
|
+
struct encodeCarrier : carrier {
|
|
62
|
+
AVCodecContext* encoder;
|
|
63
|
+
std::vector<AVFrame*> frames;
|
|
64
|
+
std::vector<AVPacket*> packets;
|
|
65
|
+
std::vector<napi_ref> frameRefs;
|
|
66
|
+
~encodeCarrier() { }
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
napi_status isFrame(napi_env env, napi_value packet);
|
|
70
|
+
AVFrame* getFrame(napi_env env, napi_value packet);
|
|
71
|
+
|
|
72
|
+
#endif // ENCODE_H
|