Skip to content

Commit b98c158

Browse files
committed
Add support for hardware accelerated decoding
1 parent 4817866 commit b98c158

File tree

5 files changed

+150
-28
lines changed

5 files changed

+150
-28
lines changed

scratch/decode_avci.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,29 @@
2222
const beamcoder = require('../index.js');
2323

2424
async function run() {
25-
let demuxer = await beamcoder.demuxer('../media/dpp/AS11_DPP_HD_EXAMPLE_1.mxf');
26-
console.log(JSON.stringify(demuxer, null, 2));
25+
// let demuxer = await beamcoder.demuxer('../media/dpp/AS11_DPP_HD_EXAMPLE_1.mxf');
26+
// console.log(JSON.stringify(demuxer, null, 2));
27+
let demuxer = await beamcoder.demuxer('M:/dpp/AS11_4K_8.mxf');
28+
// let demuxer = await beamcoder.demuxer('M:/dpp/AS11.mxf');
2729
demuxer.streams.forEach(s => s.discard = (0 == s.index) ? 'default' : 'all');
28-
let decoder = beamcoder.decoder({ name: 'h264' });
29-
//console.log(JSON.stringify(decoder, null, 2));
30+
// let decoder = beamcoder.decoder({ name: 'h264', thread_count: 4, thread_type: { FRAME: false, SLICE: true } });
31+
let decoder = beamcoder.decoder({ name: 'h264', thread_count: 1, hwaccel: 'auto' });
32+
// console.dir(decoder, { getters: true, depth: 3 });
3033
let packet = {};
31-
for ( let x = 0 ; x < 200 && packet != null; x++ ) {
32-
let packet = await demuxer.read();
33-
if (packet.stream_index === 0) {
34+
for ( let x = 0 ; x < 2000 && packet != null; x++ ) {
35+
packet = await demuxer.read();
36+
if (packet && packet.stream_index === 0) {
3437
//console.log(JSON.stringify(packet, null, 2));
3538
let frames = await decoder.decode(packet);
36-
console.log(JSON.stringify(frames.frames[0], null, 2));
39+
// console.log(JSON.stringify(frames.frames[0], null, 2));
40+
if (frames.frames[0]) {
41+
console.log(frames.frames[0].data);
42+
}
3743
console.log(x, frames.total_time);
3844
}
3945
}
4046
let frames = await decoder.flush();
4147
console.log('flush', frames.total_time, frames.length);
42-
console.log(await demuxer.seek({ pos: 79389000 }));
43-
console.log(await demuxer.read());
4448
}
4549

4650
run();

src/codec.cc

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5391,9 +5391,9 @@ napi_value getCodecCtxThreadType(napi_env env, napi_callback_info info) {
53915391

53925392
status = napi_create_object(env, &result);
53935393
CHECK_STATUS;
5394-
status = beam_set_bool(env, result, "FRAME", codec->thread_type & FF_THREAD_FRAME);
5394+
status = beam_set_bool(env, result, "FRAME", (codec->thread_type & FF_THREAD_FRAME) == FF_THREAD_FRAME);
53955395
CHECK_STATUS;
5396-
status = beam_set_bool(env, result, "SLICE", codec->thread_type & FF_THREAD_SLICE);
5396+
status = beam_set_bool(env, result, "SLICE", (codec->thread_type & FF_THREAD_SLICE) == FF_THREAD_SLICE);
53975397
CHECK_STATUS;
53985398

53995399
return result;
@@ -5445,9 +5445,9 @@ napi_value getCodecCtxActThreadType(napi_env env, napi_callback_info info) {
54455445

54465446
status = napi_create_object(env, &result);
54475447
CHECK_STATUS;
5448-
status = beam_set_bool(env, result, "FRAME", codec->active_thread_type & FF_THREAD_FRAME);
5448+
status = beam_set_bool(env, result, "FRAME", (codec->active_thread_type & FF_THREAD_FRAME) == FF_THREAD_FRAME);
54495449
CHECK_STATUS;
5450-
status = beam_set_bool(env, result, "SLICE", codec->active_thread_type & FF_THREAD_SLICE);
5450+
status = beam_set_bool(env, result, "SLICE", (codec->active_thread_type & FF_THREAD_SLICE) == FF_THREAD_SLICE);
54515451
CHECK_STATUS;
54525452

54535453
return result;
@@ -5945,15 +5945,22 @@ napi_value getCodecCtxSwPixFmt(napi_env env, napi_callback_info info) {
59455945
napi_status status;
59465946
napi_value result;
59475947
AVCodecContext* codec;
5948+
AVBufferRef* hwFramesContextRef;
5949+
AVHWFramesContext* hwFramesContext = nullptr;
5950+
AVPixelFormat sw_pix_fmt;
59485951
const char* pixFmtName;
59495952

59505953
size_t argc = 0;
59515954
status = napi_get_cb_info(env, info, &argc, nullptr, nullptr, (void**) &codec);
59525955
CHECK_STATUS;
59535956

5954-
pixFmtName = av_get_pix_fmt_name(codec->sw_pix_fmt);
5957+
hwFramesContextRef = codec->hw_frames_ctx;
5958+
if (hwFramesContextRef)
5959+
hwFramesContext = (AVHWFramesContext*)hwFramesContextRef->data;
5960+
sw_pix_fmt = hwFramesContext ? hwFramesContext->sw_format : codec->sw_pix_fmt;
5961+
pixFmtName = av_get_pix_fmt_name(sw_pix_fmt);
59555962
if (pixFmtName != nullptr) {
5956-
status = napi_create_string_utf8(env, (char*) pixFmtName, NAPI_AUTO_LENGTH, &result);
5963+
status = napi_create_string_utf8(env, pixFmtName, NAPI_AUTO_LENGTH, &result);
59575964
CHECK_STATUS;
59585965
} else {
59595966
status = napi_get_null(env, &result);

src/decode.cc

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,62 @@
2121

2222
#include "decode.h"
2323

24+
char* req_hw_type = nullptr;
25+
AVPixelFormat req_hw_pix_fmt = AV_PIX_FMT_NONE;
26+
27+
AVPixelFormat get_format(AVCodecContext *s, const AVPixelFormat *pix_fmts)
28+
{
29+
AVPixelFormat result = AV_PIX_FMT_NONE;
30+
const AVPixelFormat *p;
31+
int i, err;
32+
33+
if (0 == strcmp("auto", req_hw_type)) {
34+
for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
35+
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
36+
const AVCodecHWConfig *config = NULL;
37+
38+
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
39+
break;
40+
41+
for (i = 0;; i++) {
42+
config = avcodec_get_hw_config(s->codec, i);
43+
if (!config)
44+
break;
45+
if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
46+
continue;
47+
if (config->pix_fmt == *p)
48+
break;
49+
}
50+
51+
if (config) {
52+
err = av_hwdevice_ctx_create(&s->hw_device_ctx, config->device_type, NULL, NULL, 0);
53+
if (err < 0) {
54+
char errstr[128];
55+
av_make_error_string(errstr, 128, err);
56+
printf("Error in get_format \'auto\' av_hwdevice_ctx_create: %s\n", errstr);
57+
}
58+
break;
59+
}
60+
}
61+
result = *p;
62+
} else {
63+
err = av_hwdevice_ctx_create(&s->hw_device_ctx, av_hwdevice_find_type_by_name(req_hw_type), NULL, NULL, 0);
64+
if (err < 0) {
65+
char errstr[128];
66+
av_make_error_string(errstr, 128, err);
67+
printf("Error in get_format \'%s\' av_hwdevice_ctx_create: %s\n", req_hw_type, errstr);
68+
}
69+
result = req_hw_pix_fmt;
70+
}
71+
72+
return result;
73+
}
74+
2475
napi_value decoder(napi_env env, napi_callback_info info) {
2576
napi_status status;
2677
napi_value result, value, formatJS, formatExt, global, jsObject, assign, jsParams;
2778
napi_valuetype type;
28-
bool isArray, hasName, hasID, hasFormat, hasStream, hasParams;
79+
bool isArray, hasName, hasID, hasFormat, hasStream, hasParams, hasHWaccel;
2980
AVCodecContext* decoder = nullptr;
3081
AVFormatContext* format = nullptr;
3182
const AVCodec* codec = nullptr;
@@ -34,6 +85,7 @@ napi_value decoder(napi_env env, napi_callback_info info) {
3485
AVCodecParameters* params = nullptr;
3586
char* codecName = nullptr;
3687
size_t codecNameLen = 0;
88+
size_t hwTypeLen = 0;
3789
int32_t codecID = -1;
3890

3991
size_t argc = 1;
@@ -148,6 +200,24 @@ napi_value decoder(napi_env env, napi_callback_info info) {
148200
}
149201
}
150202

203+
status = napi_has_named_property(env, args[0], "hwaccel", &hasHWaccel);
204+
CHECK_STATUS;
205+
if (hasHWaccel) {
206+
status = napi_get_named_property(env, args[0], "hwaccel", &value);
207+
CHECK_STATUS;
208+
hwTypeLen = 64;
209+
req_hw_type = (char*) malloc(sizeof(char) * (hwTypeLen + 1));
210+
status = napi_get_value_string_utf8(env, value, req_hw_type,
211+
64, &hwTypeLen);
212+
CHECK_STATUS;
213+
req_hw_pix_fmt = av_get_pix_fmt(req_hw_type);
214+
215+
if (0 != strcmp("auto", req_hw_type) && req_hw_pix_fmt == AV_PIX_FMT_NONE)
216+
printf("Decoder hwaccel name \'%s\' not recognised\n", req_hw_type);
217+
else
218+
decoder->get_format = get_format;
219+
}
220+
151221
status = fromAVCodecContext(env, decoder, &result, false);
152222
const napi_value fargs[2] = { result, args[0] };
153223
CHECK_BAIL;
@@ -182,6 +252,7 @@ void decodeExecute(napi_env env, void* data) {
182252
decodeCarrier* c = (decodeCarrier*) data;
183253
int ret = 0;
184254
AVFrame* frame = nullptr;
255+
AVFrame *sw_frame = nullptr;
185256
HR_TIME_POINT decodeStart = NOW;
186257

187258
for ( auto it = c->packets.cbegin() ; it != c->packets.cend() ; it++ ) {
@@ -219,15 +290,30 @@ void decodeExecute(napi_env env, void* data) {
219290
}
220291
} // loop through input packets
221292

293+
AVPixelFormat frame_hw_pix_fmt = AV_PIX_FMT_NONE;
294+
if (c->decoder->hw_frames_ctx)
295+
frame_hw_pix_fmt = ((AVHWFramesContext*)c->decoder->hw_frames_ctx->data)->format;
296+
297+
frame = av_frame_alloc();
298+
sw_frame = av_frame_alloc();
222299
do {
223-
frame = av_frame_alloc();
224300
ret = avcodec_receive_frame(c->decoder, frame);
225301
if (ret == 0) {
226-
c->frames.push_back(frame);
302+
if (frame->format == frame_hw_pix_fmt) {
303+
if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) {
304+
printf("Error transferring hw data to system memory\n");
305+
}
306+
c->frames.push_back(sw_frame);
307+
av_frame_free(&frame);
308+
} else
309+
c->frames.push_back(frame);
310+
227311
frame = av_frame_alloc();
312+
sw_frame = av_frame_alloc();
228313
}
229314
} while (ret == 0);
230315
av_frame_free(&frame);
316+
av_frame_free(&sw_frame);
231317

232318
c->totalTime = microTime(decodeStart);
233319
};

src/frame.cc

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,21 +1051,46 @@ napi_value getFrameData(napi_env env, napi_callback_info info) {
10511051
napi_status status;
10521052
napi_value array, element;
10531053
frameData* f;
1054-
AVBufferRef* hintRef;
1054+
uint8_t* data;
1055+
AVBufferRef* ref;
1056+
size_t size;
1057+
int curElem;
10551058

10561059
status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &f);
10571060
CHECK_STATUS;
10581061

10591062
status = napi_create_array(env, &array);
10601063
CHECK_STATUS;
1061-
for ( int x = 0 ; x < AV_NUM_DATA_POINTERS ; x++ ) {
1062-
// printf("Buffer %i is %p\n", x, f->frame->buf[x]);
1063-
if (f->frame->buf[x] == nullptr) continue;
1064-
hintRef = av_buffer_ref(f->frame->buf[x]);
1065-
status = napi_create_external_buffer(env, hintRef->size, hintRef->data,
1066-
frameBufferFinalizer, hintRef, &element);
1064+
1065+
data = f->frame->data[0];
1066+
ref = av_buffer_ref(f->frame->buf[0]);
1067+
size = ref->size;
1068+
curElem = 0;
1069+
// work through frame bufs checking whether allocation refcounts are shared
1070+
for ( int x = 1 ; x < AV_NUM_DATA_POINTERS ; x++ ) {
1071+
// printf("Buffer %i is %p\n", x, f->frame->data[x]);
1072+
if (f->frame->data[x] == nullptr) continue;
1073+
size_t bufSize = size;
1074+
if (f->frame->buf[x] == nullptr)
1075+
bufSize = f->frame->data[x] - f->frame->data[x-1];
1076+
status = napi_create_external_buffer(env, bufSize, data, frameBufferFinalizer, ref, &element);
10671077
CHECK_STATUS;
1068-
status = napi_set_element(env, array, x, element);
1078+
status = napi_set_element(env, array, curElem, element);
1079+
CHECK_STATUS;
1080+
data = f->frame->data[x];
1081+
if (f->frame->buf[x]) {
1082+
ref = av_buffer_ref(f->frame->buf[x]);
1083+
size = ref->size;
1084+
} else {
1085+
ref = nullptr;
1086+
size -= f->frame->data[x] - f->frame->data[x-1];
1087+
}
1088+
curElem++;
1089+
}
1090+
if (data) {
1091+
status = napi_create_external_buffer(env, size, data, frameBufferFinalizer, ref, &element);
1092+
CHECK_STATUS;
1093+
status = napi_set_element(env, array, curElem, element);
10691094
CHECK_STATUS;
10701095
}
10711096

src/hwcontext.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ napi_value getHWFramesCtxSwPixFmt(napi_env env, napi_callback_info info) {
208208
status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &frames_context);
209209
CHECK_STATUS;
210210

211-
AVPixelFormat pixFmt = frames_context->format;
211+
AVPixelFormat pixFmt = frames_context->sw_format;
212212
status = napi_create_string_utf8(env, av_get_pix_fmt_name(pixFmt), NAPI_AUTO_LENGTH, &result);
213213
CHECK_STATUS;
214214

0 commit comments

Comments
 (0)