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 
30 int MythVDPAUContext::InitialiseContext(AVCodecContext* Context)
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  auto * player = GetPlayerUI(Context);
38  if (!player)
39  return -1;
40 
41  // Retrieve OpenGL render context
42  auto * render = dynamic_cast<MythRenderOpenGL*>(player->GetRender());
43  if (!render)
44  return -1;
45  OpenGLLocker locker(render);
46 
47  // Create interop
48  auto vdpauid = static_cast<MythCodecID>(kCodec_MPEG1_VDPAU + (mpeg_version(Context->codec_id) - 1));
49  auto * interop = MythVDPAUInterop::CreateVDPAU(player, render, vdpauid);
50  if (!interop)
51  return -1;
52 
53  // Allocate the device context
54  auto * hwdeviceref = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VDPAU, interop);
55  if (!hwdeviceref)
56  return -1;
57 
58  auto * hwdevicecontext = reinterpret_cast<AVHWDeviceContext*>(hwdeviceref->data);
59  if (!hwdevicecontext || !hwdevicecontext->hwctx)
60  return -1;
61 
62  // Initialise device context
63  if (av_hwdevice_ctx_init(hwdeviceref) < 0)
64  {
65  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise device context");
66  av_buffer_unref(&hwdeviceref);
67  interop->DecrRef();
68  return -1;
69  }
70 
71  // allocate the hardware frames context
72  Context->hw_frames_ctx = av_hwframe_ctx_alloc(hwdeviceref);
73  if (!Context->hw_frames_ctx)
74  {
75  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VDPAU hardware frames context");
76  av_buffer_unref(&hwdeviceref);
77  interop->DecrRef();
78  return -1;
79  }
80 
81  // Add our interop class and set the callback for its release
82  auto * hwframesctx = reinterpret_cast<AVHWFramesContext*>(Context->hw_frames_ctx->data);
83  hwframesctx->user_opaque = interop;
84  hwframesctx->free = &MythCodecContext::FramesContextFinished;
85 
86  // Initialise frames context
87  hwframesctx->sw_format = Context->sw_pix_fmt == AV_PIX_FMT_YUVJ420P ? AV_PIX_FMT_YUV420P : Context->sw_pix_fmt;
88  hwframesctx->format = AV_PIX_FMT_VDPAU;
89  hwframesctx->width = Context->coded_width;
90  hwframesctx->height = Context->coded_height;
91  int res = av_hwframe_ctx_init(Context->hw_frames_ctx);
92  if (res < 0)
93  {
94  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise VDPAU frames context");
95  av_buffer_unref(&hwdeviceref);
96  av_buffer_unref(&(Context->hw_frames_ctx));
97  return res;
98  }
99 
100  auto * vdpaudevicectx = static_cast<AVVDPAUDeviceContext*>(hwdevicecontext->hwctx);
101  if (av_vdpau_bind_context(Context, vdpaudevicectx->device,
102  vdpaudevicectx->get_proc_address, AV_HWACCEL_FLAG_IGNORE_LEVEL) != 0)
103  {
104  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to bind VDPAU context");
105  av_buffer_unref(&hwdeviceref);
106  av_buffer_unref(&(Context->hw_frames_ctx));
107  return -1;
108  }
109 
110  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU buffer pool created"));
111  av_buffer_unref(&hwdeviceref);
112 
114 
115  return 0;
116 }
117 
119  AVCodec ** /*Codec*/,
120  const QString &Decoder,
121  uint StreamType)
122 {
123  bool decodeonly = Decoder == "vdpau-dec";
124  auto success = static_cast<MythCodecID>((decodeonly ? kCodec_MPEG1_VDPAU_DEC : kCodec_MPEG1_VDPAU) + (StreamType - 1));
125  auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
126 
127  if (!Decoder.startsWith("vdpau") || qEnvironmentVariableIsSet("NO_VDPAU") || IsUnsupportedProfile(*Context))
128  return failure;
129 
130  if (!decodeonly)
131  if (!FrameTypeIsSupported(*Context, FMT_VDPAU))
132  return failure;
133 
134  QString codec = ff_codec_id_string((*Context)->codec_id);
135  QString profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
136  QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
137 
138  // VDPAU only supports 8bit 420p:(
140  bool vdpau = (type == FMT_YV12) && MythVDPAUHelper::HaveVDPAU() &&
141  (decodeonly ? codec_is_vdpau_dechw(success) : codec_is_vdpau_hw(success));
142 
143  if (vdpau)
144  {
145  MythCodecContext::CodecProfile mythprofile =
146  MythCodecContext::FFmpegToMythProfile((*Context)->codec_id, (*Context)->profile);
147  const VDPAUProfiles& profiles = MythVDPAUHelper::GetProfiles();
148  vdpau = false;
149  for (auto vdpauprofile : profiles)
150  {
151  bool match = vdpauprofile.first == mythprofile;
152  if (match)
153  {
154  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Trying %1")
155  .arg(MythCodecContext::GetProfileDescription(mythprofile, QSize())));
156  if (vdpauprofile.second.Supported((*Context)->width, (*Context)->height, (*Context)->level))
157  {
158  vdpau = true;
159  break;
160  }
161  }
162  }
163  }
164 
165  // H264 needs additional checks for old hardware
166  if (vdpau && (success == kCodec_H264_VDPAU || success == kCodec_H264_VDPAU_DEC))
167  {
168  vdpau = MythVDPAUHelper::CheckH264Decode(*Context);
169  if (!vdpau)
170  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "H264 decode check failed");
171  }
172 
173  QString desc = QString("'%1 %2 %3 %4x%5'")
174  .arg(codec, profile, pixfmt).arg((*Context)->width).arg((*Context)->height);
175 
176  if (!vdpau)
177  {
178  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU does not support decoding %1").arg(desc));
179  return failure;
180  }
181 
182  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU supports decoding %1").arg(desc));
183  (*Context)->pix_fmt = AV_PIX_FMT_VDPAU;
184  return success;
185 }
186 
188 enum AVPixelFormat MythVDPAUContext::GetFormat(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
189 {
190  while (*PixFmt != AV_PIX_FMT_NONE)
191  {
192  if (*PixFmt == AV_PIX_FMT_VDPAU)
193  if (MythCodecContext::InitialiseDecoder(Context, MythVDPAUContext::InitialiseContext, "VDPAU context creation") >= 0)
194  return AV_PIX_FMT_VDPAU;
195  PixFmt++;
196  }
197  return AV_PIX_FMT_NONE;
198 }
199 
201 enum AVPixelFormat MythVDPAUContext::GetFormat2(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
202 {
203  while (*PixFmt != AV_PIX_FMT_NONE)
204  {
205  if (*PixFmt == AV_PIX_FMT_VDPAU)
206  {
207  AVBufferRef *device = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VDPAU, nullptr);
208  if (device)
209  {
211  if (Context->sw_pix_fmt == AV_PIX_FMT_YUVJ420P)
212  Context->sw_pix_fmt = AV_PIX_FMT_YUV420P;
213  Context->hw_device_ctx = device;
214  return AV_PIX_FMT_VDPAU;
215  }
216  }
217  PixFmt++;
218  }
219  return AV_PIX_FMT_NONE;
220 }
221 
222 bool MythVDPAUContext::RetrieveFrame(AVCodecContext* /*unused*/, MythVideoFrame *Frame, AVFrame *AvFrame)
223 {
224  if (AvFrame->format != AV_PIX_FMT_VDPAU)
225  return false;
227  return RetrieveHWFrame(Frame, AvFrame);
228  return false;
229 }
230 
232 {
233  return m_codecID == kCodec_H264_VDPAU;
234 }
235 
237 {
239 }
240 
250 bool MythVDPAUContext::DecoderNeedsReset(AVCodecContext* Context)
251 {
252  if (m_resetRequired)
253  return true;
254 
256  return false;
257  if (!Context)
258  return false;
259  if (!Context->hw_frames_ctx)
260  return false;
261 
262  auto* hwframesctx = reinterpret_cast<AVHWFramesContext*>(Context->hw_frames_ctx->data);
263  auto* interop = reinterpret_cast<MythVDPAUInterop*>(hwframesctx->user_opaque);
264  if (interop && interop->IsPreempted())
265  {
266  m_resetRequired = true;
267  return true;
268  }
269  return false;
270 }
271 
272 void MythVDPAUContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
273 {
275  {
276  Context->get_buffer2 = MythCodecContext::GetBuffer;
277  Context->get_format = MythVDPAUContext::GetFormat;
278  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
279  return;
280  }
282  {
283  Context->get_format = MythVDPAUContext::GetFormat2;
284  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
285  DirectRendering = false;
286  return;
287  }
288 
289  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
290 }
MythVDPAUHelper::GetProfiles
static const VDPAUProfiles & GetProfiles(void)
Definition: mythvdpauhelper.cpp:120
MythVDPAUContext::DecoderWillResetOnAspect
bool DecoderWillResetOnAspect(void) override
Definition: mythvdpaucontext.cpp:236
MythCodecContext::m_codecID
MythCodecID m_codecID
Definition: mythcodeccontext.h:170
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:43
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:56
Frame
Definition: zmdefines.h:93
MythVDPAUInterop::CreateVDPAU
static MythVDPAUInterop * CreateVDPAU(MythPlayerUI *Player, MythRenderOpenGL *Context, MythCodecID CodecId)
Definition: mythvdpauinterop.cpp:9
MythCodecContext::NewHardwareFramesContext
static void NewHardwareFramesContext(void)
Track the number of concurrent frames contexts.
Definition: mythcodeccontext.cpp:428
MythVDPAUHelper::HaveVDPAU
static bool HaveVDPAU(bool Reinit=false)
Definition: mythvdpauhelper.cpp:53
MythCoreContext::IsUIThread
bool IsUIThread(void)
Definition: mythcorecontext.cpp:1360
MythCodecContext::InitVideoCodec
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
Definition: mythcodeccontext.cpp:302
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:435
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:188
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:680
kCodec_MPEG2_VDPAU
@ kCodec_MPEG2_VDPAU
Definition: mythcodecid.h:38
kCodec_MPEG1_VDPAU_DEC
@ kCodec_MPEG1_VDPAU_DEC
Definition: mythcodecid.h:53
MythCodecID
MythCodecID
Definition: mythcodecid.h:10
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
LOC
#define LOC
Definition: mythvdpaucontext.cpp:16
MythVDPAUContext::GetSupportedCodec
static MythCodecID GetSupportedCodec(AVCodecContext **CodecContext, AVCodec **Codec, const QString &Decoder, uint StreamType)
Definition: mythvdpaucontext.cpp:118
Decoder
Definition: decoder.h:70
kCodec_H264_VDPAU
@ kCodec_H264_VDPAU
Definition: mythcodecid.h:41
hardwareprofile.scan.profile
profile
Definition: scan.py:99
mythvdpauhelper.h
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:24
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:322
mythvdpaucontext.h
MythVDPAUInterop
Definition: mythvdpauinterop.h:25
MythCodecContext::RetrieveHWFrame
virtual bool RetrieveHWFrame(MythVideoFrame *Frame, AVFrame *AvFrame)
Definition: mythcodeccontext.cpp:625
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MythCodecContext::IsUnsupportedProfile
static bool IsUnsupportedProfile(AVCodecContext *Context)
Most hardware decoders do not support these codecs/profiles.
Definition: mythcodeccontext.cpp:595
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:70
MythRenderOpenGL
Definition: mythrenderopengl.h:99
codec_is_vdpau_hw
#define codec_is_vdpau_hw(id)
Definition: mythcodecid.h:300
MythVDPAUContext::RetrieveFrame
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
Definition: mythvdpaucontext.cpp:222
FMT_VDPAU
@ FMT_VDPAU
Definition: mythframe.h:57
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:201
MythCodecContext::CreateDevice
static AVBufferRef * CreateDevice(AVHWDeviceType Type, MythInteropGPU *Interop, const QString &Device=QString())
Definition: mythcodeccontext.cpp:556
avformatdecoder.h
MythCodecContext::FrameTypeIsSupported
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
Definition: mythcodeccontext.cpp:512
MythCodecContext::m_resetRequired
bool m_resetRequired
Definition: mythcodeccontext.h:171
MythVDPAUHelper::CheckH264Decode
static bool CheckH264Decode(AVCodecContext *Context)
Definition: mythvdpauhelper.cpp:348
MythVDPAUContext::DecoderWillResetOnFlush
bool DecoderWillResetOnFlush(void) override
Definition: mythvdpaucontext.cpp:231
MythCodecContext
Definition: mythcodeccontext.h:53
VideoFrameType
VideoFrameType
Definition: mythframe.h:20
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:783
MythVideoFrame
Definition: mythframe.h:88
MythVDPAUContext::DecoderNeedsReset
bool DecoderNeedsReset(AVCodecContext *Context) override
Report whether the decoder is known to be errored.
Definition: mythvdpaucontext.cpp:250
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:272
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:523
DecoderBase
Definition: decoderbase.h:120
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:503
kCodec_MPEG2_VDPAU_DEC
@ kCodec_MPEG2_VDPAU_DEC
Definition: mythcodecid.h:54
OpenGLLocker
Definition: mythrenderopengl.h:261