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:
John Lin 2016-10-06 15:48:39 +08:00
Родитель ea7f78cbde
Коммит 4b2aac0604
6 изменённых файлов: 302 добавлений и 7 удалений

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

@ -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',