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 
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 
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  {
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  {
89  // check for the correct player type and interop supprt
90  MythPlayerUI* player = GetPlayerUI(*Context);
92  return failure;
93  }
94 
95  // Check decoder support
97  switch ((*Codec)->id)
98  {
99  case AV_CODEC_ID_MPEG1VIDEO: mythprofile = MythCodecContext::MPEG1; break;
100  case AV_CODEC_ID_MPEG2VIDEO: mythprofile = MythCodecContext::MPEG2; break;
101  case AV_CODEC_ID_MPEG4: mythprofile = MythCodecContext::MPEG4; break;
102  case AV_CODEC_ID_H263: mythprofile = MythCodecContext::H263; break;
103  case AV_CODEC_ID_H264: mythprofile = MythCodecContext::H264; break;
104  case AV_CODEC_ID_VC1: mythprofile = MythCodecContext::VC1; break;
105  case AV_CODEC_ID_VP8: mythprofile = MythCodecContext::VP8; break;
106  case AV_CODEC_ID_VP9: mythprofile = MythCodecContext::VP9; break;
107  case AV_CODEC_ID_HEVC: mythprofile = MythCodecContext::HEVC; break;
108  default: break;
109  }
110 
111  if (mythprofile == MythCodecContext::NoProfile)
112  return failure;
113 
114  QString codec = ff_codec_id_string((*Context)->codec_id);
115  QString profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
116  QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
117 
118  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
119  if (!profiles.contains(mythprofile))
120  {
121  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VideoToolbox does not support decoding '%1 %2 %3'")
122  .arg(codec).arg(profile).arg(pixfmt));
123  return failure;
124  }
125 
126  // There is no guarantee (and no obvious way to check) whether the given
127  // profile is actually supported.
128  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VideoToolbox MAY support decoding '%1 %2 %3'")
129  .arg(codec).arg(profile).arg(pixfmt));
130  (*Context)->pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX;
131  return success;
132 }
133 
135 {
136  if (!gCoreContext->IsUIThread())
137  return -1;
138 
139  // Retrieve OpenGL render context
141  if (!render)
142  return -1;
143  OpenGLLocker locker(render);
144 
145  // The interop must have a reference to the ui player so it can be deleted
146  // from the main thread.
147  MythPlayerUI* player = GetPlayerUI(Context);
148  if (!player)
149  return -1;
150 
151  // Check interop support
154  return -1;
155 
156  // Create interop
157  MythVTBInterop* interop = MythVTBInterop::Create(render, type);
158  if (!interop)
159  return -1;
160 
161  // Set player
162  interop->SetPlayer(player);
163 
164  // Allocate the device context
165  AVBufferRef* deviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VIDEOTOOLBOX);
166  if (!deviceref)
167  {
168  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create device context");
169  interop->DecrRef();
170  return -1;
171  }
172 
173  // Add our interop class and set the callback for its release
174  auto* devicectx = reinterpret_cast<AVHWDeviceContext*>(deviceref->data);
175  devicectx->user_opaque = interop;
176  devicectx->free = MythCodecContext::DeviceContextFinished;
177 
178  // Create
179  if (av_hwdevice_ctx_init(deviceref) < 0)
180  {
181  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise device context");
182  av_buffer_unref(&deviceref);
183  return -1;
184  }
185 
186  Context->hw_device_ctx = deviceref;
187  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created hw device '%1'")
188  .arg(av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_VIDEOTOOLBOX)));
189  return 0;
190 }
191 
192 enum AVPixelFormat MythVTBContext::GetFormat(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
193 {
194  enum AVPixelFormat ret = AV_PIX_FMT_NONE;
195  while (*PixFmt != AV_PIX_FMT_NONE)
196  {
197  if (*PixFmt == AV_PIX_FMT_VIDEOTOOLBOX)
198  {
199  auto* decoder = reinterpret_cast<AvFormatDecoder*>(Context->opaque);
200  if (decoder)
201  {
202  auto* me = dynamic_cast<MythVTBContext*>(decoder->GetMythCodecContext());
203  if (me)
205  }
206  return *PixFmt;
207  }
208  PixFmt++;
209  }
210  return ret;
211 }
212 
214 {
215  static QMutex lock(QMutex::Recursive);
216  static bool s_initialised = false;
217  static VTBProfiles s_profiles;
218 
219  QMutexLocker locker(&lock);
220  if (s_initialised)
221  return s_profiles;
222  s_initialised = true;
223 
224  if (__builtin_available(macOS 10.13, *))
225  {
226  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG1Video)) { s_profiles.append(MythCodecContext::MPEG1); }
227  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG2Video)) { s_profiles.append(MythCodecContext::MPEG2); }
228  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_H263)) { s_profiles.append(MythCodecContext::H263); }
229  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG4Video)) { s_profiles.append(MythCodecContext::MPEG4); }
230  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_H264)) { s_profiles.append(MythCodecContext::H264); }
231  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { s_profiles.append(MythCodecContext::HEVC); }
232  }
233  else
234  {
235  LOG(VB_GENERAL, LOG_INFO, LOC + "Unable to check hardware decode support. Assuming all.");
236  s_profiles.append(MythCodecContext::MPEG1);
237  s_profiles.append(MythCodecContext::MPEG2);
238  s_profiles.append(MythCodecContext::H263);
239  s_profiles.append(MythCodecContext::MPEG4);
240  s_profiles.append(MythCodecContext::H264);
241  s_profiles.append(MythCodecContext::HEVC);
242  }
243 
244  return s_profiles;
245 }
246 
248 {
249  static QMutex lock(QMutex::Recursive);
250  QMutexLocker locker(&lock);
251  static bool s_checked = false;
252  static bool s_available = false;
253  if (!s_checked)
254  {
255  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
256  if (profiles.empty())
257  {
258  LOG(VB_GENERAL, LOG_INFO, LOC + "No VideoToolbox decoders found");
259  }
260  else
261  {
262  s_available = true;
263  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available VideoToolbox decoders:");
264  QSize size{0, 0};
265  for (auto profile : profiles)
266  {
267  LOG(VB_GENERAL, LOG_INFO, LOC +
269  }
270  }
271  }
272  s_checked = true;
273  return s_available;
274 }
275 
276 void MythVTBContext::GetDecoderList(QStringList &Decoders)
277 {
278  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
279  if (profiles.isEmpty())
280  return;
281 
282  QSize size(0, 0);
283  Decoders.append("VideoToolbox:");
284  for (MythCodecContext::CodecProfile profile : profiles)
285  Decoders.append(MythCodecContext::GetProfileDescription(profile, size));
286 }
287 
311 {
312  if (!Context)
313  return;
314 
315  AVPixelFormat format = AV_PIX_FMT_NV12;
317  format = AV_PIX_FMT_P010;
318 
319  if (m_framesContext)
320  {
321  auto *frames = reinterpret_cast<AVHWFramesContext*>(m_framesContext->data);
322  if ((frames->sw_format == format) && (frames->width == Context->coded_width) &&
323  (frames->height == Context->coded_height))
324  {
325  Context->hw_frames_ctx = av_buffer_ref(m_framesContext);
326  return;
327  }
328  }
329 
330  // If this is a 'spontaneous' callback from FFmpeg (i.e. not on a stream change)
331  // then we must release any direct render buffers.
333  m_parent->GetPlayer()->DiscardVideoFrames(true, true);
334 
335  av_videotoolbox_default_free(Context);
336  av_buffer_unref(&m_framesContext);
337 
338  AVBufferRef* framesref = av_hwframe_ctx_alloc(Context->hw_device_ctx);
339  auto *frames = reinterpret_cast<AVHWFramesContext*>(framesref->data);
341  frames->user_opaque = nullptr;
342  frames->sw_format = format;
343  frames->format = AV_PIX_FMT_VIDEOTOOLBOX;
344  frames->width = Context->coded_width;
345  frames->height = Context->coded_height;
346  if (av_hwframe_ctx_init(framesref) < 0)
347  {
348  av_buffer_unref(&framesref);
349  }
350  else
351  {
352  Context->hw_frames_ctx = framesref;
353  m_framesContext = av_buffer_ref(framesref);
355  }
356 }
mythvtbcontext.h
MythCodecContext::m_codecID
MythCodecID m_codecID
Definition: mythcodeccontext.h:167
MythVTBContext::MythVTBContext
MythVTBContext(DecoderBase *Parent, MythCodecID CodecID)
Definition: mythvtbcontext.cpp:22
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
mythplayerui.h
MythVTBContext::InitialiseDecoder
static int InitialiseDecoder(AVCodecContext *Context)
Definition: mythvtbcontext.cpp:134
FMT_VTB
@ FMT_VTB
Definition: mythframe.h:57
MythVTBContext::m_framesContext
AVBufferRef * m_framesContext
Definition: mythvtbcontext.h:42
MythCodecContext::NoProfile
@ NoProfile
Definition: mythcodeccontext.h:56
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
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythCodecContext::FramesContextFinished
static void FramesContextFinished(AVHWFramesContext *Context)
Definition: mythcodeccontext.cpp:425
mythframe.h
MythVTBContext::~MythVTBContext
~MythVTBContext() override
Definition: mythvtbcontext.cpp:27
MythVTBContext::GetDecoderList
static void GetDecoderList(QStringList &Decoders)
Definition: mythvtbcontext.cpp:276
MythPlayer::DiscardVideoFrames
void DiscardVideoFrames(bool KeyFrame, bool Flushed)
Places frames in the available frames queue.
Definition: mythplayer.cpp:741
MythVTBContext
Definition: mythvtbcontext.h:18
videobuffers.h
MythCodecID
MythCodecID
Definition: mythcodecid.h:11
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
mythrenderopengl.h
MythPlayerUI
Definition: mythplayerui.h:12
Decoder
Definition: decoder.h:66
MythOpenGLInterop::SetPlayer
void SetPlayer(MythPlayerUI *Player)
Definition: mythopenglinterop.cpp:278
mythlogging.h
MythCodecContext::DeviceContextFinished
static void DeviceContextFinished(AVHWDeviceContext *Context)
Definition: mythcodeccontext.cpp:435
hardwareprofile.scan.profile
profile
Definition: scan.py:99
MythOpenGLInterop::Unsupported
@ Unsupported
Definition: mythopenglinterop.h:31
LOC
#define LOC
Definition: mythvtbcontext.cpp:20
kCodec_MPEG1
@ kCodec_MPEG1
Definition: mythcodecid.h:21
MythCodecContext::VP9
@ VP9
Definition: mythcodeccontext.h:107
MythOpenGLInterop::GetInteropType
static Type GetInteropType(VideoFrameType Format, MythPlayerUI *Player)
Check whether we support direct rendering for the given VideoFrameType.
Definition: mythopenglinterop.cpp:74
MythVTBContext::HaveVTB
static bool HaveVTB(void)
Definition: mythvtbcontext.cpp:247
mythcodecid.h
MythCodecContext::MPEG4
@ MPEG4
Definition: mythcodeccontext.h:65
MythVTBContext::GetFormat
static enum AVPixelFormat GetFormat(AVCodecContext *Context, const enum AVPixelFormat *PixFmt)
Definition: mythvtbcontext.cpp:192
MythVideoFrame::ColorDepth
static int ColorDepth(int Format)
Definition: mythframe.h:382
MythCodecContext::MPEG1
@ MPEG1
Definition: mythcodeccontext.h:57
MythCodecContext::HEVC
@ HEVC
Definition: mythcodeccontext.h:94
MythCodecContext::RetrieveHWFrame
virtual bool RetrieveHWFrame(MythVideoFrame *Frame, AVFrame *AvFrame)
Definition: mythcodeccontext.cpp:605
mythvtbinterop.h
AvFormatDecoder
A decoder for media files.
Definition: avformatdecoder.h:87
MythCodecContext::H263
@ H263
Definition: mythcodeccontext.h:82
uint
unsigned int uint
Definition: compat.h:140
MythCodecContext::m_parent
DecoderBase * m_parent
Definition: mythcodeccontext.h:166
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:56
MythOpenGLInterop::Type
Type
Definition: mythopenglinterop.h:30
MythCodecContext::IsUnsupportedProfile
static bool IsUnsupportedProfile(AVCodecContext *Context)
Most hardware decoders do not support these codecs/profiles.
Definition: mythcodeccontext.cpp:575
MythCodecContext::MPEG2
@ MPEG2
Definition: mythcodeccontext.h:58
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:73
MythRenderOpenGL
Definition: mythrenderopengl.h:98
MythVTBContext::GetSupportedCodec
static MythCodecID GetSupportedCodec(AVCodecContext **Context, AVCodec **Codec, const QString &Decoder, uint StreamType)
Definition: mythvtbcontext.cpp:75
MythCodecContext::CreateDevice
static AVBufferRef * CreateDevice(AVHWDeviceType Type, MythOpenGLInterop *Interop, const QString &Device=QString())
Definition: mythcodeccontext.cpp:536
MythCodecContext::VC1
@ VC1
Definition: mythcodeccontext.h:101
kCodec_MPEG1_VTB_DEC
@ kCodec_MPEG1_VTB_DEC
Definition: mythcodecid.h:197
avformatdecoder.h
kCodec_MPEG1_VTB
@ kCodec_MPEG1_VTB
Definition: mythcodecid.h:181
MythRenderOpenGL::GetOpenGLRender
static MythRenderOpenGL * GetOpenGLRender(void)
Definition: mythrenderopengl.cpp:66
MythVTBContext::GetProfiles
static const VTBProfiles & GetProfiles(void)
Definition: mythvtbcontext.cpp:213
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:520
MythVTBInterop::Create
static MythVTBInterop * Create(MythRenderOpenGL *Context, MythOpenGLInterop::Type Type)
Definition: mythvtbinterop.cpp:26
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:310
MythCodecContext
Definition: mythcodeccontext.h:52
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:763
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:83
MythVTBContext::RetrieveFrame
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
Definition: mythvtbcontext.cpp:45
mythmainwindow.h
MythVTBInterop
Definition: mythvtbinterop.h:11
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:121
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:363
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:493
MythCodecContext::VP8
@ VP8
Definition: mythcodeccontext.h:106
DecoderBase::GetPlayer
MythPlayer * GetPlayer()
Definition: decoderbase.h:152
MythCodecContext::H264
@ H264
Definition: mythcodeccontext.h:83
OpenGLLocker
Definition: mythrenderopengl.h:256