MythTV  master
mythvideooutnull.cpp
Go to the documentation of this file.
1 #include <map>
2 #include <iostream>
3 using namespace std;
4 
5 #include "mythlogging.h"
6 #include "mythvideooutnull.h"
7 #include "videodisplayprofile.h"
8 
9 const int kNeedFreeFrames = 1;
10 const int kPrebufferFramesNormal = 12;
11 const int kPrebufferFramesSmall = 4;
12 
14 {
15  Options.renderers->append("null");
16  (*Options.safe_renderers)["dummy"].append("null");
17  (*Options.safe_renderers)["nuppel"].append("null");
18  if (Options.decoders->contains("ffmpeg"))
19  (*Options.safe_renderers)["ffmpeg"].append("null");
20 #ifdef USING_VTB
21  if (Options.decoders->contains("vtb-dec"))
22  (*Options.safe_renderers)["vtb-dec"].append("null");
23 #endif
24 #ifdef USING_VDPAU
25  if (Options.decoders->contains("vdpau-dec"))
26  (*Options.safe_renderers)["vdpau-dec"].append("null");
27 #endif
28 #ifdef USING_NVDEC
29  if (Options.decoders->contains("nvdec-dec"))
30  (*Options.safe_renderers)["nvdec-dec"].append("null");
31 #endif
32 #ifdef USING_VAAPI
33  if (Options.decoders->contains("vaapi-dec"))
34  (*Options.safe_renderers)["vaapi-dec"].append("null");
35 #endif
36 #ifdef USING_MEDIACODEC
37  if (Options.decoders->contains("mediacodec-dec"))
38  (*Options.safe_renderers)["mediacodec-dec"].append("null");
39 #endif
40 #ifdef USING_V4L2
41  if (Options.decoders->contains("v4l2-dec"))
42  (*Options.safe_renderers)["v4l2-dec"].append("null");
43 #endif
44 #ifdef USING_MMAL
45  if (Options.decoders->contains("mmal-dec"))
46  (*Options.safe_renderers)["mmal-dec"].append("null");
47 #endif
48  Options.priorities->insert("null", 10);
49 }
50 
52 {
53  LOG(VB_PLAYBACK, LOG_INFO, "VideoOutputNull()");
54  memset(&m_avPauseFrame, 0, sizeof(m_avPauseFrame));
55 }
56 
58 {
59  LOG(VB_PLAYBACK, LOG_INFO, "~VideoOutputNull()");
60  QMutexLocker locker(&m_globalLock);
61 
62  if (m_avPauseFrame.buf)
63  {
64  delete [] m_avPauseFrame.buf;
65  memset(&m_avPauseFrame, 0, sizeof(m_avPauseFrame));
66  }
67 
68  m_videoBuffers.DeleteBuffers();
69 }
70 
72 {
73  if (m_avPauseFrame.buf)
74  {
75  delete [] m_avPauseFrame.buf;
76  m_avPauseFrame.buf = nullptr;
77  }
78 
79  init(&m_avPauseFrame, FMT_YV12,
80  new unsigned char[m_videoBuffers.GetScratchFrame()->size + 128],
81  m_videoBuffers.GetScratchFrame()->width,
82  m_videoBuffers.GetScratchFrame()->height,
83  m_videoBuffers.GetScratchFrame()->size);
84 
85  m_avPauseFrame.frameNumber = m_videoBuffers.GetScratchFrame()->frameNumber;
86  m_avPauseFrame.frameCounter = m_videoBuffers.GetScratchFrame()->frameCounter;
87  clear(&m_avPauseFrame);
88 }
89 
90 bool MythVideoOutputNull::InputChanged(const QSize &video_dim_buf,
91  const QSize &video_dim_disp,
92  float aspect,
93  MythCodecID av_codec_id,
94  bool &aspect_only,
95  MythMultiLocker* Locks,
96  int ReferenceFrames,
97  bool ForceChange)
98 {
99  LOG(VB_PLAYBACK, LOG_INFO,
100  QString("InputChanged(WxH = %1x%2, aspect = %3)")
101  .arg(video_dim_disp.width())
102  .arg(video_dim_disp.height()).arg(static_cast<qreal>(aspect)));
103 
104  if (!codec_is_std(av_codec_id))
105  {
106  LOG(VB_GENERAL, LOG_ERR, QString("VideoOutputNull::InputChanged(): "
107  "new video codec is not supported."));
108  m_errorState = kError_Unknown;
109  return false;
110  }
111 
112  QMutexLocker locker(&m_globalLock);
113 
114  if (video_dim_disp == m_window.GetVideoDim())
115  {
116  m_videoBuffers.Clear();
117  MoveResize();
118  return true;
119  }
120 
121  MythVideoOutput::InputChanged(video_dim_buf, video_dim_disp,
122  aspect, av_codec_id, aspect_only, Locks,
123  ReferenceFrames, ForceChange);
124  m_videoBuffers.DeleteBuffers();
125 
126  MoveResize();
127 
128  const QSize video_dim = m_window.GetVideoDim();
129 
130  bool ok = m_videoBuffers.CreateBuffers(FMT_YV12, video_dim.width(), video_dim.height());
131  if (!ok)
132  {
133  LOG(VB_GENERAL, LOG_ERR, "VideoOutputNull::InputChanged(): "
134  "Failed to recreate buffers");
135  m_errorState = kError_Unknown;
136  }
137  else
138  {
139  CreatePauseFrame();
140  }
141 
142  if (m_dbDisplayProfile)
143  m_dbDisplayProfile->SetVideoRenderer("null");
144 
145  return ok;
146 }
147 
148 bool MythVideoOutputNull::Init(const QSize &video_dim_buf, const QSize &video_dim_disp,
149  float aspect, MythDisplay *Display,
150  const QRect &win_rect, MythCodecID codec_id)
151 {
152  if ((video_dim_disp.width() <= 0) || (video_dim_disp.height() <= 0))
153  return false;
154 
155  if (!codec_is_std(codec_id))
156  {
157  LOG(VB_GENERAL, LOG_ERR,
158  QString("Cannot create VideoOutputNull for codec %1")
159  .arg(toString(codec_id)));
160  return false;
161  }
162 
163  QMutexLocker locker(&m_globalLock);
164 
165  MythVideoOutput::Init(video_dim_buf, video_dim_disp,
166  aspect, Display, win_rect, codec_id);
167 
168  m_videoBuffers.Init(VideoBuffers::GetNumBuffers(FMT_YV12), true, kNeedFreeFrames,
170 
171  // XXX should this be GetActualVideoDim() ?
172  const QSize video_dim = m_window.GetVideoDim();
173 
174  if (!m_videoBuffers.CreateBuffers(FMT_YV12, video_dim.width(), video_dim.height()))
175  return false;
176 
177  CreatePauseFrame();
178 
179  if (m_dbDisplayProfile)
180  m_dbDisplayProfile->SetVideoRenderer("null");
181 
182  MoveResize();
183 
184  return true;
185 }
186 
187 void MythVideoOutputNull::EmbedInWidget(const QRect &rect)
188 {
189  QMutexLocker locker(&m_globalLock);
190  if (!m_window.IsEmbedding())
192 }
193 
195 {
196  QMutexLocker locker(&m_globalLock);
197  if (m_window.IsEmbedding())
199 }
200 
201 void MythVideoOutputNull::SetDeinterlacing(bool Enable, bool DoubleRate, MythDeintType Force /*=DEINT_NONE*/)
202 {
203  if (DEINT_NONE != Force)
204  {
205  MythVideoOutput::SetDeinterlacing(Enable, DoubleRate, Force);
206  return;
207  }
208  m_videoBuffers.SetDeinterlacing(DEINT_NONE, DEINT_NONE, m_videoCodecID);
209 }
210 
212 {
213  (void)osd;
214  (void)t;
215 
216  if (!buffer)
217  buffer = m_videoBuffers.GetScratchFrame();
218 
219  m_framesPlayed = buffer->frameNumber + 1;
220 }
221 
223 {
224 }
225 
226 void MythVideoOutputNull::UpdatePauseFrame(int64_t &disp_timecode, FrameScanType /*Scan*/)
227 {
228  QMutexLocker locker(&m_globalLock);
229 
230  // Try used frame first, then fall back to scratch frame.
231  m_videoBuffers.BeginLock(kVideoBuffer_used);
232  VideoFrame *used_frame = nullptr;
233  if (m_videoBuffers.Size(kVideoBuffer_used) > 0)
234  used_frame = m_videoBuffers.Head(kVideoBuffer_used);
235 
236  if (used_frame)
237  CopyFrame(&m_avPauseFrame, used_frame);
238  m_videoBuffers.EndLock();
239 
240  if (!used_frame)
241  {
242  m_videoBuffers.GetScratchFrame()->frameNumber = m_framesPlayed - 1;
243  CopyFrame(&m_avPauseFrame, m_videoBuffers.GetScratchFrame());
244  }
245 
246  disp_timecode = m_avPauseFrame.disp_timecode;
247 }
248 
250  const PIPMap & /*PipPlayers*/, FrameScanType Scan)
251 {
252  if (Frame && !Frame->dummy)
253  m_deinterlacer.Filter(Frame, Scan, nullptr);
254 }
void UpdatePauseFrame(int64_t &disp_timecode, FrameScanType Scan=kScan_Progressive) override
const int kPrebufferFramesNormal
QMap< MythPlayer *, PIPLocation > PIPMap
Definition: mythvideoout.h:32
QString toString(MarkTypes type)
bool Init(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, MythDisplay *Display, const QRect &win_rect, MythCodecID codec_id) override
MythCodecID
Definition: mythcodecid.h:10
static void GetRenderOptions(RenderOptions &Options)
void StopEmbedding(void) override
virtual bool InputChanged(const QSize &VideoDim, const QSize &VideoDispDim, float VideoAspect, MythCodecID CodecID, bool &AspectChanged, MythMultiLocker *Locks, int ReferenceFrames, bool ForceChange)
Tells video output to discard decoded frames and wait for new ones.
void PrepareFrame(VideoFrame *buffer, FrameScanType t, OSD *osd) override
FrameScanType
Definition: videoouttypes.h:78
MythDeintType
Definition: mythframe.h:120
const int kNeedFreeFrames
bool InputChanged(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, MythCodecID av_codec_id, bool &aspect_only, MythMultiLocker *Locks, int ReferenceFrames, bool ForceChange) override
Tells video output to discard decoded frames and wait for new ones.
QMap< QString, QStringList > * safe_renderers
virtual bool Init(const QSize &VideoDim, const QSize &VideoDispDim, float VideoAspect, MythDisplay *Display, const QRect &WindowRect, MythCodecID CodecID)
QStringList * renderers
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:846
virtual void EmbedInWidget(const QRect &EmbedRect)
Tells video output to embed video in an existing window.
virtual void SetDeinterlacing(bool Enable, bool DoubleRate, MythDeintType Force=DEINT_NONE)
virtual void StopEmbedding(void)
static void init(VideoFrame *vf, VideoFrameType _codec, unsigned char *_buf, int _width, int _height, int _size, const int *p=nullptr, const int *o=nullptr, float _aspect=-1.0F, double _rate=-1.0F, int _aligned=MYTH_WIDTH_ALIGNMENT)
Definition: mythframe.h:231
long long frameNumber
Definition: mythframe.h:147
~MythVideoOutputNull() override
QStringList * decoders
void ProcessFrame(VideoFrame *frame, OSD *osd, const PIPMap &pipPlayers, FrameScanType scan) override
const int kPrebufferFramesSmall
static uint GetNumBuffers(int PixelFormat, int MaxReferenceFrames=16, bool Decoder=false)
void EmbedInWidget(const QRect &rect) override
Tells video output to embed video in an existing window.
void SetDeinterlacing(bool Enable, bool DoubleRate, MythDeintType Force=DEINT_NONE) override
Definition: osd.h:131
QMap< QString, uint > * priorities
void Show(FrameScanType scan) override
#define codec_is_std(id)
Definition: mythcodecid.h:293
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23