зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1295106 - Part 3: introduce shared memory implemented with MemoryFile and support it in Sample. r=jchen,snorp
MozReview-Commit-ID: H33MJRgFvGB --HG-- extra : rebase_source : 9b18f469a4e62cd734f081ec8a8a2388fe258651
This commit is contained in:
Родитель
ea7f78cbde
Коммит
4b2aac0604
|
@ -14,6 +14,7 @@ import android.os.TransactionTooLargeException;
|
|||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
@ -120,9 +121,11 @@ import java.util.Queue;
|
|||
if (!sample.isEOS() && sample.buffer != null) {
|
||||
len = sample.info.size;
|
||||
ByteBuffer buf = mCodec.getInputBuffer(index);
|
||||
sample.writeToByteBuffer(buf);
|
||||
try {
|
||||
sample.writeToByteBuffer(buf);
|
||||
mCallbacks.onInputExhausted();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.view.Surface;
|
|||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.mozglue.JNIObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
// Proxy class of ICodec binder.
|
||||
|
@ -67,6 +68,7 @@ public final class CodecProxy {
|
|||
public void onOutput(Sample sample) throws RemoteException {
|
||||
mCallbacks.onOutput(sample);
|
||||
mRemote.releaseOutput(sample);
|
||||
sample.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -131,6 +133,10 @@ public final class CodecProxy {
|
|||
Sample sample = (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) ?
|
||||
Sample.EOS : mRemote.dequeueInput(info.size).set(bytes, info, cryptoInfo);
|
||||
mRemote.queueInput(sample);
|
||||
sample.dispose();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} catch (DeadObjectException e) {
|
||||
return false;
|
||||
} catch (RemoteException e) {
|
||||
|
|
|
@ -11,7 +11,10 @@ import android.os.Parcel;
|
|||
import android.os.Parcelable;
|
||||
|
||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.mozglue.SharedMemBuffer;
|
||||
import org.mozilla.gecko.mozglue.SharedMemory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
// Parcelable carrying input/output sample data and info cross process.
|
||||
|
@ -24,8 +27,10 @@ public final class Sample implements Parcelable {
|
|||
}
|
||||
|
||||
public interface Buffer extends Parcelable {
|
||||
void readFromByteBuffer(ByteBuffer src, int offset, int size);
|
||||
void writeToByteBuffer(ByteBuffer dest, int offset, int size);
|
||||
int capacity();
|
||||
void readFromByteBuffer(ByteBuffer src, int offset, int size) throws IOException;
|
||||
void writeToByteBuffer(ByteBuffer dest, int offset, int size) throws IOException;
|
||||
void dispose();
|
||||
}
|
||||
|
||||
private static final class ArrayBuffer implements Buffer {
|
||||
|
@ -58,7 +63,12 @@ public final class Sample implements Parcelable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void readFromByteBuffer(ByteBuffer src, int offset, int size) {
|
||||
public int capacity() {
|
||||
return mArray != null ? mArray.length : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromByteBuffer(ByteBuffer src, int offset, int size) throws IOException {
|
||||
src.position(offset);
|
||||
if (mArray == null || mArray.length != size) {
|
||||
mArray = new byte[size];
|
||||
|
@ -67,9 +77,14 @@ public final class Sample implements Parcelable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void writeToByteBuffer(ByteBuffer dest, int offset, int size) {
|
||||
public void writeToByteBuffer(ByteBuffer dest, int offset, int size) throws IOException {
|
||||
dest.put(mArray, offset, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
mArray = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Buffer buffer;
|
||||
|
@ -88,6 +103,10 @@ public final class Sample implements Parcelable {
|
|||
return new Sample(buffer, bufferInfo, cryptoInfo);
|
||||
}
|
||||
|
||||
public static Sample create(SharedMemory sharedMem) {
|
||||
return new Sample(new SharedMemBuffer(sharedMem), new BufferInfo(), null);
|
||||
}
|
||||
|
||||
private Sample(Buffer bytes, BufferInfo info, CryptoInfo cryptoInfo) {
|
||||
buffer = bytes;
|
||||
this.info = info;
|
||||
|
@ -132,7 +151,7 @@ public final class Sample implements Parcelable {
|
|||
mode);
|
||||
}
|
||||
|
||||
public Sample set(ByteBuffer bytes, BufferInfo info, CryptoInfo cryptoInfo) {
|
||||
public Sample set(ByteBuffer bytes, BufferInfo info, CryptoInfo cryptoInfo) throws IOException {
|
||||
if (bytes != null && info.size > 0) {
|
||||
buffer.readFromByteBuffer(bytes, info.offset, info.size);
|
||||
}
|
||||
|
@ -142,6 +161,19 @@ public final class Sample implements Parcelable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (isEOS()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer != null) {
|
||||
buffer.dispose();
|
||||
buffer = null;
|
||||
}
|
||||
info = null;
|
||||
cryptoInfo = null;
|
||||
}
|
||||
|
||||
public boolean isEOS() {
|
||||
return (this == EOS) ||
|
||||
((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0);
|
||||
|
@ -207,7 +239,7 @@ public final class Sample implements Parcelable {
|
|||
}
|
||||
|
||||
@WrapForJNI
|
||||
public void writeToByteBuffer(ByteBuffer dest) {
|
||||
public void writeToByteBuffer(ByteBuffer dest) throws IOException {
|
||||
if (buffer != null && dest != null && info.size > 0) {
|
||||
buffer.writeToByteBuffer(dest, info.offset, info.size);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* 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/. */
|
||||
package org.mozilla.gecko.mozglue;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import org.mozilla.gecko.media.Sample;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public final class SharedMemBuffer implements Sample.Buffer {
|
||||
private SharedMemory mSharedMem;
|
||||
|
||||
/* package */
|
||||
public SharedMemBuffer(SharedMemory sharedMem) {
|
||||
mSharedMem = sharedMem;
|
||||
}
|
||||
|
||||
protected SharedMemBuffer(Parcel in) {
|
||||
mSharedMem = in.readParcelable(Sample.class.getClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(mSharedMem, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<SharedMemBuffer> CREATOR = new Creator<SharedMemBuffer>() {
|
||||
@Override
|
||||
public SharedMemBuffer createFromParcel(Parcel in) {
|
||||
return new SharedMemBuffer(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedMemBuffer[] newArray(int size) {
|
||||
return new SharedMemBuffer[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return mSharedMem != null ? mSharedMem.getSize() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromByteBuffer(ByteBuffer src, int offset, int size) throws IOException {
|
||||
if (!src.isDirect()) {
|
||||
throw new IOException("SharedMemBuffer only support reading from direct byte buffer.");
|
||||
}
|
||||
nativeReadFromDirectBuffer(src, mSharedMem.getPointer(), offset, size);
|
||||
}
|
||||
|
||||
private native static void nativeReadFromDirectBuffer(ByteBuffer src, long dest, int offset, int size);
|
||||
|
||||
@Override
|
||||
public void writeToByteBuffer(ByteBuffer dest, int offset, int size) throws IOException {
|
||||
if (!dest.isDirect()) {
|
||||
throw new IOException("SharedMemBuffer only support writing to direct byte buffer.");
|
||||
}
|
||||
nativeWriteToDirectBuffer(mSharedMem.getPointer(), dest, offset, size);
|
||||
}
|
||||
|
||||
private native static void nativeWriteToDirectBuffer(long src, ByteBuffer dest, int offset, int size);
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (mSharedMem != null) {
|
||||
mSharedMem.dispose();
|
||||
mSharedMem = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public String toString() { return "Buffer: " + mSharedMem; }
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.mozglue;
|
||||
|
||||
import android.os.MemoryFile;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class SharedMemory implements Parcelable {
|
||||
private static final String LOGTAG = "GeckoShmem";
|
||||
private static Method sGetFDMethod = null; // MemoryFile.getFileDescriptor() is hidden. :(
|
||||
private ParcelFileDescriptor mDescriptor;
|
||||
private int mSize;
|
||||
private int mId;
|
||||
private long mHandle; // The native pointer.
|
||||
private boolean mIsMapped;
|
||||
private MemoryFile mBackedFile;
|
||||
|
||||
static {
|
||||
try {
|
||||
sGetFDMethod = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private SharedMemory(Parcel in) {
|
||||
mDescriptor = in.readFileDescriptor();
|
||||
mSize = in.readInt();
|
||||
mId = in.readInt();
|
||||
}
|
||||
|
||||
public static final Creator<SharedMemory> CREATOR = new Creator<SharedMemory>() {
|
||||
@Override
|
||||
public SharedMemory createFromParcel(Parcel in) {
|
||||
return new SharedMemory(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedMemory[] newArray(int size) {
|
||||
return new SharedMemory[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// We don't want ParcelFileDescriptor.writeToParcel() to close the fd.
|
||||
dest.writeFileDescriptor(mDescriptor.getFileDescriptor());
|
||||
dest.writeInt(mSize);
|
||||
dest.writeInt(mId);
|
||||
}
|
||||
|
||||
public SharedMemory(int id, int size) throws NoSuchMethodException, IOException {
|
||||
if (sGetFDMethod == null) {
|
||||
throw new NoSuchMethodException("MemoryFile.getFileDescriptor() doesn't exist.");
|
||||
}
|
||||
mBackedFile = new MemoryFile(null, size);
|
||||
try {
|
||||
FileDescriptor fd = (FileDescriptor)sGetFDMethod.invoke(mBackedFile);
|
||||
mDescriptor = ParcelFileDescriptor.dup(fd);
|
||||
mSize = size;
|
||||
mId = id;
|
||||
mBackedFile.allowPurging(false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
close();
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
if (mBackedFile == null) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (mIsMapped) {
|
||||
unmap(mHandle, mSize);
|
||||
mHandle = 0;
|
||||
}
|
||||
|
||||
if (mDescriptor != null) {
|
||||
try {
|
||||
mDescriptor.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mDescriptor = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Should only be called by process that allocates shared memory.
|
||||
public void dispose() {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
if (mBackedFile != null) {
|
||||
mBackedFile.close();
|
||||
mBackedFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
private native void unmap(long address, int size);
|
||||
|
||||
public boolean isValid() { return mDescriptor != null; }
|
||||
|
||||
public int getSize() { return mSize; }
|
||||
|
||||
private int getFD() {
|
||||
return isValid() ? mDescriptor.getFd() : -1;
|
||||
}
|
||||
|
||||
public long getPointer() {
|
||||
if (!isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!mIsMapped) {
|
||||
mHandle = map(getFD(), mSize);
|
||||
if (mHandle != 0) {
|
||||
mIsMapped = true;
|
||||
}
|
||||
}
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
private native long map(int fd, int size);
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
if (mBackedFile != null) {
|
||||
Log.w(LOGTAG, "dispose() not called before finalizing");
|
||||
}
|
||||
dispose();
|
||||
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SHM(" + getSize() + " bytes): id=" + mId + ", backing=" + mBackedFile + ",fd=" + mDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
return (this == that) ||
|
||||
((that instanceof SharedMemory) && (hashCode() == that.hashCode()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mId;
|
||||
}
|
||||
}
|
|
@ -574,6 +574,8 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
|||
'menu/MenuPanel.java',
|
||||
'menu/MenuPopup.java',
|
||||
'MotionEventInterceptor.java',
|
||||
'mozglue/SharedMemBuffer.java',
|
||||
'mozglue/SharedMemory.java',
|
||||
'notifications/NotificationClient.java',
|
||||
'notifications/NotificationHelper.java',
|
||||
'notifications/NotificationReceiver.java',
|
||||
|
|
Загрузка…
Ссылка в новой задаче