зеркало из 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.util.Log;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
@ -120,9 +121,11 @@ import java.util.Queue;
|
||||||
if (!sample.isEOS() && sample.buffer != null) {
|
if (!sample.isEOS() && sample.buffer != null) {
|
||||||
len = sample.info.size;
|
len = sample.info.size;
|
||||||
ByteBuffer buf = mCodec.getInputBuffer(index);
|
ByteBuffer buf = mCodec.getInputBuffer(index);
|
||||||
sample.writeToByteBuffer(buf);
|
|
||||||
try {
|
try {
|
||||||
|
sample.writeToByteBuffer(buf);
|
||||||
mCallbacks.onInputExhausted();
|
mCallbacks.onInputExhausted();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import android.view.Surface;
|
||||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||||
import org.mozilla.gecko.mozglue.JNIObject;
|
import org.mozilla.gecko.mozglue.JNIObject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
// Proxy class of ICodec binder.
|
// Proxy class of ICodec binder.
|
||||||
|
@ -67,6 +68,7 @@ public final class CodecProxy {
|
||||||
public void onOutput(Sample sample) throws RemoteException {
|
public void onOutput(Sample sample) throws RemoteException {
|
||||||
mCallbacks.onOutput(sample);
|
mCallbacks.onOutput(sample);
|
||||||
mRemote.releaseOutput(sample);
|
mRemote.releaseOutput(sample);
|
||||||
|
sample.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,6 +133,10 @@ public final class CodecProxy {
|
||||||
Sample sample = (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) ?
|
Sample sample = (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) ?
|
||||||
Sample.EOS : mRemote.dequeueInput(info.size).set(bytes, info, cryptoInfo);
|
Sample.EOS : mRemote.dequeueInput(info.size).set(bytes, info, cryptoInfo);
|
||||||
mRemote.queueInput(sample);
|
mRemote.queueInput(sample);
|
||||||
|
sample.dispose();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
} catch (DeadObjectException e) {
|
} catch (DeadObjectException e) {
|
||||||
return false;
|
return false;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
|
|
@ -11,7 +11,10 @@ import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
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;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
// Parcelable carrying input/output sample data and info cross process.
|
// 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 {
|
public interface Buffer extends Parcelable {
|
||||||
void readFromByteBuffer(ByteBuffer src, int offset, int size);
|
int capacity();
|
||||||
void writeToByteBuffer(ByteBuffer dest, int offset, int size);
|
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 {
|
private static final class ArrayBuffer implements Buffer {
|
||||||
|
@ -58,7 +63,12 @@ public final class Sample implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
src.position(offset);
|
||||||
if (mArray == null || mArray.length != size) {
|
if (mArray == null || mArray.length != size) {
|
||||||
mArray = new byte[size];
|
mArray = new byte[size];
|
||||||
|
@ -67,9 +77,14 @@ public final class Sample implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
dest.put(mArray, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
mArray = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Buffer buffer;
|
public Buffer buffer;
|
||||||
|
@ -88,6 +103,10 @@ public final class Sample implements Parcelable {
|
||||||
return new Sample(buffer, bufferInfo, cryptoInfo);
|
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) {
|
private Sample(Buffer bytes, BufferInfo info, CryptoInfo cryptoInfo) {
|
||||||
buffer = bytes;
|
buffer = bytes;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
@ -132,7 +151,7 @@ public final class Sample implements Parcelable {
|
||||||
mode);
|
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) {
|
if (bytes != null && info.size > 0) {
|
||||||
buffer.readFromByteBuffer(bytes, info.offset, info.size);
|
buffer.readFromByteBuffer(bytes, info.offset, info.size);
|
||||||
}
|
}
|
||||||
|
@ -142,6 +161,19 @@ public final class Sample implements Parcelable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
if (isEOS()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer != null) {
|
||||||
|
buffer.dispose();
|
||||||
|
buffer = null;
|
||||||
|
}
|
||||||
|
info = null;
|
||||||
|
cryptoInfo = null;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEOS() {
|
public boolean isEOS() {
|
||||||
return (this == EOS) ||
|
return (this == EOS) ||
|
||||||
((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0);
|
((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0);
|
||||||
|
@ -207,7 +239,7 @@ public final class Sample implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@WrapForJNI
|
@WrapForJNI
|
||||||
public void writeToByteBuffer(ByteBuffer dest) {
|
public void writeToByteBuffer(ByteBuffer dest) throws IOException {
|
||||||
if (buffer != null && dest != null && info.size > 0) {
|
if (buffer != null && dest != null && info.size > 0) {
|
||||||
buffer.writeToByteBuffer(dest, info.offset, info.size);
|
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/MenuPanel.java',
|
||||||
'menu/MenuPopup.java',
|
'menu/MenuPopup.java',
|
||||||
'MotionEventInterceptor.java',
|
'MotionEventInterceptor.java',
|
||||||
|
'mozglue/SharedMemBuffer.java',
|
||||||
|
'mozglue/SharedMemory.java',
|
||||||
'notifications/NotificationClient.java',
|
'notifications/NotificationClient.java',
|
||||||
'notifications/NotificationHelper.java',
|
'notifications/NotificationHelper.java',
|
||||||
'notifications/NotificationReceiver.java',
|
'notifications/NotificationReceiver.java',
|
||||||
|
|
Загрузка…
Ссылка в новой задаче