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