Difference between revisions of "Building Plugins:HelloMyth"
(→mythhello.pro Files) |
|||
(34 intermediate revisions by 12 users not shown) | |||
Line 1: | Line 1: | ||
− | |||
[[Category:HOWTO]] | [[Category:HOWTO]] | ||
[[Category:Developer_Documentation]] | [[Category:Developer_Documentation]] | ||
Line 9: | Line 8: | ||
As a '''disclaimer''', I am also very new to plugin development and so please correct me where I might be wrong. | As a '''disclaimer''', I am also very new to plugin development and so please correct me where I might be wrong. | ||
− | + | Before you start you may need to install some development tools if you don't already have them (Qt5 development tools and headers) (For reference you can see a full list of dependencies the Ubuntu packaging needs to build [https://github.com/MythTV/packaging/blob/fixes/31/deb/debian/control#L11 here]. For example: | |
+ | <pre> | ||
+ | sudo apt-get install qt5-qmake libqt5-dev ccache git g++ libmyth-dev | ||
+ | </pre> | ||
+ | |||
+ | NOTE: a quick way for those using Ubuntu to install all the required build dependencies is to use this (you will have to find and uncomment the correct '''deb-src''' line from /etc/apt/sources.list.d/ for this to work): | ||
+ | <pre> | ||
+ | sudo apt-get build-dep mythtv | ||
+ | </pre> | ||
+ | |||
+ | Now lets get a copy of the MythTV source code from the git repository at [https://github.com/organizations/MythTV github]: | ||
<pre> | <pre> | ||
− | + | git clone git://github.com/MythTV/mythtv.git | |
− | |||
</pre> | </pre> | ||
− | + | By default a new checkout from git will use the master branch but you can choose any branch you require for example to use the fixes/31 branch do this: | |
− | <pre>sudo | + | <pre> |
+ | git checkout fixes/31 | ||
+ | </pre> | ||
+ | |||
+ | At this point it would be wise to make sure you can build, install and run the clean sources before making any changes (change the configure parameters as required - the example assumes you want to install to the same place as some packages like Ubuntu do). | ||
+ | <pre> | ||
+ | cd mythtv | ||
+ | ./configure --prefix=/usr | ||
+ | make -j4 | ||
+ | sudo make install | ||
+ | cd ../mythplugins | ||
+ | ./configure --prefix=/usr | ||
+ | make -j4 | ||
+ | sudo make install | ||
+ | </pre> | ||
+ | You can now test the install to make sure everything is working correctly. | ||
+ | |||
+ | Now lets add our new plugin - create the following directory tree within the mythplugins directory: | ||
+ | <pre> | ||
+ | cd mythtv/mythplugins | ||
+ | mkdir -p mythhello/mythhello | ||
</pre> | </pre> | ||
Line 35: | Line 63: | ||
2) Create another file called mythhello.pro in the second mythhello (mythplugins/mythhello/mythhello/mythhello.pro) directory | 2) Create another file called mythhello.pro in the second mythhello (mythplugins/mythhello/mythhello/mythhello.pro) directory | ||
+ | {{Code box|mythhello.pro| | ||
<pre> | <pre> | ||
include ( ../../mythconfig.mak ) | include ( ../../mythconfig.mak ) | ||
include ( ../../settings.pro ) | include ( ../../settings.pro ) | ||
+ | include ( ../../programs-libs.pro ) | ||
+ | |||
+ | QT += network sql xml widgets | ||
TEMPLATE = lib | TEMPLATE = lib | ||
Line 45: | Line 77: | ||
INSTALLS += target | INSTALLS += target | ||
− | + | INCLUDEPATH += $${PREFIX}/include/mythtv | |
− | + | INCLUDEPATH += $${PREFIX}/include/mythtv/libmythui | |
− | installfiles.path = $${PREFIX}/share/mythtv | + | INCLUDEPATH += $${PREFIX}/include/mythtv/libmythbase |
+ | |||
+ | installfiles.path = $${PREFIX}/share/mythtv/themes/default | ||
installfiles.files = hello-ui.xml | installfiles.files = hello-ui.xml | ||
− | INSTALLS += | + | INSTALLS += installfiles |
# Input | # Input | ||
Line 56: | Line 90: | ||
SOURCES += main.cpp mythhello.cpp | SOURCES += main.cpp mythhello.cpp | ||
− | + | DEFINES += MPLUGIN_API | |
− | + | ||
+ | use_hidesyms { | ||
+ | QMAKE_CXXFLAGS += -fvisibility=hidden | ||
} | } | ||
− | |||
+ | android { | ||
+ | # to discriminate plugins in a flat directory structure | ||
+ | TARGET = mythplugin$${TARGET} | ||
+ | } | ||
− | + | include ( ../../libs-targetfix.pro ) | |
− | |||
− | |||
− | |||
</pre> | </pre> | ||
+ | }} | ||
− | + | === CPP Files === | |
− | + | Now we create the cpp/h files which should be put in mythplugins/mythhello/mythhello/. | |
− | + | Here's the main file that takes care of initializing, running and destructing the plugin: | |
+ | |||
+ | {{Code box|main.cpp| | ||
+ | <pre> | ||
+ | // C++ headers | ||
+ | #include <unistd.h> | ||
− | + | // QT headers | |
+ | #include <QApplication> | ||
− | + | // MythTV headers | |
+ | #include <mythcontext.h> | ||
+ | #include <mythcorecontext.h> | ||
+ | #include <mythplugin.h> | ||
+ | #include <mythpluginapi.h> | ||
+ | #include <mythversion.h> | ||
+ | #include <mythmainwindow.h> | ||
− | + | // MythHello headers | |
+ | #include "mythhello.h" | ||
− | |||
− | |||
− | |||
using namespace std; | using namespace std; | ||
− | + | static int RunHello(void) | |
− | + | { | |
− | + | MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); | |
− | + | ||
− | + | MythHello *mythhello = new MythHello(mainStack, "hello"); | |
+ | |||
+ | if (mythhello->Create()) | ||
+ | { | ||
+ | mainStack->AddScreen(mythhello); | ||
+ | return 0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | delete mythhello; | ||
+ | return -1; | ||
+ | } | ||
+ | } | ||
− | + | static void runHello(void) | |
− | + | { | |
− | + | RunHello(); | |
− | + | } | |
+ | |||
+ | static void setupKeys(void) | ||
+ | { | ||
+ | REG_JUMP("MythHello", QT_TRANSLATE_NOOP("MythHello", | ||
+ | "Sample plugin"), "", runHello); | ||
} | } | ||
int mythplugin_init(const char *libversion) | int mythplugin_init(const char *libversion) | ||
{ | { | ||
− | if (! | + | if (!gCoreContext->TestPluginVersion("mythhello", |
+ | libversion, | ||
+ | MYTH_BINARY_VERSION)) | ||
return -1; | return -1; | ||
− | + | ||
+ | setupKeys(); | ||
+ | |||
return 0; | return 0; | ||
} | } | ||
− | int mythplugin_run (void) | + | int mythplugin_run(void) |
{ | { | ||
− | + | return RunHello(); | |
+ | } | ||
− | + | int mythplugin_config(void) | |
− | + | { | |
− | + | return 0; | |
− | |||
− | |||
− | return | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
</pre> | </pre> | ||
+ | }} | ||
− | + | {{Code box|mythhello.h| | |
− | |||
<pre> | <pre> | ||
#ifndef MYTHHELLO_H | #ifndef MYTHHELLO_H | ||
#define MYTHHELLO_H | #define MYTHHELLO_H | ||
− | + | // MythTV headers | |
− | |||
− | |||
− | |||
+ | #include <mythscreentype.h> | ||
+ | #include <mythuibutton.h> | ||
− | class MythHello : | + | |
+ | /** \class MythHello | ||
+ | * \brief Example plugin. Shows how to use Text areas and buttons | ||
+ | */ | ||
+ | class MythHello : public MythScreenType | ||
{ | { | ||
+ | Q_OBJECT | ||
+ | |||
+ | public: | ||
+ | MythHello(MythScreenStack *parent, QString name); | ||
+ | bool Create(void) override; // MythScreenType | ||
+ | bool keyPressEvent(QKeyEvent *) override; // MythScreenType | ||
+ | |||
+ | |||
+ | private: | ||
+ | MythUIText *m_titleText; | ||
+ | MythUIText *m_outText; | ||
+ | MythUIButton *m_cancelButton; | ||
+ | MythUIButton *m_okButton; | ||
+ | private slots: | ||
+ | void ok_clicked(void); | ||
+ | void cancel_clicked(void); | ||
+ | }; | ||
− | + | #endif /* MYTHHELLO_H */ | |
+ | </pre> | ||
+ | }} | ||
− | + | {{Code box|mythhello.cpp| | |
− | + | <pre> | |
− | + | // POSIX headers | |
+ | #include <unistd.h> | ||
− | + | // MythTV headers | |
+ | #include <mythuibutton.h> | ||
+ | #include <mythuitext.h> | ||
+ | #include <mythmainwindow.h> | ||
+ | #include <mythcontext.h> | ||
+ | #include <mythdirs.h> | ||
+ | // MythHello headers | ||
+ | #include "mythhello.h" | ||
− | # | + | #define LOC QString("MythHello: ") |
− | + | #define LOC_WARN QString("MythHello, Warning: ") | |
+ | #define LOC_ERR QString("MythHello, Error: ") | ||
− | + | /** \brief Creates a new MythHello Screen | |
+ | * \param parent Pointer to the screen stack | ||
+ | * \param name The name of the window | ||
+ | */ | ||
+ | MythHello::MythHello(MythScreenStack *parent, QString name) : | ||
+ | MythScreenType(parent, name), | ||
+ | m_cancelButton(NULL) | ||
− | + | { | |
− | + | //example of how to find the configuration dir currently used. | |
− | + | QString confdir = GetConfDir(); | |
+ | LOG(VB_GENERAL, LOG_DEBUG, LOC + "Conf dir:" + confdir); | ||
+ | } | ||
+ | |||
+ | bool MythHello::Create(void) | ||
+ | { | ||
+ | bool foundtheme = false; | ||
− | / | + | // Load the theme for this screen |
− | + | foundtheme = LoadWindowFromXML("hello-ui.xml", "hello", this); | |
− | + | ||
− | + | if (!foundtheme) | |
− | + | return false; | |
+ | |||
+ | bool err = false; | ||
+ | UIUtilE::Assign(this, m_titleText, "title", &err); | ||
+ | UIUtilE::Assign(this, m_outText, "outtext", &err); | ||
+ | UIUtilE::Assign(this, m_cancelButton, "cancel", &err); | ||
+ | UIUtilE::Assign(this, m_okButton, "ok", &err); | ||
− | + | if (err) | |
− | + | { | |
− | + | LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'hello'"); | |
+ | return false; | ||
+ | } | ||
+ | |||
− | + | BuildFocusList(); | |
+ | SetFocusWidget(m_cancelButton); | ||
− | + | connect(m_okButton, SIGNAL(Clicked()), this, SLOT(ok_clicked())); | |
+ | connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(cancel_clicked())); | ||
+ | |||
+ | return true; | ||
+ | } | ||
− | MythHello:: | + | bool MythHello::keyPressEvent(QKeyEvent *event) |
− | |||
− | |||
{ | { | ||
+ | if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event)) | ||
+ | return true; | ||
+ | |||
+ | bool handled = false; | ||
+ | QStringList actions; | ||
+ | handled = GetMythMainWindow()->TranslateKeyPress("Hello", event, actions); | ||
+ | for (int i = 0; i < actions.size() && !handled; i++) | ||
+ | { | ||
+ | QString action = actions[i]; | ||
+ | handled = true; | ||
+ | |||
+ | if (action == "ESCAPE") | ||
+ | Close(); | ||
+ | else | ||
+ | handled = false; | ||
+ | } | ||
+ | |||
+ | if (!handled && MythScreenType::keyPressEvent(event)) | ||
+ | handled = true; | ||
+ | |||
+ | return handled; | ||
} | } | ||
− | MythHello:: | + | void MythHello::ok_clicked(void) |
+ | { | ||
+ | m_outText->SetText(QString("OK clicked")); | ||
+ | } | ||
− | + | void MythHello::cancel_clicked(void) | |
− | </pre> | + | { |
+ | m_outText->SetText(QString("Cancel clicked")); | ||
+ | }</pre> | ||
+ | }} | ||
=== The UI File === | === The UI File === | ||
Line 188: | Line 332: | ||
What would a plugin be without a UI? Now create hello-ui.xml and put it in mythplugins/mythhello/mythhello/. | What would a plugin be without a UI? Now create hello-ui.xml and put it in mythplugins/mythhello/mythhello/. | ||
+ | {{Code box|hello-ui.xml| | ||
<pre> | <pre> | ||
<?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||
<mythuitheme> | <mythuitheme> | ||
+ | <window name="hello"> | ||
+ | <textarea name="title"> | ||
+ | <area>0,10,800,100</area> | ||
+ | <font>large</font> | ||
+ | <align>allcenter</align> | ||
+ | <multiline>yes</multiline> | ||
+ | <value>Hello World</value> | ||
+ | </textarea> | ||
− | + | <textarea name="outtext"> | |
+ | <area>0,300,800,100</area> | ||
+ | <font>large</font> | ||
+ | <align>allcenter</align> | ||
+ | <multiline>yes</multiline> | ||
+ | </textarea> | ||
− | + | <button name="cancel" from="basebutton"> | |
− | + | <position>500,400</position> | |
− | + | <value>Cancel</value> | |
− | + | </button> | |
− | |||
− | + | <button name="ok" from="basebutton"> | |
− | + | <position>200,400</position> | |
+ | <value>OK</value> | ||
+ | </button> | ||
+ | </window> | ||
+ | </mythuitheme> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</pre> | </pre> | ||
+ | }} | ||
=== Building === | === Building === | ||
Line 220: | Line 373: | ||
<pre> | <pre> | ||
− | |||
qmake | qmake | ||
make | make | ||
− | make install | + | sudo make install |
</pre> | </pre> | ||
− | Make sure everything compiled OK and the files where copied to your | + | Make sure everything compiled OK and the files where copied to your MythTV installation directories. |
− | |||
− | |||
=== Adding MythHello to your Menus === | === Adding MythHello to your Menus === | ||
Line 253: | Line 403: | ||
[[MythPlugin Architecture]] | [[MythPlugin Architecture]] | ||
+ | |||
+ | [[Building_Plugins:MythNotes]] - Another plug-in tutorial | ||
+ | |||
+ | If you wish to compile the existing set of plugins, you will need at least the following packages (it is a long list): | ||
+ | <pre> | ||
+ | sudo apt-get install libxinerama-dev libxv-dev libxrandr-dev libxml2-dev libavahi-compat-libdnssd-dev libssl-dev libass-dev libfftw3-dev libmp3lame-dev libva-dev libasound2-dev libpulse-dev libsdl1.2-dev libfreetype6-dev libpng12-dev libx264-dev libvpx-dev libcrystalhd-dev libudev-dev uuid-dev libbz2-dev libmysqlclient-dev python-oauth libdate-manip-perl libdatetime-format-iso8601-perl libimage-size-perl libsoap-lite-perl libjson-perl dcraw libcdio-paranoia-dev libraw1394-dev libiec61883-dev libavc1394-dev libtag1-dev libflac-dev libvorbis-dev libexif-dev | ||
+ | </pre> | ||
[[Category:HOWTO]] | [[Category:HOWTO]] |
Latest revision as of 15:36, 10 May 2020
Contents
Creating Your First Plugin: Hello Myth
This is a really simple skeleton plugin that doesn't do anything. It'll show you what is absolutely necessary to create a plugin, then you can expand on that by dissecting others.
As a disclaimer, I am also very new to plugin development and so please correct me where I might be wrong.
Before you start you may need to install some development tools if you don't already have them (Qt5 development tools and headers) (For reference you can see a full list of dependencies the Ubuntu packaging needs to build here. For example:
sudo apt-get install qt5-qmake libqt5-dev ccache git g++ libmyth-dev
NOTE: a quick way for those using Ubuntu to install all the required build dependencies is to use this (you will have to find and uncomment the correct deb-src line from /etc/apt/sources.list.d/ for this to work):
sudo apt-get build-dep mythtv
Now lets get a copy of the MythTV source code from the git repository at github:
git clone git://github.com/MythTV/mythtv.git
By default a new checkout from git will use the master branch but you can choose any branch you require for example to use the fixes/31 branch do this:
git checkout fixes/31
At this point it would be wise to make sure you can build, install and run the clean sources before making any changes (change the configure parameters as required - the example assumes you want to install to the same place as some packages like Ubuntu do).
cd mythtv ./configure --prefix=/usr make -j4 sudo make install cd ../mythplugins ./configure --prefix=/usr make -j4 sudo make install
You can now test the install to make sure everything is working correctly.
Now lets add our new plugin - create the following directory tree within the mythplugins directory:
cd mythtv/mythplugins mkdir -p mythhello/mythhello
mythhello.pro Files
The *.pro files are used by qmake to create the Makefiles.
1) Create a file called mythhello.pro in the first mythhello directory:
TEMPLATE = subdirs # Directories SUBDIRS = mythhello
"mythhello" refers to the second mythhello directory.
2) Create another file called mythhello.pro in the second mythhello (mythplugins/mythhello/mythhello/mythhello.pro) directory
include ( ../../mythconfig.mak ) include ( ../../settings.pro ) include ( ../../programs-libs.pro ) QT += network sql xml widgets TEMPLATE = lib CONFIG += plugin thread TARGET = mythhello target.path = $${LIBDIR}/mythtv/plugins INSTALLS += target INCLUDEPATH += $${PREFIX}/include/mythtv INCLUDEPATH += $${PREFIX}/include/mythtv/libmythui INCLUDEPATH += $${PREFIX}/include/mythtv/libmythbase installfiles.path = $${PREFIX}/share/mythtv/themes/default installfiles.files = hello-ui.xml INSTALLS += installfiles # Input HEADERS += mythhello.h SOURCES += main.cpp mythhello.cpp DEFINES += MPLUGIN_API use_hidesyms { QMAKE_CXXFLAGS += -fvisibility=hidden } android { # to discriminate plugins in a flat directory structure TARGET = mythplugin$${TARGET} } include ( ../../libs-targetfix.pro )
CPP Files
Now we create the cpp/h files which should be put in mythplugins/mythhello/mythhello/.
Here's the main file that takes care of initializing, running and destructing the plugin:
// C++ headers #include <unistd.h> // QT headers #include <QApplication> // MythTV headers #include <mythcontext.h> #include <mythcorecontext.h> #include <mythplugin.h> #include <mythpluginapi.h> #include <mythversion.h> #include <mythmainwindow.h> // MythHello headers #include "mythhello.h" using namespace std; static int RunHello(void) { MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); MythHello *mythhello = new MythHello(mainStack, "hello"); if (mythhello->Create()) { mainStack->AddScreen(mythhello); return 0; } else { delete mythhello; return -1; } } static void runHello(void) { RunHello(); } static void setupKeys(void) { REG_JUMP("MythHello", QT_TRANSLATE_NOOP("MythHello", "Sample plugin"), "", runHello); } int mythplugin_init(const char *libversion) { if (!gCoreContext->TestPluginVersion("mythhello", libversion, MYTH_BINARY_VERSION)) return -1; setupKeys(); return 0; } int mythplugin_run(void) { return RunHello(); } int mythplugin_config(void) { return 0; }
#ifndef MYTHHELLO_H #define MYTHHELLO_H // MythTV headers #include <mythscreentype.h> #include <mythuibutton.h> /** \class MythHello * \brief Example plugin. Shows how to use Text areas and buttons */ class MythHello : public MythScreenType { Q_OBJECT public: MythHello(MythScreenStack *parent, QString name); bool Create(void) override; // MythScreenType bool keyPressEvent(QKeyEvent *) override; // MythScreenType private: MythUIText *m_titleText; MythUIText *m_outText; MythUIButton *m_cancelButton; MythUIButton *m_okButton; private slots: void ok_clicked(void); void cancel_clicked(void); }; #endif /* MYTHHELLO_H */
// POSIX headers #include <unistd.h> // MythTV headers #include <mythuibutton.h> #include <mythuitext.h> #include <mythmainwindow.h> #include <mythcontext.h> #include <mythdirs.h> // MythHello headers #include "mythhello.h" #define LOC QString("MythHello: ") #define LOC_WARN QString("MythHello, Warning: ") #define LOC_ERR QString("MythHello, Error: ") /** \brief Creates a new MythHello Screen * \param parent Pointer to the screen stack * \param name The name of the window */ MythHello::MythHello(MythScreenStack *parent, QString name) : MythScreenType(parent, name), m_cancelButton(NULL) { //example of how to find the configuration dir currently used. QString confdir = GetConfDir(); LOG(VB_GENERAL, LOG_DEBUG, LOC + "Conf dir:" + confdir); } bool MythHello::Create(void) { bool foundtheme = false; // Load the theme for this screen foundtheme = LoadWindowFromXML("hello-ui.xml", "hello", this); if (!foundtheme) return false; bool err = false; UIUtilE::Assign(this, m_titleText, "title", &err); UIUtilE::Assign(this, m_outText, "outtext", &err); UIUtilE::Assign(this, m_cancelButton, "cancel", &err); UIUtilE::Assign(this, m_okButton, "ok", &err); if (err) { LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'hello'"); return false; } BuildFocusList(); SetFocusWidget(m_cancelButton); connect(m_okButton, SIGNAL(Clicked()), this, SLOT(ok_clicked())); connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(cancel_clicked())); return true; } bool MythHello::keyPressEvent(QKeyEvent *event) { if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event)) return true; bool handled = false; QStringList actions; handled = GetMythMainWindow()->TranslateKeyPress("Hello", event, actions); for (int i = 0; i < actions.size() && !handled; i++) { QString action = actions[i]; handled = true; if (action == "ESCAPE") Close(); else handled = false; } if (!handled && MythScreenType::keyPressEvent(event)) handled = true; return handled; } void MythHello::ok_clicked(void) { m_outText->SetText(QString("OK clicked")); } void MythHello::cancel_clicked(void) { m_outText->SetText(QString("Cancel clicked")); }
The UI File
What would a plugin be without a UI? Now create hello-ui.xml and put it in mythplugins/mythhello/mythhello/.
<?xml version="1.0" encoding="utf-8"?> <mythuitheme> <window name="hello"> <textarea name="title"> <area>0,10,800,100</area> <font>large</font> <align>allcenter</align> <multiline>yes</multiline> <value>Hello World</value> </textarea> <textarea name="outtext"> <area>0,300,800,100</area> <font>large</font> <align>allcenter</align> <multiline>yes</multiline> </textarea> <button name="cancel" from="basebutton"> <position>500,400</position> <value>Cancel</value> </button> <button name="ok" from="basebutton"> <position>200,400</position> <value>OK</value> </button> </window> </mythuitheme>
Building
Go to the top mythhello directory (mythplugins/mythhello) and run these commands:
qmake make sudo make install
Make sure everything compiled OK and the files where copied to your MythTV installation directories.
Adding MythHello to your Menus
As a final step you have to add your plugin to the main MythTv menu -- in my case /usr/share/mythtv/mainmenu.xml. Add the following anywhere in the XML file between the <mythmenu> root tag:
<button> <type>HELLO_MYTH</type> <text>Hello Myth</text> <action>PLUGIN mythhello</action> </button>
Finishing Up
Now restart MythFrontend and you should see a 'Hello Myth' button on the main menu.
Good Luck
- Mozmonkey
More about plugins
Building_Plugins:MythNotes - Another plug-in tutorial
If you wish to compile the existing set of plugins, you will need at least the following packages (it is a long list):
sudo apt-get install libxinerama-dev libxv-dev libxrandr-dev libxml2-dev libavahi-compat-libdnssd-dev libssl-dev libass-dev libfftw3-dev libmp3lame-dev libva-dev libasound2-dev libpulse-dev libsdl1.2-dev libfreetype6-dev libpng12-dev libx264-dev libvpx-dev libcrystalhd-dev libudev-dev uuid-dev libbz2-dev libmysqlclient-dev python-oauth libdate-manip-perl libdatetime-format-iso8601-perl libimage-size-perl libsoap-lite-perl libjson-perl dcraw libcdio-paranoia-dev libraw1394-dev libiec61883-dev libavc1394-dev libtag1-dev libflac-dev libvorbis-dev libexif-dev