|
MythTV
0.26-pre
|
00001 // Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com> 00002 // 00003 // Use, modification and distribution is allowed without limitation, 00004 // warranty, or liability of any kind. 00005 // 00006 00007 // C 00008 #include <cmath> 00009 #include <cstdio> 00010 00011 // C++ 00012 #include <algorithm> 00013 #include <iostream> 00014 using namespace std; 00015 00016 // Qt 00017 #include <QPainter> 00018 00019 // mythtv 00020 #include <mythuivideo.h> 00021 00022 // mythmusic 00023 #include "visualize.h" 00024 #include "mainvisual.h" 00025 #include "constants.h" 00026 #include "musicplayer.h" 00027 00028 // fast inlines 00029 #include "inlines.h" 00030 00031 00033 // MainVisual 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 // force an update 00137 m_updateTimer->start(1000 / m_fps); 00138 } 00139 00140 // Caller holds mutex() lock 00141 void MainVisual::prepare() 00142 { 00143 while (!m_nodes.empty()) 00144 delete m_nodes.takeLast(); 00145 } 00146 00147 // This is called via : mythtv/libs/libmyth/output.cpp :: OutputListeners::dispatchVisual 00148 // from : mythtv/libs/libmyth/audio/audiooutputbase.cpp :: AudioOutputBase::AddData 00149 // Caller holds mutex() lock 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 // len is length of buffer in fully converted samples 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 }
1.7.6.1