Bug 1265755 - Support encoder case for CodecProxy; r=jolin

MozReview-Commit-ID: 4cEZQs8spo7

--HG--
extra : rebase_source : 33989d576cbd15194c5d740745fd5ddf35958346
This commit is contained in:
Munro Mengjue Chiang 2017-03-30 08:51:12 +08:00
Родитель 0d0b538b3e
Коммит 8c7e3d6e57
10 изменённых файлов: 145 добавлений и 17 удалений

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

@ -196,7 +196,8 @@ public:
JavaCallbacksSupport::AttachNative( JavaCallbacksSupport::AttachNative(
mJavaCallbacks, mozilla::MakeUnique<CallbacksSupport>(this)); mJavaCallbacks, mozilla::MakeUnique<CallbacksSupport>(this));
mJavaDecoder = CodecProxy::Create(mFormat, mJavaDecoder = CodecProxy::Create(false, // false indicates to create a decoder and true denotes encoder
mFormat,
mSurfaceTexture->JavaSurface(), mSurfaceTexture->JavaSurface(),
mJavaCallbacks, mJavaCallbacks,
mDrmStubId); mDrmStubId);
@ -276,7 +277,7 @@ public:
mJavaCallbacks, mozilla::MakeUnique<CallbacksSupport>(this)); mJavaCallbacks, mozilla::MakeUnique<CallbacksSupport>(this));
mJavaDecoder = mJavaDecoder =
CodecProxy::Create(mFormat, nullptr, mJavaCallbacks, mDrmStubId); CodecProxy::Create(false, mFormat, nullptr, mJavaCallbacks, mDrmStubId);
if (mJavaDecoder == nullptr) { if (mJavaDecoder == nullptr) {
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
__func__); __func__);

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

@ -24,4 +24,5 @@ interface ICodec {
oneway void queueInput(in Sample sample); oneway void queueInput(in Sample sample);
oneway void releaseOutput(in Sample sample, in boolean render); oneway void releaseOutput(in Sample sample, in boolean render);
oneway void setRates(in int newBitRate);
} }

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

@ -35,6 +35,7 @@ public interface AsyncCodec {
public abstract ByteBuffer getInputBuffer(int index); public abstract ByteBuffer getInputBuffer(int index);
public abstract ByteBuffer getOutputBuffer(int index); public abstract ByteBuffer getOutputBuffer(int index);
public abstract void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags); public abstract void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags);
public abstract void setRates(int newBitRate);
public abstract void queueSecureInputBuffer(int index, int offset, CryptoInfo info, long presentationTimeUs, int flags); public abstract void queueSecureInputBuffer(int index, int offset, CryptoInfo info, long presentationTimeUs, int flags);
public abstract void releaseOutputBuffer(int index, boolean render); public abstract void releaseOutputBuffer(int index, boolean render);
} }

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

@ -339,7 +339,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
if (DEBUG) { Log.d(LOGTAG, "configure " + this); } if (DEBUG) { Log.d(LOGTAG, "configure " + this); }
MediaFormat fmt = format.asFormat(); MediaFormat fmt = format.asFormat();
String codecName = getDecoderForFormat(fmt); String codecName = getCodecForFormat(fmt, flags == MediaCodec.CONFIGURE_FLAG_ENCODE ? true : false);
if (codecName == null) { if (codecName == null) {
Log.e(LOGTAG, "FAIL: cannot find codec"); Log.e(LOGTAG, "FAIL: cannot find codec");
return false; return false;
@ -401,7 +401,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
mCodec = null; mCodec = null;
} }
private String getDecoderForFormat(MediaFormat format) { private String getCodecForFormat(MediaFormat format, boolean isEncoder) {
String mime = format.getString(MediaFormat.KEY_MIME); String mime = format.getString(MediaFormat.KEY_MIME);
if (mime == null) { if (mime == null) {
return null; return null;
@ -409,7 +409,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
int numCodecs = MediaCodecList.getCodecCount(); int numCodecs = MediaCodecList.getCodecCount();
for (int i = 0; i < numCodecs; i++) { for (int i = 0; i < numCodecs; i++) {
MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
if (info.isEncoder()) { if (info.isEncoder() == !isEncoder) {
continue; continue;
} }
String[] types = info.getSupportedTypes(); String[] types = info.getSupportedTypes();
@ -493,6 +493,15 @@ import java.util.concurrent.ConcurrentLinkedQueue;
mInputProcessor.onSample(sample); mInputProcessor.onSample(sample);
} }
@Override
public synchronized void setRates(int newBitRate) {
try {
mCodec.setRates(newBitRate);
} catch (Exception e) {
reportError(Error.FATAL, e);
}
}
@Override @Override
public synchronized void releaseOutput(Sample sample, boolean render) { public synchronized void releaseOutput(Sample sample, boolean render) {
try { try {

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

@ -27,6 +27,7 @@ public final class CodecProxy {
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private ICodec mRemote; private ICodec mRemote;
private boolean mIsEncoder;
private FormatParam mFormat; private FormatParam mFormat;
private Surface mOutputSurface; private Surface mOutputSurface;
private CallbacksForwarder mCallbacks; private CallbacksForwarder mCallbacks;
@ -102,21 +103,24 @@ public final class CodecProxy {
} }
@WrapForJNI @WrapForJNI
public static CodecProxy create(MediaFormat format, public static CodecProxy create(boolean isEncoder,
MediaFormat format,
Surface surface, Surface surface,
Callbacks callbacks, Callbacks callbacks,
String drmStubId) { String drmStubId) {
return RemoteManager.getInstance().createCodec(format, surface, callbacks, drmStubId); return RemoteManager.getInstance().createCodec(isEncoder, format, surface, callbacks, drmStubId);
} }
public static CodecProxy createCodecProxy(MediaFormat format, public static CodecProxy createCodecProxy(boolean isEncoder,
MediaFormat format,
Surface surface, Surface surface,
Callbacks callbacks, Callbacks callbacks,
String drmStubId) { String drmStubId) {
return new CodecProxy(format, surface, callbacks, drmStubId); return new CodecProxy(isEncoder, format, surface, callbacks, drmStubId);
} }
private CodecProxy(MediaFormat format, Surface surface, Callbacks callbacks, String drmStubId) { private CodecProxy(boolean isEncoder, MediaFormat format, Surface surface, Callbacks callbacks, String drmStubId) {
mIsEncoder = isEncoder;
mFormat = new FormatParam(format); mFormat = new FormatParam(format);
mOutputSurface = surface; mOutputSurface = surface;
mRemoteDrmStubId = drmStubId; mRemoteDrmStubId = drmStubId;
@ -126,7 +130,7 @@ public final class CodecProxy {
boolean init(ICodec remote) { boolean init(ICodec remote) {
try { try {
remote.setCallbacks(mCallbacks); remote.setCallbacks(mCallbacks);
if (!remote.configure(mFormat, mOutputSurface, 0, mRemoteDrmStubId)) { if (!remote.configure(mFormat, mOutputSurface, mIsEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0, mRemoteDrmStubId)) {
return false; return false;
} }
remote.start(); remote.start();
@ -257,6 +261,32 @@ public final class CodecProxy {
return true; return true;
} }
@WrapForJNI
public synchronized boolean setRates(int newBitRate) {
if (!mIsEncoder) {
Log.w(LOGTAG, "this api is encoder-only");
return false;
}
if (android.os.Build.VERSION.SDK_INT < 19) {
Log.w(LOGTAG, "this api was added in API level 19");
return false;
}
if (mRemote == null) {
Log.w(LOGTAG, "codec already ended");
return true;
}
try {
mRemote.setRates(newBitRate);
} catch (RemoteException e) {
Log.e(LOGTAG, "remote fail to set rates:" + newBitRate);
e.printStackTrace();
}
return true;
}
@WrapForJNI @WrapForJNI
public synchronized boolean releaseOutput(Sample sample, boolean render) { public synchronized boolean releaseOutput(Sample sample, boolean render) {
if (!mSurfaceOutputs.remove(sample)) { if (!mSurfaceOutputs.remove(sample)) {

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

@ -19,6 +19,11 @@ import java.nio.ByteBuffer;
* <li>{@link MediaFormat#KEY_HEIGHT}</li> * <li>{@link MediaFormat#KEY_HEIGHT}</li>
* <li>{@link MediaFormat#KEY_CHANNEL_COUNT}</li> * <li>{@link MediaFormat#KEY_CHANNEL_COUNT}</li>
* <li>{@link MediaFormat#KEY_SAMPLE_RATE}</li> * <li>{@link MediaFormat#KEY_SAMPLE_RATE}</li>
* <li>{@link MediaFormat#KEY_BIT_RATE}</li>
* <li>{@link MediaFormat#KEY_BITRATE_MODE}</li>
* <li>{@link MediaFormat#KEY_COLOR_FORMAT}</li>
* <li>{@link MediaFormat#KEY_FRAME_RATE}</li>
* <li>{@link MediaFormat#KEY_I_FRAME_INTERVAL}</li>
* <li>"csd-0"</li> * <li>"csd-0"</li>
* <li>"csd-1"</li> * <li>"csd-1"</li>
* </ul> * </ul>
@ -94,6 +99,26 @@ public final class FormatParam implements Parcelable {
mFormat.setByteBuffer(KEY_CONFIG_1, mFormat.setByteBuffer(KEY_CONFIG_1,
ByteBuffer.wrap(bundle.getByteArray((KEY_CONFIG_1)))); ByteBuffer.wrap(bundle.getByteArray((KEY_CONFIG_1))));
} }
if (bundle.containsKey(MediaFormat.KEY_BIT_RATE)) {
mFormat.setInteger(MediaFormat.KEY_BIT_RATE,
bundle.getInt(MediaFormat.KEY_BIT_RATE));
}
if (bundle.containsKey(MediaFormat.KEY_BITRATE_MODE)) {
mFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
bundle.getInt(MediaFormat.KEY_BITRATE_MODE));
}
if (bundle.containsKey(MediaFormat.KEY_COLOR_FORMAT)) {
mFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
bundle.getInt(MediaFormat.KEY_COLOR_FORMAT));
}
if (bundle.containsKey(MediaFormat.KEY_FRAME_RATE)) {
mFormat.setInteger(MediaFormat.KEY_FRAME_RATE,
bundle.getInt(MediaFormat.KEY_FRAME_RATE));
}
if (bundle.containsKey(MediaFormat.KEY_I_FRAME_INTERVAL)) {
mFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,
bundle.getInt(MediaFormat.KEY_I_FRAME_INTERVAL));
}
} }
@Override @Override
@ -128,6 +153,21 @@ public final class FormatParam implements Parcelable {
bundle.putByteArray(KEY_CONFIG_1, bundle.putByteArray(KEY_CONFIG_1,
Sample.byteArrayFromBuffer(bytes, 0, bytes.capacity())); Sample.byteArrayFromBuffer(bytes, 0, bytes.capacity()));
} }
if (mFormat.containsKey(MediaFormat.KEY_BIT_RATE)) {
bundle.putInt(MediaFormat.KEY_BIT_RATE, mFormat.getInteger(MediaFormat.KEY_BIT_RATE));
}
if (mFormat.containsKey(MediaFormat.KEY_BITRATE_MODE)) {
bundle.putInt(MediaFormat.KEY_BITRATE_MODE, mFormat.getInteger(MediaFormat.KEY_BITRATE_MODE));
}
if (mFormat.containsKey(MediaFormat.KEY_COLOR_FORMAT)) {
bundle.putInt(MediaFormat.KEY_COLOR_FORMAT, mFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT));
}
if (mFormat.containsKey(MediaFormat.KEY_FRAME_RATE)) {
bundle.putInt(MediaFormat.KEY_FRAME_RATE, mFormat.getInteger(MediaFormat.KEY_FRAME_RATE));
}
if (mFormat.containsKey(MediaFormat.KEY_I_FRAME_INTERVAL)) {
bundle.putInt(MediaFormat.KEY_I_FRAME_INTERVAL, mFormat.getInteger(MediaFormat.KEY_I_FRAME_INTERVAL));
}
return bundle; return bundle;
} }
} }

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

@ -13,6 +13,7 @@ import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.Surface; import android.view.Surface;
@ -332,12 +333,27 @@ final class JellyBeanAsyncCodec implements AsyncCodec {
} }
} }
@Override
public final void setRates(int newBitRate) {
if (android.os.Build.VERSION.SDK_INT >= 19) {
Bundle params = new Bundle();
params.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, newBitRate * 1000);
mCodec.setParameters(params);
}
}
@Override @Override
public final void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags) { public final void queueInputBuffer(int index, int offset, int size, long presentationTimeUs, int flags) {
assertCallbacks(); assertCallbacks();
mInputEnded = (flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0; mInputEnded = (flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
if ((android.os.Build.VERSION.SDK_INT >= 19) && ((flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0)) {
Bundle params = new Bundle();
params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
mCodec.setParameters(params);
}
try { try {
mCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags); mCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {

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

@ -109,7 +109,8 @@ public final class RemoteManager implements IBinder.DeathRecipient {
return mConnection.connect(); return mConnection.connect();
} }
public synchronized CodecProxy createCodec(MediaFormat format, public synchronized CodecProxy createCodec(boolean isEncoder,
MediaFormat format,
Surface surface, Surface surface,
CodecProxy.Callbacks callbacks, CodecProxy.Callbacks callbacks,
String drmStubId) { String drmStubId) {
@ -119,7 +120,7 @@ public final class RemoteManager implements IBinder.DeathRecipient {
} }
try { try {
ICodec remote = mRemote.createCodec(); ICodec remote = mRemote.createCodec();
CodecProxy proxy = CodecProxy.createCodecProxy(format, surface, callbacks, drmStubId); CodecProxy proxy = CodecProxy.createCodecProxy(isEncoder, format, surface, callbacks, drmStubId);
if (proxy.init(remote)) { if (proxy.init(remote)) {
mProxies.add(proxy); mProxies.add(proxy);
return proxy; return proxy;

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

@ -184,9 +184,9 @@ const char CodecProxy::name[] =
constexpr char CodecProxy::Create_t::name[]; constexpr char CodecProxy::Create_t::name[];
constexpr char CodecProxy::Create_t::signature[]; constexpr char CodecProxy::Create_t::signature[];
auto CodecProxy::Create(mozilla::jni::Object::Param a0, mozilla::jni::Object::Param a1, mozilla::jni::Object::Param a2, mozilla::jni::String::Param a3) -> CodecProxy::LocalRef auto CodecProxy::Create(bool a0, mozilla::jni::Object::Param a1, mozilla::jni::Object::Param a2, mozilla::jni::Object::Param a3, mozilla::jni::String::Param a4) -> CodecProxy::LocalRef
{ {
return mozilla::jni::Method<Create_t>::Call(CodecProxy::Context(), nullptr, a0, a1, a2, a3); return mozilla::jni::Method<Create_t>::Call(CodecProxy::Context(), nullptr, a0, a1, a2, a3, a4);
} }
constexpr char CodecProxy::Flush_t::name[]; constexpr char CodecProxy::Flush_t::name[];
@ -229,6 +229,14 @@ auto CodecProxy::ReleaseOutput(mozilla::jni::Object::Param a0, bool a1) const ->
return mozilla::jni::Method<ReleaseOutput_t>::Call(CodecProxy::mCtx, nullptr, a0, a1); return mozilla::jni::Method<ReleaseOutput_t>::Call(CodecProxy::mCtx, nullptr, a0, a1);
} }
constexpr char CodecProxy::SetRates_t::name[];
constexpr char CodecProxy::SetRates_t::signature[];
auto CodecProxy::SetRates(int32_t a0) const -> bool
{
return mozilla::jni::Method<SetRates_t>::Call(CodecProxy::mCtx, nullptr, a0);
}
const char CodecProxy::NativeCallbacks::name[] = const char CodecProxy::NativeCallbacks::name[] =
"org/mozilla/gecko/media/CodecProxy$NativeCallbacks"; "org/mozilla/gecko/media/CodecProxy$NativeCallbacks";

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

@ -668,13 +668,14 @@ public:
typedef CodecProxy::LocalRef ReturnType; typedef CodecProxy::LocalRef ReturnType;
typedef CodecProxy::Param SetterType; typedef CodecProxy::Param SetterType;
typedef mozilla::jni::Args< typedef mozilla::jni::Args<
bool,
mozilla::jni::Object::Param, mozilla::jni::Object::Param,
mozilla::jni::Object::Param, mozilla::jni::Object::Param,
mozilla::jni::Object::Param, mozilla::jni::Object::Param,
mozilla::jni::String::Param> Args; mozilla::jni::String::Param> Args;
static constexpr char name[] = "create"; static constexpr char name[] = "create";
static constexpr char signature[] = static constexpr char signature[] =
"(Landroid/media/MediaFormat;Landroid/view/Surface;Lorg/mozilla/gecko/media/CodecProxy$Callbacks;Ljava/lang/String;)Lorg/mozilla/gecko/media/CodecProxy;"; "(ZLandroid/media/MediaFormat;Landroid/view/Surface;Lorg/mozilla/gecko/media/CodecProxy$Callbacks;Ljava/lang/String;)Lorg/mozilla/gecko/media/CodecProxy;";
static const bool isStatic = true; static const bool isStatic = true;
static const mozilla::jni::ExceptionMode exceptionMode = static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT; mozilla::jni::ExceptionMode::ABORT;
@ -684,7 +685,7 @@ public:
mozilla::jni::DispatchTarget::CURRENT; mozilla::jni::DispatchTarget::CURRENT;
}; };
static auto Create(mozilla::jni::Object::Param, mozilla::jni::Object::Param, mozilla::jni::Object::Param, mozilla::jni::String::Param) -> CodecProxy::LocalRef; static auto Create(bool, mozilla::jni::Object::Param, mozilla::jni::Object::Param, mozilla::jni::Object::Param, mozilla::jni::String::Param) -> CodecProxy::LocalRef;
struct Flush_t { struct Flush_t {
typedef CodecProxy Owner; typedef CodecProxy Owner;
@ -786,6 +787,26 @@ public:
auto ReleaseOutput(mozilla::jni::Object::Param, bool) const -> bool; auto ReleaseOutput(mozilla::jni::Object::Param, bool) const -> bool;
struct SetRates_t {
typedef CodecProxy Owner;
typedef bool ReturnType;
typedef bool SetterType;
typedef mozilla::jni::Args<
int32_t> Args;
static constexpr char name[] = "setRates";
static constexpr char signature[] =
"(I)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 SetRates(int32_t) const -> bool;
static const mozilla::jni::CallingThread callingThread = static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY; mozilla::jni::CallingThread::ANY;