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  const 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  const 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, const 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  return true;
194 }
195 
196 bool MythMMALContext::GetBuffer2(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
197 {
198  // Sanity checks
199  if (!Context || !AvFrame || !Frame || !m_interop)
200  {
201  LOG(VB_GENERAL, LOG_ERR, LOC + "Error");
202  return false;
203  }
204 
205  // MMAL?
206  if (Frame->m_type != FMT_MMAL || static_cast<AVPixelFormat>(AvFrame->format) != AV_PIX_FMT_MMAL)
207  {
208  LOG(VB_GENERAL, LOG_ERR, LOC + "Not an MMAL frame");
209  return false;
210  }
211 
212  Frame->m_width = AvFrame->width;
213  Frame->m_height = AvFrame->height;
214  Frame->m_pixFmt = Context->pix_fmt;
215  Frame->m_swPixFmt = Context->sw_pix_fmt;
216  Frame->m_directRendering = 1;
217  AvFrame->opaque = Frame;
218 
219  // Frame->data[3] holds MMAL_BUFFER_HEADER_T
220  Frame->m_buffer = AvFrame->data[3];
221  // Retain the buffer so it is not released before we display it
222  Frame->m_priv[0] = reinterpret_cast<unsigned char*>(av_buffer_ref(AvFrame->buf[0]));
223  // Add interop
224  Frame->m_priv[1] = reinterpret_cast<unsigned char*>(m_interop);
225  // Set the release method
226  AvFrame->buf[1] = av_buffer_create(reinterpret_cast<uint8_t*>(Frame), 0, MythCodecContext::ReleaseBuffer,
227  static_cast<AvFormatDecoder*>(Context->opaque), 0);
228  return true;
229 }
230 
231 AVPixelFormat MythMMALContext::GetFormat(AVCodecContext*, const AVPixelFormat *PixFmt)
232 {
233  while (*PixFmt != AV_PIX_FMT_NONE)
234  {
235  if (*PixFmt == AV_PIX_FMT_MMAL)
236  return AV_PIX_FMT_MMAL;
237  PixFmt++;
238  }
239  return AV_PIX_FMT_NONE;
240 }
241 
242 bool MythMMALContext::HaveMMAL(bool Reinit /*=false*/)
243 {
244  static QRecursiveMutex lock;
245  QMutexLocker locker(&lock);
246  static bool s_checked = false;
247  static bool s_available = false;
248 
249  if (s_checked && !Reinit)
250  return s_available;
251  s_checked = true;
252 
253  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
254  if (profiles.isEmpty())
255  return s_available;
256 
257  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available MMAL decoders:");
258  s_available = true;
259  QSize size{0, 0};
260  for (auto profile : std::as_const(profiles))
261  LOG(VB_GENERAL, LOG_INFO, LOC + MythCodecContext::GetProfileDescription(profile, size));
262  return s_available;
263 }
264 
265 void MythMMALContext::GetDecoderList(QStringList &Decoders)
266 {
267  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
268  if (profiles.isEmpty())
269  return;
270 
271  QSize size(0, 0);
272  Decoders.append("MMAL:");
273  for (MythCodecContext::CodecProfile profile : profiles)
274  Decoders.append(MythCodecContext::GetProfileDescription(profile, size));
275 }
276 
277 // Broadcom
278 extern "C" {
279 #include "interface/vmcs_host/vc_vchi_gencmd.h"
280 }
281 
283 {
284  static QRecursiveMutex lock;
285  static bool s_initialised = false;
286  static MMALProfiles s_profiles;
287 
288  QMutexLocker locker(&lock);
289  if (s_initialised)
290  return s_profiles;
291  s_initialised = true;
292 
293  static const QPair<QString, MythCodecContext::CodecProfile> s_map[] =
294  {
295  { "MPG2", MythCodecContext::MPEG2 },
296  { "MPG4", MythCodecContext::MPEG4 },
297  { "WVC1", MythCodecContext::VC1 },
298  { "H264", MythCodecContext::H264 }
299  };
300 
301  vcos_init();
302  VCHI_INSTANCE_T vchi_instance;
303  if (vchi_initialise(&vchi_instance) != 0)
304  return s_profiles;
305  if (vchi_connect(nullptr, 0, vchi_instance) != 0)
306  return s_profiles;
307  VCHI_CONNECTION_T *vchi_connection = nullptr;
308  vc_vchi_gencmd_init(vchi_instance, &vchi_connection, 1 );
309 
310  for (auto profile : s_map)
311  {
312  char command[32];
313  char* response = nullptr;
314  int responsesize = 0;
315  QString msg = QString("codec_enabled %1").arg(profile.first);
316  if (!vc_gencmd(command, sizeof(command), msg.toLocal8Bit().constData()))
317  vc_gencmd_string_property(command, profile.first.toLocal8Bit().constData(), &response, &responsesize);
318 
319  if (response && responsesize && qstrcmp(response, "enabled") == 0)
320  s_profiles.append(profile.second);
321  }
322 
323  vc_gencmd_stop();
324  vchi_disconnect(vchi_instance);
325 
326  return s_profiles;
327 }
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:169
MythVideoFrame::GetPitchForPlane
static int GetPitchForPlane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:303
mythplayerui.h
MythMMALContext::HaveMMAL
static bool HaveMMAL(bool Reinit=false)
Definition: mythmmalcontext.cpp:242
MythCodecMap::GetCodecContext
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
Definition: mythavutil.cpp:288
MythCodecID
MythCodecID
Definition: mythcodecid.h:11
MythCodecContext::H264
@ H264
Definition: mythcodeccontext.h:84
Frame
Definition: zmdefines.h:102
MythCodecContext::VC1
@ VC1
Definition: mythcodeccontext.h:102
MythCodecContext::InitVideoCodec
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
Definition: mythcodeccontext.cpp:307
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
codec_is_mmal_dec
static bool codec_is_mmal_dec(MythCodecID id)
Definition: mythcodecid.h:363
MythMMALContext::GetBuffer
static bool GetBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
Definition: mythmmalcontext.cpp:163
AvFormatDecoder::CodecMap
MythCodecMap * CodecMap(void)
Definition: avformatdecoder.cpp:427
MythCodecContext::NoProfile
@ NoProfile
Definition: mythcodeccontext.h:57
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
Decoder
Definition: decoder.h:70
MythMMALContext::GetSupportedCodec
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
Definition: mythmmalcontext.cpp:40
hardwareprofile.scan.profile
profile
Definition: scan.py:97
kCodec_MPEG1_MMAL
@ kCodec_MPEG1_MMAL
Definition: mythcodecid.h:246
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:466
MythCodecContext::ReleaseBuffer
static void ReleaseBuffer(void *Opaque, uint8_t *Data)
Definition: mythcodeccontext.cpp:416
MythMMALContext::GetFormat
static enum AVPixelFormat GetFormat(AVCodecContext *, const AVPixelFormat *PixFmt)
Definition: mythmmalcontext.cpp:231
MythCodecContext::MPEG2
@ MPEG2
Definition: mythcodeccontext.h:59
VideoFrameTypes
std::vector< VideoFrameType > VideoFrameTypes
Definition: mythframe.h:82
LOC
#define LOC
Definition: mythmmalcontext.cpp:11
MythMMALContext::InitVideoCodec
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
Definition: mythmmalcontext.cpp:106
VideoFrameType
VideoFrameType
Definition: mythframe.h:19
MythCodecMap::FreeCodecContext
void FreeCodecContext(const AVStream *Stream)
Definition: mythavutil.cpp:336
AvFormatDecoder
A decoder for media files.
Definition: avformatdecoder.h:80
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
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:72
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:55
MythMMALContext::GetProfiles
static const MMALProfiles & GetProfiles(void)
Definition: mythmmalcontext.cpp:282
MythRenderOpenGL
Definition: mythrenderopengl.h:96
MythVideoFrame::GetHeightForPlane
static int GetHeightForPlane(VideoFrameType Type, int Height, uint Plane)
Definition: mythframe.h:257
MythMMALContext::HwDecoderInit
int HwDecoderInit(AVCodecContext *Context) override
Definition: mythmmalcontext.cpp:133
FMT_MMAL
@ FMT_MMAL
Definition: mythframe.h:59
kCodec_MPEG1
@ kCodec_MPEG1
Definition: mythcodecid.h:22
avformatdecoder.h
codec_is_mmal
static bool codec_is_mmal(MythCodecID id)
Definition: mythcodecid.h:361
MythCodecContext::FrameTypeIsSupported
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
Definition: mythcodeccontext.cpp:515
mythmmalcontext.h
MythVideoFrame::GetNumPlanes
static uint GetNumPlanes(VideoFrameType Type)
Definition: mythframe.h:213
kCodec_MPEG1_MMAL_DEC
@ kCodec_MPEG1_MMAL_DEC
Definition: mythcodecid.h:262
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:196
AvFormatDecoder::GetVideoCodecID
MythCodecID GetVideoCodecID(void) const override
Definition: avformatdecoder.h:114
VideoBuffers::ReinitBuffer
static bool ReinitBuffer(MythVideoFrame *Frame, VideoFrameType Type, MythCodecID CodecID, int Width, int Height)
Definition: videobuffers.cpp:982
MythCodecContext
Definition: mythcodeccontext.h:52
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:789
MythCodecContext::MPEG4
@ MPEG4
Definition: mythcodeccontext.h:66
MythVideoFrame
Definition: mythframe.h:87
MythMMALContext::~MythMMALContext
~MythMMALContext() override
Definition: mythmmalcontext.cpp:18
DecoderBase
Definition: decoderbase.h:121
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:506
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:363
MythMMALContext::GetDecoderList
static void GetDecoderList(QStringList &Decoders)
Definition: mythmmalcontext.cpp:265
uint
unsigned int uint
Definition: freesurround.h:24
MythMMALContext::SetDecoderOptions
void SetDecoderOptions(AVCodecContext *Context, const AVCodec *Codec) override
Definition: mythmmalcontext.cpp:151