MythTV  master
mythvdpaucontext.cpp
Go to the documentation of this file.
1 // MythTV
2 #include "mythmainwindow.h"
3 #include "avformatdecoder.h"
4 #include "mythvdpauinterop.h"
5 #include "mythvdpauhelper.h"
6 #include "mythvdpaucontext.h"
7 #include "mythplayerui.h"
8 
9 // FFmpeg
10 extern "C" {
11 #include "libavutil/hwcontext_vdpau.h"
12 #include "libavutil/pixdesc.h"
13 #include "libavcodec/vdpau.h"
14 }
15 
16 #define LOC QString("VDPAUDec: ")
17 
25  : MythCodecContext(Parent, CodecID)
26 {
27 }
28 
31 {
32  if (!gCoreContext->IsUIThread() || !Context)
33  return -1;
34 
35  // The interop must have a reference to the ui player so it can be deleted
36  // from the main thread.
37  MythPlayerUI* player = GetPlayerUI(Context);
38  if (!player)
39  return -1;
40 
41  // Retrieve OpenGL render context
43  if (!render)
44  return -1;
45  OpenGLLocker locker(render);
46 
47  // Check interop support
49  return -1;
50 
51  // Create interop
52  auto vdpauid = static_cast<MythCodecID>(kCodec_MPEG1_VDPAU + (mpeg_version(Context->codec_id) - 1));
53  MythVDPAUInterop *interop = MythVDPAUInterop::Create(render, vdpauid);
54  if (!interop)
55  return -1;
56 
57  // Set player
58  interop->SetPlayer(player);
59 
60  // Allocate the device context
61  AVBufferRef* hwdeviceref = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VDPAU, interop);
62  if (!hwdeviceref)
63  return -1;
64 
65  auto* hwdevicecontext = reinterpret_cast<AVHWDeviceContext*>(hwdeviceref->data);
66  if (!hwdevicecontext || !hwdevicecontext->hwctx)
67  return -1;
68 
69  // Initialise device context
70  if (av_hwdevice_ctx_init(hwdeviceref) < 0)
71  {
72  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise device context");
73  av_buffer_unref(&hwdeviceref);
74  interop->DecrRef();
75  return -1;
76  }
77 
78  // allocate the hardware frames context
79  Context->hw_frames_ctx = av_hwframe_ctx_alloc(hwdeviceref);
80  if (!Context->hw_frames_ctx)
81  {
82  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VDPAU hardware frames context");
83  av_buffer_unref(&hwdeviceref);
84  interop->DecrRef();
85  return -1;
86  }
87 
88  // Add our interop class and set the callback for its release
89  auto* hwframesctx = reinterpret_cast<AVHWFramesContext*>(Context->hw_frames_ctx->data);
90  hwframesctx->user_opaque = interop;
91  hwframesctx->free = &MythCodecContext::FramesContextFinished;
92 
93  // Initialise frames context
94  hwframesctx->sw_format = Context->sw_pix_fmt == AV_PIX_FMT_YUVJ420P ? AV_PIX_FMT_YUV420P : Context->sw_pix_fmt;
95  hwframesctx->format = AV_PIX_FMT_VDPAU;
96  hwframesctx->width = Context->coded_width;
97  hwframesctx->height = Context->coded_height;
98  int res = av_hwframe_ctx_init(Context->hw_frames_ctx);
99  if (res < 0)
100  {
101  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise VDPAU frames context");
102  av_buffer_unref(&hwdeviceref);
103  av_buffer_unref(&(Context->hw_frames_ctx));
104  return res;
105  }
106 
107  auto* vdpaudevicectx = static_cast<AVVDPAUDeviceContext*>(hwdevicecontext->hwctx);
108  if (av_vdpau_bind_context(Context, vdpaudevicectx->device,
109  vdpaudevicectx->get_proc_address, AV_HWACCEL_FLAG_IGNORE_LEVEL) != 0)
110  {
111  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to bind VDPAU context");
112  av_buffer_unref(&hwdeviceref);
113  av_buffer_unref(&(Context->hw_frames_ctx));
114  return -1;
115  }
116 
117  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU buffer pool created"));
118  av_buffer_unref(&hwdeviceref);
119 
121 
122  return 0;
123 }
124 
126  AVCodec ** /*Codec*/,
127  const QString &Decoder,
128  uint StreamType)
129 {
130  bool decodeonly = Decoder == "vdpau-dec";
131  auto success = static_cast<MythCodecID>((decodeonly ? kCodec_MPEG1_VDPAU_DEC : kCodec_MPEG1_VDPAU) + (StreamType - 1));
132  auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
133 
134  if (!Decoder.startsWith("vdpau") || getenv("NO_VDPAU") || IsUnsupportedProfile(*Context))
135  return failure;
136 
137  if (!decodeonly)
138  {
139  // check for the correct player type and interop supprt
140  MythPlayerUI* player = GetPlayerUI(*Context);
142  return failure;
143  }
144 
145  QString codec = ff_codec_id_string((*Context)->codec_id);
146  QString profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
147  QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
148 
149  // VDPAU only supports 8bit 420p:(
151  bool vdpau = (type == FMT_YV12) && MythVDPAUHelper::HaveVDPAU() &&
152  (decodeonly ? codec_is_vdpau_dechw(success) : codec_is_vdpau_hw(success));
153 
154  if (vdpau)
155  {
156  MythCodecContext::CodecProfile mythprofile =
157  MythCodecContext::FFmpegToMythProfile((*Context)->codec_id, (*Context)->profile);
158  const VDPAUProfiles& profiles = MythVDPAUHelper::GetProfiles();
159  vdpau = false;
160  for (auto vdpauprofile : profiles)
161  {
162  bool match = vdpauprofile.first == mythprofile;
163  if (match)
164  {
165  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Trying %1")
166  .arg(MythCodecContext::GetProfileDescription(mythprofile, QSize())));
167  if (vdpauprofile.second.Supported((*Context)->width, (*Context)->height, (*Context)->level))
168  {
169  vdpau = true;
170  break;
171  }
172  }
173  }
174  }
175 
176  // H264 needs additional checks for old hardware
177  if (vdpau && (success == kCodec_H264_VDPAU || success == kCodec_H264_VDPAU_DEC))
178  {
180  if (!vdpau)
181  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "H264 decode check failed");
182  }
183 
184  QString desc = QString("'%1 %2 %3 %4x%5'")
185  .arg(codec).arg(profile).arg(pixfmt).arg((*Context)->width).arg((*Context)->height);
186 
187  if (!vdpau)
188  {
189  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU does not support decoding %1").arg(desc));
190  return failure;
191  }
192 
193  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU supports decoding %1").arg(desc));
194  (*Context)->pix_fmt = AV_PIX_FMT_VDPAU;
195  return success;
196 }
197 
199 enum AVPixelFormat MythVDPAUContext::GetFormat(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
200 {
201  while (*PixFmt != AV_PIX_FMT_NONE)
202  {
203  if (*PixFmt == AV_PIX_FMT_VDPAU)
205  return AV_PIX_FMT_VDPAU;
206  PixFmt++;
207  }
208  return AV_PIX_FMT_NONE;
209 }
210 
212 enum AVPixelFormat MythVDPAUContext::GetFormat2(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
213 {
214  while (*PixFmt != AV_PIX_FMT_NONE)
215  {
216  if (*PixFmt == AV_PIX_FMT_VDPAU)
217  {
218  AVBufferRef *device = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VDPAU, nullptr);
219  if (device)
220  {
222  if (Context->sw_pix_fmt == AV_PIX_FMT_YUVJ420P)
223  Context->sw_pix_fmt = AV_PIX_FMT_YUV420P;
224  Context->hw_device_ctx = device;
225  return AV_PIX_FMT_VDPAU;
226  }
227  }
228  PixFmt++;
229  }
230  return AV_PIX_FMT_NONE;
231 }
232 
233 bool MythVDPAUContext::RetrieveFrame(AVCodecContext* /*unused*/, MythVideoFrame *Frame, AVFrame *AvFrame)
234 {
235  if (AvFrame->format != AV_PIX_FMT_VDPAU)
236  return false;
238  return RetrieveHWFrame(Frame, AvFrame);
239  return false;
240 }
241 
243 {
244  return m_codecID == kCodec_H264_VDPAU;
245 }
246 
248 {
250 }
251 
262 {
263  if (m_resetRequired)
264  return true;
265 
267  return false;
268  if (!Context)
269  return false;
270  if (!Context->hw_frames_ctx)
271  return false;
272 
273  auto* hwframesctx = reinterpret_cast<AVHWFramesContext*>(Context->hw_frames_ctx->data);
274  auto* interop = reinterpret_cast<MythVDPAUInterop*>(hwframesctx->user_opaque);
275  if (interop && interop->IsPreempted())
276  {
277  m_resetRequired = true;
278  return true;
279  }
280  return false;
281 }
282 
283 void MythVDPAUContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
284 {
286  {
287  Context->get_buffer2 = MythCodecContext::GetBuffer;
288  Context->get_format = MythVDPAUContext::GetFormat;
289  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
290  return;
291  }
293  {
295  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
296  DirectRendering = false;
297  return;
298  }
299 
300  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
301 }
MythVDPAUHelper::GetProfiles
static const VDPAUProfiles & GetProfiles(void)
Definition: mythvdpauhelper.cpp:120
MythVDPAUContext::DecoderWillResetOnAspect
bool DecoderWillResetOnAspect(void) override
Definition: mythvdpaucontext.cpp:247
MythCodecContext::m_codecID
MythCodecID m_codecID
Definition: mythcodeccontext.h:167
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
mythplayerui.h
mpeg_version
uint mpeg_version(int codec_id)
Definition: mythcodecid.cpp:455
mythvdpauinterop.h
MythVDPAUContext::InitialiseContext
static int InitialiseContext(AVCodecContext *Context)
Create a VDPAU device for use with direct rendering.
Definition: mythvdpaucontext.cpp:30
VDPAUProfiles
std::vector< VDPAUProfile > VDPAUProfiles
Definition: mythvdpauhelper.h:38
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:55
Frame
Definition: zmdefines.h:94
MythCodecContext::NewHardwareFramesContext
static void NewHardwareFramesContext(void)
Track the number of concurrent frames contexts.
Definition: mythcodeccontext.cpp:418
arg
arg(title).arg(filename).arg(doDelete))
MythCoreContext::IsUIThread
bool IsUIThread(void)
Definition: mythcorecontext.cpp:1353
Context
QHash< QString, Action * > Context
Definition: action.h:77
MythCodecContext::InitVideoCodec
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
Definition: mythcodeccontext.cpp:292
MythVDPAUContext::MythVDPAUContext
MythVDPAUContext(DecoderBase *Parent, MythCodecID CodecID)
Definition: mythvdpaucontext.cpp:24
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythCodecContext::FramesContextFinished
static void FramesContextFinished(AVHWFramesContext *Context)
Definition: mythcodeccontext.cpp:425
MythVDPAUContext::GetFormat
static enum AVPixelFormat GetFormat(AVCodecContext *Context, const enum AVPixelFormat *PixFmt)
\ brief Confirm pixel format and create VDPAU device for direct rendering (MythVDPAUInterop required)
Definition: mythvdpaucontext.cpp:199
codec_is_vdpau_dec
#define codec_is_vdpau_dec(id)
Definition: mythcodecid.h:304
MythCodecContext::FFmpegToMythProfile
static CodecProfile FFmpegToMythProfile(AVCodecID CodecID, int Profile)
Definition: mythcodeccontext.cpp:660
MythVDPAUHelper::HaveVDPAU
static bool HaveVDPAU(void)
Definition: mythvdpauhelper.cpp:53
kCodec_MPEG2_VDPAU
@ kCodec_MPEG2_VDPAU
Definition: mythcodecid.h:38
kCodec_MPEG1_VDPAU_DEC
@ kCodec_MPEG1_VDPAU_DEC
Definition: mythcodecid.h:53
MythVDPAUInterop::Create
static MythVDPAUInterop * Create(MythRenderOpenGL *Context, MythCodecID CodecId)
Definition: mythvdpauinterop.cpp:9
MythCodecID
MythCodecID
Definition: mythcodecid.h:11
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
LOC
#define LOC
Definition: mythvdpaucontext.cpp:16
MythPlayerUI
Definition: mythplayerui.h:12
MythVDPAUContext::GetSupportedCodec
static MythCodecID GetSupportedCodec(AVCodecContext **CodecContext, AVCodec **Codec, const QString &Decoder, uint StreamType)
Definition: mythvdpaucontext.cpp:125
Decoder
Definition: decoder.h:66
MythOpenGLInterop::SetPlayer
void SetPlayer(MythPlayerUI *Player)
Definition: mythopenglinterop.cpp:278
kCodec_H264_VDPAU
@ kCodec_H264_VDPAU
Definition: mythcodecid.h:41
hardwareprofile.scan.profile
profile
Definition: scan.py:99
mythvdpauhelper.h
MythOpenGLInterop::Unsupported
@ Unsupported
Definition: mythopenglinterop.h:31
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:19
kCodec_MPEG1
@ kCodec_MPEG1
Definition: mythcodecid.h:21
MythCodecContext::GetBuffer
static int GetBuffer(struct AVCodecContext *Context, AVFrame *Frame, int Flags)
A generic hardware buffer initialisation method when using AVHWFramesContext.
Definition: mythcodeccontext.cpp:312
MythOpenGLInterop::GetInteropType
static Type GetInteropType(VideoFrameType Format, MythPlayerUI *Player)
Check whether we support direct rendering for the given VideoFrameType.
Definition: mythopenglinterop.cpp:74
mythvdpaucontext.h
MythVDPAUInterop
Definition: mythvdpauinterop.h:26
MythCodecContext::RetrieveHWFrame
virtual bool RetrieveHWFrame(MythVideoFrame *Frame, AVFrame *AvFrame)
Definition: mythcodeccontext.cpp:605
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:56
MythCodecContext::IsUnsupportedProfile
static bool IsUnsupportedProfile(AVCodecContext *Context)
Most hardware decoders do not support these codecs/profiles.
Definition: mythcodeccontext.cpp:575
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:73
MythRenderOpenGL
Definition: mythrenderopengl.h:98
codec_is_vdpau_hw
#define codec_is_vdpau_hw(id)
Definition: mythcodecid.h:300
MythCodecContext::CreateDevice
static AVBufferRef * CreateDevice(AVHWDeviceType Type, MythOpenGLInterop *Interop, const QString &Device=QString())
Definition: mythcodeccontext.cpp:536
MythVDPAUContext::RetrieveFrame
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
Definition: mythvdpaucontext.cpp:233
FMT_VDPAU
@ FMT_VDPAU
Definition: mythframe.h:52
MythVDPAUContext::GetFormat2
static enum AVPixelFormat GetFormat2(AVCodecContext *Context, const enum AVPixelFormat *PixFmt)
\ brief Confirm pixel format and create VDPAU device for copy back (no MythVDPAUInterop required)
Definition: mythvdpaucontext.cpp:212
avformatdecoder.h
MythRenderOpenGL::GetOpenGLRender
static MythRenderOpenGL * GetOpenGLRender(void)
Definition: mythrenderopengl.cpp:66
MythCodecContext::m_resetRequired
bool m_resetRequired
Definition: mythcodeccontext.h:168
MythVDPAUHelper::CheckH264Decode
static bool CheckH264Decode(AVCodecContext *Context)
Definition: mythvdpauhelper.cpp:340
MythVDPAUContext::DecoderWillResetOnFlush
bool DecoderWillResetOnFlush(void) override
Definition: mythvdpaucontext.cpp:242
MythCodecContext
Definition: mythcodeccontext.h:52
VideoFrameType
VideoFrameType
Definition: mythframe.h:16
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:763
MythVideoFrame
Definition: mythframe.h:83
MythVDPAUContext::DecoderNeedsReset
bool DecoderNeedsReset(AVCodecContext *Context) override
Report whether the decoder is known to be errored.
Definition: mythvdpaucontext.cpp:261
kCodec_H264_VDPAU_DEC
@ kCodec_H264_VDPAU_DEC
Definition: mythcodecid.h:57
kCodec_MPEG1_VDPAU
@ kCodec_MPEG1_VDPAU
Definition: mythcodecid.h:37
MythVDPAUContext::InitVideoCodec
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
Definition: mythvdpaucontext.cpp:283
codec_is_vdpau_dechw
#define codec_is_vdpau_dechw(id)
Definition: mythcodecid.h:306
mythmainwindow.h
MythCodecContext::InitialiseDecoder
static int InitialiseDecoder(AVCodecContext *Context, CreateHWDecoder Callback, const QString &Debug)
Initialise a hardware decoder that is expected to use AVHWFramesContext.
Definition: mythcodeccontext.cpp:503
DecoderBase
Definition: decoderbase.h:121
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:493
kCodec_MPEG2_VDPAU_DEC
@ kCodec_MPEG2_VDPAU_DEC
Definition: mythcodecid.h:54
OpenGLLocker
Definition: mythrenderopengl.h:256