MythTV master
mainvisual.cpp
Go to the documentation of this file.
1// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
2//
3// Use, modification and distribution is allowed without limitation,
4// warranty, or liability of any kind.
5//
6
7// C++
8#include <algorithm>
9#include <cmath>
10#include <cstdio>
11#include <iostream>
12
13// Qt
14#include <QPainter>
15
16// MythTV
20
21// mythmusic
22#include "constants.h"
23#include "mainvisual.h"
24#include "musicplayer.h"
25#include "visualize.h"
26
27// fast inlines
28#include "inlines.h"
29
30
32// MainVisual
33
35 : QObject(nullptr), m_visualizerVideo(visualizer)
36{
37 setObjectName("MainVisual");
38
39 for (const VisFactory* pVisFactory = VisFactory::VisFactories();
40 pVisFactory; pVisFactory = pVisFactory->next())
41 {
42 pVisFactory->plugins(&m_visualizers);
43 }
44 m_visualizers.sort();
45
46 m_currentVisualizer = gCoreContext->GetNumSetting("MusicLastVisualizer", 0);
47
49
50 m_updateTimer = new QTimer(this);
51 m_updateTimer->setInterval(1000 / m_fps);
52 m_updateTimer->setSingleShot(true);
54}
55
57{
58 m_updateTimer->stop();
59 delete m_updateTimer;
60
61 delete m_vis;
62
63 while (!m_nodes.empty())
64 delete m_nodes.takeLast();
65
66 gCoreContext->SaveSetting("MusicLastVisualizer", m_currentVisualizer);
67}
68
70{
71 m_updateTimer->stop();
72
73 if (m_vis)
74 {
75 delete m_vis;
76 m_vis = nullptr;
77 }
78}
79
80void MainVisual::setVisual(const QString &name)
81{
82 m_updateTimer->stop();
83
84 int index = m_visualizers.indexOf(name);
85
86 if (index == -1)
87 {
88 LOG(VB_GENERAL, LOG_ERR, QString("MainVisual: visualizer %1 not found!").arg(name));
89 return;
90 }
91
92 m_currentVisualizer = index;
93
95
96 QString visName;
97 QString pluginName;
98
99 if (name.contains("-"))
100 {
101 visName = name.section('-', 0, 0);
102 pluginName = name.section('-', 1, 1);
103 }
104 else
105 {
106 visName = name;
107 pluginName.clear();
108 }
109
110 if (m_vis)
111 {
112 delete m_vis;
113 m_vis = nullptr;
114 }
115
116 for (const VisFactory* pVisFactory = VisFactory::VisFactories();
117 pVisFactory; pVisFactory = pVisFactory->next())
118 {
119 if (pVisFactory->name() == visName)
120 {
121 m_vis = pVisFactory->create(this, pluginName);
125
126 QMutexLocker locker(mutex());
127 prepare();
128
129 break;
130 }
131 }
132
133 // force an update
134 m_updateTimer->start(1000 / m_fps);
135}
136
137// Caller holds mutex() lock
139{
140 while (!m_nodes.empty())
141 delete m_nodes.takeLast();
142}
143
144// This is called via : mythtv/libs/libmyth/output.cpp :: OutputListeners::dispatchVisual
145// from : mythtv/libs/libmyth/audio/audiooutputbase.cpp :: AudioOutputBase::AddData
146// Caller holds mutex() lock
147void MainVisual::add(const void *buffer, unsigned long b_len,
148 std::chrono::milliseconds timecode,
149 int source_channels, int bits_per_sample)
150{
151 unsigned long len = b_len;
152 short *l = nullptr;
153 short *r = nullptr;
154 bool s32le = false;
155
156 // 24 bit samples are stored as s32le in the buffer.
157 // 32 bit samples are stored as float. Flag the difference.
158 if (bits_per_sample == 24)
159 {
160 s32le = true;
161 bits_per_sample = 32;
162 }
163
164 // len is length of buffer in fully converted samples
165 len /= source_channels;
166 len /= (bits_per_sample / 8);
167
168 len = std::min(len, m_samples);
169
170 int cnt = len;
171
172 if (source_channels == 2)
173 {
174 l = new short[len];
175 r = new short[len];
176
177 if (bits_per_sample == 8)
178 stereo16_from_stereopcm8(l, r, (uchar *) buffer, cnt);
179 else if (bits_per_sample == 16)
180 stereo16_from_stereopcm16(l, r, (short *) buffer, cnt);
181 else if (s32le)
182 stereo16_from_stereopcm32(l, r, (int *) buffer, cnt);
183 else if (bits_per_sample == 32)
184 stereo16_from_stereopcmfloat(l, r, (float *) buffer, cnt);
185 else
186 len = 0;
187 }
188 else if (source_channels == 1)
189 {
190 l = new short[len];
191
192 if (bits_per_sample == 8)
193 mono16_from_monopcm8(l, (uchar *) buffer, cnt);
194 else if (bits_per_sample == 16)
195 mono16_from_monopcm16(l, (short *) buffer, cnt);
196 else if (s32le)
197 mono16_from_monopcm32(l, (int *) buffer, cnt);
198 else if (bits_per_sample == 32)
199 mono16_from_monopcmfloat(l, (float *) buffer, cnt);
200 else
201 len = 0;
202 }
203 else
204 {
205 len = 0;
206 }
207
208 m_nodes.append(new VisualNode(l, r, len, timecode));
209}
210
212{
213 VisualNode *node = nullptr;
214 if (m_playing && gPlayer->getOutput())
215 {
216 QMutexLocker locker(mutex());
217 std::chrono::milliseconds timestamp = gPlayer->getOutput()->GetAudiotime();
218 while (m_nodes.size() > 1)
219 {
220 // LOG(VB_PLAYBACK, LOG_DEBUG,
221 // QString("\tMV %1 first > %2 timestamp").
222 // arg(m_nodes.first()->m_offset.count()).arg(timestamp.count()));
223 if (m_nodes.first()->m_offset >= timestamp + 5s)
224 {
225 // REW seek: drain buffer and start over
226 }
227 else if (m_nodes.first()->m_offset > timestamp)
228 {
229 break; // at current time
230 }
231
232 if (m_vis)
234
235 delete m_nodes.first();
236 m_nodes.removeFirst();
237 }
238
239 if (!m_nodes.isEmpty())
240 node = m_nodes.first();
241 }
242
243 bool stop = true;
244 if (m_vis)
245 stop = m_vis->process(node);
246
247 if (m_vis && !stop)
248 {
249 QPainter p(&m_pixmap);
252 }
253
254 if (m_playing && !stop)
255 m_updateTimer->start();
256}
257
258void MainVisual::resize(const QSize size)
259{
260 m_pixmap = QPixmap(size);
262
263 if (m_vis)
264 m_vis->resize(size);
265}
266
267void MainVisual::customEvent(QEvent *event)
268{
269 if ((event->type() == OutputEvent::kPlaying) ||
270 (event->type() == OutputEvent::kInfo) ||
271 (event->type() == OutputEvent::kBuffering) ||
272 (event->type() == OutputEvent::kPaused))
273 {
274 m_playing = true;
275 if (!m_updateTimer->isActive())
276 m_updateTimer->start();
277 }
278 else if ((event->type() == OutputEvent::kStopped) ||
279 (event->type() == OutputEvent::kError))
280 {
281 m_playing = false;
282 }
283}
virtual std::chrono::milliseconds GetAudiotime(void)=0
void timeout()
Definition: mainvisual.cpp:211
void customEvent(QEvent *event) override
Definition: mainvisual.cpp:267
unsigned long m_samples
Definition: mainvisual.h:74
void add(const void *buffer, unsigned long b_len, std::chrono::milliseconds timecode, int source_channel, int bits_per_sample) override
Definition: mainvisual.cpp:147
~MainVisual() override
Definition: mainvisual.cpp:56
bool m_playing
Definition: mainvisual.h:72
QList< VisualNode * > m_nodes
Definition: mainvisual.h:71
void prepare(void) override
Definition: mainvisual.cpp:138
MythUIVideo * m_visualizerVideo
Definition: mainvisual.h:66
void stop(void)
Definition: mainvisual.cpp:69
MainVisual(MythUIVideo *visualizer)
Definition: mainvisual.cpp:34
QPixmap m_pixmap
Definition: mainvisual.h:70
QTimer * m_updateTimer
Definition: mainvisual.h:75
int m_currentVisualizer
Definition: mainvisual.h:68
void setVisual(const QString &name)
Definition: mainvisual.cpp:80
VisualBase * m_vis
Definition: mainvisual.h:69
void resize(QSize size)
Definition: mainvisual.cpp:258
QStringList m_visualizers
Definition: mainvisual.h:67
AudioOutput * getOutput(void)
Definition: musicplayer.h:128
void SaveSetting(const QString &key, int newValue)
int GetNumSetting(const QString &key, int defaultval=0)
QMutex * mutex()
Definition: visual.h:26
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Definition: mythuitype.cpp:885
Video widget, displays raw image data.
Definition: mythuivideo.h:15
QColor GetBackgroundColor(void)
Definition: mythuivideo.h:23
void UpdateFrame(MythImage *image)
Definition: mythuivideo.cpp:49
static const Type kInfo
Definition: output.h:65
static const Type kPlaying
Definition: output.h:63
static const Type kStopped
Definition: output.h:67
static const Type kPaused
Definition: output.h:66
static const Type kError
Definition: output.h:68
static const Type kBuffering
Definition: output.h:64
const VisFactory * next() const
Definition: visualize.h:98
static const VisFactory * VisFactories()
Definition: visualize.h:102
virtual bool draw(QPainter *, const QColor &)=0
virtual bool process(VisualNode *node)=0
virtual bool processUndisplayed(VisualNode *)
Definition: visualize.h:73
virtual unsigned long getDesiredSamples(void)
Definition: visualize.h:83
virtual int getDesiredFPS(void)
Definition: visualize.h:81
virtual void resize(const QSize &size)=0
static void stereo16_from_stereopcmfloat(short *l, short *r, float *s, long cnt)
Definition: inlines.h:94
static void mono16_from_monopcmfloat(short *l, float *s, long cnt)
Definition: inlines.h:167
static void stereo16_from_stereopcm32(short *l, short *r, int *s, long cnt)
Definition: inlines.h:82
static void mono16_from_monopcm32(short *l, int *s, long cnt)
Definition: inlines.h:158
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
static void mono16_from_monopcm16(short *l, const short *s, long cnt)
static void mono16_from_monopcm8(short *l, const uchar *c, long cnt)
static void stereo16_from_stereopcm8(short *l, short *r, const uchar *c, long cnt)
static void stereo16_from_stereopcm16(short *l, short *r, const short *s, long cnt)