MythTV  master
nvdeccontext.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017 MythTV Developers <mythtv-dev@mythtv.org>
3 //
4 // This is part of MythTV (https://www.mythtv.org)
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 //
24 
25 #include "mythcorecontext.h"
26 #include "mythlogging.h"
27 #include "nvdeccontext.h"
28 #include "videooutbase.h"
29 #include "mythplayer.h"
30 
31 extern "C" {
32  #include "libavutil/pixfmt.h"
33  #include "libavutil/hwcontext.h"
34  #include "libavutil/opt.h"
35  #include "libavcodec/avcodec.h"
36 }
37 
38 #define LOC QString("NVDEC: ")
39 
41  AVCodec **ppCodec,
42  const QString &decoder,
43  uint stream_type,
44  AVPixelFormat &pix_fmt)
45 {
46  enum AVHWDeviceType type = AV_HWDEVICE_TYPE_CUDA;
47 
48  AVPixelFormat fmt = AV_PIX_FMT_NONE;
49  if (decoder == "nvdec")
50  {
51  for (int i = 0;; i++) {
52  const AVCodecHWConfig *config = avcodec_get_hw_config(*ppCodec, i);
53  if (!config)
54  {
55  LOG(VB_PLAYBACK, LOG_INFO, LOC +
56  QString("Decoder %1 does not support device type %2.")
57  .arg((*ppCodec)->name).arg(av_hwdevice_get_type_name(type)));
58  break;
59  }
60  if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
61  config->device_type == type)
62  {
63  QString decodername = QString((*ppCodec)->name) + "_cuvid";
64  if (decodername == "mpeg2video_cuvid")
65  decodername = "mpeg2_cuvid";
66  AVCodec *newCodec = avcodec_find_decoder_by_name (decodername.toLocal8Bit());
67  if (newCodec)
68  {
69  *ppCodec = newCodec;
70  fmt = config->pix_fmt;
71  }
72  else
73  LOG(VB_PLAYBACK, LOG_INFO, LOC +
74  QString("Decoder %1 does not exist.")
75  .arg(decodername));
76  break;
77  }
78  }
79  }
80  if (fmt == AV_PIX_FMT_NONE)
81  return (MythCodecID)(kCodec_MPEG1 + (stream_type - 1));
82 
83  LOG(VB_PLAYBACK, LOG_INFO, LOC +
84  QString("Decoder %1 supports device type %2.")
85  .arg((*ppCodec)->name).arg(av_hwdevice_get_type_name(type)));
86  pix_fmt = fmt;
87  return (MythCodecID)(kCodec_MPEG1_NVDEC + (stream_type - 1));
88 }
89 
90 int NvdecContext::HwDecoderInit(AVCodecContext *ctx)
91 {
92  int ret = 0;
93  AVBufferRef *hw_device_ctx = nullptr;
94 
95  const char *device = nullptr;
96  QString nvdecDevice = gCoreContext->GetSetting("NVDECDevice");
97  if (!nvdecDevice.isEmpty())
98  {
99  device = nvdecDevice.toLocal8Bit().constData();
100  }
101 
102  ret = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA,
103  device, nullptr, 0);
104  if (ret < 0)
105  {
106  char error[AV_ERROR_MAX_STRING_SIZE];
107  LOG(VB_GENERAL, LOG_ERR, LOC +
108  QString("av_hwdevice_ctx_create Device = <%3> error: %1 (%2)")
109  .arg(av_make_error_string(error, sizeof(error), ret))
110  .arg(ret).arg(nvdecDevice));
111  }
112  else
113  {
114  ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
115  av_buffer_unref(&hw_device_ctx);
116  }
117 
118  SetDeinterlace(ctx);
119 
120  return ret;
121 }
122 
123 
124 bool NvdecContext::isValidDeinterlacer(QString filtername)
125 {
126  return filtername.startsWith("nvdec");
127 }
128 
130 {
131  return MythCodecContext::GetDeinterlacers("nvdec");
132 }
133 
134 int NvdecContext::SetDeinterlace(AVCodecContext *ctx)
135 {
136  QMutexLocker lock(&contextLock);
137  bool dropSecondFld = false;
138  int ret = 0;
139  QString mode = GetDeinterlaceMode(dropSecondFld);
140  if (mode.isEmpty())
141  {
142  ret = av_opt_set(ctx->priv_data,"deint","weave",0);
143  if (ret == 0)
144  LOG(VB_GENERAL, LOG_INFO, LOC +
145  "Disabled hardware decoder based deinterlacer.");
146  return ret;
147  }
148  ret = av_opt_set(ctx->priv_data,"deint",mode.toLocal8Bit(),0);
149  // ret = av_opt_set(ctx,"deint",mode.toLocal8Bit(),AV_OPT_SEARCH_CHILDREN);
150  if (ret == 0)
151  ret = av_opt_set_int(ctx->priv_data,"drop_second_field",(int)dropSecondFld,0);
152  // ret = av_opt_set_int(ctx,"drop_second_field",(int)dropSecondFld,AV_OPT_SEARCH_CHILDREN);
153  if (ret == 0)
154  LOG(VB_GENERAL, LOG_INFO, LOC +
155  QString("Enabled hardware decoder based deinterlace '%1' mode: <%2>.")
156  .arg(deinterlacername).arg(mode));
157 
158  return ret;
159 }
160 
161 QString NvdecContext::GetDeinterlaceMode(bool &dropSecondFld)
162 {
163  // example mode - weave
164  // example deinterlacername - nvdecdoublerateweave
165 
166  dropSecondFld=true;
167  QString mode;
169  return mode;
170  mode = deinterlacername;
171  mode.remove(0,5); //remove "nvdec"
172  if (mode.startsWith("doublerate"))
173  {
174  dropSecondFld=false;
175  mode.remove(0,10); // remove "doublerate"
176  }
177  return mode;
178 }
bool isValidDeinterlacer(QString) override
MythCodecID
Definition: mythcodecid.h:10
static void error(const char *str,...)
Definition: vbi.c:42
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
int SetDeinterlace(AVCodecContext *ctx)
int HwDecoderInit(AVCodecContext *ctx) override
QString GetSetting(const QString &key, const QString &defaultval="")
#define LOC
QStringList GetDeinterlacers(void) override
virtual QStringList GetDeinterlacers(void)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static MythCodecID GetBestSupportedCodec(AVCodec **ppCodec, const QString &decoder, uint stream_type, AVPixelFormat &pix_fmt)
QString GetDeinterlaceMode(bool &dropSecondFld)