subtitles: implemented very basic renderer

This commit is contained in:
itsmattkc
2022-05-08 14:45:43 -07:00
parent 197f94f8d6
commit bdb917c591
7 changed files with 146 additions and 4 deletions
+36
View File
@@ -79,4 +79,40 @@ QString QtUtils::GetFormattedDateTime(const QDateTime &dt)
return dt.toString(Qt::TextDate);
}
QStringList QtUtils::WordWrapString(const QString &s, const QFontMetrics &fm, int bounding_width)
{
QStringList list;
QStringList lines = s.split('\n');
// Iterate every line
for (int i=0; i<lines.size(); i++) {
QString this_line = lines.at(i);
while (this_line.size() > 1 && QFontMetricsWidth(fm, this_line) >= bounding_width) {
for (int j=this_line.size()-1; j>=0; j--) {
if (this_line.at(j).isSpace()) {
QString chopped = this_line.left(j);
if (QFontMetricsWidth(fm, chopped) < bounding_width) {
list.append(chopped);
int k = j+1;
while (k < this_line.size() && this_line.at(k).isSpace()) {
k++;
}
this_line.remove(0, k);
break;
}
}
}
}
if (!this_line.isEmpty()) {
list.append(this_line);
}
}
return list;
}
}
+2
View File
@@ -62,6 +62,8 @@ public:
static QString GetFormattedDateTime(const QDateTime &dt);
static QStringList WordWrapString(const QString &s, const QFontMetrics &fm, int bounding_width);
};
}
+9
View File
@@ -118,6 +118,15 @@ void Sequence::Retranslate()
}
}
void Sequence::InvalidateCache(const TimeRange &range, const QString &from, int element, InvalidateCacheOptions options)
{
if (from == kTrackInputFormat.arg(Track::kSubtitle)) {
emit SubtitlesChanged(range);
}
super::InvalidateCache(range, from, element, options);
}
rational Sequence::VerifyLengthInternal(Track::Type type) const
{
if (!track_lists_.isEmpty()) {
+4
View File
@@ -84,6 +84,8 @@ public:
virtual void Retranslate() override;
virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) override;
static const QString kTrackInputFormat;
virtual bool IsItem() const override
@@ -102,6 +104,8 @@ signals:
void TrackAdded(Track* track);
void TrackRemoved(Track* track);
void SubtitlesChanged(const TimeRange &range);
private:
QVector<TrackList*> track_lists_;
+8
View File
@@ -275,6 +275,7 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
void ViewerWidget::ConnectedNodeChangeEvent(ViewerOutput *n)
{
auto_cacher_.SetViewerNode(n);
display_widget_->SetSubtitleTracks(dynamic_cast<Sequence*>(n));
}
void ViewerWidget::ScaleChangedEvent(const double &s)
@@ -1189,6 +1190,13 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos)
connect(show_fps_action, &QAction::triggered, display_widget_, &ViewerDisplayWidget::SetShowFPS);
}
if (context_menu_widget_ == display_widget_) {
QAction* show_subtitles_action = menu.addAction(tr("Show Subtitles"));
show_subtitles_action->setCheckable(true);
show_subtitles_action->setChecked(display_widget_->GetShowSubtitles());
connect(show_subtitles_action, &QAction::triggered, display_widget_, &ViewerDisplayWidget::SetShowSubtitles);
}
menu.exec(static_cast<QWidget*>(sender())->mapToGlobal(pos));
}
+76 -3
View File
@@ -37,8 +37,10 @@
#include "common/define.h"
#include "common/functiontimer.h"
#include "common/html.h"
#include "common/qtutils.h"
#include "config/config.h"
#include "core.h"
#include "node/block/subtitle/subtitle.h"
#include "node/gizmo/path.h"
#include "node/gizmo/point.h"
#include "node/gizmo/polygon.h"
@@ -59,6 +61,8 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
gizmos_(nullptr),
current_gizmo_(nullptr),
gizmo_drag_started_(false),
show_subtitles_(true),
subtitle_tracks_(nullptr),
hand_dragging_(false),
deinterlace_(false),
show_fps_(false),
@@ -189,6 +193,21 @@ void ViewerDisplayWidget::SetTime(const rational &time)
}
}
void ViewerDisplayWidget::SetSubtitleTracks(Sequence *list)
{
if (subtitle_tracks_) {
disconnect(subtitle_tracks_, &Sequence::SubtitlesChanged, this, &ViewerDisplayWidget::SubtitlesChanged);
}
subtitle_tracks_ = list;
if (subtitle_tracks_) {
connect(subtitle_tracks_, &Sequence::SubtitlesChanged, this, &ViewerDisplayWidget::SubtitlesChanged);
}
update();
}
QPointF ViewerDisplayWidget::TransformViewerSpaceToBufferSpace(const QPointF &pos)
{
/*
@@ -582,6 +601,53 @@ void ViewerDisplayWidget::OnPaint()
}
}
}
// Extraordinarily basic subtitle renderer. Hoping to swap this out with libass at some point.
if (show_subtitles_ && subtitle_tracks_) {
const QVector<Track*> &subtitle_tracklist = subtitle_tracks_->track_list(Track::kSubtitle)->GetTracks();
if (!subtitle_tracklist.empty()) {
QPainter p(inner_widget());
QTransform transform = GenerateWorldTransform();
QRect bounding_box = transform.mapRect(rect());
bounding_box.adjust(bounding_box.width()/10, bounding_box.height()/10, -bounding_box.width()/10, -bounding_box.height()/10);
QFont f = p.font();
int font_sz = bounding_box.height() / 18;
f.setStyleHint(QFont::SansSerif);
f.setFamily(f.defaultFamily());
f.setPointSize(font_sz);
f.setWeight(QFont::Bold);
p.setFont(f);
p.setPen(Qt::white);
QPainterPath path;
int text_line = 1;
for (int j=subtitle_tracklist.size()-1; j>=0; j--) {
Track *sub_track = subtitle_tracklist.at(j);
if (!sub_track->IsMuted()) {
if (SubtitleBlock *sub = dynamic_cast<SubtitleBlock*>(sub_track->BlockAtTime(time_))) {
// Split into lines
QStringList list = QtUtils::WordWrapString(sub->GetText(), p.fontMetrics(), bounding_box.width());
for (int i=list.size()-1; i>=0; i--) {
int w = QtUtils::QFontMetricsWidth(p.fontMetrics(), list.at(i));
path.addText(bounding_box.x() + bounding_box.width()/2 - w/2, bounding_box.y() + bounding_box.height() - p.fontMetrics().height() * text_line + p.fontMetrics().ascent(), p.font(), list.at(i));
text_line++;
}
}
}
}
p.setPen(QPen(Qt::black, font_sz / 16));
p.setBrush(Qt::white);
p.drawPath(path);
}
}
}
void ViewerDisplayWidget::OnDestroy()
@@ -618,12 +684,12 @@ QPointF ViewerDisplayWidget::GetTexturePosition(const double &x, const double &y
y / gizmo_params_.height());
}
void ViewerDisplayWidget::DrawTextWithCrudeShadow(QPainter *painter, const QRect &rect, const QString &text)
void ViewerDisplayWidget::DrawTextWithCrudeShadow(QPainter *painter, const QRect &rect, const QString &text, const QTextOption &opt)
{
painter->setPen(Qt::black);
painter->drawText(rect.adjusted(1, 1, 0, 0), text);
painter->drawText(rect.adjusted(1, 1, 0, 0), text, opt);
painter->setPen(Qt::white);
painter->drawText(rect, text);
painter->drawText(rect, text, opt);
}
rational ViewerDisplayWidget::GetGizmoTime()
@@ -807,4 +873,11 @@ void ViewerDisplayWidget::TextEditChanged()
gizmo->UpdateInputHtml(html, GetGizmoTime());
}
void ViewerDisplayWidget::SubtitlesChanged(const TimeRange &r)
{
if (time_ >= r.in() && time_ < r.out()) {
update();
}
}
}
+11 -1
View File
@@ -26,6 +26,7 @@
#include "node/color/colormanager/colormanager.h"
#include "node/node.h"
#include "node/output/track/tracklist.h"
#include "render/color.h"
#include "tool/tool.h"
#include "viewerplaybacktimer.h"
@@ -72,6 +73,7 @@ public:
void SetGizmos(Node* node);
void SetVideoParams(const VideoParams &params);
void SetTime(const rational& time);
void SetSubtitleTracks(Sequence *list);
void SetShowWidgetBackground(bool e)
{
@@ -97,6 +99,9 @@ public:
return show_fps_;
}
bool GetShowSubtitles() const { return show_subtitles_; }
void SetShowSubtitles(bool e) { show_subtitles_ = e; update(); }
void IncrementSkippedFrames();
void IncrementFrameCount()
@@ -239,7 +244,7 @@ private:
QPointF GetTexturePosition(const QSize& size);
QPointF GetTexturePosition(const double& x, const double& y);
static void DrawTextWithCrudeShadow(QPainter* painter, const QRect& rect, const QString& text);
static void DrawTextWithCrudeShadow(QPainter* painter, const QRect& rect, const QString& text, const QTextOption &opt = QTextOption());
rational GetGizmoTime();
@@ -312,6 +317,9 @@ private:
NodeGizmo *current_gizmo_;
bool gizmo_drag_started_;
bool show_subtitles_;
Sequence *subtitle_tracks_;
rational time_;
/**
@@ -365,6 +373,8 @@ private slots:
void TextEditChanged();
void SubtitlesChanged(const TimeRange &r);
};
}