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 
8 // FFmpeg
9 extern "C" {
10 #include "libavutil/hwcontext_vdpau.h"
11 #include "libavutil/pixdesc.h"
12 #include "libavcodec/vdpau.h"
13 }
14 
15 #define LOC QString("VDPAUDec: ")
16 
24  : MythCodecContext(Parent, CodecID)
25 {
26 }
27 
30 {
31  if (!gCoreContext->IsUIThread() || !Context)
32  return -1;
33 
34  // We need a player to release the interop
35  MythPlayer *player = nullptr;
36  auto *decoder = reinterpret_cast<AvFormatDecoder*>(Context->opaque);
37  if (decoder)
38  player = decoder->GetPlayer();
39  if (!player)
40  return -1;
41 
42  // Retrieve OpenGL render context
44  if (!render)
45  return -1;
46  OpenGLLocker locker(render);
47 
48  // Check interop support
50  return -1;
51 
52  // Create interop
53  auto vdpauid = static_cast<MythCodecID>(kCodec_MPEG1_VDPAU + (mpeg_version(Context->codec_id) - 1));
54  MythVDPAUInterop *interop = MythVDPAUInterop::Create(render, vdpauid);
55  if (!interop)
56  return -1;
57 
58  // Set player
59  interop->SetPlayer(player);
60 
61  // Allocate the device context
62  AVBufferRef* hwdeviceref = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VDPAU, interop);
63  if (!hwdeviceref)
64  return -1;
65 
66  auto* hwdevicecontext = reinterpret_cast<AVHWDeviceContext*>(hwdeviceref->data);
67  if (!hwdevicecontext || (hwdevicecontext && !hwdevicecontext->hwctx))
68  return -1;
69 
70  // Initialise device context
71  if (av_hwdevice_ctx_init(hwdeviceref) < 0)
72  {
73  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise device context");
74  av_buffer_unref(&hwdeviceref);
75  interop->DecrRef();
76  return -1;
77  }
78 
79  // allocate the hardware frames context
80  Context->hw_frames_ctx = av_hwframe_ctx_alloc(hwdeviceref);
81  if (!Context->hw_frames_ctx)
82  {
83  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VDPAU hardware frames context");
84  av_buffer_unref(&hwdeviceref);
85  interop->DecrRef();
86  return -1;
87  }
88 
89  // Add our interop class and set the callback for its release
90  auto* hwframesctx = reinterpret_cast<AVHWFramesContext*>(Context->hw_frames_ctx->data);
91  hwframesctx->user_opaque = interop;
92  hwframesctx->free = &MythCodecContext::FramesContextFinished;
93 
94  // Initialise frames context
95  hwframesctx->sw_format = Context->sw_pix_fmt == AV_PIX_FMT_YUVJ420P ? AV_PIX_FMT_YUV420P : Context->sw_pix_fmt;
96  hwframesctx->format = AV_PIX_FMT_VDPAU;
97  hwframesctx->width = Context->coded_width;
98  hwframesctx->height = Context->coded_height;
99  int res = av_hwframe_ctx_init(Context->hw_frames_ctx);
100  if (res < 0)
101  {
102  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise VDPAU frames context");
103  av_buffer_unref(&hwdeviceref);
104  av_buffer_unref(&(Context->hw_frames_ctx));
105  return res;
106  }
107 
108  auto* vdpaudevicectx = static_cast<AVVDPAUDeviceContext*>(hwdevicecontext->hwctx);
109  if (av_vdpau_bind_context(Context, vdpaudevicectx->device,
110  vdpaudevicectx->get_proc_address, AV_HWACCEL_FLAG_IGNORE_LEVEL) != 0)
111  {
112  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to bind VDPAU context");
113  av_buffer_unref(&hwdeviceref);
114  av_buffer_unref(&(Context->hw_frames_ctx));
115  return -1;
116  }
117 
118  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU buffer pool created"));
119  av_buffer_unref(&hwdeviceref);
120 
122 
123  return 0;
124 }
125 
127  AVCodec ** /*Codec*/,
128  const QString &Decoder,
129  uint StreamType)
130 {
131  bool decodeonly = Decoder == "vdpau-dec";
132  auto success = static_cast<MythCodecID>((decodeonly ? kCodec_MPEG1_VDPAU_DEC : kCodec_MPEG1_VDPAU) + (StreamType - 1));
133  auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
134 
135  if (!Decoder.startsWith("vdpau") || getenv("NO_VDPAU") || IsUnsupportedProfile(*Context))
136  return failure;
137 
138  if (!decodeonly)
139  {
140  // If called from outside of the main thread, we need a MythPlayer instance to
141  // process the callback interop check callback - which may fail otherwise
142  MythPlayer* player = nullptr;
143  if (!gCoreContext->IsUIThread())
144  {
145  auto* decoder = reinterpret_cast<AvFormatDecoder*>((*Context)->opaque);
146  if (decoder)
147  player = decoder->GetPlayer();
148  }
149 
150  // direct rendering needs interop support
152  return failure;
153  }
154 
155  QString codec = ff_codec_id_string((*Context)->codec_id);
156  QString profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
157  QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
158 
159  // VDPAU only supports 8bit 420p:(
160  VideoFrameType type = PixelFormatToFrameType((*Context)->pix_fmt);
161  bool vdpau = (type == FMT_YV12) && MythVDPAUHelper::HaveVDPAU() &&
162  (decodeonly ? codec_is_vdpau_dechw(success) : codec_is_vdpau_hw(success));
163 
164  if (vdpau)
165  {
166  MythCodecContext::CodecProfile mythprofile =
167  MythCodecContext::FFmpegToMythProfile((*Context)->codec_id, (*Context)->profile);
168  const VDPAUProfiles& profiles = MythVDPAUHelper::GetProfiles();
169  vdpau = false;
170  for (auto vdpauprofile : profiles)
171  {
172  bool match = vdpauprofile.first == mythprofile;
173  if (match)
174  {
175  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Trying %1")
176  .arg(MythCodecContext::GetProfileDescription(mythprofile, QSize())));
177  if (vdpauprofile.second.Supported((*Context)->width, (*Context)->height, (*Context)->level))
178  {
179  vdpau = true;
180  break;
181  }
182  }
183  }
184  }
185 
186  // H264 needs additional checks for old hardware
187  if (vdpau && (success == kCodec_H264_VDPAU || success == kCodec_H264_VDPAU_DEC))
188  {
190  if (!vdpau)
191  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "H264 decode check failed");
192  }
193 
194  QString desc = QString("'%1 %2 %3 %4x%5'")
195  .arg(codec).arg(profile).arg(pixfmt).arg((*Context)->width).arg((*Context)->height);
196 
197  if (!vdpau)
198  {
199  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU does not support decoding %1").arg(desc));
200  return failure;
201  }
202 
203  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VDPAU supports decoding %1").arg(desc));
204  (*Context)->pix_fmt = AV_PIX_FMT_VDPAU;
205  return success;
206 }
207 
209 enum AVPixelFormat MythVDPAUContext::GetFormat(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
210 {
211  while (*PixFmt != AV_PIX_FMT_NONE)
212  {
213  if (*PixFmt == AV_PIX_FMT_VDPAU)
215  return AV_PIX_FMT_VDPAU;
216  PixFmt++;
217  }
218  return AV_PIX_FMT_NONE;
219 }
220 
222 enum AVPixelFormat MythVDPAUContext::GetFormat2(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
223 {
224  while (*PixFmt != AV_PIX_FMT_NONE)
225  {
226  if (*PixFmt == AV_PIX_FMT_VDPAU)
227  {
228  AVBufferRef *device = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VDPAU, nullptr);
229  if (device)
230  {
232  if (Context->sw_pix_fmt == AV_PIX_FMT_YUVJ420P)
233  Context->sw_pix_fmt = AV_PIX_FMT_YUV420P;
234  Context->hw_device_ctx = device;
235  return AV_PIX_FMT_VDPAU;
236  }
237  }
238  PixFmt++;
239  }
240  return AV_PIX_FMT_NONE;
241 }
242 
243 bool MythVDPAUContext::RetrieveFrame(AVCodecContext* /*unused*/, VideoFrame *Frame, AVFrame *AvFrame)
244 {
245  if (AvFrame->format != AV_PIX_FMT_VDPAU)
246  return false;
248  return RetrieveHWFrame(Frame, AvFrame);
249  return false;
250 }
251 
253 {
254  return m_codecID == kCodec_H264_VDPAU;
255 }
256 
258 {
260 }
261 
272 {
273  if (m_resetRequired)
274  return true;
275 
277  return false;
278  if (!Context)
279  return false;
280  if (!Context->hw_frames_ctx)
281  return false;
282 
283  auto* hwframesctx = reinterpret_cast<AVHWFramesContext*>(Context->hw_frames_ctx->data);
284  auto* interop = reinterpret_cast<MythVDPAUInterop*>(hwframesctx->user_opaque);
285  if (interop && interop->IsPreempted())
286  {
287  m_resetRequired = true;
288  return true;
289  }
290  return false;
291 }
292 
293 void MythVDPAUContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
294 {
296  {
297  Context->get_buffer2 = MythCodecContext::GetBuffer;
298  Context->get_format = MythVDPAUContext::GetFormat;
299  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
300  return;
301  }
303  {
305  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
306  DirectRendering = false;
307  return;
308  }
309 
310  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
311 }
MythVDPAUHelper::GetProfiles
static const VDPAUProfiles & GetProfiles(void)
Definition: mythvdpauhelper.cpp:120
MythVDPAUContext::DecoderWillResetOnAspect
bool DecoderWillResetOnAspect(void) override
Definition: mythvdpaucontext.cpp:257
MythCodecContext::m_codecID
MythCodecID m_codecID
Definition: mythcodeccontext.h:165
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
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:29
MythCodecContext::RetrieveHWFrame
virtual bool RetrieveHWFrame(VideoFrame *Frame, AVFrame *AvFrame)
Definition: mythcodeccontext.cpp:601
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:54
MythVDPAUContext::RetrieveFrame
bool RetrieveFrame(AVCodecContext *Context, VideoFrame *Frame, AVFrame *AvFrame) override
Definition: mythvdpaucontext.cpp:243
Frame
Definition: zmdefines.h:94
MythCodecContext::NewHardwareFramesContext
static void NewHardwareFramesContext(void)
Track the number of concurrent frames contexts.
Definition: mythcodeccontext.cpp:417
arg
arg(title).arg(filename).arg(doDelete))
PixelFormatToFrameType
VideoFrameType PixelFormatToFrameType(AVPixelFormat fmt)
Definition: mythavutil.cpp:69
MythCoreContext::IsUIThread
bool IsUIThread(void)
Definition: mythcorecontext.cpp:1356
MythOpenGLInterop::SetPlayer
void SetPlayer(MythPlayer *Player)
Definition: mythopenglinterop.cpp:280
Context
QHash< QString, Action * > Context
Definition: action.h:77
MythCodecContext::InitVideoCodec
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
Definition: mythcodeccontext.cpp:291
MythVDPAUContext::MythVDPAUContext
MythVDPAUContext(DecoderBase *Parent, MythCodecID CodecID)
Definition: mythvdpaucontext.cpp:23
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythCodecContext::FramesContextFinished
static void FramesContextFinished(AVHWFramesContext *Context)
Definition: mythcodeccontext.cpp:424
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:209
codec_is_vdpau_dec
#define codec_is_vdpau_dec(id)
Definition: mythcodecid.h:304
MythPlayer
Definition: mythplayer.h:165
VideoFrame
Definition: mythframe.h:138
MythCodecContext::FFmpegToMythProfile
static CodecProfile FFmpegToMythProfile(AVCodecID CodecID, int Profile)
Definition: mythcodeccontext.cpp:656
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:15
MythVDPAUContext::GetSupportedCodec
static MythCodecID GetSupportedCodec(AVCodecContext **CodecContext, AVCodec **Codec, const QString &Decoder, uint StreamType)
Definition: mythvdpaucontext.cpp:126
Decoder
Definition: decoder.h:66
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:28
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:311
mythvdpaucontext.h
MythVDPAUInterop
Definition: mythvdpauinterop.h:26
AvFormatDecoder
A decoder for video files.
Definition: avformatdecoder.h:89
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MythCodecContext::IsUnsupportedProfile
static bool IsUnsupportedProfile(AVCodecContext *Context)
Most hardware decoders do not support these codecs/profiles.
Definition: mythcodeccontext.cpp:571
MythRenderOpenGL
Definition: mythrenderopengl.h:95
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:532
FMT_VDPAU
@ FMT_VDPAU
Definition: mythframe.h:61
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:222
avformatdecoder.h
MythRenderOpenGL::GetOpenGLRender
static MythRenderOpenGL * GetOpenGLRender(void)
Definition: mythrenderopengl.cpp:63
MythCodecContext::m_resetRequired
bool m_resetRequired
Definition: mythcodeccontext.h:166
MythVDPAUHelper::CheckH264Decode
static bool CheckH264Decode(AVCodecContext *Context)
Definition: mythvdpauhelper.cpp:340
MythVDPAUContext::DecoderWillResetOnFlush
bool DecoderWillResetOnFlush(void) override
Definition: mythvdpaucontext.cpp:252
MythCodecContext
Definition: mythcodeccontext.h:51
VideoFrameType
VideoFrameType
Definition: mythframe.h:25
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:759
VDPAUProfiles
QList< VDPAUProfile > VDPAUProfiles
Definition: mythvdpauhelper.h:36
MythVDPAUContext::DecoderNeedsReset
bool DecoderNeedsReset(AVCodecContext *Context) override
Report whether the decoder is known to be errored.
Definition: mythvdpaucontext.cpp:271
kCodec_H264_VDPAU_DEC
@ kCodec_H264_VDPAU_DEC
Definition: mythcodecid.h:57
MythOpenGLInterop::GetInteropType
static Type GetInteropType(VideoFrameType Format, MythPlayer *Player)
Check whether we support direct rendering for the given VideoFrameType.
Definition: mythopenglinterop.cpp:77
kCodec_MPEG1_VDPAU
@ kCodec_MPEG1_VDPAU
Definition: mythcodecid.h:37
MythVDPAUContext::InitVideoCodec
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
Definition: mythvdpaucontext.cpp:293
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:493
DecoderBase
Definition: decoderbase.h:120
kCodec_MPEG2_VDPAU_DEC
@ kCodec_MPEG2_VDPAU_DEC
Definition: mythcodecid.h:54
OpenGLLocker
Definition: mythrenderopengl.h:253