2014-08-13 12:22:00 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
#ifndef MOZILLA_MEDIASOURCEREADER_H_
|
|
|
|
#define MOZILLA_MEDIASOURCEREADER_H_
|
|
|
|
|
|
|
|
#include "mozilla/Attributes.h"
|
|
|
|
#include "mozilla/ReentrantMonitor.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsError.h"
|
2014-08-20 08:14:00 +00:00
|
|
|
#include "nsString.h"
|
2014-08-13 12:22:00 +00:00
|
|
|
#include "nsTArray.h"
|
|
|
|
#include "MediaDecoderReader.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
class MediaSourceDecoder;
|
2014-08-22 02:14:36 +00:00
|
|
|
class SourceBufferDecoder;
|
2014-09-04 01:57:06 +00:00
|
|
|
class TrackBuffer;
|
2014-08-13 12:22:00 +00:00
|
|
|
|
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
class MediaSource;
|
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
|
|
|
|
class MediaSourceReader : public MediaDecoderReader
|
|
|
|
{
|
|
|
|
public:
|
2014-09-01 03:50:23 +00:00
|
|
|
explicit MediaSourceReader(MediaSourceDecoder* aDecoder);
|
2014-08-13 12:22:00 +00:00
|
|
|
|
|
|
|
nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
// Although we technically don't implement anything here, we return NS_OK
|
|
|
|
// so that when the state machine initializes and calls this function
|
|
|
|
// we don't return an error code back to the media element.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-09-05 00:04:54 +00:00
|
|
|
// Indicates the point in time at which the reader should consider
|
|
|
|
// registered TrackBuffers essential for initialization.
|
|
|
|
void PrepareInitialization();
|
|
|
|
|
2014-08-13 12:22:00 +00:00
|
|
|
bool IsWaitingMediaResources() MOZ_OVERRIDE;
|
|
|
|
|
2014-12-10 22:03:56 +00:00
|
|
|
nsRefPtr<AudioDataPromise> RequestAudioData() MOZ_OVERRIDE;
|
|
|
|
nsRefPtr<VideoDataPromise>
|
|
|
|
RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) MOZ_OVERRIDE;
|
2014-08-13 12:22:00 +00:00
|
|
|
|
2014-12-17 23:41:19 +00:00
|
|
|
virtual size_t SizeOfVideoQueueInFrames() MOZ_OVERRIDE;
|
|
|
|
virtual size_t SizeOfAudioQueueInFrames() MOZ_OVERRIDE;
|
|
|
|
|
2015-01-14 00:27:00 +00:00
|
|
|
virtual bool IsDormantNeeded() MOZ_OVERRIDE;
|
|
|
|
virtual void ReleaseMediaResources() MOZ_OVERRIDE;
|
|
|
|
|
2014-08-13 12:22:00 +00:00
|
|
|
void OnAudioDecoded(AudioData* aSample);
|
2014-12-10 22:03:56 +00:00
|
|
|
void OnAudioNotDecoded(NotDecodedReason aReason);
|
2014-08-13 12:22:00 +00:00
|
|
|
void OnVideoDecoded(VideoData* aSample);
|
2014-12-10 22:03:56 +00:00
|
|
|
void OnVideoNotDecoded(NotDecodedReason aReason);
|
2014-08-13 12:22:00 +00:00
|
|
|
|
2015-01-30 06:11:11 +00:00
|
|
|
void DoVideoSeek();
|
|
|
|
void DoAudioSeek();
|
2015-01-11 22:05:08 +00:00
|
|
|
void OnVideoSeekCompleted(int64_t aTime);
|
2015-01-30 06:11:12 +00:00
|
|
|
void OnVideoSeekFailed(nsresult aResult);
|
2015-01-11 22:05:08 +00:00
|
|
|
void OnAudioSeekCompleted(int64_t aTime);
|
2015-01-30 06:11:12 +00:00
|
|
|
void OnAudioSeekFailed(nsresult aResult);
|
2014-11-05 00:32:26 +00:00
|
|
|
|
2014-12-22 08:20:31 +00:00
|
|
|
virtual bool IsWaitForDataSupported() MOZ_OVERRIDE { return true; }
|
|
|
|
virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) MOZ_OVERRIDE;
|
|
|
|
void MaybeNotifyHaveData();
|
|
|
|
|
2014-08-13 12:22:00 +00:00
|
|
|
bool HasVideo() MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
return mInfo.HasVideo();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HasAudio() MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
return mInfo.HasAudio();
|
|
|
|
}
|
|
|
|
|
2014-11-05 00:32:26 +00:00
|
|
|
void NotifyTimeRangesChanged();
|
|
|
|
|
2014-10-28 20:30:36 +00:00
|
|
|
// We can't compute a proper start time since we won't necessarily
|
|
|
|
// have the first frame of the resource available. This does the same
|
|
|
|
// as chrome/blink and assumes that we always start at t=0.
|
|
|
|
virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio) MOZ_OVERRIDE { return 0; }
|
2014-11-12 04:50:22 +00:00
|
|
|
|
2014-12-22 08:20:30 +00:00
|
|
|
// Buffering heuristics don't make sense for MSE, because the arrival of data
|
|
|
|
// is at least partly controlled by javascript, and javascript does not expect
|
|
|
|
// us to sit on unplayed data just because it may not be enough to play
|
|
|
|
// through.
|
|
|
|
bool UseBufferingHeuristics() MOZ_OVERRIDE { return false; }
|
2014-10-28 20:30:36 +00:00
|
|
|
|
2015-01-03 02:08:06 +00:00
|
|
|
bool IsMediaSeekable() MOZ_OVERRIDE { return true; }
|
2014-08-13 12:22:00 +00:00
|
|
|
|
|
|
|
nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE;
|
2014-11-18 12:23:00 +00:00
|
|
|
void ReadUpdatedMetadata(MediaInfo* aInfo) MOZ_OVERRIDE;
|
2014-12-16 09:52:57 +00:00
|
|
|
nsRefPtr<SeekPromise>
|
2015-01-16 18:57:59 +00:00
|
|
|
Seek(int64_t aTime, int64_t aEndTime) MOZ_OVERRIDE;
|
2014-09-04 01:57:06 +00:00
|
|
|
|
2015-01-16 18:58:00 +00:00
|
|
|
void CancelSeek() MOZ_OVERRIDE;
|
|
|
|
|
2014-11-12 04:50:21 +00:00
|
|
|
// Acquires the decoder monitor, and is thus callable on any thread.
|
2014-11-12 04:50:21 +00:00
|
|
|
nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE;
|
|
|
|
|
2015-01-07 23:58:55 +00:00
|
|
|
already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType,
|
|
|
|
int64_t aTimestampOffset /* microseconds */);
|
2014-08-13 12:22:00 +00:00
|
|
|
|
2014-09-04 01:57:06 +00:00
|
|
|
void AddTrackBuffer(TrackBuffer* aTrackBuffer);
|
|
|
|
void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
|
|
|
|
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
|
|
|
|
|
2014-12-09 19:43:21 +00:00
|
|
|
nsRefPtr<ShutdownPromise> Shutdown() MOZ_OVERRIDE;
|
2014-08-13 12:22:00 +00:00
|
|
|
|
2015-01-03 02:08:06 +00:00
|
|
|
virtual void BreakCycles() MOZ_OVERRIDE;
|
2014-08-13 12:22:00 +00:00
|
|
|
|
|
|
|
bool IsShutdown()
|
|
|
|
{
|
|
|
|
ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
|
|
|
|
return mDecoder->IsShutdown();
|
|
|
|
}
|
|
|
|
|
2014-09-04 01:57:06 +00:00
|
|
|
// Return true if all of the active tracks contain data for the specified time.
|
2014-09-10 02:27:51 +00:00
|
|
|
bool TrackBuffersContainTime(int64_t aTime);
|
2014-08-13 12:22:00 +00:00
|
|
|
|
2014-08-26 07:25:09 +00:00
|
|
|
// Mark the reader to indicate that EndOfStream has been called on our MediaSource
|
|
|
|
void Ended();
|
|
|
|
|
|
|
|
// Return true if the Ended method has been called
|
|
|
|
bool IsEnded();
|
2015-01-24 10:46:21 +00:00
|
|
|
bool IsNearEnd(int64_t aTime /* microseconds */);
|
|
|
|
|
|
|
|
// Set the duration of the attached mediasource element.
|
|
|
|
void SetMediaSourceDuration(double aDuration /* seconds */);
|
2014-08-26 07:25:09 +00:00
|
|
|
|
2014-10-13 22:05:00 +00:00
|
|
|
#ifdef MOZ_EME
|
|
|
|
nsresult SetCDMProxy(CDMProxy* aProxy);
|
|
|
|
#endif
|
|
|
|
|
2015-01-13 09:31:03 +00:00
|
|
|
virtual bool IsAsync() const MOZ_OVERRIDE {
|
2015-02-09 12:28:59 +00:00
|
|
|
return (!GetAudioReader() || GetAudioReader()->IsAsync()) &&
|
|
|
|
(!GetVideoReader() || GetVideoReader()->IsAsync());
|
2015-01-13 09:31:03 +00:00
|
|
|
}
|
|
|
|
|
2015-01-16 03:14:56 +00:00
|
|
|
// Returns true if aReader is a currently active audio or video
|
|
|
|
bool IsActiveReader(MediaDecoderReader* aReader);
|
|
|
|
|
2015-01-29 02:35:58 +00:00
|
|
|
// Returns a string describing the state of the MediaSource internal
|
|
|
|
// buffered data. Used for debugging purposes.
|
|
|
|
void GetMozDebugReaderData(nsAString& aString);
|
|
|
|
|
2014-08-13 12:22:00 +00:00
|
|
|
private:
|
2015-02-09 12:28:59 +00:00
|
|
|
// Switch the current audio/video source to the source that
|
2015-01-31 01:45:49 +00:00
|
|
|
// contains aTarget (or up to aTolerance after target). Both
|
|
|
|
// aTarget and aTolerance are in microseconds.
|
2015-02-06 12:51:46 +00:00
|
|
|
// Search can be made using a fuzz factor. Should an approximated value be
|
|
|
|
// found instead, aTarget will be updated to the actual target found.
|
2015-02-09 12:28:59 +00:00
|
|
|
enum SwitchSourceResult {
|
2015-02-24 05:38:41 +00:00
|
|
|
SOURCE_NONE = -1,
|
2015-02-09 12:28:59 +00:00
|
|
|
SOURCE_EXISTING = 0,
|
|
|
|
SOURCE_NEW = 1,
|
2015-01-24 10:45:58 +00:00
|
|
|
};
|
2015-01-31 01:45:49 +00:00
|
|
|
|
2015-02-06 12:51:46 +00:00
|
|
|
SwitchSourceResult SwitchAudioSource(int64_t* aTarget);
|
|
|
|
SwitchSourceResult SwitchVideoSource(int64_t* aTarget);
|
2015-01-30 06:11:11 +00:00
|
|
|
|
|
|
|
void DoAudioRequest();
|
|
|
|
void DoVideoRequest();
|
|
|
|
|
2015-01-30 06:11:12 +00:00
|
|
|
void CompleteAudioSeekAndDoRequest()
|
|
|
|
{
|
|
|
|
mAudioSeekRequest.Complete();
|
|
|
|
DoAudioRequest();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CompleteVideoSeekAndDoRequest()
|
|
|
|
{
|
|
|
|
mVideoSeekRequest.Complete();
|
|
|
|
DoVideoRequest();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CompleteAudioSeekAndRejectPromise()
|
|
|
|
{
|
|
|
|
mAudioSeekRequest.Complete();
|
|
|
|
mAudioPromise.Reject(DECODE_ERROR, __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CompleteVideoSeekAndRejectPromise()
|
|
|
|
{
|
|
|
|
mVideoSeekRequest.Complete();
|
|
|
|
mVideoPromise.Reject(DECODE_ERROR, __func__);
|
|
|
|
}
|
|
|
|
|
2015-02-09 12:28:59 +00:00
|
|
|
MediaDecoderReader* GetAudioReader() const;
|
|
|
|
MediaDecoderReader* GetVideoReader() const;
|
|
|
|
int64_t GetReaderAudioTime(int64_t aTime) const;
|
|
|
|
int64_t GetReaderVideoTime(int64_t aTime) const;
|
|
|
|
|
2015-01-24 10:45:58 +00:00
|
|
|
// Will reject the MediaPromise with END_OF_STREAM if mediasource has ended
|
|
|
|
// or with WAIT_FOR_DATA otherwise.
|
2015-01-24 10:46:21 +00:00
|
|
|
void CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime /* microseconds */);
|
2014-08-13 12:22:00 +00:00
|
|
|
|
2015-02-09 12:28:59 +00:00
|
|
|
// Return a decoder from the set available in aTrackDecoders that has data
|
2014-09-10 02:21:17 +00:00
|
|
|
// available in the range requested by aTarget.
|
2015-02-13 05:52:42 +00:00
|
|
|
already_AddRefed<SourceBufferDecoder> SelectDecoder(int64_t aTarget /* microseconds */,
|
|
|
|
int64_t aTolerance /* microseconds */,
|
2015-02-09 12:28:59 +00:00
|
|
|
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
|
2014-12-22 08:20:31 +00:00
|
|
|
bool HaveData(int64_t aTarget, MediaData::Type aType);
|
2014-09-08 00:07:56 +00:00
|
|
|
|
2014-11-05 00:32:26 +00:00
|
|
|
void AttemptSeek();
|
2015-01-30 06:11:11 +00:00
|
|
|
bool IsSeeking() { return mPendingSeekTime != -1; }
|
2014-09-07 11:54:00 +00:00
|
|
|
|
2015-02-09 12:28:59 +00:00
|
|
|
nsRefPtr<SourceBufferDecoder> mAudioSourceDecoder;
|
|
|
|
nsRefPtr<SourceBufferDecoder> mVideoSourceDecoder;
|
2014-08-13 12:22:00 +00:00
|
|
|
|
2014-09-04 01:57:06 +00:00
|
|
|
nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
|
2014-12-09 19:43:21 +00:00
|
|
|
nsTArray<nsRefPtr<TrackBuffer>> mShutdownTrackBuffers;
|
2014-09-05 00:04:54 +00:00
|
|
|
nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
|
2014-09-04 01:57:06 +00:00
|
|
|
nsRefPtr<TrackBuffer> mAudioTrack;
|
|
|
|
nsRefPtr<TrackBuffer> mVideoTrack;
|
2014-08-13 12:22:00 +00:00
|
|
|
|
2015-01-30 06:11:11 +00:00
|
|
|
MediaPromiseConsumerHolder<AudioDataPromise> mAudioRequest;
|
|
|
|
MediaPromiseConsumerHolder<VideoDataPromise> mVideoRequest;
|
|
|
|
|
2014-12-10 22:03:56 +00:00
|
|
|
MediaPromiseHolder<AudioDataPromise> mAudioPromise;
|
|
|
|
MediaPromiseHolder<VideoDataPromise> mVideoPromise;
|
|
|
|
|
2014-12-22 08:20:31 +00:00
|
|
|
MediaPromiseHolder<WaitForDataPromise> mAudioWaitPromise;
|
|
|
|
MediaPromiseHolder<WaitForDataPromise> mVideoWaitPromise;
|
|
|
|
MediaPromiseHolder<WaitForDataPromise>& WaitPromise(MediaData::Type aType)
|
|
|
|
{
|
|
|
|
return aType == MediaData::AUDIO_DATA ? mAudioWaitPromise : mVideoWaitPromise;
|
|
|
|
}
|
|
|
|
|
2014-10-13 22:05:00 +00:00
|
|
|
#ifdef MOZ_EME
|
|
|
|
nsRefPtr<CDMProxy> mCDMProxy;
|
|
|
|
#endif
|
|
|
|
|
2014-08-13 12:22:00 +00:00
|
|
|
// These are read and written on the decode task queue threads.
|
2014-09-04 01:57:06 +00:00
|
|
|
int64_t mLastAudioTime;
|
|
|
|
int64_t mLastVideoTime;
|
|
|
|
|
2015-01-30 06:11:12 +00:00
|
|
|
MediaPromiseConsumerHolder<SeekPromise> mAudioSeekRequest;
|
|
|
|
MediaPromiseConsumerHolder<SeekPromise> mVideoSeekRequest;
|
|
|
|
MediaPromiseHolder<SeekPromise> mSeekPromise;
|
|
|
|
|
2014-11-05 00:32:26 +00:00
|
|
|
// Temporary seek information while we wait for the data
|
|
|
|
// to be added to the track buffer.
|
|
|
|
int64_t mPendingSeekTime;
|
|
|
|
bool mWaitingForSeekData;
|
|
|
|
|
2014-08-13 12:22:00 +00:00
|
|
|
int64_t mTimeThreshold;
|
2014-08-21 03:14:48 +00:00
|
|
|
bool mDropAudioBeforeThreshold;
|
2014-08-13 12:22:00 +00:00
|
|
|
bool mDropVideoBeforeThreshold;
|
|
|
|
|
2015-02-09 12:29:01 +00:00
|
|
|
bool mAudioDiscontinuity;
|
|
|
|
bool mVideoDiscontinuity;
|
|
|
|
|
2014-08-26 07:25:09 +00:00
|
|
|
bool mEnded;
|
2015-01-24 10:46:21 +00:00
|
|
|
double mMediaSourceDuration;
|
2014-09-03 09:56:22 +00:00
|
|
|
|
2014-09-05 00:04:54 +00:00
|
|
|
bool mHasEssentialTrackBuffers;
|
2014-12-09 19:43:21 +00:00
|
|
|
|
2014-12-12 22:22:23 +00:00
|
|
|
void ContinueShutdown();
|
2014-12-09 19:43:21 +00:00
|
|
|
MediaPromiseHolder<ShutdownPromise> mMediaSourceShutdownPromise;
|
2014-11-21 03:48:22 +00:00
|
|
|
#ifdef MOZ_FMP4
|
2014-11-04 13:14:00 +00:00
|
|
|
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
|
2014-11-21 03:48:22 +00:00
|
|
|
#endif
|
2014-08-13 12:22:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif /* MOZILLA_MEDIASOURCEREADER_H_ */
|