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  {
84  // Direct rendering needs interop support
85  MythPlayerUI* player = GetPlayerUI(*Context);
87  return failure;
88  }
89 
90  // look for a decoder
91  QString name = QString((*Codec)->name) + "_mmal";
92  if (name == "mpeg2video_mmal")
93  name = "mpeg2_mmal";
94  AVCodec *codec = avcodec_find_decoder_by_name(name.toLocal8Bit());
95  AvFormatDecoder *decoder = dynamic_cast<AvFormatDecoder*>(reinterpret_cast<DecoderBase*>((*Context)->opaque));
96  if (!codec || !decoder)
97  {
98  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to find %1").arg(name));
99  return failure;
100  }
101 
102  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found MMAL/FFmpeg decoder '%1'").arg(name));
103  *Codec = codec;
104  decoder->CodecMap()->FreeCodecContext(Stream);
105  *Context = decoder->CodecMap()->GetCodecContext(Stream, *Codec);
106  (*Context)->pix_fmt = decodeonly ? (*Context)->pix_fmt : AV_PIX_FMT_MMAL;
107  return success;
108 }
109 
110 void MythMMALContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
111 {
113  {
114  DirectRendering = false;
115  return;
116  }
117  else if (codec_is_mmal(m_codecID))
118  {
119  Context->get_format = MythMMALContext::GetFormat;
120  DirectRendering = false;
121  return;
122  }
123 
124  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
125 }
126 
128 {
130  return GetBuffer(Context, Frame, AvFrame, 0);
131  else if (codec_is_mmal(m_codecID))
132  return GetBuffer2(Context, Frame, AvFrame, 0);
133  return false;
134 }
135 
136 
138 {
139  if (!Context)
140  return -1;
141 
143  return 0;
144 
145  if (!codec_is_mmal(m_codecID) || Context->pix_fmt != AV_PIX_FMT_MMAL)
146  return -1;
147 
150  return m_interop ? 0 : -1;
151 }
152 
153 void MythMMALContext::SetDecoderOptions(AVCodecContext *Context, AVCodec *Codec)
154 {
155  if (!(codec_is_mmal(m_codecID)))
156  return;
157  if (!(Context && Codec))
158  return;
159  if (!(Codec->priv_class && Context->priv_data))
160  return;
161  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Setting number of extra buffers to 8");
162  av_opt_set(Context->priv_data, "extra_buffers", "8", 0);
163 }
164 
165 bool MythMMALContext::GetBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
166 {
167  // Sanity checks
168  if (!Context || !AvFrame || !Frame)
169  return false;
170 
171  // Ensure we can render this format
172  AvFormatDecoder *decoder = static_cast<AvFormatDecoder*>(Context->opaque);
173  VideoFrameType type = MythAVUtil::PixelFormatToFrameType(static_cast<AVPixelFormat>(AvFrame->format));
174  const VideoFrameTypes* supported = decoder->GetPlayer()->DirectRenderFormats();
175  auto foundIt = std::find(supported->cbegin(), supported->cend(), type);
176  // No fallback currently (unlikely)
177  if (foundIt == supported->end())
178  return false;
179 
180  // Re-allocate if necessary
181  if ((Frame->m_type != type) || (Frame->m_width != AvFrame->width) || (Frame->m_height != AvFrame->height))
182  if (!VideoBuffers::ReinitBuffer(Frame, type, decoder->GetVideoCodecID(), AvFrame->width, AvFrame->height))
183  return false;
184 
185  // Copy data
186  uint count = MythVideoFrame::GetNumPlanes(Frame->m_type);
187  for (uint plane = 0; plane < count; ++plane)
188  {
189  MythVideoFrame::CopyPlane(Frame->m_buffer + Frame->m_offsets[plane], Frame->m_pitches[plane],
190  AvFrame->data[plane], AvFrame->linesize[plane],
191  MythVideoFrame::GetPitchForPlane(Frame->m_type, AvFrame->width, plane),
192  MythVideoFrame::GetHeightForPlane(Frame->m_type, AvFrame->height, plane));
193  }
194 
195  AvFrame->reordered_opaque = Context->reordered_opaque;
196  return true;
197 }
198 
199 bool MythMMALContext::GetBuffer2(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
200 {
201  // Sanity checks
202  if (!Context || !AvFrame || !Frame || !m_interop)
203  {
204  LOG(VB_GENERAL, LOG_ERR, LOC + "Error");
205  return false;
206  }
207 
208  // MMAL?
209  if (Frame->m_type != FMT_MMAL || static_cast<AVPixelFormat>(AvFrame->format) != AV_PIX_FMT_MMAL)
210  {
211  LOG(VB_GENERAL, LOG_ERR, LOC + "Not an MMAL frame");
212  return false;
213  }
214 
215  Frame->m_width = AvFrame->width;
216  Frame->m_height = AvFrame->height;
217  Frame->m_pixFmt = Context->pix_fmt;
218  Frame->m_swPixFmt = Context->sw_pix_fmt;
219  Frame->m_directRendering = 1;
220  AvFrame->opaque = Frame;
221  AvFrame->reordered_opaque = Context->reordered_opaque;
222 
223  // Frame->data[3] holds MMAL_BUFFER_HEADER_T
224  Frame->m_buffer = AvFrame->data[3];
225  // Retain the buffer so it is not released before we display it
226  Frame->m_priv[0] = reinterpret_cast<unsigned char*>(av_buffer_ref(AvFrame->buf[0]));
227  // Add interop
228  Frame->m_priv[1] = reinterpret_cast<unsigned char*>(m_interop);
229  // Set the release method
230  AvFrame->buf[1] = av_buffer_create(reinterpret_cast<uint8_t*>(Frame), 0, MythCodecContext::ReleaseBuffer,
231  static_cast<AvFormatDecoder*>(Context->opaque), 0);
232  return true;
233 }
234 
235 AVPixelFormat MythMMALContext::GetFormat(AVCodecContext*, const AVPixelFormat *PixFmt)
236 {
237  while (*PixFmt != AV_PIX_FMT_NONE)
238  {
239  if (*PixFmt == AV_PIX_FMT_MMAL)
240  return AV_PIX_FMT_MMAL;
241  PixFmt++;
242  }
243  return AV_PIX_FMT_NONE;
244 }
245 
247 {
248  static QMutex lock(QMutex::Recursive);
249  QMutexLocker locker(&lock);
250  static bool s_checked = false;
251  static bool s_available = false;
252 
253  if (s_checked)
254  return s_available;
255  s_checked = true;
256 
257  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
258  if (profiles.isEmpty())
259  return s_available;
260 
261  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available MMAL decoders:");
262  s_available = true;
263  QSize size{0, 0};
264  for (auto profile : qAsConst(profiles))
265  LOG(VB_GENERAL, LOG_INFO, LOC + MythCodecContext::GetProfileDescription(profile, size));
266  return s_available;
267 }
268 
269 void MythMMALContext::GetDecoderList(QStringList &Decoders)
270 {
271  const MMALProfiles& profiles = MythMMALContext::GetProfiles();
272  if (profiles.isEmpty())
273  return;
274 
275  QSize size(0, 0);
276  Decoders.append("MMAL:");
277  for (MythCodecContext::CodecProfile profile : profiles)
278  Decoders.append(MythCodecContext::GetProfileDescription(profile, size));
279 }
280 
281 // Broadcom
282 extern "C" {
283 #include "interface/vmcs_host/vc_vchi_gencmd.h"
284 }
285 
287 {
288  static QMutex lock(QMutex::Recursive);
289  static bool s_initialised = false;
290  static MMALProfiles s_profiles;
291 
292  QMutexLocker locker(&lock);
293  if (s_initialised)
294  return s_profiles;
295  s_initialised = true;
296 
297  static const QPair<QString, MythCodecContext::CodecProfile> s_map[] =
298  {
299  { "MPG2", MythCodecContext::MPEG2 },
300  { "MPG4", MythCodecContext::MPEG4 },
301  { "WVC1", MythCodecContext::VC1 },
302  { "H264", MythCodecContext::H264 }
303  };
304 
305  vcos_init();
306  VCHI_INSTANCE_T vchi_instance;
307  if (vchi_initialise(&vchi_instance) != 0)
308  return s_profiles;
309  if (vchi_connect(nullptr, 0, vchi_instance) != 0)
310  return s_profiles;
311  VCHI_CONNECTION_T *vchi_connection = nullptr;
312  vc_vchi_gencmd_init(vchi_instance, &vchi_connection, 1 );
313 
314  for (auto profile : s_map)
315  {
316  char command[32];
317  char* response = nullptr;
318  int responsesize = 0;
319  QString msg = QString("codec_enabled %1").arg(profile.first);
320  if (!vc_gencmd(command, sizeof(command), msg.toLocal8Bit().constData()))
321  vc_gencmd_string_property(command, profile.first.toLocal8Bit().constData(), &response, &responsesize);
322 
323  if (response && responsesize && qstrcmp(response, "enabled") == 0)
324  s_profiles.append(profile.second);
325  }
326 
327  vc_gencmd_stop();
328  vchi_disconnect(vchi_instance);
329 
330  return s_profiles;
331 }
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:167
MythVideoFrame::GetPitchForPlane
static int GetPitchForPlane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:287
mythplayerui.h
MythMMALContext::SetDecoderOptions
void SetDecoderOptions(AVCodecContext *Context, AVCodec *Codec) override
Definition: mythmmalcontext.cpp:153
MythCodecContext::DestroyInterop
static void DestroyInterop(MythOpenGLInterop *Interop)
Definition: mythcodeccontext.cpp:453
MythCodecMap::GetCodecContext
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
Definition: mythavutil.cpp:241
MythCodecContext::NoProfile
@ NoProfile
Definition: mythcodeccontext.h:56
MythCodecContext::CodecProfile
CodecProfile
Definition: mythcodeccontext.h:55
Frame
Definition: zmdefines.h:94
arg
arg(title).arg(filename).arg(doDelete))
Context
QHash< QString, Action * > Context
Definition: action.h:77
MythCodecContext::InitVideoCodec
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
Definition: mythcodeccontext.cpp:292
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:165
AvFormatDecoder::CodecMap
MythCodecMap * CodecMap(void)
Definition: avformatdecoder.cpp:378
MythCodecID
MythCodecID
Definition: mythcodecid.h:11
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
MythPlayerUI
Definition: mythplayerui.h:12
Decoder
Definition: decoder.h:66
MythMMALInterop::Create
static MythMMALInterop * Create(MythRenderOpenGL *Context, Type InteropType)
Definition: mythmmalinterop.cpp:51
hardwareprofile.scan.profile
profile
Definition: scan.py:99
MythPlayer::DirectRenderFormats
const VideoFrameTypes * DirectRenderFormats(void)
Return a list of frame types that can be rendered directly.
Definition: mythplayer.cpp:674
MythOpenGLInterop::Unsupported
@ Unsupported
Definition: mythopenglinterop.h:31
MythVideoFrame::CopyPlane
static void CopyPlane(uint8_t *To, int ToPitch, const uint8_t *From, int FromPitch, int PlaneWidth, int PlaneHeight)
Definition: mythframe.cpp:185
MythCodecContext::ReleaseBuffer
static void ReleaseBuffer(void *Opaque, uint8_t *Data)
Definition: mythcodeccontext.cpp:403
MythOpenGLInterop::MMAL
@ MMAL
Definition: mythopenglinterop.h:40
MythMMALContext::GetFormat
static enum AVPixelFormat GetFormat(AVCodecContext *, const AVPixelFormat *PixFmt)
Definition: mythmmalcontext.cpp:235
VideoFrameTypes
std::vector< VideoFrameType > VideoFrameTypes
Definition: mythframe.h:78
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:110
MythOpenGLInterop::GetInteropType
static Type GetInteropType(VideoFrameType Format, MythPlayerUI *Player)
Check whether we support direct rendering for the given VideoFrameType.
Definition: mythopenglinterop.cpp:74
MythCodecMap::FreeCodecContext
void FreeCodecContext(const AVStream *Stream)
Definition: mythavutil.cpp:289
MythCodecContext::MPEG4
@ MPEG4
Definition: mythcodeccontext.h:65
MythMMALContext::HaveMMAL
static bool HaveMMAL(void)
Definition: mythmmalcontext.cpp:246
AvFormatDecoder
A decoder for media files.
Definition: avformatdecoder.h:87
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:127
MythCodecContext::MPEG2
@ MPEG2
Definition: mythcodeccontext.h:58
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:74
MythMMALContext::GetProfiles
static const MMALProfiles & GetProfiles(void)
Definition: mythmmalcontext.cpp:286
MythRenderOpenGL
Definition: mythrenderopengl.h:99
MythVideoFrame::GetHeightForPlane
static int GetHeightForPlane(VideoFrameType Type, int Height, uint Plane)
Definition: mythframe.h:241
MythMMALContext::HwDecoderInit
int HwDecoderInit(AVCodecContext *Context) override
Definition: mythmmalcontext.cpp:137
MythCodecContext::VC1
@ VC1
Definition: mythcodeccontext.h:101
avformatdecoder.h
mythmmalcontext.h
MythRenderOpenGL::GetOpenGLRender
static MythRenderOpenGL * GetOpenGLRender(void)
Definition: mythrenderopengl.cpp:66
MythVideoFrame::GetNumPlanes
static uint GetNumPlanes(VideoFrameType Type)
Definition: mythframe.h:197
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:199
AvFormatDecoder::GetVideoCodecID
MythCodecID GetVideoCodecID(void) const override
Definition: avformatdecoder.h:142
VideoBuffers::ReinitBuffer
static bool ReinitBuffer(MythVideoFrame *Frame, VideoFrameType Type, MythCodecID CodecID, int Width, int Height)
Definition: videobuffers.cpp:991
FMT_MMAL
@ FMT_MMAL
Definition: mythframe.h:55
MythCodecContext
Definition: mythcodeccontext.h:52
VideoFrameType
VideoFrameType
Definition: mythframe.h:16
MythCodecContext::GetProfileDescription
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
Definition: mythcodeccontext.cpp:763
kCodec_MPEG1_MMAL_DEC
@ kCodec_MPEG1_MMAL_DEC
Definition: mythcodecid.h:261
MythVideoFrame
Definition: mythframe.h:83
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:121
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:493
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:269
DecoderBase::GetPlayer
MythPlayer * GetPlayer()
Definition: decoderbase.h:152
MythCodecContext::H264
@ H264
Definition: mythcodeccontext.h:83