Merge "MediaCodec: address API review #2" into rvc-dev am: de9e6f71d0 am: dc770a7dbf
Change-Id: Ib299871b89c730f47ed4e39b1e48c3fa10bc0094
This commit is contained in:
@@ -16805,6 +16805,7 @@ package android.hardware {
|
|||||||
field public static final long USAGE_PROTECTED_CONTENT = 16384L; // 0x4000L
|
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_SENSOR_DIRECT_DATA = 8388608L; // 0x800000L
|
||||||
field public static final long USAGE_VIDEO_ENCODE = 65536L; // 0x10000L
|
field public static final long USAGE_VIDEO_ENCODE = 65536L; // 0x10000L
|
||||||
|
field public static final int YCBCR_420_888 = 35; // 0x23
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class Sensor {
|
public final class Sensor {
|
||||||
@@ -25205,6 +25206,7 @@ package android.media {
|
|||||||
method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int);
|
method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int);
|
||||||
method @Nullable public android.media.Image getOutputImage(int);
|
method @Nullable public android.media.Image getOutputImage(int);
|
||||||
method @NonNull public android.media.MediaCodec.QueueRequest getQueueRequest(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 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 queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
|
||||||
method public void release();
|
method public void release();
|
||||||
@@ -25305,17 +25307,7 @@ package android.media {
|
|||||||
method public void set(int, int);
|
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 {
|
public class MediaCodec.IncompatibleWithBlockModelException extends java.lang.RuntimeException {
|
||||||
ctor public MediaCodec.IncompatibleWithBlockModelException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class MediaCodec.LinearBlock {
|
public static final class MediaCodec.LinearBlock {
|
||||||
@@ -25345,12 +25337,12 @@ package android.media {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final class MediaCodec.OutputFrame {
|
public static final class MediaCodec.OutputFrame {
|
||||||
|
method @NonNull public java.util.Set<java.lang.String> getChangedKeys();
|
||||||
method public int getFlags();
|
method public int getFlags();
|
||||||
method @NonNull public android.media.MediaFormat getFormat();
|
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 @Nullable public android.media.MediaCodec.LinearBlock getLinearBlock();
|
||||||
method public long getPresentationTimeUs();
|
method public long getPresentationTimeUs();
|
||||||
method public void retrieveChangedKeys(@NonNull java.util.Set<java.lang.String>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class MediaCodec.QueueRequest {
|
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 setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
|
||||||
method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
|
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 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 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 setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
|
||||||
method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
|
method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
public final class HardwareBuffer implements Parcelable, AutoCloseable {
|
public final class HardwareBuffer implements Parcelable, AutoCloseable {
|
||||||
/** @hide */
|
/** @hide */
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef(prefix = { "RGB", "BLOB", "D_", "DS_", "S_" }, value = {
|
@IntDef(prefix = { "RGB", "BLOB", "YCBCR_", "D_", "DS_", "S_" }, value = {
|
||||||
RGBA_8888,
|
RGBA_8888,
|
||||||
RGBA_FP16,
|
RGBA_FP16,
|
||||||
RGBA_1010102,
|
RGBA_1010102,
|
||||||
@@ -54,6 +54,7 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
|
|||||||
RGB_888,
|
RGB_888,
|
||||||
RGB_565,
|
RGB_565,
|
||||||
BLOB,
|
BLOB,
|
||||||
|
YCBCR_420_888,
|
||||||
D_16,
|
D_16,
|
||||||
D_24,
|
D_24,
|
||||||
DS_24UI8,
|
DS_24UI8,
|
||||||
@@ -79,6 +80,8 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
|
|||||||
public static final int RGBA_1010102 = 0x2b;
|
public static final int RGBA_1010102 = 0x2b;
|
||||||
/** Format: opaque format used for raw data transfer; must have a height of 1 */
|
/** Format: opaque format used for raw data transfer; must have a height of 1 */
|
||||||
public static final int BLOB = 0x21;
|
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 */
|
/** Format: 16 bits depth */
|
||||||
public static final int D_16 = 0x30;
|
public static final int D_16 = 0x30;
|
||||||
/** Format: 24 bits depth */
|
/** Format: 24 bits depth */
|
||||||
@@ -396,6 +399,7 @@ public final class HardwareBuffer implements Parcelable, AutoCloseable {
|
|||||||
case RGB_565:
|
case RGB_565:
|
||||||
case RGB_888:
|
case RGB_888:
|
||||||
case BLOB:
|
case BLOB:
|
||||||
|
case YCBCR_420_888:
|
||||||
case D_16:
|
case D_16:
|
||||||
case D_24:
|
case D_24:
|
||||||
case DS_24UI8:
|
case DS_24UI8:
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ import java.nio.ByteOrder;
|
|||||||
import java.nio.ReadOnlyBufferException;
|
import java.nio.ReadOnlyBufferException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.BlockingQueue;
|
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
|
* If this codec is to be used with {@link LinearBlock} and/or {@link
|
||||||
* GraphicBlock}, pass this flag.
|
* HardwareBuffer}, pass this flag.
|
||||||
* <p>
|
* <p>
|
||||||
* When this flag is set, the following APIs throw {@link IncompatibleWithBlockModelException}.
|
* When this flag is set, the following APIs throw {@link IncompatibleWithBlockModelException}.
|
||||||
* <ul>
|
* <ul>
|
||||||
@@ -1989,6 +1991,19 @@ final public class MediaCodec {
|
|||||||
* Thrown when the codec is configured for block model and an incompatible API is called.
|
* Thrown when the codec is configured for block model and an incompatible API is called.
|
||||||
*/
|
*/
|
||||||
public class IncompatibleWithBlockModelException extends RuntimeException {
|
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 {
|
throws CryptoException {
|
||||||
synchronized(mBufferLock) {
|
synchronized(mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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);
|
invalidateByteBuffer(mCachedInputBuffers, index);
|
||||||
mDequeuedInputBuffers.remove(index);
|
mDequeuedInputBuffers.remove(index);
|
||||||
@@ -2784,7 +2801,9 @@ final public class MediaCodec {
|
|||||||
int flags) throws CryptoException {
|
int flags) throws CryptoException {
|
||||||
synchronized(mBufferLock) {
|
synchronized(mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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);
|
invalidateByteBuffer(mCachedInputBuffers, index);
|
||||||
mDequeuedInputBuffers.remove(index);
|
mDequeuedInputBuffers.remove(index);
|
||||||
@@ -2819,7 +2838,9 @@ final public class MediaCodec {
|
|||||||
public final int dequeueInputBuffer(long timeoutUs) {
|
public final int dequeueInputBuffer(long timeoutUs) {
|
||||||
synchronized (mBufferLock) {
|
synchronized (mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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);
|
int res = native_dequeueInputBuffer(timeoutUs);
|
||||||
@@ -2989,178 +3010,21 @@ final public class MediaCodec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Section of memory that represents a graphic block. Applications may
|
* Map a {@link HardwareBuffer} object into {@link Image}, so that the content of the buffer is
|
||||||
* acquire a block via {@link GraphicBlock#obtain} and queue
|
* accessible. Depending on the usage and pixel format of the hardware buffer, it may not be
|
||||||
* the block as an input buffer to a codec, or get a block allocated by
|
* mappable; this method returns null in that case.
|
||||||
* codec as an output buffer from {@link OutputFrame}.
|
|
||||||
*
|
*
|
||||||
* {@see QueueRequest#setGraphicBlock}
|
* @param hardwareBuffer {@link HardwareBuffer} to map.
|
||||||
* {@see OutputFrame#getGraphicBlock}
|
* @return Mapped {@link Image} object, or null if the buffer is not mappable.
|
||||||
*/
|
*/
|
||||||
public static final class GraphicBlock {
|
public static @Nullable Image mapHardwareBuffer(@NonNull HardwareBuffer hardwareBuffer) {
|
||||||
// No public constructors.
|
return native_mapHardwareBuffer(hardwareBuffer);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static native @Nullable Image native_mapHardwareBuffer(
|
||||||
* Map the memory and return the mapped region.
|
@NonNull HardwareBuffer hardwareBuffer);
|
||||||
* <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();
|
private static native void native_closeMediaImage(long context);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder-like class for queue requests. Use this class to prepare a
|
* Builder-like class for queue requests. Use this class to prepare a
|
||||||
@@ -3185,7 +3049,7 @@ final public class MediaCodec {
|
|||||||
* @param offset The byte offset into the input buffer at which the data starts.
|
* @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 size The number of bytes of valid input data.
|
||||||
* @param cryptoInfo Metadata describing the structure of the encrypted input sample.
|
* @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
|
* @return this object
|
||||||
* @throws IllegalStateException if a buffer is already set
|
* @throws IllegalStateException if a buffer is already set
|
||||||
*/
|
*/
|
||||||
@@ -3197,7 +3061,7 @@ final public class MediaCodec {
|
|||||||
if (!isAccessible()) {
|
if (!isAccessible()) {
|
||||||
throw new IllegalStateException("The request is stale");
|
throw new IllegalStateException("The request is stale");
|
||||||
}
|
}
|
||||||
if (mLinearBlock != null || mGraphicBlock != null) {
|
if (mLinearBlock != null || mHardwareBuffer != null) {
|
||||||
throw new IllegalStateException("Cannot set block twice");
|
throw new IllegalStateException("Cannot set block twice");
|
||||||
}
|
}
|
||||||
mLinearBlock = block;
|
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}.
|
* 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
|
* @return this object
|
||||||
* @throws IllegalStateException if a buffer is already set
|
* @throws IllegalStateException if a buffer is already set
|
||||||
*/
|
*/
|
||||||
public @NonNull QueueRequest setGraphicBlock(
|
public @NonNull QueueRequest setHardwareBuffer(
|
||||||
@NonNull GraphicBlock block) {
|
@NonNull HardwareBuffer buffer) {
|
||||||
if (!isAccessible()) {
|
if (!isAccessible()) {
|
||||||
throw new IllegalStateException("The request is stale");
|
throw new IllegalStateException("The request is stale");
|
||||||
}
|
}
|
||||||
if (mLinearBlock != null || mGraphicBlock != null) {
|
if (mLinearBlock != null || mHardwareBuffer != null) {
|
||||||
throw new IllegalStateException("Cannot set block twice");
|
throw new IllegalStateException("Cannot set block twice");
|
||||||
}
|
}
|
||||||
mGraphicBlock = block;
|
mHardwareBuffer = buffer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3375,7 +3244,7 @@ final public class MediaCodec {
|
|||||||
if (!isAccessible()) {
|
if (!isAccessible()) {
|
||||||
throw new IllegalStateException("The request is stale");
|
throw new IllegalStateException("The request is stale");
|
||||||
}
|
}
|
||||||
if (mLinearBlock == null && mGraphicBlock == null) {
|
if (mLinearBlock == null && mHardwareBuffer == null) {
|
||||||
throw new IllegalStateException("No block is set");
|
throw new IllegalStateException("No block is set");
|
||||||
}
|
}
|
||||||
setAccessible(false);
|
setAccessible(false);
|
||||||
@@ -3384,9 +3253,9 @@ final public class MediaCodec {
|
|||||||
mIndex, mLinearBlock, mOffset, mSize, mCryptoInfo,
|
mIndex, mLinearBlock, mOffset, mSize, mCryptoInfo,
|
||||||
mPresentationTimeUs, mFlags,
|
mPresentationTimeUs, mFlags,
|
||||||
mTuningKeys, mTuningValues);
|
mTuningKeys, mTuningValues);
|
||||||
} else if (mGraphicBlock != null) {
|
} else if (mHardwareBuffer != null) {
|
||||||
mCodec.native_queueGraphicBlock(
|
mCodec.native_queueHardwareBuffer(
|
||||||
mIndex, mGraphicBlock, mPresentationTimeUs, mFlags,
|
mIndex, mHardwareBuffer, mPresentationTimeUs, mFlags,
|
||||||
mTuningKeys, mTuningValues);
|
mTuningKeys, mTuningValues);
|
||||||
}
|
}
|
||||||
clear();
|
clear();
|
||||||
@@ -3397,7 +3266,7 @@ final public class MediaCodec {
|
|||||||
mOffset = 0;
|
mOffset = 0;
|
||||||
mSize = 0;
|
mSize = 0;
|
||||||
mCryptoInfo = null;
|
mCryptoInfo = null;
|
||||||
mGraphicBlock = null;
|
mHardwareBuffer = null;
|
||||||
mPresentationTimeUs = 0;
|
mPresentationTimeUs = 0;
|
||||||
mFlags = 0;
|
mFlags = 0;
|
||||||
mTuningKeys.clear();
|
mTuningKeys.clear();
|
||||||
@@ -3420,7 +3289,7 @@ final public class MediaCodec {
|
|||||||
private int mOffset = 0;
|
private int mOffset = 0;
|
||||||
private int mSize = 0;
|
private int mSize = 0;
|
||||||
private MediaCodec.CryptoInfo mCryptoInfo = null;
|
private MediaCodec.CryptoInfo mCryptoInfo = null;
|
||||||
private GraphicBlock mGraphicBlock = null;
|
private HardwareBuffer mHardwareBuffer = null;
|
||||||
private long mPresentationTimeUs = 0;
|
private long mPresentationTimeUs = 0;
|
||||||
private @BufferFlag int mFlags = 0;
|
private @BufferFlag int mFlags = 0;
|
||||||
private final ArrayList<String> mTuningKeys = new ArrayList<>();
|
private final ArrayList<String> mTuningKeys = new ArrayList<>();
|
||||||
@@ -3440,9 +3309,9 @@ final public class MediaCodec {
|
|||||||
@NonNull ArrayList<String> keys,
|
@NonNull ArrayList<String> keys,
|
||||||
@NonNull ArrayList<Object> values);
|
@NonNull ArrayList<Object> values);
|
||||||
|
|
||||||
private native void native_queueGraphicBlock(
|
private native void native_queueHardwareBuffer(
|
||||||
int index,
|
int index,
|
||||||
@NonNull GraphicBlock block,
|
@NonNull HardwareBuffer buffer,
|
||||||
long presentationTimeUs,
|
long presentationTimeUs,
|
||||||
int flags,
|
int flags,
|
||||||
@NonNull ArrayList<String> keys,
|
@NonNull ArrayList<String> keys,
|
||||||
@@ -3535,7 +3404,9 @@ final public class MediaCodec {
|
|||||||
@NonNull BufferInfo info, long timeoutUs) {
|
@NonNull BufferInfo info, long timeoutUs) {
|
||||||
synchronized (mBufferLock) {
|
synchronized (mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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);
|
int res = native_dequeueOutputBuffer(info, timeoutUs);
|
||||||
@@ -3917,7 +3788,10 @@ final public class MediaCodec {
|
|||||||
public ByteBuffer[] getInputBuffers() {
|
public ByteBuffer[] getInputBuffers() {
|
||||||
synchronized (mBufferLock) {
|
synchronized (mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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) {
|
if (mCachedInputBuffers == null) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
@@ -3953,7 +3827,9 @@ final public class MediaCodec {
|
|||||||
public ByteBuffer[] getOutputBuffers() {
|
public ByteBuffer[] getOutputBuffers() {
|
||||||
synchronized (mBufferLock) {
|
synchronized (mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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) {
|
if (mCachedOutputBuffers == null) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
@@ -3985,7 +3861,10 @@ final public class MediaCodec {
|
|||||||
public ByteBuffer getInputBuffer(int index) {
|
public ByteBuffer getInputBuffer(int index) {
|
||||||
synchronized (mBufferLock) {
|
synchronized (mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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);
|
ByteBuffer newBuffer = getBuffer(true /* input */, index);
|
||||||
@@ -4019,7 +3898,10 @@ final public class MediaCodec {
|
|||||||
public Image getInputImage(int index) {
|
public Image getInputImage(int index) {
|
||||||
synchronized (mBufferLock) {
|
synchronized (mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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);
|
Image newImage = getImage(true /* input */, index);
|
||||||
@@ -4053,7 +3935,9 @@ final public class MediaCodec {
|
|||||||
public ByteBuffer getOutputBuffer(int index) {
|
public ByteBuffer getOutputBuffer(int index) {
|
||||||
synchronized (mBufferLock) {
|
synchronized (mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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);
|
ByteBuffer newBuffer = getBuffer(false /* input */, index);
|
||||||
@@ -4086,7 +3970,9 @@ final public class MediaCodec {
|
|||||||
public Image getOutputImage(int index) {
|
public Image getOutputImage(int index) {
|
||||||
synchronized (mBufferLock) {
|
synchronized (mBufferLock) {
|
||||||
if (mBufferMode == BUFFER_MODE_BLOCK) {
|
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);
|
Image newImage = getImage(false /* input */, index);
|
||||||
@@ -4112,22 +3998,22 @@ final public class MediaCodec {
|
|||||||
* @throws IllegalStateException if this output frame is not linear.
|
* @throws IllegalStateException if this output frame is not linear.
|
||||||
*/
|
*/
|
||||||
public @Nullable LinearBlock getLinearBlock() {
|
public @Nullable LinearBlock getLinearBlock() {
|
||||||
if (mGraphicBlock != null) {
|
if (mHardwareBuffer != null) {
|
||||||
throw new IllegalStateException("This output frame is not linear");
|
throw new IllegalStateException("This output frame is not linear");
|
||||||
}
|
}
|
||||||
return mLinearBlock;
|
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.
|
* @throws IllegalStateException if this output frame is not graphic.
|
||||||
*/
|
*/
|
||||||
public @Nullable GraphicBlock getGraphicBlock() {
|
public @Nullable HardwareBuffer getHardwareBuffer() {
|
||||||
if (mLinearBlock != null) {
|
if (mLinearBlock != null) {
|
||||||
throw new IllegalStateException("This output frame is not graphic");
|
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.
|
* the previous frame. The entries may have been removed/changed/added.
|
||||||
* Client can find out what the change is by querying {@link MediaFormat}
|
* Client can find out what the change is by querying {@link MediaFormat}
|
||||||
* object returned from {@link #getFormat}.
|
* object returned from {@link #getFormat}.
|
||||||
*/
|
*/
|
||||||
public void retrieveChangedKeys(@NonNull Set<String> keys) {
|
public @NonNull Set<String> getChangedKeys() {
|
||||||
keys.clear();
|
if (mKeySet.isEmpty() && !mChangedKeys.isEmpty()) {
|
||||||
keys.addAll(mChangedKeys);
|
mKeySet.addAll(mChangedKeys);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableSet(mKeySet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
mLinearBlock = null;
|
mLinearBlock = null;
|
||||||
mGraphicBlock = null;
|
mHardwareBuffer = null;
|
||||||
mFormat = null;
|
mFormat = null;
|
||||||
mChangedKeys.clear();
|
mChangedKeys.clear();
|
||||||
|
mKeySet.clear();
|
||||||
mLoaded = false;
|
mLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4194,11 +4083,12 @@ final public class MediaCodec {
|
|||||||
|
|
||||||
private final int mIndex;
|
private final int mIndex;
|
||||||
private LinearBlock mLinearBlock = null;
|
private LinearBlock mLinearBlock = null;
|
||||||
private GraphicBlock mGraphicBlock = null;
|
private HardwareBuffer mHardwareBuffer = null;
|
||||||
private long mPresentationTimeUs = 0;
|
private long mPresentationTimeUs = 0;
|
||||||
private @BufferFlag int mFlags = 0;
|
private @BufferFlag int mFlags = 0;
|
||||||
private MediaFormat mFormat = null;
|
private MediaFormat mFormat = null;
|
||||||
private final ArrayList<String> mChangedKeys = new ArrayList<>();
|
private final ArrayList<String> mChangedKeys = new ArrayList<>();
|
||||||
|
private final Set<String> mKeySet = new HashSet<>();
|
||||||
private boolean mAccessible = false;
|
private boolean mAccessible = false;
|
||||||
private boolean mLoaded = false;
|
private boolean mLoaded = false;
|
||||||
}
|
}
|
||||||
@@ -4773,6 +4663,7 @@ final public class MediaCodec {
|
|||||||
private final ByteBuffer mInfo;
|
private final ByteBuffer mInfo;
|
||||||
private final int mXOffset;
|
private final int mXOffset;
|
||||||
private final int mYOffset;
|
private final int mYOffset;
|
||||||
|
private final long mBufferContext;
|
||||||
|
|
||||||
private final static int TYPE_YUV = 1;
|
private final static int TYPE_YUV = 1;
|
||||||
|
|
||||||
@@ -4828,6 +4719,9 @@ final public class MediaCodec {
|
|||||||
if (mBuffer != null) {
|
if (mBuffer != null) {
|
||||||
java.nio.NioUtils.freeDirectBuffer(mBuffer);
|
java.nio.NioUtils.freeDirectBuffer(mBuffer);
|
||||||
}
|
}
|
||||||
|
if (mBufferContext != 0) {
|
||||||
|
native_closeMediaImage(mBufferContext);
|
||||||
|
}
|
||||||
mIsImageValid = false;
|
mIsImageValid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4860,6 +4754,8 @@ final public class MediaCodec {
|
|||||||
mYOffset = yOffset;
|
mYOffset = yOffset;
|
||||||
mInfo = info;
|
mInfo = info;
|
||||||
|
|
||||||
|
mBufferContext = 0;
|
||||||
|
|
||||||
// read media-info. See MediaImage2
|
// read media-info. See MediaImage2
|
||||||
if (info.remaining() == 104) {
|
if (info.remaining() == 104) {
|
||||||
int type = info.getInt();
|
int type = info.getInt();
|
||||||
@@ -4921,7 +4817,7 @@ final public class MediaCodec {
|
|||||||
|
|
||||||
public MediaImage(
|
public MediaImage(
|
||||||
@NonNull Image.Plane[] planes, int width, int height, int format, boolean readOnly,
|
@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;
|
mWidth = width;
|
||||||
mHeight = height;
|
mHeight = height;
|
||||||
mFormat = format;
|
mFormat = format;
|
||||||
@@ -4941,6 +4837,8 @@ final public class MediaCodec {
|
|||||||
}
|
}
|
||||||
cropRect.offset(-xOffset, -yOffset);
|
cropRect.offset(-xOffset, -yOffset);
|
||||||
super.setCropRect(cropRect);
|
super.setCropRect(cropRect);
|
||||||
|
|
||||||
|
mBufferContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MediaPlane extends Plane {
|
private class MediaPlane extends Plane {
|
||||||
|
|||||||
@@ -34,10 +34,14 @@
|
|||||||
#include <nativehelper/JNIHelp.h>
|
#include <nativehelper/JNIHelp.h>
|
||||||
#include <nativehelper/ScopedLocalRef.h>
|
#include <nativehelper/ScopedLocalRef.h>
|
||||||
|
|
||||||
|
#include <C2AllocatorGralloc.h>
|
||||||
|
#include <C2BlockInternal.h>
|
||||||
#include <C2Buffer.h>
|
#include <C2Buffer.h>
|
||||||
|
|
||||||
#include <android/hardware/cas/native/1.0/IDescrambler.h>
|
#include <android/hardware/cas/native/1.0/IDescrambler.h>
|
||||||
|
|
||||||
|
#include <android_runtime/android_hardware_HardwareBuffer.h>
|
||||||
|
|
||||||
#include <binder/MemoryHeapBase.h>
|
#include <binder/MemoryHeapBase.h>
|
||||||
|
|
||||||
#include <cutils/compiler.h>
|
#include <cutils/compiler.h>
|
||||||
@@ -58,6 +62,8 @@
|
|||||||
#include <media/stagefright/PersistentSurface.h>
|
#include <media/stagefright/PersistentSurface.h>
|
||||||
#include <mediadrm/ICrypto.h>
|
#include <mediadrm/ICrypto.h>
|
||||||
|
|
||||||
|
#include <private/android/AHardwareBufferHelpers.h>
|
||||||
|
|
||||||
#include <system/window.h>
|
#include <system/window.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
@@ -143,15 +149,6 @@ static struct {
|
|||||||
jfieldID lockId;
|
jfieldID lockId;
|
||||||
} gLinearBlockInfo;
|
} gLinearBlockInfo;
|
||||||
|
|
||||||
static struct {
|
|
||||||
jclass clazz;
|
|
||||||
jmethodID ctorId;
|
|
||||||
jmethodID setInternalStateId;
|
|
||||||
jfieldID contextId;
|
|
||||||
jfieldID validId;
|
|
||||||
jfieldID lockId;
|
|
||||||
} gGraphicBlockInfo;
|
|
||||||
|
|
||||||
struct fields_t {
|
struct fields_t {
|
||||||
jmethodID postEventFromNativeID;
|
jmethodID postEventFromNativeID;
|
||||||
jmethodID lockAndGetContextID;
|
jmethodID lockAndGetContextID;
|
||||||
@@ -167,7 +164,7 @@ struct fields_t {
|
|||||||
jfieldID patternSkipBlocksID;
|
jfieldID patternSkipBlocksID;
|
||||||
jfieldID queueRequestIndexID;
|
jfieldID queueRequestIndexID;
|
||||||
jfieldID outputFrameLinearBlockID;
|
jfieldID outputFrameLinearBlockID;
|
||||||
jfieldID outputFrameGraphicBlockID;
|
jfieldID outputFrameHardwareBufferID;
|
||||||
jfieldID outputFrameChangedKeysID;
|
jfieldID outputFrameChangedKeysID;
|
||||||
jfieldID outputFrameFormatID;
|
jfieldID outputFrameFormatID;
|
||||||
};
|
};
|
||||||
@@ -176,16 +173,6 @@ static fields_t gFields;
|
|||||||
static const void *sRefBaseOwner;
|
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(
|
JMediaCodec::JMediaCodec(
|
||||||
@@ -706,16 +693,22 @@ status_t JMediaCodec::getOutputFrame(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case C2BufferData::GRAPHIC: {
|
case C2BufferData::GRAPHIC: {
|
||||||
std::unique_ptr<JMediaCodecGraphicBlock> context{new JMediaCodecGraphicBlock};
|
const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
|
||||||
context->mBuffer = c2Buffer;
|
uint32_t width, height, format, stride, igbp_slot, generation;
|
||||||
ScopedLocalRef<jobject> graphicBlock{env, env->NewObject(
|
uint64_t usage, igbp_id;
|
||||||
gGraphicBlockInfo.clazz, gGraphicBlockInfo.ctorId)};
|
_UnwrapNativeCodec2GrallocMetadata(
|
||||||
env->CallVoidMethod(
|
c2Handle, &width, &height, &format, &usage, &stride, &generation,
|
||||||
graphicBlock.get(),
|
&igbp_id, &igbp_slot);
|
||||||
gGraphicBlockInfo.setInternalStateId,
|
native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
|
||||||
(jlong)context.release(),
|
GraphicBuffer* graphicBuffer = new GraphicBuffer(
|
||||||
true);
|
grallocHandle, GraphicBuffer::CLONE_HANDLE,
|
||||||
env->SetObjectField(frame, gFields.outputFrameGraphicBlockID, graphicBlock.get());
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
|
case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
|
||||||
@@ -737,16 +730,7 @@ status_t JMediaCodec::getOutputFrame(
|
|||||||
true);
|
true);
|
||||||
env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
|
env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
|
||||||
} else {
|
} else {
|
||||||
std::unique_ptr<JMediaCodecGraphicBlock> context{new JMediaCodecGraphicBlock};
|
// No-op.
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1873,6 +1857,113 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
|
|||||||
env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
|
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(
|
static status_t ConvertKeyValueListsToAMessage(
|
||||||
JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
|
JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
|
||||||
static struct Fields {
|
static struct Fields {
|
||||||
@@ -2031,11 +2122,6 @@ static void android_media_MediaCodec_native_queueLinearBlock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
NativeCryptoInfo cryptoInfo{env, cryptoInfoObj};
|
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(
|
err = codec->queueEncryptedLinearBlock(
|
||||||
index,
|
index,
|
||||||
memory,
|
memory,
|
||||||
@@ -2059,10 +2145,10 @@ static void android_media_MediaCodec_native_queueLinearBlock(
|
|||||||
throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
|
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,
|
JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
|
||||||
jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
|
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);
|
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
|
||||||
|
|
||||||
@@ -2078,29 +2164,21 @@ static void android_media_MediaCodec_native_queueGraphicBlock(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<C2Buffer> buffer;
|
AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
|
||||||
std::shared_ptr<C2GraphicBlock> block;
|
env, bufferObj);
|
||||||
ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gGraphicBlockInfo.lockId)};
|
sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
|
||||||
if (env->MonitorEnter(lock.get()) == JNI_OK) {
|
C2Handle *handle = WrapNativeCodec2GrallocHandle(
|
||||||
if (env->GetBooleanField(bufferObj, gGraphicBlockInfo.validId)) {
|
graphicBuffer->handle, graphicBuffer->format,
|
||||||
JMediaCodecGraphicBlock *context = (JMediaCodecGraphicBlock *)env->GetLongField(
|
graphicBuffer->width, graphicBuffer->height,
|
||||||
bufferObj, gGraphicBlockInfo.contextId);
|
graphicBuffer->usage, graphicBuffer->stride);
|
||||||
buffer = context->mBuffer;
|
std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(handle);
|
||||||
block = context->mBlock;
|
|
||||||
}
|
|
||||||
env->MonitorExit(lock.get());
|
|
||||||
} else {
|
|
||||||
throwExceptionAsNecessary(env, INVALID_OPERATION);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!block && !buffer) {
|
if (!block) {
|
||||||
throwExceptionAsNecessary(env, BAD_VALUE);
|
throwExceptionAsNecessary(env, BAD_VALUE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!buffer) {
|
std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
|
||||||
buffer = C2Buffer::CreateGraphicBuffer(block->share(block->crop(), C2Fence{}));
|
block->crop(), C2Fence{}));
|
||||||
}
|
|
||||||
AString errorDetailMsg;
|
AString errorDetailMsg;
|
||||||
err = codec->queueBuffer(index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
|
err = codec->queueBuffer(index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
|
||||||
throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
|
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;");
|
env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
|
||||||
CHECK(gFields.outputFrameLinearBlockID != NULL);
|
CHECK(gFields.outputFrameLinearBlockID != NULL);
|
||||||
|
|
||||||
gFields.outputFrameGraphicBlockID =
|
gFields.outputFrameHardwareBufferID =
|
||||||
env->GetFieldID(clazz.get(), "mGraphicBlock", "Landroid/media/MediaCodec$GraphicBlock;");
|
env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
|
||||||
CHECK(gFields.outputFrameGraphicBlockID != NULL);
|
CHECK(gFields.outputFrameHardwareBufferID != NULL);
|
||||||
|
|
||||||
gFields.outputFrameChangedKeysID =
|
gFields.outputFrameChangedKeysID =
|
||||||
env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
|
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;");
|
gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
|
||||||
CHECK(gLinearBlockInfo.lockId != NULL);
|
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(
|
static void android_media_MediaCodec_native_setup(
|
||||||
@@ -2949,196 +3006,6 @@ static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
|
|||||||
return isCompatible;
|
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[] = {
|
static const JNINativeMethod gMethods[] = {
|
||||||
{ "native_release", "()V", (void *)android_media_MediaCodec_release },
|
{ "native_release", "()V", (void *)android_media_MediaCodec_release },
|
||||||
|
|
||||||
@@ -3184,14 +3051,20 @@ static const JNINativeMethod gMethods[] = {
|
|||||||
{ "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
|
{ "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
|
||||||
(void *)android_media_MediaCodec_queueSecureInputBuffer },
|
(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",
|
{ "native_queueLinearBlock",
|
||||||
"(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
|
"(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
|
||||||
"Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
|
"Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
|
||||||
(void *)android_media_MediaCodec_native_queueLinearBlock },
|
(void *)android_media_MediaCodec_native_queueLinearBlock },
|
||||||
|
|
||||||
{ "native_queueGraphicBlock",
|
{ "native_queueHardwareBuffer",
|
||||||
"(ILandroid/media/MediaCodec$GraphicBlock;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
|
"(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
|
||||||
(void *)android_media_MediaCodec_native_queueGraphicBlock },
|
(void *)android_media_MediaCodec_native_queueHardwareBuffer },
|
||||||
|
|
||||||
{ "native_getOutputFrame",
|
{ "native_getOutputFrame",
|
||||||
"(Landroid/media/MediaCodec$OutputFrame;I)V",
|
"(Landroid/media/MediaCodec$OutputFrame;I)V",
|
||||||
@@ -3265,20 +3138,6 @@ static const JNINativeMethod gLinearBlockMethods[] = {
|
|||||||
(void *)android_media_MediaCodec_LinearBlock_checkCompatible },
|
(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 register_android_media_MediaCodec(JNIEnv *env) {
|
||||||
int result = AndroidRuntime::registerNativeMethods(env,
|
int result = AndroidRuntime::registerNativeMethods(env,
|
||||||
"android/media/MediaCodec", gMethods, NELEM(gMethods));
|
"android/media/MediaCodec", gMethods, NELEM(gMethods));
|
||||||
@@ -3289,12 +3148,5 @@ int register_android_media_MediaCodec(JNIEnv *env) {
|
|||||||
"android/media/MediaCodec$LinearBlock",
|
"android/media/MediaCodec$LinearBlock",
|
||||||
gLinearBlockMethods,
|
gLinearBlockMethods,
|
||||||
NELEM(gLinearBlockMethods));
|
NELEM(gLinearBlockMethods));
|
||||||
if (result != JNI_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = AndroidRuntime::registerNativeMethods(env,
|
|
||||||
"android/media/MediaCodec$GraphicBlock",
|
|
||||||
gGraphicBlockMethods,
|
|
||||||
NELEM(gGraphicBlockMethods));
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user