#include "definitions.h"
#include "slideshowclip.h"
#include "profilesdialog.h"
+
+#ifdef USE_BLACKMAGIC
#include "blackmagic/devices.h"
+#endif
#include <mlt++/Mlt.h>
}
}
-Render::Render(const QString & rendererName, int winid, QString profile, QWidget *parent) :
+Render::Render(Kdenlive::MONITORID rendererName, int winid, QString profile, QWidget *parent) :
AbstractRender(rendererName, parent),
- analyseAudio(KdenliveSettings::monitor_audio()),
m_name(rendererName),
m_mltConsumer(NULL),
m_mltProducer(NULL),
m_blackClip(NULL),
m_winid(winid)
{
+ analyseAudio = KdenliveSettings::monitor_audio();
if (profile.isEmpty()) profile = KdenliveSettings::current_profile();
buildConsumer(profile);
m_mltProducer = m_blackClip->cut(0, 1);
m_mltConsumer->connect(*m_mltProducer);
m_mltProducer->set_speed(0.0);
m_refreshTimer.setSingleShot(true);
- m_refreshTimer.setInterval(50);
+ m_refreshTimer.setInterval(70);
connect(&m_refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
}
void Render::closeMlt()
-{
+{
//delete m_osdTimer;
m_requestList.clear();
m_infoThread.waitForFinished();
m_blackClip->set("id", "black");
m_blackClip->set("mlt_type", "producer");
- if (KdenliveSettings::external_display() && m_name != "clip") {
+ if (KdenliveSettings::external_display() && m_name != Kdenlive::clipMonitor) {
+#ifdef USE_BLACKMAGIC
// Use blackmagic card for video output
QMap< QString, QString > profileProperties = ProfilesDialog::getSettingsFromFile(profileName);
int device = KdenliveSettings::blackmagic_output_device();
if (m_mltConsumer && m_mltConsumer->is_valid()) return;
} else KMessageBox::informationList(qApp->activeWindow(), i18n("Your project's profile %1 is not compatible with the blackmagic output card. Please see supported profiles below. Switching to normal video display.", m_mltProfile->description()), BMInterface::supportedModes(KdenliveSettings::blackmagic_output_device()));
}
+#endif
}
m_externalConsumer = false;
QString videoDriver = KdenliveSettings::videodrivername();
buildConsumer(profileName);
double new_fps = m_mltProfile->fps();
double new_dar = m_mltProfile->dar();
-
+
if (!dropSceneList) {
// We need to recover our playlist
if (current_fps != new_fps) {
else delete producer;
}
}
-
+
if (!m_mltProducer || !path.isEmpty()) {
QImage pix(width, height, QImage::Format_RGB32);
pix.fill(Qt::black);
m_requestList.removeAll(info);
m_requestList.append(info);
m_infoMutex.unlock();
- if (!m_infoThread.isRunning())
+ if (!m_infoThread.isRunning()) {
m_infoThread = QtConcurrent::run(this, &Render::processFileProperties);
+ }
}
void Render::forceProcessing(const QString &id)
{
- m_infoMutex.lock();
+ if (m_processingClipId == id) return;
+ QMutexLocker lock(&m_infoMutex);
for (int i = 0; i < m_requestList.count(); i++) {
requestClipInfo info = m_requestList.at(i);
if (info.clipId == id) {
}
}
}
- m_infoMutex.unlock();
}
-int Render::processingItems() const
+int Render::processingItems()
{
+ QMutexLocker lock(&m_infoMutex);
int count = m_requestList.count();
- if (m_infoThread.isRunning()) count++;
+ if (!m_processingClipId.isEmpty()) {
+ // one clip is currently processed
+ count++;
+ }
return count;
}
bool Render::isProcessing(const QString &id)
{
if (m_processingClipId == id) return true;
- m_infoMutex.lock();
+ QMutexLocker lock(&m_infoMutex);
for (int i = 0; i < m_requestList.count(); i++) {
requestClipInfo info = m_requestList.at(i);
if (info.clipId == id) {
- m_infoMutex.unlock();
return true;
}
}
- m_infoMutex.unlock();
return false;
}
while (!m_requestList.isEmpty()) {
m_infoMutex.lock();
info = m_requestList.takeFirst();
- m_infoMutex.unlock();
m_processingClipId = info.clipId;
+ m_infoMutex.unlock();
+
QString path;
bool proxyProducer;
if (info.xml.hasAttribute("proxy") && info.xml.attribute("proxy") != "-") {
path = info.xml.attribute("proxy");
- proxyProducer = true;
+ // Check for missing proxies
+ if (QFileInfo(path).size() <= 0) {
+ // proxy is missing, re-create it
+ emit requestProxy(info.clipId);
+ proxyProducer = false;
+ path = info.xml.attribute("resource");
+ }
+ else proxyProducer = true;
}
else {
path = info.xml.attribute("resource");
if (producer == NULL || producer->is_blank() || !producer->is_valid()) {
kDebug() << " / / / / / / / / ERROR / / / / // CANNOT LOAD PRODUCER: "<<path;
+ m_processingClipId.clear();
if (proxyProducer) {
// Proxy file is corrupted
emit removeInvalidProxy(info.clipId, false);
}
else emit removeInvalidClip(info.clipId, info.replaceProducer);
delete producer;
- m_processingClipId.clear();
continue;
}
producer->set("out", info.xml.attribute("proxy_out").toInt());
if (producer->get_out() != info.xml.attribute("proxy_out").toInt()) {
// Proxy file length is different than original clip length, this will corrupt project so disable this proxy clip
+ m_processingClipId.clear();
emit removeInvalidProxy(info.clipId, true);
delete producer;
- m_processingClipId.clear();
continue;
}
}
int imageWidth = (int)((double) info.imageHeight * m_mltProfile->width() / m_mltProfile->height() + 0.5);
int fullWidth = (int)((double) info.imageHeight * m_mltProfile->dar() + 0.5);
int frameNumber = info.xml.attribute("thumbnail", "-1").toInt();
-
+
if ((!info.replaceProducer && info.xml.hasAttribute("file_hash")) || proxyProducer) {
// Clip already has all properties
if (proxyProducer) {
Mlt::Frame *frame = producer->get_frame();
if (frame && frame->is_valid()) {
QImage img = KThumb::getFrame(frame, imageWidth, fullWidth, info.imageHeight);
- delete frame;
emit replyGetImage(info.clipId, img);
}
+ if (frame) delete frame;
}
- emit replyGetFileProperties(info.clipId, producer, stringMap(), stringMap(), info.replaceProducer);
m_processingClipId.clear();
+ emit replyGetFileProperties(info.clipId, producer, stringMap(), stringMap(), info.replaceProducer);
continue;
}
stringMap filePropertyMap;
stringMap metadataPropertyMap;
+ char property[200];
+
if (frameNumber > 0) producer->seek(frameNumber);
-
+
duration = duration > 0 ? duration : producer->get_playtime();
filePropertyMap["duration"] = QString::number(duration);
//kDebug() << "/////// PRODUCER: " << url.path() << " IS: " << producer->get_playtime();
}
}
- if (producer->get_double("meta.media.frame_rate_den") > 0) {
- filePropertyMap["fps"] = locale.toString(producer->get_double("meta.media.frame_rate_num") / producer->get_double("meta.media.frame_rate_den"));
- } else filePropertyMap["fps"] = producer->get("source_fps");
+ // Get frame rate
+ int vindex = producer->get_int("video_index");
+ if (vindex > -1) {
+ snprintf(property, sizeof(property), "meta.media.%d.stream.frame_rate", vindex);
+ if (producer->get(property))
+ filePropertyMap["fps"] = producer->get(property);
+ }
+
+ if (!filePropertyMap.contains("fps")) {
+ if (producer->get_double("meta.media.frame_rate_den") > 0) {
+ filePropertyMap["fps"] = locale.toString(producer->get_double("meta.media.frame_rate_num") / producer->get_double("meta.media.frame_rate_den"));
+ } else filePropertyMap["fps"] = producer->get("source_fps");
+ }
Mlt::Frame *frame = producer->get_frame();
if (frame && frame->is_valid()) {
}
} while (variance == -1);
delete frame;
- if (frameNumber > -1) filePropertyMap["thumbnail"] = frameNumber;
+ if (frameNumber > -1) filePropertyMap["thumbnail"] = QString::number(frameNumber);
emit replyGetImage(info.clipId, img);
} else if (frame->get_int("test_audio") == 0) {
emit replyGetImage(info.clipId, "audio-x-generic", fullWidth, info.imageHeight);
}
}
// Retrieve audio / video codec name
-
// If there is a
- char property[200];
- if (producer->get_int("video_index") > -1) {
+
+ if (vindex > -1) {
/*if (context->duration == AV_NOPTS_VALUE) {
kDebug() << " / / / / / / / /ERROR / / / CLIP HAS UNKNOWN DURATION";
emit removeInvalidClip(clipId);
return;
}*/
// Get the video_index
- int default_video = producer->get_int("video_index");
int video_max = 0;
int default_audio = producer->get_int("audio_index");
int audio_max = 0;
+ int scan = producer->get_int("meta.media.progressive");
+ filePropertyMap["progressive"] = QString::number(scan);
+
// Find maximum stream index values
for (int ix = 0; ix < producer->get_int("meta.media.nb_streams"); ix++) {
snprintf(property, sizeof(property), "meta.media.%d.stream.type", ix);
else if (type == "audio")
audio_max = ix;
}
- filePropertyMap["default_video"] = QString::number(default_video);
+ filePropertyMap["default_video"] = QString::number(vindex);
filePropertyMap["video_max"] = QString::number(video_max);
filePropertyMap["default_audio"] = QString::number(default_audio);
filePropertyMap["audio_max"] = QString::number(audio_max);
- snprintf(property, sizeof(property), "meta.media.%d.codec.long_name", default_video);
+ snprintf(property, sizeof(property), "meta.media.%d.codec.long_name", vindex);
if (producer->get(property)) {
filePropertyMap["videocodec"] = producer->get(property);
} else {
- snprintf(property, sizeof(property), "meta.media.%d.codec.name", default_video);
+ snprintf(property, sizeof(property), "meta.media.%d.codec.name", vindex);
if (producer->get(property))
filePropertyMap["videocodec"] = producer->get(property);
}
QString query;
- query = QString("meta.media.%1.codec.pix_fmt").arg(default_video);
+ query = QString("meta.media.%1.codec.pix_fmt").arg(vindex);
filePropertyMap["pix_fmt"] = producer->get(query.toUtf8().constData());
filePropertyMap["colorspace"] = producer->get("meta.media.colorspace");
metadataPropertyMap[ name.section('.', 0, -2)] = value;
}
producer->seek(0);
+ m_processingClipId.clear();
emit replyGetFileProperties(info.clipId, producer, filePropertyMap, metadataPropertyMap, info.replaceProducer);
}
m_processingClipId.clear();
QMutexLocker locker(&m_mutex);
QString currentId;
int consumerPosition = 0;
- if (m_winid == -1 || !m_mltConsumer) return -1;
+ if (m_winid == -1 || !m_mltConsumer) {
+ kDebug()<<" / / / / WARNING, MONITOR NOT READY";
+ if (producer) delete producer;
+ return -1;
+ }
m_mltConsumer->set("refresh", 0);
if (!m_mltConsumer->is_stopped()) {
m_mltConsumer->stop();
m_mltConsumer->purge();
consumerPosition = m_mltConsumer->position();
- if (m_mltProducer) {
- m_mltProducer->set_speed(0);
- currentId = m_mltProducer->get("id");
- delete m_mltProducer;
- m_mltProducer = NULL;
- emit stopped();
- }
blockSignals(true);
- if (producer && producer->is_valid()) {
- m_mltProducer = producer;
- } else m_mltProducer = m_blackClip->cut(0, 1);
+ if (!producer || !producer->is_valid()) {
+ if (producer) delete producer;
+ producer = m_blackClip->cut(0, 1);
+ }
- if (!m_mltProducer || !m_mltProducer->is_valid()) {
+ if (!producer || !producer->is_valid()) {
kDebug() << " WARNING - - - - -INVALID PLAYLIST: ";
return -1;
}
- if (position == -1 && m_mltProducer->get("id") == currentId) position = consumerPosition;
- if (position != -1) m_mltProducer->seek(position);
+ if (m_mltProducer) currentId = m_mltProducer->get("id");
+ emit stopped();
+ if (position == -1 && producer->get("id") == currentId) position = consumerPosition;
+ if (position != -1) producer->seek(position);
int volume = KdenliveSettings::volume();
- m_mltProducer->set("meta.volume", (double)volume / 100);
- m_fps = m_mltProducer->get_fps();
+ producer->set("meta.volume", (double)volume / 100);
+ m_fps = producer->get_fps();
blockSignals(false);
- int error = connectPlaylist();
+ m_mltConsumer->connect(*producer);
+
+ if (m_mltProducer) {
+ m_mltProducer->set_speed(0);
+ delete m_mltProducer;
+ m_mltProducer = NULL;
+ }
+ m_mltProducer = producer;
+ m_mltProducer->set_speed(0);
+ emit durationChanged(m_mltProducer->get_playtime());
+ if (m_mltConsumer->start() == -1) {
+ // ARGH CONSUMER BROKEN!!!!
+ KMessageBox::error(qApp->activeWindow(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install or your driver settings, please fix it."));
+ if (m_showFrameEvent) delete m_showFrameEvent;
+ m_showFrameEvent = NULL;
+ if (m_pauseEvent) delete m_pauseEvent;
+ m_pauseEvent = NULL;
+ delete m_mltConsumer;
+ m_mltConsumer = NULL;
+ return -1;
+ }
position = m_mltProducer->position();
m_mltConsumer->set("refresh", 1);
m_mltConsumer->wait_for(ev);
delete ev;
emit rendererPosition(position);
- return error;
+ return 0;
}
int Render::setSceneList(QDomDocument list, int position)
}
kDebug() << "// NEW SCENE LIST DURATION SET TO: " << m_mltProducer->get_playtime();
- if (error == 0) error = connectPlaylist();
- else connectPlaylist();
+ m_mltConsumer->connect(*m_mltProducer);
+ m_mltProducer->set_speed(0);
fillSlowMotionProducers();
blockSignals(false);
+ emit durationChanged(m_mltProducer->get_playtime());
return error;
//kDebug()<<"// SETSCN LST, POS: "<<position;
QString playlist;
Mlt::Profile profile((mlt_profile) 0);
Mlt::Consumer xmlConsumer(profile, "xml:kdenlive_playlist");
+ if (!xmlConsumer.is_valid()) return QString();
m_mltProducer->optimise();
xmlConsumer.set("terminate_on_pause", 1);
Mlt::Producer prod(m_mltProducer->get_producer());
+ if (!prod.is_valid()) return QString();
bool split = m_isSplitView;
if (split) slotSplitView(false);
xmlConsumer.connect(prod);
- xmlConsumer.start();
- while (!xmlConsumer.is_stopped()) {}
+ xmlConsumer.run();
playlist = QString::fromUtf8(xmlConsumer.get("kdenlive_playlist"));
if (split) slotSplitView(true);
return playlist;
QFile file(path);
QDomDocument doc;
doc.setContent(sceneList(), false);
- if (!kdenliveData.isNull()) {
+ if (doc.isNull()) return false;
+ QDomElement root = doc.documentElement();
+ if (!kdenliveData.isNull() && !root.isNull()) {
// add Kdenlive specific tags
- QDomNode mlt = doc.elementsByTagName("mlt").at(0);
- mlt.appendChild(doc.importNode(kdenliveData, true));
+ root.appendChild(doc.importNode(kdenliveData, true));
}
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
kWarning() << "////// ERROR writing to file: " << path;
Mlt::Consumer xmlConsumer(*m_mltProfile, ("xml:" + url.path()).toUtf8().constData());
m_mltProducer->optimise();
xmlConsumer.set("terminate_on_pause", 1);
- if (m_name == "clip") {
+ if (m_name == Kdenlive::clipMonitor) {
Mlt::Producer *prod = m_mltProducer->cut(zone.x(), zone.y());
Mlt::Playlist list;
list.insert_at(0, prod, 0);
return m_fps;
}
-int Render::connectPlaylist()
-{
- if (!m_mltConsumer) return -1;
- m_mltConsumer->connect(*m_mltProducer);
- m_mltProducer->set_speed(0);
- if (m_mltConsumer->start() == -1) {
- // ARGH CONSUMER BROKEN!!!!
- KMessageBox::error(qApp->activeWindow(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install or your driver settings, please fix it."));
- if (m_showFrameEvent) delete m_showFrameEvent;
- m_showFrameEvent = NULL;
- if (m_pauseEvent) delete m_pauseEvent;
- m_pauseEvent = NULL;
- delete m_mltConsumer;
- m_mltConsumer = NULL;
- return -1;
- }
- emit durationChanged(m_mltProducer->get_playtime());
- return 0;
-}
-
-
int Render::volume() const
{
if (!m_mltConsumer || !m_mltProducer) return -1;
void Render::start()
{
+ m_refreshTimer.stop();
QMutexLocker locker(&m_mutex);
if (m_winid == -1) {
kDebug() << "----- BROKEN MONITOR: " << m_name << ", RESTART";
return;
}
-
- if (m_mltConsumer && m_mltConsumer->is_stopped()) {
+ if (!m_mltConsumer) return;
+ if (m_mltConsumer->is_stopped()) {
if (m_mltConsumer->start() == -1) {
//KMessageBox::error(qApp->activeWindow(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install or your driver settings, please fix it."));
kDebug(QtWarningMsg) << "/ / / / CANNOT START MONITOR";
void Render::stop()
{
+ m_refreshTimer.stop();
QMutexLocker locker(&m_mutex);
if (m_mltProducer == NULL) return;
if (m_mltConsumer && !m_mltConsumer->is_stopped()) {
void Render::stop(const GenTime & startTime)
{
+ m_refreshTimer.stop();
QMutexLocker locker(&m_mutex);
if (m_mltProducer) {
if (m_isZoneMode) resetZoneMode();
return;
if (m_isZoneMode) resetZoneMode();
if (play && m_mltProducer->get_speed() == 0.0) {
- if (m_name == "clip" && m_mltConsumer->position() == m_mltProducer->get_out()) m_mltProducer->seek(0);
+ if (m_name == Kdenlive::clipMonitor && m_mltConsumer->position() == m_mltProducer->get_out()) m_mltProducer->seek(0);
if (m_mltConsumer->is_stopped()) {
m_mltConsumer->start();
}
m_mltProducer->set_speed(1.0);
- m_mltConsumer->set("refresh", "1");
+ m_mltConsumer->set("refresh", 1);
} else if (!play) {
m_mltProducer->set_speed(0.0);
m_mltConsumer->set("refresh", 0);
m_mltProducer->seek(m_mltConsumer->position());
if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
if (m_isZoneMode) resetZoneMode();
-
+
//emitConsumerStopped();
/*m_mltConsumer->set("refresh", 0);
m_mltConsumer->stop();
m_mltProducer->seek((int)(startTime.frames(m_fps)));
m_mltProducer->set_speed(1.0);
m_mltConsumer->set("refresh", 1);
+ if (m_mltConsumer->is_stopped()) m_mltConsumer->start();
m_isZoneMode = true;
}
{
if (!m_mltProducer)
return;
-
resetZoneMode();
m_mltProducer->seek(pos);
if (m_mltProducer->get_speed() == 0) {
void Render::doRefresh()
{
- m_refreshTimer.start();
- /*QMutexLocker locker(&m_mutex);
- if (m_mltConsumer) {
- if (m_mltConsumer->is_stopped()) {
- kDebug()<<"pppppppppppppppp\n\nSTARTING CONSUMER: "<<m_name<<m_mltConsumer->start();
- }
- //m_mltProducer->set_speed(1);
- m_mltConsumer->set("refresh", 1);
- //m_mltProducer->set_speed(0);
- }*/
+ if (m_mltProducer && m_mltProducer->get_speed() == 0) m_refreshTimer.start();
}
void Render::refresh()
return 0;
}
-const QString & Render::rendererName() const
-{
- return m_name;
-}
-
void Render::emitFrameUpdated(Mlt::Frame& frame)
{
- mlt_image_format format = mlt_image_rgb24;
+ mlt_image_format format = mlt_image_rgb24a;
+ int width = 0;
+ int height = 0;
+ const uchar* image = frame.get_image(format, width, height);
+ QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
+ memcpy(qimage.scanLine(0), image, width * height * 4);
+
+ /*mlt_image_format format = mlt_image_rgb24;
int width = 0;
int height = 0;
const uchar* image = frame.get_image(format, width, height);
QImage qimage(width, height, QImage::Format_RGB888);
- memcpy(qimage.bits(), image, width * height * 3);
- emit frameUpdated(qimage);
+ memcpy(qimage.bits(), image, width * height * 3);*/
+ emit frameUpdated(qimage.rgbSwapped());
}
void Render::emitFrameNumber()
if (m_mltProducer) {
double pos = m_mltProducer->position();
if (m_isLoopMode) play(m_loopStart);
- else if (m_isZoneMode) resetZoneMode();
+ //else if (m_isZoneMode) resetZoneMode();
emit rendererStopped((int) pos);
}
}
}
service.lock();
return new Mlt::Tractor(service);
-
+
}
void Render::unlockService(Mlt::Tractor *tractor)
service.lock();
for (int j = 0; j < params.count(); j++) {
filter->set((prefix + params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData());
- }
+ }
delete clip;
service.unlock();
trackProducer.set("hide", 0);
}
if (audioMixingBroken) fixAudioMixing(tractor);
-
+
tractor.multitrack()->refresh();
tractor.refresh();
refresh();
}
}
}
- QDomElement tractor = doc.elementsByTagName("tractor").at(0).toElement();
- int out = tractor.attribute("out").toInt();
- out = factor * out + 0.5;
- tractor.setAttribute("out", out);
- emit durationChanged(out);
+ QDomElement root = doc.documentElement();
+ if (!root.isNull()) {
+ QDomElement tractor = root.firstChildElement("tractor");
+ int out = tractor.attribute("out").toInt();
+ out = factor * out + 0.5;
+ tractor.setAttribute("out", out);
+ emit durationChanged(out);
+ }
//kDebug() << "///////////////////////////// " << out << " \n" << doc.toString() << "\n-------------------------";
return doc.toString();
return m_mltProducer;
}
+const QString Render::activeClipId()
+{
+ if (m_mltProducer) return m_mltProducer->get("id");
+ return QString();
+}
+
+//static
+bool Render::getBlackMagicDeviceList(KComboBox *devicelist)
+{
+ Mlt::Profile profile;
+ Mlt::Producer bm(profile, "decklink");
+ int found_devices = 0;
+ if (bm.is_valid()) found_devices = bm.get_int("devices");
+ if (found_devices <= 0) {
+ devicelist->setEnabled(false);
+ return false;
+ }
+ for (int i = 0; i < found_devices; i++) {
+ char *tmp = qstrdup(QString("device.%1").arg(i).toUtf8().constData());
+ devicelist->addItem(bm.get(tmp));
+ delete[] tmp;
+ }
+ return true;
+}
+
+bool Render::getBlackMagicOutputDeviceList(KComboBox *devicelist)
+{
+ Mlt::Profile profile;
+ Mlt::Consumer bm(profile, "decklink");
+ int found_devices = 0;
+ if (bm.is_valid()) found_devices = bm.get_int("devices");
+ if (found_devices <= 0) {
+ devicelist->setEnabled(false);
+ return false;
+ }
+ for (int i = 0; i < found_devices; i++) {
+ char *tmp = qstrdup(QString("device.%1").arg(i).toUtf8().constData());
+ devicelist->addItem(bm.get(tmp));
+ delete[] tmp;
+ }
+ return true;
+}
#include "renderer.moc"