00001
00002
00003
00004
00005
00006
00007
00008 #include <cmath>
00009 #include <cstdio>
00010
00011
00012 #include <algorithm>
00013 #include <iostream>
00014 using namespace std;
00015
00016
00017 #include <QPainter>
00018
00019
00020 #include <mythuivideo.h>
00021
00022
00023 #include "visualize.h"
00024 #include "mainvisual.h"
00025 #include "constants.h"
00026 #include "musicplayer.h"
00027
00028
00029 #include "inlines.h"
00030
00031
00033
00034
00035 MainVisual::MainVisual(MythUIVideo *visualizer)
00036 : QObject(NULL), MythTV::Visual(), m_visualizerVideo(visualizer),
00037 m_vis(NULL), m_playing(false), m_fps(20), m_samples(SAMPLES_DEFAULT_SIZE),
00038 m_updateTimer(NULL)
00039 {
00040 setObjectName("MainVisual");
00041
00042 for (const VisFactory* pVisFactory = VisFactory::VisFactories();
00043 pVisFactory; pVisFactory = pVisFactory->next())
00044 {
00045 pVisFactory->plugins(&m_visualizers);
00046 }
00047 m_visualizers.sort();
00048
00049 m_currentVisualizer = gCoreContext->GetNumSetting("MusicLastVisualizer", 0);
00050
00051 resize(m_visualizerVideo->GetArea().size());
00052
00053 m_updateTimer = new QTimer(this);
00054 m_updateTimer->setInterval(1000 / m_fps);
00055 m_updateTimer->setSingleShot(true);
00056 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(timeout()));
00057 }
00058
00059 MainVisual::~MainVisual()
00060 {
00061 m_updateTimer->stop();
00062 delete m_updateTimer;
00063
00064 if (m_vis)
00065 delete m_vis;
00066
00067 while (!m_nodes.empty())
00068 delete m_nodes.takeLast();
00069
00070 gCoreContext->SaveSetting("MusicLastVisualizer", m_currentVisualizer);
00071 }
00072
00073 void MainVisual::stop(void)
00074 {
00075 m_updateTimer->stop();
00076
00077 if (m_vis)
00078 {
00079 delete m_vis;
00080 m_vis = NULL;
00081 }
00082 }
00083
00084 void MainVisual::setVisual(const QString &name)
00085 {
00086 m_updateTimer->stop();
00087
00088 int index = m_visualizers.indexOf(name);
00089
00090 if (index == -1)
00091 {
00092 LOG(VB_GENERAL, LOG_ERR, QString("MainVisual: visualizer %1 not found!").arg(name));
00093 return;
00094 }
00095
00096 m_currentVisualizer = index;
00097
00098 m_pixmap.fill(m_visualizerVideo->GetBackgroundColor());
00099
00100 QString visName, pluginName;
00101
00102 if (name.contains("-"))
00103 {
00104 visName = name.section('-', 0, 0);
00105 pluginName = name.section('-', 1, 1);
00106 }
00107 else
00108 {
00109 visName = name;
00110 pluginName.clear();
00111 }
00112
00113 if (m_vis)
00114 {
00115 delete m_vis;
00116 m_vis = NULL;
00117 }
00118
00119 for (const VisFactory* pVisFactory = VisFactory::VisFactories();
00120 pVisFactory; pVisFactory = pVisFactory->next())
00121 {
00122 if (pVisFactory->name() == visName)
00123 {
00124 m_vis = pVisFactory->create(this, pluginName);
00125 m_vis->resize(m_visualizerVideo->GetArea().size());
00126 m_fps = m_vis->getDesiredFPS();
00127 m_samples = m_vis->getDesiredSamples();
00128
00129 QMutexLocker locker(mutex());
00130 prepare();
00131
00132 break;
00133 }
00134 }
00135
00136
00137 m_updateTimer->start(1000 / m_fps);
00138 }
00139
00140
00141 void MainVisual::prepare()
00142 {
00143 while (!m_nodes.empty())
00144 delete m_nodes.takeLast();
00145 }
00146
00147
00148
00149
00150 void MainVisual::add(uchar *buffer, unsigned long b_len, unsigned long timecode, int source_channels, int bits_per_sample)
00151 {
00152 unsigned long len = b_len, cnt;
00153 short *l = 0, *r = 0;
00154
00155
00156 len /= source_channels;
00157 len /= (bits_per_sample / 8);
00158
00159 if (len > m_samples)
00160 len = m_samples;
00161
00162 cnt = len;
00163
00164 if (source_channels == 2)
00165 {
00166 l = new short[len];
00167 r = new short[len];
00168
00169 if (bits_per_sample == 8)
00170 stereo16_from_stereopcm8(l, r, buffer, cnt);
00171 else if (bits_per_sample == 16)
00172 stereo16_from_stereopcm16(l, r, (short *) buffer, cnt);
00173 }
00174 else if (source_channels == 1)
00175 {
00176 l = new short[len];
00177
00178 if (bits_per_sample == 8)
00179 mono16_from_monopcm8(l, buffer, cnt);
00180 else if (bits_per_sample == 16)
00181 mono16_from_monopcm16(l, (short *) buffer, cnt);
00182 }
00183 else
00184 len = 0;
00185
00186 m_nodes.append(new VisualNode(l, r, len, timecode));
00187 }
00188
00189 void MainVisual::timeout()
00190 {
00191 VisualNode *node = NULL;
00192 if (m_playing && gPlayer->getOutput())
00193 {
00194 QMutexLocker locker(mutex());
00195 int64_t timestamp = gPlayer->getOutput()->GetAudiotime();
00196 while (m_nodes.size() > 1)
00197 {
00198 if ((int64_t)m_nodes.first()->offset > timestamp)
00199 break;
00200
00201 if (m_vis)
00202 m_vis->processUndisplayed(node);
00203
00204 delete m_nodes.first();
00205 m_nodes.removeFirst();
00206 }
00207
00208 if (!m_nodes.isEmpty())
00209 node = m_nodes.first();
00210 }
00211
00212 bool stop = true;
00213 if (m_vis)
00214 stop = m_vis->process(node);
00215
00216 if (m_vis && !stop)
00217 {
00218 QPainter p(&m_pixmap);
00219 if (m_vis->draw(&p, m_visualizerVideo->GetBackgroundColor()))
00220 m_visualizerVideo->UpdateFrame(&m_pixmap);
00221 }
00222
00223 if (m_playing && !stop)
00224 m_updateTimer->start();
00225 }
00226
00227 void MainVisual::resize(const QSize &size)
00228 {
00229 m_pixmap = QPixmap(size);
00230 m_pixmap.fill(m_visualizerVideo->GetBackgroundColor());
00231
00232 if (m_vis)
00233 m_vis->resize(size);
00234 }
00235
00236 void MainVisual::customEvent(QEvent *event)
00237 {
00238 if ((event->type() == OutputEvent::Playing) ||
00239 (event->type() == OutputEvent::Info) ||
00240 (event->type() == OutputEvent::Buffering) ||
00241 (event->type() == OutputEvent::Paused))
00242 {
00243 m_playing = true;
00244 if (!m_updateTimer->isActive())
00245 m_updateTimer->start();
00246 }
00247 else if ((event->type() == OutputEvent::Stopped) ||
00248 (event->type() == OutputEvent::Error))
00249 {
00250 m_playing = false;
00251 }
00252 }