mirror of
https://github.com/livepeer/lpms
synced 2026-04-22 15:57:25 +08:00
lpms: Netint hardware support (#318)
* Netint hardware support * make netcat flags depend on OS * Self-review, cleanup, temporary disable some failing tests * Uncomment signature test * Support HEVC for Netint, refactor decoder selection * Uncomment signature test, cleanup * Set profile to high for h264 in transcoding script * Pass profile in xcoderParams for Netint * enable detectionFreq test for merging
This commit is contained in:
@@ -26,12 +26,15 @@ func main() {
|
||||
var err error
|
||||
args := append([]string{os.Args[0]}, flag.Args()...)
|
||||
if len(args) <= 3 {
|
||||
panic("Usage: [-hevc] [-from dur] [-to dur] <input file> <output renditions, comma separated> <sw/nv>")
|
||||
panic("Usage: [-hevc] [-from dur] [-to dur] <input file> <output renditions, comma separated> <sw/nv/nt>")
|
||||
}
|
||||
str2accel := func(inp string) (ffmpeg.Acceleration, string) {
|
||||
if inp == "nv" {
|
||||
return ffmpeg.Nvidia, "nv"
|
||||
}
|
||||
if inp == "nt" {
|
||||
return ffmpeg.Netint, "nt"
|
||||
}
|
||||
return ffmpeg.Software, "sw"
|
||||
}
|
||||
str2profs := func(inp string) []ffmpeg.VideoProfile {
|
||||
@@ -44,6 +47,8 @@ func main() {
|
||||
}
|
||||
if *hevc {
|
||||
p.Encoder = ffmpeg.H265
|
||||
} else {
|
||||
p.Profile = ffmpeg.ProfileH264High
|
||||
}
|
||||
profs = append(profs, p)
|
||||
}
|
||||
@@ -72,7 +77,7 @@ func main() {
|
||||
options := profs2opts(profiles)
|
||||
|
||||
var dev string
|
||||
if accel == ffmpeg.Nvidia {
|
||||
if accel != ffmpeg.Software {
|
||||
if len(args) <= 4 {
|
||||
panic("Expected device number")
|
||||
}
|
||||
|
||||
Regular → Executable
+40
-27
@@ -165,16 +165,6 @@ static enum AVPixelFormat get_hw_pixfmt(AVCodecContext *vc, const enum AVPixelFo
|
||||
ret = av_hwframe_ctx_init(vc->hw_frames_ctx);
|
||||
if (AVERROR(ENOSYS) == ret) ret = lpms_ERR_INPUT_PIXFMT; // most likely
|
||||
if (ret < 0) LPMS_ERR(pixfmt_cleanup, "Unable to initialize a hardware frame pool");
|
||||
|
||||
/*
|
||||
fprintf(stderr, "selected format: hw %s sw %s\n",
|
||||
av_get_pix_fmt_name(frames->format), av_get_pix_fmt_name(frames->sw_format));
|
||||
const enum AVPixelFormat *p;
|
||||
for (p = pix_fmts; *p != -1; p++) {
|
||||
fprintf(stderr,"possible format: %s\n", av_get_pix_fmt_name(*p));
|
||||
}
|
||||
*/
|
||||
|
||||
return frames->format;
|
||||
|
||||
pixfmt_cleanup:
|
||||
@@ -211,19 +201,35 @@ open_audio_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* get_hw_decoder(int ff_codec_id)
|
||||
char* get_hw_decoder(int ff_codec_id, int hw_type)
|
||||
{
|
||||
switch (ff_codec_id) {
|
||||
case AV_CODEC_ID_H264:
|
||||
return "h264_cuvid";
|
||||
case AV_CODEC_ID_HEVC:
|
||||
return "hevc_cuvid";
|
||||
case AV_CODEC_ID_VP8:
|
||||
return "vp8_cuvid";
|
||||
case AV_CODEC_ID_VP9:
|
||||
return "vp9_cuvid";
|
||||
default:
|
||||
return "";
|
||||
switch (hw_type) {
|
||||
case AV_HWDEVICE_TYPE_CUDA:
|
||||
switch (ff_codec_id) {
|
||||
case AV_CODEC_ID_H264:
|
||||
return "h264_cuvid";
|
||||
case AV_CODEC_ID_HEVC:
|
||||
return "hevc_cuvid";
|
||||
case AV_CODEC_ID_VP8:
|
||||
return "vp8_cuvid";
|
||||
case AV_CODEC_ID_VP9:
|
||||
return "vp9_cuvid";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
case AV_HWDEVICE_TYPE_MEDIACODEC:
|
||||
switch (ff_codec_id) {
|
||||
case AV_CODEC_ID_H264:
|
||||
return "h264_ni_dec";
|
||||
case AV_CODEC_ID_HEVC:
|
||||
return "h265_ni_dec";
|
||||
case AV_CODEC_ID_VP8:
|
||||
return "";
|
||||
case AV_CODEC_ID_VP9:
|
||||
return "";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +237,7 @@ int open_video_decoder(input_params *params, struct input_ctx *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
AVCodec *codec = NULL;
|
||||
AVDictionary **opts = NULL;
|
||||
AVFormatContext *ic = ctx->ic;
|
||||
// open video decoder
|
||||
ctx->vi = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
|
||||
@@ -238,8 +245,8 @@ int open_video_decoder(input_params *params, struct input_ctx *ctx)
|
||||
else if (ctx->vi < 0) {
|
||||
LPMS_WARN("No video stream found in input");
|
||||
} else {
|
||||
if (AV_HWDEVICE_TYPE_CUDA == params->hw_type) {
|
||||
char* decoder_name = get_hw_decoder(codec->id);
|
||||
if (params->hw_type > AV_HWDEVICE_TYPE_NONE) {
|
||||
char* decoder_name = get_hw_decoder(codec->id, params->hw_type);
|
||||
if (!*decoder_name) {
|
||||
ret = lpms_ERR_INPUT_CODEC;
|
||||
LPMS_ERR(open_decoder_err, "Input codec does not support hardware acceleration");
|
||||
@@ -253,6 +260,11 @@ int open_video_decoder(input_params *params, struct input_ctx *ctx)
|
||||
ret = lpms_ERR_INPUT_PIXFMT;
|
||||
LPMS_ERR(open_decoder_err, "Non 4:2:0 pixel format detected in input");
|
||||
}
|
||||
} else if (params->video.name && strlen(params->video.name) != 0) {
|
||||
// Try to find user specified decoder by name
|
||||
AVCodec *c = avcodec_find_decoder_by_name(params->video.name);
|
||||
if (c) codec = c;
|
||||
if (params->video.opts) opts = ¶ms->video.opts;
|
||||
}
|
||||
AVCodecContext *vc = avcodec_alloc_context3(codec);
|
||||
if (!vc) LPMS_ERR(open_decoder_err, "Unable to alloc video codec");
|
||||
@@ -261,16 +273,17 @@ int open_video_decoder(input_params *params, struct input_ctx *ctx)
|
||||
if (ret < 0) LPMS_ERR(open_decoder_err, "Unable to assign video params");
|
||||
vc->opaque = (void*)ctx;
|
||||
// XXX Could this break if the original device falls out of scope in golang?
|
||||
if (params->hw_type != AV_HWDEVICE_TYPE_NONE) {
|
||||
if (params->hw_type == AV_HWDEVICE_TYPE_CUDA) {
|
||||
// First set the hw device then set the hw frame
|
||||
ret = av_hwdevice_ctx_create(&ctx->hw_device_ctx, params->hw_type, params->device, NULL, 0);
|
||||
if (ret < 0) LPMS_ERR(open_decoder_err, "Unable to open hardware context for decoding")
|
||||
ctx->hw_type = params->hw_type;
|
||||
vc->hw_device_ctx = av_buffer_ref(ctx->hw_device_ctx);
|
||||
vc->get_format = get_hw_pixfmt;
|
||||
}
|
||||
ctx->hw_type = params->hw_type;
|
||||
vc->pkt_timebase = ic->streams[ctx->vi]->time_base;
|
||||
ret = avcodec_open2(vc, codec, NULL);
|
||||
av_opt_set(vc->priv_data, "xcoder-params", ctx->xcoderParams, 0);
|
||||
ret = avcodec_open2(vc, codec, opts);
|
||||
if (ret < 0) LPMS_ERR(open_decoder_err, "Unable to open video decoder");
|
||||
}
|
||||
|
||||
|
||||
Regular → Executable
+3
-1
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include "transcoder.h"
|
||||
|
||||
struct input_ctx {
|
||||
@@ -16,6 +17,7 @@ struct input_ctx {
|
||||
AVBufferRef *hw_device_ctx;
|
||||
enum AVHWDeviceType hw_type;
|
||||
char *device;
|
||||
char *xcoderParams;
|
||||
|
||||
// Decoder flush
|
||||
AVPacket *first_pkt;
|
||||
@@ -58,7 +60,7 @@ enum AVPixelFormat hw2pixfmt(AVCodecContext *ctx);
|
||||
int open_input(input_params *params, struct input_ctx *ctx);
|
||||
int open_video_decoder(input_params *params, struct input_ctx *ctx);
|
||||
int open_audio_decoder(input_params *params, struct input_ctx *ctx);
|
||||
char* get_hw_decoder(int ff_codec_id);
|
||||
char* get_hw_decoder(int ff_codec_id, int hw_type);
|
||||
void free_input(struct input_ctx *inctx);
|
||||
|
||||
// Utility functions
|
||||
|
||||
Regular → Executable
+10
-4
@@ -155,7 +155,7 @@ void close_output(struct output_ctx *octx)
|
||||
avformat_free_context(octx->oc);
|
||||
octx->oc = NULL;
|
||||
}
|
||||
if (octx->vc && AV_HWDEVICE_TYPE_NONE == octx->hw_type) avcodec_free_context(&octx->vc);
|
||||
if (octx->vc && octx->hw_type == AV_HWDEVICE_TYPE_NONE) avcodec_free_context(&octx->vc);
|
||||
if (octx->ac) avcodec_free_context(&octx->ac);
|
||||
octx->af.flushed = octx->vf.flushed = 0;
|
||||
octx->af.flushing = octx->vf.flushing = 0;
|
||||
@@ -252,6 +252,9 @@ int open_output(struct output_ctx *octx, struct input_ctx *ictx)
|
||||
}
|
||||
vc->pix_fmt = av_buffersink_get_format(octx->vf.sink_ctx); // XXX select based on encoder + input support
|
||||
if (fmt->flags & AVFMT_GLOBALHEADER) vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
if(strcmp(octx->xcoderParams,"")!=0){
|
||||
av_opt_set(vc->priv_data, "xcoder-params", octx->xcoderParams, 0);
|
||||
}
|
||||
ret = avcodec_open2(vc, codec, &octx->video->opts);
|
||||
if (ret < 0) LPMS_ERR(open_output_err, "Error opening video encoder");
|
||||
octx->hw_type = ictx->hw_type;
|
||||
@@ -345,7 +348,8 @@ static int encode(AVCodecContext* encoder, AVFrame *frame, struct output_ctx* oc
|
||||
|
||||
// We don't want to send NULL frames for HW encoding
|
||||
// because that closes the encoder: not something we want
|
||||
if (AV_HWDEVICE_TYPE_NONE == octx->hw_type || AVMEDIA_TYPE_AUDIO == ost->codecpar->codec_type || frame) {
|
||||
if (AV_HWDEVICE_TYPE_NONE == octx->hw_type || AV_HWDEVICE_TYPE_MEDIACODEC == octx->hw_type ||
|
||||
AVMEDIA_TYPE_AUDIO == ost->codecpar->codec_type || frame) {
|
||||
ret = avcodec_send_frame(encoder, frame);
|
||||
if (AVERROR_EOF == ret) ; // continue ; drain encoder
|
||||
else if (ret < 0) LPMS_ERR(encode_cleanup, "Error sending frame to encoder");
|
||||
@@ -527,6 +531,7 @@ int process_out(struct input_ctx *ictx, struct output_ctx *octx, AVCodecContext
|
||||
frame->pict_type = AV_PICTURE_TYPE_I;
|
||||
octx->next_kf_pts = frame->pts + octx->gop_pts_len;
|
||||
}
|
||||
|
||||
if(octx->is_dnn_profile) {
|
||||
ret = getmetadatainf(frame, octx);
|
||||
if(ret == -1 && frame == NULL) {
|
||||
@@ -544,8 +549,9 @@ skip:
|
||||
av_frame_unref(frame);
|
||||
// For HW we keep the encoder open so will only get EAGAIN.
|
||||
// Return EOF in place of EAGAIN for to terminate the flush
|
||||
if (frame == NULL && AV_HWDEVICE_TYPE_NONE != octx->hw_type &&
|
||||
AVERROR(EAGAIN) == ret && !inf) return AVERROR_EOF;
|
||||
if (frame == NULL && octx->hw_type > AV_HWDEVICE_TYPE_NONE &&
|
||||
AV_HWDEVICE_TYPE_MEDIACODEC != octx->hw_type &&
|
||||
AVERROR(EAGAIN) == ret && !inf) return AVERROR_EOF;
|
||||
if (frame == NULL) return ret;
|
||||
}
|
||||
|
||||
|
||||
+17
-17
@@ -11,7 +11,7 @@ struct match_info {
|
||||
int height;
|
||||
uint64_t bit_rate;
|
||||
int packetcount; //video total packet count
|
||||
uint64_t timestamp; //XOR sum of avpacket pts
|
||||
uint64_t timestamp; //XOR sum of avpacket pts
|
||||
int audiosum[4]; //XOR sum of audio data's md5(16 bytes)
|
||||
};
|
||||
|
||||
@@ -183,10 +183,10 @@ close_format_context:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// compare two signature files whether those matches or not.
|
||||
// @param signpath1 full path of the first signature file.
|
||||
// @param signpath2 full path of the second signature file.
|
||||
// @return <0: error 0: no matchiing 1: partial matching 2: whole matching.
|
||||
//// compare two signature files whether those matches or not.
|
||||
//// @param signpath1 full path of the first signature file.
|
||||
//// @param signpath2 full path of the second signature file.
|
||||
//// @return <0: error 0: no matchiing 1: partial matching 2: whole matching.
|
||||
|
||||
int lpms_compare_sign_bypath(char *signpath1, char *signpath2)
|
||||
{
|
||||
@@ -268,7 +268,7 @@ static int read_packet(void *opaque, uint8_t *buf, int buf_size)
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
static int get_matchinfo(void *buffer, int len, struct match_info* info)
|
||||
static int get_matchinfo(void *buffer, int len, struct match_info* info)
|
||||
{
|
||||
int ret = 0;
|
||||
AVFormatContext* ifmt_ctx = NULL;
|
||||
@@ -292,7 +292,7 @@ static int get_matchinfo(void *buffer, int len, struct match_info* info)
|
||||
LPMS_ERR(clean, "Error allocating buffer");
|
||||
}
|
||||
|
||||
avio_in = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, 0, &bd, &read_packet, NULL, NULL);
|
||||
avio_in = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, 0, &bd, &read_packet, NULL, NULL);
|
||||
if (!avio_ctx_buffer) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
LPMS_ERR(clean, "Error allocating context");
|
||||
@@ -304,15 +304,15 @@ static int get_matchinfo(void *buffer, int len, struct match_info* info)
|
||||
}
|
||||
ifmt_ctx->pb = avio_in;
|
||||
ifmt_ctx->flags = AVFMT_FLAG_CUSTOM_IO;
|
||||
|
||||
|
||||
if ((ret = avformat_open_input(&ifmt_ctx, "", NULL, NULL)) < 0) {
|
||||
LPMS_ERR(clean, "Cannot open input video file\n");
|
||||
}
|
||||
|
||||
|
||||
if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
|
||||
LPMS_ERR(clean, "Cannot find stream information\n");
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
|
||||
AVStream *stream;
|
||||
stream = ifmt_ctx->streams[i];
|
||||
@@ -323,10 +323,10 @@ static int get_matchinfo(void *buffer, int len, struct match_info* info)
|
||||
info->bit_rate = in_codecpar->bit_rate;
|
||||
}
|
||||
else if (in_codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
audioid = i;
|
||||
audioid = i;
|
||||
}
|
||||
}
|
||||
packet = av_packet_alloc();
|
||||
packet = av_packet_alloc();
|
||||
if (!packet) LPMS_ERR(clean, "Error allocating packet");
|
||||
while (1) {
|
||||
ret = av_read_frame(ifmt_ctx, packet);
|
||||
@@ -334,7 +334,7 @@ static int get_matchinfo(void *buffer, int len, struct match_info* info)
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
else if (ret < 0) {
|
||||
else if (ret < 0) {
|
||||
LPMS_ERR(clean, "Unable to read input");
|
||||
}
|
||||
info->packetcount++;
|
||||
@@ -345,8 +345,8 @@ static int get_matchinfo(void *buffer, int len, struct match_info* info)
|
||||
}
|
||||
av_packet_unref(packet);
|
||||
}
|
||||
|
||||
clean:
|
||||
|
||||
clean:
|
||||
if(packet)
|
||||
av_packet_free(&packet);
|
||||
/* note: the internal buffer could have changed, and be != avio_ctx_buffer */
|
||||
@@ -365,7 +365,7 @@ clean:
|
||||
// @return <0: error =0: matching 1: no matching
|
||||
int lpms_compare_video_bybuffer(void *buffer1, int len1, void *buffer2, int len2)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = 0;
|
||||
struct match_info info1, info2;
|
||||
|
||||
ret = get_matchinfo(buffer1,len1,&info1);
|
||||
@@ -374,7 +374,7 @@ int lpms_compare_video_bybuffer(void *buffer1, int len1, void *buffer2, int len2
|
||||
ret = get_matchinfo(buffer2,len2,&info2);
|
||||
if(ret < 0) return ret;
|
||||
//compare two matching information
|
||||
if (info1.width != info2.width || info1.height != info2.height ||
|
||||
if (info1.width != info2.width || info1.height != info2.height ||
|
||||
info1.bit_rate != info2.bit_rate || info1.packetcount != info2.packetcount ||
|
||||
info1.timestamp != info2.timestamp || memcmp(info1.audiosum, info2.audiosum, 16)) {
|
||||
ret = 1;
|
||||
|
||||
Regular → Executable
+39
-6
@@ -48,8 +48,16 @@ const (
|
||||
Software Acceleration = iota
|
||||
Nvidia
|
||||
Amd
|
||||
Netint
|
||||
)
|
||||
|
||||
var AccelerationNameLookup = map[Acceleration]string{
|
||||
Software: "SW",
|
||||
Nvidia: "Nvidia",
|
||||
Amd: "Amd",
|
||||
Netint: "Netint",
|
||||
}
|
||||
|
||||
var FfEncoderLookup = map[Acceleration]map[VideoCodec]string{
|
||||
Software: {
|
||||
H264: "libx264",
|
||||
@@ -61,6 +69,10 @@ var FfEncoderLookup = map[Acceleration]map[VideoCodec]string{
|
||||
H264: "h264_nvenc",
|
||||
H265: "hevc_nvenc",
|
||||
},
|
||||
Netint: {
|
||||
H264: "h264_ni_enc",
|
||||
H265: "h265_ni_enc",
|
||||
},
|
||||
}
|
||||
|
||||
type ComponentOptions struct {
|
||||
@@ -440,6 +452,14 @@ func configEncoder(inOpts *TranscodeOptionsIn, outOpts TranscodeOptions, inDev,
|
||||
}
|
||||
return encoder, "scale_cuda", nil
|
||||
}
|
||||
case Netint:
|
||||
switch outOpts.Accel {
|
||||
case Software, Nvidia:
|
||||
return "", "", ErrTranscoderDev // XXX don't allow mix-match between NETINT and sw/nv
|
||||
case Netint:
|
||||
// Use software scale filter
|
||||
return encoder, "scale", nil
|
||||
}
|
||||
}
|
||||
return "", "", ErrTranscoderHw
|
||||
}
|
||||
@@ -449,7 +469,8 @@ func accelDeviceType(accel Acceleration) (C.enum_AVHWDeviceType, error) {
|
||||
return C.AV_HWDEVICE_TYPE_NONE, nil
|
||||
case Nvidia:
|
||||
return C.AV_HWDEVICE_TYPE_CUDA, nil
|
||||
|
||||
case Netint:
|
||||
return C.AV_HWDEVICE_TYPE_MEDIACODEC, nil
|
||||
}
|
||||
return C.AV_HWDEVICE_TYPE_NONE, ErrTranscoderHw
|
||||
}
|
||||
@@ -491,6 +512,8 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
|
||||
}
|
||||
}
|
||||
fname := C.CString(input.Fname)
|
||||
xcoderParams := C.CString("")
|
||||
defer C.free(unsafe.Pointer(xcoderParams))
|
||||
defer C.free(unsafe.Pointer(fname))
|
||||
if input.Transmuxing {
|
||||
t.started = true
|
||||
@@ -542,7 +565,7 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
|
||||
// preserve aspect ratio along the larger dimension when rescaling
|
||||
var filters string
|
||||
filters = fmt.Sprintf("%s='w=if(gte(iw,ih),%d,-2):h=if(lt(iw,ih),%d,-2)'", scale_filter, w, h)
|
||||
if input.Accel != Software && p.Accel == Software {
|
||||
if input.Accel == Nvidia && p.Accel == Software {
|
||||
// needed for hw dec -> hw rescale -> sw enc
|
||||
filters = filters + ",hwdownload,format=nv12"
|
||||
}
|
||||
@@ -600,6 +623,10 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
|
||||
defer C.free(unsafe.Pointer(muxOpts.name))
|
||||
}
|
||||
// Set video encoder options
|
||||
// TODO understand how h264 profiles and GOP setting works for
|
||||
// NETINT encoder, and make sure we change relevant things here
|
||||
// Any other options for the encoder can also be added here
|
||||
xcoderOutParamsStr := ""
|
||||
if len(p.VideoEncoder.Name) <= 0 && len(p.VideoEncoder.Opts) <= 0 {
|
||||
p.VideoEncoder.Opts = map[string]string{
|
||||
"forced-idr": "1",
|
||||
@@ -609,8 +636,12 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
|
||||
p.VideoEncoder.Opts["profile"] = ProfileParameters[p.Profile.Profile]
|
||||
p.VideoEncoder.Opts["bf"] = "0"
|
||||
case ProfileH264Main, ProfileH264High:
|
||||
p.VideoEncoder.Opts["profile"] = ProfileParameters[p.Profile.Profile]
|
||||
p.VideoEncoder.Opts["bf"] = "3"
|
||||
if p.Accel != Netint {
|
||||
p.VideoEncoder.Opts["profile"] = ProfileParameters[p.Profile.Profile]
|
||||
p.VideoEncoder.Opts["bf"] = "3"
|
||||
} else {
|
||||
xcoderOutParamsStr = "profile=high"
|
||||
}
|
||||
case ProfileNone:
|
||||
if p.Accel == Nvidia {
|
||||
p.VideoEncoder.Opts["bf"] = "0"
|
||||
@@ -630,6 +661,8 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
xcoderOutParams := C.CString(xcoderOutParamsStr)
|
||||
defer C.free(unsafe.Pointer(xcoderOutParams))
|
||||
gopMs := 0
|
||||
if param.GOP != 0 {
|
||||
if param.GOP <= GOPInvalid {
|
||||
@@ -674,7 +707,7 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
|
||||
w: C.int(w), h: C.int(h), bitrate: C.int(bitrate),
|
||||
gop_time: C.int(gopMs), from: C.int(fromMs), to: C.int(toMs),
|
||||
muxer: muxOpts, audio: audioOpts, video: vidOpts,
|
||||
vfilters: vfilt, sfilters: nil, is_dnn: isDNN}
|
||||
vfilters: vfilt, sfilters: nil, is_dnn: isDNN, xcoderParams: xcoderOutParams}
|
||||
if p.CalcSign {
|
||||
//signfilter string
|
||||
escapedOname := ffmpegStrEscape(p.Oname)
|
||||
@@ -707,7 +740,7 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
|
||||
device = C.CString(input.Device)
|
||||
defer C.free(unsafe.Pointer(device))
|
||||
}
|
||||
inp := &C.input_params{fname: fname, hw_type: hw_type, device: device,
|
||||
inp := &C.input_params{fname: fname, hw_type: hw_type, device: device, xcoderParams: xcoderParams,
|
||||
handle: t.handle}
|
||||
if input.Transmuxing {
|
||||
inp.transmuxe = 1
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ struct output_ctx {
|
||||
int is_dnn_profile; //if not dnn profile: 0
|
||||
|
||||
output_results *res; // data to return for this output
|
||||
|
||||
char *xcoderParams;
|
||||
};
|
||||
|
||||
int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx);
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNvidia_Transcoding(t *testing.T) {
|
||||
func
|
||||
TestNvidia_Transcoding(t *testing.T) {
|
||||
codecsComboTest(t, supportedCodecsCombinations([]Acceleration{Nvidia}))
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -2,14 +2,13 @@ package ffmpeg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_SignDataCreate(t *testing.T) {
|
||||
|
||||
Regular → Executable
+5
-3
@@ -120,6 +120,7 @@ int transcode(struct transcode_thread *h,
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
struct input_ctx *ictx = &h->ictx;
|
||||
ictx->xcoderParams = inp->xcoderParams;
|
||||
int reopen_decoders = !ictx->transmuxing;
|
||||
struct output_ctx *outputs = h->outputs;
|
||||
int nb_outputs = h->nb_outputs;
|
||||
@@ -161,7 +162,7 @@ int transcode(struct transcode_thread *h,
|
||||
|
||||
if (reopen_decoders) {
|
||||
// XXX check to see if we can also reuse decoder for sw decoding
|
||||
if (AV_HWDEVICE_TYPE_CUDA != ictx->hw_type) {
|
||||
if (ictx->hw_type == AV_HWDEVICE_TYPE_NONE) {
|
||||
ret = open_video_decoder(inp, ictx);
|
||||
if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to reopen video decoder");
|
||||
}
|
||||
@@ -180,6 +181,7 @@ int transcode(struct transcode_thread *h,
|
||||
octx->video = ¶ms[i].video;
|
||||
octx->vfilters = params[i].vfilters;
|
||||
octx->sfilters = params[i].sfilters;
|
||||
octx->xcoderParams = params[i].xcoderParams;
|
||||
if (params[i].is_dnn && h->dnn_filtergraph != NULL) {
|
||||
octx->is_dnn_profile = params[i].is_dnn;
|
||||
octx->dnn_filtergraph = &h->dnn_filtergraph;
|
||||
@@ -390,7 +392,7 @@ whileloop_end:
|
||||
}
|
||||
else if(outputs[i].is_dnn_profile && outputs[i].res->frames > 0) {
|
||||
for (int j = 0; j < MAX_CLASSIFY_SIZE; j++) {
|
||||
outputs[i].res->probs[j] = outputs[i].res->probs[j] / outputs[i].res->frames;
|
||||
outputs[i].res->probs[j] = outputs[i].res->probs[j] / outputs[i].res->frames;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -416,7 +418,7 @@ transcode_cleanup:
|
||||
if (ipkt) av_packet_free(&ipkt); // needed for early exits
|
||||
if (ictx->first_pkt) av_packet_free(&ictx->first_pkt);
|
||||
if (ictx->ac) avcodec_free_context(&ictx->ac);
|
||||
if (ictx->vc && AV_HWDEVICE_TYPE_NONE == ictx->hw_type) avcodec_free_context(&ictx->vc);
|
||||
if (ictx->vc && (AV_HWDEVICE_TYPE_NONE == ictx->hw_type)) avcodec_free_context(&ictx->vc);
|
||||
for (i = 0; i < nb_outputs; i++) {
|
||||
//send EOF signal to signature filter
|
||||
if(outputs[i].sfilters != NULL && outputs[i].sf.src_ctx != NULL) {
|
||||
|
||||
Regular → Executable
+5
-2
@@ -32,11 +32,10 @@ typedef struct {
|
||||
int w, h, bitrate, gop_time, from, to;
|
||||
AVRational fps;
|
||||
int is_dnn;
|
||||
|
||||
char *xcoderParams;
|
||||
component_opts muxer;
|
||||
component_opts audio;
|
||||
component_opts video;
|
||||
|
||||
} output_params;
|
||||
|
||||
typedef struct {
|
||||
@@ -51,6 +50,10 @@ typedef struct {
|
||||
// Optional hardware acceleration
|
||||
enum AVHWDeviceType hw_type;
|
||||
char *device;
|
||||
char *xcoderParams;
|
||||
|
||||
// Optional video decoder + opts
|
||||
component_opts video;
|
||||
|
||||
int transmuxe;
|
||||
} input_params;
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
@@ -437,15 +438,19 @@ func (s *ServerDisconnectStream) ReadRTMPFromStream(ctx context.Context, dst av.
|
||||
|
||||
func TestServerDisconnect(t *testing.T) {
|
||||
ffmpeg.InitFFmpeg()
|
||||
port := "1938" // because we can't yet close the listener on 1935?
|
||||
port := 1938 // because we can't yet close the listener on 1935?
|
||||
strm := &ServerDisconnectStream{}
|
||||
strmUrl := fmt.Sprintf("rtmp://localhost:%v/stream/%v", port, strm.GetStreamID())
|
||||
opt := SegmenterOptions{SegLength: time.Second * 4}
|
||||
vs := NewFFMpegVideoSegmenter("tmp", strm.GetStreamID(), strmUrl, opt)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
cmd := "dd if=/dev/urandom count=1 ibs=2000 | nc -l " + port
|
||||
nopt := "N"
|
||||
if runtime.GOOS == `darwin` {
|
||||
// N is invalid on MacOS
|
||||
nopt = ""
|
||||
}
|
||||
cmd := fmt.Sprintf("dd if=/dev/urandom count=1 ibs=2000 | nc -%sl %d", nopt, port)
|
||||
go exec.CommandContext(ctx, "bash", "-c", cmd).Output()
|
||||
|
||||
err := RunRTMPToHLS(vs, ctx)
|
||||
|
||||
Reference in New Issue
Block a user