Bug 1349883 - part 3: resolve decode promise according to buffer status. r=jya
MozReview-Commit-ID: JwOOi56t30Y
--- a/dom/media/platforms/android/JavaCallbacksSupport.h
+++ b/dom/media/platforms/android/JavaCallbacksSupport.h
@@ -18,22 +18,22 @@ public:
typedef java::CodecProxy::NativeCallbacks::Natives<JavaCallbacksSupport> Base;
using Base::AttachNative;
using Base::DisposeNative;
JavaCallbacksSupport() : mCanceled(false) { }
virtual ~JavaCallbacksSupport() { }
- virtual void HandleInputExhausted() = 0;
+ virtual void HandleInput(int64_t aTimestamp, bool aProcessed) = 0;
- void OnInputExhausted()
+ void OnInputStatus(jlong aTimestamp, bool aProcessed)
{
if (!mCanceled) {
- HandleInputExhausted();
+ HandleInput(aTimestamp, aProcessed);
}
}
virtual void HandleOutput(java::Sample::Param aSample) = 0;
void OnOutput(jni::Object::Param aSample)
{
if (!mCanceled) {
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -90,19 +90,19 @@ public:
gfx::IntSize mDisplaySize;
};
class CallbacksSupport final : public JavaCallbacksSupport
{
public:
CallbacksSupport(RemoteVideoDecoder* aDecoder) : mDecoder(aDecoder) { }
- void HandleInputExhausted() override
+ void HandleInput(int64_t aTimestamp, bool aProcessed) override
{
- mDecoder->ReturnDecodedData();
+ mDecoder->UpdateInputStatus(aTimestamp, aProcessed);
}
void HandleOutput(Sample::Param aSample) override
{
UniquePtr<VideoData::Listener> releaseSample(
new RenderOrReleaseOutput(mDecoder->mJavaDecoder, aSample));
BufferInfo::LocalRef info = aSample->Info();
@@ -138,18 +138,17 @@ public:
gl::OriginPos::BottomLeft);
RefPtr<VideoData> v = VideoData::CreateFromImage(
inputInfo.mDisplaySize, offset, presentationTimeUs, inputInfo.mDurationUs,
img, !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME),
presentationTimeUs);
v->SetListener(Move(releaseSample));
-
- mDecoder->Output(v);
+ mDecoder->UpdateOutputStatus(v);
}
if (isEOS) {
mDecoder->DrainComplete();
}
}
void HandleError(const MediaResult& aError) override
@@ -292,19 +291,19 @@ public:
}
private:
class CallbacksSupport final : public JavaCallbacksSupport
{
public:
CallbacksSupport(RemoteAudioDecoder* aDecoder) : mDecoder(aDecoder) { }
- void HandleInputExhausted() override
+ void HandleInput(int64_t aTimestamp, bool aProcessed) override
{
- mDecoder->ReturnDecodedData();
+ mDecoder->UpdateInputStatus(aTimestamp, aProcessed);
}
void HandleOutput(Sample::Param aSample) override
{
BufferInfo::LocalRef info = aSample->Info();
int32_t flags;
bool ok = NS_SUCCEEDED(info->Flags(&flags));
@@ -342,17 +341,17 @@ private:
jni::ByteBuffer::New(audio.get(), size);
aSample->WriteToByteBuffer(dest);
RefPtr<AudioData> data = new AudioData(
0, presentationTimeUs,
FramesToUsecs(numFrames, mOutputSampleRate).value(), numFrames,
Move(audio), mOutputChannels, mOutputSampleRate);
- mDecoder->Output(data);
+ mDecoder->UpdateOutputStatus(data);
}
if ((flags & MediaCodec::BUFFER_FLAG_END_OF_STREAM) != 0) {
mDecoder->DrainComplete();
}
}
void HandleOutputFormatChanged(MediaFormat::Param aFormat) override
@@ -432,25 +431,27 @@ RemoteDataDecoder::RemoteDataDecoder(Med
MediaFormat::Param aFormat,
const nsString& aDrmStubId,
TaskQueue* aTaskQueue)
: mType(aType)
, mMimeType(aMimeType)
, mFormat(aFormat)
, mDrmStubId(aDrmStubId)
, mTaskQueue(aTaskQueue)
+ , mNumPendingInputs(0)
{
}
RefPtr<MediaDataDecoder::FlushPromise>
RemoteDataDecoder::Flush()
{
RefPtr<RemoteDataDecoder> self = this;
return InvokeAsync(mTaskQueue, __func__, [self, this]() {
mDecodedData.Clear();
+ mNumPendingInputs = 0;
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
mDrainStatus = DrainStatus::DRAINED;
mJavaDecoder->Flush();
return FlushPromise::CreateAndResolve(true, __func__);
});
}
@@ -538,21 +539,51 @@ RemoteDataDecoder::Decode(MediaRawData*
? mDecodePromise.Ensure(__func__)
: DecodePromise::CreateAndReject(
MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
});
}
void
-RemoteDataDecoder::Output(MediaData* aSample)
+RemoteDataDecoder::UpdateInputStatus(int64_t aTimestamp, bool aProcessed)
{
if (!mTaskQueue->IsCurrentThreadIn()) {
mTaskQueue->Dispatch(
- NewRunnableMethod<MediaData*>(this, &RemoteDataDecoder::Output, aSample));
+ NewRunnableMethod<int64_t, bool>(this,
+ &RemoteDataDecoder::UpdateInputStatus,
+ aTimestamp,
+ aProcessed));
+ return;
+ }
+ AssertOnTaskQueue();
+ if (mShutdown) {
+ return;
+ }
+
+ if (!aProcessed) {
+ mNumPendingInputs++;
+ } else if (mNumPendingInputs > 0) {
+ mNumPendingInputs--;
+ }
+
+ if (mNumPendingInputs == 0 || // Input has been processed, request the next one.
+ !mDecodedData.IsEmpty()) { // Previous output arrived before Decode().
+ ReturnDecodedData();
+ }
+}
+
+void
+RemoteDataDecoder::UpdateOutputStatus(MediaData* aSample)
+{
+ if (!mTaskQueue->IsCurrentThreadIn()) {
+ mTaskQueue->Dispatch(
+ NewRunnableMethod<MediaData*>(this,
+ &RemoteDataDecoder::UpdateOutputStatus,
+ aSample));
return;
}
AssertOnTaskQueue();
if (mShutdown) {
return;
}
mDecodedData.AppendElement(aSample);
ReturnDecodedData();
--- a/dom/media/platforms/android/RemoteDataDecoder.h
+++ b/dom/media/platforms/android/RemoteDataDecoder.h
@@ -40,17 +40,18 @@ protected:
virtual ~RemoteDataDecoder() { }
RemoteDataDecoder(MediaData::Type aType,
const nsACString& aMimeType,
java::sdk::MediaFormat::Param aFormat,
const nsString& aDrmStubId, TaskQueue* aTaskQueue);
// Methods only called on mTaskQueue.
RefPtr<ShutdownPromise> ProcessShutdown();
- void Output(MediaData* aSample);
+ void UpdateInputStatus(int64_t aTimestamp, bool aProcessed);
+ void UpdateOutputStatus(MediaData* aSample);
void ReturnDecodedData();
void DrainComplete();
void Error(const MediaResult& aError);
void AssertOnTaskQueue()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
}
@@ -71,13 +72,14 @@ protected:
enum class DrainStatus
{
DRAINED,
DRAINABLE,
DRAINING,
};
DrainStatus mDrainStatus = DrainStatus::DRAINED;
DecodedData mDecodedData;
+ size_t mNumPendingInputs;
};
} // namespace mozilla
#endif
--- a/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp
@@ -71,17 +71,17 @@ public:
if(mEncodedImage._buffer) {
delete [] mEncodedImage._buffer;
}
mEncodedImage._buffer = newBuffer;
mEncodedImage._size = minimumSize;
}
}
- void HandleInputExhausted() override
+ void HandleInput(jlong aTimestamp, bool aProcessed) override
{
CSFLogDebug(logTag, "%s %p", __FUNCTION__, this);
}
void HandleOutputFormatChanged(MediaFormat::Param aFormat) override
{
CSFLogDebug(logTag, "%s %p", __FUNCTION__, this);
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java
@@ -30,25 +30,25 @@ public final class CodecProxy {
private boolean mIsEncoder;
private FormatParam mFormat;
private Surface mOutputSurface;
private CallbacksForwarder mCallbacks;
private String mRemoteDrmStubId;
private Queue<Sample> mSurfaceOutputs = new ConcurrentLinkedQueue<>();
public interface Callbacks {
- void onInputExhausted();
+ void onInputStatus(long timestamp, boolean processed);
void onOutputFormatChanged(MediaFormat format);
void onOutput(Sample output);
void onError(boolean fatal);
}
@WrapForJNI
public static class NativeCallbacks extends JNIObject implements Callbacks {
- public native void onInputExhausted();
+ public native void onInputStatus(long timestamp, boolean processed);
public native void onOutputFormatChanged(MediaFormat format);
public native void onOutput(Sample output);
public native void onError(boolean fatal);
@Override // JNIObject
protected void disposeNative() {
throw new UnsupportedOperationException();
}
@@ -60,24 +60,24 @@ public final class CodecProxy {
CallbacksForwarder(Callbacks callbacks) {
mCallbacks = callbacks;
}
@Override
public synchronized void onInputQueued(long timestamp) throws RemoteException {
if (!mEndOfInput) {
- mCallbacks.onInputExhausted();
+ mCallbacks.onInputStatus(timestamp, true /* processed */);
}
}
@Override
public synchronized void onInputPending(long timestamp) throws RemoteException {
if (!mEndOfInput) {
- mCallbacks.onInputExhausted();
+ mCallbacks.onInputStatus(timestamp, false /* processed */);
}
}
@Override
public void onOutputFormatChanged(FormatParam format) throws RemoteException {
mCallbacks.onOutputFormatChanged(format.asFormat());
}
--- a/widget/android/GeneratedJNINatives.h
+++ b/widget/android/GeneratedJNINatives.h
@@ -449,19 +449,19 @@ public:
template<class Impl>
const JNINativeMethod CodecProxy::NativeCallbacks::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnError_t>(
mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnError_t, Impl>
::template Wrap<&Impl::OnError>),
- mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnInputExhausted_t>(
- mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnInputExhausted_t, Impl>
- ::template Wrap<&Impl::OnInputExhausted>),
+ mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnInputStatus_t>(
+ mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnInputStatus_t, Impl>
+ ::template Wrap<&Impl::OnInputStatus>),
mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnOutput_t>(
mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnOutput_t, Impl>
::template Wrap<&Impl::OnOutput>),
mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnOutputFormatChanged_t>(
mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnOutputFormatChanged_t, Impl>
::template Wrap<&Impl::OnOutputFormatChanged>)
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -1820,18 +1820,18 @@ constexpr char CodecProxy::NativeCallbac
auto CodecProxy::NativeCallbacks::DisposeNative() const -> void
{
return mozilla::jni::Method<DisposeNative_t>::Call(NativeCallbacks::mCtx, nullptr);
}
constexpr char CodecProxy::NativeCallbacks::OnError_t::name[];
constexpr char CodecProxy::NativeCallbacks::OnError_t::signature[];
-constexpr char CodecProxy::NativeCallbacks::OnInputExhausted_t::name[];
-constexpr char CodecProxy::NativeCallbacks::OnInputExhausted_t::signature[];
+constexpr char CodecProxy::NativeCallbacks::OnInputStatus_t::name[];
+constexpr char CodecProxy::NativeCallbacks::OnInputStatus_t::signature[];
constexpr char CodecProxy::NativeCallbacks::OnOutput_t::name[];
constexpr char CodecProxy::NativeCallbacks::OnOutput_t::signature[];
constexpr char CodecProxy::NativeCallbacks::OnOutputFormatChanged_t::name[];
constexpr char CodecProxy::NativeCallbacks::OnOutputFormatChanged_t::signature[];
const char MediaDrmProxy::name[] =
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -5182,24 +5182,26 @@ public:
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
- struct OnInputExhausted_t {
+ struct OnInputStatus_t {
typedef NativeCallbacks Owner;
typedef void ReturnType;
typedef void SetterType;
- typedef mozilla::jni::Args<> Args;
- static constexpr char name[] = "onInputExhausted";
- static constexpr char signature[] =
- "()V";
+ typedef mozilla::jni::Args<
+ int64_t,
+ bool> Args;
+ static constexpr char name[] = "onInputStatus";
+ static constexpr char signature[] =
+ "(JZ)V";
static const bool isStatic = false;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};