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  static QMutex lock(QMutex::Recursive);
247  QMutexLocker locker(&lock);
248  static bool s_checked = false;
249  static bool s_available = false;
250 
251  if (s_checked && !Reinit)
252  return s_available;
253  s_checked = true;
254 
255  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
256  if (profiles.isEmpty())
257  return s_available;
258 
259  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available MMAL decoders:");
260  s_available = true;
261  QSize size{0, 0};
262  for (auto profile : qAsConst(profiles))
263  LOG(VB_GENERAL, LOG_INFO, LOC + MythCodecContext::GetProfileDescription(profile, size));
264  return s_available;
265 }
266 
267 void MythMMALContext::GetDecoderList(QStringList &Decoders)
268 {
269  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
270  if (profiles.isEmpty())
271  return;
272 
273  QSize size(0, 0);
274  Decoders.append("MMAL:");
275  for (MythCodecContext::CodecProfile profile : profiles)
276  Decoders.append(MythCodecContext::GetProfileDescription(profile, size));
277 }
278 
279 // Broadcom
280 extern "C" {
281 #include "interface/vmcs_host/vc_vchi_gencmd.h"
282 }
283 
285 {
286  static QMutex lock(QMutex::Recursive);
287  static bool s_initialised = false;
288  static MMALProfiles s_profiles;
289 
290  QMutexLocker locker(&lock);
291  if (s_initialised)
292  return s_profiles;
293  s_initialised = true;
294 
295  static const QPair<QString, MythCodecContext::CodecProfile> s_map[] =
296  {
297  { "MPG2", MythCodecContext::MPEG2 },
298  { "MPG4", MythCodecContext::MPEG4 },
299  { "WVC1", MythCodecContext::VC1 },
300  { "H264", MythCodecContext::H264 }
301  };
302 
303  vcos_init();
304  VCHI_INSTANCE_T vchi_instance;
305  if (vchi_initialise(&vchi_instance) != 0)
306  return s_profiles;
307  if (vchi_connect(nullptr, 0, vchi_instance) != 0)
308  return s_profiles;
309  VCHI_CONNECTION_T *vchi_connection = nullptr;
310  vc_vchi_gencmd_init(vchi_instance, &vchi_connection, 1 );
311 
312  for (auto profile : s_map)
313  {
314  char command[32];
315  char* response = nullptr;
316  int responsesize = 0;
317  QString msg = QString("codec_enabled %1").arg(profile.first);
318  if (!vc_gencmd(command, sizeof(command), msg.toLocal8Bit().constData()))
319  vc_gencmd_string_property(command, profile.first.toLocal8Bit().constData(), &response, &responsesize);
320 
321  if (response && responsesize && qstrcmp(response, "enabled") == 0)
322  s_profiles.append(profile.second);
323  }
324 
325  vc_gencmd_stop();
326  vchi_disconnect(vchi_instance);
327 
328  return s_profiles;
329 }
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:168
MythVideoFrame::GetPitchForPlane
static int GetPitchForPlane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:300
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:238
MythCodecContext::NoProfile
@ NoProfile
Definition: mythcodeccontext.h:56
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:54
Frame
Definition: zmdefines.h:93
arg
arg(title).arg(filename).arg(doDelete))
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:371
MythCodecID
MythCodecID
Definition: mythcodecid.h:10
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
Decoder
Definition: decoder.h:65
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:187
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:81
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:286
MythCodecContext::MPEG4
@ MPEG4
Definition: mythcodeccontext.h:65
AvFormatDecoder
A decoder for media files.
Definition: avformatdecoder.h:85
uint
unsigned int uint
Definition: compat.h:141
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:58
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:70
MythMMALContext::GetProfiles
static const MMALProfiles & GetProfiles(void)
Definition: mythmmalcontext.cpp:284
MythRenderOpenGL
Definition: mythrenderopengl.h:96
MythVideoFrame::GetHeightForPlane
static int GetHeightForPlane(VideoFrameType Type, int Height, uint Plane)
Definition: mythframe.h:254
MythMMALContext::HwDecoderInit
int HwDecoderInit(AVCodecContext *Context) override
Definition: mythmmalcontext.cpp:133
MythCodecContext::VC1
@ VC1
Definition: mythcodeccontext.h:101
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:210
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:58
MythCodecContext
Definition: mythcodeccontext.h:51
VideoFrameType
VideoFrameType
Definition: mythframe.h:18
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:85
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:267
MythCodecContext::H264
@ H264
Definition: mythcodeccontext.h:83