Files
haikuports/media-video/qmplay2/patches/qmplay2-19.08.27.patchset
Gerasim Troeglazov 710c5223c4 QMPlay2: bump version
2019-09-01 23:31:04 +10:00

763 lines
17 KiB
Plaintext

From 88801511a1276e4d284b0fe32be9ec8c5855f06a Mon Sep 17 00:00:00 2001
From: Gerasim Troeglazov <3dEyes@gmail.com>
Date: Sun, 1 Sep 2019 22:52:49 +1000
Subject: Add haiku support
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f6710ef..11d985a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,6 +36,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
elseif(ANDROID)
set(DEFAULT_ALSA OFF)
set(DEFAULT_PORTAUDIO OFF)
+elseif(HAIKU)
+ set(DEFAULT_ALSA OFF)
+ set(DEFAULT_PORTAUDIO OFF)
else()
set(DEFAULT_ALSA OFF)
set(DEFAULT_PORTAUDIO ON)
@@ -55,7 +58,7 @@ if(WIN32)
add_feature_info(CMD USE_CMD "Show CMD when running QMPlay2")
endif()
-if(NOT WIN32 AND NOT APPLE AND NOT ANDROID)
+if(NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
option(USE_FREEDESKTOP_NOTIFICATIONS "Use Freedesktop notifications" ON)
add_feature_info("Freedesktop notifications" USE_FREEDESKTOP_NOTIFICATIONS "Use Freedesktop notifications")
endif()
@@ -84,7 +87,7 @@ add_feature_info(Modplug USE_MODPLUG "Build with Modplug module")
option(USE_EXTENSIONS "Build with Extensions module" ON)
add_feature_info(Extensions USE_EXTENSIONS "Build with Extensions module")
-if(USE_EXTENSIONS AND NOT WIN32 AND NOT APPLE AND NOT ANDROID)
+if(USE_EXTENSIONS AND NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
option(USE_MPRIS2 "Build Extensions with MPRIS2 support" ON)
add_feature_info(MPRIS2 USE_MPRIS2 "Build Extensions with MPRIS2 support")
endif()
diff --git a/src/gui/Main.cpp b/src/gui/Main.cpp
index 9c64652..cbe7316 100644
--- a/src/gui/Main.cpp
+++ b/src/gui/Main.cpp
@@ -599,6 +599,10 @@ int main(int argc, char *argv[])
checkForEGL();
#endif
+#ifdef Q_OS_HAIKU
+ setenv("HOME", "/boot/home", 1);
+#endif
+
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#ifndef Q_OS_WIN
QGuiApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
@@ -684,7 +688,7 @@ int main(int argc, char *argv[])
}
if (!cmakeBuildFound)
{
-#if !defined Q_OS_WIN && !defined Q_OS_MACOS && !defined Q_OS_ANDROID
+#if !defined Q_OS_WIN && !defined Q_OS_MACOS && !defined Q_OS_ANDROID && !defined Q_OS_HAIKU
sharePath = QCoreApplication::applicationDirPath() + "/../share/qmplay2";
libPath = QMPlay2CoreClass::getLibDir();
if (libPath.isEmpty() || !QDir(libPath).exists("qmplay2"))
@@ -902,5 +906,9 @@ int main(int argc, char *argv[])
if (canDeleteApp)
#endif
delete qApp;
+
+#ifdef Q_OS_HAIKU
+ kill(::getpid(), SIGKILL);
+#endif
return 0;
}
diff --git a/src/gui/MainWidget.cpp b/src/gui/MainWidget.cpp
index 139dd2a..c9804c5 100644
--- a/src/gui/MainWidget.cpp
+++ b/src/gui/MainWidget.cpp
@@ -145,7 +145,7 @@ MainWidget::MainWidget(QList<QPair<QString, QString>> &arguments) :
setIconSize({22, 22});
SettingsWidget::InitSettings();
-#ifndef Q_OS_ANDROID
+#if !defined Q_OS_ANDROID && !defined Q_OS_HAIKU
settings.init("MainWidget/WidgetsLocked", false);
#else
settings.init("MainWidget/WidgetsLocked", true);
diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt
index 449882a..17b3da6 100644
--- a/src/modules/CMakeLists.txt
+++ b/src/modules/CMakeLists.txt
@@ -7,6 +7,9 @@ if(WIN32)
elseif(APPLE)
set(MODULES_INSTALL_PATH "${CMAKE_INSTALL_LIBDIR}/modules")
set(QMPLAY2_MODULE SHARED) # otherwise CMake uses ".so" extension
+elseif(HAIKU)
+ set(MODULES_INSTALL_PATH "modules")
+ set(QMPLAY2_MODULE MODULE)
else()
set(MODULES_INSTALL_PATH "${CMAKE_INSTALL_LIBDIR}/qmplay2/modules")
set(QMPLAY2_MODULE MODULE)
@@ -60,6 +63,10 @@ if(USE_PULSEAUDIO)
add_subdirectory(PulseAudio)
endif()
+if(HAIKU)
+ add_subdirectory(MediaKit)
+endif()
+
if(USE_XVIDEO)
add_subdirectory(XVideo)
endif()
diff --git a/src/modules/MediaKit/CMakeLists.txt b/src/modules/MediaKit/CMakeLists.txt
new file mode 100644
index 0000000..f94e365
--- /dev/null
+++ b/src/modules/MediaKit/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 3.1)
+project(MediaKit)
+
+set(MediaKit_HDR
+ MediaKit.hpp
+ MediaKitWriter.hpp
+ RingBuffer.hpp
+ SndPlayer.hpp
+)
+
+set(MediaKit_SRC
+ MediaKit.cpp
+ MediaKitWriter.cpp
+ RingBuffer.cpp
+ SndPlayer.cpp
+)
+
+set(MediaKit_RESOURCES
+ icon.qrc
+)
+
+include_directories(../../qmplay2/headers)
+
+add_library(${PROJECT_NAME} ${QMPLAY2_MODULE}
+ ${MediaKit_HDR}
+ ${MediaKit_SRC}
+ ${MediaKit_RESOURCES}
+)
+
+target_link_libraries(${PROJECT_NAME}
+ be
+ media
+ libqmplay2
+)
+
+install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${MODULES_INSTALL_PATH})
diff --git a/src/modules/MediaKit/MediaKit.cpp b/src/modules/MediaKit/MediaKit.cpp
new file mode 100644
index 0000000..cc9998b
--- /dev/null
+++ b/src/modules/MediaKit/MediaKit.cpp
@@ -0,0 +1,65 @@
+#include <MediaKit.hpp>
+#include <MediaKitWriter.hpp>
+
+MediaKit::MediaKit() :
+ Module( "MediaKit" )
+{
+ m_icon = QIcon( ":/MediaKit" );
+
+ init( "WriterEnabled", true );
+ init( "Delay", 0.2 );
+}
+
+QList< MediaKit::Info > MediaKit::getModulesInfo( const bool showDisabled ) const
+{
+ QList< Info > modulesInfo;
+ if ( showDisabled || getBool( "WriterEnabled" ) )
+ modulesInfo += Info( MediaKitWriterName, WRITER, QStringList( "audio" ) );
+ return modulesInfo;
+}
+void *MediaKit::createInstance( const QString &name )
+{
+ if ( name == MediaKitWriterName && getBool( "WriterEnabled" ) )
+ return new MediaKitWriter( *this );
+ return NULL;
+}
+
+MediaKit::SettingsWidget *MediaKit::getSettingsWidget()
+{
+ return new ModuleSettingsWidget( *this );
+}
+
+QMPLAY2_EXPORT_MODULE( MediaKit )
+
+/**/
+
+#include <QDoubleSpinBox>
+#include <QGridLayout>
+#include <QCheckBox>
+#include <QLabel>
+
+ModuleSettingsWidget::ModuleSettingsWidget( Module &module ) :
+ Module::SettingsWidget( module )
+{
+ enabledB = new QCheckBox( tr( "Enabled" ) );
+ enabledB->setChecked( sets().getBool( "WriterEnabled" ) );
+
+ QLabel *delayL = new QLabel( tr( "Delay" ) + ": " );
+
+ delayB = new QDoubleSpinBox;
+ delayB->setRange( 0.01, 1.0 );
+ delayB->setSingleStep( 0.01 );
+ delayB->setSuffix( " " + tr( "sec" ) );
+ delayB->setValue( sets().getDouble( "Delay" ) );
+
+ QGridLayout *layout = new QGridLayout( this );
+ layout->addWidget( enabledB, 0, 0, 1, 2 );
+ layout->addWidget( delayL, 1, 0, 1, 1 );
+ layout->addWidget( delayB, 1, 1, 1, 1 );
+}
+
+void ModuleSettingsWidget::saveSettings()
+{
+ sets().set( "WriterEnabled", enabledB->isChecked() );
+ sets().set( "Delay", delayB->value() );
+}
diff --git a/src/modules/MediaKit/MediaKit.hpp b/src/modules/MediaKit/MediaKit.hpp
new file mode 100644
index 0000000..ed89e32
--- /dev/null
+++ b/src/modules/MediaKit/MediaKit.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <Module.hpp>
+
+class MediaKit : public Module
+{
+public:
+ MediaKit();
+private:
+ QList< Info > getModulesInfo( const bool ) const;
+ void *createInstance( const QString & );
+
+ SettingsWidget *getSettingsWidget();
+};
+
+/**/
+
+#include <QCoreApplication>
+
+class QDoubleSpinBox;
+class QCheckBox;
+
+class ModuleSettingsWidget : public Module::SettingsWidget
+{
+ Q_DECLARE_TR_FUNCTIONS( ModuleSettingsWidget )
+public:
+ ModuleSettingsWidget( Module & );
+private:
+ void saveSettings();
+
+ QCheckBox *enabledB;
+ QDoubleSpinBox *delayB;
+};
diff --git a/src/modules/MediaKit/MediaKitWriter.cpp b/src/modules/MediaKit/MediaKitWriter.cpp
new file mode 100644
index 0000000..a86e584
--- /dev/null
+++ b/src/modules/MediaKit/MediaKitWriter.cpp
@@ -0,0 +1,85 @@
+#include <MediaKitWriter.hpp>
+#include <QMPlay2Core.hpp>
+
+MediaKitWriter::MediaKitWriter( Module &module ) :
+ err( false )
+{
+ addParam( "delay" );
+ addParam( "chn" );
+ addParam( "rate" );
+
+ SetModule( module );
+}
+
+bool MediaKitWriter::set()
+{
+ if ( player.delay != sets().getDouble( "Delay" ) )
+ {
+ player.delay = sets().getDouble( "Delay" );
+ return false;
+ }
+ return sets().getBool( "WriterEnabled" );
+}
+
+bool MediaKitWriter::readyWrite() const
+{
+ return !err && player.isOpen();
+}
+
+bool MediaKitWriter::processParams( bool * )
+{
+ bool resetAudio = false;
+
+ uchar chn = getParam( "chn" ).toUInt();
+ if ( player.channels != chn )
+ {
+ resetAudio = true;
+ player.channels = chn;
+ }
+ uint rate = getParam( "rate" ).toUInt();
+ if ( player.sample_rate != rate )
+ {
+ resetAudio = true;
+ player.sample_rate = rate;
+ }
+
+ if ( resetAudio || err )
+ {
+ player.stop();
+ err = !player.start();
+ if ( !err )
+ modParam( "delay", player.delay );
+ else
+ QMPlay2Core.logError( "MediaKitWriter :: " + tr ( "Cannot open audio output stream" ) );
+ }
+
+ return readyWrite();
+}
+qint64 MediaKitWriter::write( const QByteArray &arr )
+{
+ if ( !arr.size() || !readyWrite() )
+ return 0;
+
+ err = !player.write( arr );
+ if ( err )
+ {
+ QMPlay2Core.logError( "MediaKitWriter :: " + tr ( "Playback error" ) );
+ return 0;
+ }
+
+ return arr.size();
+}
+
+qint64 MediaKitWriter::size() const
+{
+ return -1;
+}
+QString MediaKitWriter::name() const
+{
+ return MediaKitWriterName;
+}
+
+bool MediaKitWriter::open()
+{
+ return player.isOK();
+}
diff --git a/src/modules/MediaKit/MediaKitWriter.hpp b/src/modules/MediaKit/MediaKitWriter.hpp
new file mode 100644
index 0000000..28fa249
--- /dev/null
+++ b/src/modules/MediaKit/MediaKitWriter.hpp
@@ -0,0 +1,30 @@
+#include <Writer.hpp>
+#include <SndPlayer.hpp>
+
+#include <QCoreApplication>
+
+class MediaKitWriter : public Writer
+{
+ Q_DECLARE_TR_FUNCTIONS( MediaKitWriter )
+public:
+ MediaKitWriter( Module & );
+private:
+ bool set();
+
+ bool readyWrite() const;
+
+ bool processParams( bool *paramsCorrected );
+ qint64 write( const QByteArray & );
+
+ qint64 size() const;
+ QString name() const;
+
+ bool open();
+
+ /**/
+
+ SndPlayer player;
+ bool err;
+};
+
+#define MediaKitWriterName "MediaKit Writer"
diff --git a/src/modules/MediaKit/RingBuffer.cpp b/src/modules/MediaKit/RingBuffer.cpp
new file mode 100644
index 0000000..915becc
--- /dev/null
+++ b/src/modules/MediaKit/RingBuffer.cpp
@@ -0,0 +1,129 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "RingBuffer.hpp"
+
+RingBuffer::RingBuffer( int size )
+{
+ initialized = false;
+ Buffer = new unsigned char[size];
+ if(Buffer!=NULL) {
+ memset( Buffer, 0, size );
+ BufferSize = size;
+ } else {
+ BufferSize = 0;
+ }
+ reader = 0;
+ writer = 0;
+ writeBytesAvailable = size;
+ if((locker=create_sem(1,"locker")) >= B_OK) {
+ initialized = true;
+ } else {
+ if(Buffer!=NULL) {
+ delete[] Buffer;
+ }
+ }
+}
+
+RingBuffer::~RingBuffer( )
+{
+ if(initialized) {
+ delete[] Buffer;
+ delete_sem(locker);
+ }
+}
+
+bool
+RingBuffer::Empty( void )
+{
+ memset( Buffer, 0, BufferSize );
+ reader = 0;
+ writer = 0;
+ writeBytesAvailable = BufferSize;
+ return true;
+}
+
+int
+RingBuffer::Read( unsigned char *data, int size )
+{
+ acquire_sem(locker);
+
+ if( data == 0 || size <= 0 || writeBytesAvailable == BufferSize ) {
+ release_sem(locker);
+ return 0;
+ }
+
+ int readBytesAvailable = BufferSize - writeBytesAvailable;
+
+ if( size > readBytesAvailable ) {
+ size = readBytesAvailable;
+ }
+
+ if(size > BufferSize - reader) {
+ int len = BufferSize - reader;
+ memcpy(data, Buffer + reader, len);
+ memcpy(data + len, Buffer, size-len);
+ } else {
+ memcpy(data, Buffer + reader, size);
+ }
+
+ reader = (reader + size) % BufferSize;
+ writeBytesAvailable += size;
+
+ release_sem(locker);
+ return size;
+}
+
+int
+RingBuffer::Write( unsigned char *data, int size )
+{
+ acquire_sem(locker);
+
+ if( data == 0 || size <= 0 || writeBytesAvailable == 0 ) {
+ release_sem(locker);
+ return 0;
+ }
+
+ if( size > writeBytesAvailable ) {
+ size = writeBytesAvailable;
+ }
+
+ if(size > BufferSize - writer) {
+ int len = BufferSize - writer;
+ memcpy(Buffer + writer, data, len);
+ memcpy(Buffer, data+len, size-len);
+ } else {
+ memcpy(Buffer + writer, data, size);
+ }
+
+ writer = (writer + size) % BufferSize;
+ writeBytesAvailable -= size;
+
+ release_sem(locker);
+ return size;
+}
+
+int
+RingBuffer::GetSize( void )
+{
+ return BufferSize;
+}
+
+int
+RingBuffer::GetWriteAvailable( void )
+{
+ return writeBytesAvailable;
+}
+
+int
+RingBuffer::GetReadAvailable( void )
+{
+ return BufferSize - writeBytesAvailable;
+}
+
+status_t
+RingBuffer::InitCheck( void )
+{
+ return initialized?B_OK:B_ERROR;
+}
diff --git a/src/modules/MediaKit/RingBuffer.hpp b/src/modules/MediaKit/RingBuffer.hpp
new file mode 100644
index 0000000..4715632
--- /dev/null
+++ b/src/modules/MediaKit/RingBuffer.hpp
@@ -0,0 +1,31 @@
+#ifndef __RING_BUFFER_H__
+#define __RING_BUFFER_H__
+
+#include <OS.h>
+
+class RingBuffer {
+
+public:
+ RingBuffer(int size);
+ ~RingBuffer();
+ int Read( unsigned char* dataPtr, int numBytes );
+ int Write( unsigned char *dataPtr, int numBytes );
+
+ bool Empty( void );
+ int GetSize( );
+ int GetWriteAvailable( );
+ int GetReadAvailable( );
+ status_t InitCheck( );
+private:
+ unsigned char *Buffer;
+ int BufferSize;
+ int reader;
+ int writer;
+ int writeBytesAvailable;
+
+ sem_id locker;
+
+ bool initialized;
+};
+
+#endif
diff --git a/src/modules/MediaKit/SndPlayer.cpp b/src/modules/MediaKit/SndPlayer.cpp
new file mode 100644
index 0000000..ca7ad89
--- /dev/null
+++ b/src/modules/MediaKit/SndPlayer.cpp
@@ -0,0 +1,103 @@
+#include <SndPlayer.hpp>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <SoundPlayer.h>
+
+
+static void proc(void *cookie, void *buffer, size_t len, const media_raw_audio_format &format)
+{
+ RingBuffer *ring = (RingBuffer*)cookie;
+ unsigned char* ptr = (unsigned char*)buffer;
+
+ int readed = ring->Read(ptr,len);
+
+ if(readed <len)
+ memset(ptr+readed, 0, len - readed);
+}
+
+SndPlayer::SndPlayer()
+{
+ channels = sample_rate = delay = 0;
+ player = NULL;
+ _isOK = true;
+}
+
+bool SndPlayer::start()
+{
+ int gSoundBufferSize = 8192 * sizeof(float);
+
+ media_raw_audio_format form = {
+ sample_rate,
+ channels,
+ media_raw_audio_format::B_AUDIO_FLOAT,
+ B_MEDIA_LITTLE_ENDIAN,
+ gSoundBufferSize
+ };
+
+ ring = new RingBuffer(gSoundBufferSize * 3);
+ if(ring->InitCheck() != B_OK) {
+ delete ring; ring = 0;
+ return false;
+ }
+
+ player = new BSoundPlayer(&form, "QMPlay2_BSoundPlayer", proc, NULL, (void*)ring);
+
+ if(player->InitCheck() != B_OK) {
+ delete player;
+ player = NULL;
+ return false;
+ }
+
+ player->Start();
+ player->SetHasData(true);
+
+ _isOK = true;
+
+ return player;
+}
+void SndPlayer::stop()
+{
+ if ( player )
+ {
+ if(player) {
+ player->Stop();
+ delete player;
+ delete ring;
+ }
+
+ player = NULL;
+ ring = NULL;
+ }
+}
+
+double SndPlayer::getLatency()
+{
+ double lat = player->Latency() / (ring->GetSize()*4.0);
+
+ return lat;
+}
+
+bool SndPlayer::write( const QByteArray &arr )
+{
+ int s = arr.size();
+ while ( s > 0 && s % 4 )
+ s--;
+ if ( s <= 0 )
+ return false;
+
+ int len=s;
+
+ unsigned char *src_ptr = (unsigned char *)arr.data();
+
+ for(;;) {
+ int len2 = ring->Write(src_ptr,len);
+ if(len2 == len)break;
+ len -= len2;
+ src_ptr += len2;
+ snooze(100);
+ }
+
+ return true;
+}
diff --git a/src/modules/MediaKit/SndPlayer.hpp b/src/modules/MediaKit/SndPlayer.hpp
new file mode 100644
index 0000000..b0ca8c2
--- /dev/null
+++ b/src/modules/MediaKit/SndPlayer.hpp
@@ -0,0 +1,49 @@
+#ifndef PULSE_HPP
+#define PULSE_HPP
+
+#include <QByteArray>
+
+#include <SoundPlayer.h>
+
+#include <Window.h>
+#include <View.h>
+#include <TextControl.h>
+
+#include "RingBuffer.hpp"
+
+class SndPlayer
+{
+public:
+ SndPlayer();
+ inline ~SndPlayer()
+ {
+ stop();
+ }
+
+ inline bool isOK() const
+ {
+ return _isOK;
+ }
+ inline bool isOpen() const
+ {
+ return player;
+ }
+
+ bool start();
+ void stop();
+
+ double getLatency();
+
+ bool write( const QByteArray & );
+
+ double delay;
+ uchar channels;
+ uint sample_rate;
+
+private:
+ bool _isOK;
+ BSoundPlayer *player;
+ RingBuffer *ring;
+};
+
+#endif
diff --git a/src/modules/MediaKit/icon.qrc b/src/modules/MediaKit/icon.qrc
new file mode 100644
index 0000000..24b4ebd
--- /dev/null
+++ b/src/modules/MediaKit/icon.qrc
@@ -0,0 +1,3 @@
+<RCC><qresource>
+ <file alias="MediaKit">MediaKit.png</file>
+</qresource></RCC>
diff --git a/src/qmplay2/QMPlay2Core.cpp b/src/qmplay2/QMPlay2Core.cpp
index 55f775d..044ea1f 100644
--- a/src/qmplay2/QMPlay2Core.cpp
+++ b/src/qmplay2/QMPlay2Core.cpp
@@ -201,7 +201,7 @@ void QMPlay2CoreClass::init(bool loadModules, bool modulesInSubdirs, const QStri
settingsDir = QCoreApplication::applicationDirPath() + "/settings/";
else
{
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_OS_HAIKU)
settingsDir = QFileInfo(QSettings(QSettings::IniFormat, QSettings::UserScope, QString()).fileName()).absolutePath() + "/QMPlay2/";
#elif defined(Q_OS_MACOS)
settingsDir = Functions::cleanPath(QStandardPaths::standardLocations(QStandardPaths::DataLocation).value(0, settingsDir));
@@ -392,6 +392,11 @@ QStringList QMPlay2CoreClass::getModules(const QString &type, int typeLen) const
#elif defined Q_OS_WIN
if (type == "videoWriters")
defaultModules << "OpenGL 2" << "DirectDraw";
+#elif defined Q_OS_HAIKU
+ if ( type == "videoWriters" )
+ defaultModules << "QPainter";
+ else if ( type == "audioWriters" )
+ defaultModules << "MediaKit";
#endif
if (type == "decoders")
defaultModules << "FFmpeg Decoder";
--
2.23.0