From ed1ff780adc388f444d66d7ec63ca7b3caef522a Mon Sep 17 00:00:00 2001 From: wang-bin Date: Sat, 11 May 2013 13:48:43 +0800 Subject: [PATCH] use internal context if context type is wrong or no context TODO: filters need to manager their contexts, which sometimes are shared by multiple filters. so shall we use smart ptr, like RefCount? --- src/AVThread.cpp | 12 ++++------ src/Filter.cpp | 32 ++++++++++++++++++++++--- src/FilterContext.cpp | 48 +++++++++++++++++++++++++++++++++++++ src/OSDFilter.cpp | 22 +++++------------ src/QtAV/Filter.h | 15 ++++++------ src/QtAV/FilterContext.h | 18 +++++++++++++- src/QtAV/OSDFilter.h | 6 +++-- src/QtAV/private/Filter_p.h | 3 +++ src/VideoThread.cpp | 6 +++-- 9 files changed, 123 insertions(+), 39 deletions(-) diff --git a/src/AVThread.cpp b/src/AVThread.cpp index 488d6f26..8c727325 100644 --- a/src/AVThread.cpp +++ b/src/AVThread.cpp @@ -37,10 +37,8 @@ AVThreadPrivate::~AVThreadPrivate() { } packets.setBlocking(true); //??? packets.clear(); - if (filter_context) { - delete filter_context; //TODO: need it? - filter_context = 0; - } + //not neccesary context is managed by filters. + filter_context = 0; qDeleteAll(filters); //TODO: is it safe? filters.clear(); } @@ -147,10 +145,8 @@ void AVThread::resetState() d.demux_end = false; d.packets.setBlocking(true); d.packets.clear(); - if (d.filter_context) { - delete d.filter_context; - d.filter_context = 0; - } + //not neccesary context is managed by filters. + d.filter_context = 0; } bool AVThread::tryPause() diff --git a/src/Filter.cpp b/src/Filter.cpp index 7ea06f23..efffa4bf 100644 --- a/src/Filter.cpp +++ b/src/Filter.cpp @@ -21,6 +21,7 @@ #include "QtAV/Filter.h" #include "private/Filter_p.h" +#include "QtAV/Statistics.h" namespace QtAV { @@ -34,10 +35,35 @@ Filter::~Filter() { } -void Filter::process(FilterContext *context, Statistics *statistics) +void Filter::process(FilterContext *&context, Statistics *statistics, QByteArray* data) { - Q_UNUSED(context); - Q_UNUSED(statistics); + DPTR_D(Filter); + if(context) + context->type(); + if (!context || context->type() != contextType()) { + if (context) { + qDebug("incompatible context type"); + //we don't delete it because the context MUST be used by other filters + //TODO: How to release them at the end? refcount? + } else { + qDebug("null context"); + } + //use internal context + if (d.context) { + qDebug("replace context with internal one"); + context = d.context; + } else { + context = FilterContext::create(contextType()); + qDebug("new filter context=%p, type=%d", context, contextType()); + context->video_width = statistics->video_only.width; + context->video_height = statistics->video_only.height; + } + } + if (data) + context->initializeOnData(data); + d.context = context; + d.statistics = statistics; + process(); } void Filter::setEnabled(bool enabled) diff --git a/src/FilterContext.cpp b/src/FilterContext.cpp index e74de949..3221c2e6 100644 --- a/src/FilterContext.cpp +++ b/src/FilterContext.cpp @@ -20,6 +20,8 @@ ******************************************************************************/ #include "QtAV/FilterContext.h" +#include +#include namespace QtAV { @@ -36,10 +38,21 @@ FilterContext* FilterContext::create(Type t) return ctx; } +FilterContext::FilterContext(): + video_width(0) + , video_height(0) +{ +} + FilterContext::~FilterContext() { } +void FilterContext::initializeOnData(QByteArray *data) +{ + Q_UNUSED(data); + qDebug("%s", __PRETTY_FUNCTION__); +} VideoFilterContext::VideoFilterContext(): rect(32, 32, 0, 0) @@ -48,8 +61,23 @@ VideoFilterContext::VideoFilterContext(): QPainterFilterContext::QPainterFilterContext(): painter(0) + , paint_device(0) { +} +QPainterFilterContext::~QPainterFilterContext() +{ + if (paint_device) { + if (painter) { //painter may assigned by vo + painter->end(); + qDebug("delete painter"); + delete painter; + painter = 0; + } + qDebug("delete paint device"); + delete paint_device; + paint_device = 0; + } } FilterContext::Type QPainterFilterContext::type() const @@ -57,5 +85,25 @@ FilterContext::Type QPainterFilterContext::type() const return FilterContext::QtPainter; } +void QPainterFilterContext::initializeOnData(QByteArray *data) +{ + Q_ASSERT(video_width > 0 && video_height > 0); + if (!data) + return; + if (data->isEmpty()) + return; + if (paint_device) { + if (painter) { + painter->end(); //destroy a paint device that is being painted is not allowed! + } + delete paint_device; + paint_device = 0; + } + paint_device = new QImage((uchar*)data->data(), video_width, video_height, QImage::Format_RGB32); + if (!painter) + painter = new QPainter(); + painter->begin((QImage*)paint_device); +} + } //namespace QtAV diff --git a/src/OSDFilter.cpp b/src/OSDFilter.cpp index 8b4d808c..b0263d96 100644 --- a/src/OSDFilter.cpp +++ b/src/OSDFilter.cpp @@ -43,25 +43,15 @@ OSDFilterImpl::OSDFilterImpl(): } template<> -void OSDFilterQPainter::process(FilterContext *context, Statistics *statistics) +void OSDFilterQPainter::process() { if (mShowType == ShowNone) return; - if (!context || context->type() != contextType()) { - if (context && context->type() != contextType()) { - qDebug("incompatible context type"); - delete context; - context = 0; - } else { - qDebug("null context"); - } - context = FilterContext::create(FilterContext::QtPainter); - QPainterFilterContext* ctx = static_cast(context); - ctx->painter = new QPainter(); - } - QPainterFilterContext* ctx = static_cast(context); + DPTR_D(Filter); + QPainterFilterContext* ctx = static_cast(d.context); + //qDebug("ctx=%p tid=%p main tid=%p", ctx, QThread::currentThread(), qApp->thread()); if (!ctx->painter) { - //qWarning("null QPainter in OSDFilterQPainter!"); + qWarning("null QPainter in OSDFilterQPainter!"); return; } if (!ctx->painter->isActive()) { @@ -72,7 +62,7 @@ void OSDFilterQPainter::process(FilterContext *context, Statistics *statistics) p->save(); //TODO: move outside? p->setFont(mFont); p->setPen(Qt::white); - p->drawText(ctx->rect.topLeft(), text(statistics)); + p->drawText(ctx->rect.topLeft(), text(d.statistics)); p->restore(); //TODO: move outside? } /* diff --git a/src/QtAV/Filter.h b/src/QtAV/Filter.h index d555d648..ee33c925 100644 --- a/src/QtAV/Filter.h +++ b/src/QtAV/Filter.h @@ -40,12 +40,8 @@ class Q_EXPORT Filter { DPTR_DECLARE_PRIVATE(Filter) public: - virtual ~Filter() = 0; + virtual ~Filter(); //isEnabled() then setContext - /*! - * if context is null, or contextType() != context->type(), then create a right one and assign it to context. - */ - virtual void process(FilterContext *context, Statistics* statistics); //TODO: parameter FrameContext void setEnabled(bool enabled); //AVComponent.enabled bool isEnabled() const; @@ -55,14 +51,19 @@ public: virtual FilterContext::Type contextType() const; + /*! + * check context and apply the filter + * if context is null, or contextType() != context->type(), then create a right one and assign it to context. + */ + void process(FilterContext *&context, Statistics* statistics, QByteArray* data = 0); + protected: /* * If the filter is in AVThread, it's safe to operate on ref. */ Filter(FilterPrivate& d); + virtual void process() = 0; - friend class AVThread; - friend class VideoThread; DPTR_DECLARE(Filter) }; diff --git a/src/QtAV/FilterContext.h b/src/QtAV/FilterContext.h index 233d2b38..d054dc6b 100644 --- a/src/QtAV/FilterContext.h +++ b/src/QtAV/FilterContext.h @@ -30,6 +30,7 @@ */ class QPainter; +class QPaintDevice; namespace QtAV { class FilterContext; @@ -46,10 +47,16 @@ public: None }; static FilterContext* create(Type t); + + FilterContext(); virtual ~FilterContext(); virtual Type type() const = 0; - QByteArray data; //TODO: initialize() on data + //TODO: how to move them to VideoFilterContext? + int video_width, video_height; //original size //QPainter, paintdevice, surface etc. contains all of them here? +protected: + virtual void initializeOnData(QByteArray *data); //private? + friend class Filter; }; class Q_EXPORT VideoFilterContext : public FilterContext @@ -64,8 +71,17 @@ class Q_EXPORT QPainterFilterContext : public VideoFilterContext { public: QPainterFilterContext(); + virtual ~QPainterFilterContext(); + QPainter *painter; + /* + * for the filters apply on decoded data, paint_device must be initialized once the data changes + * can we allocate memory on stack? + */ + QPaintDevice *paint_device; virtual Type type() const; //QtPainter +protected: + virtual void initializeOnData(QByteArray* data); }; diff --git a/src/QtAV/OSDFilter.h b/src/QtAV/OSDFilter.h index ecc6c199..c087d968 100644 --- a/src/QtAV/OSDFilter.h +++ b/src/QtAV/OSDFilter.h @@ -31,21 +31,23 @@ class OSDFilterPrivate; //TODO: not template. OSDFilter : public Filter, public OSD class OSDFilter : public Filter, public OSD { - DPTR_DECLARE_PRIVATE(OSDFilter) protected: + DPTR_DECLARE_PRIVATE(OSDFilter) OSDFilter(OSDFilterPrivate& d); }; template class OSDFilterImpl : public OSDFilter { + //DPTR_DECLARE_PRIVATE(OSDFilterImpl) public: OSDFilterImpl(); ~OSDFilterImpl() {} - virtual void process(FilterContext *context, Statistics* statistics); FilterContext::Type contextType() const { return (FilterContext::Type)TypeTrait::type; } +protected: + virtual void process(); }; typedef OSDFilterImpl OSDFilterQPainter; diff --git a/src/QtAV/private/Filter_p.h b/src/QtAV/private/Filter_p.h index ec15a7a5..f8b0ef40 100644 --- a/src/QtAV/private/Filter_p.h +++ b/src/QtAV/private/Filter_p.h @@ -28,18 +28,21 @@ namespace QtAV { class Filter; class FilterContext; +class Statistics; class FilterPrivate : public DPtrPrivate { public: FilterPrivate(): enabled(true) , context(0) + , statistics(0) , opacity(1) {} virtual ~FilterPrivate() {} bool enabled; FilterContext *context; //used only when is necessary + Statistics *statistics; qreal opacity; }; diff --git a/src/VideoThread.cpp b/src/VideoThread.cpp index 0e6e10a2..3b5e2c8c 100644 --- a/src/VideoThread.cpp +++ b/src/VideoThread.cpp @@ -162,8 +162,10 @@ void VideoThread::run() QByteArray data = dec->data(); if (d.statistics) { d.statistics->video.current_time = QTime().addMSecs(int(pkt.pts * 1000.0)); //TODO: is it expensive? - foreach (Filter *filter, d.filters) { - filter->process(d.filter_context, d.statistics); + if (!d.filters.isEmpty()) { + foreach (Filter *filter, d.filters) { + filter->process(d.filter_context, d.statistics, &data); + } } }