', autoPos);
const autoStr = htmlStr.substring(autoPos, endPos);
- const sharedEndPos = autoStr.lastIndexOf('">win64-gpl-shared-4.3');
+ const sharedEndPos = autoStr.lastIndexOf('">win64-gpl-shared-4.');
+ if (sharedEndPos === -1)
+ throw new Error('Failed to find latest v4.x autobuild from "https://github.com/BtbN/FFmpeg-Builds/wiki/Latest"');
const startStr = ' s.discard = (0 == s.index) ? 'default' : 'all');
- let decoder = beamcoder.decoder({ name: 'h264' });
- //console.log(JSON.stringify(decoder, null, 2));
+ // let decoder = beamcoder.decoder({ name: 'h264', thread_count: 4, thread_type: { FRAME: false, SLICE: true } });
+ let decoder = beamcoder.decoder({ name: 'h264', thread_count: 1, hwaccel: true });
+ // console.dir(decoder, { getters: true, depth: 3 });
let packet = {};
- for ( let x = 0 ; x < 200 && packet != null; x++ ) {
- let packet = await demuxer.read();
- if (packet.stream_index === 0) {
+ for ( let x = 0 ; x < 2000 && packet != null; x++ ) {
+ packet = await demuxer.read();
+ if (packet && packet.stream_index === 0) {
//console.log(JSON.stringify(packet, null, 2));
let frames = await decoder.decode(packet);
- console.log(JSON.stringify(frames.frames[0], null, 2));
+ // console.log(JSON.stringify(frames.frames[0], null, 2));
+ if (frames.frames[0]) {
+ console.log(frames.frames[0].data);
+ }
console.log(x, frames.total_time);
}
}
let frames = await decoder.flush();
console.log('flush', frames.total_time, frames.length);
- console.log(await demuxer.seek({ pos: 79389000 }));
- console.log(await demuxer.read());
}
run();
diff --git a/src/codec.cc b/src/codec.cc
index 176a61b..95df3e0 100644
--- a/src/codec.cc
+++ b/src/codec.cc
@@ -4871,12 +4871,6 @@ napi_value getCodecCtxDebug(napi_env env, napi_callback_info info) {
CHECK_STATUS;
status = beam_set_bool(env, result, "BUGS", codec->debug & FF_DEBUG_BUGS);
CHECK_STATUS;
- #if FF_API_DEBUG_MV
- status = beam_set_bool(env, result, "VIS_QP", codec->debug & FF_DEBUG_VIS_QP);
- CHECK_STATUS;
- status = beam_set_bool(env, result, "VIS_MB_TYPE", codec->debug & FF_DEBUG_VIS_MB_TYPE);
- CHECK_STATUS;
- #endif
status = beam_set_bool(env, result, "BUFFERS", codec->debug & FF_DEBUG_BUFFERS);
CHECK_STATUS;
status = beam_set_bool(env, result, "THREADS", codec->debug & FF_DEBUG_THREADS);
@@ -4963,18 +4957,6 @@ napi_value setCodecCtxDebug(napi_env env, napi_callback_info info) {
if (present) { codec->debug = (flag) ?
codec->debug | FF_DEBUG_BUGS :
codec->debug & ~FF_DEBUG_BUGS; }
-#if FF_API_DEBUG_MV
- status = beam_get_bool(env, args[0], "VIS_QP", &present, &flag);
- CHECK_STATUS;
- if (present) { codec->debug = (flag) ?
- codec->debug | FF_DEBUG_VIS_QP :
- codec->debug & ~FF_DEBUG_VIS_QP; }
- status = beam_get_bool(env, args[0], "VIS_MB_TYPE", &present, &flag);
- CHECK_STATUS;
- if (present) { codec->debug = (flag) ?
- codec->debug | FF_DEBUG_VIS_MB_TYPE :
- codec->debug & ~FF_DEBUG_VIS_MB_TYPE; }
-#endif
status = beam_get_bool(env, args[0], "BUFFERS", &present, &flag);
CHECK_STATUS;
if (present) { codec->debug = (flag) ?
@@ -5409,9 +5391,9 @@ napi_value getCodecCtxThreadType(napi_env env, napi_callback_info info) {
status = napi_create_object(env, &result);
CHECK_STATUS;
- status = beam_set_bool(env, result, "FRAME", codec->thread_type & FF_THREAD_FRAME);
+ status = beam_set_bool(env, result, "FRAME", (codec->thread_type & FF_THREAD_FRAME) == FF_THREAD_FRAME);
CHECK_STATUS;
- status = beam_set_bool(env, result, "SLICE", codec->thread_type & FF_THREAD_SLICE);
+ status = beam_set_bool(env, result, "SLICE", (codec->thread_type & FF_THREAD_SLICE) == FF_THREAD_SLICE);
CHECK_STATUS;
return result;
@@ -5463,55 +5445,14 @@ napi_value getCodecCtxActThreadType(napi_env env, napi_callback_info info) {
status = napi_create_object(env, &result);
CHECK_STATUS;
- status = beam_set_bool(env, result, "FRAME", codec->active_thread_type & FF_THREAD_FRAME);
- CHECK_STATUS;
- status = beam_set_bool(env, result, "SLICE", codec->active_thread_type & FF_THREAD_SLICE);
- CHECK_STATUS;
-
- return result;
-}
-
-napi_value getCodecCtxThreadSafeCBs(napi_env env, napi_callback_info info) {
- napi_status status;
- napi_value result;
- AVCodecContext* codec;
-
- size_t argc = 0;
- status = napi_get_cb_info(env, info, &argc, nullptr, nullptr, (void**) &codec);
+ status = beam_set_bool(env, result, "FRAME", (codec->active_thread_type & FF_THREAD_FRAME) == FF_THREAD_FRAME);
CHECK_STATUS;
- status = napi_create_int32(env, codec->thread_safe_callbacks, &result);
+ status = beam_set_bool(env, result, "SLICE", (codec->active_thread_type & FF_THREAD_SLICE) == FF_THREAD_SLICE);
CHECK_STATUS;
return result;
}
-napi_value setCodecCtxThreadSafeCBs(napi_env env, napi_callback_info info) {
- napi_status status;
- napi_value result;
- napi_valuetype type;
- AVCodecContext* codec;
-
- size_t argc = 1;
- napi_value args[1];
- status = napi_get_cb_info(env, info, &argc, args, nullptr, (void**) &codec);
- CHECK_STATUS;
- if (argc < 1) {
- NAPI_THROW_ERROR("A value is required to set the thread_safe_callbacks property.");
- }
- status = napi_typeof(env, args[0], &type);
- CHECK_STATUS;
- if (type != napi_number) {
- NAPI_THROW_ERROR("A number is required to set the thread_safe_callbacks property.");
- }
-
- status = napi_get_value_int32(env, args[0], &codec->thread_safe_callbacks);
- CHECK_STATUS;
-
- status = napi_get_undefined(env, &result);
- CHECK_STATUS;
- return result;
-}
-
napi_value getCodecCtxNsseWeight(napi_env env, napi_callback_info info) {
napi_status status;
napi_value result;
@@ -6004,15 +5945,22 @@ napi_value getCodecCtxSwPixFmt(napi_env env, napi_callback_info info) {
napi_status status;
napi_value result;
AVCodecContext* codec;
+ AVBufferRef* hwFramesContextRef;
+ AVHWFramesContext* hwFramesContext = nullptr;
+ AVPixelFormat sw_pix_fmt;
const char* pixFmtName;
size_t argc = 0;
status = napi_get_cb_info(env, info, &argc, nullptr, nullptr, (void**) &codec);
CHECK_STATUS;
- pixFmtName = av_get_pix_fmt_name(codec->sw_pix_fmt);
+ hwFramesContextRef = codec->hw_frames_ctx;
+ if (hwFramesContextRef)
+ hwFramesContext = (AVHWFramesContext*)hwFramesContextRef->data;
+ sw_pix_fmt = hwFramesContext ? hwFramesContext->sw_format : codec->sw_pix_fmt;
+ pixFmtName = av_get_pix_fmt_name(sw_pix_fmt);
if (pixFmtName != nullptr) {
- status = napi_create_string_utf8(env, (char*) pixFmtName, NAPI_AUTO_LENGTH, &result);
+ status = napi_create_string_utf8(env, pixFmtName, NAPI_AUTO_LENGTH, &result);
CHECK_STATUS;
} else {
status = napi_get_null(env, &result);
@@ -7221,8 +7169,6 @@ napi_status fromAVCodecContext(napi_env env, AVCodecContext* codec,
{ "active_thread_type", nullptr, nullptr, getCodecCtxActThreadType, failBoth, nullptr,
napi_enumerable, codec},
// TODO find a way of exposing a custom getBuffer?
- { "thread_safe_callbacks", nullptr, nullptr, getCodecCtxThreadSafeCBs, setCodecCtxThreadSafeCBs, nullptr,
- (napi_property_attributes) (napi_writable | napi_enumerable), codec},
{ "nsse_weight", nullptr, nullptr,
encoding ? getCodecCtxNsseWeight : nullptr,
encoding ? setCodecCtxNsseWeight : failDecoding, nullptr,
@@ -7230,10 +7176,10 @@ napi_status fromAVCodecContext(napi_env env, AVCodecContext* codec,
{ "profile", nullptr, nullptr, getCodecCtxProfile,
encoding ? setCodecCtxProfile : failDecoding, nullptr,
encoding ? (napi_property_attributes) (napi_writable | napi_enumerable) : napi_enumerable, codec},
- // 110
{ "level", nullptr, nullptr, getCodecCtxLevel,
encoding ? setCodecCtxLevel : failDecoding, nullptr,
encoding ? (napi_property_attributes) (napi_writable | napi_enumerable) : napi_enumerable, codec},
+ // 110
{ "skip_loop_filter", nullptr, nullptr,
encoding ? nullptr : getCodecCtxSkipLpFilter,
encoding ? failEncoding : setCodecCtxSkipLpFilter, nullptr,
@@ -7267,11 +7213,11 @@ napi_status fromAVCodecContext(napi_env env, AVCodecContext* codec,
encoding ? napi_default : napi_enumerable, codec},
// TODO not exposing lowres ... it's on its way out
// not exposing PTS correct stats - "not intended to be used by user apps"
- // 120
{ "sub_charenc", nullptr, nullptr,
encoding ? nullptr : getCodecCtxSubCharenc,
encoding ? failEncoding : setCodecCtxSubCharenc, nullptr,
encoding ? napi_default : (napi_property_attributes) (napi_writable | napi_enumerable), codec},
+ // 120
{ "sub_charenc_mode", nullptr, nullptr,
encoding ? nullptr : getCodecCtxSubCharencMode, failBoth, nullptr,
encoding ? napi_default : napi_enumerable, codec},
@@ -7302,11 +7248,11 @@ napi_status fromAVCodecContext(napi_env env, AVCodecContext* codec,
getCodecHWFramesCtx,
encoding ? setCodecHWFramesCtx : failDecoding, nullptr,
encoding ? (napi_property_attributes) (napi_writable | napi_enumerable) : napi_enumerable, codec},
- // 130
{ "sub_text_format", nullptr, nullptr,
encoding ? nullptr : getCodecCtxSubTextFmt,
encoding ? failEncoding : setCodecCtxSubTextFmt, nullptr,
encoding ? napi_default : (napi_property_attributes) (napi_writable | napi_enumerable), codec},
+ // 130
{ "trailing_padding", nullptr, nullptr, getCodecCtxTrailPad, setCodecCtxTrailPad, nullptr,
(napi_property_attributes) (napi_writable | napi_enumerable), codec},
{ "max_pixels", nullptr, nullptr, getCodecCtxMaxPixels, setCodecCtxMaxPixels, nullptr,
@@ -7330,15 +7276,15 @@ napi_status fromAVCodecContext(napi_env env, AVCodecContext* codec,
encoding ? flushEnc : flushDec, nullptr, nullptr, nullptr, napi_enumerable, codec},
{ "extractParams", nullptr, extractParams, nullptr, nullptr, nullptr, napi_enumerable, nullptr},
{ "useParams", nullptr, useParams, nullptr, nullptr, nullptr, napi_enumerable, nullptr},
- // 140
// Hidden values - to allow Object.assign to work
{ "params", nullptr, nullptr, nullptr, nop, undef, // Set for muxing
napi_writable, nullptr},
+ // 140
{ "stream_index", nullptr, nullptr, nullptr, nop, undef, napi_writable, nullptr },
{ "demuxer", nullptr, nullptr, nullptr, nop, undef, napi_writable, nullptr},
{ "_CodecContext", nullptr, nullptr, nullptr, nullptr, extCodec, napi_default, nullptr }
};
- status = napi_define_properties(env, jsCodec, 144, desc);
+ status = napi_define_properties(env, jsCodec, 143, desc);
PASS_STATUS;
*result = jsCodec;
diff --git a/src/decode.cc b/src/decode.cc
index 9ff6d14..b196ddb 100644
--- a/src/decode.cc
+++ b/src/decode.cc
@@ -21,11 +21,47 @@
#include "decode.h"
+AVPixelFormat get_format(AVCodecContext *s, const AVPixelFormat *pix_fmts)
+{
+ const AVPixelFormat *p;
+ int i, err;
+
+ for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
+ const AVCodecHWConfig *config = NULL;
+
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ break;
+
+ for (i = 0;; i++) {
+ config = avcodec_get_hw_config(s->codec, i);
+ if (!config)
+ break;
+ if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
+ continue;
+ if (config->pix_fmt == *p)
+ break;
+ }
+
+ if (config) {
+ err = av_hwdevice_ctx_create(&s->hw_device_ctx, config->device_type, NULL, NULL, 0);
+ if (err < 0) {
+ char errstr[128];
+ av_make_error_string(errstr, 128, err);
+ printf("Error in get_format av_hwdevice_ctx_create: %s\n", errstr);
+ }
+ break;
+ }
+ }
+
+ return *p;
+}
+
napi_value decoder(napi_env env, napi_callback_info info) {
napi_status status;
napi_value result, value, formatJS, formatExt, global, jsObject, assign, jsParams;
napi_valuetype type;
- bool isArray, hasName, hasID, hasFormat, hasStream, hasParams;
+ bool isArray, hasName, hasID, hasFormat, hasStream, hasParams, hasHWaccel;
AVCodecContext* decoder = nullptr;
AVFormatContext* format = nullptr;
const AVCodec* codec = nullptr;
@@ -35,6 +71,7 @@ napi_value decoder(napi_env env, napi_callback_info info) {
char* codecName = nullptr;
size_t codecNameLen = 0;
int32_t codecID = -1;
+ bool hwaccel = false;
size_t argc = 1;
napi_value args[1];
@@ -81,6 +118,7 @@ napi_value decoder(napi_env env, napi_callback_info info) {
NAPI_THROW_ERROR("Stream index is out of bounds for the given format.");
}
params = format->streams[streamIdx]->codecpar;
+ codecID = params->codec_id;
codecName = (char*) avcodec_get_name(params->codec_id);
codecNameLen = strlen(codecName);
goto create;
@@ -98,6 +136,7 @@ napi_value decoder(napi_env env, napi_callback_info info) {
}
status = napi_get_value_external(env, jsParams, (void**) ¶ms);
CHECK_STATUS;
+ codecID = params->codec_id;
codecName = (char*) avcodec_get_name(params->codec_id);
codecNameLen = strlen(codecName);
goto create;
@@ -146,6 +185,17 @@ napi_value decoder(napi_env env, napi_callback_info info) {
}
}
+ status = napi_has_named_property(env, args[0], "hwaccel", &hasHWaccel);
+ CHECK_STATUS;
+ if (hasHWaccel) {
+ status = napi_get_named_property(env, args[0], "hwaccel", &value);
+ CHECK_STATUS;
+ status = napi_get_value_bool(env, value, &hwaccel);
+ CHECK_STATUS;
+ if (hwaccel)
+ decoder->get_format = get_format;
+ }
+
status = fromAVCodecContext(env, decoder, &result, false);
const napi_value fargs[2] = { result, args[0] };
CHECK_BAIL;
@@ -180,6 +230,7 @@ void decodeExecute(napi_env env, void* data) {
decodeCarrier* c = (decodeCarrier*) data;
int ret = 0;
AVFrame* frame = nullptr;
+ AVFrame *sw_frame = nullptr;
HR_TIME_POINT decodeStart = NOW;
for ( auto it = c->packets.cbegin() ; it != c->packets.cend() ; it++ ) {
@@ -217,15 +268,30 @@ void decodeExecute(napi_env env, void* data) {
}
} // loop through input packets
+ AVPixelFormat frame_hw_pix_fmt = AV_PIX_FMT_NONE;
+ if (c->decoder->hw_frames_ctx)
+ frame_hw_pix_fmt = ((AVHWFramesContext*)c->decoder->hw_frames_ctx->data)->format;
+
+ frame = av_frame_alloc();
+ sw_frame = av_frame_alloc();
do {
- frame = av_frame_alloc();
ret = avcodec_receive_frame(c->decoder, frame);
if (ret == 0) {
- c->frames.push_back(frame);
+ if (frame->format == frame_hw_pix_fmt) {
+ if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) {
+ printf("Error transferring hw data to system memory\n");
+ }
+ c->frames.push_back(sw_frame);
+ av_frame_free(&frame);
+ } else
+ c->frames.push_back(frame);
+
frame = av_frame_alloc();
+ sw_frame = av_frame_alloc();
}
} while (ret == 0);
av_frame_free(&frame);
+ av_frame_free(&sw_frame);
c->totalTime = microTime(decodeStart);
};
diff --git a/src/filter.cc b/src/filter.cc
index c9bc01b..c055eee 100644
--- a/src/filter.cc
+++ b/src/filter.cc
@@ -992,13 +992,7 @@ void filtererExecute(napi_env env, void* data) {
}
p = c->outParams[i].find("channel_layouts");
if (p != c->outParams[i].end()) {
- const int64_t out_channel_layout = av_get_channel_layout(p->second.c_str());
- int out_channel_counts[] = { av_get_channel_layout_nb_channels(out_channel_layout), -1 };
- ret = av_opt_set_int_list(sinkCtx, "channel_counts", out_channel_counts, -1,
- AV_OPT_SEARCH_CHILDREN);
- if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output channel count\n"); }
-
- const int64_t out_channel_layouts[] = { out_channel_layout, -1 };
+ const int64_t out_channel_layouts[] = { (int64_t)av_get_channel_layout(p->second.c_str()), -1 };
ret = av_opt_set_int_list(sinkCtx, "channel_layouts", out_channel_layouts, -1,
AV_OPT_SEARCH_CHILDREN);
if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n"); }
@@ -1453,8 +1447,8 @@ napi_value filterer(napi_env env, napi_callback_info info) {
struct filterCarrier : carrier {
filtContexts *srcCtxs = nullptr;
filtContexts *sinkCtxs = nullptr;
- std::map > srcFrames;
- std::map > dstFrames;
+ std::unordered_map > srcFrames;
+ std::unordered_map > dstFrames;
std::vector frameRefs;
~filterCarrier() {}
};
diff --git a/src/frame.cc b/src/frame.cc
index da40cd2..baf9d4b 100644
--- a/src/frame.cc
+++ b/src/frame.cc
@@ -1051,21 +1051,46 @@ napi_value getFrameData(napi_env env, napi_callback_info info) {
napi_status status;
napi_value array, element;
frameData* f;
- AVBufferRef* hintRef;
+ uint8_t* data;
+ AVBufferRef* ref;
+ size_t size;
+ int curElem;
status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &f);
CHECK_STATUS;
status = napi_create_array(env, &array);
CHECK_STATUS;
- for ( int x = 0 ; x < AV_NUM_DATA_POINTERS ; x++ ) {
- // printf("Buffer %i is %p\n", x, f->frame->buf[x]);
- if (f->frame->buf[x] == nullptr) continue;
- hintRef = av_buffer_ref(f->frame->buf[x]);
- status = napi_create_external_buffer(env, hintRef->size, hintRef->data,
- frameBufferFinalizer, hintRef, &element);
+
+ data = f->frame->data[0];
+ ref = f->frame->buf[0] ? av_buffer_ref(f->frame->buf[0]) : nullptr;
+ size = ref ? ref->size : 0;
+ curElem = 0;
+ // work through frame bufs checking whether allocation refcounts are shared
+ for ( int x = 1 ; x < AV_NUM_DATA_POINTERS ; x++ ) {
+ // printf("Buffer %i is %p\n", x, f->frame->data[x]);
+ if (f->frame->data[x] == nullptr) continue;
+ size_t bufSize = size;
+ if (f->frame->buf[x] == nullptr)
+ bufSize = f->frame->data[x] - f->frame->data[x-1];
+ status = napi_create_external_buffer(env, bufSize, data, frameBufferFinalizer, ref, &element);
CHECK_STATUS;
- status = napi_set_element(env, array, x, element);
+ status = napi_set_element(env, array, curElem, element);
+ CHECK_STATUS;
+ data = f->frame->data[x];
+ if (f->frame->buf[x]) {
+ ref = av_buffer_ref(f->frame->buf[x]);
+ size = ref->size;
+ } else {
+ ref = nullptr;
+ size -= f->frame->data[x] - f->frame->data[x-1];
+ }
+ curElem++;
+ }
+ if (data) {
+ status = napi_create_external_buffer(env, size, data, frameBufferFinalizer, ref, &element);
+ CHECK_STATUS;
+ status = napi_set_element(env, array, curElem, element);
CHECK_STATUS;
}
diff --git a/src/hwcontext.cc b/src/hwcontext.cc
index 850dada..c739dd6 100644
--- a/src/hwcontext.cc
+++ b/src/hwcontext.cc
@@ -208,7 +208,7 @@ napi_value getHWFramesCtxSwPixFmt(napi_env env, napi_callback_info info) {
status = napi_get_cb_info(env, info, 0, nullptr, nullptr, (void**) &frames_context);
CHECK_STATUS;
- AVPixelFormat pixFmt = frames_context->format;
+ AVPixelFormat pixFmt = frames_context->sw_format;
status = napi_create_string_utf8(env, av_get_pix_fmt_name(pixFmt), NAPI_AUTO_LENGTH, &result);
CHECK_STATUS;
diff --git a/types/Muxer.d.ts b/types/Muxer.d.ts
index 81cec39..fed21bf 100644
--- a/types/Muxer.d.ts
+++ b/types/Muxer.d.ts
@@ -1,6 +1,5 @@
import { Packet } from "./Packet"
import { Frame } from "./Frame"
-import { Stream } from "./Stream"
import { OutputFormat, FormatContext } from "./FormatContext"
export interface Muxer extends Omit
- metadata: Array
+ metadata: { [key: string]: string }
/**
* Average framerate
*