~registry/stellarium/socis2015-de430

« back to all changes in this revision

Viewing changes to src/core/StelVideoMgr.hpp

  • Committer: georg-zotti
  • Date: 2015-12-14 13:02:24 UTC
  • mfrom: (7721.1.367 trunk)
  • Revision ID: georg.zotti@univie.ac.at-20151214130224-g5sqnc31ghcmw0ux
merge-in trunk r8088

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2012 Sibi Antony
 
2
 * Copyright (C) 2012 Sibi Antony (Phonon/QT4 implementation)
 
3
 * Copyright (C) 2015 Georg Zotti (Reactivated with QT5 classes)
3
4
 *
4
5
 * This program is free software; you can redistribute it and/or
5
6
 * modify it under the terms of the GNU General Public License
22
23
#include <QObject>
23
24
#include <QMap>
24
25
#include <QString>
25
 
 
26
 
class StelVideoMgr : public QObject
 
26
#ifdef ENABLE_MEDIA
 
27
#include <QSize>
 
28
#include <QSizeF>
 
29
#include <QPoint>
 
30
#include <QPointF>
 
31
#include <QMediaContent>
 
32
#include <QMediaPlayer>
 
33
#include "StelFader.hpp"
 
34
#endif
 
35
#include "StelModule.hpp"
 
36
 
 
37
class QGraphicsVideoItem;
 
38
 
 
39
//! @class StelVideoMgr
 
40
//! A scriptable way to show videos embedded in the screen.
 
41
//! After experimental support with Qt4/Phonon library, this feature is back.
 
42
//! Videos can be scaled, paused, placed and relocated (shifted) on screen.
 
43
//! Setting opacity seems not to do much unless setting it to zero, the video is then simply invisible.
 
44
//! Therefore smooth fading in/out or setting a semitransparent overlay does not work, but there is now an intro/end animation available:
 
45
//! zooming out from a pixel position to a player frame position, and returning to that spot close to end of video playback.
 
46
//!
 
47
//! However, support for multimedia content depends on the operating system, installed codecs, and completeness of the QtMultimedia system support,
 
48
//! so some features or video formats may not work for you (test video and re-code it if necessary).
 
49
//!
 
50
//! <h2>Linux notes</h2>
 
51
//! The listed functions have been tested and work on Ubuntu 15.04 with Qt5.4 with NVidia 9800M and Intel Core-i3/HD5500.
 
52
//! You need to install GStreamer plugins. Most critical seems to be gstreamer0.10-ffmpeg from
 
53
//! https://launchpad.net/~mc3man/+archive/ubuntu/gstffmpeg-keep,
 
54
//! then it plays
 
55
//! <ul>
 
56
//! <li>MP4 (h264)</li>
 
57
//! <li>Apple MOV(Sorenson)</li>
 
58
//! <li>WMV.</li>
 
59
//! <li>Some type of AVI failed</li>
 
60
//! </ul>
 
61
//!
 
62
//! <h2>Windows notes</h2>
 
63
//! According to https://wiki.qt.io/Qt_Multimedia, MinGW is limited to the decaying DirectShow platform plugin.
 
64
//! The WMF platform plugin requires Visual Studio, so building with MSVC should provide better result.
 
65
//! Some signals are not triggered under Windows, so we cannot use them, globally.
 
66
//! There is partial success with MP4 files on MinGW, but also these are rendered badly. Often just shows an error on Windows/MinGW:
 
67
//! DirectShowPlayerService::doRender: Unresolved error code 80040154
 
68
//! (number may differ, also seen: 80040228. Where is a list?)
 
69
//! The formats tested on Windows are: <ul>
 
70
//! <li>MP4 (h264; OK) </li>
 
71
//! <li>WMV (OK, but jumping to different locations via seekVideo() seems not to work properly) </li>
 
72
//! <li>MOV (mp4v codec, very jerky, basically unusable) </li>
 
73
//! <li>AVI (DIVX MP4 codec, same bad issues as MOV) </li>
 
74
//! <li>OGV (invalid media) </li>
 
75
//! <li>WEBM (invalid media) </li>
 
76
//! </ul>
 
77
//!
 
78
//! <h2>Mac OS X Notes</h2>
 
79
//! NOT TESTED ON A MAC! There is a critical difference (causing a crash!) between Win and Linux to either hide or not hide the player just after loading.
 
80
//! Please somebody find out Mac behaviour.
 
81
//!
 
82
//! QtMultimedia is a bit tricky to use: There seems to be no way to load a media file to analyze resolution or duration before starting its replay.
 
83
//! This means, configuring player frames either require absolute frame coordinates, or triggering necessary configuration steps only after replay has started.
 
84
//! We opted for the latter solution because it allows scaled but undistorted video frames which may also take current screen resolution into account.
 
85
//!
 
86
//! Under unclear circumstances we also have a pair of messages:
 
87
//! @code Failed to start video surface due to main thread blocked.
 
88
//! @code Failed to start video surface
 
89
//! and non-appearing video frame, this seems to be https://bugreports.qt.io/browse/QTBUG-39567.
 
90
//! This occurred on an Intel NUC5i3 with SSD, so loading the file should not be much of an issue.
 
91
//!
 
92
//! To help in debugging scripts, this module can be quite verbose in the logfile if Stellarium is called with the command-line argument "--verbose".
 
93
 
 
94
class StelVideoMgr : public StelModule
27
95
{
28
96
        Q_OBJECT
29
97
 
32
100
        ~StelVideoMgr();
33
101
 
34
102
public slots:
35
 
        void loadVideo(const QString& filename, const QString& id, float x, float y, bool show, float alpha);
36
 
        void playVideo(const QString& id);
 
103
 
 
104
        // Methods from StelModule: only update() needed.
 
105
        virtual void init(){;} // Or do something?
 
106
 
 
107
        //! Update the module with respect to the time. This allows the special effects in @name playVideoPopout(), and may evaluate things like video resolution when they become available.
 
108
        //! @param deltaTime the time increment in second since last call.
 
109
        virtual void update(double deltaTime);
 
110
 
 
111
        //! load a video from @param filename, assign an @param id for it for later reference.
 
112
        //! If @param id is already in use, replace it.
 
113
        //! Prepare replay at upper-left corner @param x/@param y in native resolution,
 
114
        //! decide whether to @param show (play) the video already, and set opacity @name alpha.
 
115
        //! If you want non-native resolution, load with @param show set to false, and use @name resizeVideo() and @name showVideo().
 
116
        //! @bug Note that with @param alpha =0 the video is invisible as expected, other values make it fully opaque. There is no semi-transparency possible.
 
117
        void loadVideo(const QString& filename, const QString& id, const float x, const float y, const bool show, const float alpha);
 
118
        //! play video from current position. If @param keepLastFrame is true, video pauses at last frame.
 
119
        void playVideo(const QString& id, const bool keepVisibleAtEnd=false);
 
120
 
 
121
        //! Play a video which has previously been loaded with loadVideo with a complex effect.
 
122
        //! The video appears to pop out from @param fromX/ @param fromY,
 
123
        //! grows within @param popupDuration to size @param finalSizeX/@param finalSizeY, and
 
124
        //! shrinks back towards @param fromX/@param fromY at the end during @param popdownDuration.
 
125
        //! @param id the identifier used when loadVideo was called
 
126
        //! @param fromX X position of starting point, counted from left of window. May be absolute (if >1) or relative (0<X<1)
 
127
        //! @param fromY Y position of starting point, counted from top of window. May be absolute (if >1) or relative (0<Y<1)
 
128
        //! @param atCenterX X position of center of final video frame, counted from left of window. May be absolute (if >1) or relative (0<X<1)
 
129
        //! @param atCenterY Y position of center of final video frame, counted from top of window. May be absolute (if >1) or relative (0<Y<1)
 
130
        //! @param finalSizeX X size of final video frame. May be absolute (if >1) or relative to window size (0<X<1). If -1, scale proportional from @param finalSizeY.
 
131
        //! @param finalSizeY Y size of final video frame. May be absolute (if >1) or relative to window size (0<Y<1). If -1, scale proportional from @param finalSizeX.
 
132
        //! @param popupDuration duration of growing (start) / shrinking (end) transitions (seconds)
 
133
        //! @param frozenInTransition true if video should be paused during growing/shrinking transition.
 
134
        void playVideoPopout(const QString& id, float fromX, float fromY, float atCenterX, float atCenterY, float finalSizeX, float finalSizeY, float popupDuration, bool frozenInTransition);
 
135
 
 
136
        //! Pause video, keep it visible on-screen.
 
137
        //! Sending @name playVideo() continues replay, sending seekVideo() can move to a different position.
37
138
        void pauseVideo(const QString& id);
 
139
 
 
140
        //! Stop playing, resets video and hides video output window
38
141
        void stopVideo(const QString& id);
 
142
 
 
143
        //! Unload video from memory.
39
144
        void dropVideo(const QString& id);
40
 
        void seekVideo(const QString& id, qint64 ms);
41
 
        void setVideoXY(const QString& id, float x, float y);
42
 
        void setVideoAlpha(const QString& id, float alpha);
43
 
        void resizeVideo(const QString& id, float w, float h);
44
 
        void showVideo(const QString& id, bool show);
 
145
 
 
146
        //! Seek a position in video @param id. Pause the video playing if @param pause=true.
 
147
        //! @note This may not work if video has not been fully loaded. Better wait a second before proceeding after loadVideo(), and call seekVideo(., ., false); pauseVideo(.);
 
148
        void seekVideo(const QString& id, const qint64 ms, bool pause=false);
 
149
 
 
150
        //! move upper left corner of video @name id to @name x, @name y.
 
151
        //! If x or y are <1, this is relative to screen size!
 
152
        void setVideoXY(const QString& id, const float x, const float y, const bool relative=false);
 
153
 
 
154
        //! sets opacity
 
155
        //! @param alpha opacity for the video (0=transparent, ... 1=fully opaque).
 
156
        //! @note if alpha is 0, also @name showVideo(id, true) cannot show the video.
 
157
        //! @bug (as of Qt5.5) Note that with @param alpha =0 the video is invisible as expected, other values make it fully opaque. There is no semi-transparency possible.
 
158
        void setVideoAlpha(const QString& id, const float alpha);
 
159
 
 
160
        //! set video size to width @param w and height @param h.
 
161
        //! Use @param w=-1 or @param h=-1 for autoscale from the other dimension,
 
162
        //! or use @param w=h=-1 for native size of video.
 
163
        //! if @param w or @param h are <=1, the size is relative to screen dimensions.
 
164
        //! This should be the preferred use, because it allows the development of device-independent scripts.
 
165
        //! When native resolution is unknown at the time you call this, it will be evaluated at the next update() after resolution becomes known.
 
166
        //! Autoscaling uses viewport dimensions at the time of calling, so resizing the Stellarium window will not resize the video frame during replay.
 
167
        void resizeVideo(const QString& id, float w = -1.0f, float h = -1.0f);
 
168
 
 
169
        //! show or hide video player
 
170
        //! @param id name given during loadVideo()
 
171
        //! @param show @value true to show, @value false to hide
 
172
        void showVideo(const QString& id, const bool show);
 
173
 
 
174
        //! returns duration (in milliseconds) of loaded video. This may return valid result only after @name playVideo() or @name pauseVideo() have been called.
 
175
        //! Returns -1 if video has not been analyzed yet. (loaded, but not started).
 
176
        qint64 getVideoDuration(const QString& id);
 
177
 
 
178
        //! returns current position (in milliseconds) of loaded video. This may return valid result only after @name playVideo() or @name pauseVideo() have been called.
 
179
        //! Returns -1 if video has not been analyzed yet. (loaded, but not started).
 
180
        qint64 getVideoPosition(const QString& id);
 
181
 
 
182
        //! returns resolution (in pixels) of loaded video. Returned value may be invalid before video has been fully loaded.
 
183
        QSize getVideoResolution(const QString& id);
 
184
        //! returns native width (in pixels) of loaded video, or -1 in case of trouble.
 
185
        int getVideoWidth(const QString& id);
 
186
        //! returns native height (in pixels) of loaded video, or -1 in case of trouble.
 
187
        int getVideoHeight(const QString& id);
 
188
 
 
189
        //! set mute state of video player
 
190
        //! @param mute true to silence the video, false to hear audio.
 
191
        void muteVideo(const QString& id, bool muteVideo=true);
 
192
        //! set volume for video. Valid values are 0..100, values outside this range will be clamped.
 
193
        void setVideoVolume(const QString& id, int newVolume);
 
194
        //! return currently set volume (0..100) of media player, or -1 in case of some error.
 
195
        int getVideoVolume(const QString& id);
 
196
 
 
197
        //! returns whether video is currently playing.
 
198
        //! @param id name assigned during loadVideo().
 
199
        //! @note If video is not found, also returns @value false.
 
200
        bool isVideoPlaying(const QString& id);
 
201
 
 
202
#ifdef ENABLE_MEDIA
 
203
private slots:
 
204
        // Slots to handle QMediaPlayer signals. Never call them yourself!
 
205
        // Some of them are useful to understand media handling and to get to crucial information like native resolution and duration during loading of media.
 
206
        // Most only give simple debug output...
 
207
        void handleAudioAvailableChanged(bool available);
 
208
        void handleBufferStatusChanged(int percentFilled);
 
209
        void handleDurationChanged(qint64 duration);
 
210
        void handleError(QMediaPlayer::Error error);
 
211
        void handleMediaStatusChanged(QMediaPlayer::MediaStatus status);
 
212
        void handleMutedChanged(bool muted);
 
213
        //void handlePositionChanged(qint64 position); // periodically notify where in the video we are. Could be used to update scale bars, not needed.
 
214
        void handleSeekableChanged(bool seekable);
 
215
        void handleStateChanged(QMediaPlayer::State state);
 
216
        void handleVideoAvailableChanged(bool videoAvailable);
 
217
        void handleVolumeChanged(int volume);
 
218
 
 
219
        // Slots to handle QMediaPlayer change signals inherited from QMediaObject:
 
220
        void handleAvailabilityChanged(bool available);
 
221
        void handleAvailabilityChanged(QMultimedia::AvailabilityStatus availability);
 
222
        //! @note This one works, while handleMetaDataChanged(key, value) is not called on Windows (QTBUG-42034)
 
223
        void handleMetaDataChanged();
 
224
        // This signal is not triggered on Windows, we must work around using handleMetaDataChanged()
 
225
        //void handleMetaDataChanged(const QString & key, const QVariant & value);
 
226
#endif
 
227
 
45
228
 
46
229
private:
47
230
#if 0
 
231
        // Traces of old Qt4/Phonon:
48
232
        typedef struct {
49
233
                QWidget *widget;
50
234
                Phonon::VideoPlayer *player;
52
236
        } VideoPlayer;
53
237
        QMap<QString, VideoPlayer*> videoObjects; 
54
238
#endif
55
 
 
 
239
#ifdef ENABLE_MEDIA
 
240
        typedef struct {
 
241
                //QVideoWidget *widget; // would be easiest, but only with QtQuick2...
 
242
                QGraphicsVideoItem *videoItem;
 
243
                QMediaPlayer *player;
 
244
                qint64 duration;           //!< duration of video. This becomes available only after loading or at begin of playing! (?)
 
245
                QSize resolution;          //!< stores resolution of video. This becomes available only after loading or at begin of playing, so we must apply a trick with signals and slots to set it.
 
246
                bool keepVisible;          //!< true if you want to show the last frame after video has played. (Due to delays in signal/slot handling of mediaplayer status changes, we use update() to stop a few frames before end.)
 
247
                bool needResize;           //!< becomes true if resize is called before resolution becomes available.
 
248
                bool simplePlay;           //!< only play in one static size. true for playVideo(), false during playVideoPopout().
 
249
                LinearFader fader;         //!< Used during @name playVideoPopout() for nice transition effects.
 
250
                QSizeF  targetFrameSize;   //!< Video frame size, used during @name playVideo(), and final frame size during @name playVideoPopout().
 
251
                QPointF popupOrigin;       //!< Screen point where video appears to come out during @name playVideoPopout()
 
252
                QPointF popupTargetCenter; //!< Target frame position (center of target frame) used during @name playVideoPopout()
 
253
                int lastPos;               //!< This should not be required: We must track a bug in QtMultimedia where the QMediaPlayer is in playing state but does not progress the video position. In update() we try to let it run again.
 
254
        } VideoPlayer;
 
255
        QMap<QString, VideoPlayer*> videoObjects;
 
256
        bool verbose;                      //!< true to write many more log entries (useful for script debugging) Activate with command-line option "--verbose"
 
257
#endif
56
258
};
57
259
 
58
260
#endif // _STELVIDEOMGR_HPP_