| 1 | /* |
| 2 | * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. |
| 3 | * Copyright (C) 2007 Collabora Ltd. All rights reserved. |
| 4 | * Copyright (C) 2007 Alp Toker <alp@atoker.com> |
| 5 | * Copyright (C) 2009, 2010, 2011, 2012, 2013, 2015, 2016 Igalia S.L |
| 6 | * Copyright (C) 2014 Cable Television Laboratories, Inc. |
| 7 | * Copyright (C) 2015, 2016 Metrological Group B.V. |
| 8 | * |
| 9 | * This library is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU Library General Public |
| 11 | * License as published by the Free Software Foundation; either |
| 12 | * version 2 of the License, or (at your option) any later version. |
| 13 | * |
| 14 | * This library is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 17 | * Library General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU Library General Public License |
| 20 | * aint with this library; see the file COPYING.LIB. If not, write to |
| 21 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 22 | * Boston, MA 02110-1301, USA. |
| 23 | */ |
| 24 | |
| 25 | #pragma once |
| 26 | |
| 27 | #if ENABLE(VIDEO) && USE(GSTREAMER) |
| 28 | |
| 29 | #include "GStreamerCommon.h" |
| 30 | #include "MediaPlayerPrivateGStreamerBase.h" |
| 31 | |
| 32 | #include <glib.h> |
| 33 | #include <gst/gst.h> |
| 34 | #include <gst/pbutils/install-plugins.h> |
| 35 | #include <wtf/Forward.h> |
| 36 | #include <wtf/RunLoop.h> |
| 37 | #include <wtf/WeakPtr.h> |
| 38 | |
| 39 | #if ENABLE(VIDEO_TRACK) |
| 40 | #include "TrackPrivateBaseGStreamer.h" |
| 41 | #include <wtf/text/AtomicStringHash.h> |
| 42 | #endif |
| 43 | |
| 44 | typedef struct _GstMpegtsSection GstMpegtsSection; |
| 45 | |
| 46 | namespace WebCore { |
| 47 | |
| 48 | #if ENABLE(WEB_AUDIO) |
| 49 | class AudioSourceProvider; |
| 50 | class AudioSourceProviderGStreamer; |
| 51 | #endif |
| 52 | |
| 53 | class AudioTrackPrivateGStreamer; |
| 54 | class InbandMetadataTextTrackPrivateGStreamer; |
| 55 | class InbandTextTrackPrivateGStreamer; |
| 56 | class MediaPlayerRequestInstallMissingPluginsCallback; |
| 57 | class VideoTrackPrivateGStreamer; |
| 58 | |
| 59 | #if ENABLE(MEDIA_SOURCE) |
| 60 | class MediaSourcePrivateClient; |
| 61 | #endif |
| 62 | |
| 63 | class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateGStreamerBase { |
| 64 | public: |
| 65 | explicit MediaPlayerPrivateGStreamer(MediaPlayer*); |
| 66 | virtual ~MediaPlayerPrivateGStreamer(); |
| 67 | |
| 68 | static void registerMediaEngine(MediaEngineRegistrar); |
| 69 | static bool isAvailable(); |
| 70 | |
| 71 | void handleMessage(GstMessage*); |
| 72 | void handlePluginInstallerResult(GstInstallPluginsReturn); |
| 73 | |
| 74 | bool hasVideo() const override { return m_hasVideo; } |
| 75 | bool hasAudio() const override { return m_hasAudio; } |
| 76 | |
| 77 | void load(const String &url) override; |
| 78 | #if ENABLE(MEDIA_SOURCE) |
| 79 | void load(const String& url, MediaSourcePrivateClient*) override; |
| 80 | #endif |
| 81 | #if ENABLE(MEDIA_STREAM) |
| 82 | void load(MediaStreamPrivate&) override; |
| 83 | #endif |
| 84 | void commitLoad(); |
| 85 | void cancelLoad() override; |
| 86 | |
| 87 | void prepareToPlay() override; |
| 88 | void play() override; |
| 89 | void pause() override; |
| 90 | |
| 91 | bool paused() const override; |
| 92 | bool seeking() const override; |
| 93 | |
| 94 | MediaTime platformDuration() const; |
| 95 | MediaTime durationMediaTime() const override; |
| 96 | MediaTime currentMediaTime() const override; |
| 97 | void seek(const MediaTime&) override; |
| 98 | |
| 99 | void setRate(float) override; |
| 100 | double rate() const override; |
| 101 | void setPreservesPitch(bool) override; |
| 102 | |
| 103 | void setPreload(MediaPlayer::Preload) override; |
| 104 | void fillTimerFired(); |
| 105 | |
| 106 | std::unique_ptr<PlatformTimeRanges> buffered() const override; |
| 107 | MediaTime maxMediaTimeSeekable() const override; |
| 108 | bool didLoadingProgress() const override; |
| 109 | unsigned long long totalBytes() const override; |
| 110 | MediaTime maxTimeLoaded() const override; |
| 111 | |
| 112 | bool hasSingleSecurityOrigin() const override; |
| 113 | Optional<bool> wouldTaintOrigin(const SecurityOrigin&) const override; |
| 114 | |
| 115 | void loadStateChanged(); |
| 116 | void timeChanged(); |
| 117 | void didEnd(); |
| 118 | virtual void durationChanged(); |
| 119 | void loadingFailed(MediaPlayer::NetworkState, MediaPlayer::ReadyState = MediaPlayer::HaveNothing, bool forceNotifications = false); |
| 120 | |
| 121 | virtual void sourceSetup(GstElement*); |
| 122 | |
| 123 | GstElement* audioSink() const override; |
| 124 | virtual void configurePlaySink() { } |
| 125 | |
| 126 | void simulateAudioInterruption() override; |
| 127 | |
| 128 | virtual bool changePipelineState(GstState); |
| 129 | |
| 130 | #if ENABLE(WEB_AUDIO) |
| 131 | AudioSourceProvider* audioSourceProvider() override; |
| 132 | #endif |
| 133 | |
| 134 | bool isLiveStream() const override { return m_isStreaming; } |
| 135 | |
| 136 | void enableTrack(TrackPrivateBaseGStreamer::TrackType, unsigned index); |
| 137 | |
| 138 | bool handleSyncMessage(GstMessage*) override; |
| 139 | |
| 140 | private: |
| 141 | static void getSupportedTypes(HashSet<String, ASCIICaseInsensitiveHash>&); |
| 142 | static MediaPlayer::SupportsType supportsType(const MediaEngineSupportParameters&); |
| 143 | void syncOnClock(bool sync); |
| 144 | |
| 145 | GstElement* createAudioSink() override; |
| 146 | |
| 147 | MediaTime playbackPosition() const; |
| 148 | |
| 149 | virtual void updateStates(); |
| 150 | virtual void asyncStateChangeDone(); |
| 151 | |
| 152 | void createGSTPlayBin(const URL&, const String& pipelineName); |
| 153 | |
| 154 | bool loadNextLocation(); |
| 155 | void mediaLocationChanged(GstMessage*); |
| 156 | |
| 157 | virtual void setDownloadBuffering(); |
| 158 | void processBufferingStats(GstMessage*); |
| 159 | #if ENABLE(VIDEO_TRACK) |
| 160 | #if USE(GSTREAMER_MPEGTS) |
| 161 | void processMpegTsSection(GstMpegtsSection*); |
| 162 | #endif |
| 163 | |
| 164 | void processTableOfContents(GstMessage*); |
| 165 | void processTableOfContentsEntry(GstTocEntry*); |
| 166 | |
| 167 | void purgeInvalidAudioTracks(Vector<String> validTrackIds); |
| 168 | void purgeInvalidVideoTracks(Vector<String> validTrackIds); |
| 169 | void purgeInvalidTextTracks(Vector<String> validTrackIds); |
| 170 | #endif |
| 171 | virtual bool doSeek(const MediaTime& position, float rate, GstSeekFlags seekType); |
| 172 | virtual void updatePlaybackRate(); |
| 173 | |
| 174 | String engineDescription() const override { return "GStreamer" ; } |
| 175 | bool didPassCORSAccessCheck() const override; |
| 176 | bool canSaveMediaData() const override; |
| 177 | |
| 178 | void purgeOldDownloadFiles(const char*); |
| 179 | static void uriDecodeBinElementAddedCallback(GstBin*, GstElement*, MediaPlayerPrivateGStreamer*); |
| 180 | static void downloadBufferFileCreatedCallback(MediaPlayerPrivateGStreamer*); |
| 181 | |
| 182 | void setPlaybinURL(const URL& urlString); |
| 183 | void loadFull(const String& url, const String& pipelineName); |
| 184 | |
| 185 | #if GST_CHECK_VERSION(1, 10, 0) |
| 186 | void updateTracks(); |
| 187 | void clearTracks(); |
| 188 | #endif |
| 189 | |
| 190 | protected: |
| 191 | bool m_buffering; |
| 192 | int m_bufferingPercentage; |
| 193 | mutable MediaTime m_cachedPosition; |
| 194 | mutable MediaTime m_cachedDuration; |
| 195 | bool m_canFallBackToLastFinishedSeekPosition; |
| 196 | bool m_changingRate; |
| 197 | bool m_downloadFinished; |
| 198 | bool m_errorOccured; |
| 199 | mutable bool m_isEndReached; |
| 200 | mutable bool m_isStreaming; |
| 201 | bool m_paused; |
| 202 | float m_playbackRate; |
| 203 | GstState m_currentState; |
| 204 | GstState m_oldState; |
| 205 | GstState m_requestedState; |
| 206 | bool m_resetPipeline; |
| 207 | bool m_seeking; |
| 208 | bool m_seekIsPending; |
| 209 | MediaTime m_seekTime; |
| 210 | GRefPtr<GstElement> m_source; |
| 211 | bool m_volumeAndMuteInitialized; |
| 212 | |
| 213 | void readyTimerFired(); |
| 214 | |
| 215 | void notifyPlayerOfVideo(); |
| 216 | void notifyPlayerOfVideoCaps(); |
| 217 | void notifyPlayerOfAudio(); |
| 218 | |
| 219 | #if ENABLE(VIDEO_TRACK) |
| 220 | void notifyPlayerOfText(); |
| 221 | void newTextSample(); |
| 222 | #endif |
| 223 | |
| 224 | void ensureAudioSourceProvider(); |
| 225 | void setAudioStreamProperties(GObject*); |
| 226 | |
| 227 | static void setAudioStreamPropertiesCallback(MediaPlayerPrivateGStreamer*, GObject*); |
| 228 | |
| 229 | static void sourceSetupCallback(MediaPlayerPrivateGStreamer*, GstElement*); |
| 230 | static void videoChangedCallback(MediaPlayerPrivateGStreamer*); |
| 231 | static void videoSinkCapsChangedCallback(MediaPlayerPrivateGStreamer*); |
| 232 | static void audioChangedCallback(MediaPlayerPrivateGStreamer*); |
| 233 | #if ENABLE(VIDEO_TRACK) |
| 234 | static void textChangedCallback(MediaPlayerPrivateGStreamer*); |
| 235 | static GstFlowReturn newTextSampleCallback(MediaPlayerPrivateGStreamer*); |
| 236 | #endif |
| 237 | |
| 238 | private: |
| 239 | |
| 240 | #if ENABLE(VIDEO_TRACK) |
| 241 | GRefPtr<GstElement> m_textAppSink; |
| 242 | GRefPtr<GstPad> m_textAppSinkPad; |
| 243 | #endif |
| 244 | GstStructure* m_mediaLocations; |
| 245 | int m_mediaLocationCurrentIndex; |
| 246 | bool m_playbackRatePause; |
| 247 | MediaTime m_timeOfOverlappingSeek; |
| 248 | float m_lastPlaybackRate; |
| 249 | Timer m_fillTimer; |
| 250 | MediaTime m_maxTimeLoaded; |
| 251 | bool m_loadingStalled { false }; |
| 252 | MediaPlayer::Preload m_preload; |
| 253 | bool m_delayingLoad; |
| 254 | mutable MediaTime m_maxTimeLoadedAtLastDidLoadingProgress; |
| 255 | bool m_hasVideo; |
| 256 | bool m_hasAudio; |
| 257 | RunLoop::Timer<MediaPlayerPrivateGStreamer> m_readyTimerHandler; |
| 258 | mutable unsigned long long m_totalBytes; |
| 259 | URL m_url; |
| 260 | bool m_preservesPitch; |
| 261 | mutable Optional<Seconds> m_lastQueryTime; |
| 262 | bool m_isLegacyPlaybin; |
| 263 | #if GST_CHECK_VERSION(1, 10, 0) |
| 264 | GRefPtr<GstStreamCollection> m_streamCollection; |
| 265 | FloatSize naturalSize() const final; |
| 266 | #if ENABLE(MEDIA_STREAM) |
| 267 | RefPtr<MediaStreamPrivate> m_streamPrivate; |
| 268 | #endif // ENABLE(MEDIA_STREAM) |
| 269 | #endif // GST_CHECK_VERSION(1, 10, 0) |
| 270 | String m_currentAudioStreamId; |
| 271 | String m_currentVideoStreamId; |
| 272 | String m_currentTextStreamId; |
| 273 | #if ENABLE(WEB_AUDIO) |
| 274 | std::unique_ptr<AudioSourceProviderGStreamer> m_audioSourceProvider; |
| 275 | #endif |
| 276 | GRefPtr<GstElement> m_autoAudioSink; |
| 277 | GRefPtr<GstElement> m_downloadBuffer; |
| 278 | Vector<RefPtr<MediaPlayerRequestInstallMissingPluginsCallback>> m_missingPluginCallbacks; |
| 279 | #if ENABLE(VIDEO_TRACK) |
| 280 | HashMap<AtomicString, RefPtr<AudioTrackPrivateGStreamer>> m_audioTracks; |
| 281 | HashMap<AtomicString, RefPtr<InbandTextTrackPrivateGStreamer>> m_textTracks; |
| 282 | HashMap<AtomicString, RefPtr<VideoTrackPrivateGStreamer>> m_videoTracks; |
| 283 | RefPtr<InbandMetadataTextTrackPrivateGStreamer> m_chaptersTrack; |
| 284 | #if USE(GSTREAMER_MPEGTS) |
| 285 | HashMap<AtomicString, RefPtr<InbandMetadataTextTrackPrivateGStreamer>> m_metadataTracks; |
| 286 | #endif |
| 287 | #endif |
| 288 | virtual bool isMediaSource() const { return false; } |
| 289 | |
| 290 | uint64_t m_httpResponseTotalSize { 0 }; |
| 291 | uint64_t m_networkReadPosition { 0 }; |
| 292 | mutable uint64_t m_readPositionAtLastDidLoadingProgress { 0 }; |
| 293 | |
| 294 | HashSet<RefPtr<WebCore::SecurityOrigin>> m_origins; |
| 295 | Optional<bool> m_hasTaintedOrigin { WTF::nullopt }; |
| 296 | }; |
| 297 | |
| 298 | } |
| 299 | |
| 300 | #endif // USE(GSTREAMER) |
| 301 | |