From 623c7ac1fac4f52a39f102649d062cc900e470d6 Mon Sep 17 00:00:00 2001 From: Dan Dennedy Date: Thu, 27 Aug 2009 05:14:10 +0000 Subject: [PATCH] Add Mac OS X compatibility through new MLT sdl_audio consumer and a QTGLWidget! svn path=/trunk/kdenlive/; revision=3839 --- src/CMakeLists.txt | 12 +++- src/kdenlivesettingsdialog.cpp | 4 ++ src/main.cpp | 4 -- src/mainwindow.cpp | 2 + src/monitor.cpp | 17 +++++ src/monitor.h | 6 ++ src/renderer.cpp | 28 +++++++- src/renderer.h | 13 ++++ src/videoglwidget.cpp | 117 +++++++++++++++++++++++++++++++++ src/videoglwidget.h | 40 +++++++++++ 10 files changed, 237 insertions(+), 6 deletions(-) create mode 100644 src/videoglwidget.cpp create mode 100644 src/videoglwidget.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bfd7c7dc..80881964 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,13 @@ - add_subdirectory( widgets ) add_subdirectory( mimetypes ) find_package(Nepomuk REQUIRED) +if (APPLE) + find_package(OpenGL) + set(QT_USE_QTOPENGL TRUE) +endif (APPLE) + include_directories ( ${KDE4_INCLUDE_DIR} ${KDE4_INCLUDE_DIR}/KDE @@ -180,6 +184,10 @@ else(NO_JOGSHUTTLE) set(kdenlive_SRCS jogshuttle.cpp ${kdenlive_SRCS}) endif(NO_JOGSHUTTLE) +if (APPLE) + set(kdenlive_SRCS videoglwidget.cpp ${kdenlive_SRCS}) +endif (APPLE) + kde4_add_kcfg_files(kdenlive_SRCS kdenlivesettings.kcfgc ) QT4_ADD_DBUS_ADAPTOR(kdenlive_SRCS org.kdenlive.MainWindow.xml mainwindow.h MainWindow) kde4_add_executable(kdenlive ${kdenlive_SRCS} ${kdenlive_UI}) @@ -199,6 +207,8 @@ target_link_libraries(kdenlive if (APPLE) find_package(SDL REQUIRED) target_link_libraries(kdenlive ${SDL_LIBRARY}) + target_link_libraries(kdenlive ${QT_QTOPENGL_LIBRARY}) + target_link_libraries(kdenlive ${OPENGL_LIBRARIES}) endif (APPLE) install(TARGETS kdenlive DESTINATION ${BIN_INSTALL_DIR}) diff --git a/src/kdenlivesettingsdialog.cpp b/src/kdenlivesettingsdialog.cpp index 2a1ccaa2..ff01bba2 100644 --- a/src/kdenlivesettingsdialog.cpp +++ b/src/kdenlivesettingsdialog.cpp @@ -207,12 +207,14 @@ void KdenliveSettingsDialog::initDevices() { // Fill audio drivers m_configSdl.kcfg_audio_driver->addItem(i18n("Automatic"), QString()); +#ifndef Q_WS_MAC m_configSdl.kcfg_audio_driver->addItem(i18n("OSS"), "dsp"); m_configSdl.kcfg_audio_driver->addItem(i18n("ALSA"), "alsa"); m_configSdl.kcfg_audio_driver->addItem(i18n("PulseAudio"), "pulse"); m_configSdl.kcfg_audio_driver->addItem(i18n("OSS with DMA access"), "dma"); m_configSdl.kcfg_audio_driver->addItem(i18n("Esound daemon"), "esd"); m_configSdl.kcfg_audio_driver->addItem(i18n("ARTS daemon"), "artsc"); +#endif if (!KdenliveSettings::audiodrivername().isEmpty()) for (int i = 1; i < m_configSdl.kcfg_audio_driver->count(); i++) { @@ -224,6 +226,7 @@ void KdenliveSettingsDialog::initDevices() // Fill video drivers m_configSdl.kcfg_video_driver->addItem(i18n("Automatic"), QString()); +#ifndef Q_WS_MAC m_configSdl.kcfg_video_driver->addItem(i18n("XVideo"), "x11"); m_configSdl.kcfg_video_driver->addItem(i18n("X11"), "x11_noaccel"); m_configSdl.kcfg_video_driver->addItem(i18n("XFree86 DGA 2.0"), "dga"); @@ -233,6 +236,7 @@ void KdenliveSettingsDialog::initDevices() m_configSdl.kcfg_video_driver->addItem(i18n("SVGAlib"), "svgalib"); m_configSdl.kcfg_video_driver->addItem(i18n("General graphics interface"), "ggi"); m_configSdl.kcfg_video_driver->addItem(i18n("Ascii art library"), "aalib"); +#endif // Fill the list of audio playback devices m_configSdl.kcfg_audio_device->addItem(i18n("Default"), QString()); diff --git a/src/main.cpp b/src/main.cpp index 817d072d..369de55e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,10 +28,6 @@ #include //new -#if defined(__APPLE_KDE__) || defined(__DARWIN__) -#include -#endif - int main(int argc, char *argv[]) { KAboutData aboutData(QByteArray("kdenlive"), QByteArray("kdenlive"), diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6d86b82c..8ce29546 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -384,6 +384,8 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, QWidget *parent void MainWindow::queryQuit() { if (queryClose()) { + if (m_projectMonitor) m_projectMonitor->stop(); + if (m_clipMonitor) m_clipMonitor->stop(); delete m_effectStack; delete m_activeTimeline; delete m_projectMonitor; diff --git a/src/monitor.cpp b/src/monitor.cpp index ea0478e0..88f35599 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -122,10 +122,21 @@ Monitor::Monitor(QString name, MonitorManager *manager, QWidget *parent) : QVBoxLayout *rendererBox = new QVBoxLayout(m_ui.video_frame); rendererBox->setContentsMargins(0, 0, 0, 0); +#ifdef Q_WS_MAC + m_glWidget = new VideoGLWidget(m_ui.video_frame); + rendererBox->addWidget(m_glWidget); + render = new Render(m_name, (int) m_ui.video_frame->winId(), -1, this); + m_glWidget->setImageAspectRatio(render->dar()); + m_glWidget->setBackgroundColor(KdenliveSettings::window_background()); + m_glWidget->resize(m_ui.video_frame->size()); + connect(render, SIGNAL(showImageSignal(QImage)), m_glWidget, SLOT(showImage(QImage))); + m_monitorRefresh = 0; +#else m_monitorRefresh = new MonitorRefresh(m_ui.video_frame); rendererBox->addWidget(m_monitorRefresh); render = new Render(m_name, (int) m_monitorRefresh->winId(), -1, this); m_monitorRefresh->setRenderer(render); +#endif connect(m_ruler, SIGNAL(seekRenderer(int)), this, SLOT(slotSeek(int))); connect(render, SIGNAL(durationChanged(int)), this, SLOT(adjustRulerSize(int))); @@ -142,7 +153,9 @@ Monitor::Monitor(QString name, MonitorManager *manager, QWidget *parent) : } else { connect(m_ruler, SIGNAL(zoneChanged(QPoint)), this, SLOT(setClipZone(QPoint))); } +#ifndef Q_WS_MAC m_monitorRefresh->show(); +#endif kDebug() << "/////// BUILDING MONITOR, ID: " << m_ui.video_frame->winId(); } @@ -753,9 +766,13 @@ void Monitor::slotSwitchMonitorInfo(bool show) KdenliveSettings::setDisplayMonitorInfo(show); if (show) { if (m_overlay) return; +#ifndef Q_WS_MAC m_overlay = new Overlay(m_monitorRefresh); m_overlay->raise(); m_overlay->setHidden(true); +#else + m_overlay = new Overlay(m_glWidget); +#endif } else { delete m_overlay; m_overlay = NULL; diff --git a/src/monitor.h b/src/monitor.h index 35b539e9..9d7723f3 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -30,6 +30,9 @@ #include "gentime.h" #include "ui_monitor_ui.h" +#ifdef Q_WS_MAC +#include "videoglwidget.h" +#endif class MonitorManager; class Render; @@ -112,6 +115,9 @@ private: QMenu *m_configMenu; QMenu *m_playMenu; QPoint m_DragStartPosition; +#ifdef Q_WS_MAC + VideoGLWidget *m_glWidget; +#endif GenTime getSnapForPos(bool previous); bool m_frametimecode; diff --git a/src/renderer.cpp b/src/renderer.cpp index 7b5ce609..7b4be874 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -56,7 +56,11 @@ static void consumer_frame_show(mlt_consumer, Render * self, mlt_frame frame_ptr { // detect if the producer has finished playing. Is there a better way to do it? if (self->m_isBlocked) return; - if (mlt_properties_get_double(MLT_FRAME_PROPERTIES(frame_ptr), "_speed") == 0.0) { + Mlt::Frame frame(frame_ptr); +#ifdef Q_WS_MAC + self->showFrame(frame); +#endif + if (frame.get_double("_speed") == 0.0) { self->emitConsumerStopped(); } else { self->emitFrameNumber(mlt_frame_get_position(frame_ptr)); @@ -76,6 +80,9 @@ Render::Render(const QString & rendererName, int winid, int /* extid */, QWidget m_isSplitView(false), m_blackClip(NULL), m_winid(winid) +#ifdef Q_WS_MAC + , m_glWidget(0) +#endif { kDebug() << "////////// USING PROFILE: " << (char*)KdenliveSettings::current_profile().toUtf8().data(); @@ -166,7 +173,13 @@ void Render::buildConsumer() } setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1); +#ifdef Q_WS_MAC + m_mltConsumer = new Mlt::Consumer(*m_mltProfile , "sdl_audio"); + m_mltConsumer->set("preview_off", 1); + m_mltConsumer->set("preview_format", mlt_image_rgb24a); +#else m_mltConsumer = new Mlt::Consumer(*m_mltProfile , "sdl_preview"); +#endif m_mltConsumer->set("resize", 1); m_mltConsumer->set("window_id", m_winid); m_mltConsumer->set("terminate_on_pause", 1); @@ -1431,6 +1444,19 @@ void Render::exportCurrentFrame(KUrl url, bool /*notify*/) //if (notify) QApplication::postEvent(qApp->activeWindow(), new UrlEvent(url, 10003)); } +#ifdef Q_WS_MAC +void Render::showFrame(Mlt::Frame& frame) +{ + 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); + memcpy(qimage.scanLine(0), image, width * height * 4); + emit showImageSignal(qimage); +} +#endif + /** MLT PLAYLIST DIRECT MANIPULATON **/ diff --git a/src/renderer.h b/src/renderer.h index 71319916..74011cb2 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -29,6 +29,10 @@ #include #include +#ifdef Q_WS_MAC +#include "videoglwidget.h" +#endif + /**Render encapsulates the client side of the interface to a renderer. From Kdenlive's point of view, you treat the Render object as the @@ -205,6 +209,9 @@ Q_OBJECT public: const QList producersList(); void updatePreviewSettings(); void setDropFrames(bool show); +#ifdef Q_WS_MAC + void showFrame(Mlt::Frame&); +#endif private: // Private attributes & methods /** The name of this renderer - useful to identify the renderes by what they do - e.g. background rendering, workspace monitor, etc... */ @@ -232,6 +239,10 @@ private: // Private attributes & methods /** A human-readable description of this renderer. */ int m_winid; +#ifdef Q_WS_MAC + VideoGLWidget *m_glWidget; +#endif + /** Sets the description of this renderer to desc. */ void closeMlt(); void mltCheckLength(Mlt::Tractor *tractor); @@ -274,6 +285,8 @@ signals: // Signals void removeInvalidClip(const QString &, bool replaceProducer); void refreshDocumentProducers(); void blockMonitors(); + /** Used on OS X - emitted when a frame's image is to be shown. */ + void showImageSignal(QImage); public slots: // Public slots /** Start Consumer */ diff --git a/src/videoglwidget.cpp b/src/videoglwidget.cpp new file mode 100644 index 00000000..8fa6b344 --- /dev/null +++ b/src/videoglwidget.cpp @@ -0,0 +1,117 @@ + +#include +#include +#include "videoglwidget.h" + +#ifndef GL_TEXTURE_RECTANGLE_EXT +#define GL_TEXTURE_RECTANGLE_EXT GL_TEXTURE_RECTANGLE_NV +#endif + +VideoGLWidget::VideoGLWidget(QWidget *parent) + : QGLWidget(parent) + , m_image_width(0) + , m_image_height(0) + , m_texture(0) + , m_display_ratio(4.0/3.0) + , m_backgroundColor(Qt::gray) +{ +} + +VideoGLWidget::~VideoGLWidget() +{ + makeCurrent(); + if (m_texture) + glDeleteTextures(1, &m_texture); +} + +QSize VideoGLWidget::minimumSizeHint() const +{ + return QSize(40, 30); +} + +QSize VideoGLWidget::sizeHint() const +{ + return QSize(400, 300); +} + +void VideoGLWidget::initializeGL() +{ + qglClearColor(m_backgroundColor); + glShadeModel(GL_FLAT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_LIGHTING); + glDisable(GL_DITHER); + glDisable(GL_BLEND); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +} + +void VideoGLWidget::resizeGL(int width, int height) +{ + double this_aspect = (double) width / height; + + // Special case optimisation to negate odd effect of sample aspect ratio + // not corresponding exactly with image resolution. + if ((int)(this_aspect * 1000) == (int)(m_display_ratio * 1000)) + { + w = width; + h = height; + } + // Use OpenGL to normalise sample aspect ratio + else if (height * m_display_ratio > width) + { + w = width; + h = width / m_display_ratio; + } + else + { + w = height * m_display_ratio; + h = height; + } + x = (width - w) / 2; + y = (height - h) / 2; + + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0, width, height, 0); + glMatrixMode(GL_MODELVIEW); +} + +void VideoGLWidget::paintGL() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (m_texture) + { + glEnable(GL_TEXTURE_RECTANGLE_EXT); + glBegin(GL_QUADS); + glTexCoord2i(0, 0); + glVertex2i(x, y); + glTexCoord2i(m_image_width, 0); + glVertex2i(x + w, y); + glTexCoord2i(m_image_width, m_image_height); + glVertex2i(x + w, y + h); + glTexCoord2i(0, m_image_height); + glVertex2i(x, y + h); + glEnd(); + glDisable(GL_TEXTURE_RECTANGLE_EXT); + } +} + +void VideoGLWidget::showImage(QImage image) +{ + m_image_width = image.width(); + m_image_height = image.height(); + + makeCurrent(); + if (m_texture) + glDeleteTextures(1, &m_texture); + glPixelStorei(GL_UNPACK_ROW_LENGTH, m_image_width); + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_RECTANGLE_EXT, m_texture); + glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA8, m_image_width, m_image_height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, image.bits()); + updateGL(); +} diff --git a/src/videoglwidget.h b/src/videoglwidget.h new file mode 100644 index 00000000..9b089da5 --- /dev/null +++ b/src/videoglwidget.h @@ -0,0 +1,40 @@ + +#ifndef VIDEOGLWIDGET_H +#define VIDEOGLWIDGET_H + +#include + +class VideoGLWidget : public QGLWidget +{ + Q_OBJECT + +public: + VideoGLWidget(QWidget *parent = 0); + ~VideoGLWidget(); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + void setImageAspectRatio(double ratio) { + m_display_ratio = ratio; + } + void setBackgroundColor(QColor color) { + m_backgroundColor = color; + } + +private: + int x, y, w, h; + int m_image_width, m_image_height; + GLuint m_texture; + double m_display_ratio; + QColor m_backgroundColor; + +public slots: + void showImage(QImage image); + +protected: + void initializeGL(); + void resizeGL(int width, int height); + void paintGL(); +}; + +#endif -- 2.39.2