Skip to content

Commit

Permalink
subtitle: get bounding rect in getImage
Browse files Browse the repository at this point in the history
  • Loading branch information
wang-bin committed Sep 30, 2014
1 parent 2c4783e commit c6c873e
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 46 deletions.
10 changes: 9 additions & 1 deletion src/QtAV/Subtitle.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,15 @@ class Q_AV_EXPORT Subtitle : public QObject
// call setTimestamp before getText/Image
//plain text. separated by '\n' if more more than 1 text rects found
Q_INVOKABLE QString getText() const;
Q_INVOKABLE QImage getImage(int width, int height);
/*!
* \brief getImage
* Get a subtitle image with given (video) frame size. The result image size usually smaller than
* given frame size because subtitle are lines of text. The boundingRect indicates the actual
* image position and size relative to given size.
* The result image format is QImage::Format_ARGB32
* \return empty image if no image, or subtitle processor does not support renderering
*/
Q_INVOKABLE QImage getImage(int width, int height, QRect* boundingRect = 0);
// used for embedded subtitles.
// used by libass to set style etc.
bool processHeader(const QByteArray& data);
Expand Down
11 changes: 10 additions & 1 deletion src/QtAV/private/SubtitleProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ FACTORY_DECLARE(SubtitleProcessor)
class Q_AV_PRIVATE_EXPORT SubtitleProcessor
{
public:
SubtitleProcessor();
virtual ~SubtitleProcessor() {}
virtual SubtitleProcessorId id() const = 0;
virtual QString name() const = 0;
Expand Down Expand Up @@ -73,7 +74,15 @@ class Q_AV_PRIVATE_EXPORT SubtitleProcessor
// return timestamp, insert it to Subtitle's internal linkedlist. can be invalid if only support renderering
virtual SubtitleFrame processLine(const QByteArray& data, qreal pts = -1, qreal duration = 0) = 0;
virtual QString getText(qreal pts) const = 0;
virtual QImage getImage(qreal pts, int width, int height) = 0;
// default null image
virtual QImage getImage(qreal pts, QRect* boundingRect = 0);
void setFrameSize(int width, int height);
QSize frameSize() const;
protected:
// default do nothing
virtual void onFrameSizeChanged(int width, int height);
private:
int m_width, m_height;
};

} //namespace QtAV
Expand Down
19 changes: 12 additions & 7 deletions src/subtitle/Subtitle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Subtitle::Private {
bool loaded;
bool fuzzy_match;
bool update_text;
bool update_image;
bool update_image; //TODO: detect image change from engine
SubtitleProcessor *processor;
QList<SubtitleProcessor*> processors;
QByteArray codec;
Expand Down Expand Up @@ -119,7 +119,7 @@ Subtitle::Subtitle(QObject *parent) :
, priv(new Private())
{
// TODO: use factory.registedNames() and the order
setEngines(QStringList() << "FFmpeg" << "LibASS");
setEngines(QStringList() << "LibASS" << "FFmpeg");
}

Subtitle::~Subtitle()
Expand Down Expand Up @@ -278,6 +278,7 @@ QStringList Subtitle::suffixes() const

void Subtitle::setTimestamp(qreal t)
{
// TODO: detect image change?
{
QMutexLocker lock(&priv->mutex);
Q_UNUSED(lock);
Expand Down Expand Up @@ -380,24 +381,28 @@ QString Subtitle::getText() const
return priv->current_text;
}

QImage Subtitle::getImage(int width, int height)
QImage Subtitle::getImage(int width, int height, QRect* boundingRect)
{
QMutexLocker lock(&priv->mutex);
Q_UNUSED(lock);
if (!isLoaded())
return QImage();
if (!priv->current_count || width == 0 || height == 0)
if (width == 0 || height == 0)
return QImage();
// always render the image to support animations
#if 0
if (!priv->current_count) //seems ok to use this code
return QImage();
// always render the image to support animations
if (!priv->update_image
&& width == priv->current_image.width() && height == priv->current_image.height())
return priv->current_image;
#endif
priv->update_image = false;
if (!priv->processor)
if (!canRender())
return QImage();
priv->current_image = priv->processor->getImage(priv->t, width, height);
priv->processor->setFrameSize(width, height);
// TODO: store bounding rect here and not in processor
priv->current_image = priv->processor->getImage(priv->t, boundingRect);
return priv->current_image;
}

Expand Down
32 changes: 32 additions & 0 deletions src/subtitle/SubtitleProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ namespace QtAV {

FACTORY_DEFINE(SubtitleProcessor)

SubtitleProcessor::SubtitleProcessor()
: m_width(0)
, m_height(0)
{}

bool SubtitleProcessor::process(const QString &path)
{
QFile f(path);
Expand All @@ -41,4 +46,31 @@ bool SubtitleProcessor::process(const QString &path)
return ok;
}

QImage SubtitleProcessor::getImage(qreal pts, QRect *boundingRect)
{
Q_UNUSED(pts)
Q_UNUSED(boundingRect)
return QImage();
}

void SubtitleProcessor::setFrameSize(int width, int height)
{
if (width == m_width && height == m_height)
return;
m_width = width;
m_height = height;
onFrameSizeChanged(m_width, m_height);
}

QSize SubtitleProcessor::frameSize() const
{
return QSize(m_width, m_height);
}

void SubtitleProcessor::onFrameSizeChanged(int width, int height)
{
Q_UNUSED(width);
Q_UNUSED(height);
}

} //namespace QtAV
21 changes: 0 additions & 21 deletions src/subtitle/SubtitleProcessorFFmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

#include <string>
#include <QtDebug>
#include <QtGui/QPainter>
#include "QtAV/private/SubtitleProcessor.h"
#include "QtAV/prepost.h"
#include "QtAV/AVDemuxer.h"
Expand All @@ -45,13 +44,11 @@ class SubtitleProcessorFFmpeg : public SubtitleProcessor
virtual QList<SubtitleFrame> frames() const;
virtual SubtitleFrame processLine(const QByteArray& data, qreal pts = -1, qreal duration = 0);
virtual QString getText(qreal pts) const;
virtual QImage getImage(qreal pts, int width, int height);
private:
bool processSubtitle();
AVCodecContext *codec_ctx;
AVDemuxer m_reader;
QList<SubtitleFrame> m_frames;
QFont m_font;
};

static const SubtitleProcessorId SubtitleProcessorId_FFmpeg = "qtav.subtitle.processor.ffmpeg";
Expand All @@ -68,8 +65,6 @@ void RegisterSubtitleProcessorFFmpeg_Man()
SubtitleProcessorFFmpeg::SubtitleProcessorFFmpeg()
: codec_ctx(0)
{
m_font.setBold(true);
m_font.setPixelSize(24);
}

SubtitleProcessorId SubtitleProcessorFFmpeg::id() const
Expand Down Expand Up @@ -147,22 +142,6 @@ QString SubtitleProcessorFFmpeg::getText(qreal pts) const
return text.trimmed();
}

QImage SubtitleProcessorFFmpeg::getImage(qreal pts, int width, int height)
{
QString text = getText(pts);
if (text.isEmpty())
return QImage();
QImage img(width, height, QImage::Format_ARGB32);
img.fill(Qt::transparent);
QPainter p(&img);
p.setPen(QColor(Qt::white));
p.setFont(m_font);
const int flags = Qt::AlignHCenter | Qt::AlignBottom | Qt::TextWordWrap;
//QRect box = fm.boundingRect(0, 0, width, height, flags, text);
p.drawText(0, 0, width, height, flags, text);
return img;
}

SubtitleFrame SubtitleProcessorFFmpeg::processLine(const QByteArray &data, qreal pts, qreal duration)
{
// AV_CODEC_ID_xxx and srt, subrip are available for ffmpeg >= 1.0. AV_CODEC_ID_xxx
Expand Down
35 changes: 21 additions & 14 deletions src/subtitle/SubtitleProcessorLibASS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ extern "C" {
#include <ass/ass.h>
}
#include <QtDebug>
#include <QtGui/QPainter>
#include "QtAV/private/SubtitleProcessor.h"
#include "QtAV/prepost.h"
#include "QtAV/Packet.h"
Expand All @@ -45,10 +44,13 @@ class SubtitleProcessorLibASS : public SubtitleProcessor
// supportsFromFile must be true
virtual bool process(const QString& path);
virtual QList<SubtitleFrame> frames() const;
virtual bool canRender() const { return true;}
virtual QString getText(qreal pts) const;
virtual QImage getImage(qreal pts, int width, int height);
virtual QImage getImage(qreal pts, QRect *boundingRect = 0);
virtual bool processHeader(const QByteArray& data);
virtual SubtitleFrame processLine(const QByteArray& data, qreal pts = -1, qreal duration = 0);
protected:
virtual void onFrameSizeChanged(int width, int height);
private:
// render 1 ass image into a 32bit QImage with alpha channel.
//use dstX, dstY instead of img->dst_x/y because image size is small then ass renderer size
Expand All @@ -57,10 +59,10 @@ class SubtitleProcessorLibASS : public SubtitleProcessor
ASS_Library *m_ass;
ASS_Renderer *m_renderer;
ASS_Track *m_track;
// video frame width, height
int m_width, m_height;
QList<SubtitleFrame> m_frames;
QImage m_image; //cache the image for the last invocation. return this if image does not change
//cache the image for the last invocation. return this if image does not change
QImage m_image;
QRect m_bound;
};

static const SubtitleProcessorId SubtitleProcessorId_LibASS = "qtav.subtitle.processor.libass";
Expand Down Expand Up @@ -88,8 +90,6 @@ SubtitleProcessorLibASS::SubtitleProcessorLibASS()
: m_ass(0)
, m_renderer(0)
, m_track(0)
, m_width(0)
, m_height(0)
{
m_ass = ass_library_init();
if (!m_ass) {
Expand Down Expand Up @@ -214,7 +214,7 @@ QString SubtitleProcessorLibASS::getText(qreal pts) const
return text.trimmed();
}

QImage SubtitleProcessorLibASS::getImage(qreal pts, int width, int height)
QImage SubtitleProcessorLibASS::getImage(qreal pts, QRect *boundingRect)
{
if (!m_ass) {
qWarning("ass library not available");
Expand All @@ -228,15 +228,11 @@ QImage SubtitleProcessorLibASS::getImage(qreal pts, int width, int height)
qWarning("ass track not available");
return QImage();
}
if (width != m_width || height != m_height) {
m_width = width;
m_height = height;
qDebug("ass_set_frame_size %dx%d", width, height);
ass_set_frame_size(m_renderer, width, height);
}
int detect_change = 0;
ASS_Image *img = ass_render_frame(m_renderer, m_track, (long long)(pts * 1000.0), &detect_change);
if (!detect_change) {
if (boundingRect)
*boundingRect = m_bound;
return m_image;
}
QRect rect(0, 0, 0, 0);
Expand All @@ -245,6 +241,10 @@ QImage SubtitleProcessorLibASS::getImage(qreal pts, int width, int height)
rect |= QRect(i->dst_x, i->dst_y, i->w, i->h);
i = i->next;
}
m_bound = rect;
if (boundingRect) {
*boundingRect = m_bound;
}
QImage image(rect.size(), QImage::Format_ARGB32);
image.fill(Qt::transparent);
i = img;
Expand All @@ -260,6 +260,13 @@ QImage SubtitleProcessorLibASS::getImage(qreal pts, int width, int height)
return image;
}

void SubtitleProcessorLibASS::onFrameSizeChanged(int width, int height)
{
if (!m_renderer)
return;
ass_set_frame_size(m_renderer, width, height);
}

void SubtitleProcessorLibASS::processTrack(ASS_Track *track)
{
// language, track type
Expand Down
4 changes: 2 additions & 2 deletions tests/subtitle/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include <QGuiApplication>
#include <QApplication>
#include <QtCore/QElapsedTimer>
#include <QtCore/QStringList>
#include <QtDebug>
Expand All @@ -22,7 +22,7 @@ private slots:

int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QApplication a(argc, argv);
qDebug() << "help: ./subtitle [-engine engine] [-f file] [-fuzzy] [-t sec] [-t1 sec] [-count n]";
qDebug() << "-fuzzy: fuzzy match subtitle name";
qDebug() << "-t: set subtitle begin time";
Expand Down

0 comments on commit c6c873e

Please sign in to comment.