Bug 1299068 - part 5: release/render buffers when VideoData sent to compositor. r=snorp

MozReview-Commit-ID: JmEKLKlJnaL

--HG--
extra : rebase_source : 5177ed35206aad3423b9960ea5e9e59459540cde
This commit is contained in:
John Lin 2016-11-30 17:55:52 +08:00
Родитель 28b5d4c496
Коммит 0c318ba97d
4 изменённых файлов: 122 добавлений и 4 удалений

Просмотреть файл

@ -114,6 +114,40 @@ struct SampleTime final
class RemoteVideoDecoder final : public RemoteDataDecoder
{
public:
// Hold an output buffer and render it to the surface when the frame is sent to compositor, or
// release it if not presented.
class RenderOrReleaseOutput : public VideoData::Listener
{
public:
RenderOrReleaseOutput(java::CodecProxy::Param aCodec, java::Sample::Param aSample)
: mCodec(aCodec),
mSample(aSample)
{}
~RenderOrReleaseOutput()
{
ReleaseOutput(false);
}
void OnSentToCompositor() override
{
ReleaseOutput(true);
mCodec = nullptr;
mSample = nullptr;
}
private:
void ReleaseOutput(bool aToRender)
{
if (mCodec && mSample) {
mCodec->ReleaseOutput(mSample, aToRender);
}
}
java::CodecProxy::GlobalRef mCodec;
java::Sample::GlobalRef mSample;
};
class CallbacksSupport final : public JavaCallbacksSupport
{
public:
@ -168,6 +202,9 @@ public:
mDecoder->mConfig.mDisplay.width,
mDecoder->mConfig.mDisplay.height));
UniquePtr<VideoData::Listener> listener(new RenderOrReleaseOutput(mDecoder->mJavaDecoder, aSample));
v->SetListener(Move(listener));
mDecoderCallback->Output(v);
}

Просмотреть файл

@ -18,6 +18,8 @@ import org.mozilla.gecko.mozglue.JNIObject;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
// Proxy class of ICodec binder.
public final class CodecProxy {
@ -29,6 +31,7 @@ public final class CodecProxy {
private Surface mOutputSurface;
private CallbacksForwarder mCallbacks;
private String mRemoteDrmStubId;
private Queue<Sample> mSurfaceOutputs = new ConcurrentLinkedQueue<>();
public interface Callbacks {
void onInputExhausted();
@ -67,9 +70,18 @@ public final class CodecProxy {
@Override
public void onOutput(Sample sample) throws RemoteException {
mCallbacks.onOutput(sample);
mRemote.releaseOutput(sample, true);
sample.dispose();
if (mOutputSurface != null) {
// Don't render to surface just yet. Callback will make that happen when it's time.
if (!sample.isEOS() || sample.info.size > 0) {
mSurfaceOutputs.offer(sample);
}
mCallbacks.onOutput(sample);
} else {
// Non-surface output needs no rendering.
mCallbacks.onOutput(sample);
mRemote.releaseOutput(sample, false);
sample.dispose();
}
}
@Override
@ -196,6 +208,21 @@ public final class CodecProxy {
return true;
}
if (DEBUG) Log.d(LOGTAG, "release " + this);
if (!mSurfaceOutputs.isEmpty()) {
// Flushing output buffers to surface may cause some frames to be skipped and
// should not happen unless caller release codec before processing all buffers.
Log.w(LOGTAG, "release codec when " + mSurfaceOutputs.size() + " output buffers unhandled");
try {
for (Sample s : mSurfaceOutputs) {
mRemote.releaseOutput(s, true);
}
} catch (RemoteException e) {
e.printStackTrace();
}
mSurfaceOutputs.clear();
}
try {
RemoteManager.getInstance().releaseCodec(this);
} catch (DeadObjectException e) {
@ -207,7 +234,32 @@ public final class CodecProxy {
return true;
}
public synchronized void reportError(boolean fatal) {
@WrapForJNI
public synchronized boolean releaseOutput(Sample sample, boolean render) {
if (!mSurfaceOutputs.remove(sample)) {
if (mRemote != null) Log.w(LOGTAG, "already released: " + sample);
return true;
}
if (mRemote == null) {
Log.w(LOGTAG, "codec already ended");
sample.dispose();
return true;
}
if (DEBUG && !render) Log.d(LOGTAG, "drop output:" + sample.info.presentationTimeUs);
try {
mRemote.releaseOutput(sample, render);
} catch (RemoteException e) {
e.printStackTrace();
}
sample.dispose();
return true;
}
/* package */ synchronized void reportError(boolean fatal) {
mCallbacks.reportError(fatal);
}
}

Просмотреть файл

@ -221,6 +221,14 @@ auto CodecProxy::Release() const -> bool
return mozilla::jni::Method<Release_t>::Call(CodecProxy::mCtx, nullptr);
}
constexpr char CodecProxy::ReleaseOutput_t::name[];
constexpr char CodecProxy::ReleaseOutput_t::signature[];
auto CodecProxy::ReleaseOutput(mozilla::jni::Object::Param a0, bool a1) const -> bool
{
return mozilla::jni::Method<ReleaseOutput_t>::Call(CodecProxy::mCtx, nullptr, a0, a1);
}
const char CodecProxy::NativeCallbacks::name[] =
"org/mozilla/gecko/media/CodecProxy$NativeCallbacks";

Просмотреть файл

@ -765,6 +765,27 @@ public:
auto Release() const -> bool;
struct ReleaseOutput_t {
typedef CodecProxy Owner;
typedef bool ReturnType;
typedef bool SetterType;
typedef mozilla::jni::Args<
mozilla::jni::Object::Param,
bool> Args;
static constexpr char name[] = "releaseOutput";
static constexpr char signature[] =
"(Lorg/mozilla/gecko/media/Sample;Z)Z";
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;
};
auto ReleaseOutput(mozilla::jni::Object::Param, bool) const -> bool;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;