1 /******************************************************************************
2     QtAV:  Media play library based on Qt and FFmpeg
3     Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
4 
5 *   This file is part of QtAV
6 
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License as published by the Free Software Foundation; either
10     version 2.1 of the License, or (at your option) any later version.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.
16 
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 ******************************************************************************/
21 
22 #ifndef QAV_VIDEORENDERER_H
23 #define QAV_VIDEORENDERER_H
24 
25 #include <QtCore/QByteArray>
26 #include <QtCore/QSize>
27 #include <QtCore/QRectF>
28 #include <QtGui/QColor>
29 #include <QtAV/AVOutput.h>
30 #include <QtAV/VideoFrame.h>
31 
32 /*!
33  * A bridge for VideoOutput(QObject based) and video renderer backend classes
34  * Every public setter call it's virtual onSetXXX(...) which has default behavior.
35  * While VideoOutput.onSetXXX(...) simply calls backend's setXXX(...) and return whether the result is desired.
36  */
37 QT_BEGIN_NAMESPACE
38 class QWidget;
39 class QWindow;
40 class QGraphicsItem;
41 QT_END_NAMESPACE
42 
43 namespace QtAV {
44 
45 typedef int VideoRendererId;
46 extern Q_AV_EXPORT VideoRendererId VideoRendererId_OpenGLWindow;
47 class Filter;
48 class OpenGLVideo;
49 class VideoFormat;
50 class VideoRendererPrivate;
51 class Q_AV_EXPORT VideoRenderer : public AVOutput
52 {
53     DPTR_DECLARE_PRIVATE(VideoRenderer)
54 public:
55     //TODO: original video size mode
56     // fillmode: keepsize
57     enum OutAspectRatioMode {
58         RendererAspectRatio //Use renderer's aspect ratio, i.e. stretch to fit the renderer rect
59       , VideoAspectRatio    //Use video's aspect ratio and align center in renderer.
60       , CustomAspectRation  //Use the ratio set by setOutAspectRatio(qreal). Mode will be set to this if that function is called
61       //, AspectRatio4_3, AspectRatio16_9
62     };
63     enum Quality { //TODO: deprecated. simpily use int 0~100
64         QualityDefault, //good
65         QualityBest,
66         QualityFastest
67     };
68 
69     template<class C>
Register(VideoRendererId id,const char * name)70     static bool Register(VideoRendererId id, const char* name) { return Register(id, create<C>, name);}
71     static VideoRenderer* create(VideoRendererId id);
72     static VideoRenderer* create(const char* name);
73     /*!
74      * \brief next
75      * \param id NULL to get the first id address
76      * \return address of id or NULL if not found/end
77      */
78     static VideoRendererId* next(VideoRendererId* id = 0);
79     static const char* name(VideoRendererId id);
80     static VideoRendererId id(const char* name);
81 
82     VideoRenderer();
83     virtual ~VideoRenderer();
84     virtual VideoRendererId id() const = 0;
85 
86     bool receive(const VideoFrame& frame);
87     /*!
88      * \brief setPreferredPixelFormat
89      * \param pixfmt
90      *  pixfmt will be used if decoded format is not supported by this renderer. otherwise, use decoded format.
91      *  return false if \a pixfmt is not supported and not changed.
92      */
93     bool setPreferredPixelFormat(VideoFormat::PixelFormat pixfmt);
94     /*!
95      * \brief preferredPixelFormat
96      * \return preferred pixel format. e.g. WidgetRenderer is rgb formats.
97      */
98     virtual VideoFormat::PixelFormat preferredPixelFormat() const; //virtual?
99     /*!
100      * \brief forcePreferredPixelFormat
101      *  force to use preferredPixelFormat() even if incoming format is supported
102      * \param force
103      */
104     void forcePreferredPixelFormat(bool force = true);
105     bool isPreferredPixelFormatForced() const;
106     virtual bool isSupported(VideoFormat::PixelFormat pixfmt) const = 0;
107 
108     /*!
109      * \brief sourceAspectRatio
110      * The display aspect ratio of received video frame. 0 for an invalid frame.
111      * sourceAspectRatioChanged() (a signal for QObject renderers) will be called if the new frame has a different DAR.
112      */
113     qreal sourceAspectRatio() const;
114 
115     void setOutAspectRatioMode(OutAspectRatioMode mode);
116     OutAspectRatioMode outAspectRatioMode() const;
117     //If setOutAspectRatio(qreal) is used, then OutAspectRatioMode is CustomAspectRation
118     void setOutAspectRatio(qreal ratio);
119     qreal outAspectRatio() const;//
120 
121     void setQuality(Quality q);
122     Quality quality() const;
123 
124     void resizeRenderer(const QSize& size);
125     void resizeRenderer(int width, int height);
126     QSize rendererSize() const;
127     int rendererWidth() const;
128     int rendererHeight() const;
129     //geometry size of current video frame. can not use frameSize because qwidget use it
130     QSize videoFrameSize() const;
131 
132     /*!
133      * \brief orientation
134      * 0, 90, 180, 270. other values are ignored
135      * outAspectRatio() corresponds with orientation == 0. displayed aspect ratio may change if orientation is not 0
136      */
137     int orientation() const;
138     void setOrientation(int value);
139 
140     //The video frame rect in renderer you shoud paint to. e.g. in RendererAspectRatio mode, the rect equals to renderer's
141     QRect videoRect() const;
142     /*
143      * region of interest, ROI
144      * invalid rect means the whole source rect
145      * null rect is the whole available source rect. e.g. (0, 0, 0, 0) equals whole source rect
146      * (20, 30, 0, 0) equals (20, 30, sourceWidth - 20, sourceHeight - 30)
147      * if |x|<1, |y|<1, |width|<1, |height|<1 means the ratio of source rect(normalized value)
148      * |width| == 1 or |height| == 1 is a normalized value iff x or y is normalized
149      * call realROI() to get the frame rect actually to be render
150      * TODO: nagtive width or height means invert direction. is nagtive necessary?
151      */
152     QRectF regionOfInterest() const;
153     // TODO: reset aspect ratio to roi.width/roi/heghit
154     void setRegionOfInterest(qreal x, qreal y, qreal width, qreal height);
155     void setRegionOfInterest(const QRectF& roi);
156     // compute the real ROI
157     QRect realROI() const;
158     // |w| <= 1, |x| < 1
159     QRectF normalizedROI() const;
160 
161     // TODO: map normalized
162     /*!
163      * \brief mapToFrame
164      *  map point in VideoRenderer coordinate to VideoFrame, with current ROI
165      */
166     QPointF mapToFrame(const QPointF& p) const;
167     /*!
168      * \brief mapFromFrame
169      *  map point in VideoFrame coordinate to VideoRenderer, with current ROI
170      */
171     QPointF mapFromFrame(const QPointF& p) const;
172     // to avoid conflicting width QWidget::window()
qwindow()173     virtual QWindow* qwindow() { return 0;}
174     /*!
175      * \brief widget
176      * \return default is 0. A QWidget subclass can return \a this
177      */
widget()178     virtual QWidget* widget() { return 0; }
179     /*!
180      * \brief graphicsItem
181      * \return default is 0. A QGraphicsItem subclass can return \a this
182      */
graphicsItem()183     virtual QGraphicsItem* graphicsItem() { return 0; }
184     /*!
185      * \brief brightness, contrast, hue, saturation
186      *  values range between -1.0 and 1.0, the default is 0.
187      *  value is not changed if does not implementd and onChangingXXX() returns false.
188      *  video widget/item will update after if onChangingXXX/setXXX returns true
189      * \return \a false if failed to set (may be onChangingXXX not implemented or return false)
190      */
191     qreal brightness() const;
192     bool setBrightness(qreal brightness);
193     qreal contrast() const;
194     bool setContrast(qreal contrast);
195     qreal hue() const;
196     bool setHue(qreal hue);
197     qreal saturation() const;
198     bool setSaturation(qreal saturation);
199     QColor backgroundColor() const;
200     void setBackgroundColor(const QColor& c);
201 
202     /*!
203      * \brief opengl
204      * Currently you can only use it to set custom shader OpenGLVideo.setUserShader()
205      */
opengl()206     virtual OpenGLVideo* opengl() const { return NULL;}
207 protected:
208     VideoRenderer(VideoRendererPrivate &d);
209     //TODO: batch drawBackground(color, region)=>loop drawBackground(color,rect)
210     virtual bool receiveFrame(const VideoFrame& frame) = 0;
211     QRegion backgroundRegion() const;
212     virtual void drawBackground();
213     //draw the current frame using the current paint engine. called by paintEvent()
214     // TODO: parameter VideoFrame
215     virtual void drawFrame() = 0; //You MUST reimplement this to display a frame. Other draw functions are not essential
216     virtual void handlePaintEvent(); //has default. User don't have to implement it
217     virtual void updateUi(); // by default post an UpdateRequest event for window and UpdateLater event for widget to ensure ui update
218 
219 private: // property change. used as signals in subclasses. implemented by moc
sourceAspectRatioChanged(qreal)220     virtual void sourceAspectRatioChanged(qreal) {}
outAspectRatioChanged()221     virtual void outAspectRatioChanged() {}
outAspectRatioModeChanged()222     virtual void outAspectRatioModeChanged() {}
orientationChanged()223     virtual void orientationChanged() {}
videoRectChanged()224     virtual void videoRectChanged() {}
contentRectChanged()225     virtual void contentRectChanged() {}
regionOfInterestChanged()226     virtual void regionOfInterestChanged() {}
videoFrameSizeChanged()227     virtual void videoFrameSizeChanged() {}
rendererSizeChanged()228     virtual void rendererSizeChanged() {}
brightnessChanged(qreal)229     virtual void brightnessChanged(qreal) {}
contrastChanged(qreal)230     virtual void contrastChanged(qreal) {}
hueChanged(qreal)231     virtual void hueChanged(qreal) {}
saturationChanged(qreal)232     virtual void saturationChanged(qreal) {}
backgroundColorChanged()233     virtual void backgroundColorChanged() {}
234 private: // mainly used by VideoOutput class
235     /*!
236      * return false if value not changed. default is true
237      */
238     virtual bool onSetPreferredPixelFormat(VideoFormat::PixelFormat pixfmt);
239     virtual bool onForcePreferredPixelFormat(bool force = true);
240     virtual void onSetOutAspectRatioMode(OutAspectRatioMode mode);
241     virtual void onSetOutAspectRatio(qreal ratio);
242     virtual bool onSetQuality(Quality q);
243     virtual void onResizeRenderer(int width, int height);
244     virtual bool onSetOrientation(int value);
245     virtual bool onSetRegionOfInterest(const QRectF& roi);
246     virtual QPointF onMapToFrame(const QPointF& p) const;
247     virtual QPointF onMapFromFrame(const QPointF& p) const;
248     /*!
249      * \brief onSetXX
250      *  It's called when user call setXXX() with a new value. You should implement how to actually change the value, e.g. change brightness with shader.
251      * \return
252      *  false: It's default. means not implemented. \a brightness() does not change.
253      *  true: Implement this and return true. \a brightness() will change to new value
254      */
255     virtual bool onSetBrightness(qreal brightness);
256     virtual bool onSetContrast(qreal contrast);
257     virtual bool onSetHue(qreal hue);
258     virtual bool onSetSaturation(qreal saturation);
259     virtual void onSetBackgroundColor(const QColor& color);
260 private:
261     template<class C>
create()262     static VideoRenderer* create() {
263         return new C();
264     }
265     typedef VideoRenderer* (*VideoRendererCreator)();
266     static bool Register(VideoRendererId id, VideoRendererCreator, const char *name);
267     friend class VideoOutput;
268     //the size of decoded frame. get called in receiveFrame(). internal use only
269     void setInSize(const QSize& s);
270     void setInSize(int width, int height);
271 };
272 
273 } //namespace QtAV
274 #endif // QAV_VIDEORENDERER_H
275