MythTV  master
mythcodeccontext.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 "mythcodeccontext.h"
28 #include "videooutbase.h"
29 #include "mythplayer.h"
30 #ifdef USING_VAAPI2
31 #include "vaapi2context.h"
32 #endif
33 #ifdef USING_NVDEC
34 #include "nvdeccontext.h"
35 #endif
36 
37 extern "C" {
38  #include "libavutil/pixfmt.h"
39  #include "libavutil/hwcontext.h"
40  #include "libavcodec/avcodec.h"
41  // #include "libavfilter/avfilter.h"
42  #include "libavfilter/buffersink.h"
43  #include "libavfilter/buffersrc.h"
44  // #include "libavformat/avformat.h"
45  #include "libavutil/opt.h"
46  #include "libavutil/buffer.h"
47 }
48 
49 #define LOC QString("MythCodecContext: ")
50 
52  stream(nullptr),
53  buffersink_ctx(nullptr),
54  buffersrc_ctx(nullptr),
55  filter_graph(nullptr),
56  filtersInitialized(false),
57  hw_frames_ctx(nullptr),
58  player(nullptr),
59  ptsUsed(0),
60  doublerate(false)
61 {
62  priorPts[0] = 0;
63  priorPts[1] = 0;
64 }
65 
66 // static
68 {
69  MythCodecContext *mctx = nullptr;
70 #ifdef USING_VAAPI2
71  if (codec_is_vaapi2(codec))
72  mctx = new Vaapi2Context();
73 #endif
74 #ifdef USING_NVDEC
75  if (codec_is_nvdec(codec))
76  mctx = new NvdecContext();
77 #endif
78  // In case neither was defined
79  Q_UNUSED(codec);
80 
81  if (!mctx)
82  mctx = new MythCodecContext();
83  return mctx;
84 }
85 
86 // static
87 QStringList MythCodecContext::GetDeinterlacers(const QString& decodername)
88 {
89  QStringList ret;
90 #ifdef USING_VAAPI2
91  if (decodername == "vaapi2")
92  {
93  ret.append("vaapi2default");
94  ret.append("vaapi2bob");
95  ret.append("vaapi2weave");
96  ret.append("vaapi2motion_adaptive");
97  ret.append("vaapi2motion_compensated");
98  ret.append("vaapi2doubleratedefault");
99  ret.append("vaapi2doubleratebob");
100  ret.append("vaapi2doublerateweave");
101  ret.append("vaapi2doubleratemotion_adaptive");
102  ret.append("vaapi2doubleratemotion_compensated");
103 
104 /*
105  Explanation of vaapi2 deinterlacing modes.
106  "mode", "Deinterlacing mode",
107  "default", "Use the highest-numbered (and therefore possibly most advanced) deinterlacing algorithm",
108  "bob", "Use the bob deinterlacing algorithm",
109  "weave", "Use the weave deinterlacing algorithm",
110  "motion_adaptive", "Use the motion adaptive deinterlacing algorithm",
111  "motion_compensated", "Use the motion compensated deinterlacing algorithm",
112 
113  "rate", "Generate output at frame rate or field rate",
114  "frame", "Output at frame rate (one frame of output for each field-pair)",
115  "field", "Output at field rate (one frame of output for each field)",
116 
117  "auto", "Only deinterlace fields, passing frames through unchanged",
118  1 = enabled
119  0 = disabled
120 */
121  }
122 #endif
123 #ifdef USING_NVDEC
124  if (decodername == "nvdec")
125  {
126  ret.append("nvdecweave");
127  ret.append("nvdecbob");
128  ret.append("nvdecadaptive");
129  ret.append("nvdecdoublerateweave");
130  ret.append("nvdecdoubleratebob");
131  ret.append("nvdecdoublerateadaptive");
132 
133 /*
134  Explanation of nvdec deinterlacing modes.
135  "weave", "Weave deinterlacing (do nothing)"
136  "bob", "Bob deinterlacing"
137  "adaptive", "Adaptive deinterlacing"
138  "drop_second_field", "Drop second field when deinterlacing"
139 */
140 
141  }
142 #endif
143  // in case neither of the above was defined
144  Q_UNUSED(decodername);
145  return ret;
146 }
147 // static - Find if a deinterlacer is codec-provided
148 bool MythCodecContext::isCodecDeinterlacer(const QString& decodername)
149 {
150  return (decodername.startsWith("vaapi2")
151  || decodername.startsWith("nvdec") );
152 }
153 
154 // Currently this will only set up the filter after an interlaced frame.
155 // If we need other filters apart from deinterlace filters we will
156 // need to make a change here.
157 
158 int MythCodecContext::FilteredReceiveFrame(AVCodecContext *ctx, AVFrame *frame)
159 {
160  int ret = 0;
161 
162  while (true)
163  {
164  if (filter_graph)
165  {
166  ret = av_buffersink_get_frame(buffersink_ctx, frame);
167  if (ret >= 0)
168  {
169  if (priorPts[0] && ptsUsed == priorPts[1])
170  {
171  frame->pts = priorPts[1] + (priorPts[1] - priorPts[0])/2;
172  frame->scte_cc_len = 0;
173  frame->atsc_cc_len = 0;
174  av_frame_remove_side_data(frame, AV_FRAME_DATA_A53_CC);
175  }
176  else
177  {
178  frame->pts = priorPts[1];
179  ptsUsed = priorPts[1];
180  }
181  }
182  if (ret != AVERROR(EAGAIN))
183  break;
184  }
185 
186  // EAGAIN or no filter graph
187  ret = avcodec_receive_frame(ctx, frame);
188  if (ret < 0)
189  break;
190  priorPts[0]=priorPts[1];
191  priorPts[1]=frame->pts;
192  if (frame->interlaced_frame || filter_graph)
193  {
194  if (!filtersInitialized
195  || width != frame->width
196  || height != frame->height)
197  {
198  // bypass any frame of unknown format
199  if (frame->format < 0)
200  break;
201  ret = InitDeinterlaceFilter(ctx, frame);
202  if (ret < 0)
203  {
204  LOG(VB_GENERAL, LOG_ERR, LOC + "InitDeinterlaceFilter failed - continue without filters");
205  break;
206  }
207  }
208  if (filter_graph)
209  {
210  ret = av_buffersrc_add_frame(buffersrc_ctx, frame);
211  if (ret < 0)
212  break;
213  }
214  else
215  break;
216  }
217  else
218  break;
219  }
220 
221  return ret;
222 }
223 
224 // Setup or change deinterlacer.
225 // Same usage as VideoOutBase::SetupDeinterlace
226 // enable - true to enable, false to disable
227 // name - empty to use video profile deinterlacers, otherwise
228 // use the supplied name.
229 // return true if the deinterlacer was found as a hardware deinterlacer.
230 // return false if the deinterlacer is nnt a hardware deinterlacer,
231 // and a videououtput deinterlacer should be tried instead.
232 
233 bool MythCodecContext::setDeinterlacer(bool enable, QString name)
234 {
235  QMutexLocker lock(&contextLock);
236  // Code to disable interlace
237  if (!enable)
238  {
239  if (deinterlacername.isEmpty())
240  return true;
241  deinterlacername.clear();
242  doublerate = false;
243  filtersInitialized = false;
244  return true;
245  }
246 
247  // Code to enable or change interlace
248  if (name.isEmpty())
249  {
250  if (deinterlacername.isEmpty())
251  {
252  DecoderBase *dec = nullptr;
253  VideoDisplayProfile *vdp = nullptr;
254  if (player)
255  dec = player->GetDecoder();
256  if (dec)
257  vdp = dec->GetVideoDisplayProfile();
258  if (vdp)
259  name = vdp->GetFilteredDeint(QString());
260  }
261  else
263  }
264  bool ret = true;
266  name.clear();
267 
268  if (name.isEmpty())
269  ret = false;
270 
271  if (deinterlacername == name)
272  return ret;
273 
275  doublerate = deinterlacername.contains("doublerate");
276  filtersInitialized = false;
277  return ret;
278 }
279 
281 {
282  deinterlacername.clear();
283  doublerate = false;
284  return setDeinterlacer(true);
285 }
286 
288 {
289  return setDeinterlacer(true,GetFallbackDeint());
290 }
291 
293 {
294 
295  DecoderBase *dec = nullptr;
296  VideoDisplayProfile *vdp = nullptr;
297  if (player)
298  dec = player->GetDecoder();
299  if (dec)
300  vdp = dec->GetVideoDisplayProfile();
301  if (vdp)
302  return vdp->GetFallbackDeinterlacer();
303  return QString();
304 }
305 
306 // Dummy default method for those that do not use deinterlacers
307 
308 int MythCodecContext::InitDeinterlaceFilter(AVCodecContext * /*ctx*/, AVFrame *frame)
309 {
310  QMutexLocker lock(&contextLock);
311  width = frame->width;
312  height = frame->height;
313  filtersInitialized = true;
314  return 0;
315 }
bool setDeinterlacer(bool enable, QString name=QString())
static bool isCodecDeinterlacer(const QString &decodername)
AVFilterContext * buffersink_ctx
MythCodecID
Definition: mythcodecid.h:10
struct AVFrame AVFrame
QString GetFilteredDeint(const QString &override)
QString GetFallbackDeinterlacer(void) const
VideoDisplayProfile * GetVideoDisplayProfile(void)
Definition: decoderbase.h:271
#define LOC
AVFilterGraph * filter_graph
virtual int InitDeinterlaceFilter(AVCodecContext *ctx, AVFrame *frame)
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
MythPlayer * player
virtual int FilteredReceiveFrame(AVCodecContext *ctx, AVFrame *frame)
const char * name
Definition: ParseText.cpp:328
virtual QStringList GetDeinterlacers(void)
static MythCodecContext * createMythCodecContext(MythCodecID codec)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
AVFilterContext * buffersrc_ctx
#define codec_is_vaapi2(id)
Definition: mythcodecid.h:146
#define codec_is_nvdec(id)
Definition: mythcodecid.h:148
QString GetFallbackDeint(void)
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:278