From 5c1d75e24ccc446f4e15767dcea55167b1678d66 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Tue, 2 Apr 2019 09:33:34 +0200 Subject: [PATCH 01/14] Add Eclipse and dist files to gitignore --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 9a851162..3a695f8d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,11 @@ ffmpeg help.h keys.h patch.flag +.cproject +.project +.settings +omxplayer-dist +omxplayer-dist.tgz +omxplayer.1 +version.h +MAN From 50cefb9cdafa9969b5d4fc302a430e5285cea77d Mon Sep 17 00:00:00 2001 From: Nonoo Date: Tue, 2 Apr 2019 10:49:30 +0200 Subject: [PATCH 02/14] Add static title display option The static text displayed can be set with the --title command line argument. The default font face will be used by default with a slightly smaller font size, these can be overridden with the --title-font and --title-font-size command line arguments. The alignment of the title can be changed with --title-align --- OMXPlayerSubtitles.cpp | 36 ++++++++-- OMXPlayerSubtitles.h | 14 +++- SubtitleRenderer.cpp | 156 ++++++++++++++++++++++++++++++++++------- SubtitleRenderer.h | 45 +++++++++--- omxplayer.cpp | 42 ++++++++++- 5 files changed, 251 insertions(+), 42 deletions(-) diff --git a/OMXPlayerSubtitles.cpp b/OMXPlayerSubtitles.cpp index 7f074c3e..a64a5a41 100644 --- a/OMXPlayerSubtitles.cpp +++ b/OMXPlayerSubtitles.cpp @@ -41,6 +41,7 @@ OMXPlayerSubtitles::OMXPlayerSubtitles() BOOST_NOEXCEPT m_thread_stopped(), m_font_size(), m_centered(), + m_title_centered(), m_ghost_box(), m_lines(), m_av_clock(), @@ -58,12 +59,16 @@ bool OMXPlayerSubtitles::Open(size_t stream_count, vector&& external_subtitles, const string& font_path, const string& italic_font_path, + const string& title_font_path, float font_size, + float title_font_size, bool centered, + bool title_centered, bool ghost_box, unsigned int lines, int display, int layer, - OMXClock* clock) BOOST_NOEXCEPT + OMXClock* clock, + const string& title) BOOST_NOEXCEPT { assert(!m_open); @@ -78,18 +83,22 @@ bool OMXPlayerSubtitles::Open(size_t stream_count, m_font_path = font_path; m_italic_font_path = italic_font_path; + m_title_font_path = title_font_path; m_font_size = font_size; + m_title_font_size = title_font_size; m_centered = centered; + m_title_centered = title_centered; m_ghost_box = ghost_box; m_lines = lines; m_av_clock = clock; m_display = display; m_layer = layer; + m_title = title; if(!Create()) return false; - SendToRenderer(Message::Flush{m_external_subtitles}); + SendToRenderer(Message::Flush{m_external_subtitles, m_title}); #ifndef NDEBUG m_open = true; @@ -118,8 +127,8 @@ void OMXPlayerSubtitles::Process() { try { - RenderLoop(m_font_path, m_italic_font_path, m_font_size, m_centered, - m_ghost_box, m_lines, m_av_clock); + RenderLoop(m_font_path, m_italic_font_path, m_title_font_path, m_font_size, m_title_font_size, + m_centered, m_title_centered, m_ghost_box, m_lines, m_av_clock); } catch(Enforce_error& e) { @@ -146,8 +155,11 @@ Iterator FindSubtitle(Iterator begin, Iterator end, int time) void OMXPlayerSubtitles:: RenderLoop(const string& font_path, const string& italic_font_path, + const string& title_font_path, float font_size, + float title_font_size, bool centered, + bool title_centered, bool ghost_box, unsigned int lines, OMXClock* clock) @@ -155,14 +167,18 @@ RenderLoop(const string& font_path, SubtitleRenderer renderer(m_display, m_layer, font_path, italic_font_path, + title_font_path, font_size, - 0.01f, 0.06f, + title_font_size, + 0.06f, 0.06f, centered, + title_centered, 0xDD, ghost_box ? 0x80 : 0, lines); vector subtitles; + std::string title; int prev_now{}; size_t next_index{}; @@ -248,7 +264,13 @@ RenderLoop(const string& font_path, [&](Message::Flush&& args) { subtitles = std::move(args.subtitles); + title = std::move(args.title); prev_now = INT_MAX; + + if (title != "") { + renderer.prepare_title(title); + renderer.show_next(); + } }, [&](Message::Touch&&) { @@ -328,7 +350,7 @@ void OMXPlayerSubtitles::FlushRenderer() if(GetUseExternalSubtitles()) { - SendToRenderer(Message::Flush{m_external_subtitles}); + SendToRenderer(Message::Flush{m_external_subtitles, m_title}); } else { @@ -500,4 +522,4 @@ void OMXPlayerSubtitles::DisplayText(const std::string& text, int duration) BOOS void OMXPlayerSubtitles::SetSubtitleRect(int x1, int y1, int x2, int y2) BOOST_NOEXCEPT { SendToRenderer(Message::SetRect{x1, y1, x2, y2}); -} \ No newline at end of file +} diff --git a/OMXPlayerSubtitles.h b/OMXPlayerSubtitles.h index 91c374c0..e6c2f084 100644 --- a/OMXPlayerSubtitles.h +++ b/OMXPlayerSubtitles.h @@ -43,12 +43,16 @@ class OMXPlayerSubtitles : public OMXThread std::vector&& external_subtitles, const std::string& font_path, const std::string& italic_font_path, + const std::string& title_font_path, float font_size, + float title_font_size, bool centered, + bool title_centered, bool ghost_box, unsigned int lines, int display, int layer, - OMXClock* clock) BOOST_NOEXCEPT; + OMXClock* clock, + const string& title) BOOST_NOEXCEPT; void Close() BOOST_NOEXCEPT; void Flush() BOOST_NOEXCEPT; void Resume() BOOST_NOEXCEPT; @@ -99,6 +103,7 @@ class OMXPlayerSubtitles : public OMXThread struct Flush { std::vector subtitles; + std::string title; }; struct Push { @@ -141,8 +146,11 @@ class OMXPlayerSubtitles : public OMXThread void Process(); void RenderLoop(const std::string& font_path, const std::string& italic_font_path, + const std::string& title_font_path, float font_size, + float title_font_size, bool centered, + bool title_centered, bool ghost_box, unsigned int lines, OMXClock* clock); @@ -167,13 +175,17 @@ class OMXPlayerSubtitles : public OMXThread std::atomic m_thread_stopped; std::string m_font_path; std::string m_italic_font_path; + std::string m_title_font_path; float m_font_size; + float m_title_font_size; bool m_centered; + bool m_title_centered; bool m_ghost_box; unsigned int m_lines; OMXClock* m_av_clock; int m_display; int m_layer; + std::string m_title; #ifndef NDEBUG bool m_open; diff --git a/SubtitleRenderer.cpp b/SubtitleRenderer.cpp index 540162ff..161579cd 100644 --- a/SubtitleRenderer.cpp +++ b/SubtitleRenderer.cpp @@ -88,7 +88,7 @@ class BoxRenderer { } }; -void SubtitleRenderer::load_glyph(InternalChar ch) { +void SubtitleRenderer::load_glyph(InternalChar ch, bool title) { VGfloat escapement[2]{}; auto load_glyph_internal = @@ -180,6 +180,13 @@ void SubtitleRenderer::load_glyph(InternalChar ch) { } }; + if (title) { + load_glyph_internal(ft_face_title_, vg_font_title_, false); + glyphs_title_[ch].advance = escapement[0]; + load_glyph_internal(ft_face_title_, vg_font_title_border_, true); + return; + } + if (!ch.italic()) { load_glyph_internal(ft_face_, vg_font_, false); glyphs_[ch].advance = escapement[0]; @@ -191,10 +198,13 @@ void SubtitleRenderer::load_glyph(InternalChar ch) { } } -int SubtitleRenderer::get_text_width(const std::vector& text) { +int SubtitleRenderer::get_text_width(const std::vector& text, bool title) { int width = 0; for (auto c = text.begin(); c != text.end(); ++c) { - width += glyphs_.at(*c).advance; + if (title) + width += glyphs_title_.at(*c).advance; + else + width += glyphs_.at(*c).advance; } return width; } @@ -217,10 +227,15 @@ get_internal_chars(const std::string& str, TagTracker& tag_tracker) { } void SubtitleRenderer:: -prepare_glyphs(const std::vector& text) { +prepare_glyphs(const std::vector& text, bool title) { for (auto c = text.begin(); c != text.end(); ++c) { - if (glyphs_.find(*c) == glyphs_.end()) - load_glyph(*c); + if (title) { + if (glyphs_title_.find(*c) == glyphs_title_.end()) + load_glyph(*c, title); + } else { + if (glyphs_.find(*c) == glyphs_.end()) + load_glyph(*c, title); + } } } @@ -264,14 +279,18 @@ SubtitleRenderer:: SubtitleRenderer(int display, int layer, const std::string& font_path, const std::string& italic_font_path, + const std::string& title_font_path, float font_size, + float title_font_size, float margin_left, float margin_bottom, bool centered, + bool title_centered, unsigned int white_level, unsigned int box_opacity, unsigned int lines) : prepared_(), + title_prepared_(), dispman_element_(), dispman_display_(), display_(), @@ -279,19 +298,24 @@ SubtitleRenderer(int display, int layer, surface_(), vg_font_(), vg_font_border_(), + vg_font_title_(), + vg_font_title_border_(), ft_library_(), ft_face_(), ft_face_italic_(), + ft_face_title_(), ft_stroker_(), centered_(centered), + title_centered_(title_centered), white_level_(white_level), box_opacity_(box_opacity), - font_size_(font_size) + font_size_(font_size), + title_font_size_(title_font_size) { try { ENFORCE(graphics_get_display_size(display, &screen_width_, &screen_height_) >= 0); - initialize_fonts(font_path, italic_font_path); + initialize_fonts(font_path, italic_font_path, title_font_path); int abs_margin_bottom = static_cast(margin_bottom * screen_height_ + 0.5f) - config_.box_offset; @@ -299,15 +323,16 @@ SubtitleRenderer(int display, int layer, int buffer_padding = (config_.line_height+2)/4; int buffer_bottom = clamp(abs_margin_bottom + config_.box_offset - buffer_padding, 0, (int) screen_height_-1); - int buffer_top = clamp(buffer_bottom + config_.line_height * (int) lines + buffer_padding*2, + int buffer_top = clamp(buffer_bottom + config_.title_line_height + config_.title_line_padding + + config_.line_height * (int) lines + buffer_padding*2, 0, (int) screen_height_-1); config_.buffer_x = 0; config_.buffer_y = screen_height_ - buffer_top - 1; config_.buffer_width = screen_width_; config_.buffer_height = buffer_top - buffer_bottom + 1; - config_.margin_left = (screen_width_ - screen_height_) / 2 + - static_cast(margin_left * screen_height_ + 0.5f); + config_.margin_left = static_cast(margin_left * screen_width_ + 0.5f); + config_.margin_bottom = abs_margin_bottom - buffer_bottom; config_fullscreen_ = config_; // save full-screen config for scaling reference. @@ -328,21 +353,27 @@ void SubtitleRenderer::destroy() { void SubtitleRenderer:: initialize_fonts(const std::string& font_path, - const std::string& italic_font_path) { + const std::string& italic_font_path, + const std::string& title_font_path) { ENFORCE(!FT_Init_FreeType(&ft_library_)); ENFORCE2(!FT_New_Face(ft_library_, font_path.c_str(), 0, &ft_face_), "Unable to open font"); ENFORCE2(!FT_New_Face(ft_library_, italic_font_path.c_str(), 0, &ft_face_italic_), "Unable to open italic font"); + ENFORCE2(!FT_New_Face(ft_library_, title_font_path.c_str(), 0, &ft_face_title_), + "Unable to open title font"); + uint32_t font_size = font_size_*screen_height_; + uint32_t title_font_size = title_font_size_*screen_height_; ENFORCE(!FT_Set_Pixel_Sizes(ft_face_, 0, font_size)); ENFORCE(!FT_Set_Pixel_Sizes(ft_face_italic_, 0, font_size)); + ENFORCE(!FT_Set_Pixel_Sizes(ft_face_title_, 0, title_font_size)); - auto get_bbox = [this](char32_t cp) { - auto glyph_index = FT_Get_Char_Index(ft_face_, cp); - ENFORCE(!FT_Load_Glyph(ft_face_, glyph_index, FT_LOAD_NO_HINTING)); + auto get_bbox = [this](char32_t cp, FT_Face& font) { + auto glyph_index = FT_Get_Char_Index(font, cp); + ENFORCE(!FT_Load_Glyph(font, glyph_index, FT_LOAD_NO_HINTING)); FT_Glyph glyph; - ENFORCE(!FT_Get_Glyph(ft_face_->glyph, &glyph)); + ENFORCE(!FT_Get_Glyph(font->glyph, &glyph)); SCOPE_EXIT {FT_Done_Glyph(glyph);}; FT_BBox bbox; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox); @@ -350,15 +381,24 @@ initialize_fonts(const std::string& font_path, }; constexpr float padding_factor = 0.05f; - int y_min = get_bbox('g').yMin; - int y_max = get_bbox('M').yMax; + int y_min = get_bbox('g', ft_face_).yMin; + int y_max = get_bbox('M', ft_face_).yMax; y_max += -y_min*0.7f; config_.line_height = y_max - y_min; - const int v_padding = config_.line_height*padding_factor + 0.5f; + int v_padding = config_.line_height*padding_factor + 0.5f; config_.line_height += v_padding*2; config_.box_offset = y_min-v_padding; config_.box_h_padding = config_.line_height/5.0f + 0.5f; + y_min = get_bbox('g', ft_face_title_).yMin; + y_max = get_bbox('M', ft_face_title_).yMax; + y_max += -y_min*0.7f; + config_.title_line_height = y_max - y_min; + v_padding = config_.title_line_height*padding_factor + 0.5f; + config_.title_line_height += v_padding*2; + config_.title_line_padding = config_.line_height * 0.5f + 0.5f; + config_.title_box_offset = y_min-v_padding; + config_.title_box_h_padding = config_.title_line_height/5.0f + 0.5f; constexpr float border_thickness = 0.044f; ENFORCE(!FT_Stroker_New(ft_library_, &ft_stroker_)); @@ -376,6 +416,7 @@ void SubtitleRenderer::destroy_fonts() { ft_library_ = {}; ft_face_ = {}; ft_face_italic_ = {}; + ft_face_title_ = {}; ft_stroker_ = {}; } } @@ -496,6 +537,9 @@ void SubtitleRenderer::initialize_vg() { create_vg_font(vg_font_); create_vg_font(vg_font_border_); + create_vg_font(vg_font_title_); + create_vg_font(vg_font_title_border_); + // VGfloat color[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; // vgSetfv(VG_CLEAR_COLOR, 4, color); } @@ -523,11 +567,22 @@ prepare(const std::vector& text_lines) BOOST_NOEXCEPT { internal_lines_.resize(n_lines); line_widths_.resize(n_lines); line_positions_.resize(n_lines); + + int title_line_height = config_.title_line_height; + int title_line_padding = config_.title_line_padding; + + if (!title_prepared_) { + title_line_height = 0; + title_line_padding = 0; + } + for (int i = 0; i < n_lines; ++i) { internal_lines_[i] = get_internal_chars(text_lines[i], tag_tracker); - prepare_glyphs(internal_lines_[i]); - line_widths_[i] = get_text_width(internal_lines_[i]); - line_positions_[i].second = config_.margin_bottom + (n_lines-i-1)*config_.line_height; + prepare_glyphs(internal_lines_[i], false); + line_widths_[i] = get_text_width(internal_lines_[i], false); + line_positions_[i].second = config_.margin_bottom + + title_line_height + title_line_padding + + (n_lines-i-1)*config_.line_height; if (centered_) line_positions_[i].first = config_.buffer_width/2 - line_widths_[i]/2; else @@ -537,13 +592,57 @@ prepare(const std::vector& text_lines) BOOST_NOEXCEPT { prepared_ = true; } +void SubtitleRenderer:: +prepare_title(const std::string& line) BOOST_NOEXCEPT { + TagTracker tag_tracker; + + internal_info_line_ = get_internal_chars(line, tag_tracker); + prepare_glyphs(internal_info_line_, true); + info_line_width_ = get_text_width(internal_info_line_, true); + info_line_position_.second = config_.margin_bottom; + if (title_centered_) + info_line_position_.first = config_.buffer_width/2 - info_line_width_/2; + else + info_line_position_.first = config_.margin_left; + + title_prepared_ = true; +} + void SubtitleRenderer::clear() BOOST_NOEXCEPT { vgClear(0, 0, screen_width_, screen_height_); assert(!vgGetError()); } -void SubtitleRenderer::draw() BOOST_NOEXCEPT { - clear(); +void SubtitleRenderer::draw_title(bool clear_needed) BOOST_NOEXCEPT { + if (clear_needed) + clear(); + + // info line graybox + { + BoxRenderer box_renderer(box_opacity_); + box_renderer.push(info_line_position_.first - config_.box_h_padding, + info_line_position_.second + config_.title_box_offset, + info_line_width_ + config_.title_box_h_padding*2, + config_.title_line_height); + box_renderer.render(); + } + + //info line background + draw_text(vg_font_title_border_, + internal_info_line_, + info_line_position_.first, info_line_position_.second, + 0); + + //info line foreground + draw_text(vg_font_title_, + internal_info_line_, + info_line_position_.first, info_line_position_.second, + white_level_); +} + +void SubtitleRenderer::draw(bool clear_needed) BOOST_NOEXCEPT { + if (clear_needed) + clear(); const auto n_lines = internal_lines_.size(); @@ -598,6 +697,10 @@ void SubtitleRenderer::set_rect(int x1, int y1, int x2, int y2) BOOST_NOEXCEPT config_.box_h_padding = config_fullscreen_.box_h_padding * height_mod + 0.5f; config_.margin_left = config_fullscreen_.margin_left * width_mod + 0.5f; config_.margin_bottom = config_fullscreen_.margin_bottom * height_mod + 0.5f; + config_.title_line_height = config_fullscreen_.title_line_height * height_mod + 0.5f; + config_.title_line_padding = config_fullscreen_.title_line_padding * height_mod + 0.5f; + config_.title_box_offset = config_fullscreen_.title_box_offset * height_mod + 0.5f; + config_.title_box_h_padding = config_fullscreen_.title_box_h_padding * height_mod + 0.5f; // resize dispmanx element ENFORCE(dispman_element_); @@ -615,7 +718,10 @@ void SubtitleRenderer::set_rect(int x1, int y1, int x2, int y2) BOOST_NOEXCEPT // resize font glyphs_.clear(); // clear cached glyphs + glyphs_title_.clear(); float font_size = height*font_size_; + float title_font_size = height*title_font_size_; ENFORCE(!FT_Set_Pixel_Sizes(ft_face_, 0, font_size)); ENFORCE(!FT_Set_Pixel_Sizes(ft_face_italic_, 0, font_size)); -} \ No newline at end of file + ENFORCE(!FT_Set_Pixel_Sizes(ft_face_title_, 0, title_font_size)); +} diff --git a/SubtitleRenderer.h b/SubtitleRenderer.h index 3f60798f..66a39cde 100644 --- a/SubtitleRenderer.h +++ b/SubtitleRenderer.h @@ -91,6 +91,10 @@ typedef struct { int box_h_padding; int margin_left; int margin_bottom; + int title_line_height; + int title_line_padding; + int title_box_offset; + int title_box_h_padding; } SubtitleConfig; class SubtitleRenderer { @@ -100,34 +104,47 @@ class SubtitleRenderer { SubtitleRenderer(int display, int layer, const std::string& font_path, const std::string& italic_font_path, + const std::string& title_font_path, float font_size, + float title_font_size, float margin_left, float margin_bottom, bool centered, + bool title_centered, unsigned int white_level, unsigned int box_opacity, unsigned int lines); ~SubtitleRenderer() BOOST_NOEXCEPT; void prepare(const std::vector& text_lines) BOOST_NOEXCEPT; + void prepare_title(const std::string& line) BOOST_NOEXCEPT; void unprepare() BOOST_NOEXCEPT { prepared_ = false; } void show_next() BOOST_NOEXCEPT { + if (title_prepared_) + draw_title(1); if (prepared_) { // puts("Expensive show_next!"); - draw(); + draw(!title_prepared_); } swap_buffers(); } void hide() BOOST_NOEXCEPT { - clear(); + if (title_prepared_) + draw_title(1); + else + clear(); + swap_buffers(); + + if (title_prepared_) + draw_title(1); if (prepared_) - draw(); + draw(!title_prepared_); } void set_rect(int width, int height, int x, int y) BOOST_NOEXCEPT; @@ -166,22 +183,25 @@ class SubtitleRenderer { void destroy(); void initialize_fonts(const std::string& font_name, - const std::string& italic_font_path); + const std::string& italic_font_path, + const std::string& title_font_path); void destroy_fonts(); void initialize_vg(); void destroy_vg(); void initialize_window(int display, int layer); void destroy_window(); void clear() BOOST_NOEXCEPT; - void draw() BOOST_NOEXCEPT; + void draw_title(bool clear_needed) BOOST_NOEXCEPT; + void draw(bool clear_needed) BOOST_NOEXCEPT; void swap_buffers() BOOST_NOEXCEPT; - void prepare_glyphs(const std::vector& text); - void load_glyph(InternalChar ch); - int get_text_width(const std::vector& text); + void prepare_glyphs(const std::vector& text, bool title); + void load_glyph(InternalChar ch, bool title); + int get_text_width(const std::vector& text, bool title); std::vector get_internal_chars(const std::string& str, TagTracker& tag_tracker); bool prepared_; + bool title_prepared_; DISPMANX_ELEMENT_HANDLE_T dispman_element_; DISPMANX_DISPLAY_HANDLE_T dispman_display_; EGLDisplay display_; @@ -189,20 +209,29 @@ class SubtitleRenderer { EGLSurface surface_; VGFont vg_font_; VGFont vg_font_border_; + VGFont vg_font_title_; + VGFont vg_font_title_border_; FT_Library ft_library_; FT_Face ft_face_; FT_Face ft_face_italic_; + FT_Face ft_face_title_; FT_Stroker ft_stroker_; std::unordered_map glyphs_; + std::unordered_map glyphs_title_; std::vector> internal_lines_; std::vector> line_positions_; std::vector line_widths_; + std::vector internal_info_line_; + std::pair info_line_position_; + int info_line_width_; bool centered_; + bool title_centered_; unsigned int white_level_; unsigned int box_opacity_; uint32_t screen_width_; uint32_t screen_height_; float font_size_; + float title_font_size_; SubtitleConfig config_fullscreen_; SubtitleConfig config_; }; diff --git a/omxplayer.cpp b/omxplayer.cpp index 0d4ab5e5..0dff667e 100644 --- a/omxplayer.cpp +++ b/omxplayer.cpp @@ -85,11 +85,15 @@ std::string m_external_subtitles_path; bool m_has_external_subtitles = false; std::string m_font_path = "/usr/share/fonts/truetype/freefont/FreeSans.ttf"; std::string m_italic_font_path = "/usr/share/fonts/truetype/freefont/FreeSansOblique.ttf"; +std::string m_title_font_path = "/usr/share/fonts/truetype/freefont/FreeSans.ttf"; std::string m_dbus_name = "org.mpris.MediaPlayer2.omxplayer"; bool m_asked_for_font = false; bool m_asked_for_italic_font = false; float m_font_size = 0.055f; +bool m_asked_for_title_font = false; +float m_title_font_size = 0.035f; bool m_centered = false; +bool m_title_centered = false; bool m_ghost_box = true; unsigned int m_subtitle_lines = 3; bool m_Pause = false; @@ -114,6 +118,7 @@ bool m_has_audio = false; bool m_has_subtitle = false; bool m_gen_log = false; bool m_loop = false; +std::string m_title; enum{ERROR=-1,SUCCESS,ONEBYTE}; @@ -532,6 +537,10 @@ int main(int argc, char *argv[]) const int font_opt = 0x100; const int italic_font_opt = 0x201; const int font_size_opt = 0x101; + const int title_opt = 0x214; + const int title_font_opt = 0x215; + const int title_font_size_opt = 0x216; + const int title_align_opt = 0x217; const int align_opt = 0x102; const int no_ghost_box_opt = 0x203; const int subtitles_opt = 0x103; @@ -600,6 +609,10 @@ int main(int argc, char *argv[]) { "font", required_argument, NULL, font_opt }, { "italic-font", required_argument, NULL, italic_font_opt }, { "font-size", required_argument, NULL, font_size_opt }, + { "title", required_argument, NULL, title_opt }, + { "title-font", required_argument, NULL, title_font_opt }, + { "title-font-size", required_argument, NULL, title_font_size_opt }, + { "title-align", required_argument, NULL, title_align_opt }, { "align", required_argument, NULL, align_opt }, { "no-ghost-box", no_argument, NULL, no_ghost_box_opt }, { "subtitles", required_argument, NULL, subtitles_opt }, @@ -780,6 +793,20 @@ int main(int argc, char *argv[]) m_font_size = thousands*0.001f; } break; + case title_font_opt: + m_title_font_path = optarg; + m_asked_for_title_font = true; + break; + case title_font_size_opt: + { + const int thousands = atoi(optarg); + if (thousands > 0) + m_title_font_size = thousands*0.001f; + } + break; + case title_align_opt: + m_title_centered = !strcmp(optarg, "center"); + break; case align_opt: m_centered = !strcmp(optarg, "center"); break; @@ -813,6 +840,9 @@ int main(int argc, char *argv[]) m_config_video.aspectMode = 0; } break; + case title_opt: + m_title = optarg; + break; case vol_opt: m_Volume = atoi(optarg); break; @@ -960,6 +990,12 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } + if(m_asked_for_title_font && !Exists(m_title_font_path)) + { + PrintFileNotFound(m_title_font_path); + return EXIT_FAILURE; + } + if(m_has_external_subtitles && !Exists(m_external_subtitles_path)) { PrintFileNotFound(m_external_subtitles_path); @@ -1115,12 +1151,16 @@ int main(int argc, char *argv[]) std::move(external_subtitles), m_font_path, m_italic_font_path, + m_title_font_path, m_font_size, + m_title_font_size, m_centered, + m_title_centered, m_ghost_box, m_subtitle_lines, m_config_video.display, m_config_video.layer + 1, - m_av_clock)) + m_av_clock, + m_title)) goto do_exit; if(m_config_video.dst_rect.x2 > 0 && m_config_video.dst_rect.y2 > 0) m_player_subtitles.SetSubtitleRect(m_config_video.dst_rect.x1, m_config_video.dst_rect.y1, m_config_video.dst_rect.x2, m_config_video.dst_rect.y2); From c6e2ebc8fb4f10ba09e2e02d14cb84cce75389b8 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Tue, 2 Apr 2019 11:07:11 +0200 Subject: [PATCH 03/14] Fix title variable names --- SubtitleRenderer.cpp | 32 ++++++++++++++++---------------- SubtitleRenderer.h | 6 +++--- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/SubtitleRenderer.cpp b/SubtitleRenderer.cpp index 161579cd..0bffdb30 100644 --- a/SubtitleRenderer.cpp +++ b/SubtitleRenderer.cpp @@ -596,14 +596,14 @@ void SubtitleRenderer:: prepare_title(const std::string& line) BOOST_NOEXCEPT { TagTracker tag_tracker; - internal_info_line_ = get_internal_chars(line, tag_tracker); - prepare_glyphs(internal_info_line_, true); - info_line_width_ = get_text_width(internal_info_line_, true); - info_line_position_.second = config_.margin_bottom; + internal_title_line_ = get_internal_chars(line, tag_tracker); + prepare_glyphs(internal_title_line_, true); + title_line_width_ = get_text_width(internal_title_line_, true); + title_line_position_.second = config_.margin_bottom; if (title_centered_) - info_line_position_.first = config_.buffer_width/2 - info_line_width_/2; + title_line_position_.first = config_.buffer_width/2 - title_line_width_/2; else - info_line_position_.first = config_.margin_left; + title_line_position_.first = config_.margin_left; title_prepared_ = true; } @@ -617,26 +617,26 @@ void SubtitleRenderer::draw_title(bool clear_needed) BOOST_NOEXCEPT { if (clear_needed) clear(); - // info line graybox + // title line graybox { BoxRenderer box_renderer(box_opacity_); - box_renderer.push(info_line_position_.first - config_.box_h_padding, - info_line_position_.second + config_.title_box_offset, - info_line_width_ + config_.title_box_h_padding*2, + box_renderer.push(title_line_position_.first - config_.box_h_padding, + title_line_position_.second + config_.title_box_offset, + title_line_width_ + config_.title_box_h_padding*2, config_.title_line_height); box_renderer.render(); } - //info line background + // title line background draw_text(vg_font_title_border_, - internal_info_line_, - info_line_position_.first, info_line_position_.second, + internal_title_line_, + title_line_position_.first, title_line_position_.second, 0); - //info line foreground + // title line foreground draw_text(vg_font_title_, - internal_info_line_, - info_line_position_.first, info_line_position_.second, + internal_title_line_, + title_line_position_.first, title_line_position_.second, white_level_); } diff --git a/SubtitleRenderer.h b/SubtitleRenderer.h index 66a39cde..e0b7126b 100644 --- a/SubtitleRenderer.h +++ b/SubtitleRenderer.h @@ -221,9 +221,9 @@ class SubtitleRenderer { std::vector> internal_lines_; std::vector> line_positions_; std::vector line_widths_; - std::vector internal_info_line_; - std::pair info_line_position_; - int info_line_width_; + std::vector internal_title_line_; + std::pair title_line_position_; + int title_line_width_; bool centered_; bool title_centered_; unsigned int white_level_; From c48adf59695cbcc310696c814a1bc05c75c19a71 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Tue, 2 Apr 2019 12:09:34 +0200 Subject: [PATCH 04/14] Add title related command line arguments --- README.md | 126 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index c0f6d5d9..9fbf66a9 100644 --- a/README.md +++ b/README.md @@ -51,67 +51,71 @@ Copy over `omxplayer-dist/*` to the Pi `/`. Usage: omxplayer [OPTIONS] [FILE] - -h --help Print this help - -v --version Print version info - -k --keys Print key bindings - -n --aidx index Audio stream index : e.g. 1 - -o --adev device Audio out device : e.g. hdmi/local/both/alsa[:device] - -i --info Dump stream format and exit - -I --with-info dump stream format before playback - -s --stats Pts and buffer stats - -p --passthrough Audio passthrough - -d --deinterlace Force deinterlacing - --nodeinterlace Force no deinterlacing - --nativedeinterlace let display handle interlace - --anaglyph type convert 3d to anaglyph - --advanced[=0] Enable/disable advanced deinterlace for HD videos (default enabled) - -w --hw Hw audio decoding - -3 --3d mode Switch tv into 3d mode (e.g. SBS/TB) - -M --allow-mvc Allow decoding of both views of MVC stereo stream - -y --hdmiclocksync Display refresh rate to match video (default) - -z --nohdmiclocksync Do not adjust display refresh rate to match video - -t --sid index Show subtitle with index - -r --refresh Adjust framerate/resolution to video - -g --genlog Generate log file - -l --pos n Start position (hh:mm:ss) - -b --blank[=0xAARRGGBB] Set the video background color to black (or optional ARGB value) - --loop Loop file. Ignored if file not seekable - --no-boost-on-downmix Don't boost volume when downmixing - --vol n set initial volume in millibels (default 0) - --amp n set initial amplification in millibels (default 0) - --no-osd Do not display status information on screen - --no-keys Disable keyboard input (prevents hangs for certain TTYs) - --subtitles path External subtitles in UTF-8 srt format - --font path Default: /usr/share/fonts/truetype/freefont/FreeSans.ttf - --italic-font path Default: /usr/share/fonts/truetype/freefont/FreeSansOblique.ttf - --font-size size Font size in 1/1000 screen height (default: 55) - --align left/center Subtitle alignment (default: left) - --no-ghost-box No semitransparent boxes behind subtitles - --lines n Number of lines in the subtitle buffer (default: 3) - --win 'x1 y1 x2 y2' Set position of video window - --win x1,y1,x2,y2 Set position of video window - --crop 'x1 y1 x2 y2' Set crop area for input video - --crop x1,y1,x2,y2 Set crop area for input video - --aspect-mode type Letterbox, fill, stretch. Default: stretch if win is specified, letterbox otherwise - --audio_fifo n Size of audio output fifo in seconds - --video_fifo n Size of video output fifo in MB - --audio_queue n Size of audio input queue in MB - --video_queue n Size of video input queue in MB - --threshold n Amount of buffered data required to finish buffering [s] - --timeout n Timeout for stalled file/network operations (default 10s) - --orientation n Set orientation of video (0, 90, 180 or 270) - --fps n Set fps of video where timestamps are not present - --live Set for live tv or vod type stream - --layout Set output speaker layout (e.g. 5.1) - --dbus_name name default: org.mpris.MediaPlayer2.omxplayer - --key-config Uses key bindings in instead of the default - --alpha Set video transparency (0..255) - --layer n Set video render layer number (higher numbers are on top) - --display n Set display to output to - --cookie 'cookie' Send specified cookie as part of HTTP requests - --user-agent 'ua' Send specified User-Agent as part of HTTP requests - --lavfdopts 'opts' Options passed to libavformat, e.g. 'probesize:250000,...' - --avdict 'opts' Options passed to demuxer, e.g., 'rtsp_transport:tcp,...' + -h --help Print this help + -v --version Print version info + -k --keys Print key bindings + -n --aidx index Audio stream index : e.g. 1 + -o --adev device Audio out device : e.g. hdmi/local/both/alsa[:device] + -i --info Dump stream format and exit + -I --with-info dump stream format before playback + -s --stats Pts and buffer stats + -p --passthrough Audio passthrough + -d --deinterlace Force deinterlacing + --nodeinterlace Force no deinterlacing + --nativedeinterlace let display handle interlace + --anaglyph type convert 3d to anaglyph + --advanced[=0] Enable/disable advanced deinterlace for HD videos (default enabled) + -w --hw Hw audio decoding + -3 --3d mode Switch tv into 3d mode (e.g. SBS/TB) + -M --allow-mvc Allow decoding of both views of MVC stereo stream + -y --hdmiclocksync Display refresh rate to match video (default) + -z --nohdmiclocksync Do not adjust display refresh rate to match video + -t --sid index Show subtitle with index + -r --refresh Adjust framerate/resolution to video + -g --genlog Generate log file + -l --pos n Start position (hh:mm:ss) + -b --blank[=0xAARRGGBB] Set the video background color to black (or optional ARGB value) + --loop Loop file. Ignored if file not seekable + --no-boost-on-downmix Don't boost volume when downmixing + --vol n set initial volume in millibels (default 0) + --amp n set initial amplification in millibels (default 0) + --no-osd Do not display status information on screen + --no-keys Disable keyboard input (prevents hangs for certain TTYs) + --subtitles path External subtitles in UTF-8 srt format + --font path Default: /usr/share/fonts/truetype/freefont/FreeSans.ttf + --italic-font path Default: /usr/share/fonts/truetype/freefont/FreeSansOblique.ttf + --title-font path Default: /usr/share/fonts/truetype/freefont/FreeSans.ttf + --font-size size Font size in 1/1000 screen height (default: 55) + --title-font-size size Title font size in 1/1000 screen height (default: 35) + --align left/center Subtitle alignment (default: left) + --title-align left/center Title alignment (default: left) + --title string Display static title string + --no-ghost-box No semitransparent boxes behind subtitles + --lines n Number of lines in the subtitle buffer (default: 3) + --win 'x1 y1 x2 y2' Set position of video window + --win x1,y1,x2,y2 Set position of video window + --crop 'x1 y1 x2 y2' Set crop area for input video + --crop x1,y1,x2,y2 Set crop area for input video + --aspect-mode type Letterbox, fill, stretch. Default: stretch if win is specified, letterbox otherwise + --audio_fifo n Size of audio output fifo in seconds + --video_fifo n Size of video output fifo in MB + --audio_queue n Size of audio input queue in MB + --video_queue n Size of video input queue in MB + --threshold n Amount of buffered data required to finish buffering [s] + --timeout n Timeout for stalled file/network operations (default 10s) + --orientation n Set orientation of video (0, 90, 180 or 270) + --fps n Set fps of video where timestamps are not present + --live Set for live tv or vod type stream + --layout Set output speaker layout (e.g. 5.1) + --dbus_name name default: org.mpris.MediaPlayer2.omxplayer + --key-config Uses key bindings in instead of the default + --alpha Set video transparency (0..255) + --layer n Set video render layer number (higher numbers are on top) + --display n Set display to output to + --cookie 'cookie' Send specified cookie as part of HTTP requests + --user-agent 'ua' Send specified User-Agent as part of HTTP requests + --lavfdopts 'opts' Options passed to libavformat, e.g. 'probesize:250000,...' + --avdict 'opts' Options passed to demuxer, e.g., 'rtsp_transport:tcp,...' For example: From fb26ecc2ef2d22d379f1dfead9a912b2c273ef30 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Tue, 2 Apr 2019 16:24:06 +0200 Subject: [PATCH 05/14] Add show elapsed time and video duration --- OMXPlayerSubtitles.cpp | 63 +++++++++++++++++++++++++++++-- OMXPlayerSubtitles.h | 5 ++- README.md | 3 +- SubtitleRenderer.cpp | 86 +++++++++++++++++++++++++++++++----------- SubtitleRenderer.h | 66 +++++++++++++++++++++----------- omxplayer.cpp | 12 ++++-- 6 files changed, 183 insertions(+), 52 deletions(-) diff --git a/OMXPlayerSubtitles.cpp b/OMXPlayerSubtitles.cpp index a64a5a41..a4552314 100644 --- a/OMXPlayerSubtitles.cpp +++ b/OMXPlayerSubtitles.cpp @@ -23,6 +23,7 @@ #include "utils/ScopeExit.h" #include "utils/Clamp.h" #include "utils/log.h" +#include "utils/Strprintf.h" #include #include @@ -68,7 +69,8 @@ bool OMXPlayerSubtitles::Open(size_t stream_count, unsigned int lines, int display, int layer, OMXClock* clock, - const string& title) BOOST_NOEXCEPT + const string& title, + bool show_time) BOOST_NOEXCEPT { assert(!m_open); @@ -94,11 +96,12 @@ bool OMXPlayerSubtitles::Open(size_t stream_count, m_display = display; m_layer = layer; m_title = title; + m_show_time = show_time; if(!Create()) return false; - SendToRenderer(Message::Flush{m_external_subtitles, m_title}); + SendToRenderer(Message::Flush{m_external_subtitles, m_title, m_show_time}); #ifndef NDEBUG m_open = true; @@ -190,12 +193,36 @@ RenderLoop(const string& font_path, bool osd{}; chrono::time_point osd_stop; int delay{}; + bool show_time{}; auto GetCurrentTime = [&] { return static_cast(clock->OMXMediaTime()/1000) - delay; }; + auto PrepareTime = [&] + { + extern OMXReader m_omx_reader; + auto t = (unsigned) (m_av_clock->OMXMediaTime()*1e-3); + auto dur = m_omx_reader.GetStreamLength() / 1000; + + std::string time_curr; + std::string time_total; + int hours = t/3600000; + if (hours) + time_curr = strprintf("%02d:%02d:%02d", hours, (t/60000)%60, (t/1000)%60); + else + time_curr = strprintf("%02d:%02d", (t/60000)%60, (t/1000)%60); + + hours = dur/3600; + if (hours) + time_total = strprintf("%02d:%02d:%02d", hours, (dur/60)%60, dur%60); + else + time_total = strprintf("%02d:%02d", (dur/60)%60, dur%60); + + renderer.prepare_time(time_curr + " / " + time_total); + }; + auto TryPrepare = [&](int time) { for(; next_index != subtitles.size(); ++next_index) @@ -230,6 +257,9 @@ RenderLoop(const string& font_path, } }; + auto show_time_offset = GetCurrentTime() % 1000; + chrono::time_point show_time_next_update; + for(;;) { int timeout = INT_MAX; @@ -246,7 +276,18 @@ RenderLoop(const string& font_path, have_next ? subtitles[next_index].start - now : INT_MAX; - timeout = min(min(till_stop, till_next_start), 1000); + int till_next_show_time = 1000; + if (show_time) + till_next_show_time = 1000 - (GetCurrentTime() % 1000) + show_time_offset; + + timeout = min(min(till_next_show_time, min(till_stop, till_next_start)), 1000); + } + + if(show_time) + { + procrustes(timeout, + chrono::duration_cast( + show_time_next_update - chrono::steady_clock::now()).count()); } if(osd) @@ -265,11 +306,12 @@ RenderLoop(const string& font_path, { subtitles = std::move(args.subtitles); title = std::move(args.title); + show_time = std::move(args.show_time); prev_now = INT_MAX; if (title != "") { renderer.prepare_title(title); - renderer.show_next(); + renderer.redraw(); } }, [&](Message::Touch&&) @@ -321,11 +363,20 @@ RenderLoop(const string& font_path, if(osd && chrono::steady_clock::now() >= osd_stop) osd = false; + bool redraw_needed = false; + + if (show_time && chrono::steady_clock::now() >= show_time_next_update) { + show_time_next_update = chrono::steady_clock::now() + chrono::seconds(1); + PrepareTime(); + redraw_needed = true; + } + if(!osd && current_stop <= now) { if(have_next && subtitles[next_index].start <= now) { renderer.show_next(); + redraw_needed = false; // printf("show error: %i ms\n", now - subtitles[next_index].start); showing = true; current_stop = subtitles[next_index].stop; @@ -337,10 +388,14 @@ RenderLoop(const string& font_path, else if(showing) { renderer.hide(); + redraw_needed = false; // printf("hide error: %i ms\n", now - current_stop); showing = false; } } + + if(redraw_needed) + renderer.redraw(); } } diff --git a/OMXPlayerSubtitles.h b/OMXPlayerSubtitles.h index e6c2f084..654bbf51 100644 --- a/OMXPlayerSubtitles.h +++ b/OMXPlayerSubtitles.h @@ -52,7 +52,8 @@ class OMXPlayerSubtitles : public OMXThread unsigned int lines, int display, int layer, OMXClock* clock, - const string& title) BOOST_NOEXCEPT; + const string& title, + bool show_time) BOOST_NOEXCEPT; void Close() BOOST_NOEXCEPT; void Flush() BOOST_NOEXCEPT; void Resume() BOOST_NOEXCEPT; @@ -104,6 +105,7 @@ class OMXPlayerSubtitles : public OMXThread { std::vector subtitles; std::string title; + bool show_time; }; struct Push { @@ -186,6 +188,7 @@ class OMXPlayerSubtitles : public OMXThread int m_display; int m_layer; std::string m_title; + bool m_show_time; #ifndef NDEBUG bool m_open; diff --git a/README.md b/README.md index 9fbf66a9..6705ae76 100644 --- a/README.md +++ b/README.md @@ -86,10 +86,11 @@ Usage: omxplayer [OPTIONS] [FILE] --italic-font path Default: /usr/share/fonts/truetype/freefont/FreeSansOblique.ttf --title-font path Default: /usr/share/fonts/truetype/freefont/FreeSans.ttf --font-size size Font size in 1/1000 screen height (default: 55) - --title-font-size size Title font size in 1/1000 screen height (default: 35) + --title-font-size size Title font size in 1/1000 screen height (default: 25) --align left/center Subtitle alignment (default: left) --title-align left/center Title alignment (default: left) --title string Display static title string + -T --show-time Show elapsed and total time --no-ghost-box No semitransparent boxes behind subtitles --lines n Number of lines in the subtitle buffer (default: 3) --win 'x1 y1 x2 y2' Set position of video window diff --git a/SubtitleRenderer.cpp b/SubtitleRenderer.cpp index 0bffdb30..9fa950a4 100644 --- a/SubtitleRenderer.cpp +++ b/SubtitleRenderer.cpp @@ -289,8 +289,9 @@ SubtitleRenderer(int display, int layer, unsigned int white_level, unsigned int box_opacity, unsigned int lines) -: prepared_(), +: show_subtitle_(), title_prepared_(), + time_prepared_(), dispman_element_(), dispman_display_(), display_(), @@ -305,6 +306,8 @@ SubtitleRenderer(int display, int layer, ft_face_italic_(), ft_face_title_(), ft_stroker_(), + prepared_lines_(), + prepared_lines_active_(), centered_(centered), title_centered_(title_centered), white_level_(white_level), @@ -563,10 +566,11 @@ void SubtitleRenderer:: prepare(const std::vector& text_lines) BOOST_NOEXCEPT { const int n_lines = text_lines.size(); TagTracker tag_tracker; + PreparedSubtitleLines& lines = prepared_lines_[!prepared_lines_active_]; - internal_lines_.resize(n_lines); - line_widths_.resize(n_lines); - line_positions_.resize(n_lines); + lines.internal_lines_.resize(n_lines); + lines.line_widths_.resize(n_lines); + lines.line_positions_.resize(n_lines); int title_line_height = config_.title_line_height; int title_line_padding = config_.title_line_padding; @@ -577,19 +581,32 @@ prepare(const std::vector& text_lines) BOOST_NOEXCEPT { } for (int i = 0; i < n_lines; ++i) { - internal_lines_[i] = get_internal_chars(text_lines[i], tag_tracker); - prepare_glyphs(internal_lines_[i], false); - line_widths_[i] = get_text_width(internal_lines_[i], false); - line_positions_[i].second = config_.margin_bottom + + lines.internal_lines_[i] = get_internal_chars(text_lines[i], tag_tracker); + prepare_glyphs(lines.internal_lines_[i], false); + lines.line_widths_[i] = get_text_width(lines.internal_lines_[i], false); + lines.line_positions_[i].second = config_.margin_bottom + title_line_height + title_line_padding + (n_lines-i-1)*config_.line_height; if (centered_) - line_positions_[i].first = config_.buffer_width/2 - line_widths_[i]/2; + lines.line_positions_[i].first = config_.buffer_width/2 - lines.line_widths_[i]/2; else - line_positions_[i].first = config_.margin_left; + lines.line_positions_[i].first = config_.margin_left; } - prepared_ = true; + lines.prepared_ = true; +} + +void SubtitleRenderer:: +prepare_time(const std::string& line) BOOST_NOEXCEPT { + TagTracker tag_tracker; + + internal_time_ = get_internal_chars(line, tag_tracker); + prepare_glyphs(internal_time_, true); + time_width_ = get_text_width(internal_time_, true); + time_position_.second = config_.margin_bottom; + time_position_.first = config_.buffer_width - time_width_ - config_.margin_left; + + time_prepared_ = true; } void SubtitleRenderer:: @@ -613,6 +630,33 @@ void SubtitleRenderer::clear() BOOST_NOEXCEPT { assert(!vgGetError()); } +void SubtitleRenderer::draw_time(bool clear_needed) BOOST_NOEXCEPT { + if (clear_needed) + clear(); + + // time graybox + { + BoxRenderer box_renderer(box_opacity_); + box_renderer.push(time_position_.first - config_.box_h_padding, + time_position_.second + config_.title_box_offset, + time_width_ + config_.title_box_h_padding*2, + config_.title_line_height); + box_renderer.render(); + } + + // time background + draw_text(vg_font_title_border_, + internal_time_, + time_position_.first, time_position_.second, + 0); + + // time foreground + draw_text(vg_font_title_, + internal_time_, + time_position_.first, time_position_.second, + white_level_); +} + void SubtitleRenderer::draw_title(bool clear_needed) BOOST_NOEXCEPT { if (clear_needed) clear(); @@ -641,18 +685,20 @@ void SubtitleRenderer::draw_title(bool clear_needed) BOOST_NOEXCEPT { } void SubtitleRenderer::draw(bool clear_needed) BOOST_NOEXCEPT { + PreparedSubtitleLines& lines = prepared_lines_[prepared_lines_active_]; + if (clear_needed) clear(); - const auto n_lines = internal_lines_.size(); + const auto n_lines = lines.internal_lines_.size(); // font graybox { BoxRenderer box_renderer(box_opacity_); for (size_t i = 0; i < n_lines; ++i) { - box_renderer.push(line_positions_[i].first - config_.box_h_padding, - line_positions_[i].second + config_.box_offset, - line_widths_[i] + config_.box_h_padding*2, + box_renderer.push(lines.line_positions_[i].first - config_.box_h_padding, + lines.line_positions_[i].second + config_.box_offset, + lines.line_widths_[i] + config_.box_h_padding*2, config_.line_height); } box_renderer.render(); @@ -661,20 +707,18 @@ void SubtitleRenderer::draw(bool clear_needed) BOOST_NOEXCEPT { //font background for (size_t i = 0; i < n_lines; ++i) { draw_text(vg_font_border_, - internal_lines_[i], - line_positions_[i].first, line_positions_[i].second, + lines.internal_lines_[i], + lines.line_positions_[i].first, lines.line_positions_[i].second, 0); } //font foreground for (size_t i = 0; i < n_lines; ++i) { draw_text(vg_font_, - internal_lines_[i], - line_positions_[i].first, line_positions_[i].second, + lines.internal_lines_[i], + lines.line_positions_[i].first, lines.line_positions_[i].second, white_level_); } - - prepared_ = false; } void SubtitleRenderer::swap_buffers() BOOST_NOEXCEPT { diff --git a/SubtitleRenderer.h b/SubtitleRenderer.h index e0b7126b..a60ae2f0 100644 --- a/SubtitleRenderer.h +++ b/SubtitleRenderer.h @@ -117,34 +117,45 @@ class SubtitleRenderer { ~SubtitleRenderer() BOOST_NOEXCEPT; void prepare(const std::vector& text_lines) BOOST_NOEXCEPT; + void prepare_time(const std::string& line) BOOST_NOEXCEPT; void prepare_title(const std::string& line) BOOST_NOEXCEPT; void unprepare() BOOST_NOEXCEPT { - prepared_ = false; + prepared_lines_[prepared_lines_active_].prepared_ = false; } - void show_next() BOOST_NOEXCEPT { - if (title_prepared_) - draw_title(1); - if (prepared_) { - // puts("Expensive show_next!"); - draw(!title_prepared_); + void redraw() BOOST_NOEXCEPT { + bool clear_needed = true; + + if (title_prepared_) { + draw_title(clear_needed); + clear_needed = false; } - swap_buffers(); - } - void hide() BOOST_NOEXCEPT { - if (title_prepared_) - draw_title(1); - else + if (time_prepared_) { + draw_time(clear_needed); + clear_needed = false; + } + + if (show_subtitle_) + draw(clear_needed); + else if (clear_needed) clear(); swap_buffers(); + } - if (title_prepared_) - draw_title(1); - if (prepared_) - draw(!title_prepared_); + void show_next() BOOST_NOEXCEPT { + prepared_lines_active_ = !prepared_lines_active_; + if (prepared_lines_[prepared_lines_active_].prepared_) + show_subtitle_ = true; + + redraw(); + } + + void hide() BOOST_NOEXCEPT { + show_subtitle_ = false; + redraw(); } void set_rect(int width, int height, int x, int y) BOOST_NOEXCEPT; @@ -155,7 +166,7 @@ class SubtitleRenderer { InternalChar(char32_t codepoint, bool italic) { val = codepoint | (static_cast(italic) << 31); } - + bool operator ==(const InternalChar& other) const { return val == other.val; } @@ -176,6 +187,13 @@ class SubtitleRenderer { int advance; }; + struct PreparedSubtitleLines { + std::vector> internal_lines_; + std::vector> line_positions_; + std::vector line_widths_; + bool prepared_; + }; + static void draw_text(VGFont font, const std::vector& text, int x, int y, @@ -191,6 +209,7 @@ class SubtitleRenderer { void initialize_window(int display, int layer); void destroy_window(); void clear() BOOST_NOEXCEPT; + void draw_time(bool clear_needed) BOOST_NOEXCEPT; void draw_title(bool clear_needed) BOOST_NOEXCEPT; void draw(bool clear_needed) BOOST_NOEXCEPT; void swap_buffers() BOOST_NOEXCEPT; @@ -200,8 +219,9 @@ class SubtitleRenderer { std::vector get_internal_chars(const std::string& str, TagTracker& tag_tracker); - bool prepared_; + bool show_subtitle_; bool title_prepared_; + bool time_prepared_; DISPMANX_ELEMENT_HANDLE_T dispman_element_; DISPMANX_DISPLAY_HANDLE_T dispman_display_; EGLDisplay display_; @@ -216,14 +236,16 @@ class SubtitleRenderer { FT_Face ft_face_italic_; FT_Face ft_face_title_; FT_Stroker ft_stroker_; + PreparedSubtitleLines prepared_lines_[2]; + int prepared_lines_active_; std::unordered_map glyphs_; std::unordered_map glyphs_title_; - std::vector> internal_lines_; - std::vector> line_positions_; - std::vector line_widths_; std::vector internal_title_line_; std::pair title_line_position_; int title_line_width_; + std::vector internal_time_; + std::pair time_position_; + int time_width_; bool centered_; bool title_centered_; unsigned int white_level_; diff --git a/omxplayer.cpp b/omxplayer.cpp index 0dff667e..672ddc3f 100644 --- a/omxplayer.cpp +++ b/omxplayer.cpp @@ -91,7 +91,7 @@ bool m_asked_for_font = false; bool m_asked_for_italic_font = false; float m_font_size = 0.055f; bool m_asked_for_title_font = false; -float m_title_font_size = 0.035f; +float m_title_font_size = 0.025f; bool m_centered = false; bool m_title_centered = false; bool m_ghost_box = true; @@ -119,6 +119,7 @@ bool m_has_subtitle = false; bool m_gen_log = false; bool m_loop = false; std::string m_title; +bool m_show_time = false; enum{ERROR=-1,SUCCESS,ONEBYTE}; @@ -613,6 +614,7 @@ int main(int argc, char *argv[]) { "title-font", required_argument, NULL, title_font_opt }, { "title-font-size", required_argument, NULL, title_font_size_opt }, { "title-align", required_argument, NULL, title_align_opt }, + { "show-time", no_argument, NULL, 'T' }, { "align", required_argument, NULL, align_opt }, { "no-ghost-box", no_argument, NULL, no_ghost_box_opt }, { "subtitles", required_argument, NULL, subtitles_opt }, @@ -659,7 +661,7 @@ int main(int argc, char *argv[]) //Build default keymap just in case the --key-config option isn't used map keymap = KeyConfig::buildDefaultKeymap(); - while ((c = getopt_long(argc, argv, "wiIhvkn:l:o:cslb::pd3:Myzt:rg", longopts, NULL)) != -1) + while ((c = getopt_long(argc, argv, "wiIhvkn:l:o:cslb::pd3:Myzt:rgT", longopts, NULL)) != -1) { switch (c) { @@ -772,6 +774,9 @@ int main(int argc, char *argv[]) m_loop_from = m_incr; } break; + case 'T': + m_show_time = true; + break; case no_osd_opt: m_osd = false; break; @@ -1160,7 +1165,8 @@ int main(int argc, char *argv[]) m_subtitle_lines, m_config_video.display, m_config_video.layer + 1, m_av_clock, - m_title)) + m_title, + m_show_time)) goto do_exit; if(m_config_video.dst_rect.x2 > 0 && m_config_video.dst_rect.y2 > 0) m_player_subtitles.SetSubtitleRect(m_config_video.dst_rect.x1, m_config_video.dst_rect.y1, m_config_video.dst_rect.x2, m_config_video.dst_rect.y2); From 9a07c5d7626768e19dd27fa8c616aea511dcea2b Mon Sep 17 00:00:00 2001 From: Nonoo Date: Tue, 2 Apr 2019 22:25:25 +0200 Subject: [PATCH 06/14] Also redraw displayed time on displaying OSD messages --- OMXPlayerSubtitles.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OMXPlayerSubtitles.cpp b/OMXPlayerSubtitles.cpp index a4552314..ecd7c7d9 100644 --- a/OMXPlayerSubtitles.cpp +++ b/OMXPlayerSubtitles.cpp @@ -333,6 +333,8 @@ RenderLoop(const string& font_path, [&](Message::DisplayText&& args) { renderer.prepare(args.text_lines); + if (show_time) + PrepareTime(); // Also regenerate displayed time. renderer.show_next(); showing = true; osd = true; From f53cabb893753a116c87d071d5d516f17a77c5a1 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Wed, 3 Apr 2019 10:37:01 +0200 Subject: [PATCH 07/14] Use messages to set title and show time --- OMXPlayerSubtitles.cpp | 29 ++++++++++++++++++----------- OMXPlayerSubtitles.h | 15 +++++++++++---- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/OMXPlayerSubtitles.cpp b/OMXPlayerSubtitles.cpp index ecd7c7d9..10c1655e 100644 --- a/OMXPlayerSubtitles.cpp +++ b/OMXPlayerSubtitles.cpp @@ -96,12 +96,13 @@ bool OMXPlayerSubtitles::Open(size_t stream_count, m_display = display; m_layer = layer; m_title = title; - m_show_time = show_time; if(!Create()) return false; - SendToRenderer(Message::Flush{m_external_subtitles, m_title, m_show_time}); + SendToRenderer(Message::Flush{m_external_subtitles}); + SendToRenderer(Message::SetTitle{m_title}); + SendToRenderer(Message::SetShowTime{show_time}); #ifndef NDEBUG m_open = true; @@ -181,7 +182,6 @@ RenderLoop(const string& font_path, lines); vector subtitles; - std::string title; int prev_now{}; size_t next_index{}; @@ -305,14 +305,7 @@ RenderLoop(const string& font_path, [&](Message::Flush&& args) { subtitles = std::move(args.subtitles); - title = std::move(args.title); - show_time = std::move(args.show_time); prev_now = INT_MAX; - - if (title != "") { - renderer.prepare_title(title); - renderer.redraw(); - } }, [&](Message::Touch&&) { @@ -345,6 +338,20 @@ RenderLoop(const string& font_path, [&](Message::SetRect&& args) { renderer.set_rect(args.x1, args.y1, args.x2, args.y2); + }, + [&](Message::SetTitle&& args) + { + renderer.prepare_title(args.title); + renderer.redraw(); + }, + [&](Message::SetShowTime&& args) + { + show_time = args.show; + if (show_time) + PrepareTime(); + else + renderer.prepare_time(""); + renderer.redraw(); }); if(exit) break; @@ -407,7 +414,7 @@ void OMXPlayerSubtitles::FlushRenderer() if(GetUseExternalSubtitles()) { - SendToRenderer(Message::Flush{m_external_subtitles, m_title}); + SendToRenderer(Message::Flush{m_external_subtitles}); } else { diff --git a/OMXPlayerSubtitles.h b/OMXPlayerSubtitles.h index 654bbf51..f41b6e01 100644 --- a/OMXPlayerSubtitles.h +++ b/OMXPlayerSubtitles.h @@ -104,8 +104,6 @@ class OMXPlayerSubtitles : public OMXThread struct Flush { std::vector subtitles; - std::string title; - bool show_time; }; struct Push { @@ -132,6 +130,14 @@ class OMXPlayerSubtitles : public OMXThread int x2; int y2; }; + struct SetTitle + { + std::string title; + }; + struct SetShowTime + { + bool show; + }; }; template @@ -169,7 +175,9 @@ class OMXPlayerSubtitles : public OMXThread Message::SetPaused, Message::SetDelay, Message::DisplayText, - Message::SetRect> m_mailbox; + Message::SetRect, + Message::SetTitle, + Message::SetShowTime> m_mailbox; bool m_visible; bool m_use_external_subtitles; size_t m_active_index; @@ -188,7 +196,6 @@ class OMXPlayerSubtitles : public OMXThread int m_display; int m_layer; std::string m_title; - bool m_show_time; #ifndef NDEBUG bool m_open; From 4b7f3c1867879e9dba54d357451385f002754205 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Wed, 3 Apr 2019 10:38:15 +0200 Subject: [PATCH 08/14] Unprepare if no title or time to be rendered --- SubtitleRenderer.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/SubtitleRenderer.cpp b/SubtitleRenderer.cpp index 9fa950a4..7a71ec0f 100644 --- a/SubtitleRenderer.cpp +++ b/SubtitleRenderer.cpp @@ -600,6 +600,11 @@ void SubtitleRenderer:: prepare_time(const std::string& line) BOOST_NOEXCEPT { TagTracker tag_tracker; + if (line == "") { + time_prepared_ = false; + return; + } + internal_time_ = get_internal_chars(line, tag_tracker); prepare_glyphs(internal_time_, true); time_width_ = get_text_width(internal_time_, true); @@ -613,6 +618,11 @@ void SubtitleRenderer:: prepare_title(const std::string& line) BOOST_NOEXCEPT { TagTracker tag_tracker; + if (line == "") { + title_prepared_ = false; + return; + } + internal_title_line_ = get_internal_chars(line, tag_tracker); prepare_glyphs(internal_title_line_, true); title_line_width_ = get_text_width(internal_title_line_, true); From b97fa5ab3320c8df364af4d54e60b96a4ea6676e Mon Sep 17 00:00:00 2001 From: Nonoo Date: Wed, 3 Apr 2019 11:05:29 +0200 Subject: [PATCH 09/14] Add key bindings to toggle/show/hide static title and time display --- KeyConfig.cpp | 18 ++++++++++++++++++ KeyConfig.h | 6 ++++++ OMXPlayerSubtitles.cpp | 34 ++++++++++++++++++++++++++++++++-- OMXPlayerSubtitles.h | 25 ++++++++++++++++++++++++- README.md | 6 ++++++ omxplayer.cpp | 31 +++++++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 3 deletions(-) diff --git a/KeyConfig.cpp b/KeyConfig.cpp index 2aadbd8f..dfd6e5a5 100644 --- a/KeyConfig.cpp +++ b/KeyConfig.cpp @@ -62,6 +62,18 @@ int convertStringToAction(string str_action) return KeyConfig::ACTION_SHOW_SUBTITLES; if(str_action == "HIDE_SUBTITLES") return KeyConfig::ACTION_HIDE_SUBTITLES; + if(str_action == "TOGGLE_TITLE") + return KeyConfig::ACTION_TOGGLE_TITLE; + if(str_action == "SHOW_TITLE") + return KeyConfig::ACTION_SHOW_TITLE; + if(str_action == "HIDE_TITLE") + return KeyConfig::ACTION_HIDE_TITLE; + if(str_action == "TOGGLE_TIME") + return KeyConfig::ACTION_TOGGLE_TIME; + if(str_action == "SHOW_TIME") + return KeyConfig::ACTION_SHOW_TIME; + if(str_action == "HIDE_TIME") + return KeyConfig::ACTION_HIDE_TIME; return -1; } @@ -128,6 +140,12 @@ map KeyConfig::buildDefaultKeymap() keymap['v'] = ACTION_STEP; keymap['w'] = ACTION_SHOW_SUBTITLES; keymap['x'] = ACTION_HIDE_SUBTITLES; + keymap['t'] = ACTION_TOGGLE_TITLE; + keymap['e'] = ACTION_SHOW_TITLE; + keymap['r'] = ACTION_HIDE_TITLE; + keymap['y'] = ACTION_TOGGLE_TIME; + keymap['g'] = ACTION_SHOW_TIME; + keymap['h'] = ACTION_HIDE_TIME; return keymap; } diff --git a/KeyConfig.h b/KeyConfig.h index e90a2ea6..38fc34e9 100644 --- a/KeyConfig.h +++ b/KeyConfig.h @@ -45,6 +45,12 @@ class KeyConfig ACTION_PLAY = 36, ACTION_CHANGE_FILE = 37, ACTION_SET_LAYER = 38, + ACTION_TOGGLE_TITLE = 39, + ACTION_HIDE_TITLE = 40, + ACTION_SHOW_TITLE = 41, + ACTION_TOGGLE_TIME = 42, + ACTION_HIDE_TIME = 43, + ACTION_SHOW_TIME = 44 }; #define KEY_LEFT 0x5b44 diff --git a/OMXPlayerSubtitles.cpp b/OMXPlayerSubtitles.cpp index 10c1655e..5b4131a2 100644 --- a/OMXPlayerSubtitles.cpp +++ b/OMXPlayerSubtitles.cpp @@ -96,13 +96,16 @@ bool OMXPlayerSubtitles::Open(size_t stream_count, m_display = display; m_layer = layer; m_title = title; + m_show_title = (title != ""); + m_show_time = show_time; if(!Create()) return false; SendToRenderer(Message::Flush{m_external_subtitles}); SendToRenderer(Message::SetTitle{m_title}); - SendToRenderer(Message::SetShowTime{show_time}); + SendToRenderer(Message::SetShowTitle{m_show_title}); + SendToRenderer(Message::SetShowTime{m_show_time}); #ifndef NDEBUG m_open = true; @@ -341,7 +344,20 @@ RenderLoop(const string& font_path, }, [&](Message::SetTitle&& args) { - renderer.prepare_title(args.title); + m_title = args.title; + if (m_show_title) + renderer.prepare_title(m_title); + else + renderer.prepare_title(""); + renderer.redraw(); + }, + [&](Message::SetShowTitle&& args) + { + m_show_title = args.show; + if (m_show_title) + renderer.prepare_title(m_title); + else + renderer.prepare_title(""); renderer.redraw(); }, [&](Message::SetShowTime&& args) @@ -494,6 +510,20 @@ void OMXPlayerSubtitles::SetVisible(bool visible) BOOST_NOEXCEPT } } +void OMXPlayerSubtitles::SetTitleVisible(bool visible) BOOST_NOEXCEPT +{ + assert(m_open); + + SendToRenderer(Message::SetShowTitle{visible}); +} + +void OMXPlayerSubtitles::SetTimeVisible(bool visible) BOOST_NOEXCEPT +{ + assert(m_open); + + SendToRenderer(Message::SetShowTime{visible}); +} + void OMXPlayerSubtitles::SetActiveStream(size_t index) BOOST_NOEXCEPT { assert(m_open); diff --git a/OMXPlayerSubtitles.h b/OMXPlayerSubtitles.h index f41b6e01..23109bd9 100644 --- a/OMXPlayerSubtitles.h +++ b/OMXPlayerSubtitles.h @@ -66,7 +66,23 @@ class OMXPlayerSubtitles : public OMXThread assert(m_open); return m_visible; } - + + void SetTitleVisible(bool visible) BOOST_NOEXCEPT; + + bool GetTitleVisible() BOOST_NOEXCEPT + { + assert(m_open); + return m_show_title; + } + + void SetTimeVisible(bool visible) BOOST_NOEXCEPT; + + bool GetTimeVisible() BOOST_NOEXCEPT + { + assert(m_open); + return m_show_time; + } + void SetActiveStream(size_t index) BOOST_NOEXCEPT; size_t GetActiveStream() BOOST_NOEXCEPT @@ -134,6 +150,10 @@ class OMXPlayerSubtitles : public OMXThread { std::string title; }; + struct SetShowTitle + { + bool show; + }; struct SetShowTime { bool show; @@ -177,6 +197,7 @@ class OMXPlayerSubtitles : public OMXThread Message::DisplayText, Message::SetRect, Message::SetTitle, + Message::SetShowTitle, Message::SetShowTime> m_mailbox; bool m_visible; bool m_use_external_subtitles; @@ -196,6 +217,8 @@ class OMXPlayerSubtitles : public OMXThread int m_display; int m_layer; std::string m_title; + bool m_show_title; + bool m_show_time; #ifndef NDEBUG bool m_open; diff --git a/README.md b/README.md index 6705ae76..99a0fc53 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,12 @@ Key bindings to control omxplayer while playing: x hide subtitles d decrease subtitle delay (- 250 ms) f increase subtitle delay (+ 250 ms) + t toggle static title display + e show static title + r hide static title + y toggle time display + g show time + h hide time q exit omxplayer p / space pause/resume - decrease volume diff --git a/omxplayer.cpp b/omxplayer.cpp index 672ddc3f..172bb688 100644 --- a/omxplayer.cpp +++ b/omxplayer.cpp @@ -119,6 +119,7 @@ bool m_has_subtitle = false; bool m_gen_log = false; bool m_loop = false; std::string m_title; +bool m_show_title = false; bool m_show_time = false; enum{ERROR=-1,SUCCESS,ONEBYTE}; @@ -1581,6 +1582,36 @@ int main(int argc, char *argv[]) m_Volume / 100.0f)); printf("Current Volume: %.2fdB\n", m_Volume / 100.0f); break; + case KeyConfig::ACTION_TOGGLE_TITLE: + if(m_title != "") + { + m_player_subtitles.SetTitleVisible(!m_player_subtitles.GetTitleVisible()); + } + break; + case KeyConfig::ACTION_HIDE_TITLE: + if(m_title != "") + { + m_player_subtitles.SetTitleVisible(false); + } + break; + case KeyConfig::ACTION_SHOW_TITLE: + if(m_title != "") + { + m_player_subtitles.SetTitleVisible(true); + } + break; + case KeyConfig::ACTION_TOGGLE_TIME: + m_show_time = !m_show_time; + m_player_subtitles.SetTimeVisible(m_show_time); + break; + case KeyConfig::ACTION_HIDE_TIME: + m_show_time = false; + m_player_subtitles.SetTimeVisible(m_show_time); + break; + case KeyConfig::ACTION_SHOW_TIME: + m_show_time = true; + m_player_subtitles.SetTimeVisible(m_show_time); + break; default: break; } From e017c43f17a22a3e91cf924d583e790e2900929c Mon Sep 17 00:00:00 2001 From: Nonoo Date: Wed, 3 Apr 2019 11:08:50 +0200 Subject: [PATCH 10/14] Apply subtitle displacement immediately during draw when title is visible --- SubtitleRenderer.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/SubtitleRenderer.cpp b/SubtitleRenderer.cpp index 7a71ec0f..6acf04c2 100644 --- a/SubtitleRenderer.cpp +++ b/SubtitleRenderer.cpp @@ -572,20 +572,11 @@ prepare(const std::vector& text_lines) BOOST_NOEXCEPT { lines.line_widths_.resize(n_lines); lines.line_positions_.resize(n_lines); - int title_line_height = config_.title_line_height; - int title_line_padding = config_.title_line_padding; - - if (!title_prepared_) { - title_line_height = 0; - title_line_padding = 0; - } - for (int i = 0; i < n_lines; ++i) { lines.internal_lines_[i] = get_internal_chars(text_lines[i], tag_tracker); prepare_glyphs(lines.internal_lines_[i], false); lines.line_widths_[i] = get_text_width(lines.internal_lines_[i], false); lines.line_positions_[i].second = config_.margin_bottom + - title_line_height + title_line_padding + (n_lines-i-1)*config_.line_height; if (centered_) lines.line_positions_[i].first = config_.buffer_width/2 - lines.line_widths_[i]/2; @@ -702,12 +693,21 @@ void SubtitleRenderer::draw(bool clear_needed) BOOST_NOEXCEPT { const auto n_lines = lines.internal_lines_.size(); + int title_line_height = config_.title_line_height; + int title_line_padding = config_.title_line_padding; + + if (!title_prepared_) { + title_line_height = 0; + title_line_padding = 0; + } + // font graybox { BoxRenderer box_renderer(box_opacity_); for (size_t i = 0; i < n_lines; ++i) { box_renderer.push(lines.line_positions_[i].first - config_.box_h_padding, - lines.line_positions_[i].second + config_.box_offset, + lines.line_positions_[i].second + config_.box_offset + + title_line_height + title_line_padding, lines.line_widths_[i] + config_.box_h_padding*2, config_.line_height); } @@ -718,7 +718,8 @@ void SubtitleRenderer::draw(bool clear_needed) BOOST_NOEXCEPT { for (size_t i = 0; i < n_lines; ++i) { draw_text(vg_font_border_, lines.internal_lines_[i], - lines.line_positions_[i].first, lines.line_positions_[i].second, + lines.line_positions_[i].first, lines.line_positions_[i].second + + title_line_height + title_line_padding, 0); } @@ -726,7 +727,8 @@ void SubtitleRenderer::draw(bool clear_needed) BOOST_NOEXCEPT { for (size_t i = 0; i < n_lines; ++i) { draw_text(vg_font_, lines.internal_lines_[i], - lines.line_positions_[i].first, lines.line_positions_[i].second, + lines.line_positions_[i].first, lines.line_positions_[i].second + + title_line_height + title_line_padding, white_level_); } } From 65d8cd24252115490213b3a334506192ad8e1b52 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Wed, 3 Apr 2019 11:13:44 +0200 Subject: [PATCH 11/14] Add missing key bindings --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 99a0fc53..79933048 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,8 @@ The list of valid [action]s roughly corresponds to the list of default key bindi PREVIOUS_SUBTITLE NEXT_SUBTITLE TOGGLE_SUBTITLE + SHOW_SUBTITLES + HIDE_SUBTITLES DECREASE_SUBTITLE_DELAY INCREASE_SUBTITLE_DELAY EXIT @@ -186,6 +188,12 @@ The list of valid [action]s roughly corresponds to the list of default key bindi SEEK_BACK_LARGE SEEK_FORWARD_LARGE STEP + TOGGLE_TITLE + SHOW_TITLE + HIDE_TITLE + TOGGLE_TIME + SHOW_TIME + HIDE_TIME Valid [key]s include all alpha-numeric characters and most symbols, as well as: From ebd40f453dc5bd82b388431b1861f979ee60d005 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Wed, 3 Apr 2019 11:38:39 +0200 Subject: [PATCH 12/14] Add D-BUS control commands for set/get/toggle/hide/show static title and time --- OMXControl.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++ OMXPlayerSubtitles.cpp | 7 ++++++ OMXPlayerSubtitles.h | 8 +++++++ README.md | 48 +++++++++++++++++++++++++++++++++++++++ dbuscontrol.sh | 35 +++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+) diff --git a/OMXControl.cpp b/OMXControl.cpp index 7345d8b2..b091923e 100644 --- a/OMXControl.cpp +++ b/OMXControl.cpp @@ -1125,6 +1125,57 @@ OMXControlResult OMXControl::handle_event(DBusMessage *m) dbus_respond_ok(m); return KeyConfig::ACTION_HIDE_SUBTITLES; } + else if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_PLAYER, "SetTitle")) + { + DBusError error; + dbus_error_init(&error); + + const char *title; + dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &title, DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&error)) + { + CLog::Log(LOGWARNING, "Set title D-Bus Error: %s", error.message ); + dbus_error_free(&error); + dbus_respond_ok(m); + return KeyConfig::ACTION_BLANK; + } + else + { + subtitles->SetTitle(title); + dbus_respond_string(m, title); + return KeyConfig::ACTION_BLANK; + } + } + else if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_PLAYER, "GetTitle")) + { + dbus_respond_string(m, subtitles->GetTitle().c_str()); + return KeyConfig::ACTION_BLANK; + } + else if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_PLAYER, "ShowTitle")) + { + subtitles->SetTitleVisible(true); + dbus_respond_ok(m); + return KeyConfig::ACTION_SHOW_TITLE; + } + else if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_PLAYER, "HideTitle")) + { + subtitles->SetTitleVisible(false); + dbus_respond_ok(m); + return KeyConfig::ACTION_HIDE_TITLE; + } + else if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_PLAYER, "ShowTime")) + { + subtitles->SetTimeVisible(true); + dbus_respond_ok(m); + return KeyConfig::ACTION_SHOW_TIME; + } + else if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_PLAYER, "HideTime")) + { + subtitles->SetTimeVisible(false); + dbus_respond_ok(m); + return KeyConfig::ACTION_HIDE_TIME; + } else if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_PLAYER, "OpenUri")) { DBusError error; diff --git a/OMXPlayerSubtitles.cpp b/OMXPlayerSubtitles.cpp index 5b4131a2..13363289 100644 --- a/OMXPlayerSubtitles.cpp +++ b/OMXPlayerSubtitles.cpp @@ -510,6 +510,13 @@ void OMXPlayerSubtitles::SetVisible(bool visible) BOOST_NOEXCEPT } } +void OMXPlayerSubtitles::SetTitle(std::string line) BOOST_NOEXCEPT +{ + assert(m_open); + + SendToRenderer(Message::SetTitle{line}); +} + void OMXPlayerSubtitles::SetTitleVisible(bool visible) BOOST_NOEXCEPT { assert(m_open); diff --git a/OMXPlayerSubtitles.h b/OMXPlayerSubtitles.h index 23109bd9..df7ca961 100644 --- a/OMXPlayerSubtitles.h +++ b/OMXPlayerSubtitles.h @@ -67,6 +67,14 @@ class OMXPlayerSubtitles : public OMXThread return m_visible; } + void SetTitle(std::string line) BOOST_NOEXCEPT; + + std::string GetTitle() BOOST_NOEXCEPT + { + assert(m_open); + return m_title; + } + void SetTitleVisible(bool visible) BOOST_NOEXCEPT; bool GetTitleVisible() BOOST_NOEXCEPT diff --git a/README.md b/README.md index 79933048..3b53ad80 100644 --- a/README.md +++ b/README.md @@ -515,6 +515,54 @@ Turns off subtitles. :-------------: | ------- Return | `null` +##### SetTitle (w) + +Sets the current static title. + + Params | Type | Description +:-------------: | --------- | -------------------------------- +1 | `string` | Static title to display. + +##### GetTitle (ro) + +The current static title. + + Params | Type +:-------------: | --------- + Return | `string` + +##### ShowTitle + +Turns on title display. + + Params | Type +:-------------: | ------- + Return | `null` + +##### HideTitle + +Turns off title display. + + Params | Type +:-------------: | ------- + Return | `null` + +##### ShowTime + +Turns on time display. + + Params | Type +:-------------: | ------- + Return | `null` + +##### HideTime + +Turns off time display. + + Params | Type +:-------------: | ------- + Return | `null` + ##### GetSource The current file or stream that is being played. diff --git a/dbuscontrol.sh b/dbuscontrol.sh index f88a5a8b..27ecbaad 100755 --- a/dbuscontrol.sh +++ b/dbuscontrol.sh @@ -104,6 +104,41 @@ hidesubtitles) showsubtitles) dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:31 >/dev/null ;; + +settitle) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetTitle string:"$2" >/dev/null + ;; + +gettitle) + title=$(dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.GetTitle) + [ $? -ne 0 ] && exit 1 + echo "$title" | sed 's/^ *//' + ;; + +toggletitle) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:39 >/dev/null + ;; + +hidetitle) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:40 >/dev/null + ;; + +showtitle) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:41 >/dev/null + ;; + +toggletime) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:42 >/dev/null + ;; + +hidetime) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:43 >/dev/null + ;; + +showtime) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:44 >/dev/null + ;; + getsource) source=$(dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.GetSource) [ $? -ne 0 ] && exit 1 From 9187d9046b942db4767efa8f065ecb7eaeed90b3 Mon Sep 17 00:00:00 2001 From: Nonoo Date: Wed, 3 Apr 2019 11:45:58 +0200 Subject: [PATCH 13/14] Fix D-BUS volume query --- dbuscontrol.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbuscontrol.sh b/dbuscontrol.sh index 27ecbaad..a0337617 100755 --- a/dbuscontrol.sh +++ b/dbuscontrol.sh @@ -35,7 +35,7 @@ openuri) ;; volume) - volume=`dbus-send --print-reply=double --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Set string:"org.mpris.MediaPlayer2.Player" string:"Volume" ${2:+double:}$2` + volume=`dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Set string:"org.mpris.MediaPlayer2.Player" string:"Volume" ${2:+double:}$2` [ $? -ne 0 ] && exit 1 volume="$(awk '{print $2}' <<< "$volume")" echo "Volume: $volume" From 3be784c9829eef775b1d305fcbfa33c4a331913a Mon Sep 17 00:00:00 2001 From: Nonoo Date: Wed, 3 Apr 2019 11:57:38 +0200 Subject: [PATCH 14/14] Fix D-BUS settitle command --- KeyConfig.cpp | 4 +++- KeyConfig.h | 3 ++- OMXControl.cpp | 3 +-- omxplayer.cpp | 4 ++++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/KeyConfig.cpp b/KeyConfig.cpp index dfd6e5a5..78faa075 100644 --- a/KeyConfig.cpp +++ b/KeyConfig.cpp @@ -74,7 +74,9 @@ int convertStringToAction(string str_action) return KeyConfig::ACTION_SHOW_TIME; if(str_action == "HIDE_TIME") return KeyConfig::ACTION_HIDE_TIME; - + if(str_action == "SET_TITLE") + return KeyConfig::ACTION_SET_TITLE; + return -1; } /* Grabs the substring prior to the ':', this is the Action */ diff --git a/KeyConfig.h b/KeyConfig.h index 38fc34e9..5e87a0a4 100644 --- a/KeyConfig.h +++ b/KeyConfig.h @@ -50,7 +50,8 @@ class KeyConfig ACTION_SHOW_TITLE = 41, ACTION_TOGGLE_TIME = 42, ACTION_HIDE_TIME = 43, - ACTION_SHOW_TIME = 44 + ACTION_SHOW_TIME = 44, + ACTION_SET_TITLE = 45 }; #define KEY_LEFT 0x5b44 diff --git a/OMXControl.cpp b/OMXControl.cpp index b091923e..fa224b2a 100644 --- a/OMXControl.cpp +++ b/OMXControl.cpp @@ -1142,9 +1142,8 @@ OMXControlResult OMXControl::handle_event(DBusMessage *m) } else { - subtitles->SetTitle(title); dbus_respond_string(m, title); - return KeyConfig::ACTION_BLANK; + return OMXControlResult(KeyConfig::ACTION_SET_TITLE, title); } } else if (dbus_message_is_method_call(m, OMXPLAYER_DBUS_INTERFACE_PLAYER, "GetTitle")) diff --git a/omxplayer.cpp b/omxplayer.cpp index 172bb688..8f8e9ff3 100644 --- a/omxplayer.cpp +++ b/omxplayer.cpp @@ -1582,6 +1582,10 @@ int main(int argc, char *argv[]) m_Volume / 100.0f)); printf("Current Volume: %.2fdB\n", m_Volume / 100.0f); break; + case KeyConfig::ACTION_SET_TITLE: + m_title = result.getWinArg(); + m_player_subtitles.SetTitle(m_title); + break; case KeyConfig::ACTION_TOGGLE_TITLE: if(m_title != "") {