MythTV  master
vaapi2context.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 "vaapi2context.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 "libavcodec/avcodec.h"
35  #include "libavfilter/avfilter.h"
36  #include "libavformat/avformat.h"
37  #include "libavfilter/buffersrc.h"
38 }
39 
40 #define LOC QString("VAAPI2: ")
41 
43 {
44  CloseFilters();
45 }
46 
47 
49  AVCodec **ppCodec,
50  const QString &decoder,
51  uint stream_type,
52  AVPixelFormat &pix_fmt)
53 {
54  enum AVHWDeviceType type = AV_HWDEVICE_TYPE_VAAPI;
55 
56  AVPixelFormat fmt = AV_PIX_FMT_NONE;
57  if (decoder == "vaapi2")
58  {
59  for (int i = 0;; i++) {
60  const AVCodecHWConfig *config = avcodec_get_hw_config(*ppCodec, i);
61  if (!config) {
62  LOG(VB_PLAYBACK, LOG_INFO, LOC +
63  QString("Decoder %1 does not support device type %2.")
64  .arg((*ppCodec)->name).arg(av_hwdevice_get_type_name(type)));
65  break;
66  }
67  if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
68  config->device_type == type) {
69  fmt = config->pix_fmt;
70  break;
71  }
72  }
73  }
74  if (fmt == AV_PIX_FMT_NONE)
75  return (MythCodecID)(kCodec_MPEG1 + (stream_type - 1));
76 
77  LOG(VB_PLAYBACK, LOG_INFO, LOC +
78  QString("Decoder %1 supports device type %2.")
79  .arg((*ppCodec)->name).arg(av_hwdevice_get_type_name(type)));
80  pix_fmt = fmt;
81  return (MythCodecID)(kCodec_MPEG1_VAAPI2 + (stream_type - 1));
82 }
83 
84 // const char *filter_descr = "scale=78:24,transpose=cclock";
85 /* other way:
86  scale=78:24 [scl]; [scl] transpose=cclock // assumes "[in]" and "[out]" to be input output pads respectively
87  */
88 
89 int Vaapi2Context::HwDecoderInit(AVCodecContext *ctx)
90 {
91  int ret = 0;
92  AVBufferRef *hw_device_ctx = nullptr;
93 
94  const char *device = nullptr;
95  QString vaapiDevice = gCoreContext->GetSetting("VAAPIDevice");
96  if (!vaapiDevice.isEmpty())
97  {
98  device = vaapiDevice.toLocal8Bit().constData();
99  }
100 
101  ret = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI,
102  device, nullptr, 0);
103  if (ret < 0)
104  {
105  char error[AV_ERROR_MAX_STRING_SIZE];
106  LOG(VB_GENERAL, LOG_ERR, LOC +
107  QString("av_hwdevice_ctx_create Device = <%3> error: %1 (%2)")
108  .arg(av_make_error_string(error, sizeof(error), ret))
109  .arg(ret).arg(vaapiDevice));
110  }
111  else
112  {
113  ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
114  av_buffer_unref(&hw_device_ctx);
115  }
116 
117  return ret;
118 }
119 
121 {
122  // example filter - deinterlace_vaapi=mode=default:rate=frame:auto=1
123  // example deinterlacername - vaapi2doubleratemotion_compensated
124  QString ret;
125  QString rate="frame";
127  return ret;
128  QString filtername = deinterlacername;
129  filtername.remove(0,6); //remove "vaapi2"
130  if (filtername.startsWith("doublerate"))
131  {
132  rate="field";
133  filtername.remove(0,10); // remove "doublerate"
134  }
135  ret=QString("deinterlace_vaapi=mode=%1:rate=%2:auto=1")
136  .arg(filtername).arg(rate);
137 
138  return ret;
139 }
140 
141 bool Vaapi2Context::isValidDeinterlacer(QString filtername)
142 {
143  return filtername.startsWith("vaapi2");
144 }
145 
147 {
148  return MythCodecContext::GetDeinterlacers("vaapi2");
149 }
150 
151 
152 int Vaapi2Context::InitDeinterlaceFilter(AVCodecContext *ctx, AVFrame *frame)
153 {
154  QMutexLocker lock(&contextLock);
155  char args[512];
156  int ret = 0;
157  CloseFilters();
158  width = frame->width;
159  height = frame->height;
160  filtersInitialized = true;
161  if (!player || !stream)
162  {
163  LOG(VB_GENERAL, LOG_ERR, LOC + "Player or stream is not set up in MythCodecContext");
164  return -1;
165  }
167  {
168  QString request = deinterlacername;
170  LOG(VB_PLAYBACK, LOG_INFO, LOC
171  + QString("Deinterlacer %1 requires double rate, switching to %2 instead.")
172  .arg(request).arg(deinterlacername));
174  deinterlacername.clear();
175  doublerate = deinterlacername.contains("doublerate");
176 
177  // if the fallback is a non-vaapi - deinterlace will be turned off
178  // and the videoout methods can take over.
179  }
180  QString filters;
182  filters = GetDeinterlaceFilter();
183 
184  if (filters.isEmpty())
185  {
186  LOG(VB_GENERAL, LOG_INFO, LOC +
187  "Disabled hardware decoder based deinterlacer.");
188  return ret;
189  }
190  const AVFilter *buffersrc = avfilter_get_by_name("buffer");
191  const AVFilter *buffersink = avfilter_get_by_name("buffersink");
192  AVFilterInOut *outputs = avfilter_inout_alloc();
193  AVFilterInOut *inputs = avfilter_inout_alloc();
194  AVRational time_base = stream->time_base;
195  AVBufferSrcParameters* params = nullptr;
196 
197  filter_graph = avfilter_graph_alloc();
198  if (!outputs || !inputs || !filter_graph)
199  {
200  ret = AVERROR(ENOMEM);
201  goto end;
202  }
203 
204  /* buffer video source: the decoded frames from the decoder will be inserted here. */
205  snprintf(args, sizeof(args),
206  "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
207  frame->width, frame->height, frame->format, // ctx->pix_fmt,
208  time_base.num, time_base.den,
209  ctx->sample_aspect_ratio.num, ctx->sample_aspect_ratio.den);
210 
211  // isInterlaced = frame->interlaced_frame;
212 
213  ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
214  args, nullptr, filter_graph);
215  if (ret < 0)
216  {
217  LOG(VB_GENERAL, LOG_ERR, LOC + "avfilter_graph_create_filter failed for buffer source");
218  goto end;
219  }
220 
221  params = av_buffersrc_parameters_alloc();
222  if (hw_frames_ctx)
223  av_buffer_unref(&hw_frames_ctx);
224  hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);
225  params->hw_frames_ctx = hw_frames_ctx;
226 
227  ret = av_buffersrc_parameters_set(buffersrc_ctx, params);
228 
229  if (ret < 0)
230  {
231  LOG(VB_GENERAL, LOG_ERR, LOC + "av_buffersrc_parameters_set failed");
232  goto end;
233  }
234 
235  av_freep(&params);
236 
237  /* buffer video sink: to terminate the filter chain. */
238  ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
239  nullptr, nullptr, filter_graph);
240  if (ret < 0)
241  {
242  LOG(VB_GENERAL, LOG_ERR, LOC + "avfilter_graph_create_filter failed for buffer sink");
243  goto end;
244  }
245 
246  /*
247  * Set the endpoints for the filter graph. The filter_graph will
248  * be linked to the graph described by filters_descr.
249  */
250 
251  /*
252  * The buffer source output must be connected to the input pad of
253  * the first filter described by filters_descr; since the first
254  * filter input label is not specified, it is set to "in" by
255  * default.
256  */
257  outputs->name = av_strdup("in");
258  outputs->filter_ctx = buffersrc_ctx;
259  outputs->pad_idx = 0;
260  outputs->next = nullptr;
261 
262  /*
263  * The buffer sink input must be connected to the output pad of
264  * the last filter described by filters_descr; since the last
265  * filter output label is not specified, it is set to "out" by
266  * default.
267  */
268  inputs->name = av_strdup("out");
269  inputs->filter_ctx = buffersink_ctx;
270  inputs->pad_idx = 0;
271  inputs->next = nullptr;
272 
273  if ((ret = avfilter_graph_parse_ptr(filter_graph, filters.toLocal8Bit(),
274  &inputs, &outputs,nullptr)) < 0)
275  {
276  LOG(VB_GENERAL, LOG_ERR, LOC
277  + QString("avfilter_graph_parse_ptr failed for %1").arg(filters));
278  goto end;
279  }
280 
281  if ((ret = avfilter_graph_config(filter_graph, nullptr)) < 0)
282  {
283  LOG(VB_GENERAL, LOG_ERR, LOC
284  + QString("avfilter_graph_config failed"));
285  goto end;
286  }
287 
288  LOG(VB_GENERAL, LOG_INFO, LOC +
289  QString("Enabled hardware decoder based deinterlace filter '%1': <%2>.")
290  .arg(deinterlacername).arg(filters));
291 end:
292  if (ret < 0)
293  {
294  avfilter_graph_free(&filter_graph);
295  filter_graph = nullptr;
296  doublerate = false;
297  }
298  avfilter_inout_free(&inputs);
299  avfilter_inout_free(&outputs);
300 
301  return ret;
302 }
303 
305 {
306  avfilter_graph_free(&filter_graph);
307  filter_graph = nullptr;
308  buffersink_ctx = nullptr;
309  buffersrc_ctx = nullptr;
310  filtersInitialized = false;
311  ptsUsed = 0;
312  priorPts[0] = 0;
313  priorPts[1] = 0;
314  // isInterlaced = 0;
315  width = 0;
316  height = 0;
317 
318  if (hw_frames_ctx)
319  av_buffer_unref(&hw_frames_ctx);
320 }
static MythCodecID GetBestSupportedCodec(AVCodec **ppCodec, const QString &decoder, uint stream_type, AVPixelFormat &pix_fmt)
#define LOC
static bool isCodecDeinterlacer(const QString &decodername)
AVFilterContext * buffersink_ctx
MythCodecID
Definition: mythcodecid.h:10
static void error(const char *str,...)
Definition: vbi.c:42
struct AVFrame AVFrame
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
AVFilterGraph * filter_graph
int InitDeinterlaceFilter(AVCodecContext *ctx, AVFrame *frame) override
MythPlayer * player
QString GetSetting(const QString &key, const QString &defaultval="")
int HwDecoderInit(AVCodecContext *ctx) override
bool isValidDeinterlacer(QString) override
QString GetDeinterlaceFilter(void) override
virtual QStringList GetDeinterlacers(void)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
AVFilterContext * buffersrc_ctx
QStringList GetDeinterlacers(void) override
bool CanSupportDoubleRate(void)
AVBufferRef * hw_frames_ctx
QString GetFallbackDeint(void)