Merge "MediaCodec: address API review #2" into rvc-dev

This commit is contained in:
Wonsik Kim
2020-03-19 21:46:28 +00:00
committed by Android (Google) Code Review
4 changed files with 271 additions and 525 deletions

View File

@@ -16805,6 +16805,7 @@ package android.hardware {
field public static final long USAGE_PROTECTED_CONTENT = 16384L; // 0x4000L
field public static final long USAGE_SENSOR_DIRECT_DATA = 8388608L; // 0x800000L
field public static final long USAGE_VIDEO_ENCODE = 65536L; // 0x10000L
field public static final int YCBCR_420_888 = 35; // 0x23
}
public final class Sensor {
@@ -25205,6 +25206,7 @@ package android.media {
method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int);
method @Nullable public android.media.Image getOutputImage(int);
method @NonNull public android.media.MediaCodec.QueueRequest getQueueRequest(int);
method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
method public void release();
@@ -25305,17 +25307,7 @@ package android.media {
method public void set(int, int);
}
public static final class MediaCodec.GraphicBlock {
method protected void finalize();
method public static boolean isCodecCopyFreeCompatible(@NonNull String[]);
method public boolean isMappable();
method @NonNull public android.media.Image map();
method @NonNull public static android.media.MediaCodec.GraphicBlock obtain(int, int, int, long, @NonNull String[]);
method public void recycle();
}
public class MediaCodec.IncompatibleWithBlockModelException extends java.lang.RuntimeException {
ctor public MediaCodec.IncompatibleWithBlockModelException();
}
public static final class MediaCodec.LinearBlock {
@@ -25345,12 +25337,12 @@ package android.media {
}
public static final class MediaCodec.OutputFrame {
method @NonNull public java.util.Set<java.lang.String> getChangedKeys();
method public int getFlags();
method @NonNull public android.media.MediaFormat getFormat();
method @Nullable public android.media.MediaCodec.GraphicBlock getGraphicBlock();
method @Nullable public android.hardware.HardwareBuffer getHardwareBuffer();
method @Nullable public android.media.MediaCodec.LinearBlock getLinearBlock();
method public long getPresentationTimeUs();
method public void retrieveChangedKeys(@NonNull java.util.Set<java.lang.String>);
}
public final class MediaCodec.QueueRequest {
@@ -25358,7 +25350,7 @@ package android.media {
method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
method @NonNull public android.media.MediaCodec.QueueRequest setFloatParameter(@NonNull String, float);
method @NonNull public android.media.MediaCodec.QueueRequest setGraphicBlock(@NonNull android.media.MediaCodec.GraphicBlock);
method @NonNull public android.media.MediaCodec.QueueRequest setHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);

View File

@@ -46,7 +46,7 @@ import java.lang.annotation.RetentionPolicy;
public final class HardwareBuffer implements Parcelable, AutoCloseable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "RGB", "BLOB", "D_", "DS_", "S_" }, value = {
@IntDef(prefix = { "RGB", "BLOB", "YCBCR_", "D_", "DS_", "S_" }, value = {
RGBA_8888,
RGBA_FP16,
RGBA_1010102,
@@ -54,6 +54,7 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
RGB_888,
RGB_565,
BLOB,
YCBCR_420_888,
D_16,
D_24,
DS_24UI8,
@@ -79,6 +80,8 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
public static final int RGBA_1010102 = 0x2b;
/** Format: opaque format used for raw data transfer; must have a height of 1 */
public static final int BLOB = 0x21;
/** Format: Planar YCbCr 420; must have an even width and height */
public static final int YCBCR_420_888 = 0x23;
/** Format: 16 bits depth */
public static final int D_16 = 0x30;
/** Format: 24 bits depth */
@@ -396,6 +399,7 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
case RGB_565:
case RGB_888:
case BLOB:
case YCBCR_420_888:
case D_16:
case D_24:
case DS_24UI8:

View File

@@ -42,7 +42,9 @@ import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
@@ -1957,7 +1959,7 @@ final public class MediaCodec {
/**
* If this codec is to be used with {@link LinearBlock} and/or {@link
* GraphicBlock}, pass this flag.
* HardwareBuffer}, pass this flag.
* <p>
* When this flag is set, the following APIs throw {@link IncompatibleWithBlockModelException}.
* <ul>
@@ -1989,6 +1991,19 @@ final public class MediaCodec {
* Thrown when the codec is configured for block model and an incompatible API is called.
*/
public class IncompatibleWithBlockModelException extends RuntimeException {
IncompatibleWithBlockModelException() { }
IncompatibleWithBlockModelException(String message) {
super(message);
}
IncompatibleWithBlockModelException(String message, Throwable cause) {
super(message, cause);
}
IncompatibleWithBlockModelException(Throwable cause) {
super(cause);
}
}
/**
@@ -2532,7 +2547,9 @@ final public class MediaCodec {
throws CryptoException {
synchronized(mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("queueInputBuffer() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use getQueueRequest() to queue buffers");
}
invalidateByteBuffer(mCachedInputBuffers, index);
mDequeuedInputBuffers.remove(index);
@@ -2784,7 +2801,9 @@ final public class MediaCodec {
int flags) throws CryptoException {
synchronized(mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("queueSecureInputBuffer() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use getQueueRequest() to queue buffers");
}
invalidateByteBuffer(mCachedInputBuffers, index);
mDequeuedInputBuffers.remove(index);
@@ -2819,7 +2838,9 @@ final public class MediaCodec {
public final int dequeueInputBuffer(long timeoutUs) {
synchronized (mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("dequeueInputBuffer() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use MediaCodec.Callback objectes to get input buffer slots.");
}
}
int res = native_dequeueInputBuffer(timeoutUs);
@@ -2989,179 +3010,22 @@ final public class MediaCodec {
}
/**
* Section of memory that represents a graphic block. Applications may
* acquire a block via {@link GraphicBlock#obtain} and queue
* the block as an input buffer to a codec, or get a block allocated by
* codec as an output buffer from {@link OutputFrame}.
* Map a {@link HardwareBuffer} object into {@link Image}, so that the content of the buffer is
* accessible. Depending on the usage and pixel format of the hardware buffer, it may not be
* mappable; this method returns null in that case.
*
* {@see QueueRequest#setGraphicBlock}
* {@see OutputFrame#getGraphicBlock}
* @param hardwareBuffer {@link HardwareBuffer} to map.
* @return Mapped {@link Image} object, or null if the buffer is not mappable.
*/
public static final class GraphicBlock {
// No public constructors.
private GraphicBlock() {}
/**
* Returns true if the buffer is mappable.
* @throws IllegalStateException if invalid
*/
public boolean isMappable() {
synchronized (mLock) {
if (!mValid) {
throw new IllegalStateException("The graphic block is invalid");
}
return mMappable;
}
}
/**
* Map the memory and return the mapped region.
* <p>
* Calling {@link #recycle} or
* {@link QueueRequest#setGraphicBlock} causes the returned
* {@link Image} object to be closed, if not already.
*
* @return mapped memory region as {@link Image} object
* @throws IllegalStateException if not mappable or invalid
*/
public @NonNull Image map() {
synchronized (mLock) {
if (!mValid) {
throw new IllegalStateException("The graphic block is invalid");
}
if (!mMappable) {
throw new IllegalStateException("The graphic block is not mappable");
}
if (mMapped == null) {
mMapped = native_map();
}
return mMapped;
}
}
private native Image native_map();
/**
* Mark this block as ready to be recycled by the framework once it is
* no longer in use. All operations to this object after
* this call will cause exceptions, as well as attempt to access the
* previously mapped memory region. Caller should clear all references
* to this object after this call.
* <p>
* To avoid excessive memory consumption, it is recommended that callers
* recycle buffers as soon as they no longer need the buffers.
*
* @throws IllegalStateException if invalid
*/
public void recycle() {
synchronized (mLock) {
if (!mValid) {
throw new IllegalStateException("The graphic block is invalid");
}
if (mMapped != null) {
mMapped.close();
mMapped = null;
}
native_recycle();
mValid = false;
mNativeContext = 0;
}
sPool.offer(this);
}
private native void native_recycle();
/**
* Returns true if it is possible to allocate a graphic block that
* can be passed to all listed codecs as an input buffer without
* copying.
* <p>
* Note that even if this function returns true, {@link #obtain}
* may still throw due to invalid arguments or allocation failure.
* In addition, choosing a format that is not natively supported by the
* codec may cause color conversion.
*
* @param codecNames list of codecs that the client wants to use a
* graphic block without copying. Null entries are
* ignored.
*/
public static boolean isCodecCopyFreeCompatible(@NonNull String[] codecNames) {
return native_checkCompatible(codecNames);
}
private static native boolean native_checkCompatible(@NonNull String[] codecNames);
// Called from native
private void setInternalStateLocked(long context, boolean isMappable) {
mNativeContext = context;
mMappable = isMappable;
mValid = (context != 0);
}
private static final BlockingQueue<GraphicBlock> sPool =
new LinkedBlockingQueue<>();
/**
* Obtain a graphic block object of dimension
* {@code width}x{@code height}.
* If {@link #isCodecCopyFreeCompatible} with the same
* {@code codecNames} returned true, the returned
* {@link GraphicBlock} object can be queued to the listed codecs
* without copying. The returned {@link GraphicBlock} object is always
* read/write mappable.
*
* @param width requested width of the graphic block
* @param height requested height of the graphic block
* @param format the format of pixels. One of the {@code COLOR_Format}
* values from {@link MediaCodecInfo.CodecCapabilities}.
* @param usage the usage of the buffer. @HardwareBuffer.Usage
* @param codecNames list of codecs that the client wants to use this
* graphic block without copying. Null entries are
* ignored.
* @return a graphic block object.
* @throws IllegalArgumentException if the parameters are invalid or
* not supported
* @throws IOException if an error occurred while allocating a buffer
*/
public static @NonNull GraphicBlock obtain(
int width,
int height,
int format,
@HardwareBuffer.Usage long usage,
@NonNull String[] codecNames) {
GraphicBlock buffer = sPool.poll();
if (buffer == null) {
buffer = new GraphicBlock();
}
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException(
"non-positive width or height: " + width + "x" + height);
}
synchronized (buffer.mLock) {
buffer.native_obtain(width, height, format, usage, codecNames);
}
return buffer;
}
private native void native_obtain(
int width,
int height,
int format,
@HardwareBuffer.Usage long usage,
@NonNull String[] codecNames);
@Override
protected void finalize() {
native_recycle();
}
private final Object mLock = new Object();
private boolean mValid = false;
private boolean mMappable = false;
private Image mMapped = null;
private long mNativeContext = 0;
public static @Nullable Image mapHardwareBuffer(@NonNull HardwareBuffer hardwareBuffer) {
return native_mapHardwareBuffer(hardwareBuffer);
}
private static native @Nullable Image native_mapHardwareBuffer(
@NonNull HardwareBuffer hardwareBuffer);
private static native void native_closeMediaImage(long context);
/**
* Builder-like class for queue requests. Use this class to prepare a
* queue request and send it.
@@ -3185,7 +3049,7 @@ final public class MediaCodec {
* @param offset The byte offset into the input buffer at which the data starts.
* @param size The number of bytes of valid input data.
* @param cryptoInfo Metadata describing the structure of the encrypted input sample.
* may be null if clear.
* may be null for non-encrypted content.
* @return this object
* @throws IllegalStateException if a buffer is already set
*/
@@ -3197,7 +3061,7 @@ final public class MediaCodec {
if (!isAccessible()) {
throw new IllegalStateException("The request is stale");
}
if (mLinearBlock != null || mGraphicBlock != null) {
if (mLinearBlock != null || mHardwareBuffer != null) {
throw new IllegalStateException("Cannot set block twice");
}
mLinearBlock = block;
@@ -3208,22 +3072,27 @@ final public class MediaCodec {
}
/**
* Set a graphic block to this queue request. Exactly one buffer must
* Set a harware graphic buffer to this queue request. Exactly one buffer must
* be set for a queue request before calling {@link #queue}.
* <p>
* Note: buffers should have format {@link HardwareBuffer#YCBCR_420_888},
* a single layer, and an appropriate usage ({@link HardwareBuffer#USAGE_CPU_READ_OFTEN}
* for software codecs and {@link HardwareBuffer#USAGE_VIDEO_ENCODE} for hardware)
* for codecs to recognize. Codecs may throw exception if the buffer is not recognizable.
*
* @param block The graphic block object
* @param buffer The hardware graphic buffer object
* @return this object
* @throws IllegalStateException if a buffer is already set
*/
public @NonNull QueueRequest setGraphicBlock(
@NonNull GraphicBlock block) {
public @NonNull QueueRequest setHardwareBuffer(
@NonNull HardwareBuffer buffer) {
if (!isAccessible()) {
throw new IllegalStateException("The request is stale");
}
if (mLinearBlock != null || mGraphicBlock != null) {
if (mLinearBlock != null || mHardwareBuffer != null) {
throw new IllegalStateException("Cannot set block twice");
}
mGraphicBlock = block;
mHardwareBuffer = buffer;
return this;
}
@@ -3375,7 +3244,7 @@ final public class MediaCodec {
if (!isAccessible()) {
throw new IllegalStateException("The request is stale");
}
if (mLinearBlock == null && mGraphicBlock == null) {
if (mLinearBlock == null && mHardwareBuffer == null) {
throw new IllegalStateException("No block is set");
}
setAccessible(false);
@@ -3384,9 +3253,9 @@ final public class MediaCodec {
mIndex, mLinearBlock, mOffset, mSize, mCryptoInfo,
mPresentationTimeUs, mFlags,
mTuningKeys, mTuningValues);
} else if (mGraphicBlock != null) {
mCodec.native_queueGraphicBlock(
mIndex, mGraphicBlock, mPresentationTimeUs, mFlags,
} else if (mHardwareBuffer != null) {
mCodec.native_queueHardwareBuffer(
mIndex, mHardwareBuffer, mPresentationTimeUs, mFlags,
mTuningKeys, mTuningValues);
}
clear();
@@ -3397,7 +3266,7 @@ final public class MediaCodec {
mOffset = 0;
mSize = 0;
mCryptoInfo = null;
mGraphicBlock = null;
mHardwareBuffer = null;
mPresentationTimeUs = 0;
mFlags = 0;
mTuningKeys.clear();
@@ -3420,7 +3289,7 @@ final public class MediaCodec {
private int mOffset = 0;
private int mSize = 0;
private MediaCodec.CryptoInfo mCryptoInfo = null;
private GraphicBlock mGraphicBlock = null;
private HardwareBuffer mHardwareBuffer = null;
private long mPresentationTimeUs = 0;
private @BufferFlag int mFlags = 0;
private final ArrayList<String> mTuningKeys = new ArrayList<>();
@@ -3440,9 +3309,9 @@ final public class MediaCodec {
@NonNull ArrayList<String> keys,
@NonNull ArrayList<Object> values);
private native void native_queueGraphicBlock(
private native void native_queueHardwareBuffer(
int index,
@NonNull GraphicBlock block,
@NonNull HardwareBuffer buffer,
long presentationTimeUs,
int flags,
@NonNull ArrayList<String> keys,
@@ -3535,7 +3404,9 @@ final public class MediaCodec {
@NonNull BufferInfo info, long timeoutUs) {
synchronized (mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("dequeueOutputBuffer() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use MediaCodec.Callback objects to get output buffer slots.");
}
}
int res = native_dequeueOutputBuffer(info, timeoutUs);
@@ -3917,7 +3788,10 @@ final public class MediaCodec {
public ByteBuffer[] getInputBuffers() {
synchronized (mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("getInputBuffers() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please obtain MediaCodec.LinearBlock or HardwareBuffer "
+ "objects and attach to QueueRequest objects.");
}
if (mCachedInputBuffers == null) {
throw new IllegalStateException();
@@ -3953,7 +3827,9 @@ final public class MediaCodec {
public ByteBuffer[] getOutputBuffers() {
synchronized (mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("getOutputBuffers() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use getOutputFrame to get output frames.");
}
if (mCachedOutputBuffers == null) {
throw new IllegalStateException();
@@ -3985,7 +3861,10 @@ final public class MediaCodec {
public ByteBuffer getInputBuffer(int index) {
synchronized (mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("getInputBuffer() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please obtain MediaCodec.LinearBlock or HardwareBuffer "
+ "objects and attach to QueueRequest objects.");
}
}
ByteBuffer newBuffer = getBuffer(true /* input */, index);
@@ -4019,7 +3898,10 @@ final public class MediaCodec {
public Image getInputImage(int index) {
synchronized (mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("getInputImage() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please obtain MediaCodec.LinearBlock or HardwareBuffer "
+ "objects and attach to QueueRequest objects.");
}
}
Image newImage = getImage(true /* input */, index);
@@ -4053,7 +3935,9 @@ final public class MediaCodec {
public ByteBuffer getOutputBuffer(int index) {
synchronized (mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("getOutputBuffer() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use getOutputFrame() to get output frames.");
}
}
ByteBuffer newBuffer = getBuffer(false /* input */, index);
@@ -4086,7 +3970,9 @@ final public class MediaCodec {
public Image getOutputImage(int index) {
synchronized (mBufferLock) {
if (mBufferMode == BUFFER_MODE_BLOCK) {
throw new IncompatibleWithBlockModelException();
throw new IncompatibleWithBlockModelException("getOutputImage() "
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use getOutputFrame() to get output frames.");
}
}
Image newImage = getImage(false /* input */, index);
@@ -4112,22 +3998,22 @@ final public class MediaCodec {
* @throws IllegalStateException if this output frame is not linear.
*/
public @Nullable LinearBlock getLinearBlock() {
if (mGraphicBlock != null) {
if (mHardwareBuffer != null) {
throw new IllegalStateException("This output frame is not linear");
}
return mLinearBlock;
}
/**
* Returns the output graphic block, or null if this frame is empty.
* Returns the output hardware graphic buffer, or null if this frame is empty.
*
* @throws IllegalStateException if this output frame is not graphic.
*/
public @Nullable GraphicBlock getGraphicBlock() {
public @Nullable HardwareBuffer getHardwareBuffer() {
if (mLinearBlock != null) {
throw new IllegalStateException("This output frame is not graphic");
}
return mGraphicBlock;
return mHardwareBuffer;
}
/**
@@ -4153,21 +4039,24 @@ final public class MediaCodec {
}
/**
* Populate {@code keys} with the name of entries that has changed from
* Returns an unmodifiable set of the names of entries that has changed from
* the previous frame. The entries may have been removed/changed/added.
* Client can find out what the change is by querying {@link MediaFormat}
* object returned from {@link #getFormat}.
*/
public void retrieveChangedKeys(@NonNull Set<String> keys) {
keys.clear();
keys.addAll(mChangedKeys);
public @NonNull Set<String> getChangedKeys() {
if (mKeySet.isEmpty() && !mChangedKeys.isEmpty()) {
mKeySet.addAll(mChangedKeys);
}
return Collections.unmodifiableSet(mKeySet);
}
void clear() {
mLinearBlock = null;
mGraphicBlock = null;
mHardwareBuffer = null;
mFormat = null;
mChangedKeys.clear();
mKeySet.clear();
mLoaded = false;
}
@@ -4194,11 +4083,12 @@ final public class MediaCodec {
private final int mIndex;
private LinearBlock mLinearBlock = null;
private GraphicBlock mGraphicBlock = null;
private HardwareBuffer mHardwareBuffer = null;
private long mPresentationTimeUs = 0;
private @BufferFlag int mFlags = 0;
private MediaFormat mFormat = null;
private final ArrayList<String> mChangedKeys = new ArrayList<>();
private final Set<String> mKeySet = new HashSet<>();
private boolean mAccessible = false;
private boolean mLoaded = false;
}
@@ -4773,6 +4663,7 @@ final public class MediaCodec {
private final ByteBuffer mInfo;
private final int mXOffset;
private final int mYOffset;
private final long mBufferContext;
private final static int TYPE_YUV = 1;
@@ -4828,6 +4719,9 @@ final public class MediaCodec {
if (mBuffer != null) {
java.nio.NioUtils.freeDirectBuffer(mBuffer);
}
if (mBufferContext != 0) {
native_closeMediaImage(mBufferContext);
}
mIsImageValid = false;
}
}
@@ -4860,6 +4754,8 @@ final public class MediaCodec {
mYOffset = yOffset;
mInfo = info;
mBufferContext = 0;
// read media-info. See MediaImage2
if (info.remaining() == 104) {
int type = info.getInt();
@@ -4921,7 +4817,7 @@ final public class MediaCodec {
public MediaImage(
@NonNull Image.Plane[] planes, int width, int height, int format, boolean readOnly,
long timestamp, int xOffset, int yOffset, @Nullable Rect cropRect) {
long timestamp, int xOffset, int yOffset, @Nullable Rect cropRect, long context) {
mWidth = width;
mHeight = height;
mFormat = format;
@@ -4941,6 +4837,8 @@ final public class MediaCodec {
}
cropRect.offset(-xOffset, -yOffset);
super.setCropRect(cropRect);
mBufferContext = context;
}
private class MediaPlane extends Plane {

View File

@@ -34,10 +34,14 @@
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <C2AllocatorGralloc.h>
#include <C2BlockInternal.h>
#include <C2Buffer.h>
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <binder/MemoryHeapBase.h>
#include <cutils/compiler.h>
@@ -58,6 +62,8 @@
#include <media/stagefright/PersistentSurface.h>
#include <mediadrm/ICrypto.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <system/window.h>
namespace android {
@@ -143,15 +149,6 @@ static struct {
jfieldID lockId;
} gLinearBlockInfo;
static struct {
jclass clazz;
jmethodID ctorId;
jmethodID setInternalStateId;
jfieldID contextId;
jfieldID validId;
jfieldID lockId;
} gGraphicBlockInfo;
struct fields_t {
jmethodID postEventFromNativeID;
jmethodID lockAndGetContextID;
@@ -167,7 +164,7 @@ struct fields_t {
jfieldID patternSkipBlocksID;
jfieldID queueRequestIndexID;
jfieldID outputFrameLinearBlockID;
jfieldID outputFrameGraphicBlockID;
jfieldID outputFrameHardwareBufferID;
jfieldID outputFrameChangedKeysID;
jfieldID outputFrameFormatID;
};
@@ -176,16 +173,6 @@ static fields_t gFields;
static const void *sRefBaseOwner;
struct JMediaCodecGraphicBlock {
std::shared_ptr<C2Buffer> mBuffer;
std::shared_ptr<const C2GraphicView> mReadonlyMapping;
std::shared_ptr<C2GraphicBlock> mBlock;
std::shared_ptr<C2GraphicView> mReadWriteMapping;
sp<MediaCodecBuffer> mLegacyBuffer;
};
////////////////////////////////////////////////////////////////////////////////
JMediaCodec::JMediaCodec(
@@ -706,16 +693,22 @@ status_t JMediaCodec::getOutputFrame(
break;
}
case C2BufferData::GRAPHIC: {
std::unique_ptr<JMediaCodecGraphicBlock> context{new JMediaCodecGraphicBlock};
context->mBuffer = c2Buffer;
ScopedLocalRef<jobject> graphicBlock{env, env->NewObject(
gGraphicBlockInfo.clazz, gGraphicBlockInfo.ctorId)};
env->CallVoidMethod(
graphicBlock.get(),
gGraphicBlockInfo.setInternalStateId,
(jlong)context.release(),
true);
env->SetObjectField(frame, gFields.outputFrameGraphicBlockID, graphicBlock.get());
const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
uint32_t width, height, format, stride, igbp_slot, generation;
uint64_t usage, igbp_id;
_UnwrapNativeCodec2GrallocMetadata(
c2Handle, &width, &height, &format, &usage, &stride, &generation,
&igbp_id, &igbp_slot);
native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
GraphicBuffer* graphicBuffer = new GraphicBuffer(
grallocHandle, GraphicBuffer::CLONE_HANDLE,
width, height, format, 1, usage, stride);
ScopedLocalRef<jobject> hardwareBuffer{
env,
android_hardware_HardwareBuffer_createFromAHardwareBuffer(
env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
env->SetObjectField(
frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
break;
}
case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
@@ -737,16 +730,7 @@ status_t JMediaCodec::getOutputFrame(
true);
env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
} else {
std::unique_ptr<JMediaCodecGraphicBlock> context{new JMediaCodecGraphicBlock};
context->mLegacyBuffer = buffer;
ScopedLocalRef<jobject> graphicBlock{env, env->NewObject(
gGraphicBlockInfo.clazz, gGraphicBlockInfo.ctorId)};
env->CallVoidMethod(
graphicBlock.get(),
gGraphicBlockInfo.setInternalStateId,
(jlong)context.release(),
true);
env->SetObjectField(frame, gFields.outputFrameGraphicBlockID, graphicBlock.get());
// No-op.
}
}
}
@@ -1873,6 +1857,113 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
}
static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jobject bufferObj) {
ALOGV("android_media_MediaCodec_mapHardwareBuffer");
AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
env, bufferObj);
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(hardwareBuffer, &desc);
if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
return nullptr;
}
if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
ALOGI("mapHardwareBuffer: buffer not CPU readable");
return nullptr;
}
bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
uint64_t cpuUsage = desc.usage;
cpuUsage = (cpuUsage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
cpuUsage = (cpuUsage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
AHardwareBuffer_Planes planes;
int err = AHardwareBuffer_lockPlanes(
hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
if (err != 0) {
ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
return nullptr;
}
if (planes.planeCount != 3) {
ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
return nullptr;
}
ScopedLocalRef<jclass> planeClazz(
env, env->FindClass("android/media/MediaCodec$MediaImage$MediaPlane"));
ScopedLocalRef<jobjectArray> planeArray{
env, env->NewObjectArray(3, planeClazz.get(), NULL)};
CHECK(planeClazz.get() != NULL);
jmethodID planeConstructID = env->GetMethodID(planeClazz.get(), "<init>",
"([Ljava/nio/ByteBuffer;IIIII)V");
// plane indices are Y-U-V.
for (uint32_t i = 0; i < 3; ++i) {
const AHardwareBuffer_Plane &plane = planes.planes[i];
ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
env,
plane.data,
plane.rowStride * (desc.height - 1) + plane.pixelStride * (desc.width - 1) + 1,
0,
plane.rowStride * (desc.height - 1) + plane.pixelStride * (desc.width - 1) + 1,
readOnly,
true)};
ScopedLocalRef<jobject> planeObj{env, env->NewObject(
planeClazz.get(), planeConstructID,
byteBuffer.get(), plane.rowStride, plane.pixelStride)};
env->SetObjectArrayElement(planeArray.get(), i, planeObj.get());
}
ScopedLocalRef<jclass> imageClazz(
env, env->FindClass("android/media/MediaCodec$MediaImage"));
CHECK(imageClazz.get() != NULL);
jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
"([Landroid/media/Image$Plane;IIIZJIILandroid/graphics/Rect;J)V");
jobject img = env->NewObject(imageClazz.get(), imageConstructID,
planeArray.get(),
desc.width,
desc.height,
desc.format, // ???
(jboolean)readOnly /* readOnly */,
(jlong)0 /* timestamp */,
(jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
(jlong)hardwareBuffer);
// if MediaImage creation fails, return null
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return nullptr;
}
AHardwareBuffer_acquire(hardwareBuffer);
return img;
}
static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jlong context) {
if (context == 0) {
return;
}
AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
int32_t fenceFd = -1;
int err = AHardwareBuffer_unlock(hardwareBuffer, &fenceFd);
if (err == 0) {
sp<Fence> fence{new Fence(fenceFd)};
} else {
ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
// Continue to release the hardwareBuffer
}
AHardwareBuffer_release(hardwareBuffer);
}
static status_t ConvertKeyValueListsToAMessage(
JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
static struct Fields {
@@ -2031,11 +2122,6 @@ static void android_media_MediaCodec_native_queueLinearBlock(
}
NativeCryptoInfo cryptoInfo{env, cryptoInfoObj};
size_t cryptoSize = 0;
for (int i = 0; i < cryptoInfo.mNumSubSamples; ++i) {
cryptoSize += cryptoInfo.mSubSamples[i].mNumBytesOfClearData;
cryptoSize += cryptoInfo.mSubSamples[i].mNumBytesOfEncryptedData;
}
err = codec->queueEncryptedLinearBlock(
index,
memory,
@@ -2059,10 +2145,10 @@ static void android_media_MediaCodec_native_queueLinearBlock(
throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
}
static void android_media_MediaCodec_native_queueGraphicBlock(
static void android_media_MediaCodec_native_queueHardwareBuffer(
JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
ALOGV("android_media_MediaCodec_native_queueGraphicBlock");
ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -2078,29 +2164,21 @@ static void android_media_MediaCodec_native_queueGraphicBlock(
return;
}
std::shared_ptr<C2Buffer> buffer;
std::shared_ptr<C2GraphicBlock> block;
ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gGraphicBlockInfo.lockId)};
if (env->MonitorEnter(lock.get()) == JNI_OK) {
if (env->GetBooleanField(bufferObj, gGraphicBlockInfo.validId)) {
JMediaCodecGraphicBlock *context = (JMediaCodecGraphicBlock *)env->GetLongField(
bufferObj, gGraphicBlockInfo.contextId);
buffer = context->mBuffer;
block = context->mBlock;
}
env->MonitorExit(lock.get());
} else {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
env, bufferObj);
sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
C2Handle *handle = WrapNativeCodec2GrallocHandle(
graphicBuffer->handle, graphicBuffer->format,
graphicBuffer->width, graphicBuffer->height,
graphicBuffer->usage, graphicBuffer->stride);
std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(handle);
if (!block && !buffer) {
if (!block) {
throwExceptionAsNecessary(env, BAD_VALUE);
return;
}
if (!buffer) {
buffer = C2Buffer::CreateGraphicBuffer(block->share(block->crop(), C2Fence{}));
}
std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
block->crop(), C2Fence{}));
AString errorDetailMsg;
err = codec->queueBuffer(index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
@@ -2534,9 +2612,9 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) {
env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
CHECK(gFields.outputFrameLinearBlockID != NULL);
gFields.outputFrameGraphicBlockID =
env->GetFieldID(clazz.get(), "mGraphicBlock", "Landroid/media/MediaCodec$GraphicBlock;");
CHECK(gFields.outputFrameGraphicBlockID != NULL);
gFields.outputFrameHardwareBufferID =
env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
CHECK(gFields.outputFrameHardwareBufferID != NULL);
gFields.outputFrameChangedKeysID =
env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
@@ -2729,27 +2807,6 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) {
gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
CHECK(gLinearBlockInfo.lockId != NULL);
clazz.reset(env->FindClass("android/media/MediaCodec$GraphicBlock"));
CHECK(clazz.get() != NULL);
gGraphicBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
gGraphicBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
CHECK(gGraphicBlockInfo.ctorId != NULL);
gGraphicBlockInfo.setInternalStateId = env->GetMethodID(
clazz.get(), "setInternalStateLocked", "(JZ)V");
CHECK(gGraphicBlockInfo.setInternalStateId != NULL);
gGraphicBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
CHECK(gGraphicBlockInfo.contextId != NULL);
gGraphicBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
CHECK(gGraphicBlockInfo.validId != NULL);
gGraphicBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
CHECK(gGraphicBlockInfo.lockId != NULL);
}
static void android_media_MediaCodec_native_setup(
@@ -2949,196 +3006,6 @@ static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
return isCompatible;
}
// MediaCodec.GraphicBlock
template <class T>
static jobject CreateImage(JNIEnv *env, const std::shared_ptr<T> &view) {
bool readOnly = std::is_const<T>::value;
const C2PlanarLayout layout = view->layout();
jint format = HAL_PIXEL_FORMAT_YCBCR_420_888;
switch (layout.type) {
case C2PlanarLayout::TYPE_YUV: {
if (layout.numPlanes != 3) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
const C2PlaneInfo & yPlane = layout.planes[C2PlanarLayout::PLANE_Y];
const C2PlaneInfo & uPlane = layout.planes[C2PlanarLayout::PLANE_U];
const C2PlaneInfo & vPlane = layout.planes[C2PlanarLayout::PLANE_V];
if (yPlane.rowSampling != 1 || yPlane.colSampling != 1) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
if (uPlane.rowSampling != vPlane.rowSampling
|| uPlane.colSampling != vPlane.colSampling) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
if (uPlane.rowSampling == 2 && uPlane.colSampling == 2) {
format = HAL_PIXEL_FORMAT_YCBCR_420_888;
break;
} else if (uPlane.rowSampling == 1 && uPlane.colSampling == 2) {
format = HAL_PIXEL_FORMAT_YCBCR_422_888;
break;
} else if (uPlane.rowSampling == 1 && uPlane.colSampling == 1) {
format = HAL_PIXEL_FORMAT_YCBCR_444_888;
break;
}
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
case C2PlanarLayout::TYPE_RGB: {
if (layout.numPlanes != 3) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
format = HAL_PIXEL_FORMAT_FLEX_RGB_888;
break;
}
case C2PlanarLayout::TYPE_RGBA: {
if (layout.numPlanes != 4) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
format = HAL_PIXEL_FORMAT_FLEX_RGBA_8888;
break;
}
case C2PlanarLayout::TYPE_YUVA:
[[fallthrough]];
default:
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
ScopedLocalRef<jclass> planeClazz(
env, env->FindClass("android/media/MediaCodec$MediaImage$MediaPlane"));
ScopedLocalRef<jobjectArray> planeArray{
env, env->NewObjectArray(layout.numPlanes, planeClazz.get(), NULL)};
CHECK(planeClazz.get() != NULL);
jmethodID planeConstructID = env->GetMethodID(planeClazz.get(), "<init>",
"([Ljava/nio/ByteBuffer;IIIII)V");
// plane indices are happened to be Y-U-V and R-G-B(-A) order.
for (uint32_t i = 0; i < layout.numPlanes; ++i) {
const C2PlaneInfo &plane = layout.planes[i];
if (plane.rowInc < 0 || plane.colInc < 0) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
ssize_t minOffset = plane.minOffset(view->width(), view->height());
ssize_t maxOffset = plane.maxOffset(view->width(), view->height());
ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
env,
view->data()[plane.rootIx] + plane.offset + minOffset,
maxOffset - minOffset + 1,
0,
maxOffset - minOffset + 1,
readOnly,
true)};
ScopedLocalRef<jobject> jPlane{env, env->NewObject(
planeClazz.get(), planeConstructID,
byteBuffer.get(), plane.rowInc, plane.colInc)};
}
ScopedLocalRef<jclass> imageClazz(
env, env->FindClass("android/media/MediaCodec$MediaImage"));
CHECK(imageClazz.get() != NULL);
jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
"([Landroid/media/Image$Plane;IIIZJIILandroid/graphics/Rect;)V");
jobject img = env->NewObject(imageClazz.get(), imageConstructID,
planeArray.get(),
view->width(),
view->height(),
format,
(jboolean)readOnly /* readOnly */,
(jlong)0 /* timestamp */,
(jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */);
// if MediaImage creation fails, return null
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return nullptr;
}
return img;
}
static jobject android_media_MediaCodec_GraphicBlock_native_map(
JNIEnv *env, jobject thiz) {
JMediaCodecGraphicBlock *context =
(JMediaCodecGraphicBlock *)env->GetLongField(thiz, gGraphicBlockInfo.contextId);
if (context->mBuffer) {
std::shared_ptr<C2Buffer> buffer = context->mBuffer;
if (!context->mReadonlyMapping) {
const C2BufferData data = buffer->data();
if (data.type() != C2BufferData::GRAPHIC) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
if (data.graphicBlocks().size() != 1u) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
C2ConstGraphicBlock block = data.graphicBlocks().front();
context->mReadonlyMapping =
std::make_shared<const C2GraphicView>(block.map().get());
}
return CreateImage(env, context->mReadonlyMapping);
} else if (context->mBlock) {
std::shared_ptr<C2GraphicBlock> block = context->mBlock;
if (!context->mReadWriteMapping) {
context->mReadWriteMapping =
std::make_shared<C2GraphicView>(block->map().get());
}
return CreateImage(env, context->mReadWriteMapping);
} else if (context->mLegacyBuffer) {
}
throwExceptionAsNecessary(env, INVALID_OPERATION);
return nullptr;
}
static void android_media_MediaCodec_GraphicBlock_native_recycle(
JNIEnv *env, jobject thiz) {
JMediaCodecGraphicBlock *context =
(JMediaCodecGraphicBlock *)env->GetLongField(thiz, gGraphicBlockInfo.contextId);
env->CallVoidMethod(thiz, gGraphicBlockInfo.setInternalStateId, 0, false /* isMappable */);
delete context;
}
static void android_media_MediaCodec_GraphicBlock_native_obtain(
JNIEnv *env, jobject thiz,
jint width, jint height, jint format, jlong usage, jobjectArray codecNames) {
std::unique_ptr<JMediaCodecGraphicBlock> context{new JMediaCodecGraphicBlock};
std::vector<std::string> names;
PopulateNamesVector(env, codecNames, &names);
context->mBlock = MediaCodec::FetchGraphicBlock(width, height, format, usage, names);
if (!context->mBlock) {
jniThrowException(env, "java/io/IOException", nullptr);
return;
}
env->CallVoidMethod(
thiz,
gGraphicBlockInfo.setInternalStateId,
(jlong)context.release(),
true /*isMappable */);
}
static jboolean android_media_MediaCodec_GraphicBlock_checkCompatible(
JNIEnv *env, jobjectArray codecNames) {
std::vector<std::string> names;
PopulateNamesVector(env, codecNames, &names);
bool isCompatible = false;
status_t err = MediaCodec::CanFetchGraphicBlock(names, &isCompatible);
if (err != OK) {
throwExceptionAsNecessary(env, err);
}
return isCompatible;
}
static const JNINativeMethod gMethods[] = {
{ "native_release", "()V", (void *)android_media_MediaCodec_release },
@@ -3184,14 +3051,20 @@ static const JNINativeMethod gMethods[] = {
{ "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
(void *)android_media_MediaCodec_queueSecureInputBuffer },
{ "native_mapHardwareBuffer",
"(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
(void *)android_media_MediaCodec_mapHardwareBuffer },
{ "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
{ "native_queueLinearBlock",
"(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
"Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
(void *)android_media_MediaCodec_native_queueLinearBlock },
{ "native_queueGraphicBlock",
"(ILandroid/media/MediaCodec$GraphicBlock;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
(void *)android_media_MediaCodec_native_queueGraphicBlock },
{ "native_queueHardwareBuffer",
"(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
(void *)android_media_MediaCodec_native_queueHardwareBuffer },
{ "native_getOutputFrame",
"(Landroid/media/MediaCodec$OutputFrame;I)V",
@@ -3265,20 +3138,6 @@ static const JNINativeMethod gLinearBlockMethods[] = {
(void *)android_media_MediaCodec_LinearBlock_checkCompatible },
};
static const JNINativeMethod gGraphicBlockMethods[] = {
{ "native_map", "()Landroid/media/Image;",
(void *)android_media_MediaCodec_GraphicBlock_native_map },
{ "native_recycle", "()V",
(void *)android_media_MediaCodec_GraphicBlock_native_recycle },
{ "native_obtain", "(IIIJ[Ljava/lang/String;)V",
(void *)android_media_MediaCodec_GraphicBlock_native_obtain },
{ "native_checkCompatible", "([Ljava/lang/String;)Z",
(void *)android_media_MediaCodec_GraphicBlock_checkCompatible },
};
int register_android_media_MediaCodec(JNIEnv *env) {
int result = AndroidRuntime::registerNativeMethods(env,
"android/media/MediaCodec", gMethods, NELEM(gMethods));
@@ -3289,12 +3148,5 @@ int register_android_media_MediaCodec(JNIEnv *env) {
"android/media/MediaCodec$LinearBlock",
gLinearBlockMethods,
NELEM(gLinearBlockMethods));
if (result != JNI_OK) {
return result;
}
result = AndroidRuntime::registerNativeMethods(env,
"android/media/MediaCodec$GraphicBlock",
gGraphicBlockMethods,
NELEM(gGraphicBlockMethods));
return result;
}