From 06fdc7b8971303138564e429d4095888f3ecb0b7 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Fri, 25 May 2012 18:14:32 +0200 Subject: [PATCH] Qt-based media player This patch implements a simple Qt-based media player which is actually a graphical user interface for the SDL-based 'avplay' media player from 'libav'. It starts 'avplay' as a child and shows its graphical output in a 'QNitpickerViewWidget'. The widgets for controlling the player state send the according keyboard and mouse input events to 'avplay'. The 'qt_avplay' player supports the following configuration options: -> name of the media file to play (may appear multiple times) -> name of a framebuffer filter service to filter the video output Fixes #222. --- .../input/ps2 => include/input}/event_queue.h | 1 + os/src/drivers/input/ps2/ps2_keyboard.h | 2 +- os/src/drivers/input/ps2/ps2_mouse.h | 2 +- qt4/run/qt_avplay.run | 160 ++++++++++++++++++ qt4/src/app/qt_avplay/README | 18 ++ qt4/src/app/qt_avplay/avplay_policy.h | 115 +++++++++++++ qt4/src/app/qt_avplay/control_bar.cpp | 73 ++++++++ qt4/src/app/qt_avplay/control_bar.h | 58 +++++++ .../app/qt_avplay/filter_framebuffer_policy.h | 77 +++++++++ qt4/src/app/qt_avplay/framebuffer_root.h | 64 +++++++ .../framebuffer_session_component.cc | 86 ++++++++++ .../qt_avplay/framebuffer_session_component.h | 57 +++++++ qt4/src/app/qt_avplay/input_service.cpp | 40 +++++ qt4/src/app/qt_avplay/input_service.h | 24 +++ qt4/src/app/qt_avplay/main.cpp | 45 +++++ qt4/src/app/qt_avplay/main_window.cpp | 129 ++++++++++++++ qt4/src/app/qt_avplay/main_window.h | 43 +++++ qt4/src/app/qt_avplay/qt_avplay.pro | 12 ++ qt4/src/app/qt_avplay/style.qrc | 10 ++ qt4/src/app/qt_avplay/style.qss | 32 ++++ qt4/src/app/qt_avplay/target.mk | 9 + 21 files changed, 1055 insertions(+), 2 deletions(-) rename os/{src/drivers/input/ps2 => include/input}/event_queue.h (98%) create mode 100644 qt4/run/qt_avplay.run create mode 100644 qt4/src/app/qt_avplay/README create mode 100644 qt4/src/app/qt_avplay/avplay_policy.h create mode 100644 qt4/src/app/qt_avplay/control_bar.cpp create mode 100644 qt4/src/app/qt_avplay/control_bar.h create mode 100644 qt4/src/app/qt_avplay/filter_framebuffer_policy.h create mode 100644 qt4/src/app/qt_avplay/framebuffer_root.h create mode 100644 qt4/src/app/qt_avplay/framebuffer_session_component.cc create mode 100644 qt4/src/app/qt_avplay/framebuffer_session_component.h create mode 100644 qt4/src/app/qt_avplay/input_service.cpp create mode 100644 qt4/src/app/qt_avplay/input_service.h create mode 100644 qt4/src/app/qt_avplay/main.cpp create mode 100644 qt4/src/app/qt_avplay/main_window.cpp create mode 100644 qt4/src/app/qt_avplay/main_window.h create mode 100644 qt4/src/app/qt_avplay/qt_avplay.pro create mode 100644 qt4/src/app/qt_avplay/style.qrc create mode 100644 qt4/src/app/qt_avplay/style.qss create mode 100644 qt4/src/app/qt_avplay/target.mk diff --git a/os/src/drivers/input/ps2/event_queue.h b/os/include/input/event_queue.h similarity index 98% rename from os/src/drivers/input/ps2/event_queue.h rename to os/include/input/event_queue.h index a35dcd323..499b6f5d1 100644 --- a/os/src/drivers/input/ps2/event_queue.h +++ b/os/include/input/event_queue.h @@ -14,6 +14,7 @@ #ifndef _EVENT_QUEUE_H_ #define _EVENT_QUEUE_H_ +#include #include #include diff --git a/os/src/drivers/input/ps2/ps2_keyboard.h b/os/src/drivers/input/ps2/ps2_keyboard.h index 52ff0b885..435653f61 100644 --- a/os/src/drivers/input/ps2/ps2_keyboard.h +++ b/os/src/drivers/input/ps2/ps2_keyboard.h @@ -15,13 +15,13 @@ #define _PS2_KEYBOARD_H_ #include +#include #include #include "input_driver.h" #include "serial_interface.h" #include "scan_code_set_1.h" #include "scan_code_set_2.h" -#include "event_queue.h" class Ps2_keyboard : public Input_driver { diff --git a/os/src/drivers/input/ps2/ps2_mouse.h b/os/src/drivers/input/ps2/ps2_mouse.h index 8b92a2060..d9a4e7074 100644 --- a/os/src/drivers/input/ps2/ps2_mouse.h +++ b/os/src/drivers/input/ps2/ps2_mouse.h @@ -15,9 +15,9 @@ #define _PS2_MOUSE_H_ #include +#include #include -#include "event_queue.h" #include "input_driver.h" class Ps2_mouse : public Input_driver diff --git a/qt4/run/qt_avplay.run b/qt4/run/qt_avplay.run new file mode 100644 index 000000000..1764a9697 --- /dev/null +++ b/qt4/run/qt_avplay.run @@ -0,0 +1,160 @@ +# +# Build +# + +build { + core + init + drivers/input/ps2 + drivers/pci + drivers/framebuffer + drivers/timer + drivers/audio_out + server/nitpicker + app/avplay + app/qt_avplay +} + +# +# Download media file +# + +set media_url "ftp://ftp.untergrund.net/users/ae/dhstv/escape-chotro.mp4" +if {![file exists bin/mediafile]} { + puts "downloading media file from $media_url" + catch { exec wget -O bin/mediafile $media_url } +} + +create_boot_directory + +# +# Generate config +# + +set config { + + + + + + + + + + + + + + + + + } + +append_if [have_spec sdl] config { + + + + + + + } + +append_if [have_spec pci] config { + + + + } + +append_if [have_spec vesa] config { + + + + } + +append_if [have_spec pl11x] config { + + + + } + +append_if [have_spec ps2] config { + + + + } + +append config { + + + + + + + + + + + + + + + + + + + +} + +install_config $config + +# +# Boot modules +# + +# generic modules +set boot_modules { + core + init + timer + audio_out_drv + nitpicker + qt_avplay + dejavusans.lib.so + freetype.lib.so + ld.lib.so + libc.lib.so + libc_lock_pipe.lib.so + libm.lib.so + libpng.lib.so + jpeg.lib.so + qnitpickerviewwidget.lib.so + qt_core.lib.so + qt_gui.lib.so + qt_xml.lib.so + zlib.lib.so + avcodec.lib.so + avformat.lib.so + avutil.lib.so + avfilter.lib.so + swscale.lib.so + sdl.lib.so + pthread.lib.so + libc_log.lib.so + libc_rom.lib.so + avplay + mediafile +} + +# platform-specific modules +lappend_if [have_spec linux] boot_modules fb_sdl +lappend_if [have_spec pci] boot_modules pci_drv +lappend_if [have_spec vesa] boot_modules vesa_drv +lappend_if [have_spec ps2] boot_modules ps2_drv +lappend_if [have_spec pl11x] boot_modules pl11x_drv + +build_boot_image $boot_modules + +append qemu_args " -m 512 -soundhw all" + +run_genode_until forever + diff --git a/qt4/src/app/qt_avplay/README b/qt4/src/app/qt_avplay/README new file mode 100644 index 000000000..5e9a2ef51 --- /dev/null +++ b/qt4/src/app/qt_avplay/README @@ -0,0 +1,18 @@ +This directory contains a simple Qt-based media player which is actually a +graphical user interface for the SDL-based 'avplay' media player from 'libav'. +It starts 'avplay' as a child and shows its graphical output in a +'QNitpickerViewWidget'. The widgets for controlling the player state send the +according keyboard and mouse input events to 'avplay'. + +The 'qt_avplay' player supports the following configuration options: + +:':' + name of the media file to play + +:'': + + This node contains the name of a framebuffer filter service to filter the + video output. It may appear multiple times. If specified more than once, it + is possible to build a post-processing pipeline for the video display where + each processing stage is executed by a separate program. + diff --git a/qt4/src/app/qt_avplay/avplay_policy.h b/qt4/src/app/qt_avplay/avplay_policy.h new file mode 100644 index 000000000..e010ab528 --- /dev/null +++ b/qt4/src/app/qt_avplay/avplay_policy.h @@ -0,0 +1,115 @@ +/* + * \brief Avplay policy + * \author Christian Prochaska + * \date 2012-04-05 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _AVPLAY_POLICY_H_ +#define _AVPLAY_POLICY_H_ + +/* Qt4 includes */ +#include +#include +#include +#include +#include + +/* Genode includes */ +#include + + +class Avplay_policy : public QObject, public Genode::Slave_policy +{ + Q_OBJECT + + private: + + Genode::Service_registry &_input_in; + Genode::Service_registry &_framebuffer_in; + + const char *_mediafile; + int _sdl_audio_volume; + QByteArray _config_byte_array; + + + const char *_config() + { + QDomDocument config_doc; + + QDomElement config_node = config_doc.createElement("config"); + config_doc.appendChild(config_node); + + QDomElement arg0_node = config_doc.createElement("arg"); + arg0_node.setAttribute("value", "avplay"); + config_node.appendChild(arg0_node); + + QDomElement arg1_node = config_doc.createElement("arg"); + arg1_node.setAttribute("value", _mediafile); + config_node.appendChild(arg1_node); + + QDomElement sdl_audio_volume_node = config_doc.createElement("sdl_audio_volume"); + sdl_audio_volume_node.setAttribute("value", QString::number(_sdl_audio_volume)); + config_node.appendChild(sdl_audio_volume_node); + + _config_byte_array = config_doc.toByteArray(4); + + return _config_byte_array.constData(); + } + + protected: + + const char **_permitted_services() const + { + static const char *permitted_services[] = { + "CAP", "LOG", "RM", "ROM", "SIGNAL", + "Timer", "Audio_out", 0 }; + + return permitted_services; + }; + + public: + + Avplay_policy(Genode::Rpc_entrypoint &entrypoint, + Genode::Service_registry &input_in, + Genode::Service_registry &framebuffer_in, + const char *mediafile) + : Genode::Slave_policy("avplay", entrypoint, Genode::env()->ram_session()), + _input_in(input_in), + _framebuffer_in(framebuffer_in), + _mediafile(mediafile), + _sdl_audio_volume(100) + { + configure(_config()); + } + + Genode::Service *resolve_session_request(const char *service_name, + const char *args) + { + if (strcmp(service_name, "Input") == 0) + return _input_in.find(service_name); + + if (strcmp(service_name, "Framebuffer") == 0) { + Genode::Client client; + return _framebuffer_in.wait_for_service(service_name, &client, name()); + } + + return Slave_policy::resolve_session_request(service_name, args); + } + + public Q_SLOTS: + + void volume_changed(int value) + { + _sdl_audio_volume = value; + configure(_config()); + } +}; + +#endif /* _AVPLAY_POLICY_H_ */ diff --git a/qt4/src/app/qt_avplay/control_bar.cpp b/qt4/src/app/qt_avplay/control_bar.cpp new file mode 100644 index 000000000..d830364ad --- /dev/null +++ b/qt4/src/app/qt_avplay/control_bar.cpp @@ -0,0 +1,73 @@ +/* + * \brief Control bar + * \author Christian Prochaska + * \date 2012-03-30 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include + +/* Qoost includes */ +#include + +#include "input_service.h" +#include "main_window.h" + + +void Control_bar::_rewind() +{ + /* mouse click at horizontal position 0 */ + ev_queue.add(Input::Event(Input::Event::PRESS, Input::BTN_LEFT, 0, 0, 0, 0)); + ev_queue.add(Input::Event(Input::Event::RELEASE, Input::BTN_LEFT, 0, 0, 0, 0)); +} + + +void Control_bar::_pause_resume() +{ + ev_queue.add(Input::Event(Input::Event::PRESS, Input::KEY_SPACE, 0, 0, 0, 0)); + ev_queue.add(Input::Event(Input::Event::RELEASE, Input::KEY_SPACE, 0, 0, 0, 0)); + + _playing = !_playing; + if (_playing) + update_style_id(_play_pause_button, "play"); + else + update_style_id(_play_pause_button, "pause"); +} + + +void Control_bar::_stop() +{ + if (_playing) + _pause_resume(); + + _rewind(); +} + + +Control_bar::Control_bar() +: _playing(true) +{ + update_style_id(_play_pause_button, "play"); + + _volume_slider->setOrientation(Qt::Horizontal); + _volume_slider->setRange(0, 100); + _volume_slider->setTickInterval(10); + _volume_slider->setValue(100); + + _layout->addWidget(_play_pause_button); + _layout->addWidget(_stop_button); + _layout->addStretch(); + _layout->addWidget(_volume_label); + _layout->addWidget(_volume_slider); + + connect(_play_pause_button, SIGNAL(clicked()), this, SLOT(_pause_resume())); + connect(_stop_button, SIGNAL(clicked()), this, SLOT(_stop())); + connect(_volume_slider, SIGNAL(valueChanged(int)), this, SIGNAL(volume_changed(int))); +} diff --git a/qt4/src/app/qt_avplay/control_bar.h b/qt4/src/app/qt_avplay/control_bar.h new file mode 100644 index 000000000..05b1db5a7 --- /dev/null +++ b/qt4/src/app/qt_avplay/control_bar.h @@ -0,0 +1,58 @@ +/* + * \brief Control bar + * \author Christian Prochaska + * \date 2012-03-30 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _CONTROL_BAR_H_ +#define _CONTROL_BAR_H_ + +/* Qt includes */ +#include + +/* Qoost includes */ +#include +#include + +struct Play_pause_button : QPushButton { Q_OBJECT }; +struct Stop_button : QPushButton { Q_OBJECT }; +struct Volume_label : QLabel { Q_OBJECT }; +struct Volume_slider : QSlider { Q_OBJECT }; + +class Control_bar : public Compound_widget +{ + Q_OBJECT + + private: + + QMember _play_pause_button; + QMember _stop_button; + QMember _volume_label; + QMember _volume_slider; + + bool _playing; + + void _rewind(); + + private Q_SLOTS: + + void _pause_resume(); + void _stop(); + + public: + + Control_bar(); + + Q_SIGNALS: + + void volume_changed(int value); +}; + +#endif /* _CONTROL_BAR_H_ */ diff --git a/qt4/src/app/qt_avplay/filter_framebuffer_policy.h b/qt4/src/app/qt_avplay/filter_framebuffer_policy.h new file mode 100644 index 000000000..e417d2505 --- /dev/null +++ b/qt4/src/app/qt_avplay/filter_framebuffer_policy.h @@ -0,0 +1,77 @@ +/* + * \brief Filter framebuffer policy + * \author Christian Prochaska + * \date 2012-04-11 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _FILTER_FRAMEBUFFER_POLICY_H_ +#define _FILTER_FRAMEBUFFER_POLICY_H_ + +/* Genode includes */ +#include +#include + + +class Filter_framebuffer_policy : public Genode::Slave_policy +{ + private: + + Genode::Service_registry &_framebuffer_in; + Genode::Service_registry &_framebuffer_out; + + protected: + + const char **_permitted_services() const + { + static const char *permitted_services[] = { + "CAP", "LOG", "RM", "ROM", "SIGNAL", + "Timer", 0 }; + + return permitted_services; + }; + + public: + + Filter_framebuffer_policy(const char *name, + Genode::Rpc_entrypoint &entrypoint, + Genode::Service_registry &framebuffer_in, + Genode::Service_registry &framebuffer_out) + : Genode::Slave_policy(name, entrypoint, Genode::env()->ram_session()), + _framebuffer_in(framebuffer_in), + _framebuffer_out(framebuffer_out) { } + + Genode::Service *resolve_session_request(const char *service_name, + const char *args) + { + if (strcmp(service_name, "Framebuffer") == 0) { + Genode::Client client; + return _framebuffer_in.wait_for_service(service_name, &client, name()); + } + + return Slave_policy::resolve_session_request(service_name, args); + } + + bool announce_service(const char *name, + Genode::Root_capability root, + Genode::Allocator *alloc, + Genode::Server *server) + { + if (strcmp(name, "Framebuffer") == 0) { + _framebuffer_out.insert(new (alloc) Genode::Child_service(name, root, server)); + return true; + } + + return Slave_policy::announce_service(name, root, alloc, server); + } + + +}; + +#endif /* _FILTER_FRAMEBUFFER_POLICY_H_ */ diff --git a/qt4/src/app/qt_avplay/framebuffer_root.h b/qt4/src/app/qt_avplay/framebuffer_root.h new file mode 100644 index 000000000..b4d933099 --- /dev/null +++ b/qt4/src/app/qt_avplay/framebuffer_root.h @@ -0,0 +1,64 @@ +/* + * \brief Framebuffer root + * \author Christian Prochaska + * \date 2012-04-02 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + + +#ifndef _FRAMEBUFFER_ROOT_H_ +#define _FRAMEBUFFER_ROOT_H_ + +/* Genode includes */ +#include + +#include "framebuffer_session_component.h" + +namespace Framebuffer { + + /** + * Shortcut for single-client root component + */ + typedef Genode::Root_component Root_component; + + + class Root : public Root_component + { + private: + + QNitpickerViewWidget &_nitpicker_view_widget; + int _max_width; + int _max_height; + + protected: + + Session_component *_create_session(const char *args) + { + return new (md_alloc()) + Session_component(args, _nitpicker_view_widget, + _max_width, _max_height); + } + + public: + + Root(Genode::Rpc_entrypoint *session_ep, + Genode::Allocator *md_alloc, + QNitpickerViewWidget &nitpicker_view_widget, + int max_width = 0, + int max_height = 0) + : Root_component(session_ep, md_alloc), + _nitpicker_view_widget(nitpicker_view_widget), + _max_width(max_width), + _max_height(max_height) { } + + }; + +} + +#endif /* _FRAMEBUFFER_ROOT_H_ */ diff --git a/qt4/src/app/qt_avplay/framebuffer_session_component.cc b/qt4/src/app/qt_avplay/framebuffer_session_component.cc new file mode 100644 index 000000000..f2ae5f45b --- /dev/null +++ b/qt4/src/app/qt_avplay/framebuffer_session_component.cc @@ -0,0 +1,86 @@ +/* + * \brief Framebuffer session component + * \author Christian Prochaska + * \date 2012-04-02 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include +#include + +#include "framebuffer_session_component.h" + +namespace Framebuffer { + + + int Session_component::_limited_size(int requested_size, int max_size) + { + if (requested_size == 0) + return max_size; + else + return (max_size > 0) ? Genode::min(requested_size, max_size) : requested_size; + } + + + static inline long session_arg(const char *arg, const char *key) + { + return Genode::Arg_string::find_arg(arg, key).long_value(0); + } + + + Session_component::Session_component(const char *args, + QNitpickerViewWidget &nitpicker_view_widget, + int max_width, + int max_height) + : _nitpicker(Nitpicker::Connection( + _limited_size(session_arg(args, "fb_width"), max_width), + _limited_size(session_arg(args, "fb_height"), max_height))), + _framebuffer(_nitpicker.framebuffer_session()) + { + Nitpicker::View_capability nitpicker_view_cap = _nitpicker.create_view(); + Mode _mode = _framebuffer.mode(); + nitpicker_view_widget.setNitpickerView(nitpicker_view_cap, + 0, 0, + _mode.width(), + _mode.height()); + } + + + Genode::Dataspace_capability Session_component::dataspace() + { + return _framebuffer.dataspace(); + } + + + void Session_component::release() + { + _framebuffer.release(); + } + + + Mode Session_component::mode() const + { + return _framebuffer.mode(); + } + + + void Session_component::mode_sigh(Genode::Signal_context_capability sigh_cap) + { + _framebuffer.mode_sigh(sigh_cap); + } + + + void Session_component::refresh(int x, int y, int w, int h) + { + _framebuffer.refresh(x, y, w, h); + } +} diff --git a/qt4/src/app/qt_avplay/framebuffer_session_component.h b/qt4/src/app/qt_avplay/framebuffer_session_component.h new file mode 100644 index 000000000..ed917b97c --- /dev/null +++ b/qt4/src/app/qt_avplay/framebuffer_session_component.h @@ -0,0 +1,57 @@ +/* + * \brief Framebuffer session component + * \author Christian Prochaska + * \date 2012-04-02 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + + +#ifndef _FRAMEBUFFER_SESSION_COMPONENT_H_ +#define _FRAMEBUFFER_SESSION_COMPONENT_H_ + +/* Genode includes */ +#include +#include +#include + +/* Qt4 includes */ +#include + + +namespace Framebuffer { + + class Session_component : public Genode::Rpc_object + { + private: + + Nitpicker::Connection _nitpicker; + Session_client _framebuffer; + + int _limited_size(int requested_size, int max_size); + + public: + + /** + * Constructor + */ + Session_component(const char *args, + QNitpickerViewWidget &nitpicker_view_widget, + int max_width = 0, + int max_height = 0); + + Genode::Dataspace_capability dataspace(); + void release(); + Mode mode() const; + void mode_sigh(Genode::Signal_context_capability sigh_cap); + void refresh(int x, int y, int w, int h); + }; + +} + +#endif /* _FRAMEBUFFER_SESSION_COMPONENT_H_ */ diff --git a/qt4/src/app/qt_avplay/input_service.cpp b/qt4/src/app/qt_avplay/input_service.cpp new file mode 100644 index 000000000..99d9a098f --- /dev/null +++ b/qt4/src/app/qt_avplay/input_service.cpp @@ -0,0 +1,40 @@ +/* + * \brief Input service + * \author Christian Prochaska + * \date 2012-03-29 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include + +#include "input_service.h" + +using namespace Genode; + +Event_queue ev_queue; + + +namespace Input { + + /* + * Event handling is disabled on queue creation and will be enabled later if a + * session is created. + */ + void event_handling(bool enable) + { + if (enable) + ev_queue.enable(); + else + ev_queue.disable(); + } + + bool event_pending() { return !ev_queue.empty(); } + Event get_event() { return ev_queue.get(); } +} diff --git a/qt4/src/app/qt_avplay/input_service.h b/qt4/src/app/qt_avplay/input_service.h new file mode 100644 index 000000000..0fb0f06a1 --- /dev/null +++ b/qt4/src/app/qt_avplay/input_service.h @@ -0,0 +1,24 @@ +/* + * \brief Input service + * \author Christian Prochaska + * \date 2012-03-29 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INPUT_SERVICE_H_ +#define _INPUT_SERVICE_H_ + +/* Genode includes */ +#include + +extern Event_queue ev_queue; + +extern void create_input_service(); + +#endif /* _INPUT_SERVICE_H_ */ diff --git a/qt4/src/app/qt_avplay/main.cpp b/qt4/src/app/qt_avplay/main.cpp new file mode 100644 index 000000000..5e4b5094f --- /dev/null +++ b/qt4/src/app/qt_avplay/main.cpp @@ -0,0 +1,45 @@ +/* + * \brief Simple Qt interface for 'avplay' media player + * \author Christian Prochaska + * \date 2012-03-21 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Qt includes */ +#include + +/* qt_avplay includes */ +#include "main_window.h" + + +static inline void load_stylesheet() +{ + QFile file(":style.qss"); + if (!file.open(QFile::ReadOnly)) { + qWarning() << "Warning:" << file.errorString() + << "opening file" << file.fileName(); + return; + } + + qApp->setStyleSheet(QLatin1String(file.readAll())); +} + + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + load_stylesheet(); + + QMember main_window; + + main_window->show(); + + return app.exec(); +} diff --git a/qt4/src/app/qt_avplay/main_window.cpp b/qt4/src/app/qt_avplay/main_window.cpp new file mode 100644 index 000000000..49670d5b3 --- /dev/null +++ b/qt4/src/app/qt_avplay/main_window.cpp @@ -0,0 +1,129 @@ +/* + * \brief Main window of the media player + * \author Christian Prochaska + * \date 2012-03-29 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include +#include + +/* qt_avplay includes */ +#include "avplay_policy.h" +#include "filter_framebuffer_policy.h" +#include "framebuffer_root.h" +#include "input_service.h" +#include "main_window.h" + + +using namespace Genode; + + +struct Framebuffer_filter +{ + enum { MAX_FILTER_NAME_SIZE = 32 }; + char name[MAX_FILTER_NAME_SIZE]; + Genode::Number_of_bytes ram_quota; + + Service_registry *framebuffer_out_registry; + Rpc_entrypoint *ep; + Filter_framebuffer_policy *policy; + Slave *slave; +}; + + +Main_window::Main_window() +{ + /* look for dynamic linker */ + + try { + static Rom_connection ldso_rom("ld.lib.so"); + Process::dynamic_linker(ldso_rom.dataspace()); + } catch (...) { + PERR("ld.lib.so not found"); + } + + /* get the name of the media file from the config file */ + enum { MAX_LEN_MEDIAFILE_NAME = 256 }; + static char mediafile[MAX_LEN_MEDIAFILE_NAME] = "mediafile"; + try { + config()->xml_node().sub_node("mediafile").attribute("name").value(mediafile, sizeof(mediafile)); + } catch(...) { + PWRN("no config node found, using \"mediafile\""); + } + + /* create local services */ + + enum { STACK_SIZE = 2*sizeof(addr_t)*1024 }; + static Cap_connection cap; + static Rpc_entrypoint avplay_ep(&cap, STACK_SIZE, "avplay_ep"); + static Service_registry input_registry; + static Service_registry nitpicker_framebuffer_registry; + + static Input::Root input_root(&avplay_ep, env()->heap()); + static Local_service input_service(Input::Session::service_name(), &input_root); + input_registry.insert(&input_service); + avplay_ep.manage(&input_root); + + /* find out which filtering framebuffer services to start and sort them in reverse order */ + + static QList framebuffer_filters; + try { + Xml_node node = config()->xml_node().sub_node("framebuffer_filter"); + for (; ; node = node.next("framebuffer_filter")) { + Framebuffer_filter *framebuffer_filter = new Framebuffer_filter; + node.attribute("name").value(framebuffer_filter->name, sizeof(framebuffer_filter->name)); + node.attribute("ram_quota").value(&framebuffer_filter->ram_quota); + qDebug() << "filter:" << framebuffer_filter->name << "," << framebuffer_filter->ram_quota; + framebuffer_filters.prepend(framebuffer_filter); + } + } catch (Config::Invalid) { + } catch (Xml_node::Nonexistent_sub_node) { + } + + /* start the filtering framebuffer services */ + + Service_registry *framebuffer_in_registry = &nitpicker_framebuffer_registry; + + Q_FOREACH(Framebuffer_filter *framebuffer_filter, framebuffer_filters) { + framebuffer_filter->framebuffer_out_registry = new Service_registry; + framebuffer_filter->ep = new Rpc_entrypoint(&cap, STACK_SIZE, "filter_fb_ep"); + framebuffer_filter->policy = new Filter_framebuffer_policy(framebuffer_filter->name, + *framebuffer_filter->ep, + *framebuffer_in_registry, + *framebuffer_filter->framebuffer_out_registry); + framebuffer_filter->slave = new Slave(*framebuffer_filter->ep, + *framebuffer_filter->policy, + framebuffer_filter->ram_quota); + framebuffer_in_registry = framebuffer_filter->framebuffer_out_registry; + } + + Rpc_entrypoint *local_framebuffer_ep = framebuffer_filters.isEmpty() ? + &avplay_ep : + framebuffer_filters.at(0)->ep; + + static Framebuffer::Root framebuffer_root(local_framebuffer_ep, env()->heap(), *_avplay_widget, 640, 480); + static Local_service framebuffer_service(Framebuffer::Session::service_name(), &framebuffer_root); + nitpicker_framebuffer_registry.insert(&framebuffer_service); + + /* start avplay */ + + static Avplay_policy avplay_policy(avplay_ep, input_registry, *framebuffer_in_registry, mediafile); + static Genode::Slave avplay_slave(avplay_ep, avplay_policy, 32*1024*1024); + + /* add widgets to layout */ + + _layout->addWidget(_avplay_widget); + _layout->addWidget(_control_bar); + + connect(_control_bar, SIGNAL(volume_changed(int)), &avplay_policy, SLOT(volume_changed(int))); +} diff --git a/qt4/src/app/qt_avplay/main_window.h b/qt4/src/app/qt_avplay/main_window.h new file mode 100644 index 000000000..7931c7a06 --- /dev/null +++ b/qt4/src/app/qt_avplay/main_window.h @@ -0,0 +1,43 @@ +/* + * \brief Main window of the media player + * \author Christian Prochaska + * \date 2012-03-29 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _MAIN_WINDOW_H_ +#define _MAIN_WINDOW_H_ + +/* Qt includes */ +#include +#include +#include + +/* Qoost includes */ +#include +#include + +#include "control_bar.h" + + +class Main_window : public Compound_widget +{ + Q_OBJECT + + private: + + QMember _avplay_widget; + QMember _control_bar; + + public: + + Main_window(); +}; + +#endif /* _MAIN_WINDOW_H_ */ diff --git a/qt4/src/app/qt_avplay/qt_avplay.pro b/qt4/src/app/qt_avplay/qt_avplay.pro new file mode 100644 index 000000000..8b9dc41c5 --- /dev/null +++ b/qt4/src/app/qt_avplay/qt_avplay.pro @@ -0,0 +1,12 @@ +TEMPLATE = app +TARGET = qt_avplay +QT = core gui xml +HEADERS = avplay_policy.h \ + control_bar.h \ + main_window.h +SOURCES = control_bar.cpp \ + framebuffer_session_component.cc \ + input_service.cpp \ + main.cpp \ + main_window.cpp +RESOURCES = style.qrc diff --git a/qt4/src/app/qt_avplay/style.qrc b/qt4/src/app/qt_avplay/style.qrc new file mode 100644 index 000000000..0adacff03 --- /dev/null +++ b/qt4/src/app/qt_avplay/style.qrc @@ -0,0 +1,10 @@ + + + +style.qss +../../../contrib/qt-everywhere-opensource-src-4.7.4/examples/network/torrent/icons/player_play.png +../../../contrib/qt-everywhere-opensource-src-4.7.4/examples/network/torrent/icons/player_pause.png +../../../contrib/qt-everywhere-opensource-src-4.7.4/examples/network/torrent/icons/player_stop.png +../../../contrib/qt-everywhere-opensource-src-4.7.4/demos/mobile/guitartuner/src/mycomponents/images/volume.png + + diff --git a/qt4/src/app/qt_avplay/style.qss b/qt4/src/app/qt_avplay/style.qss new file mode 100644 index 000000000..08e0a4d73 --- /dev/null +++ b/qt4/src/app/qt_avplay/style.qss @@ -0,0 +1,32 @@ +Main_window { + max-width: 640px; + max-height: 512px; +} + +Play_pause_button, Stop_button { + width: 32px; + height: 32px; +} + +Play_pause_button#play { + border-image: url(:player_pause.png); +} + + +Play_pause_button#pause { + border-image: url(:player_play.png); +} + + +Stop_button { + border-image: url(:player_stop.png); +} + +Volume_label { + background-image: url(:volume.png); + min-width: 16px; + max-width: 32px; + min-height: 16px; + max-height: 32px; + margin-right: 5px; +} diff --git a/qt4/src/app/qt_avplay/target.mk b/qt4/src/app/qt_avplay/target.mk new file mode 100644 index 000000000..d60ce481b --- /dev/null +++ b/qt4/src/app/qt_avplay/target.mk @@ -0,0 +1,9 @@ +# identify the qt4 repository by searching for a file that is unique for qt4 +QT4_REP_DIR := $(call select_from_repositories,lib/import/import-qt4.inc) +QT4_REP_DIR := $(realpath $(dir $(QT4_REP_DIR))../..) + +include $(QT4_REP_DIR)/src/app/tmpl/target_defaults.inc + +include $(QT4_REP_DIR)/src/app/tmpl/target_final.inc + +LIBS += qnitpickerviewwidget