MythTV  master
mythvtbcontext.cpp
Go to the documentation of this file.
1 // Mythtv
2 #include "mythmainwindow.h"
3 #include "mythlogging.h"
4 #include "mythcodecid.h"
5 #include "mythframe.h"
6 #include "avformatdecoder.h"
8 #include "videobuffers.h"
9 #include "mythvtbinterop.h"
10 #include "mythplayerui.h"
11 #include "mythvtbcontext.h"
12 
13 // FFmpeg
14 extern "C" {
15 #include "libavutil/hwcontext_videotoolbox.h"
16 #include "libavcodec/videotoolbox.h"
17 #include "libavutil/pixdesc.h"
18 }
19 
20 #define LOC QString("VTBDec: ")
21 
23  : MythCodecContext(Parent, CodecID)
24 {
25 }
26 
28 {
29  av_buffer_unref(&m_framesContext);
30 }
31 
32 void MythVTBContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
33 {
35  {
36  Context->get_format = MythVTBContext::GetFormat;
37  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
38  DirectRendering = false;
39  return;
40  }
41 
42  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
43 }
44 
45 bool MythVTBContext::RetrieveFrame(AVCodecContext* Context, MythVideoFrame* Frame, AVFrame* AvFrame)
46 {
47  if (AvFrame->format != AV_PIX_FMT_VIDEOTOOLBOX)
48  return false;
50  return RetrieveHWFrame(Frame, AvFrame);
52  return GetBuffer2(Context, Frame, AvFrame, 0);
53  return false;
54 }
55 
56 int MythVTBContext::HwDecoderInit(AVCodecContext *Context)
57 {
59  {
60  AVBufferRef *device = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VIDEOTOOLBOX, nullptr);
61  if (device)
62  {
63  Context->hw_device_ctx = device;
64  return 0;
65  }
66  }
67  else if (codec_is_vtb(m_codecID))
68  {
69  return MythCodecContext::InitialiseDecoder2(Context, MythVTBContext::InitialiseDecoder, "Create VTB decoder");
70  }
71 
72  return -1;
73 }
74 
76  AVCodec ** Codec,
77  const QString &Decoder,
78  uint StreamType)
79 {
80  bool decodeonly = Decoder == "vtb-dec";
81  auto success = static_cast<MythCodecID>((decodeonly ? kCodec_MPEG1_VTB_DEC : kCodec_MPEG1_VTB) + (StreamType - 1));
82  auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
83 
84  if (!Decoder.startsWith("vtb") || IsUnsupportedProfile(*Context))
85  return failure;
86 
87  if (!decodeonly)
88  if (!FrameTypeIsSupported(*Context, FMT_VTB))
89  return failure;
90 
91  // Check decoder support
93  switch ((*Codec)->id)
94  {
95  case AV_CODEC_ID_MPEG1VIDEO: mythprofile = MythCodecContext::MPEG1; break;
96  case AV_CODEC_ID_MPEG2VIDEO: mythprofile = MythCodecContext::MPEG2; break;
97  case AV_CODEC_ID_MPEG4: mythprofile = MythCodecContext::MPEG4; break;
98  case AV_CODEC_ID_H263: mythprofile = MythCodecContext::H263; break;
99  case AV_CODEC_ID_H264: mythprofile = MythCodecContext::H264; break;
100  case AV_CODEC_ID_VC1: mythprofile = MythCodecContext::VC1; break;
101  case AV_CODEC_ID_VP8: mythprofile = MythCodecContext::VP8; break;
102  case AV_CODEC_ID_VP9: mythprofile = MythCodecContext::VP9; break;
103  case AV_CODEC_ID_HEVC: mythprofile = MythCodecContext::HEVC; break;
104  default: break;
105  }
106 
107  if (mythprofile == MythCodecContext::NoProfile)
108  return failure;
109 
110  QString codec = ff_codec_id_string((*Context)->codec_id);
111  QString profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
112  QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
113 
114  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
115  if (!profiles.contains(mythprofile))
116  {
117  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VideoToolbox does not support decoding '%1 %2 %3'")
118  .arg(codec).arg(profile).arg(pixfmt));
119  return failure;
120  }
121 
122  // There is no guarantee (and no obvious way to check) whether the given
123  // profile is actually supported.
124  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VideoToolbox MAY support decoding '%1 %2 %3'")
125  .arg(codec).arg(profile).arg(pixfmt));
126  (*Context)->pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX;
127  return success;
128 }
129 
130 int MythVTBContext::InitialiseDecoder(AVCodecContext *Context)
131 {
132  if (!gCoreContext->IsUIThread())
133  return -1;
134 
135  // The interop must have a reference to the ui player so it can be deleted
136  // from the main thread.
137  auto * player = GetPlayerUI(Context);
138  if (!player)
139  return -1;
140 
141  // Retrieve OpenGL render context
142  auto * render = dynamic_cast<MythRenderOpenGL*>(player->GetRender());
143  if (!render)
144  return -1;
145  OpenGLLocker locker(render);
146 
147  // Create interop
148  auto * interop = MythVTBInterop::CreateVTB(player, render);
149  if (!interop)
150  return -1;
151 
152  // Allocate the device context
153  auto * deviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VIDEOTOOLBOX);
154  if (!deviceref)
155  {
156  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create device context");
157  interop->DecrRef();
158  return -1;
159  }
160 
161  // Add our interop class and set the callback for its release
162  auto * devicectx = reinterpret_cast<AVHWDeviceContext*>(deviceref->data);
163  devicectx->user_opaque = interop;
164  devicectx->free = MythCodecContext::DeviceContextFinished;
165 
166  // Create
167  if (av_hwdevice_ctx_init(deviceref) < 0)
168  {
169  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise device context");
170  av_buffer_unref(&deviceref);
171  return -1;
172  }
173 
174  Context->hw_device_ctx = deviceref;
175  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created hw device '%1'")
176  .arg(av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_VIDEOTOOLBOX)));
177  return 0;
178 }
179 
180 enum AVPixelFormat MythVTBContext::GetFormat(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
181 {
182  enum AVPixelFormat ret = AV_PIX_FMT_NONE;
183  while (*PixFmt != AV_PIX_FMT_NONE)
184  {
185  if (*PixFmt == AV_PIX_FMT_VIDEOTOOLBOX)
186  {
187  auto* decoder = reinterpret_cast<AvFormatDecoder*>(Context->opaque);
188  if (decoder)
189  {
190  auto* me = dynamic_cast<MythVTBContext*>(decoder->GetMythCodecContext());
191  if (me)
192  me->InitFramesContext(Context);
193  }
194  return *PixFmt;
195  }
196  PixFmt++;
197  }
198  return ret;
199 }
200 
202 {
203 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
204  static QMutex lock(QMutex::Recursive);
205 #else
206  static QRecursiveMutex lock;
207 #endif
208  static bool s_initialised = false;
209  static VTBProfiles s_profiles;
210 
211  QMutexLocker locker(&lock);
212  if (s_initialised)
213  return s_profiles;
214  s_initialised = true;
215 
216  if (__builtin_available(macOS 10.13, *))
217  {
218  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG1Video)) { s_profiles.append(MythCodecContext::MPEG1); }
219  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG2Video)) { s_profiles.append(MythCodecContext::MPEG2); }
220  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_H263)) { s_profiles.append(MythCodecContext::H263); }
221  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG4Video)) { s_profiles.append(MythCodecContext::MPEG4); }
222  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_H264)) { s_profiles.append(MythCodecContext::H264); }
223  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { s_profiles.append(MythCodecContext::HEVC); }
224  }
225  else
226  {
227  LOG(VB_GENERAL, LOG_INFO, LOC + "Unable to check hardware decode support. Assuming all.");
228  s_profiles.append(MythCodecContext::MPEG1);
229  s_profiles.append(MythCodecContext::MPEG2);
230  s_profiles.append(MythCodecContext::H263);
231  s_profiles.append(MythCodecContext::MPEG4);
232  s_profiles.append(MythCodecContext::H264);
233  s_profiles.append(MythCodecContext::HEVC);
234  }
235 
236  return s_profiles;
237 }
238 
239 bool MythVTBContext::HaveVTB(bool Reinit /*=false*/)
240 {
241 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
242  static QMutex lock(QMutex::Recursive);
243 #else
244  static QRecursiveMutex lock;
245 #endif
246  QMutexLocker locker(&lock);
247  static bool s_checked = false;
248  static bool s_available = false;
249  if (!s_checked || Reinit)
250  {
251  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
252  if (profiles.empty())
253  {
254  LOG(VB_GENERAL, LOG_INFO, LOC + "No VideoToolbox decoders found");
255  }
256  else
257  {
258  s_available = true;
259  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available VideoToolbox decoders:");
260  QSize size{0, 0};
261  for (auto profile : profiles)
262  {
263  LOG(VB_GENERAL, LOG_INFO, LOC +
265  }
266  }
267  }
268  s_checked = true;
269  return s_available;
270 }
271 
272 void MythVTBContext::GetDecoderList(QStringList &Decoders)
273 {
274  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
275  if (profiles.isEmpty())
276  return;
277 
278  QSize size(0, 0);
279  Decoders.append("VideoToolbox:");
280  for (MythCodecContext::CodecProfile profile : profiles)
281  Decoders.append(MythCodecContext::GetProfileDescription(profile, size));
282 }
283 
306 void MythVTBContext::InitFramesContext(AVCodecContext *Context)
307 {
308  if (!Context)
309  return;
310 
311  AVPixelFormat format = AV_PIX_FMT_NV12;
313  format = AV_PIX_FMT_P010;
314 
315  if (m_framesContext)
316  {
317  auto *frames = reinterpret_cast<AVHWFramesContext*>(m_framesContext->data);
318  if ((frames->sw_format == format) && (frames->width == Context->coded_width) &&
319  (frames->height == Context->coded_height))
320  {
321  Context->hw_frames_ctx = av_buffer_ref(m_framesContext);
322  return;
323  }
324  }
325 
326  // If this is a 'spontaneous' callback from FFmpeg (i.e. not on a stream change)
327  // then we must release any direct render buffers.
329  m_parent->GetPlayer()->DiscardVideoFrames(true, true);
330 
331  av_videotoolbox_default_free(Context);
332  av_buffer_unref(&m_framesContext);
333 
334  AVBufferRef* framesref = av_hwframe_ctx_alloc(Context->hw_device_ctx);
335  auto *frames = reinterpret_cast<AVHWFramesContext*>(framesref->data);
337  frames->user_opaque = nullptr;
338  frames->sw_format = format;
339  frames->format = AV_PIX_FMT_VIDEOTOOLBOX;
340  frames->width = Context->coded_width;
341  frames->height = Context->coded_height;
342  if (av_hwframe_ctx_init(framesref) < 0)
343  {
344  av_buffer_unref(&framesref);
345  }
346  else
347  {
348  Context->hw_frames_ctx = framesref;
349  m_framesContext = av_buffer_ref(framesref);
351  }
352 }
mythvtbcontext.h
MythCodecContext::m_codecID
MythCodecID m_codecID
Definition: mythcodeccontext.h:170
MythVTBContext::MythVTBContext
MythVTBContext(DecoderBase *Parent, MythCodecID CodecID)
Definition: mythvtbcontext.cpp:22
mythplayerui.h
MythVTBContext::InitialiseDecoder
static int InitialiseDecoder(AVCodecContext *Context)
Definition: mythvtbcontext.cpp:130
FMT_VTB
@ FMT_VTB
Definition: mythframe.h:62
MythVTBContext::m_framesContext
AVBufferRef * m_framesContext
Definition: mythvtbcontext.h:42
MythCodecContext::NoProfile
@ NoProfile
Definition: mythcodeccontext.h:58
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:56
Frame
Definition: zmdefines.h:93
MythCodecContext::NewHardwareFramesContext
static void NewHardwareFramesContext(void)
Track the number of concurrent frames contexts.
Definition: mythcodeccontext.cpp:428
MythCoreContext::IsUIThread
bool IsUIThread(void)
Definition: mythcorecontext.cpp:1360
MythCodecContext::InitVideoCodec
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
Definition: mythcodeccontext.cpp:302
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythCodecContext::FramesContextFinished
static void FramesContextFinished(AVHWFramesContext *Context)
Definition: mythcodeccontext.cpp:435
mythframe.h
MythVTBContext::~MythVTBContext
~MythVTBContext() override
Definition: mythvtbcontext.cpp:27
MythVTBContext::GetDecoderList
static void GetDecoderList(QStringList &Decoders)
Definition: mythvtbcontext.cpp:272
MythPlayer::DiscardVideoFrames
void DiscardVideoFrames(bool KeyFrame, bool Flushed)
Places frames in the available frames queue.
Definition: mythplayer.cpp:637
MythVTBInterop::CreateVTB
static MythVTBInterop * CreateVTB(MythPlayerUI *Player, MythRenderOpenGL *Context)
Definition: mythvtbinterop.cpp:20
MythVTBContext
Definition: mythvtbcontext.h:17
videobuffers.h
MythCodecID
MythCodecID
Definition: mythcodecid.h:10
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
mythrenderopengl.h
Decoder
Definition: decoder.h:70
mythlogging.h
MythCodecContext::DeviceContextFinished
static void DeviceContextFinished(AVHWDeviceContext *Context)
Definition: mythcodeccontext.cpp:445
hardwareprofile.scan.profile
profile
Definition: scan.py:99
LOC
#define LOC
Definition: mythvtbcontext.cpp:20
kCodec_MPEG1
@ kCodec_MPEG1
Definition: mythcodecid.h:21
MythCodecContext::VP9
@ VP9
Definition: mythcodeccontext.h:109
mythcodecid.h
MythCodecContext::MPEG4
@ MPEG4
Definition: mythcodeccontext.h:67
MythVTBContext::GetFormat
static enum AVPixelFormat GetFormat(AVCodecContext *Context, const enum AVPixelFormat *PixFmt)
Definition: mythvtbcontext.cpp:180
MythVideoFrame::ColorDepth
static int ColorDepth(int Format)
Definition: mythframe.h:399
MythCodecContext::MPEG1
@ MPEG1
Definition: mythcodeccontext.h:59
MythCodecContext::HEVC
@ HEVC
Definition: mythcodeccontext.h:96
MythCodecContext::RetrieveHWFrame
virtual bool RetrieveHWFrame(MythVideoFrame *Frame, AVFrame *AvFrame)
Definition: mythcodeccontext.cpp:625
mythvtbinterop.h
AvFormatDecoder
A decoder for media files.
Definition: avformatdecoder.h:85
MythCodecContext::H263
@ H263
Definition: mythcodeccontext.h:84
uint
unsigned int uint
Definition: compat.h:140
MythCodecContext::m_parent
DecoderBase * m_parent
Definition: mythcodeccontext.h:169
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
MythCodecContext::MPEG2
@ MPEG2
Definition: mythcodeccontext.h:60
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:70
MythRenderOpenGL
Definition: mythrenderopengl.h:99
MythVTBContext::GetSupportedCodec
static MythCodecID GetSupportedCodec(AVCodecContext **Context, AVCodec **Codec, const QString &Decoder, uint StreamType)
Definition: mythvtbcontext.cpp:75
MythCodecContext::VC1
@ VC1
Definition: mythcodeccontext.h:103
kCodec_MPEG1_VTB_DEC
@ kCodec_MPEG1_VTB_DEC
Definition: mythcodecid.h:197
MythCodecContext::CreateDevice
static AVBufferRef * CreateDevice(AVHWDeviceType Type, MythInteropGPU *Interop, const QString &Device=QString())
Definition: mythcodeccontext.cpp:556
avformatdecoder.h
kCodec_MPEG1_VTB
@ kCodec_MPEG1_VTB
Definition: mythcodecid.h:181
MythCodecContext::FrameTypeIsSupported
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
Definition: mythcodeccontext.cpp:512
MythVTBContext::GetProfiles
static const VTBProfiles & GetProfiles(void)
Definition: mythvtbcontext.cpp:201
MythCodecContext::InitialiseDecoder2
static int InitialiseDecoder2(AVCodecContext *Context, CreateHWDecoder Callback, const QString &Debug)
Initialise a hardware decoder that is NOT expected to use AVHWFramesContext.
Definition: mythcodeccontext.cpp:540
MythVTBContext::InitVideoCodec
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
Definition: mythvtbcontext.cpp:32
MythVTBContext::InitFramesContext
void InitFramesContext(AVCodecContext *Context)
Create a hardware frames context if needed.
Definition: mythvtbcontext.cpp:306
MythCodecContext
Definition: mythcodeccontext.h:53
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:783
codec_is_vtb
#define codec_is_vtb(id)
Definition: mythcodecid.h:333
MythVTBContext::HwDecoderInit
int HwDecoderInit(AVCodecContext *Context) override
Definition: mythvtbcontext.cpp:56
MythVideoFrame
Definition: mythframe.h:88
MythVTBContext::RetrieveFrame
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
Definition: mythvtbcontext.cpp:45
mythmainwindow.h
VTBProfiles
QList< MythCodecContext::CodecProfile > VTBProfiles
Definition: mythvtbcontext.h:15
codec_is_vtb_dec
#define codec_is_vtb_dec(id)
Definition: mythcodecid.h:335
DecoderBase
Definition: decoderbase.h:120
MythCodecContext::GetBuffer2
static bool GetBuffer2(struct AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int Flags)
A generic hardware buffer initialisation method when AVHWFramesContext is NOT used.
Definition: mythcodeccontext.cpp:373
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:503
MythCodecContext::VP8
@ VP8
Definition: mythcodeccontext.h:108
DecoderBase::GetPlayer
MythPlayer * GetPlayer()
Definition: decoderbase.h:152
MythVTBContext::HaveVTB
static bool HaveVTB(bool Reinit=false)
Definition: mythvtbcontext.cpp:239
MythCodecContext::H264
@ H264
Definition: mythcodeccontext.h:85
OpenGLLocker
Definition: mythrenderopengl.h:261