Skip to content

Commit

Permalink
Playback: NVDEC decoding
Browse files Browse the repository at this point in the history
NVDEC decoding for NVidia graphics adapters. This does not yet support
GPU to Video direct rendering. It works for video up to 4K but not
4K at 50fps. It also includes support for GPU based deinterlace.

Refs #13357
  • Loading branch information
bennettpeter authored and mark-kendall committed Jan 26, 2019
1 parent 62d9915 commit 8eb4637
Show file tree
Hide file tree
Showing 17 changed files with 730 additions and 203 deletions.
20 changes: 20 additions & 0 deletions mythtv/configure
Expand Up @@ -135,6 +135,7 @@ Advanced options (experts only):
--disable-crystalhd disable Broadcom CrystalHD hardware decoder support
--disable-vaapi disable VAAPI hardware accelerated video decoding
--disable-vaapi2 disable VAAPI2 hardware accelerated video decoding
--disable-nvdec disable NVDEC (CUVID) hardware accelerated video decoding
--disable-openmax disable OpenMAX hardware accelerated video decoding
--disable-dxva2 disable hardware accelerated decoding on windows
--disable-mediacodec disable hardware accelerated decoding on android
Expand Down Expand Up @@ -1397,6 +1398,7 @@ EXTERNAL_LIBRARY_LIST="
sdl2
vaapi
vaapi2
nvdec
"

HWACCEL_AUTODETECT_LIBRARY_LIST="
Expand Down Expand Up @@ -2041,6 +2043,7 @@ USING_LIST='
opengles
vaapi
vaapi2
nvdec
vdpau
openmax
mediacodec
Expand Down Expand Up @@ -2772,6 +2775,7 @@ enable lirc
enable mediacodec
enable vaapi
enable vaapi2
enable nvdec
enable mheg
enable mythtranscode
enable opengl
Expand Down Expand Up @@ -6986,6 +6990,19 @@ if enabled bindings_perl; then
check_pl_lib "XML::Simple" || disable_bindings_perl "XML::Simple"
fi

# nvdec processing
here="$PWD"
cd external/nv-codec-headers
if enabled nvdec ; then
make install PREFIX=$PWD/install
if [ "$?" != 0 ] ; then die "Build of nv-codec-headers failed." ; fi
PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PWD/install/lib/pkgconfig"
export PKG_CONFIG_PATH
else
rm -rf install ffnvcodec.pc
fi
cd "$here"

# Check for php dependencies
# are none at this time

Expand Down Expand Up @@ -7173,6 +7190,8 @@ ffmpeg_optenable cross_compile libmp3lame libx264 libx265 libvpx libxvid
ffmpeg_optenable vdpau libxml2 libass dxva2
ffmpeg_optenable libbluray libfontconfig libfreetype libiec61883
ffmpeg_optenable crystalhd sdl2 ffplay
ffmpeg_optenable nvdec

if test $target_os = "android"; then
enabled mediacodec && enable jni
ffmpeg_optenable mediacodec jni
Expand Down Expand Up @@ -7386,6 +7405,7 @@ if enabled x11 ; then
echo "VDPAU support ${vdpau-no}"
echo "VAAPI support ${vaapi-no}"
echo "VAAPI2 support ${vaapi2-no}"
echo "NVDEC support ${nvdec-no}"
echo "CrystalHD support ${crystalhd-no}"
echo "OpenMAX support ${openmax-no}"
if enabled openmax ; then
Expand Down
3 changes: 2 additions & 1 deletion mythtv/external/.gitignore
Expand Up @@ -16,4 +16,5 @@ ffplay_g
mythffplay
FFmpeg.old
mythffprobe
mythffserver
mythffserver
nv-codec-headers/install
7 changes: 5 additions & 2 deletions mythtv/external/Makefile
Expand Up @@ -13,8 +13,8 @@ endif
SUBDIRS_ALL = $(addsuffix -all, ${SUBDIRS})
SUBDIRS_INSTALL = $(addsuffix -install, ${SUBDIRS})
SUBDIRS_UNINSTALL = $(addsuffix -uninstall, ${SUBDIRS})
SUBDIRS_CLEAN = $(addsuffix -clean, ${SUBDIRS})
SUBDIRS_DISTCLEAN = $(addsuffix -distclean, ${SUBDIRS})
SUBDIRS_CLEAN = $(addsuffix -clean, ${SUBDIRS}, nv-codec-headers)
SUBDIRS_DISTCLEAN = $(addsuffix -distclean, ${SUBDIRS}, nv-codec-headers)

default: all
all: ${SUBDIRS_ALL}
Expand All @@ -41,3 +41,6 @@ libmythsoundtouch-all libmythsoundtouch-clean libmythsoundtouch-distclean libmyt

libXNVCtrl-all libXNVCtrl-install libXNVCtrl-uninstall libXNVCtrl-clean libXNVCtrl-distclean:
${MAKE} -C libXNVCtrl -f Makefile.lib ${@:libXNVCtrl-%=%}

nv-codec-headers-clean nv-codec-headers-distclean:
rm -rf nv-codec-headers/install nv-codec-headers/ffnvcodec.pc
83 changes: 73 additions & 10 deletions mythtv/libs/libmythtv/avformatdecoder.cpp
Expand Up @@ -73,6 +73,10 @@ extern "C" {
#include "vaapi2context.h"
#endif

#ifdef USING_NVDEC
#include "nvdeccontext.h"
#endif

extern "C" {
#include "libavutil/avutil.h"
#include "libavutil/error.h"
Expand Down Expand Up @@ -189,6 +193,9 @@ int get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic, int flags);
#ifdef USING_VAAPI2
int get_avf_buffer_vaapi2(struct AVCodecContext *c, AVFrame *pic, int flags);
#endif
#ifdef USING_NVDEC
int get_avf_buffer_nvdec(struct AVCodecContext *c, AVFrame *pic, int flags);
#endif

static int determinable_frame_size(struct AVCodecContext *avctx)
{
Expand Down Expand Up @@ -396,6 +403,10 @@ void AvFormatDecoder::GetDecoders(render_opts &opts)
opts.decoders->append("vaapi2");
(*opts.equiv_decoders)["vaapi2"].append("dummy");
#endif
#ifdef USING_NVDEC
opts.decoders->append("nvdec");
(*opts.equiv_decoders)["nvdec"].append("dummy");
#endif
#ifdef USING_MEDIACODEC
opts.decoders->append("mediacodec");
(*opts.equiv_decoders)["mediacodec"].append("dummy");
Expand Down Expand Up @@ -1600,6 +1611,23 @@ static enum AVPixelFormat get_format_vaapi2(struct AVCodecContext */*avctx*/,
}
#endif

#ifdef USING_NVDEC
static enum AVPixelFormat get_format_nvdec(struct AVCodecContext */*avctx*/,
const enum AVPixelFormat *valid_fmts)
{
enum AVPixelFormat ret = AV_PIX_FMT_NONE;
while (*valid_fmts != AV_PIX_FMT_NONE) {
if (AV_PIX_FMT_CUDA == *valid_fmts)
{
ret = *valid_fmts;
break;
}
valid_fmts++;
}
return ret;
}
#endif

#ifdef USING_MEDIACODEC
static enum AVPixelFormat get_format_mediacodec(struct AVCodecContext */*avctx*/,
const enum AVPixelFormat *valid_fmts)
Expand Down Expand Up @@ -1706,6 +1734,15 @@ void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc,
enc->get_format = get_format_vaapi2;
}
else
#endif
#ifdef USING_NVDEC
if (codec_is_nvdec(video_codec_id))
{
enc->get_buffer2 = get_avf_buffer_nvdec;
enc->get_format = get_format_nvdec;
directrendering = false;
}
else
#endif
if (codec1 && codec1->capabilities & AV_CODEC_CAP_DR1)
{
Expand Down Expand Up @@ -2519,11 +2556,11 @@ int AvFormatDecoder::ScanStreams(bool novideo)
fps = 0;
if (!is_db_ignored)
{
VideoDisplayProfile vdp;
vdp.SetInput(QSize(width, height),fps,codecName);
dec = vdp.GetDecoder();
thread_count = vdp.GetMaxCPUs();
bool skip_loop_filter = vdp.IsSkipLoopEnabled();
// VideoDisplayProfile vdp;
videoDisplayProfile.SetInput(QSize(width, height),fps,codecName);
dec = videoDisplayProfile.GetDecoder();
thread_count = videoDisplayProfile.GetMaxCPUs();
bool skip_loop_filter = videoDisplayProfile.IsSkipLoopEnabled();
if (!skip_loop_filter)
{
enc->skip_loop_filter = AVDISCARD_NONKEY;
Expand Down Expand Up @@ -2647,6 +2684,24 @@ int AvFormatDecoder::ScanStreams(bool novideo)
}
}
#endif // USING_VAAPI2
#ifdef USING_NVDEC
if (!foundgpudecoder)
{
MythCodecID nvdec_mcid;
AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P;
nvdec_mcid = NvdecContext::GetBestSupportedCodec(
&codec, dec, mpeg_version(enc->codec_id),
pix_fmt);

if (codec_is_nvdec(nvdec_mcid))
{
gCodecMap->freeCodecContext(ic->streams[selTrack]);
enc = gCodecMap->getCodecContext(ic->streams[selTrack], codec);
video_codec_id = nvdec_mcid;
foundgpudecoder = true;
}
}
#endif // USING_NVDEC
}
// default to mpeg2
if (video_codec_id == kCodec_NONE)
Expand All @@ -2667,6 +2722,7 @@ int AvFormatDecoder::ScanStreams(bool novideo)
&& (codec_is_std(video_codec_id)
|| codec_is_mediacodec(video_codec_id)
|| codec_is_vaapi2(video_codec_id)
|| codec_is_nvdec(video_codec_id)
|| GetCodecDecoderName() == "openmax"))
use_frame_timing = true;

Expand Down Expand Up @@ -3040,11 +3096,9 @@ void release_avf_buffer(void *opaque, uint8_t *data)
nd->GetPlayer()->DeLimboFrame(frame);
}

#ifdef USING_VAAPI2
static void dummy_release_avf_buffer(void * /*opaque*/, uint8_t * /*data*/)
{
}
#endif

#ifdef USING_VDPAU
int get_avf_buffer_vdpau(struct AVCodecContext *c, AVFrame *pic, int /*flags*/)
Expand Down Expand Up @@ -3181,6 +3235,14 @@ int get_avf_buffer_vaapi2(struct AVCodecContext *c, AVFrame *pic, int flags)
return avcodec_default_get_buffer2(c, pic, flags);
}
#endif
#ifdef USING_NVDEC
int get_avf_buffer_nvdec(struct AVCodecContext *c, AVFrame *pic, int flags)
{
AvFormatDecoder *nd = (AvFormatDecoder *)(c->opaque);
nd->directrendering = false;
return avcodec_default_get_buffer2(c, pic, flags);
}
#endif

void AvFormatDecoder::DecodeDTVCC(const uint8_t *buf, uint len, bool scte)
{
Expand Down Expand Up @@ -3976,8 +4038,9 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
picframe = m_parent->GetNextVideoFrame();
unsigned char *buf = picframe->buf;
bool used_picframe=false;
#ifdef USING_VAAPI2
if (IS_VAAPI_PIX_FMT((AVPixelFormat)mpa_pic->format))
#if defined(USING_VAAPI2) || defined(USING_NVDEC)
if (AV_PIX_FMT_CUDA == (AVPixelFormat)mpa_pic->format
|| IS_VAAPI_PIX_FMT((AVPixelFormat)mpa_pic->format))
{
int ret = 0;
tmp_frame = av_frame_alloc();
Expand Down Expand Up @@ -4022,7 +4085,7 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
av_freep(&pixelformats);
}
else
#endif // USING_VAAPI2
#endif // USING_VAAPI2 || USING_NVDEC
use_frame = mpa_pic;

if (!used_picframe)
Expand Down
2 changes: 2 additions & 0 deletions mythtv/libs/libmythtv/avformatdecoder.h
Expand Up @@ -209,6 +209,8 @@ class AvFormatDecoder : public DecoderBase
int flags);
friend int get_avf_buffer_vaapi2(struct AVCodecContext *c, AVFrame *pic,
int flags);
friend int get_avf_buffer_nvdec(struct AVCodecContext *c, AVFrame *pic,
int flags);
friend void release_avf_buffer(void *opaque, uint8_t *data);

friend int open_avf(URLContext *h, const char *filename, int flags);
Expand Down
3 changes: 3 additions & 0 deletions mythtv/libs/libmythtv/decoderbase.h
Expand Up @@ -12,6 +12,7 @@ using namespace std;
#include "programinfo.h"
#include "mythcodecid.h"
#include "mythavutil.h"
#include "videodisplayprofile.h"

class RingBuffer;
class TeletextViewer;
Expand Down Expand Up @@ -271,6 +272,7 @@ class DecoderBase
void TrackTotalDuration(bool track) { trackTotalDuration = track; }
int GetfpsMultiplier(void) { return fpsMultiplier; }
MythCodecContext *GetMythCodecContext(void) { return m_mythcodecctx; }
VideoDisplayProfile * GetVideoDisplayProfile(void) { return &videoDisplayProfile; }

protected:
virtual int AutoSelectTrack(uint type);
Expand Down Expand Up @@ -361,6 +363,7 @@ class DecoderBase
/// language preferences for auto-selection of streams
vector<int> languagePreference;
MythCodecContext *m_mythcodecctx;
VideoDisplayProfile videoDisplayProfile;
};

inline int DecoderBase::IncrementTrack(uint type)
Expand Down
6 changes: 6 additions & 0 deletions mythtv/libs/libmythtv/libmythtv.pro
Expand Up @@ -512,6 +512,12 @@ using_frontend {
SOURCES += vaapi2context.cpp
}

using_nvdec {
DEFINES += USING_NVDEC
HEADERS += nvdeccontext.h
SOURCES += nvdeccontext.cpp
}

using_mediacodec {
DEFINES += USING_MEDIACODEC
HEADERS += mediacodeccontext.h
Expand Down

0 comments on commit 8eb4637

Please sign in to comment.