Created
June 18, 2024 08:24
-
-
Save Ewoodss/0cae85164bb0c257b4f876f297a6e40b to your computer and use it in GitHub Desktop.
ffmpeg 6.0 patch nvmpi rtsp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/configure b/configure | |
index e06faa4..8087aee 100755 | |
--- a/configure | |
+++ b/configure | |
@@ -353,6 +353,7 @@ External library support: | |
--disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect] | |
--disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect] | |
--disable-videotoolbox disable VideoToolbox code [autodetect] | |
+ --enable-nvmpi enable nvmpi code | |
Toolchain options: | |
--arch=ARCH select architecture [$arch] | |
@@ -1913,6 +1914,7 @@ HWACCEL_LIBRARY_LIST=" | |
mmal | |
omx | |
opencl | |
+ nvmpi | |
" | |
DOCUMENT_LIST=" | |
@@ -3179,12 +3181,15 @@ h264_mediacodec_encoder_select="h264_metadata" | |
h264_mf_encoder_deps="mediafoundation" | |
h264_mmal_decoder_deps="mmal" | |
h264_nvenc_encoder_deps="nvenc" | |
+h264_nvmpi_encoder_deps="nvmpi" | |
h264_nvenc_encoder_select="atsc_a53" | |
h264_omx_encoder_deps="omx" | |
h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec" | |
h264_qsv_encoder_select="atsc_a53 qsvenc" | |
h264_rkmpp_decoder_deps="rkmpp" | |
h264_rkmpp_decoder_select="h264_mp4toannexb_bsf" | |
+h264_nvmpi_decoder_deps="nvmpi" | |
+h264_nvmpi_decoder_select="h264_mp4toannexb_bsf" | |
h264_vaapi_encoder_select="atsc_a53 cbs_h264 vaapi_encode" | |
h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" | |
h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf" | |
@@ -3201,10 +3206,13 @@ hevc_mediacodec_encoder_select="hevc_metadata" | |
hevc_mf_encoder_deps="mediafoundation" | |
hevc_nvenc_encoder_deps="nvenc" | |
hevc_nvenc_encoder_select="atsc_a53" | |
+hevc_nvmpi_encoder_deps="nvmpi" | |
hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec" | |
hevc_qsv_encoder_select="hevcparse qsvenc" | |
hevc_rkmpp_decoder_deps="rkmpp" | |
hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf" | |
+hevc_nvmpi_decoder_deps="nvmpi" | |
+hevc_nvmpi_decoder_select="hevc_mp4toannexb_bsf" | |
hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC" | |
hevc_vaapi_encoder_select="atsc_a53 cbs_h265 vaapi_encode" | |
hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m" | |
@@ -3221,6 +3229,7 @@ mpeg1_cuvid_decoder_deps="cuvid" | |
mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m" | |
mpeg2_crystalhd_decoder_select="crystalhd" | |
mpeg2_cuvid_decoder_deps="cuvid" | |
+mpeg2_nvmpi_decoder_deps="nvmpi" | |
mpeg2_mmal_decoder_deps="mmal" | |
mpeg2_mediacodec_decoder_deps="mediacodec" | |
mpeg2_qsv_decoder_select="qsvdec" | |
@@ -3229,6 +3238,7 @@ mpeg2_vaapi_encoder_select="cbs_mpeg2 vaapi_encode" | |
mpeg2_v4l2m2m_decoder_deps="v4l2_m2m mpeg2_v4l2_m2m" | |
mpeg4_crystalhd_decoder_select="crystalhd" | |
mpeg4_cuvid_decoder_deps="cuvid" | |
+mpeg4_nvmpi_decoder_deps="nvmpi" | |
mpeg4_mediacodec_decoder_deps="mediacodec" | |
mpeg4_mmal_decoder_deps="mmal" | |
mpeg4_omx_encoder_deps="omx" | |
@@ -3241,6 +3251,7 @@ vc1_mmal_decoder_deps="mmal" | |
vc1_qsv_decoder_select="qsvdec" | |
vc1_v4l2m2m_decoder_deps="v4l2_m2m vc1_v4l2_m2m" | |
vp8_cuvid_decoder_deps="cuvid" | |
+vp8_nvmpi_decoder_deps="nvmpi" | |
vp8_mediacodec_decoder_deps="mediacodec" | |
vp8_qsv_decoder_select="qsvdec" | |
vp8_rkmpp_decoder_deps="rkmpp" | |
@@ -3249,6 +3260,7 @@ vp8_vaapi_encoder_select="vaapi_encode" | |
vp8_v4l2m2m_decoder_deps="v4l2_m2m vp8_v4l2_m2m" | |
vp8_v4l2m2m_encoder_deps="v4l2_m2m vp8_v4l2_m2m" | |
vp9_cuvid_decoder_deps="cuvid" | |
+vp9_nvmpi_decoder_deps="nvmpi" | |
vp9_mediacodec_decoder_deps="mediacodec" | |
vp9_qsv_decoder_select="qsvdec" | |
vp9_rkmpp_decoder_deps="rkmpp" | |
@@ -6807,6 +6819,7 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r | |
die "ERROR: rkmpp requires --enable-libdrm"; } | |
} | |
enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init | |
+enabled nvmpi && require_pkg_config nvmpi nvmpi nvmpi.h nvmpi_create_decoder | |
if enabled gcrypt; then | |
diff --git a/libavcodec/Makefile b/libavcodec/Makefile | |
index 389253f..de624e0 100644 | |
--- a/libavcodec/Makefile | |
+++ b/libavcodec/Makefile | |
@@ -409,6 +409,8 @@ OBJS-$(CONFIG_H264_MEDIACODEC_ENCODER) += mediacodecenc.o | |
OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o | |
OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o | |
OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o | |
+OBJS-$(CONFIG_H264_NVMPI_DECODER) += nvmpi_dec.o | |
+OBJS-$(CONFIG_H264_NVMPI_ENCODER) += nvmpi_enc.o | |
OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o | |
OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o | |
OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o | |
@@ -442,6 +444,8 @@ OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o h265_profile_level | |
h2645data.o | |
OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER) += v4l2_m2m_dec.o | |
OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER) += v4l2_m2m_enc.o | |
+OBJS-$(CONFIG_HEVC_NVMPI_DECODER) += nvmpi_dec.o | |
+OBJS-$(CONFIG_HEVC_NVMPI_ENCODER) += nvmpi_enc.o | |
OBJS-$(CONFIG_HEVC_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o | |
OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o | |
OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadata.o hq_hqadsp.o \ | |
@@ -535,12 +539,14 @@ OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o | |
OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o | |
OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o | |
OBJS-$(CONFIG_MPEG2_CUVID_DECODER) += cuviddec.o | |
+OBJS-$(CONFIG_MPEG2_NVMPI_DECODER) += nvmpi_dec.o | |
OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o | |
OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER) += vaapi_encode_mpeg2.o | |
OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER) += v4l2_m2m_dec.o | |
OBJS-$(CONFIG_MPEG4_DECODER) += mpeg4videodsp.o xvididct.o | |
OBJS-$(CONFIG_MPEG4_ENCODER) += mpeg4videoenc.o | |
OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o | |
+OBJS-$(CONFIG_MPEG4_NVMPI_DECODER) += nvmpi_dec.o | |
OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o | |
OBJS-$(CONFIG_MPEG4_OMX_ENCODER) += omx.o | |
OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER) += v4l2_m2m_dec.o | |
@@ -763,6 +769,7 @@ OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o \ | |
OBJS-$(CONFIG_VP7_DECODER) += vp8.o vpx_rac.o | |
OBJS-$(CONFIG_VP8_DECODER) += vp8.o vpx_rac.o | |
OBJS-$(CONFIG_VP8_CUVID_DECODER) += cuviddec.o | |
+OBJS-$(CONFIG_VP8_NVMPI_DECODER) += nvmpi_dec.o | |
OBJS-$(CONFIG_VP8_MEDIACODEC_DECODER) += mediacodecdec.o | |
OBJS-$(CONFIG_VP8_QSV_DECODER) += qsvdec.o | |
OBJS-$(CONFIG_VP8_RKMPP_DECODER) += rkmppdec.o | |
@@ -773,6 +780,7 @@ OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r | |
vp9block.o vp9prob.o vp9mvs.o vpx_rac.o \ | |
vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o | |
OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuviddec.o | |
+OBJS-$(CONFIG_VP9_NVMPI_DECODER) += nvmpi_dec.o | |
OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER) += mediacodecdec.o | |
OBJS-$(CONFIG_VP9_RKMPP_DECODER) += rkmppdec.o | |
OBJS-$(CONFIG_VP9_VAAPI_ENCODER) += vaapi_encode_vp9.o | |
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c | |
index e593ad1..954ed1b 100644 | |
--- a/libavcodec/allcodecs.c | |
+++ b/libavcodec/allcodecs.c | |
@@ -158,11 +158,15 @@ extern const FFCodec ff_h264_mediacodec_encoder; | |
extern const FFCodec ff_h264_mmal_decoder; | |
extern const FFCodec ff_h264_qsv_decoder; | |
extern const FFCodec ff_h264_rkmpp_decoder; | |
+extern const FFCodec ff_h264_nvmpi_decoder; | |
+extern const FFCodec ff_h264_nvmpi_encoder; | |
extern const FFCodec ff_hap_encoder; | |
extern const FFCodec ff_hap_decoder; | |
extern const FFCodec ff_hevc_decoder; | |
extern const FFCodec ff_hevc_qsv_decoder; | |
extern const FFCodec ff_hevc_rkmpp_decoder; | |
+extern const FFCodec ff_hevc_nvmpi_decoder; | |
+extern const FFCodec ff_hevc_nvmpi_encoder; | |
extern const FFCodec ff_hevc_v4l2m2m_decoder; | |
extern const FFCodec ff_hnm4_video_decoder; | |
extern const FFCodec ff_hq_hqa_decoder; | |
@@ -867,20 +871,24 @@ extern const FFCodec ff_mjpeg_vaapi_encoder; | |
extern const FFCodec ff_mp3_mf_encoder; | |
extern const FFCodec ff_mpeg1_cuvid_decoder; | |
extern const FFCodec ff_mpeg2_cuvid_decoder; | |
+extern const FFCodec ff_mpeg2_nvmpi_decoder; | |
extern const FFCodec ff_mpeg2_qsv_encoder; | |
extern const FFCodec ff_mpeg2_vaapi_encoder; | |
extern const FFCodec ff_mpeg4_cuvid_decoder; | |
+extern const FFCodec ff_mpeg4_nvmpi_decoder; | |
extern const FFCodec ff_mpeg4_mediacodec_decoder; | |
extern const FFCodec ff_mpeg4_omx_encoder; | |
extern const FFCodec ff_mpeg4_v4l2m2m_encoder; | |
extern const FFCodec ff_prores_videotoolbox_encoder; | |
extern const FFCodec ff_vc1_cuvid_decoder; | |
extern const FFCodec ff_vp8_cuvid_decoder; | |
+extern const FFCodec ff_vp8_nvmpi_decoder; | |
extern const FFCodec ff_vp8_mediacodec_decoder; | |
extern const FFCodec ff_vp8_qsv_decoder; | |
extern const FFCodec ff_vp8_v4l2m2m_encoder; | |
extern const FFCodec ff_vp8_vaapi_encoder; | |
extern const FFCodec ff_vp9_cuvid_decoder; | |
+extern const FFCodec ff_vp9_nvmpi_decoder; | |
extern const FFCodec ff_vp9_mediacodec_decoder; | |
extern const FFCodec ff_vp9_qsv_decoder; | |
extern const FFCodec ff_vp9_vaapi_encoder; | |
diff --git a/libavcodec/nvmpi_dec.c b/libavcodec/nvmpi_dec.c | |
new file mode 100644 | |
index 0000000..cf6ec79 | |
--- /dev/null | |
+++ b/libavcodec/nvmpi_dec.c | |
@@ -0,0 +1,244 @@ | |
+#include <stdio.h> | |
+#include <stdlib.h> | |
+#include <sys/time.h> | |
+ | |
+#include <nvmpi.h> | |
+#include "avcodec.h" | |
+#include "decode.h" | |
+#include "internal.h" | |
+#include "libavutil/buffer.h" | |
+#include "libavutil/common.h" | |
+#include "libavutil/frame.h" | |
+#include "libavutil/hwcontext.h" | |
+#include "libavutil/hwcontext_drm.h" | |
+#include "libavutil/imgutils.h" | |
+#include "libavutil/log.h" | |
+#include "libavutil/opt.h" | |
+ | |
+#if LIBAVCODEC_VERSION_MAJOR >= 60 | |
+#include "codec_internal.h" | |
+#endif | |
+ | |
+ | |
+typedef struct { | |
+ char eos_reached; | |
+ nvmpictx* ctx; | |
+ AVClass *av_class; | |
+ AVFrame *bufFrame; | |
+ char *resize_expr; | |
+} nvmpiDecodeContext; | |
+ | |
+static nvCodingType nvmpi_get_codingtype(AVCodecContext *avctx) | |
+{ | |
+ switch (avctx->codec_id) { | |
+ case AV_CODEC_ID_H264: return NV_VIDEO_CodingH264; | |
+ case AV_CODEC_ID_HEVC: return NV_VIDEO_CodingHEVC; | |
+ case AV_CODEC_ID_VP8: return NV_VIDEO_CodingVP8; | |
+ case AV_CODEC_ID_VP9: return NV_VIDEO_CodingVP9; | |
+ case AV_CODEC_ID_MPEG4: return NV_VIDEO_CodingMPEG4; | |
+ case AV_CODEC_ID_MPEG2VIDEO: return NV_VIDEO_CodingMPEG2; | |
+ default: return NV_VIDEO_CodingUnused; | |
+ } | |
+}; | |
+ | |
+ | |
+static int nvmpi_init_decoder(AVCodecContext *avctx){ | |
+ | |
+ nvmpiDecodeContext *nvmpi_context = avctx->priv_data; | |
+ nvCodingType codectype=NV_VIDEO_CodingUnused; | |
+ nvSize resized = {0}; | |
+ | |
+ codectype =nvmpi_get_codingtype(avctx); | |
+ if (codectype == NV_VIDEO_CodingUnused) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unknown codec type (%d).\n", avctx->codec_id); | |
+ return AVERROR_UNKNOWN; | |
+ } | |
+ | |
+ //Workaround for default pix_fmt not being set, so check if it isnt set and set it, | |
+ //or if it is set, but isnt set to something we can work with. | |
+ | |
+ if(avctx->pix_fmt ==AV_PIX_FMT_NONE){ | |
+ avctx->pix_fmt=AV_PIX_FMT_YUV420P; | |
+ }else if((avctx->pix_fmt != AV_PIX_FMT_YUV420P) && (avctx->pix_fmt != AV_PIX_FMT_YUVJ420P)){ | |
+ av_log(avctx, AV_LOG_ERROR, "Invalid Pix_FMT for NVMPI: Only YUV420P and YUVJ420P are supported\n"); | |
+ return AVERROR_INVALIDDATA; | |
+ } | |
+ | |
+ if (nvmpi_context->resize_expr && sscanf(nvmpi_context->resize_expr, "%dx%d", | |
+ &resized.width, &resized.height) != 2) { | |
+ av_log(avctx, AV_LOG_ERROR, "Invalid resize expressions\n"); | |
+ return AVERROR(EINVAL); | |
+ } | |
+ | |
+ //overwrite avctx w and h if resize option is used | |
+ if(resized.width && resized.height) | |
+ { | |
+ avctx->width = resized.width; | |
+ avctx->height = resized.height; | |
+ } | |
+ | |
+ nvmpi_context->bufFrame = av_frame_alloc(); | |
+ nvmpi_context->bufFrame->width = avctx->width; | |
+ nvmpi_context->bufFrame->height = avctx->height; | |
+ if (ff_get_buffer(avctx, nvmpi_context->bufFrame, 0) < 0) { | |
+ av_frame_free(&(nvmpi_context->bufFrame)); | |
+ nvmpi_context->bufFrame = NULL; | |
+ return AVERROR(ENOMEM); | |
+ } | |
+ | |
+ nvmpi_context->ctx=nvmpi_create_decoder(codectype, NV_PIX_YUV420, resized); | |
+ | |
+ if(!nvmpi_context->ctx){ | |
+ av_frame_free(&(nvmpi_context->bufFrame)); | |
+ nvmpi_context->bufFrame = NULL; | |
+ av_log(avctx, AV_LOG_ERROR, "Failed to nvmpi_create_decoder (code = %d).\n", AVERROR_EXTERNAL); | |
+ return AVERROR_EXTERNAL; | |
+ } | |
+ | |
+ // AVCodecContext extradata contains complete NALU with pps, just have to feed it to the decoder | |
+ if(avctx->extradata_size){ | |
+ nvPacket packet; | |
+ int r; | |
+ | |
+ packet.payload_size=avctx->extradata_size; | |
+ packet.payload=avctx->extradata; | |
+ packet.pts=0; | |
+ | |
+ r = nvmpi_decoder_put_packet(nvmpi_context->ctx,&packet); | |
+ if (r < 0) { | |
+ av_log(avctx, AV_LOG_ERROR, "Failed to put pps packet (code = %d).\n", r); | |
+ return r; | |
+ } | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+ | |
+ | |
+static int nvmpi_close(AVCodecContext *avctx){ | |
+ | |
+ nvmpiDecodeContext *nvmpi_context = avctx->priv_data; | |
+ if(nvmpi_context->bufFrame) | |
+ { | |
+ av_frame_free(&(nvmpi_context->bufFrame)); | |
+ nvmpi_context->bufFrame = NULL; | |
+ } | |
+ return nvmpi_decoder_close(nvmpi_context->ctx); | |
+ | |
+} | |
+ | |
+#if LIBAVCODEC_VERSION_MAJOR >= 60 | |
+static int nvmpi_decode(AVCodecContext *avctx,AVFrame *data,int *got_frame, AVPacket *avpkt) | |
+#else | |
+static int nvmpi_decode(AVCodecContext *avctx,void *data,int *got_frame, AVPacket *avpkt) | |
+#endif | |
+{ | |
+ nvmpiDecodeContext *nvmpi_context = avctx->priv_data; | |
+ AVFrame *frame = data; | |
+ AVFrame *bufFrame = nvmpi_context->bufFrame; | |
+ nvFrame _nvframe={0}; | |
+ nvPacket packet; | |
+ int res; | |
+ | |
+ if(avpkt->size){ | |
+ packet.payload_size=avpkt->size; | |
+ packet.payload=avpkt->data; | |
+ packet.pts=avpkt->pts; | |
+ | |
+ res=nvmpi_decoder_put_packet(nvmpi_context->ctx,&packet); | |
+ } | |
+ | |
+ _nvframe.payload[0] = bufFrame->data[0]; | |
+ _nvframe.payload[1] = bufFrame->data[1]; | |
+ _nvframe.payload[2] = bufFrame->data[2]; | |
+ _nvframe.linesize[0] = bufFrame->linesize[0]; | |
+ _nvframe.linesize[1] = bufFrame->linesize[1]; | |
+ _nvframe.linesize[2] = bufFrame->linesize[2]; | |
+ | |
+ res=nvmpi_decoder_get_frame(nvmpi_context->ctx,&_nvframe,avctx->flags & AV_CODEC_FLAG_LOW_DELAY); | |
+ | |
+ if(res<0) | |
+ return avpkt->size; | |
+ | |
+ bufFrame->format=AV_PIX_FMT_YUV420P; | |
+ bufFrame->pts=_nvframe.timestamp; | |
+ bufFrame->pkt_dts = AV_NOPTS_VALUE; | |
+ av_frame_move_ref(frame, bufFrame); | |
+ | |
+ *got_frame = 1; | |
+ | |
+ bufFrame->width = avctx->width; | |
+ bufFrame->height = avctx->height; | |
+ if (ff_get_buffer(avctx, bufFrame, 0) < 0) { | |
+ return AVERROR(ENOMEM); | |
+ } | |
+ | |
+ frame->metadata = bufFrame->metadata; | |
+ bufFrame->metadata = NULL; | |
+ | |
+ return avpkt->size; | |
+} | |
+ | |
+ | |
+ | |
+#define OFFSET(x) offsetof(nvmpiDecodeContext, x) | |
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM | |
+static const AVOption options[] = { | |
+ { "resize", "Resize (width)x(height)", OFFSET(resize_expr), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, | |
+ { NULL } | |
+}; | |
+ | |
+#define NVMPI_DEC_CLASS(NAME) \ | |
+ static const AVClass nvmpi_##NAME##_dec_class = { \ | |
+ .class_name = "nvmpi_" #NAME "_dec", \ | |
+ .option = options, \ | |
+ .version = LIBAVUTIL_VERSION_INT, \ | |
+ }; | |
+ | |
+#if LIBAVCODEC_VERSION_MAJOR >= 60 | |
+ #define NVMPI_DEC(NAME, ID, BSFS) \ | |
+ NVMPI_DEC_CLASS(NAME) \ | |
+ FFCodec ff_##NAME##_nvmpi_decoder = { \ | |
+ .p.name = #NAME "_nvmpi", \ | |
+ CODEC_LONG_NAME(#NAME " (nvmpi)"), \ | |
+ .p.type = AVMEDIA_TYPE_VIDEO, \ | |
+ .p.id = ID, \ | |
+ .priv_data_size = sizeof(nvmpiDecodeContext), \ | |
+ .init = nvmpi_init_decoder, \ | |
+ .close = nvmpi_close, \ | |
+ FF_CODEC_DECODE_CB(nvmpi_decode), \ | |
+ .p.priv_class = &nvmpi_##NAME##_dec_class, \ | |
+ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ | |
+ .p.pix_fmts =(const enum AVPixelFormat[]){AV_PIX_FMT_YUV420P,AV_PIX_FMT_NV12,AV_PIX_FMT_NONE},\ | |
+ .bsfs = BSFS, \ | |
+ .p.wrapper_name = "nvmpi", \ | |
+ }; | |
+#else | |
+ #define NVMPI_DEC(NAME, ID, BSFS) \ | |
+ NVMPI_DEC_CLASS(NAME) \ | |
+ AVCodec ff_##NAME##_nvmpi_decoder = { \ | |
+ .name = #NAME "_nvmpi", \ | |
+ .long_name = NULL_IF_CONFIG_SMALL(#NAME " (nvmpi)"), \ | |
+ .type = AVMEDIA_TYPE_VIDEO, \ | |
+ .id = ID, \ | |
+ .priv_data_size = sizeof(nvmpiDecodeContext), \ | |
+ .init = nvmpi_init_decoder, \ | |
+ .close = nvmpi_close, \ | |
+ .decode = nvmpi_decode, \ | |
+ .priv_class = &nvmpi_##NAME##_dec_class, \ | |
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ | |
+ .pix_fmts =(const enum AVPixelFormat[]){AV_PIX_FMT_YUV420P,AV_PIX_FMT_NV12,AV_PIX_FMT_NONE},\ | |
+ .bsfs = BSFS, \ | |
+ .wrapper_name = "nvmpi", \ | |
+ }; | |
+#endif | |
+ | |
+ | |
+NVMPI_DEC(h264, AV_CODEC_ID_H264,"h264_mp4toannexb"); | |
+NVMPI_DEC(hevc, AV_CODEC_ID_HEVC,"hevc_mp4toannexb"); | |
+NVMPI_DEC(mpeg2, AV_CODEC_ID_MPEG2VIDEO,NULL); | |
+NVMPI_DEC(mpeg4, AV_CODEC_ID_MPEG4,NULL); | |
+NVMPI_DEC(vp9, AV_CODEC_ID_VP9,NULL); | |
+NVMPI_DEC(vp8, AV_CODEC_ID_VP8,NULL); | |
+ | |
diff --git a/libavcodec/nvmpi_enc.c b/libavcodec/nvmpi_enc.c | |
new file mode 100644 | |
index 0000000..957b7e0 | |
--- /dev/null | |
+++ b/libavcodec/nvmpi_enc.c | |
@@ -0,0 +1,557 @@ | |
+#include <nvmpi.h> | |
+#include "avcodec.h" | |
+#include "internal.h" | |
+#include <stdio.h> | |
+#include "libavutil/avstring.h" | |
+#include "libavutil/avutil.h" | |
+#include "libavutil/common.h" | |
+#include "libavutil/imgutils.h" | |
+#include "libavutil/log.h" | |
+#include "libavutil/opt.h" | |
+ | |
+#include "version.h" | |
+ | |
+#if (LIBAVCODEC_VERSION_MAJOR >= 58 && LIBAVCODEC_VERSION_MINOR>= 134) || (LIBAVCODEC_VERSION_MAJOR >= 59) | |
+#define NVMPI_FF_NEW_API | |
+#include "encode.h" | |
+#endif | |
+#if (LIBAVCODEC_VERSION_MAJOR >= 60) | |
+#include "codec_internal.h" | |
+#endif | |
+ | |
+ | |
+typedef struct { | |
+ const AVClass *class; | |
+ nvmpictx* ctx; | |
+ int num_capture_buffers; | |
+ int profile; | |
+ int level; | |
+ int rc; | |
+ int preset; | |
+ int encoder_flushing; | |
+ AVFrame *frame; //tmp frame | |
+}nvmpiEncodeContext; | |
+ | |
+nvPacket* nvmpienc_nvPacket_alloc(AVCodecContext *avctx, int bufSize); | |
+void nvmpienc_nvPacket_free(nvPacket* nPkt); | |
+int nvmpienc_nvPacket_reset(nvPacket* nPkt, AVCodecContext *avctx, int bufSize); | |
+int nvmpienc_initPktPool(AVCodecContext *avctx, int pktNum); | |
+int nvmpienc_deinitPktPool(AVCodecContext *avctx); | |
+ | |
+//alloc nvPacket and AVPacket buffer; | |
+nvPacket* nvmpienc_nvPacket_alloc(AVCodecContext *avctx, int bufSize) | |
+{ | |
+ AVPacket* pkt = av_packet_alloc(); | |
+ nvPacket* nPkt = (nvPacket*)malloc(sizeof(nvPacket)); | |
+ int res; | |
+ memset(nPkt, 0, sizeof(nvPacket)); | |
+#if LIBAVCODEC_VERSION_MAJOR >= 60 | |
+ if((res = ff_get_encode_buffer(avctx, pkt, bufSize, 0))) | |
+#else | |
+ if((res = ff_alloc_packet2(avctx,pkt,bufSize,bufSize))) | |
+#endif | |
+ { | |
+ av_packet_free(&pkt); | |
+ free(nPkt); | |
+ return NULL; | |
+ } | |
+ nPkt->privData = pkt; | |
+ nPkt->payload = pkt->data; | |
+ return nPkt; | |
+} | |
+ | |
+void nvmpienc_nvPacket_free(nvPacket* nPkt) | |
+{ | |
+ AVPacket* pkt = nPkt->privData; | |
+ av_packet_free(&pkt); | |
+ free(nPkt); | |
+} | |
+ | |
+int nvmpienc_nvPacket_reset(nvPacket* nPkt, AVCodecContext *avctx, int bufSize) | |
+{ | |
+ AVPacket* pkt = nPkt->privData; | |
+ int res; | |
+#if LIBAVCODEC_VERSION_MAJOR >= 60 | |
+ if((res = ff_get_encode_buffer(avctx, pkt, bufSize, 0))) | |
+#else | |
+ if((res = ff_alloc_packet2(avctx,pkt,bufSize,bufSize))) | |
+#endif | |
+ { | |
+ return -1; | |
+ } | |
+ nPkt->payload = pkt->data; | |
+ nPkt->payload_size = 0; | |
+ nPkt->flags = 0; | |
+ nPkt->pts = 0; | |
+ return 0; | |
+} | |
+ | |
+//must call after nvmpi_create_encoder() to preallocate buffers | |
+int nvmpienc_initPktPool(AVCodecContext *avctx, int pktNum) | |
+{ | |
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data; | |
+ //TODO free allocated mem on error | |
+ for(int i=0;i<pktNum;i++) | |
+ { | |
+ nvPacket* nPkt = nvmpienc_nvPacket_alloc(avctx, NVMPI_ENC_CHUNK_SIZE); | |
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt); | |
+ } | |
+ return 0; | |
+} | |
+ | |
+//must call before nvmpi_encoder_close() too free buffers memory | |
+int nvmpienc_deinitPktPool(AVCodecContext *avctx) | |
+{ | |
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data; | |
+ nvmpictx *ctx = nvmpi_context->ctx; | |
+ nvPacket* nPkt; | |
+ | |
+ while(nvmpi_encoder_dqEmptyPacket(ctx, &nPkt) == 0) | |
+ { | |
+ AVPacket* pkt = nPkt->privData; | |
+ av_packet_free(&pkt); | |
+ free(nPkt); | |
+ } | |
+ while(nvmpi_encoder_get_packet(ctx, &nPkt) == 0) | |
+ { | |
+ AVPacket* pkt = nPkt->privData; | |
+ av_packet_free(&pkt); | |
+ free(nPkt); | |
+ } | |
+ | |
+ //TODO check that all mem returned to nothing | |
+ return 0; | |
+} | |
+ | |
+static av_cold int nvmpi_encode_init(AVCodecContext *avctx) | |
+{ | |
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data; | |
+ | |
+ nvEncParam param={0}; | |
+ | |
+ param.width=avctx->width; | |
+ param.height=avctx->height; | |
+ param.bitrate=avctx->bit_rate; | |
+ param.vbv_buffer_size = avctx->rc_buffer_size; | |
+ //TODO use rc_initial_buffer_occupancy or ignore? | |
+ param.mode_vbr=0; | |
+ param.idr_interval=60; | |
+ param.iframe_interval=30; | |
+ param.peak_bitrate=avctx->rc_max_rate; | |
+ param.fps_n=avctx->framerate.num; | |
+ param.fps_d=avctx->framerate.den; | |
+ param.profile=nvmpi_context->profile& ~FF_PROFILE_H264_INTRA; | |
+ param.level=nvmpi_context->level; | |
+ param.capture_num=nvmpi_context->num_capture_buffers; | |
+ param.hw_preset_type=nvmpi_context->preset; | |
+ param.insert_spspps_idr=(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)?0:1; | |
+ | |
+ nvmpi_context->frame = av_frame_alloc(); | |
+ if (!nvmpi_context->frame) return AVERROR(ENOMEM); | |
+ | |
+ if(nvmpi_context->rc==1){ | |
+ param.mode_vbr=1; | |
+ } | |
+ | |
+ if(avctx->qmin >= 0 && avctx->qmax >= 0){ | |
+ param.qmin=avctx->qmin; | |
+ param.qmax=avctx->qmax; | |
+ } | |
+ | |
+ if (avctx->refs >= 0){ | |
+ param.refs=avctx->refs; | |
+ | |
+ } | |
+ | |
+ if(avctx->max_b_frames > 0 && avctx->max_b_frames < 3){ | |
+ param.max_b_frames=avctx->max_b_frames; | |
+ } | |
+ | |
+ if(avctx->gop_size>0){ | |
+ param.idr_interval=param.iframe_interval=avctx->gop_size; | |
+ | |
+ } | |
+ | |
+ //TODO should replace it | |
+ if ((avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) && (avctx->codec->id == AV_CODEC_ID_H264)){ | |
+ | |
+ uint8_t *dst[4]; | |
+ int linesize[4]; | |
+ nvFrame _nvframe={0}; | |
+ nvPacket *nPkt; | |
+ nvmpictx *_ctx; | |
+ int i; | |
+ int ret; | |
+ av_image_alloc(dst, linesize,avctx->width,avctx->height,avctx->pix_fmt,1); | |
+ | |
+ nvmpi_context->ctx = nvmpi_create_encoder(NV_VIDEO_CodingH264,¶m); | |
+ _ctx = nvmpi_context->ctx; | |
+ //TODO error handling. if(!_ctx) | |
+ nvmpienc_initPktPool(avctx,nvmpi_context->num_capture_buffers); | |
+ i=0; | |
+ | |
+ while(true) | |
+ { | |
+ _nvframe.payload[0]=dst[0]; | |
+ _nvframe.payload[1]=dst[1]; | |
+ _nvframe.payload[2]=dst[2]; | |
+ _nvframe.payload_size[0]=linesize[0]*avctx->height; | |
+ _nvframe.payload_size[1]=linesize[1]*avctx->height/2; | |
+ _nvframe.payload_size[2]=linesize[2]*avctx->height/2; | |
+ | |
+ nvmpi_encoder_put_frame(_ctx,&_nvframe); | |
+ | |
+ ret=nvmpi_encoder_get_packet(_ctx,&nPkt); | |
+ | |
+ if(ret<0) | |
+ continue; | |
+ | |
+ //find idr index 0x0000000165 | |
+ while((nPkt->payload[i]!=0||nPkt->payload[i+1]!=0||nPkt->payload[i+2]!=0||nPkt->payload[i+3]!=0x01||nPkt->payload[i+4]!=0x65)) | |
+ { | |
+ i++; | |
+ } | |
+ | |
+ avctx->extradata_size=i; | |
+ avctx->extradata = av_mallocz( avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE ); | |
+ memcpy( avctx->extradata, nPkt->payload,avctx->extradata_size); | |
+ memset( avctx->extradata + avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE ); | |
+ | |
+ nvmpienc_nvPacket_free(nPkt); | |
+ nPkt = nvmpienc_nvPacket_alloc(avctx, NVMPI_ENC_CHUNK_SIZE); | |
+ | |
+ //return buffer to pool | |
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt); | |
+ //send eos | |
+ nvmpi_encoder_put_frame(nvmpi_context->ctx,NULL); | |
+ | |
+ break; | |
+ } | |
+ | |
+ //drain encoder | |
+ while(true) | |
+ { | |
+ ret=nvmpi_encoder_get_packet(_ctx,&nPkt); | |
+ if(ret < 0) | |
+ { | |
+ if(ret == -2) break; //got eos | |
+ usleep(1000); | |
+ continue; | |
+ } | |
+ nvmpienc_nvPacket_free(nPkt); | |
+ nPkt = nvmpienc_nvPacket_alloc(avctx, NVMPI_ENC_CHUNK_SIZE); | |
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt); | |
+ } | |
+ | |
+ av_freep(&dst[0]); //free allocated image planes | |
+ nvmpienc_deinitPktPool(avctx); | |
+ nvmpi_encoder_close(nvmpi_context->ctx); | |
+ nvmpi_context->ctx = NULL; | |
+ } | |
+ | |
+ if(avctx->codec->id == AV_CODEC_ID_H264) | |
+ { | |
+ nvmpi_context->ctx=nvmpi_create_encoder(NV_VIDEO_CodingH264,¶m); | |
+ } | |
+ else if(avctx->codec->id == AV_CODEC_ID_HEVC) | |
+ { | |
+ nvmpi_context->ctx=nvmpi_create_encoder(NV_VIDEO_CodingHEVC,¶m); | |
+ } | |
+ //else TODO | |
+ | |
+ if(nvmpi_context->ctx) | |
+ { | |
+ nvmpienc_initPktPool(avctx,nvmpi_context->num_capture_buffers); | |
+ } | |
+ //TODO error handling. if(!nvmpi_context->ctx) | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int ff_nvmpi_send_frame(AVCodecContext *avctx,const AVFrame *frame) | |
+{ | |
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data; | |
+ nvFrame _nvframe={0}; | |
+ int res; | |
+ | |
+ if (nvmpi_context->encoder_flushing) | |
+ return AVERROR_EOF; | |
+ | |
+ if(frame) | |
+ { | |
+ _nvframe.payload[0]=frame->data[0]; | |
+ _nvframe.payload[1]=frame->data[1]; | |
+ _nvframe.payload[2]=frame->data[2]; | |
+ | |
+ _nvframe.payload_size[0]=frame->linesize[0]*frame->height; | |
+ _nvframe.payload_size[1]=frame->linesize[1]*frame->height/2; | |
+ _nvframe.payload_size[2]=frame->linesize[2]*frame->height/2; | |
+ | |
+ _nvframe.linesize[0]=frame->linesize[0]; | |
+ _nvframe.linesize[1]=frame->linesize[1]; | |
+ _nvframe.linesize[2]=frame->linesize[2]; | |
+ | |
+ _nvframe.timestamp=frame->pts; | |
+ | |
+ res=nvmpi_encoder_put_frame(nvmpi_context->ctx,&_nvframe); | |
+ | |
+ if(res<0) | |
+ return res; | |
+ } | |
+ else | |
+ { | |
+ nvmpi_context->encoder_flushing = 1; | |
+ nvmpi_encoder_put_frame(nvmpi_context->ctx,NULL); | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int ff_nvmpi_receive_packet(AVCodecContext *avctx, AVPacket *pkt) | |
+{ | |
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data; | |
+ nvPacket *nPkt; | |
+ AVPacket *aPkt; | |
+ int res; | |
+ | |
+ res = nvmpi_encoder_get_packet(nvmpi_context->ctx,&nPkt); | |
+ if(res<0) | |
+ { | |
+ //If the encoder is in flushing state, then get_packet will block and return either a packet or EOF | |
+ if(nvmpi_context->encoder_flushing) return AVERROR_EOF; | |
+ return AVERROR(EAGAIN); //nvmpi get_packet returns -1 if no packets are pending | |
+ } | |
+ | |
+ aPkt = (AVPacket*)(nPkt->privData); | |
+ aPkt->dts=aPkt->pts=nPkt->pts; | |
+ av_shrink_packet(aPkt, nPkt->payload_size); | |
+ if(nPkt->flags& AV_PKT_FLAG_KEY) aPkt->flags = AV_PKT_FLAG_KEY; | |
+ av_packet_move_ref(pkt, aPkt); | |
+ | |
+ if(nvmpienc_nvPacket_reset(nPkt, avctx, NVMPI_ENC_CHUNK_SIZE)) | |
+ { | |
+ nvmpienc_nvPacket_free(nPkt); | |
+ return AVERROR(ENOMEM); | |
+ } | |
+ | |
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt); | |
+ | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * //old avcodec .encode2 api. TODO: remove it | |
+static int ff_nvmpi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,const AVFrame *frame, int *got_packet) | |
+{ | |
+ int res; | |
+ *got_packet = 0; | |
+ | |
+ res = ff_nvmpi_send_frame(avctx, frame); | |
+ | |
+ if(res < 0) | |
+ { | |
+ if(res != AVERROR_EOF && res != AVERROR(EAGAIN)) return res; | |
+ } | |
+ | |
+ res = ff_nvmpi_receive_packet(avctx, pkt); | |
+ if(res<0) return res; | |
+ | |
+ *got_packet = 1; | |
+ | |
+ return 0; | |
+} | |
+*/ | |
+ | |
+#ifdef NVMPI_FF_NEW_API | |
+static int ff_nvmpi_receive_packet_async(AVCodecContext *avctx, AVPacket *pkt) | |
+{ | |
+ int res; | |
+ nvmpiEncodeContext * nvmpi_context = avctx->priv_data; | |
+ AVFrame *frame = nvmpi_context->frame; | |
+ bool needSendFrame = true; | |
+ | |
+ if (!frame->buf[0]) | |
+ { | |
+ res = ff_encode_get_frame(avctx, frame); | |
+ if (res < 0) | |
+ { | |
+ if(res == AVERROR(EAGAIN)) needSendFrame = false; | |
+ else if(res == AVERROR_EOF) frame = NULL; | |
+ else return res; | |
+ } | |
+ } | |
+ | |
+ if(needSendFrame) | |
+ { | |
+ res = ff_nvmpi_send_frame(avctx, frame); | |
+ if (res < 0) | |
+ { | |
+ if(res != AVERROR_EOF && res != AVERROR(EAGAIN)) return res; | |
+ } | |
+ else av_frame_unref(frame); | |
+ } | |
+ | |
+ res = ff_nvmpi_receive_packet(avctx, pkt); | |
+ if(res<0) return res; | |
+ | |
+ return 0; | |
+} | |
+#endif | |
+ | |
+static av_cold int nvmpi_encode_close(AVCodecContext *avctx) | |
+{ | |
+ nvmpiEncodeContext *nvmpi_context = avctx->priv_data; | |
+ | |
+ //drain encoder | |
+ { | |
+ int ret; | |
+ nvPacket *nPkt; | |
+ if(!nvmpi_context->encoder_flushing) | |
+ { | |
+ nvmpi_context->encoder_flushing = 1; | |
+ nvmpi_encoder_put_frame(nvmpi_context->ctx,NULL); | |
+ } | |
+ | |
+ while(1) | |
+ { | |
+ ret=nvmpi_encoder_get_packet(nvmpi_context->ctx,&nPkt); | |
+ if(ret < 0) | |
+ { | |
+ if(ret == -2) break; //got eos | |
+ usleep(1000); | |
+ continue; | |
+ } | |
+ nvmpienc_nvPacket_free(nPkt); | |
+ nPkt = nvmpienc_nvPacket_alloc(avctx, NVMPI_ENC_CHUNK_SIZE); | |
+ nvmpi_encoder_qEmptyPacket(nvmpi_context->ctx, nPkt); | |
+ } | |
+ } | |
+ | |
+ nvmpienc_deinitPktPool(avctx); | |
+ nvmpi_encoder_close(nvmpi_context->ctx); | |
+ av_frame_free(&nvmpi_context->frame); | |
+ | |
+ return 0; | |
+} | |
+ | |
+#if LIBAVCODEC_VERSION_MAJOR >= 60 | |
+static const FFCodecDefault defaults[] = { | |
+#else | |
+static const AVCodecDefault defaults[] = { | |
+#endif | |
+ { "b", "2M" }, | |
+ { "qmin", "-1" }, | |
+ { "qmax", "-1" }, | |
+ { "qdiff", "-1" }, | |
+ { "qblur", "-1" }, | |
+ { "qcomp", "-1" }, | |
+ { "g", "50" }, | |
+ { "bf", "0" }, | |
+ { "refs", "0" }, | |
+ { NULL }, | |
+}; | |
+ | |
+ | |
+#define OFFSET(x) offsetof(nvmpiEncodeContext, x) | |
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM | |
+ | |
+static const AVOption options[] = { | |
+ { "num_capture_buffers", "Number of buffers in the capture context", OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 10 }, 1, 32, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, | |
+ /// Profile, | |
+ | |
+ { "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, FF_PROFILE_H264_HIGH, VE, "profile" }, | |
+ { "baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_BASELINE }, 0, 0, VE, "profile" }, | |
+ { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_MAIN }, 0, 0, VE, "profile" }, | |
+ { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_HIGH }, 0, 0, VE, "profile" }, | |
+ | |
+ /// Profile Level | |
+ { "level", "Profile Level", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 62, VE, "level" }, | |
+ { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "level" }, | |
+ { "1.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 10 }, 0, 0, VE, "level" }, | |
+ { "1.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 11 }, 0, 0, VE, "level" }, | |
+ { "1.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 12 }, 0, 0, VE, "level" }, | |
+ { "1.3", "", 0, AV_OPT_TYPE_CONST, { .i64 = 13 }, 0, 0, VE, "level" }, | |
+ { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 20 }, 0, 0, VE, "level" }, | |
+ { "2.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 21 }, 0, 0, VE, "level" }, | |
+ { "2.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 22 }, 0, 0, VE, "level" }, | |
+ { "3.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 30 }, 0, 0, VE, "level" }, | |
+ { "3.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 31 }, 0, 0, VE, "level" }, | |
+ { "3.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 32 }, 0, 0, VE, "level" }, | |
+ { "4.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 40 }, 0, 0, VE, "level" }, | |
+ { "4.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 41 }, 0, 0, VE, "level" }, | |
+ { "4.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 42 }, 0, 0, VE, "level" }, | |
+ { "5.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 50 }, 0, 0, VE, "level" }, | |
+ { "5.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, 0, 0, VE, "level" }, | |
+ | |
+ { "rc", "Override the preset rate-control", OFFSET(rc), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, "rc" }, | |
+ { "cbr", "Constant bitrate mode", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "rc" }, | |
+ { "vbr", "Variable bitrate mode", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "rc" }, | |
+ | |
+ { "preset", "Set the encoding preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = 3 }, 1, 4, VE, "preset" }, | |
+ { "default", "", 0, AV_OPT_TYPE_CONST, { .i64 = 3 }, 0, 0, VE, "preset" }, | |
+ { "slow", "", 0, AV_OPT_TYPE_CONST, { .i64 = 4 }, 0, 0, VE, "preset" }, | |
+ { "medium", "", 0, AV_OPT_TYPE_CONST, { .i64 = 3 }, 0, 0, VE, "preset" }, | |
+ { "fast", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, VE, "preset" }, | |
+ { "ultrafast", "", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "preset" }, | |
+ { NULL } | |
+}; | |
+ | |
+ | |
+#define NVMPI_ENC_CLASS(NAME) \ | |
+ static const AVClass nvmpi_ ## NAME ## _enc_class = { \ | |
+ .class_name = #NAME "_nvmpi_encoder", \ | |
+ .item_name = av_default_item_name, \ | |
+ .option = options, \ | |
+ .version = LIBAVUTIL_VERSION_INT, \ | |
+ }; | |
+ | |
+ | |
+#if LIBAVCODEC_VERSION_MAJOR >= 60 | |
+ #define NVMPI_ENC(NAME, LONGNAME, CODEC) \ | |
+ NVMPI_ENC_CLASS(NAME) \ | |
+ FFCodec ff_ ## NAME ## _nvmpi_encoder = { \ | |
+ .p.name = #NAME "_nvmpi" , \ | |
+ CODEC_LONG_NAME("nvmpi " LONGNAME " encoder wrapper"), \ | |
+ .p.type = AVMEDIA_TYPE_VIDEO, \ | |
+ .p.id = CODEC , \ | |
+ .priv_data_size = sizeof(nvmpiEncodeContext), \ | |
+ .p.priv_class = &nvmpi_ ## NAME ##_enc_class, \ | |
+ .init = nvmpi_encode_init, \ | |
+ FF_CODEC_RECEIVE_PACKET_CB(ff_nvmpi_receive_packet_async), \ | |
+ .close = nvmpi_encode_close, \ | |
+ .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },\ | |
+ .p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ | |
+ .defaults = defaults,\ | |
+ .p.wrapper_name = "nvmpi", \ | |
+ }; | |
+#else | |
+ #ifdef NVMPI_FF_NEW_API | |
+ #define NVMPI_ENC_API_CALLS \ | |
+ .receive_packet = ff_nvmpi_receive_packet_async | |
+ #else | |
+ #define NVMPI_ENC_API_CALLS \ | |
+ .send_frame = ff_nvmpi_send_frame, \ | |
+ .receive_packet = ff_nvmpi_receive_packet | |
+ #endif | |
+ | |
+ #define NVMPI_ENC(NAME, LONGNAME, CODEC) \ | |
+ NVMPI_ENC_CLASS(NAME) \ | |
+ AVCodec ff_ ## NAME ## _nvmpi_encoder = { \ | |
+ .name = #NAME "_nvmpi" , \ | |
+ .long_name = NULL_IF_CONFIG_SMALL("nvmpi " LONGNAME " encoder wrapper"), \ | |
+ .type = AVMEDIA_TYPE_VIDEO, \ | |
+ .id = CODEC , \ | |
+ .priv_data_size = sizeof(nvmpiEncodeContext), \ | |
+ .priv_class = &nvmpi_ ## NAME ##_enc_class, \ | |
+ .init = nvmpi_encode_init, \ | |
+ NVMPI_ENC_API_CALLS, \ | |
+ .close = nvmpi_encode_close, \ | |
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },\ | |
+ .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ | |
+ .defaults = defaults,\ | |
+ .wrapper_name = "nvmpi", \ | |
+ }; | |
+#endif | |
+ | |
+NVMPI_ENC(h264, "H.264", AV_CODEC_ID_H264); | |
+NVMPI_ENC(hevc, "HEVC", AV_CODEC_ID_HEVC); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment