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  static QRecursiveMutex lock;
205  static bool s_initialised = false;
206  static VTBProfiles s_profiles;
207 
208  QMutexLocker locker(&lock);
209  if (s_initialised)
210  return s_profiles;
211  s_initialised = true;
212 
213  if (__builtin_available(macOS 10.13, *))
214  {
215  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG1Video)) { s_profiles.append(MythCodecContext::MPEG1); }
216  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG2Video)) { s_profiles.append(MythCodecContext::MPEG2); }
217  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_H263)) { s_profiles.append(MythCodecContext::H263); }
218  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_MPEG4Video)) { s_profiles.append(MythCodecContext::MPEG4); }
219  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_H264)) { s_profiles.append(MythCodecContext::H264); }
220  if (VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { s_profiles.append(MythCodecContext::HEVC); }
221  }
222  else
223  {
224  LOG(VB_GENERAL, LOG_INFO, LOC + "Unable to check hardware decode support. Assuming all.");
225  s_profiles.append(MythCodecContext::MPEG1);
226  s_profiles.append(MythCodecContext::MPEG2);
227  s_profiles.append(MythCodecContext::H263);
228  s_profiles.append(MythCodecContext::MPEG4);
229  s_profiles.append(MythCodecContext::H264);
230  s_profiles.append(MythCodecContext::HEVC);
231  }
232 
233  return s_profiles;
234 }
235 
236 bool MythVTBContext::HaveVTB(bool Reinit /*=false*/)
237 {
238  static QRecursiveMutex lock;
239  QMutexLocker locker(&lock);
240  static bool s_checked = false;
241  static bool s_available = false;
242  if (!s_checked || Reinit)
243  {
244  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
245  if (profiles.empty())
246  {
247  LOG(VB_GENERAL, LOG_INFO, LOC + "No VideoToolbox decoders found");
248  }
249  else
250  {
251  s_available = true;
252  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available VideoToolbox decoders:");
253  QSize size{0, 0};
254  for (auto profile : profiles)
255  {
256  LOG(VB_GENERAL, LOG_INFO, LOC +
258  }
259  }
260  }
261  s_checked = true;
262  return s_available;
263 }
264 
265 void MythVTBContext::GetDecoderList(QStringList &Decoders)
266 {
267  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
268  if (profiles.isEmpty())
269  return;
270 
271  QSize size(0, 0);
272  Decoders.append("VideoToolbox:");
273  for (MythCodecContext::CodecProfile profile : profiles)
274  Decoders.append(MythCodecContext::GetProfileDescription(profile, size));
275 }
276 
299 void MythVTBContext::InitFramesContext(AVCodecContext *Context)
300 {
301  if (!Context)
302  return;
303 
304  AVPixelFormat format = AV_PIX_FMT_NV12;
306  format = AV_PIX_FMT_P010;
307 
308  if (m_framesContext)
309  {
310  auto *frames = reinterpret_cast<AVHWFramesContext*>(m_framesContext->data);
311  if ((frames->sw_format == format) && (frames->width == Context->coded_width) &&
312  (frames->height == Context->coded_height))
313  {
314  Context->hw_frames_ctx = av_buffer_ref(m_framesContext);
315  return;
316  }
317  }
318 
319  // If this is a 'spontaneous' callback from FFmpeg (i.e. not on a stream change)
320  // then we must release any direct render buffers.
322  m_parent->GetPlayer()->DiscardVideoFrames(true, true);
323 
324  av_videotoolbox_default_free(Context);
325  av_buffer_unref(&m_framesContext);
326 
327  AVBufferRef* framesref = av_hwframe_ctx_alloc(Context->hw_device_ctx);
328  auto *frames = reinterpret_cast<AVHWFramesContext*>(framesref->data);
330  frames->user_opaque = nullptr;
331  frames->sw_format = format;
332  frames->format = AV_PIX_FMT_VIDEOTOOLBOX;
333  frames->width = Context->coded_width;
334  frames->height = Context->coded_height;
335  if (av_hwframe_ctx_init(framesref) < 0)
336  {
337  av_buffer_unref(&framesref);
338  }
339  else
340  {
341  Context->hw_frames_ctx = framesref;
342  m_framesContext = av_buffer_ref(framesref);
344  }
345 }
mythvtbcontext.h
MythCodecContext::m_codecID
MythCodecID m_codecID
Definition: mythcodeccontext.h:169
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:57
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:55
Frame
Definition: zmdefines.h:93
MythCodecContext::NewHardwareFramesContext
static void NewHardwareFramesContext(void)
Track the number of concurrent frames contexts.
Definition: mythcodeccontext.cpp:432
codec_is_vtb
static bool codec_is_vtb(MythCodecID id)
Definition: mythcodecid.h:348
MythCoreContext::IsUIThread
bool IsUIThread(void)
Definition: mythcorecontext.cpp:1348
MythCodecContext::InitVideoCodec
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
Definition: mythcodeccontext.cpp:306
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythCodecContext::FramesContextFinished
static void FramesContextFinished(AVHWFramesContext *Context)
Definition: mythcodeccontext.cpp:439
mythframe.h
MythVTBContext::~MythVTBContext
~MythVTBContext() override
Definition: mythvtbcontext.cpp:28
MythVTBContext::GetDecoderList
static void GetDecoderList(QStringList &Decoders)
Definition: mythvtbcontext.cpp:265
MythPlayer::DiscardVideoFrames
void DiscardVideoFrames(bool KeyFrame, bool Flushed)
Places frames in the available frames queue.
Definition: mythplayer.cpp:648
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:449
hardwareprofile.scan.profile
profile
Definition: scan.py:97
LOC
#define LOC
Definition: mythvtbcontext.cpp:21
kCodec_MPEG1
@ kCodec_MPEG1
Definition: mythcodecid.h:21
MythCodecContext::VP9
@ VP9
Definition: mythcodeccontext.h:108
mythcodecid.h
MythCodecContext::MPEG4
@ MPEG4
Definition: mythcodeccontext.h:66
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:58
MythCodecContext::HEVC
@ HEVC
Definition: mythcodeccontext.h:95
MythCodecContext::RetrieveHWFrame
virtual bool RetrieveHWFrame(MythVideoFrame *Frame, AVFrame *AvFrame)
Definition: mythcodeccontext.cpp:629
mythvtbinterop.h
AvFormatDecoder
A decoder for media files.
Definition: avformatdecoder.h:82
MythCodecContext::H263
@ H263
Definition: mythcodeccontext.h:83
uint
unsigned int uint
Definition: compat.h:81
MythCodecContext::m_parent
DecoderBase * m_parent
Definition: mythcodeccontext.h:168
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
MythCodecContext::IsUnsupportedProfile
static bool IsUnsupportedProfile(AVCodecContext *Context)
Most hardware decoders do not support these codecs/profiles.
Definition: mythcodeccontext.cpp:599
MythCodecContext::MPEG2
@ MPEG2
Definition: mythcodeccontext.h:59
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:71
MythRenderOpenGL
Definition: mythrenderopengl.h:96
codec_is_vtb_dec
static bool codec_is_vtb_dec(MythCodecID id)
Definition: mythcodecid.h:351
MythCodecContext::VC1
@ VC1
Definition: mythcodeccontext.h:102
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:560
avformatdecoder.h
kCodec_MPEG1_VTB
@ kCodec_MPEG1_VTB
Definition: mythcodecid.h:181
MythCodecContext::FrameTypeIsSupported
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
Definition: mythcodeccontext.cpp:516
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:544
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:299
MythCodecContext
Definition: mythcodeccontext.h:52
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:790
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:377
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:507
MythCodecContext::VP8
@ VP8
Definition: mythcodeccontext.h:107
DecoderBase::GetPlayer
MythPlayer * GetPlayer()
Definition: decoderbase.h:152
MythVTBContext::HaveVTB
static bool HaveVTB(bool Reinit=false)
Definition: mythvtbcontext.cpp:236
MythCodecContext::H264
@ H264
Definition: mythcodeccontext.h:84
OpenGLLocker
Definition: mythrenderopengl.h:255