@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/codec_par.h
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
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 CODEC_PAR_H
|
|
23
|
+
#define CODEC_PAR_H
|
|
24
|
+
|
|
25
|
+
#include "node_api.h"
|
|
26
|
+
#include "beamcoder_util.h"
|
|
27
|
+
|
|
28
|
+
extern "C" {
|
|
29
|
+
#include <libavcodec/avcodec.h>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void codecParamsFinalizer(napi_env env, void* data, void* hint);
|
|
33
|
+
|
|
34
|
+
napi_value makeCodecParameters(napi_env env, napi_callback_info info);
|
|
35
|
+
napi_value makeCodecParamsInternal(napi_env env, napi_callback_info info, bool ownAlloc);
|
|
36
|
+
napi_status fromAVCodecParameters(napi_env env, AVCodecParameters* c, bool ownAlloc, napi_value* result);
|
|
37
|
+
|
|
38
|
+
napi_value codecParToJSON(napi_env env, napi_callback_info info);
|
|
39
|
+
|
|
40
|
+
#endif // CODEC_PAR_H
|
package/src/decode.cc
ADDED
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Aerostat Beam Coder - Node.js native bindings for FFmpeg.
|
|
3
|
+
Copyright (C) 2018 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 "decode.h"
|
|
23
|
+
|
|
24
|
+
AVPixelFormat get_format(AVCodecContext *s, const AVPixelFormat *pix_fmts)
|
|
25
|
+
{
|
|
26
|
+
const AVPixelFormat *p;
|
|
27
|
+
int i, err;
|
|
28
|
+
|
|
29
|
+
for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
|
|
30
|
+
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
|
|
31
|
+
const AVCodecHWConfig *config = NULL;
|
|
32
|
+
|
|
33
|
+
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
|
|
34
|
+
break;
|
|
35
|
+
|
|
36
|
+
for (i = 0;; i++) {
|
|
37
|
+
config = avcodec_get_hw_config(s->codec, i);
|
|
38
|
+
if (!config)
|
|
39
|
+
break;
|
|
40
|
+
if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
|
|
41
|
+
continue;
|
|
42
|
+
if (config->pix_fmt == *p)
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (config) {
|
|
47
|
+
err = av_hwdevice_ctx_create(&s->hw_device_ctx, config->device_type, NULL, NULL, 0);
|
|
48
|
+
if (err < 0) {
|
|
49
|
+
char errstr[128];
|
|
50
|
+
av_make_error_string(errstr, 128, err);
|
|
51
|
+
printf("Error in get_format av_hwdevice_ctx_create: %s\n", errstr);
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return *p;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
napi_value decoder(napi_env env, napi_callback_info info) {
|
|
61
|
+
napi_status status;
|
|
62
|
+
napi_value result, value, formatJS, formatExt, global, jsObject, assign, jsParams;
|
|
63
|
+
napi_valuetype type;
|
|
64
|
+
bool isArray, hasName, hasID, hasFormat, hasStream, hasParams, hasHWaccel;
|
|
65
|
+
AVCodecContext* decoder = nullptr;
|
|
66
|
+
AVFormatContext* format = nullptr;
|
|
67
|
+
const AVCodec* codec = nullptr;
|
|
68
|
+
int ret = 0, streamIdx = -1;
|
|
69
|
+
const AVCodecDescriptor* codecDesc = nullptr;
|
|
70
|
+
AVCodecParameters* params = nullptr;
|
|
71
|
+
char* codecName = nullptr;
|
|
72
|
+
size_t codecNameLen = 0;
|
|
73
|
+
int32_t codecID = -1;
|
|
74
|
+
bool hwaccel = false;
|
|
75
|
+
|
|
76
|
+
size_t argc = 1;
|
|
77
|
+
napi_value args[1];
|
|
78
|
+
|
|
79
|
+
status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
|
|
80
|
+
CHECK_STATUS;
|
|
81
|
+
|
|
82
|
+
if (argc != 1) {
|
|
83
|
+
NAPI_THROW_ERROR("Decoder requires a single options object.");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
status = napi_typeof(env, args[0], &type);
|
|
87
|
+
CHECK_STATUS;
|
|
88
|
+
status = napi_is_array(env, args[0], &isArray);
|
|
89
|
+
CHECK_STATUS;
|
|
90
|
+
if ((type != napi_object) || (isArray == true)) {
|
|
91
|
+
NAPI_THROW_ERROR("Decoder must be configured with a single parameter, an options object.");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
status = napi_has_named_property(env, args[0], "name", &hasName);
|
|
95
|
+
CHECK_STATUS;
|
|
96
|
+
status = napi_has_named_property(env, args[0], "codec_id", &hasID);
|
|
97
|
+
CHECK_STATUS;
|
|
98
|
+
status = napi_has_named_property(env, args[0], "demuxer", &hasFormat);
|
|
99
|
+
CHECK_STATUS;
|
|
100
|
+
status = napi_has_named_property(env, args[0], "stream_index", &hasStream);
|
|
101
|
+
CHECK_STATUS;
|
|
102
|
+
status = napi_has_named_property(env, args[0], "params", &hasParams);
|
|
103
|
+
CHECK_STATUS;
|
|
104
|
+
|
|
105
|
+
if (hasFormat && hasStream) {
|
|
106
|
+
status = napi_get_named_property(env, args[0], "demuxer", &formatJS);
|
|
107
|
+
CHECK_STATUS;
|
|
108
|
+
status = napi_get_named_property(env, formatJS, "_formatContext", &formatExt);
|
|
109
|
+
CHECK_STATUS;
|
|
110
|
+
status = napi_get_value_external(env, formatExt, (void**) &format);
|
|
111
|
+
CHECK_STATUS;
|
|
112
|
+
|
|
113
|
+
status = napi_get_named_property(env, args[0], "stream_index", &value);
|
|
114
|
+
CHECK_STATUS;
|
|
115
|
+
status = napi_get_value_int32(env, value, &streamIdx);
|
|
116
|
+
CHECK_STATUS;
|
|
117
|
+
if (streamIdx < 0 || streamIdx >= (int) format->nb_streams) {
|
|
118
|
+
NAPI_THROW_ERROR("Stream index is out of bounds for the given format.");
|
|
119
|
+
}
|
|
120
|
+
params = format->streams[streamIdx]->codecpar;
|
|
121
|
+
codecID = params->codec_id;
|
|
122
|
+
codecName = (char*) avcodec_get_name(params->codec_id);
|
|
123
|
+
codecNameLen = strlen(codecName);
|
|
124
|
+
goto create;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (hasParams) {
|
|
128
|
+
status = napi_get_named_property(env, args[0], "params", &value);
|
|
129
|
+
CHECK_STATUS;
|
|
130
|
+
status = napi_get_named_property(env, value, "_codecPar", &jsParams);
|
|
131
|
+
CHECK_STATUS;
|
|
132
|
+
status = napi_typeof(env, jsParams, &type);
|
|
133
|
+
CHECK_STATUS;
|
|
134
|
+
if (type != napi_external) {
|
|
135
|
+
NAPI_THROW_ERROR("The provided parameters do not appear to be a valid codec parameters object.");
|
|
136
|
+
}
|
|
137
|
+
status = napi_get_value_external(env, jsParams, (void**) ¶ms);
|
|
138
|
+
CHECK_STATUS;
|
|
139
|
+
codecID = params->codec_id;
|
|
140
|
+
codecName = (char*) avcodec_get_name(params->codec_id);
|
|
141
|
+
codecNameLen = strlen(codecName);
|
|
142
|
+
goto create;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!(hasName || hasID)) {
|
|
146
|
+
NAPI_THROW_ERROR("Decoder must be identified with a 'codec_id' or a 'name'.");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (hasName) {
|
|
150
|
+
status = napi_get_named_property(env, args[0], "name", &value);
|
|
151
|
+
CHECK_STATUS;
|
|
152
|
+
codecNameLen = 64;
|
|
153
|
+
codecName = (char*) malloc(sizeof(char) * (codecNameLen + 1));
|
|
154
|
+
status = napi_get_value_string_utf8(env, value, codecName,
|
|
155
|
+
64, &codecNameLen);
|
|
156
|
+
CHECK_STATUS;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
status = napi_get_named_property(env, args[0], "codec_id", &value);
|
|
160
|
+
CHECK_STATUS;
|
|
161
|
+
status = napi_get_value_int32(env, value, (int32_t*) &codecID);
|
|
162
|
+
CHECK_STATUS;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
create:
|
|
166
|
+
codec = ((codecID == -1) && (codecName != nullptr)) ?
|
|
167
|
+
avcodec_find_decoder_by_name(codecName) :
|
|
168
|
+
avcodec_find_decoder((AVCodecID) codecID);
|
|
169
|
+
if ((codec == nullptr) && (codecID == -1)) { // one more go via codec descriptor
|
|
170
|
+
codecDesc = avcodec_descriptor_get_by_name(codecName);
|
|
171
|
+
if (codecDesc != nullptr) {
|
|
172
|
+
codec = avcodec_find_decoder(codecDesc->id);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (codec == nullptr) {
|
|
176
|
+
NAPI_THROW_ERROR("Failed to find a decoder from it's name.");
|
|
177
|
+
}
|
|
178
|
+
decoder = avcodec_alloc_context3(codec);
|
|
179
|
+
if (decoder == nullptr) {
|
|
180
|
+
NAPI_THROW_ERROR("Problem allocating decoder context.");
|
|
181
|
+
}
|
|
182
|
+
if (params != nullptr) {
|
|
183
|
+
if ((ret = avcodec_parameters_to_context(decoder, params))) {
|
|
184
|
+
printf("DEBUG: Failed to set context parameters from those provided.");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
status = napi_has_named_property(env, args[0], "hwaccel", &hasHWaccel);
|
|
189
|
+
CHECK_STATUS;
|
|
190
|
+
if (hasHWaccel) {
|
|
191
|
+
status = napi_get_named_property(env, args[0], "hwaccel", &value);
|
|
192
|
+
CHECK_STATUS;
|
|
193
|
+
status = napi_get_value_bool(env, value, &hwaccel);
|
|
194
|
+
CHECK_STATUS;
|
|
195
|
+
if (hwaccel)
|
|
196
|
+
decoder->get_format = get_format;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
status = fromAVCodecContext(env, decoder, &result, false);
|
|
200
|
+
const napi_value fargs[2] = { result, args[0] };
|
|
201
|
+
CHECK_BAIL;
|
|
202
|
+
|
|
203
|
+
status = napi_get_global(env, &global);
|
|
204
|
+
CHECK_BAIL;
|
|
205
|
+
status = napi_get_named_property(env, global, "Object", &jsObject);
|
|
206
|
+
CHECK_BAIL;
|
|
207
|
+
status = napi_get_named_property(env, jsObject, "assign", &assign);
|
|
208
|
+
CHECK_BAIL;
|
|
209
|
+
|
|
210
|
+
status = napi_call_function(env, result, assign, 2, fargs, &result);
|
|
211
|
+
CHECK_BAIL;
|
|
212
|
+
|
|
213
|
+
if (decoder != nullptr) return result;
|
|
214
|
+
|
|
215
|
+
bail:
|
|
216
|
+
if (decoder != nullptr) {
|
|
217
|
+
avcodec_close(decoder);
|
|
218
|
+
avcodec_free_context(&decoder);
|
|
219
|
+
}
|
|
220
|
+
return nullptr;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
void decoderFinalizer(napi_env env, void* data, void* hint) {
|
|
224
|
+
AVCodecContext* decoder = (AVCodecContext*) data;
|
|
225
|
+
avcodec_close(decoder);
|
|
226
|
+
avcodec_free_context(&decoder);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
void decodeExecute(napi_env env, void* data) {
|
|
230
|
+
decodeCarrier* c = (decodeCarrier*) data;
|
|
231
|
+
int ret = 0;
|
|
232
|
+
AVFrame* frame = nullptr;
|
|
233
|
+
AVFrame *sw_frame = nullptr;
|
|
234
|
+
HR_TIME_POINT decodeStart = NOW;
|
|
235
|
+
|
|
236
|
+
for ( auto it = c->packets.cbegin() ; it != c->packets.cend() ; it++ ) {
|
|
237
|
+
bump:
|
|
238
|
+
ret = avcodec_send_packet(c->decoder, *it);
|
|
239
|
+
switch (ret) {
|
|
240
|
+
case AVERROR(EAGAIN):
|
|
241
|
+
// printf("Input is not accepted in the current state - user must read output with avcodec_receive_frame().\n");
|
|
242
|
+
frame = av_frame_alloc();
|
|
243
|
+
avcodec_receive_frame(c->decoder, frame);
|
|
244
|
+
c->frames.push_back(frame);
|
|
245
|
+
goto bump;
|
|
246
|
+
case AVERROR_EOF:
|
|
247
|
+
c->status = BEAMCODER_ERROR_EOF;
|
|
248
|
+
c->errorMsg = "The decoder has been flushed, and no new packets can be sent to it.";
|
|
249
|
+
return;
|
|
250
|
+
case AVERROR(EINVAL):
|
|
251
|
+
if ((ret = avcodec_open2(c->decoder, c->decoder->codec, nullptr))) {
|
|
252
|
+
c->status = BEAMCODER_ERROR_ALLOC_DECODER;
|
|
253
|
+
c->errorMsg = avErrorMsg("Problem opening decoder: ", ret);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
goto bump;
|
|
257
|
+
case AVERROR(ENOMEM):
|
|
258
|
+
c->status = BEAMCODER_ERROR_ENOMEM;
|
|
259
|
+
c->errorMsg = "Failed to add packet to internal queue.";
|
|
260
|
+
return;
|
|
261
|
+
case 0:
|
|
262
|
+
// printf("Successfully sent packet to codec.\n");
|
|
263
|
+
break;
|
|
264
|
+
default:
|
|
265
|
+
c->status = BEAMCODER_ERROR_DECODE;
|
|
266
|
+
c->errorMsg = avErrorMsg("Error sending packet: ", ret);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
} // loop through input packets
|
|
270
|
+
|
|
271
|
+
AVPixelFormat frame_hw_pix_fmt = AV_PIX_FMT_NONE;
|
|
272
|
+
if (c->decoder->hw_frames_ctx)
|
|
273
|
+
frame_hw_pix_fmt = ((AVHWFramesContext*)c->decoder->hw_frames_ctx->data)->format;
|
|
274
|
+
|
|
275
|
+
frame = av_frame_alloc();
|
|
276
|
+
sw_frame = av_frame_alloc();
|
|
277
|
+
do {
|
|
278
|
+
ret = avcodec_receive_frame(c->decoder, frame);
|
|
279
|
+
if (ret == 0) {
|
|
280
|
+
if (frame->format == frame_hw_pix_fmt) {
|
|
281
|
+
if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) {
|
|
282
|
+
printf("Error transferring hw data to system memory\n");
|
|
283
|
+
}
|
|
284
|
+
c->frames.push_back(sw_frame);
|
|
285
|
+
av_frame_free(&frame);
|
|
286
|
+
} else
|
|
287
|
+
c->frames.push_back(frame);
|
|
288
|
+
|
|
289
|
+
frame = av_frame_alloc();
|
|
290
|
+
sw_frame = av_frame_alloc();
|
|
291
|
+
}
|
|
292
|
+
} while (ret == 0);
|
|
293
|
+
av_frame_free(&frame);
|
|
294
|
+
av_frame_free(&sw_frame);
|
|
295
|
+
|
|
296
|
+
c->totalTime = microTime(decodeStart);
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
void decodeComplete(napi_env env, napi_status asyncStatus, void* data) {
|
|
300
|
+
decodeCarrier* c = (decodeCarrier*) data;
|
|
301
|
+
napi_value result, frames, frame, prop;
|
|
302
|
+
|
|
303
|
+
for ( auto it = c->packetRefs.cbegin() ; it != c->packetRefs.cend() ; it++ ) {
|
|
304
|
+
c->status = napi_delete_reference(env, *it);
|
|
305
|
+
REJECT_STATUS;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (asyncStatus != napi_ok) {
|
|
309
|
+
c->status = asyncStatus;
|
|
310
|
+
c->errorMsg = "Decoder allocator failed to complete.";
|
|
311
|
+
}
|
|
312
|
+
REJECT_STATUS;
|
|
313
|
+
|
|
314
|
+
c->status = napi_create_object(env, &result);
|
|
315
|
+
REJECT_STATUS;
|
|
316
|
+
c->status = beam_set_string_utf8(env, result, "type", "frames");
|
|
317
|
+
REJECT_STATUS;
|
|
318
|
+
|
|
319
|
+
c->status = napi_create_array(env, &frames);
|
|
320
|
+
REJECT_STATUS;
|
|
321
|
+
c->status = napi_set_named_property(env, result, "frames", frames);
|
|
322
|
+
REJECT_STATUS;
|
|
323
|
+
|
|
324
|
+
uint32_t frameCount = 0;
|
|
325
|
+
for ( auto it = c->frames.begin() ; it != c->frames.end() ; it++ ) {
|
|
326
|
+
frameData* f = new frameData;
|
|
327
|
+
f->frame = *it;
|
|
328
|
+
|
|
329
|
+
c->status = fromAVFrame(env, f, &frame);
|
|
330
|
+
REJECT_STATUS;
|
|
331
|
+
|
|
332
|
+
c->status = napi_set_element(env, frames, frameCount++, frame);
|
|
333
|
+
REJECT_STATUS;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
c->status = napi_create_int64(env, c->totalTime, &prop);
|
|
337
|
+
REJECT_STATUS;
|
|
338
|
+
c->status = napi_set_named_property(env, result, "total_time", prop);
|
|
339
|
+
REJECT_STATUS;
|
|
340
|
+
|
|
341
|
+
napi_status status;
|
|
342
|
+
status = napi_resolve_deferred(env, c->_deferred, result);
|
|
343
|
+
FLOATING_STATUS;
|
|
344
|
+
|
|
345
|
+
tidyCarrier(env, c);
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
napi_value decode(napi_env env, napi_callback_info info) {
|
|
349
|
+
napi_value resourceName, promise, decoderJS, decoderExt, value;
|
|
350
|
+
decodeCarrier* c = new decodeCarrier;
|
|
351
|
+
bool isArray;
|
|
352
|
+
uint32_t packetsLength;
|
|
353
|
+
napi_ref packetRef;
|
|
354
|
+
|
|
355
|
+
c->status = napi_create_promise(env, &c->_deferred, &promise);
|
|
356
|
+
REJECT_RETURN;
|
|
357
|
+
|
|
358
|
+
size_t argc = 0;
|
|
359
|
+
napi_value* args = nullptr;
|
|
360
|
+
|
|
361
|
+
c->status = napi_get_cb_info(env, info, &argc, args, &decoderJS, nullptr);
|
|
362
|
+
REJECT_RETURN;
|
|
363
|
+
c->status = napi_get_named_property(env, decoderJS, "_CodecContext", &decoderExt);
|
|
364
|
+
REJECT_RETURN;
|
|
365
|
+
c->status = napi_get_value_external(env, decoderExt, (void**) &c->decoder);
|
|
366
|
+
REJECT_RETURN;
|
|
367
|
+
|
|
368
|
+
if (argc == 0) {
|
|
369
|
+
REJECT_ERROR_RETURN("Decode call requires one or more packets.",
|
|
370
|
+
BEAMCODER_INVALID_ARGS);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
args = (napi_value*) malloc(sizeof(napi_value) * argc);
|
|
374
|
+
c->status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
|
|
375
|
+
REJECT_RETURN;
|
|
376
|
+
|
|
377
|
+
c->status = napi_is_array(env, args[0], &isArray);
|
|
378
|
+
REJECT_RETURN;
|
|
379
|
+
if (isArray) {
|
|
380
|
+
c->status = napi_get_array_length(env, args[0], &packetsLength);
|
|
381
|
+
REJECT_RETURN;
|
|
382
|
+
for ( uint32_t x = 0 ; x < packetsLength ; x++ ) {
|
|
383
|
+
c->status = napi_get_element(env, args[0], x, &value);
|
|
384
|
+
REJECT_RETURN;
|
|
385
|
+
c->status = isPacket(env, value);
|
|
386
|
+
if (c->status != napi_ok) {
|
|
387
|
+
REJECT_ERROR_RETURN("All passed values in an array must be of type packet.",
|
|
388
|
+
BEAMCODER_INVALID_ARGS);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for ( uint32_t x = 0 ; x < packetsLength ; x++ ) {
|
|
392
|
+
c->status = napi_get_element(env, args[0], x, &value);
|
|
393
|
+
REJECT_RETURN;
|
|
394
|
+
c->status = napi_create_reference(env, value, 1, &packetRef);
|
|
395
|
+
REJECT_RETURN;
|
|
396
|
+
c->packetRefs.push_back(packetRef);
|
|
397
|
+
c->packets.push_back(getPacket(env, value));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
for ( uint32_t x = 0 ; x < argc ; x++ ) {
|
|
402
|
+
c->status = isPacket(env, args[x]);
|
|
403
|
+
if (c->status != napi_ok) {
|
|
404
|
+
REJECT_ERROR_RETURN("All passed packets as arguments must be of type packet.",
|
|
405
|
+
BEAMCODER_INVALID_ARGS);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
for ( uint32_t x = 0 ; x < argc ; x++ ) {
|
|
409
|
+
c->status = napi_create_reference(env, args[x], 1, &packetRef);
|
|
410
|
+
REJECT_RETURN;
|
|
411
|
+
c->packetRefs.push_back(packetRef);
|
|
412
|
+
c->packets.push_back(getPacket(env, args[x]));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
c->status = napi_create_string_utf8(env, "Decode", NAPI_AUTO_LENGTH, &resourceName);
|
|
417
|
+
REJECT_RETURN;
|
|
418
|
+
c->status = napi_create_async_work(env, nullptr, resourceName, decodeExecute,
|
|
419
|
+
decodeComplete, c, &c->_request);
|
|
420
|
+
REJECT_RETURN;
|
|
421
|
+
c->status = napi_queue_async_work(env, c->_request);
|
|
422
|
+
REJECT_RETURN;
|
|
423
|
+
|
|
424
|
+
free(args);
|
|
425
|
+
|
|
426
|
+
return promise;
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
napi_status isPacket(napi_env env, napi_value packet) {
|
|
430
|
+
napi_status status;
|
|
431
|
+
napi_value value;
|
|
432
|
+
bool result;
|
|
433
|
+
char objType[10];
|
|
434
|
+
size_t typeLen;
|
|
435
|
+
int cmp;
|
|
436
|
+
napi_valuetype type;
|
|
437
|
+
|
|
438
|
+
status = napi_typeof(env, packet, &type);
|
|
439
|
+
if ((status != napi_ok) || (type != napi_object)) return napi_invalid_arg;
|
|
440
|
+
status = napi_is_array(env, packet, &result);
|
|
441
|
+
if ((status != napi_ok) || (result == true)) return napi_invalid_arg;
|
|
442
|
+
|
|
443
|
+
status = napi_has_named_property(env, packet, "type", &result);
|
|
444
|
+
if ((status != napi_ok) || (result == false)) return napi_invalid_arg;
|
|
445
|
+
|
|
446
|
+
status = napi_has_named_property(env, packet, "_packet", &result);
|
|
447
|
+
if ((status != napi_ok) || (result == false)) return napi_invalid_arg;
|
|
448
|
+
|
|
449
|
+
status = napi_get_named_property(env, packet, "type", &value);
|
|
450
|
+
if (status != napi_ok) return status;
|
|
451
|
+
status = napi_get_value_string_utf8(env, value, objType, 10, &typeLen);
|
|
452
|
+
if (status != napi_ok) return status;
|
|
453
|
+
cmp = strcmp("Packet", objType);
|
|
454
|
+
if (cmp != 0) return napi_invalid_arg;
|
|
455
|
+
|
|
456
|
+
status = napi_get_named_property(env, packet, "_packet", &value);
|
|
457
|
+
if (status != napi_ok) return status;
|
|
458
|
+
status = napi_typeof(env, value, &type);
|
|
459
|
+
if (status != napi_ok) return status;
|
|
460
|
+
if (type != napi_external) return napi_invalid_arg;
|
|
461
|
+
|
|
462
|
+
return napi_ok;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
AVPacket* getPacket(napi_env env, napi_value packet) {
|
|
466
|
+
napi_status status;
|
|
467
|
+
napi_value value;
|
|
468
|
+
packetData* result = nullptr;
|
|
469
|
+
status = napi_get_named_property(env, packet, "_packet", &value);
|
|
470
|
+
if (status != napi_ok) return nullptr;
|
|
471
|
+
status = napi_get_value_external(env, value, (void**) &result);
|
|
472
|
+
if (status != napi_ok) return nullptr;
|
|
473
|
+
|
|
474
|
+
return result->packet;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
napi_value flushDec(napi_env env, napi_callback_info info) {
|
|
478
|
+
decodeCarrier* c = new decodeCarrier;
|
|
479
|
+
napi_value decoderJS, decoderExt, promise, resourceName;
|
|
480
|
+
|
|
481
|
+
c->status = napi_create_promise(env, &c->_deferred, &promise);
|
|
482
|
+
REJECT_RETURN;
|
|
483
|
+
|
|
484
|
+
size_t argc = 0;
|
|
485
|
+
napi_value* args = nullptr;
|
|
486
|
+
|
|
487
|
+
c->status = napi_get_cb_info(env, info, &argc, args, &decoderJS, nullptr);
|
|
488
|
+
REJECT_RETURN;
|
|
489
|
+
c->status = napi_get_named_property(env, decoderJS, "_CodecContext", &decoderExt);
|
|
490
|
+
REJECT_RETURN;
|
|
491
|
+
c->status = napi_get_value_external(env, decoderExt, (void**) &c->decoder);
|
|
492
|
+
REJECT_RETURN;
|
|
493
|
+
|
|
494
|
+
if (argc != 0) {
|
|
495
|
+
REJECT_ERROR_RETURN("Decode flush takes no arguments.",
|
|
496
|
+
BEAMCODER_INVALID_ARGS);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
c->packets.push_back(nullptr);
|
|
500
|
+
|
|
501
|
+
c->status = napi_create_string_utf8(env, "DecodeFlush", NAPI_AUTO_LENGTH, &resourceName);
|
|
502
|
+
REJECT_RETURN;
|
|
503
|
+
c->status = napi_create_async_work(env, nullptr, resourceName, decodeExecute,
|
|
504
|
+
decodeComplete, c, &c->_request);
|
|
505
|
+
REJECT_RETURN;
|
|
506
|
+
c->status = napi_queue_async_work(env, c->_request);
|
|
507
|
+
REJECT_RETURN;
|
|
508
|
+
|
|
509
|
+
return promise;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/* napi_value getDecProperties(napi_env env, napi_callback_info info) {
|
|
513
|
+
napi_status status;
|
|
514
|
+
napi_value result, decoderJS, decoderExt;
|
|
515
|
+
AVCodecContext* decoder;
|
|
516
|
+
|
|
517
|
+
size_t argc = 0;
|
|
518
|
+
napi_value* args = nullptr;
|
|
519
|
+
|
|
520
|
+
status = napi_get_cb_info(env, info, &argc, args, &decoderJS, nullptr);
|
|
521
|
+
CHECK_STATUS;
|
|
522
|
+
status = napi_get_named_property(env, decoderJS, "_CodecContext", &decoderExt);
|
|
523
|
+
CHECK_STATUS;
|
|
524
|
+
status = napi_get_value_external(env, decoderExt, (void**) &decoder);
|
|
525
|
+
CHECK_STATUS;
|
|
526
|
+
|
|
527
|
+
status = napi_create_object(env, &result);
|
|
528
|
+
CHECK_STATUS;
|
|
529
|
+
status = beam_set_string_utf8(env, result, "type", "CodecContext");
|
|
530
|
+
CHECK_STATUS;
|
|
531
|
+
status = beam_set_bool(env, result, "encoding", false);
|
|
532
|
+
CHECK_STATUS;
|
|
533
|
+
status = getPropsFromCodec(env, result, decoder, false);
|
|
534
|
+
CHECK_STATUS;
|
|
535
|
+
|
|
536
|
+
return result;
|
|
537
|
+
} */
|
|
538
|
+
|
|
539
|
+
/* napi_value setDecProperties(napi_env env, napi_callback_info info) {
|
|
540
|
+
napi_status status;
|
|
541
|
+
napi_value result, decoderJS, decoderExt;
|
|
542
|
+
napi_valuetype type;
|
|
543
|
+
AVCodecContext* decoder;
|
|
544
|
+
|
|
545
|
+
size_t argc = 1;
|
|
546
|
+
napi_value args[1];
|
|
547
|
+
|
|
548
|
+
status = napi_get_cb_info(env, info, &argc, args, &decoderJS, nullptr);
|
|
549
|
+
CHECK_STATUS;
|
|
550
|
+
status = napi_get_named_property(env, decoderJS, "_CodecContext", &decoderExt);
|
|
551
|
+
CHECK_STATUS;
|
|
552
|
+
status = napi_get_value_external(env, decoderExt, (void**) &decoder);
|
|
553
|
+
CHECK_STATUS;
|
|
554
|
+
|
|
555
|
+
if (argc < 1) {
|
|
556
|
+
NAPI_THROW_ERROR("Cannot set decoder properties with no values.");
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
status = napi_typeof(env, args[0], &type);
|
|
560
|
+
CHECK_STATUS;
|
|
561
|
+
if (type != napi_object) {
|
|
562
|
+
NAPI_THROW_ERROR("Set properties must be provided as a single object.");
|
|
563
|
+
}
|
|
564
|
+
setCodecFromProps(env, decoder, args[0], false);
|
|
565
|
+
|
|
566
|
+
status = napi_get_undefined(env, &result);
|
|
567
|
+
CHECK_STATUS;
|
|
568
|
+
return result;
|
|
569
|
+
}; */
|
package/src/decode.h
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
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 DECODE_H
|
|
23
|
+
#define DECODE_H
|
|
24
|
+
|
|
25
|
+
#include "beamcoder_util.h"
|
|
26
|
+
#include "packet.h"
|
|
27
|
+
#include "frame.h"
|
|
28
|
+
#include "codec.h"
|
|
29
|
+
#include <vector>
|
|
30
|
+
|
|
31
|
+
extern "C" {
|
|
32
|
+
#include <libavcodec/avcodec.h>
|
|
33
|
+
#include <libavutil/pixdesc.h>
|
|
34
|
+
#include <libavutil/opt.h>
|
|
35
|
+
#include <libavformat/avformat.h>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
napi_value decoder(napi_env env, napi_callback_info info);
|
|
39
|
+
|
|
40
|
+
void decodeExecute(napi_env env, void* data);
|
|
41
|
+
void decodeComplete(napi_env env, napi_status asyncStatus, void* data);
|
|
42
|
+
napi_value decode(napi_env env, napi_callback_info info);
|
|
43
|
+
napi_value flushDec(napi_env env, napi_callback_info info);
|
|
44
|
+
|
|
45
|
+
void decoderFinalizer(napi_env env, void* data, void* hint);
|
|
46
|
+
|
|
47
|
+
/* struct decoderCarrier : carrier {
|
|
48
|
+
AVCodecContext* decoder = nullptr;
|
|
49
|
+
AVCodecParameters* params = nullptr;
|
|
50
|
+
int streamIdx = -1;
|
|
51
|
+
char* codecName;
|
|
52
|
+
size_t codecNameLen = 0;
|
|
53
|
+
int32_t codecID = -1;
|
|
54
|
+
~decoderCarrier() {
|
|
55
|
+
if (decoder != nullptr) {
|
|
56
|
+
avcodec_close(decoder);
|
|
57
|
+
avcodec_free_context(&decoder);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}; */
|
|
61
|
+
|
|
62
|
+
struct decodeCarrier : carrier {
|
|
63
|
+
AVCodecContext* decoder;
|
|
64
|
+
std::vector<AVPacket*> packets;
|
|
65
|
+
std::vector<AVFrame*> frames;
|
|
66
|
+
std::vector<napi_ref> packetRefs;
|
|
67
|
+
~decodeCarrier() {
|
|
68
|
+
// printf("Decode carrier destructor.\n");
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
napi_status isPacket(napi_env env, napi_value packet);
|
|
73
|
+
AVPacket* getPacket(napi_env env, napi_value packet);
|
|
74
|
+
|
|
75
|
+
#endif // DECODE_H
|