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 "mythvtbcontext.h"
11 
12 // FFmpeg
13 extern "C" {
14 #include "libavutil/hwcontext_videotoolbox.h"
15 #include "libavcodec/videotoolbox.h"
16 #include "libavutil/pixdesc.h"
17 }
18 
19 #define LOC QString("VTBDec: ")
20 
22  : MythCodecContext(Parent, CodecID)
23 {
24 }
25 
27 {
28  av_buffer_unref(&m_framesContext);
29 }
30 
31 void MythVTBContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
32 {
34  {
35  Context->get_format = MythVTBContext::GetFormat;
36  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
37  DirectRendering = false;
38  return;
39  }
40 
41  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
42 }
43 
45 {
46  if (AvFrame->format != AV_PIX_FMT_VIDEOTOOLBOX)
47  return false;
49  return RetrieveHWFrame(Frame, AvFrame);
51  return GetBuffer2(Context, Frame, AvFrame, 0);
52  return false;
53 }
54 
56 {
58  {
59  AVBufferRef *device = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VIDEOTOOLBOX, nullptr);
60  if (device)
61  {
62  Context->hw_device_ctx = device;
63  return 0;
64  }
65  }
66  else if (codec_is_vtb(m_codecID))
67  {
69  }
70 
71  return -1;
72 }
73 
75  AVCodec ** Codec,
76  const QString &Decoder,
77  uint StreamType)
78 {
79  bool decodeonly = Decoder == "vtb-dec";
80  auto success = static_cast<MythCodecID>((decodeonly ? kCodec_MPEG1_VTB_DEC : kCodec_MPEG1_VTB) + (StreamType - 1));
81  auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
82 
83  if (!Decoder.startsWith("vtb") || IsUnsupportedProfile(*Context))
84  return failure;
85 
86  // Check decoder support
88  switch ((*Codec)->id)
89  {
90  case AV_CODEC_ID_MPEG1VIDEO: mythprofile = MythCodecContext::MPEG1; break;
91  case AV_CODEC_ID_MPEG2VIDEO: mythprofile = MythCodecContext::MPEG2; break;
92  case AV_CODEC_ID_MPEG4: mythprofile = MythCodecContext::MPEG4; break;
93  case AV_CODEC_ID_H263: mythprofile = MythCodecContext::H263; break;
94  case AV_CODEC_ID_H264: mythprofile = MythCodecContext::H264; break;
95  case AV_CODEC_ID_VC1: mythprofile = MythCodecContext::VC1; break;
96  case AV_CODEC_ID_VP8: mythprofile = MythCodecContext::VP8; break;
97  case AV_CODEC_ID_VP9: mythprofile = MythCodecContext::VP9; break;
98  case AV_CODEC_ID_HEVC: mythprofile = MythCodecContext::HEVC; break;
99  default: break;
100  }
101 
102  if (mythprofile == MythCodecContext::NoProfile)
103  return failure;
104 
105  QString codec = ff_codec_id_string((*Context)->codec_id);
106  QString profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
107  QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
108 
109  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
110  if (!profiles.contains(mythprofile))
111  {
112  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VideoToolbox does not support decoding '%1 %2 %3'")
113  .arg(codec).arg(profile).arg(pixfmt));
114  return failure;
115  }
116 
117  // There is no guarantee (and no obvious way to check) whether the given
118  // profile is actually supported.
119  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VideoToolbox MAY support decoding '%1 %2 %3'")
120  .arg(codec).arg(profile).arg(pixfmt));
121  (*Context)->pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX;
122  return success;
123 }
124 
126 {
127  if (!gCoreContext->IsUIThread())
128  return -1;
129 
130  // Retrieve OpenGL render context
132  if (!render)
133  return -1;
134  OpenGLLocker locker(render);
135 
136  // We need a player to release the interop
137  MythPlayer *player = nullptr;
138  auto *decoder = reinterpret_cast<AvFormatDecoder*>(Context->opaque);
139  if (decoder)
140  player = decoder->GetPlayer();
141  if (!player)
142  return -1;
143 
144  // Check interop support
147  return -1;
148 
149  // Create interop
150  MythVTBInterop* interop = MythVTBInterop::Create(render, type);
151  if (!interop)
152  return -1;
153 
154  // Set player
155  interop->SetPlayer(player);
156 
157  // Allocate the device context
158  AVBufferRef* deviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VIDEOTOOLBOX);
159  if (!deviceref)
160  {
161  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create device context");
162  interop->DecrRef();
163  return -1;
164  }
165 
166  // Add our interop class and set the callback for its release
167  auto* devicectx = reinterpret_cast<AVHWDeviceContext*>(deviceref->data);
168  devicectx->user_opaque = interop;
169  devicectx->free = MythCodecContext::DeviceContextFinished;
170 
171  // Create
172  if (av_hwdevice_ctx_init(deviceref) < 0)
173  {
174  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise device context");
175  av_buffer_unref(&deviceref);
176  return -1;
177  }
178 
179  Context->hw_device_ctx = deviceref;
180  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created hw device '%1'")
181  .arg(av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_VIDEOTOOLBOX)));
182  return 0;
183 }
184 
185 enum AVPixelFormat MythVTBContext::GetFormat(struct AVCodecContext* Context, const enum AVPixelFormat *PixFmt)
186 {
187  enum AVPixelFormat ret = AV_PIX_FMT_NONE;
188  while (*PixFmt != AV_PIX_FMT_NONE)
189  {
190  if (*PixFmt == AV_PIX_FMT_VIDEOTOOLBOX)
191  {
192  auto* decoder = reinterpret_cast<AvFormatDecoder*>(Context->opaque);
193  if (decoder)
194  {
195  auto* me = dynamic_cast<MythVTBContext*>(decoder->GetMythCodecContext());
196  if (me)
198  }
199  return *PixFmt;
200  }
201  PixFmt++;
202  }
203  return ret;
204 }
205 
207 {
208  static QMutex lock(QMutex::Recursive);
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 
241 {
242  static QMutex lock(QMutex::Recursive);
243  QMutexLocker locker(&lock);
244  static bool s_checked = false;
245  static bool s_available = false;
246  if (!s_checked)
247  {
248  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
249  if (profiles.empty())
250  {
251  LOG(VB_GENERAL, LOG_INFO, LOC + "No VideoToolbox decoders found");
252  }
253  else
254  {
255  s_available = true;
256  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available VideoToolbox decoders:");
257  QSize size{0, 0};
258  for (auto profile : profiles)
259  {
260  LOG(VB_GENERAL, LOG_INFO, LOC +
262  }
263  }
264  }
265  s_checked = true;
266  return s_available;
267 }
268 
269 void MythVTBContext::GetDecoderList(QStringList &Decoders)
270 {
271  const VTBProfiles& profiles = MythVTBContext::GetProfiles();
272  if (profiles.isEmpty())
273  return;
274 
275  QSize size(0, 0);
276  Decoders.append("VideoToolbox:");
277  for (MythCodecContext::CodecProfile profile : profiles)
278  Decoders.append(MythCodecContext::GetProfileDescription(profile, size));
279 }
280 
304 {
305  if (!Context)
306  return;
307 
308  AVPixelFormat format = AV_PIX_FMT_NV12;
309  if (ColorDepth(PixelFormatToFrameType(Context->sw_pix_fmt)) > 8)
310  format = AV_PIX_FMT_P010;
311 
312  if (m_framesContext)
313  {
314  auto *frames = reinterpret_cast<AVHWFramesContext*>(m_framesContext->data);
315  if ((frames->sw_format == format) && (frames->width == Context->coded_width) &&
316  (frames->height == Context->coded_height))
317  {
318  Context->hw_frames_ctx = av_buffer_ref(m_framesContext);
319  return;
320  }
321  }
322 
323  // If this is a 'spontaneous' callback from FFmpeg (i.e. not on a stream change)
324  // then we must release any direct render buffers.
326  m_parent->GetPlayer()->DiscardVideoFrames(true, true);
327 
328  av_videotoolbox_default_free(Context);
329  av_buffer_unref(&m_framesContext);
330 
331  AVBufferRef* framesref = av_hwframe_ctx_alloc(Context->hw_device_ctx);
332  auto *frames = reinterpret_cast<AVHWFramesContext*>(framesref->data);
334  frames->user_opaque = nullptr;
335  frames->sw_format = format;
336  frames->format = AV_PIX_FMT_VIDEOTOOLBOX;
337  frames->width = Context->coded_width;
338  frames->height = Context->coded_height;
339  if (av_hwframe_ctx_init(framesref) < 0)
340  {
341  av_buffer_unref(&framesref);
342  }
343  else
344  {
345  Context->hw_frames_ctx = framesref;
346  m_framesContext = av_buffer_ref(framesref);
348  }
349 }
mythvtbcontext.h
MythCodecContext::m_codecID
MythCodecID m_codecID
Definition: mythcodeccontext.h:165
MythVTBContext::MythVTBContext
MythVTBContext(DecoderBase *Parent, MythCodecID CodecID)
Definition: mythvtbcontext.cpp:21
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
MythVTBContext::InitialiseDecoder
static int InitialiseDecoder(AVCodecContext *Context)
Definition: mythvtbcontext.cpp:125
FMT_VTB
@ FMT_VTB
Definition: mythframe.h:66
MythVTBContext::m_framesContext
AVBufferRef * m_framesContext
Definition: mythvtbcontext.h:42
MythCodecContext::RetrieveHWFrame
virtual bool RetrieveHWFrame(VideoFrame *Frame, AVFrame *AvFrame)
Definition: mythcodeccontext.cpp:601
MythCodecContext::NoProfile
@ NoProfile
Definition: mythcodeccontext.h:55
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:54
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
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythCodecContext::FramesContextFinished
static void FramesContextFinished(AVHWFramesContext *Context)
Definition: mythcodeccontext.cpp:424
mythframe.h
MythVTBContext::~MythVTBContext
~MythVTBContext() override
Definition: mythvtbcontext.cpp:26
MythPlayer
Definition: mythplayer.h:165
VideoFrame
Definition: mythframe.h:138
MythVTBContext::GetDecoderList
static void GetDecoderList(QStringList &Decoders)
Definition: mythvtbcontext.cpp:269
MythPlayer::DiscardVideoFrames
void DiscardVideoFrames(bool KeyFrame, bool Flushed)
Places frames in the available frames queue.
Definition: mythplayer.cpp:1015
MythVTBContext
Definition: mythvtbcontext.h:18
videobuffers.h
MythCodecID
MythCodecID
Definition: mythcodecid.h:11
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
mythrenderopengl.h
Decoder
Definition: decoder.h:66
mythlogging.h
MythCodecContext::DeviceContextFinished
static void DeviceContextFinished(AVHWDeviceContext *Context)
Definition: mythcodeccontext.cpp:434
hardwareprofile.scan.profile
profile
Definition: scan.py:99
MythOpenGLInterop::Unsupported
@ Unsupported
Definition: mythopenglinterop.h:31
LOC
#define LOC
Definition: mythvtbcontext.cpp:19
kCodec_MPEG1
@ kCodec_MPEG1
Definition: mythcodecid.h:21
MythCodecContext::VP9
@ VP9
Definition: mythcodeccontext.h:106
MythVTBContext::HaveVTB
static bool HaveVTB(void)
Definition: mythvtbcontext.cpp:240
mythcodecid.h
MythCodecContext::MPEG4
@ MPEG4
Definition: mythcodeccontext.h:64
MythVTBContext::GetFormat
static enum AVPixelFormat GetFormat(AVCodecContext *Context, const enum AVPixelFormat *PixFmt)
Definition: mythvtbcontext.cpp:185
MythCodecContext::MPEG1
@ MPEG1
Definition: mythcodeccontext.h:56
MythCodecContext::HEVC
@ HEVC
Definition: mythcodeccontext.h:93
mythvtbinterop.h
AvFormatDecoder
A decoder for video files.
Definition: avformatdecoder.h:89
MythCodecContext::H263
@ H263
Definition: mythcodeccontext.h:81
uint
unsigned int uint
Definition: compat.h:140
MythCodecContext::m_parent
DecoderBase * m_parent
Definition: mythcodeccontext.h:164
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
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:571
MythCodecContext::MPEG2
@ MPEG2
Definition: mythcodeccontext.h:57
MythVTBContext::RetrieveFrame
bool RetrieveFrame(AVCodecContext *Context, VideoFrame *Frame, AVFrame *AvFrame) override
Definition: mythvtbcontext.cpp:44
MythRenderOpenGL
Definition: mythrenderopengl.h:95
MythVTBContext::GetSupportedCodec
static MythCodecID GetSupportedCodec(AVCodecContext **Context, AVCodec **Codec, const QString &Decoder, uint StreamType)
Definition: mythvtbcontext.cpp:74
MythCodecContext::CreateDevice
static AVBufferRef * CreateDevice(AVHWDeviceType Type, MythOpenGLInterop *Interop, const QString &Device=QString())
Definition: mythcodeccontext.cpp:532
ColorDepth
int ColorDepth(int Format)
Return the color depth for the given MythTV frame format.
Definition: mythframe.cpp:808
MythCodecContext::VC1
@ VC1
Definition: mythcodeccontext.h:100
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:63
MythVTBContext::GetProfiles
static const VTBProfiles & GetProfiles(void)
Definition: mythvtbcontext.cpp:206
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:513
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:31
MythVTBContext::InitFramesContext
void InitFramesContext(AVCodecContext *Context)
Create a hardware frames context if needed.
Definition: mythvtbcontext.cpp:303
MythCodecContext
Definition: mythcodeccontext.h:51
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:759
codec_is_vtb
#define codec_is_vtb(id)
Definition: mythcodecid.h:333
MythVTBContext::HwDecoderInit
int HwDecoderInit(AVCodecContext *Context) override
Definition: mythvtbcontext.cpp:55
MythOpenGLInterop::GetInteropType
static Type GetInteropType(VideoFrameType Format, MythPlayer *Player)
Check whether we support direct rendering for the given VideoFrameType.
Definition: mythopenglinterop.cpp:77
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:120
MythCodecContext::VP8
@ VP8
Definition: mythcodeccontext.h:105
DecoderBase::GetPlayer
MythPlayer * GetPlayer()
Definition: decoderbase.h:153
MythCodecContext::GetBuffer2
static bool GetBuffer2(struct AVCodecContext *Context, VideoFrame *Frame, AVFrame *AvFrame, int Flags)
A generic hardware buffer initialisation method when AVHWFramesContext is NOT used.
Definition: mythcodeccontext.cpp:362
MythCodecContext::H264
@ H264
Definition: mythcodeccontext.h:82
OpenGLLocker
Definition: mythrenderopengl.h:253