Skip to content

Commit 862d94a

Browse files
eysispeisipopcornmix
authored andcommitted
Subtitle scaling with video size (popcornmix#519)
Subtitle scaling with video size With this change subtitles and status texts are resized to scale and moved to follow video, when omxplayer is started with the --win option or is resized via dbus setvideopos command. Previous behavior was: when video was resized, subtitles stayed the same size, as if the video was still in fullscreen. This is particularly useful in windowed GUI omxplayer wrappers such as KenT2/tboplayer
1 parent 12b472e commit 862d94a

5 files changed

+128
-72
lines changed

OMXPlayerSubtitles.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ RenderLoop(const string& font_path,
275275
osd_stop = chrono::steady_clock::now() +
276276
chrono::milliseconds(args.duration);
277277
prev_now = INT_MAX;
278+
},
279+
[&](Message::SetRect&& args)
280+
{
281+
renderer.set_rect(args.x1, args.y1, args.x2, args.y2);
278282
});
279283

280284
if(exit) break;
@@ -492,3 +496,8 @@ void OMXPlayerSubtitles::DisplayText(const std::string& text, int duration) BOOS
492496
split(text_lines, text, is_any_of("\n"));
493497
SendToRenderer(Message::DisplayText{std::move(text_lines), duration});
494498
}
499+
500+
void OMXPlayerSubtitles::SetSubtitleRect(int x1, int y1, int x2, int y2) BOOST_NOEXCEPT
501+
{
502+
SendToRenderer(Message::SetRect{x1, y1, x2, y2});
503+
}

OMXPlayerSubtitles.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class OMXPlayerSubtitles : public OMXThread
9191

9292
bool AddPacket(OMXPacket *pkt, size_t stream_index) BOOST_NOEXCEPT;
9393

94+
void SetSubtitleRect(int x1, int y1, int x2, int y2) BOOST_NOEXCEPT;
95+
9496
private:
9597
struct Message {
9698
struct Stop {};
@@ -116,6 +118,13 @@ class OMXPlayerSubtitles : public OMXThread
116118
std::vector<std::string> text_lines;
117119
int duration;
118120
};
121+
struct SetRect
122+
{
123+
int x1;
124+
int y1;
125+
int x2;
126+
int y2;
127+
};
119128
};
120129

121130
template <typename T>
@@ -149,7 +158,8 @@ class OMXPlayerSubtitles : public OMXThread
149158
Message::Touch,
150159
Message::SetPaused,
151160
Message::SetDelay,
152-
Message::DisplayText> m_mailbox;
161+
Message::DisplayText,
162+
Message::SetRect> m_mailbox;
153163
bool m_visible;
154164
bool m_use_external_subtitles;
155165
size_t m_active_index;

SubtitleRenderer.cpp

+85-57
Original file line numberDiff line numberDiff line change
@@ -283,43 +283,35 @@ SubtitleRenderer(int display, int layer,
283283
ft_face_(),
284284
ft_face_italic_(),
285285
ft_stroker_(),
286-
line_height_(),
287-
box_offset_(),
288-
box_h_padding_(),
289-
margin_left_(),
290-
margin_bottom_(),
291-
buffer_width_(),
292-
buffer_height_(),
293286
centered_(centered),
294287
white_level_(white_level),
295-
box_opacity_(box_opacity)
288+
box_opacity_(box_opacity),
289+
font_size_(font_size)
296290
{
297291
try {
298-
uint32_t screen_width, screen_height;
299-
ENFORCE(graphics_get_display_size(display, &screen_width, &screen_height) >= 0);
300292

301-
initialize_fonts(font_path, italic_font_path, font_size*screen_height);
293+
ENFORCE(graphics_get_display_size(display, &screen_width_, &screen_height_) >= 0);
294+
initialize_fonts(font_path, italic_font_path);
302295

303296
int abs_margin_bottom =
304-
static_cast<int>(margin_bottom * screen_height + 0.5f) - box_offset_;
305-
306-
int buffer_padding = (line_height_+2)/4;
307-
int buffer_bottom = clamp(abs_margin_bottom + box_offset_ - buffer_padding,
308-
0, (int) screen_height-1);
309-
int buffer_top = clamp(buffer_bottom + line_height_ * (int) lines + buffer_padding*2,
310-
0, (int) screen_height-1);
311-
312-
buffer_width_ = screen_width;
313-
buffer_height_ = buffer_top - buffer_bottom + 1;
314-
margin_left_ = (screen_width - screen_height) / 2 +
315-
static_cast<int>(margin_left * screen_height + 0.5f);
316-
margin_bottom_ = abs_margin_bottom - buffer_bottom;
317-
318-
initialize_window(display, layer,
319-
0,
320-
screen_height - buffer_top - 1,
321-
screen_width,
322-
buffer_height_);
297+
static_cast<int>(margin_bottom * screen_height_ + 0.5f) - config_.box_offset;
298+
299+
int buffer_padding = (config_.line_height+2)/4;
300+
int buffer_bottom = clamp(abs_margin_bottom + config_.box_offset - buffer_padding,
301+
0, (int) screen_height_-1);
302+
int buffer_top = clamp(buffer_bottom + config_.line_height * (int) lines + buffer_padding*2,
303+
0, (int) screen_height_-1);
304+
305+
config_.buffer_x = 0;
306+
config_.buffer_y = screen_height_ - buffer_top - 1;
307+
config_.buffer_width = screen_width_;
308+
config_.buffer_height = buffer_top - buffer_bottom + 1;
309+
config_.margin_left = (screen_width_ - screen_height_) / 2 +
310+
static_cast<int>(margin_left * screen_height_ + 0.5f);
311+
config_.margin_bottom = abs_margin_bottom - buffer_bottom;
312+
config_fullscreen_ = config_; // save full-screen config for scaling reference.
313+
314+
initialize_window(display, layer);
323315

324316
initialize_vg();
325317
} catch (...) {
@@ -336,13 +328,13 @@ void SubtitleRenderer::destroy() {
336328

337329
void SubtitleRenderer::
338330
initialize_fonts(const std::string& font_path,
339-
const std::string& italic_font_path,
340-
unsigned int font_size) {
331+
const std::string& italic_font_path) {
341332
ENFORCE(!FT_Init_FreeType(&ft_library_));
342333
ENFORCE2(!FT_New_Face(ft_library_, font_path.c_str(), 0, &ft_face_),
343334
"Unable to open font");
344335
ENFORCE2(!FT_New_Face(ft_library_, italic_font_path.c_str(), 0, &ft_face_italic_),
345336
"Unable to open italic font");
337+
uint32_t font_size = font_size_*screen_height_;
346338
ENFORCE(!FT_Set_Pixel_Sizes(ft_face_, 0, font_size));
347339
ENFORCE(!FT_Set_Pixel_Sizes(ft_face_italic_, 0, font_size));
348340

@@ -361,17 +353,17 @@ initialize_fonts(const std::string& font_path,
361353
int y_min = get_bbox('g').yMin;
362354
int y_max = get_bbox('M').yMax;
363355
y_max += -y_min*0.7f;
364-
line_height_ = y_max - y_min;
365-
const int v_padding = line_height_*padding_factor + 0.5f;
366-
line_height_ += v_padding*2;
367-
box_offset_ = y_min-v_padding;
368-
box_h_padding_ = line_height_/5.0f + 0.5f;
356+
config_.line_height = y_max - y_min;
357+
const int v_padding = config_.line_height*padding_factor + 0.5f;
358+
config_.line_height += v_padding*2;
359+
config_.box_offset = y_min-v_padding;
360+
config_.box_h_padding = config_.line_height/5.0f + 0.5f;
369361

370362

371363
constexpr float border_thickness = 0.044f;
372364
ENFORCE(!FT_Stroker_New(ft_library_, &ft_stroker_));
373365
FT_Stroker_Set(ft_stroker_,
374-
line_height_*border_thickness*64.0f,
366+
config_.line_height*border_thickness*64.0f,
375367
FT_STROKER_LINECAP_ROUND,
376368
FT_STROKER_LINEJOIN_ROUND,
377369
0);
@@ -388,16 +380,12 @@ void SubtitleRenderer::destroy_fonts() {
388380
}
389381
}
390382

391-
void SubtitleRenderer::initialize_window(int display, int layer,
392-
unsigned int x,
393-
unsigned int y,
394-
unsigned int width,
395-
unsigned int height) {
383+
void SubtitleRenderer::initialize_window(int display, int layer) {
396384
VC_RECT_T dst_rect;
397-
dst_rect.x = x;
398-
dst_rect.y = y;
399-
dst_rect.width = width;
400-
dst_rect.height = height;
385+
dst_rect.x = config_.buffer_x;
386+
dst_rect.y = config_.buffer_y;
387+
dst_rect.width = config_.buffer_width;
388+
dst_rect.height = config_.buffer_height;
401389

402390
VC_RECT_T src_rect;
403391
src_rect.x = 0;
@@ -481,8 +469,8 @@ void SubtitleRenderer::initialize_vg() {
481469

482470
static EGL_DISPMANX_WINDOW_T nativewindow;
483471
nativewindow.element = dispman_element_;
484-
nativewindow.width = buffer_width_;
485-
nativewindow.height = buffer_height_;
472+
nativewindow.width = config_.buffer_width;
473+
nativewindow.height = config_.buffer_height;
486474

487475
surface_ = eglCreateWindowSurface(display_, config, &nativewindow, NULL);
488476
ENFORCE(surface_);
@@ -539,18 +527,18 @@ prepare(const std::vector<std::string>& text_lines) BOOST_NOEXCEPT {
539527
internal_lines_[i] = get_internal_chars(text_lines[i], tag_tracker);
540528
prepare_glyphs(internal_lines_[i]);
541529
line_widths_[i] = get_text_width(internal_lines_[i]);
542-
line_positions_[i].second = margin_bottom_ + (n_lines-i-1)*line_height_;
530+
line_positions_[i].second = config_.margin_bottom + (n_lines-i-1)*config_.line_height;
543531
if (centered_)
544-
line_positions_[i].first = buffer_width_/2 - line_widths_[i]/2;
532+
line_positions_[i].first = config_.buffer_width/2 - line_widths_[i]/2;
545533
else
546-
line_positions_[i].first = margin_left_;
534+
line_positions_[i].first = config_.margin_left;
547535
}
548536

549537
prepared_ = true;
550538
}
551539

552540
void SubtitleRenderer::clear() BOOST_NOEXCEPT {
553-
vgClear(0, 0, buffer_width_, buffer_height_);
541+
vgClear(0, 0, screen_width_, screen_height_);
554542
assert(!vgGetError());
555543
}
556544

@@ -559,24 +547,27 @@ void SubtitleRenderer::draw() BOOST_NOEXCEPT {
559547

560548
const auto n_lines = internal_lines_.size();
561549

550+
// font graybox
562551
{
563552
BoxRenderer box_renderer(box_opacity_);
564553
for (size_t i = 0; i < n_lines; ++i) {
565-
box_renderer.push(line_positions_[i].first - box_h_padding_,
566-
line_positions_[i].second + box_offset_,
567-
line_widths_[i] + box_h_padding_*2,
568-
line_height_);
554+
box_renderer.push(line_positions_[i].first - config_.box_h_padding,
555+
line_positions_[i].second + config_.box_offset,
556+
line_widths_[i] + config_.box_h_padding*2,
557+
config_.line_height);
569558
}
570559
box_renderer.render();
571560
}
572561

562+
//font background
573563
for (size_t i = 0; i < n_lines; ++i) {
574564
draw_text(vg_font_border_,
575565
internal_lines_[i],
576566
line_positions_[i].first, line_positions_[i].second,
577567
0);
578568
}
579569

570+
//font foreground
580571
for (size_t i = 0; i < n_lines; ++i) {
581572
draw_text(vg_font_,
582573
internal_lines_[i],
@@ -591,3 +582,40 @@ void SubtitleRenderer::swap_buffers() BOOST_NOEXCEPT {
591582
EGLBoolean result = eglSwapBuffers(display_, surface_);
592583
assert(result);
593584
}
585+
586+
void SubtitleRenderer::set_rect(int x1, int y1, int x2, int y2) BOOST_NOEXCEPT
587+
{
588+
uint32_t width = x2-x1;
589+
uint32_t height = y2-y1;
590+
float height_mod = (float) height / screen_height_;
591+
float width_mod = (float) width / screen_width_;
592+
config_.buffer_x = x1;
593+
config_.buffer_y = y2 - (screen_height_ - config_fullscreen_.buffer_y) * height_mod + 0.5f;
594+
config_.buffer_width = width;
595+
config_.buffer_height = config_fullscreen_.buffer_height * height_mod + 0.5f;
596+
config_.line_height = config_fullscreen_.line_height * height_mod + 0.5f;
597+
config_.box_offset = config_fullscreen_.box_offset * height_mod + 0.5f;
598+
config_.box_h_padding = config_fullscreen_.box_h_padding * height_mod + 0.5f;
599+
config_.margin_left = config_fullscreen_.margin_left * width_mod + 0.5f;
600+
config_.margin_bottom = config_fullscreen_.margin_bottom * height_mod + 0.5f;
601+
602+
// resize dispmanx element
603+
ENFORCE(dispman_element_);
604+
VC_RECT_T dst_rect;
605+
vc_dispmanx_rect_set(&dst_rect, config_.buffer_x, config_.buffer_y, config_.buffer_width, config_.buffer_height);
606+
VC_RECT_T src_rect;
607+
vc_dispmanx_rect_set(&src_rect, x1, y1, config_.buffer_width<<16, config_.buffer_height<<16);
608+
DISPMANX_UPDATE_HANDLE_T dispman_update;
609+
dispman_update = vc_dispmanx_update_start(0);
610+
ENFORCE(dispman_update);
611+
uint32_t change_flag = 1<<2 | 1<<3; // change only dst_rect and src_rect
612+
ENFORCE(!vc_dispmanx_element_change_attributes(dispman_update, dispman_element_, change_flag, 0, 0,
613+
&dst_rect, &src_rect, 0, (DISPMANX_TRANSFORM_T) 0));
614+
ENFORCE(!vc_dispmanx_update_submit_sync(dispman_update));
615+
616+
// resize font
617+
glyphs_.clear(); // clear cached glyphs
618+
float font_size = height*font_size_;
619+
ENFORCE(!FT_Set_Pixel_Sizes(ft_face_, 0, font_size));
620+
ENFORCE(!FT_Set_Pixel_Sizes(ft_face_italic_, 0, font_size));
621+
}

SubtitleRenderer.h

+21-14
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ class TagTracker {
8181
bool closing_;
8282
};
8383

84+
typedef struct {
85+
int buffer_width;
86+
int buffer_height;
87+
int buffer_y;
88+
int buffer_x;
89+
int line_height;
90+
int box_offset;
91+
int box_h_padding;
92+
int margin_left;
93+
int margin_bottom;
94+
} SubtitleConfig;
95+
8496
class SubtitleRenderer {
8597
public:
8698
SubtitleRenderer(const SubtitleRenderer&) = delete;
@@ -118,6 +130,8 @@ class SubtitleRenderer {
118130
draw();
119131
}
120132

133+
void set_rect(int width, int height, int x, int y) BOOST_NOEXCEPT;
134+
121135
private:
122136
struct InternalChar {
123137
InternalChar() = default;
@@ -152,16 +166,11 @@ class SubtitleRenderer {
152166

153167
void destroy();
154168
void initialize_fonts(const std::string& font_name,
155-
const std::string& italic_font_path,
156-
unsigned int font_size);
169+
const std::string& italic_font_path);
157170
void destroy_fonts();
158171
void initialize_vg();
159172
void destroy_vg();
160-
void initialize_window(int display, int layer,
161-
unsigned int x,
162-
unsigned int y,
163-
unsigned int width,
164-
unsigned int height);
173+
void initialize_window(int display, int layer);
165174
void destroy_window();
166175
void clear() BOOST_NOEXCEPT;
167176
void draw() BOOST_NOEXCEPT;
@@ -188,14 +197,12 @@ class SubtitleRenderer {
188197
std::vector<std::vector<InternalChar>> internal_lines_;
189198
std::vector<std::pair<int,int>> line_positions_;
190199
std::vector<int> line_widths_;
191-
int line_height_;
192-
int box_offset_;
193-
int box_h_padding_;
194-
int margin_left_;
195-
int margin_bottom_;
196-
int buffer_width_;
197-
int buffer_height_;
198200
bool centered_;
199201
unsigned int white_level_;
200202
unsigned int box_opacity_;
203+
uint32_t screen_width_;
204+
uint32_t screen_height_;
205+
float font_size_;
206+
SubtitleConfig config_fullscreen_;
207+
SubtitleConfig config_;
201208
};

omxplayer.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,7 @@ int main(int argc, char *argv[])
11201120
m_config_video.display, m_config_video.layer + 1,
11211121
m_av_clock))
11221122
goto do_exit;
1123+
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);
11231124
}
11241125

11251126
if(m_has_subtitle)
@@ -1478,6 +1479,7 @@ int main(int argc, char *argv[])
14781479
case KeyConfig::ACTION_MOVE_VIDEO:
14791480
sscanf(result.getWinArg(), "%f %f %f %f", &m_config_video.dst_rect.x1, &m_config_video.dst_rect.y1, &m_config_video.dst_rect.x2, &m_config_video.dst_rect.y2);
14801481
m_player_video.SetVideoRect(m_config_video.src_rect, m_config_video.dst_rect);
1482+
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);
14811483
break;
14821484
case KeyConfig::ACTION_CROP_VIDEO:
14831485
sscanf(result.getWinArg(), "%f %f %f %f", &m_config_video.src_rect.x1, &m_config_video.src_rect.y1, &m_config_video.src_rect.x2, &m_config_video.src_rect.y2);

0 commit comments

Comments
 (0)