--- /dev/null
+#include <stdexcept>
+#include <msp/fs/dir.h>
+#include <msp/graphics/display_private.h>
+#include <msp/graphics/window_private.h>
+#include "xineengine.h"
+
+using namespace std;
+using namespace Msp;
+
+XineEngine::XineEngine(const Graphics::Window &w, Mutex *m):
+ window(w),
+ display_mutex(m),
+ locked_thread(0),
+ lock_count(0)
+{
+ engine = xine_new();
+
+ FS::Path config_fn = FS::get_home_dir()/".xine"/"config";
+ xine_config_load(engine, config_fn.c_str());
+
+ xine_init(engine);
+
+ audio_driver = xine_open_audio_driver(engine, "auto", 0);
+ if(!audio_driver)
+ throw runtime_error("Could not open audio driver");
+
+ visual.display = window.get_display().get_private().display;
+ visual.screen = 0;
+ visual.d = window.get_private().window;
+ visual.user_data = this;
+ visual.dest_size_cb = &dest_size_cb;
+ visual.frame_output_cb = &frame_output_cb;
+ if(display_mutex)
+ {
+ visual.lock_display = &lock_cb;
+ visual.unlock_display = &unlock_cb;
+ }
+ else
+ {
+ visual.lock_display = 0;
+ visual.unlock_display = 0;
+ }
+
+ video_driver = xine_open_video_driver(engine, "auto", XINE_VISUAL_TYPE_X11_2, &visual);
+ if(!video_driver)
+ throw runtime_error("Could not open video driver");
+}
+
+XineEngine::~XineEngine()
+{
+ xine_close_video_driver(engine, video_driver);
+ xine_close_audio_driver(engine, audio_driver);
+ xine_exit(engine);
+}
+
+void XineEngine::dest_size_cb(void *user_data, int, int, double, int *dest_width, int *dest_height, double *dest_pixel_aspect)
+{
+ XineEngine &engine = *reinterpret_cast<XineEngine *>(user_data);
+ *dest_width = engine.window.get_width();
+ *dest_height = engine.window.get_height();
+ *dest_pixel_aspect = 1.0;
+}
+
+void XineEngine::frame_output_cb(void *user_data, int, int, double, int *dest_x, int *dest_y, int *dest_width, int *dest_height, double *dest_pixel_aspect, int *win_x, int *win_y)
+{
+ XineEngine &engine = *reinterpret_cast<XineEngine *>(user_data);
+ *dest_x = 0;
+ *dest_y = 0;
+ *dest_width = engine.window.get_width();
+ *dest_height = engine.window.get_height();
+ *dest_pixel_aspect = 1.0;
+ *win_x = 0;
+ *win_y = 0;
+}
+
+void XineEngine::lock_cb(void *user_data)
+{
+ XineEngine &engine = *reinterpret_cast<XineEngine *>(user_data);
+ pthread_t tid = pthread_self();
+ if(tid==engine.locked_thread)
+ ++engine.lock_count;
+ else
+ {
+ engine.display_mutex->lock();
+ engine.locked_thread = tid;
+ engine.lock_count = 1;
+ }
+}
+
+void XineEngine::unlock_cb(void *user_data)
+{
+ XineEngine &engine = *reinterpret_cast<XineEngine *>(user_data);
+ pthread_t tid = pthread_self();
+ if(tid!=engine.locked_thread)
+ throw logic_error("Unlock from non-locked thread");
+ if(!--engine.lock_count)
+ {
+ engine.locked_thread = 0;
+ engine.display_mutex->unlock();
+ }
+}
--- /dev/null
+#ifndef XINEENGINE_H_
+#define XINEENGINE_H_
+
+#include <pthread.h>
+#include <xine.h>
+#include <msp/core/mutex.h>
+#include <msp/graphics/window.h>
+
+class XineStream;
+
+class XineEngine
+{
+private:
+ const Msp::Graphics::Window &window;
+ Msp::Mutex *display_mutex;
+ pthread_t locked_thread;
+ unsigned lock_count;
+ xine_t *engine;
+ xine_audio_port_t *audio_driver;
+ x11_visual_t visual;
+ xine_video_port_t *video_driver;
+
+public:
+ XineEngine(const Msp::Graphics::Window &, Msp::Mutex * = 0);
+ ~XineEngine();
+
+ xine_t *get_engine() { return engine; }
+ xine_audio_port_t *get_audio_driver() { return audio_driver; }
+ xine_video_port_t *get_video_driver() { return video_driver; }
+
+private:
+ static void dest_size_cb(void *, int, int, double, int *, int *, double *);
+ static void frame_output_cb(void *, int, int, double, int *, int *, int *, int *, double *, int *, int *);
+ static void lock_cb(void *);
+ static void unlock_cb(void *);
+};
+
+#endif
#include <sigc++/bind.h>
#include <msp/core/getopt.h>
-#include <msp/fs/dir.h>
-#include <msp/graphics/display_private.h>
-#include <msp/graphics/window_private.h>
-#include <msp/io/print.h>
+#include "xineengine.h"
#include "xinema.h"
+#include "xinestream.h"
using namespace std;
using namespace Msp;
-Xinema::EarlyInit::EarlyInit()
-{
- XInitThreads();
-}
-
-
Xinema::Xinema(int argc, char **argv):
window(display, 1920, 1080)
{
int Xinema::main()
{
- xine = xine_new();
-
- FS::Path config_fn = FS::get_home_dir()/".xine"/"config";
- xine_config_load(xine, config_fn.c_str());
-
- xine_init(xine);
-
- xine_audio = xine_open_audio_driver(xine, "auto", 0);
-
- XLockDisplay(display.get_private().display);
window.show();
- XSync(display.get_private().display, false);
- XUnlockDisplay(display.get_private().display);
-
- xine_visual.display = display.get_private().display;
- xine_visual.screen = 0;
- xine_visual.d = window.get_private().window;
- xine_visual.user_data = this;
- xine_visual.dest_size_cb = &dest_size_cb;
- xine_visual.frame_output_cb = &frame_output_cb;
-
- xine_video = xine_open_video_driver(xine, "auto", XINE_VISUAL_TYPE_X11, &xine_visual);
-
- xine_stream = xine_stream_new(xine, xine_audio, xine_video);
- xine_open(xine_stream, filename.c_str());
- xine_play(xine_stream, 0, 0);
+ display.tick();
- xine_queue = xine_event_new_queue(xine_stream);
+ engine = new XineEngine(window, &display_mutex);
+ stream = new XineStream(*engine, filename);
+ stream->play();
Application::main();
- xine_close(xine_stream);
- xine_event_dispose_queue(xine_queue);
- xine_dispose(xine_stream);
- xine_close_video_driver(xine, xine_video);
- xine_close_audio_driver(xine, xine_audio);
- xine_exit(xine);
+ delete stream;
+ delete engine;
return exit_code;
}
void Xinema::tick()
{
- XLockDisplay(display.get_private().display);
- display.tick();
- XUnlockDisplay(display.get_private().display);
-
- while(xine_event_t *event = xine_event_get(xine_queue))
{
- switch(event->type)
- {
- case XINE_EVENT_PROGRESS:
- {
- xine_progress_data_t *data = reinterpret_cast<xine_progress_data_t *>(event->data);
- IO::print("%s [%d%%]\n", data->description, data->percent);
- }
- break;
- }
+ MutexLock lock(display_mutex);
+ display.tick();
}
-}
-void Xinema::dest_size_cb(void *user_data, int, int, double, int *dest_width, int *dest_height, double *dest_pixel_aspect)
-{
- Xinema &xinema = *reinterpret_cast<Xinema *>(user_data);
- *dest_width = xinema.window.get_width();
- *dest_height = xinema.window.get_height();
- *dest_pixel_aspect = 1.0;
-}
-
-void Xinema::frame_output_cb(void *user_data, int, int, double, int *dest_x, int *dest_y, int *dest_width, int *dest_height, double *dest_pixel_aspect, int *win_x, int *win_y)
-{
- Xinema &xinema = *reinterpret_cast<Xinema *>(user_data);
- *dest_x = 0;
- *dest_y = 0;
- *dest_width = xinema.window.get_width();
- *dest_height = xinema.window.get_height();
- *dest_pixel_aspect = 1.0;
- *win_x = 0;
- *win_y = 0;
+ stream->tick();
}
#define XINEMA_H_
#include <msp/core/application.h>
+#include <msp/core/mutex.h>
#include <msp/graphics/display.h>
#include <msp/graphics/window.h>
-#include <xine.h>
+
+class XineEngine;
+class XineStream;
class Xinema: public Msp::RegisteredApplication<Xinema>
{
private:
- struct EarlyInit
- {
- EarlyInit();
- };
-
- EarlyInit early_init;
std::string filename;
Msp::Graphics::Display display;
+ Msp::Mutex display_mutex;
Msp::Graphics::Window window;
- xine_t *xine;
- xine_audio_port_t *xine_audio;
- x11_visual_t xine_visual;
- xine_video_port_t *xine_video;
- xine_stream_t *xine_stream;
- xine_event_queue_t *xine_queue;
+ XineEngine *engine;
+ XineStream *stream;
public:
Xinema(int, char **);
private:
virtual void tick();
-
- static void dest_size_cb(void *, int, int, double, int *, int *, double *);
- static void frame_output_cb(void *, int, int, double, int *, int *, int *, int *, double *, int *, int *);
};
#endif
--- /dev/null
+#include <msp/io/print.h>
+#include "xineengine.h"
+#include "xinestream.h"
+
+using namespace std;
+using namespace Msp;
+
+XineStream::XineStream(XineEngine &engine, const string &mrl)
+{
+ stream = xine_stream_new(engine.get_engine(), engine.get_audio_driver(), engine.get_video_driver());
+ xine_open(stream, mrl.c_str());
+
+ queue = xine_event_new_queue(stream);
+}
+
+XineStream::~XineStream()
+{
+ xine_close(stream);
+ xine_event_dispose_queue(queue);
+ xine_dispose(stream);
+}
+
+void XineStream::play()
+{
+ xine_play(stream, 0, 0);
+}
+
+void XineStream::stop()
+{
+ xine_stop(stream);
+}
+
+void XineStream::tick()
+{
+ while(xine_event_t *event = xine_event_get(queue))
+ {
+ handle_event(*event);
+ xine_event_free(event);
+ }
+}
+
+void XineStream::handle_event(const xine_event_t &event)
+{
+ switch(event.type)
+ {
+ case XINE_EVENT_PROGRESS:
+ {
+ xine_progress_data_t *data = reinterpret_cast<xine_progress_data_t *>(event.data);
+ IO::print("%s [%d%%]\n", data->description, data->percent);
+ }
+ break;
+ }
+}
--- /dev/null
+#ifndef XINESTREAM_H_
+#define XINESTREAM_H_
+
+#include <string>
+#include <xine.h>
+
+class XineEngine;
+
+class XineStream
+{
+private:
+ xine_stream_t *stream;
+ xine_event_queue_t *queue;
+
+public:
+ XineStream(XineEngine &, const std::string &);
+ ~XineStream();
+
+ void play();
+ void stop();
+
+ void tick();
+private:
+ void handle_event(const xine_event_t &);
+};
+
+#endif