MythTV  master
mythmmalcontext.cpp
Go to the documentation of this file.
1 // MythTV
3 #include "mythplayerui.h"
4 #include "mythmmalcontext.h"
5 
6 // FFmpeg
7 extern "C" {
8 #include "libavutil/opt.h"
9 }
10 
11 #define LOC QString("MMAL: ")
12 
14  : MythCodecContext(Parent, Codec)
15 {
16 }
17 
19 {
20  if (m_interop)
22 }
23 
25 {
26  switch (Profile)
27  {
32  if (Width > 1920 || Height > 1088)
33  return false;
34  break;
35  default: break;
36  }
37  return true;
38 }
39 
41  AVCodec **Codec,
42  const QString &Decoder,
43  AVStream *Stream,
44  uint StreamType)
45 {
46  bool decodeonly = Decoder == "mmal-dec";
47  MythCodecID success = static_cast<MythCodecID>((decodeonly ? kCodec_MPEG1_MMAL_DEC : kCodec_MPEG1_MMAL) + (StreamType - 1));
48  MythCodecID failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
49 
50  if (!Decoder.startsWith("mmal"))
51  return failure;
52 
53  // Only MPEG2, MPEG4, VC1 and H264 supported (and HEVC will never be supported)
55  switch ((*Codec)->id)
56  {
57  case AV_CODEC_ID_MPEG2VIDEO: mythprofile = MythCodecContext::MPEG2; break;
58  case AV_CODEC_ID_MPEG4: mythprofile = MythCodecContext::MPEG4; break;
59  case AV_CODEC_ID_VC1: mythprofile = MythCodecContext::VC1; break;
60  case AV_CODEC_ID_H264:
61  if ((*Context)->profile == FF_PROFILE_H264_HIGH_10 ||
62  (*Context)->profile == FF_PROFILE_H264_HIGH_10_INTRA)
63  {
64  return failure;
65  }
66  mythprofile = MythCodecContext::H264; break;
67  default: break;
68  }
69 
70  if (mythprofile == MythCodecContext::NoProfile)
71  return failure;
72 
73  // Check size
74  if (!MythMMALContext::CheckCodecSize((*Context)->width, (*Context)->height, mythprofile))
75  return failure;
76 
77  // check actual decoder support
78  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
79  if (!profiles.contains(mythprofile))
80  return failure;
81 
82  if (!decodeonly)
83  if (!FrameTypeIsSupported(*Context, FMT_MMAL))
84  return failure;
85 
86  // look for a decoder
87  QString name = QString((*Codec)->name) + "_mmal";
88  if (name == "mpeg2video_mmal")
89  name = "mpeg2_mmal";
90  AVCodec *codec = avcodec_find_decoder_by_name(name.toLocal8Bit());
91  AvFormatDecoder *decoder = dynamic_cast<AvFormatDecoder*>(reinterpret_cast<DecoderBase*>((*Context)->opaque));
92  if (!codec || !decoder)
93  {
94  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to find %1").arg(name));
95  return failure;
96  }
97 
98  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found MMAL/FFmpeg decoder '%1'").arg(name));
99  *Codec = codec;
100  decoder->CodecMap()->FreeCodecContext(Stream);
101  *Context = decoder->CodecMap()->GetCodecContext(Stream, *Codec);
102  (*Context)->pix_fmt = decodeonly ? (*Context)->pix_fmt : AV_PIX_FMT_MMAL;
103  return success;
104 }
105 
106 void MythMMALContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
107 {
109  {
110  DirectRendering = false;
111  return;
112  }
113  else if (codec_is_mmal(m_codecID))
114  {
115  Context->get_format = MythMMALContext::GetFormat;
116  DirectRendering = false;
117  return;
118  }
119 
120  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
121 }
122 
123 bool MythMMALContext::RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame)
124 {
126  return GetBuffer(Context, Frame, AvFrame, 0);
127  else if (codec_is_mmal(m_codecID))
128  return GetBuffer2(Context, Frame, AvFrame, 0);
129  return false;
130 }
131 
132 
133 int MythMMALContext::HwDecoderInit(AVCodecContext *Context)
134 {
135  if (!Context)
136  return -1;
137 
139  return 0;
140 
141  if (!codec_is_mmal(m_codecID) || Context->pix_fmt != AV_PIX_FMT_MMAL)
142  return -1;
143 
144  if (auto * player = GetPlayerUI(Context); player != nullptr)
145  if (FrameTypeIsSupported(Context, FMT_MMAL))
146  m_interop = MythMMALInterop::CreateMMAL(dynamic_cast<MythRenderOpenGL*>(player->GetRender()));
147 
148  return m_interop ? 0 : -1;
149 }
150 
151 void MythMMALContext::SetDecoderOptions(AVCodecContext *Context, AVCodec *Codec)
152 {
153  if (!(codec_is_mmal(m_codecID)))
154  return;
155  if (!(Context && Codec))
156  return;
157  if (!(Codec->priv_class && Context->priv_data))
158  return;
159  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Setting number of extra buffers to 8");
160  av_opt_set(Context->priv_data, "extra_buffers", "8", 0);
161 }
162 
163 bool MythMMALContext::GetBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
164 {
165  // Sanity checks
166  if (!Context || !AvFrame || !Frame)
167  return false;
168 
169  // Ensure we can render this format
170  AvFormatDecoder *decoder = static_cast<AvFormatDecoder*>(Context->opaque);
171  VideoFrameType type = MythAVUtil::PixelFormatToFrameType(static_cast<AVPixelFormat>(AvFrame->format));
172  const VideoFrameTypes* supported = Frame->m_renderFormats;
173  auto foundIt = std::find(supported->cbegin(), supported->cend(), type);
174  // No fallback currently (unlikely)
175  if (foundIt == supported->end())
176  return false;
177 
178  // Re-allocate if necessary
179  if ((Frame->m_type != type) || (Frame->m_width != AvFrame->width) || (Frame->m_height != AvFrame->height))
180  if (!VideoBuffers::ReinitBuffer(Frame, type, decoder->GetVideoCodecID(), AvFrame->width, AvFrame->height))
181  return false;
182 
183  // Copy data
184  uint count = MythVideoFrame::GetNumPlanes(Frame->m_type);
185  for (uint plane = 0; plane < count; ++plane)
186  {
187  MythVideoFrame::CopyPlane(Frame->m_buffer + Frame->m_offsets[plane], Frame->m_pitches[plane],
188  AvFrame->data[plane], AvFrame->linesize[plane],
189  MythVideoFrame::GetPitchForPlane(Frame->m_type, AvFrame->width, plane),
190  MythVideoFrame::GetHeightForPlane(Frame->m_type, AvFrame->height, plane));
191  }
192 
193  AvFrame->reordered_opaque = Context->reordered_opaque;
194  return true;
195 }
196 
197 bool MythMMALContext::GetBuffer2(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
198 {
199  // Sanity checks
200  if (!Context || !AvFrame || !Frame || !m_interop)
201  {
202  LOG(VB_GENERAL, LOG_ERR, LOC + "Error");
203  return false;
204  }
205 
206  // MMAL?
207  if (Frame->m_type != FMT_MMAL || static_cast<AVPixelFormat>(AvFrame->format) != AV_PIX_FMT_MMAL)
208  {
209  LOG(VB_GENERAL, LOG_ERR, LOC + "Not an MMAL frame");
210  return false;
211  }
212 
213  Frame->m_width = AvFrame->width;
214  Frame->m_height = AvFrame->height;
215  Frame->m_pixFmt = Context->pix_fmt;
216  Frame->m_swPixFmt = Context->sw_pix_fmt;
217  Frame->m_directRendering = 1;
218  AvFrame->opaque = Frame;
219  AvFrame->reordered_opaque = Context->reordered_opaque;
220 
221  // Frame->data[3] holds MMAL_BUFFER_HEADER_T
222  Frame->m_buffer = AvFrame->data[3];
223  // Retain the buffer so it is not released before we display it
224  Frame->m_priv[0] = reinterpret_cast<unsigned char*>(av_buffer_ref(AvFrame->buf[0]));
225  // Add interop
226  Frame->m_priv[1] = reinterpret_cast<unsigned char*>(m_interop);
227  // Set the release method
228  AvFrame->buf[1] = av_buffer_create(reinterpret_cast<uint8_t*>(Frame), 0, MythCodecContext::ReleaseBuffer,
229  static_cast<AvFormatDecoder*>(Context->opaque), 0);
230  return true;
231 }
232 
233 AVPixelFormat MythMMALContext::GetFormat(AVCodecContext*, const AVPixelFormat *PixFmt)
234 {
235  while (*PixFmt != AV_PIX_FMT_NONE)
236  {
237  if (*PixFmt == AV_PIX_FMT_MMAL)
238  return AV_PIX_FMT_MMAL;
239  PixFmt++;
240  }
241  return AV_PIX_FMT_NONE;
242 }
243 
244 bool MythMMALContext::HaveMMAL(bool Reinit /*=false*/)
245 {
246 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
247  static QMutex lock(QMutex::Recursive);
248 #else
249  static QRecursiveMutex lock;
250 #endif
251  QMutexLocker locker(&lock);
252  static bool s_checked = false;
253  static bool s_available = false;
254 
255  if (s_checked && !Reinit)
256  return s_available;
257  s_checked = true;
258 
259  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
260  if (profiles.isEmpty())
261  return s_available;
262 
263  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available MMAL decoders:");
264  s_available = true;
265  QSize size{0, 0};
266  for (auto profile : qAsConst(profiles))
267  LOG(VB_GENERAL, LOG_INFO, LOC + MythCodecContext::GetProfileDescription(profile, size));
268  return s_available;
269 }
270 
271 void MythMMALContext::GetDecoderList(QStringList &Decoders)
272 {
273  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
274  if (profiles.isEmpty())
275  return;
276 
277  QSize size(0, 0);
278  Decoders.append("MMAL:");
279  for (MythCodecContext::CodecProfile profile : profiles)
280  Decoders.append(MythCodecContext::GetProfileDescription(profile, size));
281 }
282 
283 // Broadcom
284 extern "C" {
285 #include "interface/vmcs_host/vc_vchi_gencmd.h"
286 }
287 
289 {
290 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
291  static QMutex lock(QMutex::Recursive);
292 #else
293  static QRecursiveMutex lock;
294 #endif
295  static bool s_initialised = false;
296  static MMALProfiles s_profiles;
297 
298  QMutexLocker locker(&lock);
299  if (s_initialised)
300  return s_profiles;
301  s_initialised = true;
302 
303  static const QPair<QString, MythCodecContext::CodecProfile> s_map[] =
304  {
305  { "MPG2", MythCodecContext::MPEG2 },
306  { "MPG4", MythCodecContext::MPEG4 },
307  { "WVC1", MythCodecContext::VC1 },
308  { "H264", MythCodecContext::H264 }
309  };
310 
311  vcos_init();
312  VCHI_INSTANCE_T vchi_instance;
313  if (vchi_initialise(&vchi_instance) != 0)
314  return s_profiles;
315  if (vchi_connect(nullptr, 0, vchi_instance) != 0)
316  return s_profiles;
317  VCHI_CONNECTION_T *vchi_connection = nullptr;
318  vc_vchi_gencmd_init(vchi_instance, &vchi_connection, 1 );
319 
320  for (auto profile : s_map)
321  {
322  char command[32];
323  char* response = nullptr;
324  int responsesize = 0;
325  QString msg = QString("codec_enabled %1").arg(profile.first);
326  if (!vc_gencmd(command, sizeof(command), msg.toLocal8Bit().constData()))
327  vc_gencmd_string_property(command, profile.first.toLocal8Bit().constData(), &response, &responsesize);
328 
329  if (response && responsesize && qstrcmp(response, "enabled") == 0)
330  s_profiles.append(profile.second);
331  }
332 
333  vc_gencmd_stop();
334  vchi_disconnect(vchi_instance);
335 
336  return s_profiles;
337 }
MythMMALContext::CheckCodecSize
static bool CheckCodecSize(int Width, int Height, MythCodecContext::CodecProfile Profile)
Definition: mythmmalcontext.cpp:24
MythCodecContext::m_codecID
MythCodecID m_codecID
Definition: mythcodeccontext.h:170
MythVideoFrame::GetPitchForPlane
static int GetPitchForPlane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:304
mythplayerui.h
MythMMALContext::SetDecoderOptions
void SetDecoderOptions(AVCodecContext *Context, AVCodec *Codec) override
Definition: mythmmalcontext.cpp:151
MythMMALContext::HaveMMAL
static bool HaveMMAL(bool Reinit=false)
Definition: mythmmalcontext.cpp:244
MythCodecMap::GetCodecContext
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
Definition: mythavutil.cpp:250
MythCodecContext::NoProfile
@ NoProfile
Definition: mythcodeccontext.h:58
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:56
Frame
Definition: zmdefines.h:93
MythCodecContext::InitVideoCodec
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
Definition: mythcodeccontext.cpp:302
codec_is_mmal_dec
#define codec_is_mmal_dec(id)
Definition: mythcodecid.h:342
codec_is_mmal
#define codec_is_mmal(id)
Definition: mythcodecid.h:341
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
kCodec_MPEG1_MMAL
@ kCodec_MPEG1_MMAL
Definition: mythcodecid.h:245
MythMMALContext::GetBuffer
static bool GetBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
Definition: mythmmalcontext.cpp:163
AvFormatDecoder::CodecMap
MythCodecMap * CodecMap(void)
Definition: avformatdecoder.cpp:372
MythCodecID
MythCodecID
Definition: mythcodecid.h:10
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
Decoder
Definition: decoder.h:70
hardwareprofile.scan.profile
profile
Definition: scan.py:99
MythMMALInterop::CreateMMAL
static MythMMALInterop * CreateMMAL(MythRenderOpenGL *Context)
Create an MMAL interop.
Definition: mythmmalinterop.cpp:49
MythVideoFrame::CopyPlane
static void CopyPlane(uint8_t *To, int ToPitch, const uint8_t *From, int FromPitch, int PlaneWidth, int PlaneHeight)
Definition: mythframe.cpp:188
MythCodecContext::DestroyInterop
static void DestroyInterop(MythInteropGPU *Interop)
Definition: mythcodeccontext.cpp:463
MythCodecContext::ReleaseBuffer
static void ReleaseBuffer(void *Opaque, uint8_t *Data)
Definition: mythcodeccontext.cpp:413
MythMMALContext::GetFormat
static enum AVPixelFormat GetFormat(AVCodecContext *, const AVPixelFormat *PixFmt)
Definition: mythmmalcontext.cpp:233
VideoFrameTypes
std::vector< VideoFrameType > VideoFrameTypes
Definition: mythframe.h:83
LOC
#define LOC
Definition: mythmmalcontext.cpp:11
kCodec_MPEG1
@ kCodec_MPEG1
Definition: mythcodecid.h:21
MythMMALContext::InitVideoCodec
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
Definition: mythmmalcontext.cpp:106
MythCodecMap::FreeCodecContext
void FreeCodecContext(const AVStream *Stream)
Definition: mythavutil.cpp:298
MythCodecContext::MPEG4
@ MPEG4
Definition: mythcodeccontext.h:67
AvFormatDecoder
A decoder for media files.
Definition: avformatdecoder.h:85
uint
unsigned int uint
Definition: compat.h:140
MythMMALContext::m_interop
MythMMALInterop * m_interop
Definition: mythmmalcontext.h:33
MMALProfiles
QList< MythCodecContext::CodecProfile > MMALProfiles
Definition: mythmmalcontext.h:8
MythMMALContext::RetrieveFrame
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
Definition: mythmmalcontext.cpp:123
MythCodecContext::MPEG2
@ MPEG2
Definition: mythcodeccontext.h:60
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:70
MythMMALContext::GetProfiles
static const MMALProfiles & GetProfiles(void)
Definition: mythmmalcontext.cpp:288
MythRenderOpenGL
Definition: mythrenderopengl.h:99
MythVideoFrame::GetHeightForPlane
static int GetHeightForPlane(VideoFrameType Type, int Height, uint Plane)
Definition: mythframe.h:258
MythMMALContext::HwDecoderInit
int HwDecoderInit(AVCodecContext *Context) override
Definition: mythmmalcontext.cpp:133
MythCodecContext::VC1
@ VC1
Definition: mythcodeccontext.h:103
avformatdecoder.h
MythCodecContext::FrameTypeIsSupported
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
Definition: mythcodeccontext.cpp:512
mythmmalcontext.h
MythVideoFrame::GetNumPlanes
static uint GetNumPlanes(VideoFrameType Type)
Definition: mythframe.h:214
MythMMALContext::MythMMALContext
MythMMALContext(DecoderBase *Parent, MythCodecID Codec)
Definition: mythmmalcontext.cpp:13
MythMMALContext::GetBuffer2
bool GetBuffer2(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
Definition: mythmmalcontext.cpp:197
AvFormatDecoder::GetVideoCodecID
MythCodecID GetVideoCodecID(void) const override
Definition: avformatdecoder.h:141
VideoBuffers::ReinitBuffer
static bool ReinitBuffer(MythVideoFrame *Frame, VideoFrameType Type, MythCodecID CodecID, int Width, int Height)
Definition: videobuffers.cpp:981
FMT_MMAL
@ FMT_MMAL
Definition: mythframe.h:60
MythCodecContext
Definition: mythcodeccontext.h:53
VideoFrameType
VideoFrameType
Definition: mythframe.h:20
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:783
kCodec_MPEG1_MMAL_DEC
@ kCodec_MPEG1_MMAL_DEC
Definition: mythcodecid.h:261
MythVideoFrame
Definition: mythframe.h:88
MythMMALContext::GetSupportedCodec
static MythCodecID GetSupportedCodec(AVCodecContext **Context, AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
Definition: mythmmalcontext.cpp:40
MythMMALContext::~MythMMALContext
~MythMMALContext() override
Definition: mythmmalcontext.cpp:18
DecoderBase
Definition: decoderbase.h:120
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:503
find
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: dvbstreamhandler.cpp:356
MythMMALContext::GetDecoderList
static void GetDecoderList(QStringList &Decoders)
Definition: mythmmalcontext.cpp:271
MythCodecContext::H264
@ H264
Definition: mythcodeccontext.h:85