diff -r 000000000000 -r 6474c204b198 content/media/RtspMediaResource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/media/RtspMediaResource.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,243 @@ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if !defined(RtspMediaResource_h_) +#define RtspMediaResource_h_ + +#include "MediaResource.h" + +namespace mozilla { + +class RtspTrackBuffer; + +/* RtspMediaResource + * RtspMediaResource provides an interface to deliver and control RTSP media + * data to RtspDecoder. + * + * RTSP Flow Start vs HTTP Flow Start: + * For HTTP (and files stored on disk), once the channel is created and response + * data is available, HTMLMediaElement::MediaLoadListener::OnStartRequest is + * called. (Note, this is an asynchronous call following channel->AsyncOpen). + * The decoder and MediaResource are set up to talk to each other: + * InitializeDecoderForChannel and FinishDecoderSetup. + * RtspMediaResource is different from this, in that FinishDecoderSetup is + * postponed until after the initial connection with the server is made. + * RtspController, owned by RtspMediaResource, provides the interface to setup + * the connection, and calls RtspMediaResource::Listener::OnConnected + * (from nsIStreamingProtocolListener). FinishDecoderSetup is then called to + * connect RtspMediaResource with RtspDecoder and allow HTMLMediaElement to + * request playback etc. + * + * Playback: + * When the user presses play/pause, HTMLMediaElement::Play/::Pause is called, + * subsequently making calls to the decoder state machine. Upon these state + * changes, the decoder is told to start reading and decoding data. This causes + * the nsIStreamingMediaController object to send play/pause commands to the + * server. + * Data is then delivered to the host and eventually written to the + * RtspTrackBuffer objects. Note that RtspMediaResource does not know about the + * play or pause state. It only knows about the data written into its buffers. + * + * Data Structures and Flow: + * Unlike HTTP, RTSP provides separate streams for audio and video. + * As such, it creates two RtspTrackBuffer objects for the audio and video data. + * Data is read using the function ReadFrameFromTrack. These buffer objects are + * ring buffers, implying that data from the network may be discarded if the + * decoder cannot read at a high enough rate. + * + * Data is delivered via RtspMediaResource::Listener::OnMediaDataAvailable. + * This Listener implements nsIStreamingProtocolListener, and writes the data to + * the appropriate RtspTrackBuffer. The decoder then reads the data by calling + * RtspMediaResource::ReadFrameFromTrack. Note that the decoder and decode + * thread will be blocked until data is available in one of the two buffers. + * + * Seeking: + * Since the frame data received after seek is not continuous with existing + * frames in RtspTrackBuffer, the buffer must be cleared. If we don't clear the + * old frame data in RtspTrackBuffer, the decoder's behavior will be + * unpredictable. So we add |mFrameType| in RtspTrackBuffer to do this: + * When we are seeking, the mFrameType flag is set, and RtspTrackBuffer will + * drop the incoming data until the RTSP server completes the seek operation. + * Note: seeking for RTSP is carried out based on sending the seek time to the + * server, unlike HTTP in which the seek time is converted to a byte offset. + * Thus, RtspMediaResource has a SeekTime function which should be called + * instead of Seek. + * */ +class RtspMediaResource : public BaseMediaResource +{ +public: + RtspMediaResource(MediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI, + const nsACString& aContentType); + virtual ~RtspMediaResource(); + + // The following methods can be called on any thread. + + // Get the RtspMediaResource pointer if this MediaResource is a + // RtspMediaResource. For calling Rtsp specific functions. + virtual RtspMediaResource* GetRtspPointer() MOZ_OVERRIDE MOZ_FINAL { + return this; + } + + // Returns the nsIStreamingProtocolController in the RtspMediaResource. + // RtspMediaExtractor: request it to get mime type for creating decoder. + // RtspOmxDecoder: request it to send play/pause commands to RTSP server. + // The lifetime of mMediaStreamController is controlled by RtspMediaResource + // because the RtspMediaExtractor and RtspOmxDecoder won't hold the reference. + nsIStreamingProtocolController* GetMediaStreamController() { + return mMediaStreamController; + } + + virtual bool IsRealTime() MOZ_OVERRIDE { + return mRealTime; + } + + // The following methods can be called on any thread except main thread. + + // Read data from track. + // Parameters: + // aToBuffer, aToBufferSize: buffer pointer and buffer size. + // aReadCount: output actual read bytes. + // aFrameTime: output frame time stamp. + // aFrameSize: actual data size in track. + nsresult ReadFrameFromTrack(uint8_t* aBuffer, uint32_t aBufferSize, + uint32_t aTrackIdx, uint32_t& aBytes, + uint64_t& aTime, uint32_t& aFrameSize); + + // Seek to the given time offset + nsresult SeekTime(int64_t aOffset); + + // dummy + virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, + uint32_t aCount, uint32_t* aBytes) MOZ_OVERRIDE{ + return NS_ERROR_FAILURE; + } + // dummy + virtual void SetReadMode(MediaCacheStream::ReadMode aMode) MOZ_OVERRIDE {} + // dummy + virtual void SetPlaybackRate(uint32_t aBytesPerSecond) MOZ_OVERRIDE {} + // dummy + virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) + MOZ_OVERRIDE { + return NS_OK; + } + // dummy + virtual nsresult Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE { + return NS_OK; + } + // dummy + virtual void StartSeekingForMetadata() MOZ_OVERRIDE {} + // dummy + virtual void EndSeekingForMetadata() MOZ_OVERRIDE {} + // dummy + virtual int64_t Tell() MOZ_OVERRIDE { return 0; } + + // Any thread + virtual void Pin() MOZ_OVERRIDE {} + virtual void Unpin() MOZ_OVERRIDE {} + + // dummy + virtual bool IsSuspendedByCache() MOZ_OVERRIDE { return false; } + + virtual bool IsSuspended() MOZ_OVERRIDE { return false; } + virtual bool IsTransportSeekable() MOZ_OVERRIDE { return true; } + // dummy + virtual double GetDownloadRate(bool* aIsReliable) MOZ_OVERRIDE { return 0; } + + virtual int64_t GetLength() MOZ_OVERRIDE { + if (mRealTime) { + return -1; + } + return 0; + } + + // dummy + virtual int64_t GetNextCachedData(int64_t aOffset) MOZ_OVERRIDE { return 0; } + // dummy + virtual int64_t GetCachedDataEnd(int64_t aOffset) MOZ_OVERRIDE { return 0; } + // dummy + virtual bool IsDataCachedToEndOfResource(int64_t aOffset) MOZ_OVERRIDE { + return false; + } + // dummy + nsresult GetCachedRanges(nsTArray& aRanges) MOZ_OVERRIDE { + return NS_ERROR_FAILURE; + } + + // The following methods can be called on main thread only. + + virtual nsresult Open(nsIStreamListener** aStreamListener) MOZ_OVERRIDE; + virtual nsresult Close() MOZ_OVERRIDE; + virtual void Suspend(bool aCloseImmediately) MOZ_OVERRIDE; + virtual void Resume() MOZ_OVERRIDE; + virtual already_AddRefed GetCurrentPrincipal() MOZ_OVERRIDE; + virtual bool CanClone() MOZ_OVERRIDE { + return false; + } + virtual already_AddRefed CloneData(MediaDecoder* aDecoder) + MOZ_OVERRIDE { + return nullptr; + } + // dummy + virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, + uint32_t aCount) MOZ_OVERRIDE { + return NS_ERROR_FAILURE; + } + + virtual size_t SizeOfExcludingThis( + MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; + + virtual size_t SizeOfIncludingThis( + MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE { + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); + } + + // Listener implements nsIStreamingProtocolListener as + // mMediaStreamController's callback function. + // It holds RtspMediaResource reference to notify the connection status and + // data arrival. The Revoke function releases the reference when + // RtspMediaResource::OnDisconnected is called. + class Listener MOZ_FINAL : public nsIInterfaceRequestor, + public nsIStreamingProtocolListener + { + public: + Listener(RtspMediaResource* aResource) : mResource(aResource) {} + ~Listener() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEREQUESTOR + NS_DECL_NSISTREAMINGPROTOCOLLISTENER + + void Revoke(); + + private: + nsRefPtr mResource; + }; + friend class Listener; + +protected: + // Main thread access only. + // These are called on the main thread by Listener. + NS_DECL_NSISTREAMINGPROTOCOLLISTENER + + nsRefPtr mListener; + +private: + bool IsVideoEnabled(); + bool IsVideo(uint8_t tracks, nsIStreamingProtocolMetaData *meta); + // These two members are created at |RtspMediaResource::OnConnected|. + nsCOMPtr mMediaStreamController; + nsTArray> mTrackBuffer; + + // A flag that indicates the |RtspMediaResource::OnConnected| has already been + // called. + bool mIsConnected; + // live stream + bool mRealTime; +}; + +} // namespace mozilla + +#endif +