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