2014-02-04 05:49:21 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* 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(MediaQueue_h_)
|
|
|
|
# define MediaQueue_h_
|
|
|
|
|
2017-07-04 20:47:15 +03:00
|
|
|
# include "mozilla/RecursiveMutex.h"
|
2015-07-16 21:52:43 +03:00
|
|
|
# include "mozilla/TaskQueue.h"
|
|
|
|
|
|
|
|
# include "nsDeque.h"
|
2015-08-06 05:14:15 +03:00
|
|
|
# include "MediaEventSource.h"
|
2017-03-27 06:09:49 +03:00
|
|
|
# include "TimeUnits.h"
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2019-02-22 12:18:47 +03:00
|
|
|
class AudioData;
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
// Thread and type safe wrapper around nsDeque.
|
|
|
|
template <class T>
|
|
|
|
class MediaQueueDeallocator : public nsDequeFunctor {
|
2017-11-06 06:37:28 +03:00
|
|
|
virtual void operator()(void* aObject) override {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<T> releaseMe = dont_AddRef(static_cast<T*>(aObject));
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-23 09:12:00 +03:00
|
|
|
template <class T>
|
|
|
|
class MediaQueue : private nsDeque {
|
|
|
|
public:
|
|
|
|
MediaQueue()
|
|
|
|
: nsDeque(new MediaQueueDeallocator<T>()),
|
2017-07-04 20:47:15 +03:00
|
|
|
mRecursiveMutex("mediaqueue"),
|
2015-07-23 09:12:00 +03:00
|
|
|
mEndOfStream(false) {}
|
2014-02-04 05:49:21 +04:00
|
|
|
|
|
|
|
~MediaQueue() { Reset(); }
|
|
|
|
|
2016-04-25 05:13:55 +03:00
|
|
|
inline size_t GetSize() const {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2014-02-04 05:49:21 +04:00
|
|
|
return nsDeque::GetSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void Push(T* aItem) {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2019-04-25 20:08:27 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aItem);
|
2014-11-20 00:01:10 +03:00
|
|
|
NS_ADDREF(aItem);
|
2017-04-14 12:13:36 +03:00
|
|
|
MOZ_ASSERT(aItem->GetEndTime() >= aItem->mTime);
|
2014-02-04 05:49:21 +04:00
|
|
|
nsDeque::Push(aItem);
|
2015-11-25 10:15:05 +03:00
|
|
|
mPushEvent.Notify(RefPtr<T>(aItem));
|
2018-11-22 16:27:21 +03:00
|
|
|
// Pushing new data after queue has ended means that the stream is active
|
|
|
|
// again, so we should not mark it as ended.
|
|
|
|
if (mEndOfStream) {
|
|
|
|
mEndOfStream = false;
|
|
|
|
}
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
|
2014-11-20 00:01:10 +03:00
|
|
|
inline already_AddRefed<T> PopFront() {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
|
2014-03-11 07:44:09 +04:00
|
|
|
if (rv) {
|
2018-11-06 01:05:58 +03:00
|
|
|
mPopFrontEvent.Notify(rv);
|
2014-03-11 07:44:09 +04:00
|
|
|
}
|
2014-11-20 00:01:10 +03:00
|
|
|
return rv.forget();
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
|
2018-11-06 01:04:45 +03:00
|
|
|
inline already_AddRefed<T> PopBack() {
|
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
|
|
|
RefPtr<T> rv = dont_AddRef(static_cast<T*>(nsDeque::Pop()));
|
|
|
|
return rv.forget();
|
|
|
|
}
|
|
|
|
|
2016-04-25 05:13:55 +03:00
|
|
|
inline RefPtr<T> PeekFront() const {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2014-02-04 05:49:21 +04:00
|
|
|
return static_cast<T*>(nsDeque::PeekFront());
|
|
|
|
}
|
|
|
|
|
2018-11-06 01:04:45 +03:00
|
|
|
inline RefPtr<T> PeekBack() const {
|
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
|
|
|
return static_cast<T*>(nsDeque::Peek());
|
|
|
|
}
|
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
void Reset() {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2014-02-04 05:49:21 +04:00
|
|
|
while (GetSize() > 0) {
|
2016-04-19 18:04:02 +03:00
|
|
|
RefPtr<T> x = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
mEndOfStream = false;
|
|
|
|
}
|
|
|
|
|
2016-04-25 05:13:55 +03:00
|
|
|
bool AtEndOfStream() const {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2014-02-04 05:49:21 +04:00
|
|
|
return GetSize() == 0 && mEndOfStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if the media queue has had its last item added to it.
|
|
|
|
// This happens when the media stream has been completely decoded. Note this
|
|
|
|
// does not mean that the corresponding stream has finished playback.
|
2016-04-25 05:13:55 +03:00
|
|
|
bool IsFinished() const {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2014-02-04 05:49:21 +04:00
|
|
|
return mEndOfStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Informs the media queue that it won't be receiving any more items.
|
|
|
|
void Finish() {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2016-12-23 14:19:04 +03:00
|
|
|
if (!mEndOfStream) {
|
|
|
|
mEndOfStream = true;
|
|
|
|
mFinishEvent.Notify();
|
|
|
|
}
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the approximate number of microseconds of items in the queue.
|
|
|
|
int64_t Duration() {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2014-12-24 13:10:24 +03:00
|
|
|
if (GetSize() == 0) {
|
2014-02-04 05:49:21 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2016-04-25 09:36:07 +03:00
|
|
|
T* last = static_cast<T*>(nsDeque::Peek());
|
|
|
|
T* first = static_cast<T*>(nsDeque::PeekFront());
|
2017-04-14 12:13:36 +03:00
|
|
|
return (last->GetEndTime() - first->mTime).ToMicroseconds();
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void LockedForEach(nsDequeFunctor& aFunctor) const {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2014-02-04 05:49:21 +04:00
|
|
|
ForEach(aFunctor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extracts elements from the queue into aResult, in order.
|
|
|
|
// Elements whose start time is before aTime are ignored.
|
2015-10-18 08:24:48 +03:00
|
|
|
void GetElementsAfter(int64_t aTime, nsTArray<RefPtr<T>>* aResult) {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2015-11-15 16:48:08 +03:00
|
|
|
if (GetSize() == 0) return;
|
|
|
|
size_t i;
|
2014-02-04 05:49:21 +04:00
|
|
|
for (i = GetSize() - 1; i > 0; --i) {
|
|
|
|
T* v = static_cast<T*>(ObjectAt(i));
|
2017-04-14 09:14:08 +03:00
|
|
|
if (v->GetEndTime().ToMicroseconds() < aTime) break;
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
// Elements less than i have a end time before aTime. It's also possible
|
|
|
|
// that the element at i has a end time before aTime, but that's OK.
|
|
|
|
for (; i < GetSize(); ++i) {
|
2015-11-15 16:48:08 +03:00
|
|
|
RefPtr<T> elem = static_cast<T*>(ObjectAt(static_cast<size_t>(i)));
|
2014-11-20 00:01:10 +03:00
|
|
|
aResult->AppendElement(elem);
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-27 06:09:49 +03:00
|
|
|
void GetElementsAfter(const media::TimeUnit& aTime,
|
|
|
|
nsTArray<RefPtr<T>>* aResult) {
|
|
|
|
GetElementsAfter(aTime.ToMicroseconds(), aResult);
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
void GetFirstElements(uint32_t aMaxElements, nsTArray<RefPtr<T>>* aResult) {
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2015-11-15 16:48:08 +03:00
|
|
|
for (size_t i = 0; i < aMaxElements && i < GetSize(); ++i) {
|
2015-03-30 11:30:03 +03:00
|
|
|
*aResult->AppendElement() = static_cast<T*>(ObjectAt(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-22 12:18:47 +03:00
|
|
|
uint32_t AudioFramesCount() {
|
|
|
|
static_assert(mozilla::IsSame<T, AudioData>::value,
|
|
|
|
"Only usable with MediaQueue<AudioData>");
|
2017-07-04 20:47:15 +03:00
|
|
|
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
2014-02-04 05:49:21 +04:00
|
|
|
uint32_t frames = 0;
|
2015-11-15 16:48:08 +03:00
|
|
|
for (size_t i = 0; i < GetSize(); ++i) {
|
2014-02-04 05:49:21 +04:00
|
|
|
T* v = static_cast<T*>(ObjectAt(i));
|
2019-02-22 12:18:47 +03:00
|
|
|
frames += v->Frames();
|
2014-02-04 05:49:21 +04:00
|
|
|
}
|
|
|
|
return frames;
|
|
|
|
}
|
|
|
|
|
2018-11-06 01:05:58 +03:00
|
|
|
MediaEventSource<RefPtr<T>>& PopFrontEvent() { return mPopFrontEvent; }
|
2014-03-11 07:44:09 +04:00
|
|
|
|
2015-11-25 10:15:05 +03:00
|
|
|
MediaEventSource<RefPtr<T>>& PushEvent() { return mPushEvent; }
|
2015-08-06 05:14:15 +03:00
|
|
|
|
|
|
|
MediaEventSource<void>& FinishEvent() { return mFinishEvent; }
|
2014-03-11 07:44:09 +04:00
|
|
|
|
2014-02-04 05:49:21 +04:00
|
|
|
private:
|
2017-07-04 20:47:15 +03:00
|
|
|
mutable RecursiveMutex mRecursiveMutex;
|
2018-11-06 01:05:58 +03:00
|
|
|
MediaEventProducer<RefPtr<T>> mPopFrontEvent;
|
2015-11-25 10:15:05 +03:00
|
|
|
MediaEventProducer<RefPtr<T>> mPushEvent;
|
2015-08-06 05:14:15 +03:00
|
|
|
MediaEventProducer<void> mFinishEvent;
|
2014-02-04 05:49:21 +04:00
|
|
|
// True when we've decoded the last frame of data in the
|
|
|
|
// bitstream for which we're queueing frame data.
|
|
|
|
bool mEndOfStream;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif
|