diff --git a/src/controller.h b/src/controller.h index 40c93a6..07deb8c 100644 --- a/src/controller.h +++ b/src/controller.h @@ -53,6 +53,8 @@ public: set_video_stream, // int cycle_audio_stream, // no parameters set_audio_stream, // int + cycle_subtitles_stream, // no parameters + set_subtitles_stream, // int set_stereo_layout, // video_frame::stereo_layout, bool set_stereo_mode, // parameters::stereo_mode, bool toggle_stereo_mode_swap, // no parameters @@ -72,7 +74,13 @@ public: set_parallax, // float (absolute value) set_crosstalk, // 3 floats (absolute values) adjust_ghostbust, // float (relative adjustment) - set_ghostbust // float (absolute value) + set_ghostbust, // float (absolute value) + set_subtitles_font, // filename, string + set_subtitles_font_size, // int + set_subtitles_encoding, // string + set_subtitles_color, // RGB color, int + adjust_subtitles_parallax, // float + set_subtitles_parallax, // float }; type type; @@ -116,6 +124,7 @@ public: pause, // bool video_stream, // int audio_stream, // int + subtitles_stream, // int stereo_layout, // video_frame::stereo_layout, bool stereo_mode, // parameters::stereo_mode, bool stereo_mode_swap, // bool @@ -128,7 +137,12 @@ public: pos, // float parallax, // float crosstalk, // 3 floats - ghostbust // float + ghostbust, // float + subtitles_font, // string + subtitles_font_size, // int + subtitles_encoding, // string + subtitles_color, // int + subtitles_parallax, // int }; type type; diff --git a/src/media_data.cpp b/src/media_data.cpp index aa57197..02af234 100644 --- a/src/media_data.cpp +++ b/src/media_data.cpp @@ -494,7 +494,12 @@ parameters::parameters() : contrast(std::numeric_limits::quiet_NaN()), brightness(std::numeric_limits::quiet_NaN()), hue(std::numeric_limits::quiet_NaN()), - saturation(std::numeric_limits::quiet_NaN()) + saturation(std::numeric_limits::quiet_NaN()), + subtitles_color(-1), + subtitles_encoding(""), + subtitles_font(""), + subtitles_font_size(0), + subtitles_parallax(std::numeric_limits::quiet_NaN()) { } @@ -536,6 +541,26 @@ void parameters::set_defaults() { saturation = 0.0f; } + if (subtitles_color < 0 || subtitles_color > 0x00FFFFFF) + { + subtitles_color = 0x00FFFFFF; + } + if (subtitles_encoding.empty()) + { + subtitles_encoding = "UTF-8"; + } + if (subtitles_font.empty()) + { + subtitles_font = ""; + } + if (subtitles_font_size <= 0) + { + subtitles_font_size = 12; + } + if (!std::isfinite(subtitles_parallax) || subtitles_parallax < -1.0f || subtitles_parallax > +1.0f) + { + subtitles_parallax = 0.0f; + } } std::string parameters::stereo_mode_to_string(stereo_mode_t stereo_mode, bool stereo_mode_swap) @@ -760,6 +785,11 @@ void parameters::save(std::ostream &os) const s11n::save(os, brightness); s11n::save(os, hue); s11n::save(os, saturation); + s11n::save(os, subtitles_color); + s11n::save(os, subtitles_font); + s11n::save(os, subtitles_font_size); + s11n::save(os, subtitles_encoding); + s11n::save(os, subtitles_parallax); } void parameters::load(std::istream &is) @@ -777,4 +807,9 @@ void parameters::load(std::istream &is) s11n::load(is, brightness); s11n::load(is, hue); s11n::load(is, saturation); + s11n::load(is, subtitles_color); + s11n::load(is, subtitles_font); + s11n::load(is, subtitles_font_size); + s11n::load(is, subtitles_encoding); + s11n::load(is, subtitles_parallax); } diff --git a/src/media_data.h b/src/media_data.h index 8fa87f7..847579b 100644 --- a/src/media_data.h +++ b/src/media_data.h @@ -251,6 +251,12 @@ public: float brightness; // Brightness adjustment, -1 .. +1 float hue; // Hue adjustment, -1 .. +1 float saturation; // Saturation adjustment, -1 .. +1 + + int subtitles_color; // RGB color of subtitles + std::string subtitles_font; // Name of font for rendering + int subtitles_font_size; // Size of font for rendering + std::string subtitles_encoding; // Encoding of subtitle string + float subtitles_parallax; // Subtitles parallax adjustment, -1 .. +1 // Constructor parameters(); diff --git a/src/player.cpp b/src/player.cpp index 0866da7..e1505cd 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -803,6 +803,38 @@ void player::receive_cmd(const command &cmd) } } break; + case command::cycle_subtitles_stream: + if (_media_input->subtitle_streams() > 0) + { + int oldstream = _media_input->selected_subtitle_stream(); + int newstream = oldstream + 1; + if (newstream >= _media_input->subtitle_streams()) + { + newstream = 0; + } + _media_input->select_subtitle_stream(newstream); + notify(notification::subtitles_stream, oldstream, newstream); + _seek_request = -1; // Get position right + } + break; + case command::set_subtitles_stream: + if (_media_input->subtitle_streams() > 0) + { + int oldstream = _media_input->selected_subtitle_stream(); + int newstream; + s11n::load(p, newstream); + if (newstream < 0 || newstream >= _media_input->subtitle_streams()) + { + newstream = 0; + } + if (newstream != oldstream) + { + _media_input->select_subtitle_stream(newstream); + notify(notification::subtitles_stream, oldstream, newstream); + _seek_request = -1; // Get position right + } + } + break; case command::set_stereo_layout: { int stereo_layout; @@ -960,6 +992,57 @@ void player::receive_cmd(const command &cmd) parameters_changed = true; notify(notification::ghostbust, oldval, _params.ghostbust); break; + case command::set_subtitles_font: + { + std::string old_file; + old_file = _params.subtitles_font; + _params.subtitles_font = cmd.param; + parameters_changed = true; + notify(notification::subtitles_font, old_file, _params.subtitles_font); + break; + } + case command::set_subtitles_font_size: + { + int val, old_val; + s11n::load(p, val); + old_val = _params.subtitles_font_size; + _params.subtitles_font_size = val; + parameters_changed = true; + notify(notification::subtitles_font_size, old_val, _params.subtitles_font_size); + break; + } + case command::set_subtitles_encoding: + { + std::string old_val = _params.subtitles_encoding; + _params.subtitles_encoding = cmd.param; + parameters_changed = true; + notify(notification::subtitles_encoding, old_val, _params.subtitles_encoding); + break; + } + case command::set_subtitles_color: + { + int val, old_val; + s11n::load(p, val); + old_val = _params.subtitles_color; + _params.subtitles_color = val & 0x00FFFFFF; + parameters_changed = true; + notify(notification::subtitles_color, old_val, _params.subtitles_color); + break; + } + case command::adjust_subtitles_parallax: + s11n::load(p, param); + oldval = _params.subtitles_parallax; + _params.subtitles_parallax = std::max(std::min(_params.subtitles_parallax + param, 1.0f), -1.0f); + parameters_changed = true; + notify(notification::parallax, oldval, _params.subtitles_parallax); + break; + case command::set_subtitles_parallax: + s11n::load(p, param); + oldval = _params.subtitles_parallax; + _params.subtitles_parallax = std::max(std::min(param, 1.0f), -1.0f); + parameters_changed = true; + notify(notification::subtitles_parallax, oldval, _params.subtitles_parallax); + break; } if (parameters_changed && _video_output) diff --git a/src/player_qt.cpp b/src/player_qt.cpp index 6fbc7ea..13d257e 100644 --- a/src/player_qt.cpp +++ b/src/player_qt.cpp @@ -47,6 +47,10 @@ #include #include #include +#include +#include +#include +#include #include "player_qt.h" #include "qt_app.h" @@ -163,6 +167,17 @@ in_out_widget::in_out_widget(QSettings *settings, const player_qt_internal *play connect(_input_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(input_changed())); layout1->addWidget(_input_combobox, 0, 1); layout1->setColumnStretch(1, 1); + + QLabel *subtitles_label = new QLabel("Subtitles:"); + subtitles_label->setToolTip( + "

Select the subtitles stream.

"); + layout1->addWidget(subtitles_label, 0, 2); + _subtitles_combobox = new QComboBox(this); + _subtitles_combobox->setToolTip(subtitles_label->toolTip()); + connect(_subtitles_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(subtitles_changed())); + layout1->addWidget(_subtitles_combobox, 0, 3); + layout1->setColumnStretch(1, 1); + layout1->setColumnStretch(3, 1); QGridLayout *layout2 = new QGridLayout; QLabel *output_label = new QLabel("Output:"); @@ -217,9 +232,11 @@ in_out_widget::in_out_widget(QSettings *settings, const player_qt_internal *play input_label->setMinimumSize(output_label->minimumSizeHint()); audio_label->setMinimumSize(output_label->minimumSizeHint()); video_label->setMinimumSize(output_label->minimumSizeHint()); + subtitles_label->setMinimumSize(output_label->minimumSizeHint()); _video_combobox->setEnabled(false); _audio_combobox->setEnabled(false); + _subtitles_combobox->setEnabled(false); _input_combobox->setEnabled(false); _output_combobox->setEnabled(false); _swap_checkbox->setEnabled(false); @@ -361,6 +378,14 @@ void in_out_widget::audio_changed() } } +void in_out_widget::subtitles_changed() +{ + if (!_lock) + { + send_cmd(command::set_subtitles_stream, _subtitles_combobox->currentIndex()); + } +} + void in_out_widget::input_changed() { video_frame::stereo_layout_t stereo_layout; @@ -424,11 +449,13 @@ void in_out_widget::update(const player_init_data &init_data, bool have_valid_in _lock = true; _video_combobox->setEnabled(have_valid_input); _audio_combobox->setEnabled(have_valid_input); + _subtitles_combobox->setEnabled(have_valid_input); _input_combobox->setEnabled(have_valid_input); _output_combobox->setEnabled(have_valid_input); _swap_checkbox->setEnabled(have_valid_input); _video_combobox->clear(); _audio_combobox->clear(); + _subtitles_combobox->clear(); if (have_valid_input) { for (int i = 0; i < _player->get_media_input().video_streams(); i++) @@ -439,8 +466,13 @@ void in_out_widget::update(const player_init_data &init_data, bool have_valid_in { _audio_combobox->addItem(_player->get_media_input().audio_stream_name(i).c_str()); } + for (int i = 0; i < _player->get_media_input().subtitle_streams(); i++) + { + _subtitles_combobox->addItem(_player->get_media_input().subtitle_stream_name(i).c_str()); + } _video_combobox->setCurrentIndex(init_data.video_stream); _audio_combobox->setCurrentIndex(init_data.audio_stream); + _subtitles_combobox->setCurrentIndex(init_data.subtitle_stream); // Disable unsupported input modes for (int i = 0; i < _input_combobox->count(); i++) { @@ -477,6 +509,11 @@ int in_out_widget::get_audio_stream() return _audio_combobox->currentIndex(); } +int in_out_widget::get_subtitles_stream() +{ + return _subtitles_combobox->currentIndex(); +} + void in_out_widget::get_stereo_layout(video_frame::stereo_layout_t &stereo_layout, bool &stereo_layout_swap) { switch (_input_combobox->currentIndex()) @@ -639,6 +676,12 @@ void in_out_widget::receive_notification(const notification ¬e) _audio_combobox->setCurrentIndex(stream); _lock = false; break; + case notification::subtitles_stream: + s11n::load(current, stream); + _lock = true; + _subtitles_combobox->setCurrentIndex(stream); + _lock = false; + break; case notification::stereo_mode_swap: s11n::load(current, flag); _lock = true; @@ -1175,6 +1218,22 @@ stereoscopic_dialog::stereoscopic_dialog(const parameters ¶ms, QWidget *pare _g_spinbox->setDecimals(2); _g_spinbox->setSingleStep(0.01); connect(_g_spinbox, SIGNAL(valueChanged(double)), this, SLOT(g_spinbox_changed(double))); + QLabel *sp_label = new QLabel("Subtitles Parallax:"); + sp_label->setToolTip( + "

Adjust subtitles parallax, from -1 to +1. This changes the separation of left and right view, " + "and thus changes the depth of subtitles.

"); + _sp_slider = new QSlider(Qt::Horizontal); + _sp_slider->setToolTip(p_label->toolTip()); + _sp_slider->setRange(-1000, 1000); + _sp_slider->setValue(params.subtitles_parallax * 1000.0f); + connect(_sp_slider, SIGNAL(valueChanged(int)), this, SLOT(sp_slider_changed(int))); + _sp_spinbox = new QDoubleSpinBox(); + _sp_spinbox->setToolTip(p_label->toolTip()); + _sp_spinbox->setRange(-1.0, +1.0); + _sp_spinbox->setValue(params.subtitles_parallax); + _sp_spinbox->setDecimals(2); + _sp_spinbox->setSingleStep(0.01); + connect(_sp_spinbox, SIGNAL(valueChanged(double)), this, SLOT(sp_spinbox_changed(double))); QGridLayout *layout = new QGridLayout; layout->addWidget(p_label, 0, 0); @@ -1183,6 +1242,9 @@ stereoscopic_dialog::stereoscopic_dialog(const parameters ¶ms, QWidget *pare layout->addWidget(g_label, 1, 0); layout->addWidget(_g_slider, 1, 1); layout->addWidget(_g_spinbox, 1, 2); + layout->addWidget(sp_label, 2, 0); + layout->addWidget(_sp_slider, 2, 1); + layout->addWidget(_sp_spinbox, 2, 2); setLayout(layout); } @@ -1218,6 +1280,22 @@ void stereoscopic_dialog::g_spinbox_changed(double val) } } +void stereoscopic_dialog::sp_slider_changed(int val) +{ + if (!_lock) + { + send_cmd(command::set_subtitles_parallax, val / 1000.0f); + } +} + +void stereoscopic_dialog::sp_spinbox_changed(double val) +{ + if (!_lock) + { + send_cmd(command::set_subtitles_parallax, static_cast(val)); + } +} + void stereoscopic_dialog::receive_notification(const notification ¬e) { std::istringstream current(note.current); @@ -1239,6 +1317,13 @@ void stereoscopic_dialog::receive_notification(const notification ¬e) _g_spinbox->setValue(value); _lock = false; break; + case notification::subtitles_parallax: + s11n::load(current, value); + _lock = true; + _sp_slider->setValue(value * 1000.0f); + _sp_spinbox->setValue(value); + _lock = false; + break; default: /* not handled */ break; @@ -1246,11 +1331,172 @@ void stereoscopic_dialog::receive_notification(const notification ¬e) } + +subtitles_dialog::subtitles_dialog(const parameters ¶ms, QWidget *parent) : QDialog(parent), +_lock(false) +{ + setModal(false); + setWindowTitle("Subtitles Settings"); + + QLabel *font_label = new QLabel("Font:"); + _font_label = new QLabel((params.subtitles_font + ", " + str::from(params.subtitles_font_size)).c_str()); + _font_button = new QPushButton("Set font..."); + connect(_font_button, SIGNAL(pressed()), this, SLOT(font_button_pushed())); + _font_dialog = new QFontDialog; + QFont font; + font.setFamily(params.subtitles_font.c_str()); + font.setPointSize(params.subtitles_font_size); + _font_dialog->setCurrentFont(font); + + QLabel *color_label = new QLabel("Color:"); + _color_box = new QLabel(""); + _color_box->setAutoFillBackground(true); + _color_box->setMinimumSize(50, 20); + set_font_color(params.subtitles_color); + //connect(_color_box, SIGNAL(QLabel), this, SLOT(color_button_pushed())); + + _color_button = new QPushButton("Set color..."); + connect(_color_button, SIGNAL(pressed()), this, SLOT(color_button_pushed())); + + _color_dialog = new QColorDialog(); + _color_dialog->setCurrentColor(QColor(QRgb(params.subtitles_color))); + + QLabel *encoding_label = new QLabel("Encoding:"); + _encoding_combo = new QComboBox(); + encoding_label->setBuddy(_encoding_combo); + find_codecs(); + foreach (QTextCodec *codec, codecs) + _encoding_combo->addItem(codec->name(), codec->mibEnum()); + _encoding_combo->setCurrentIndex(_encoding_combo->findText(params.subtitles_encoding.c_str())); + connect(_encoding_combo, SIGNAL(currentIndexChanged(QString)), this, SLOT(encoding_changed(QString))); + + QGridLayout *layout = new QGridLayout; + layout->addWidget(font_label, 0, 0); + layout->addWidget(_font_label, 0, 1); + layout->addWidget(_font_button, 0, 2); + layout->addWidget(color_label, 1, 0); + layout->addWidget(_color_box, 1, 1); + layout->addWidget(_color_button, 1, 2); + layout->addWidget(encoding_label, 2, 0); + layout->addWidget(_encoding_combo, 2, 1); + + setLayout(layout); +} + +void subtitles_dialog::font_button_pushed() +{ + if (_font_dialog->exec()) + { + _font_label->setText(_font_dialog->currentFont().family() + ", " + QString::number(_font_dialog->currentFont().pointSize())); + + if (!_lock) + { + send_cmd(command::set_subtitles_font, _font_dialog->currentFont().family().toStdString()); + send_cmd(command::set_subtitles_font_size, _font_dialog->currentFont().pointSize()); + } + } +} + +void subtitles_dialog::color_button_pushed() +{ + if(_color_dialog->exec()) + { + set_font_color(_color_dialog->currentColor().rgb()); + + if (!_lock) + { + send_cmd(command::set_subtitles_color, static_cast(_color_dialog->currentColor().rgb())); + } + } +} + +void subtitles_dialog::encoding_changed(QString encoding) +{ + if (!_lock) + { + send_cmd(command::set_subtitles_encoding, encoding.toStdString()); + } +} + +void subtitles_dialog::set_font_color(int rgb) +{ + QPalette palette = _color_box->palette(); + palette.setColor(QPalette::Window, QColor(QRgb(rgb))); + _color_box->setPalette(palette); +} + +void subtitles_dialog::find_codecs() +{ + QMap codecMap; + QRegExp iso8859RegExp("ISO[- ]8859-([0-9]+).*"); + + foreach (int mib, QTextCodec::availableMibs()) { + QTextCodec *codec = QTextCodec::codecForMib(mib); + + QString sortKey = codec->name().toUpper(); + int rank; + + if (sortKey.startsWith("UTF-8")) { + rank = 1; + } else if (sortKey.startsWith("UTF-16")) { + rank = 2; + } else if (iso8859RegExp.exactMatch(sortKey)) { + if (iso8859RegExp.cap(1).size() == 1) + rank = 3; + else + rank = 4; + } else { + rank = 5; + } + sortKey.prepend(QChar('0' + rank)); + + codecMap.insert(sortKey, codec); + } + codecs = codecMap.values(); +} + +void subtitles_dialog::receive_notification(const notification ¬e) +{ + std::istringstream current(note.current); + int value; + + switch (note.type) + { + case notification::subtitles_font: + { + QFont font = _font_dialog->currentFont(); + font.setFamily(note.current.c_str()); + _font_dialog->setCurrentFont(font); + _font_label->setText(_font_dialog->currentFont().family() + ", " + QString::number(_font_dialog->currentFont().pointSize())); + break; + } + case notification::subtitles_font_size: + { + s11n::load(current, value); + QFont font = _font_dialog->currentFont(); + font.setPointSize(value); + _font_dialog->setCurrentFont(font); + _font_label->setText(_font_dialog->currentFont().family() + ", " + QString::number(_font_dialog->currentFont().pointSize())); + break; + } + case notification::subtitles_color: + s11n::load(current, value); + _lock = true; + set_font_color(value); + _lock = false; + break; + default: + /* not handled */ + break; + } +} + main_window::main_window(QSettings *settings, const player_init_data &init_data) : _settings(settings), _color_dialog(NULL), _crosstalk_dialog(NULL), _stereoscopic_dialog(NULL), + _subtitles_dialog(NULL), _player(NULL), _init_data(init_data), _init_data_template(init_data), @@ -1290,6 +1536,22 @@ main_window::main_window(QSettings *settings, const player_init_data &init_data) { _init_data.params.crosstalk_b = _settings->value("crosstalk_b", QString("0")).toFloat(); } + if (_init_data.params.subtitles_font.empty()) + { + _init_data.params.subtitles_font = _settings->value("subtitles_font", QFont().toString()).toString().toStdString(); + } + if (_init_data.params.subtitles_font_size <= 0) + { + _init_data.params.subtitles_font_size = _settings->value("subtitles_font_size", QString("12")).toInt(); + } + if (!(_init_data.params.subtitles_color >= 0x0 && _init_data.params.subtitles_color <= 0xFFFFFF)) + { + _init_data.params.subtitles_color = _settings->value("subtitles_color", QVariant(0xFFFFFF)).toInt(); + } + if (_init_data.params.subtitles_encoding.empty()) + { + _init_data.params.subtitles_encoding = _settings->value("subtitles_encoding", "UTF-8").toString().toStdString(); + } _settings->endGroup(); _init_data.params.set_defaults(); @@ -1340,6 +1602,9 @@ main_window::main_window(QSettings *settings, const player_init_data &init_data) QAction *preferences_stereoscopic_act = new QAction(tr("Stereoscopic Video Settings..."), this); connect(preferences_stereoscopic_act, SIGNAL(triggered()), this, SLOT(preferences_stereoscopic())); preferences_menu->addAction(preferences_stereoscopic_act); + QAction *preferences_subtitles_act = new QAction(tr("Subtitles Settings..."), this); + connect(preferences_subtitles_act, SIGNAL(triggered()), this, SLOT(preferences_subtitles())); + preferences_menu->addAction(preferences_subtitles_act); QMenu *help_menu = menuBar()->addMenu(tr("&Help")); QAction *help_manual_act = new QAction(tr("&Manual..."), this); help_manual_act->setShortcut(QKeySequence::HelpContents); @@ -1471,6 +1736,13 @@ void main_window::receive_notification(const notification ¬e) _settings->setValue("audio-stream", QVariant(_init_data.audio_stream).toString()); _settings->endGroup(); break; + + case notification::subtitles_stream: + s11n::load(current, _init_data.subtitle_stream); + _settings->beginGroup("Video/" + current_file_hash()); + _settings->setValue("subtitles-stream", QVariant(_init_data.subtitle_stream).toString()); + _settings->endGroup(); + break; case notification::contrast: s11n::load(current, _init_data.params.contrast); @@ -1512,6 +1784,28 @@ void main_window::receive_notification(const notification ¬e) _settings->setValue("ghostbust", QVariant(_init_data.params.ghostbust).toString()); _settings->endGroup(); break; + + case notification::subtitles_color: + s11n::load(current, _init_data.params.subtitles_color); + _settings->beginGroup("Video/" + current_file_hash()); + _settings->setValue("subtitles_color", QVariant(_init_data.params.subtitles_color).toString()); + _settings->endGroup(); + break; + + case notification::subtitles_font: + _init_data.params.subtitles_font = note.current; + break; + + case notification::subtitles_font_size: + s11n::load(current, _init_data.params.subtitles_font_size); + break; + + case notification::subtitles_encoding: + _init_data.params.subtitles_encoding = note.current; + _settings->beginGroup("Video/" + current_file_hash()); + _settings->setValue("subtitles_encoding", QVariant(_init_data.params.subtitles_encoding.c_str()).toString()); + _settings->endGroup(); + break; case notification::pause: case notification::stereo_layout: @@ -1570,6 +1864,10 @@ void main_window::closeEvent(QCloseEvent *event) _settings->setValue("crosstalk_r", QVariant(_init_data.params.crosstalk_r).toString()); _settings->setValue("crosstalk_g", QVariant(_init_data.params.crosstalk_g).toString()); _settings->setValue("crosstalk_b", QVariant(_init_data.params.crosstalk_b).toString()); + _settings->setValue("subtitles_font", QVariant(_init_data.params.subtitles_font.c_str()).toString()); + _settings->setValue("subtitles_font_size", QVariant(_init_data.params.subtitles_font_size).toString()); + _settings->setValue("subtitles_encoding", QVariant(_init_data.params.subtitles_encoding.c_str()).toString()); + _settings->setValue("subtitles_color", QVariant(_init_data.params.subtitles_color).toString()); _settings->endGroup(); event->accept(); } @@ -1654,6 +1952,11 @@ void main_window::open(QStringList filenames) _init_data.audio_stream = std::max(0, std::min(_init_data.audio_stream, _player->get_media_input().audio_streams() - 1)); _init_data.params.parallax = QVariant(_settings->value("parallax", QVariant(_init_data.params.parallax)).toString()).toFloat(); _init_data.params.ghostbust = QVariant(_settings->value("ghostbust", QVariant(_init_data.params.ghostbust)).toString()).toFloat(); + _init_data.params.subtitles_font = QVariant(_settings->value("subtitles_font", QVariant(_init_data.params.subtitles_font.c_str()))).toString().toStdString(); + _init_data.params.subtitles_font_size = QVariant(_settings->value("subtitles_font_size", QVariant(_init_data.params.subtitles_font_size))).toString().toInt(); + _init_data.params.subtitles_color = QVariant(_settings->value("subtitles_color", QVariant(_init_data.params.subtitles_color)).toString()).toInt(); + _init_data.params.subtitles_encoding = QVariant(_settings->value("subtitles_size", QVariant(_init_data.params.subtitles_encoding.c_str()))).toString().toStdString(); + _init_data.params.subtitles_parallax = QVariant(_settings->value("subtitles_parallax", QVariant(_init_data.params.subtitles_parallax)).toString()).toFloat(); // Get stereo mode for this video _settings->endGroup(); QString mode_fallback = QString(parameters::stereo_mode_to_string( @@ -1757,6 +2060,17 @@ void main_window::preferences_stereoscopic() _stereoscopic_dialog->activateWindow(); } +void main_window::preferences_subtitles() +{ + if (!_subtitles_dialog) + { + _subtitles_dialog = new subtitles_dialog(_init_data.params, this); + } + _subtitles_dialog->show(); + _subtitles_dialog->raise(); + _subtitles_dialog->activateWindow(); +} + void main_window::help_manual() { QUrl manual_url; diff --git a/src/player_qt.h b/src/player_qt.h index f631a08..2fcca96 100644 --- a/src/player_qt.h +++ b/src/player_qt.h @@ -33,10 +33,13 @@ #include #include #include +#include +#include #include "controller.h" #include "video_output_qt.h" #include "player.h" +#include class player_qt_internal : public player, public controller @@ -73,6 +76,7 @@ private: const player_qt_internal *_player; QComboBox *_video_combobox; QComboBox *_audio_combobox; + QComboBox *_subtitles_combobox; QComboBox *_input_combobox; QComboBox *_output_combobox; QCheckBox *_swap_checkbox; @@ -84,6 +88,7 @@ private: private slots: void video_changed(); void audio_changed(); + void subtitles_changed(); void input_changed(); void output_changed(); void swap_changed(); @@ -96,6 +101,7 @@ public: int get_video_stream(); int get_audio_stream(); + int get_subtitles_stream(); void get_stereo_layout(video_frame::stereo_layout_t &stereo_layout, bool &stereo_layout_swap); void get_stereo_mode(parameters::stereo_mode_t &stereo_mode, bool &stereo_mode_swap); @@ -202,16 +208,21 @@ class stereoscopic_dialog : public QDialog, public controller private: bool _lock; + QDoubleSpinBox *_p_spinbox; QSlider *_p_slider; QDoubleSpinBox *_g_spinbox; QSlider *_g_slider; + QDoubleSpinBox *_sp_spinbox; + QSlider *_sp_slider; private slots: void p_slider_changed(int val); void p_spinbox_changed(double val); void g_slider_changed(int val); void g_spinbox_changed(double val); + void sp_slider_changed(int val); + void sp_spinbox_changed(double val); public: stereoscopic_dialog(const parameters ¶ms, QWidget *parent); @@ -219,6 +230,37 @@ public: virtual void receive_notification(const notification ¬e); }; +class subtitles_dialog : public QDialog, public controller +{ + Q_OBJECT + +private: + bool _lock; + QLabel *_font_label; + QPushButton * _font_button; + QFontDialog * _font_dialog; + QColorDialog * _color_dialog; + QLabel * _color_box; + QPushButton * _color_button; + QComboBox * _encoding_combo; + + QList codecs; + +private slots: + void font_button_pushed(); + void color_button_pushed(); + void encoding_changed(QString encoding); + +private: + void set_font_color(int rgb); + void find_codecs(); + +public: + subtitles_dialog(const parameters ¶ms, QWidget *parent); + + virtual void receive_notification(const notification ¬e); +}; + class main_window : public QMainWindow, public controller { @@ -232,6 +274,7 @@ private: color_dialog *_color_dialog; crosstalk_dialog *_crosstalk_dialog; stereoscopic_dialog *_stereoscopic_dialog; + subtitles_dialog *_subtitles_dialog; player_qt_internal *_player; QTimer *_timer; player_init_data _init_data; @@ -250,6 +293,7 @@ private slots: void preferences_colors(); void preferences_crosstalk(); void preferences_stereoscopic(); + void preferences_subtitles(); void help_manual(); void help_website(); void help_keyboard(); diff --git a/src/subtitle_renderer.cpp b/src/subtitle_renderer.cpp index 473e915..a69d44f 100644 --- a/src/subtitle_renderer.cpp +++ b/src/subtitle_renderer.cpp @@ -104,7 +104,6 @@ void subtitle_renderer::init_ass() ass_set_message_cb(_ass_library, libass_msg_callback, NULL); ass_set_fonts_dir(_ass_library, ""); ass_set_extract_fonts(_ass_library, 1); - ass_set_style_overrides(_ass_library, NULL); _ass_renderer = ass_renderer_init(_ass_library); if (!_ass_renderer) { @@ -112,7 +111,10 @@ void subtitle_renderer::init_ass() } ass_set_hinting(_ass_renderer, ASS_HINTING_NATIVE); ass_set_fonts(_ass_renderer, NULL, "Sans", 1, NULL, 1); + _ass_initialized = true; + + set_style_overide(); } } @@ -129,6 +131,14 @@ void subtitle_renderer::render(const subtitle_box &box, int width, int height, f } } +void subtitle_renderer::set_parameters(const parameters& params) +{ + _params = params; + + set_style_overide(); +} + + void subtitle_renderer::render_ass(const subtitle_box &box, int width, int height, float pixel_aspect_ratio, uint32_t *bgra32_buffer) { // Set ASS parameters @@ -148,7 +158,7 @@ void subtitle_renderer::render_ass(const subtitle_box &box, int width, int heigh ass_process_data(ass_track, const_cast(box.str.c_str()), box.str.length()); } else - { + { std::string style = "[Script Info]\n" "ScriptType: v4.00+\n" @@ -216,3 +226,28 @@ void subtitle_renderer::blend_ass_image(const ASS_Image *img, int width, int hei src += img->stride; } } + +void subtitle_renderer::set_style_overide() +{ + if(_ass_initialized) + { + // Set subtitle style overides + char * list[5] = {NULL}; + std::string string_list[4]; + std::stringstream colour; + colour << "&H" << std::hex << (_params.subtitles_color & 0x0000FF) << ((_params.subtitles_color & 0x00FF00) >> 8) << ((_params.subtitles_color & 0xFF0000) >> 16); + + string_list[0] += "Default.Fontsize="+str::from(_params.subtitles_font_size); + string_list[1] += "Default.Fontname="+_params.subtitles_font; + string_list[2] += "Default.PrimaryColour="+colour.str(); + string_list[3] += "Default.SecondaryColour="+colour.str(); + + list[0] = const_cast(string_list[0].c_str()); + list[1] = const_cast(string_list[1].c_str()); + list[2] = const_cast(string_list[2].c_str()); + list[3] = const_cast(string_list[3].c_str()); + + ass_set_style_overrides(_ass_library, list); + } +} + diff --git a/src/subtitle_renderer.h b/src/subtitle_renderer.h index cc73952..38b9a62 100644 --- a/src/subtitle_renderer.h +++ b/src/subtitle_renderer.h @@ -29,6 +29,7 @@ extern "C" } #include "media_data.h" +#include "controller.h" class subtitle_renderer @@ -37,11 +38,13 @@ private: bool _ass_initialized; ASS_Library *_ass_library; ASS_Renderer *_ass_renderer; + parameters _params; // current parameters for display void init_ass(); void render_ass(const subtitle_box &box, int width, int height, float pixel_aspect_ratio, uint32_t *bgra32_buffer); void blend_ass_image(const ASS_Image *img, int width, int height, uint32_t *buf); + void set_style_overide(); // Set subtitle style overides public: subtitle_renderer(); @@ -50,6 +53,9 @@ public: // Render the subtitle box into a buffer in BGRA32 format. The buffer must have the correct // size for width * height pixels of type uint32_t. Pixels are assumed to have the given aspect ratio. void render(const subtitle_box &box, int width, int height, float pixel_aspect_ratio, uint32_t *bgra32_buffer); + + /* Set display parameters. */ + void set_parameters(const parameters ¶ms); }; #endif diff --git a/src/video_output.cpp b/src/video_output.cpp index 4aa3c31..d51ff6d 100644 --- a/src/video_output.cpp +++ b/src/video_output.cpp @@ -688,6 +688,8 @@ void video_output::set_parameters(const parameters ¶ms) _color_last_frame = video_frame(); } trigger_update(); + + _subtitle_renderer.set_parameters(params); } static void draw_quad(float x, float y, float w, float h) @@ -870,7 +872,7 @@ void video_output::display_current_frame( glUniform1i(glGetUniformLocation(_render_prg, "rgb_r"), right); glUniform1f(glGetUniformLocation(_render_prg, "parallax"), _params.parallax * 0.05f); glUniform1i(glGetUniformLocation(_render_prg, "subtitle"), 2); - glUniform1f(glGetUniformLocation(_render_prg, "subtitle_parallax"), 0.0f); // TODO: make this adjustable + glUniform1f(glGetUniformLocation(_render_prg, "subtitle_parallax"), _params.subtitles_parallax * 0.05f); if (_params.stereo_mode != parameters::red_green_monochrome && _params.stereo_mode != parameters::red_cyan_half_color && _params.stereo_mode != parameters::red_cyan_full_color diff --git a/src/video_output_qt.cpp b/src/video_output_qt.cpp index 97ba606..5ac4491 100644 --- a/src/video_output_qt.cpp +++ b/src/video_output_qt.cpp @@ -546,10 +546,13 @@ void video_output_qt::process_events() void video_output_qt::receive_notification(const notification ¬e) { - if (note.type == notification::play) + std::istringstream current(note.current); + + switch(note.type) { - std::istringstream current(note.current); + case notification::play: s11n::load(current, _playing); + break; } /* More is currently not implemented. * In the future, an on-screen display might show hints about what happened. */