DO NOT MERGE MediaCodec: add methods to query/subscribe vendor parameters

Bug: 183242434
Test: atest android.media.cts.MediaCodecTest
Change-Id: Iaef8f8aef564dc8cda84a83f6cc628d87649b43d
This commit is contained in:
Wonsik Kim
2021-03-18 21:38:57 -07:00
parent abffe558e3
commit 197e1a7f5e
4 changed files with 327 additions and 0 deletions

View File

@@ -20445,7 +20445,9 @@ package android.media {
method @NonNull public android.media.MediaFormat getOutputFormat(int);
method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int);
method @Nullable public android.media.Image getOutputImage(int);
method @Nullable public android.media.MediaCodec.ParameterDescriptor getParameterDescriptor(@NonNull String);
method @NonNull public android.media.MediaCodec.QueueRequest getQueueRequest(int);
method @NonNull public java.util.List<java.lang.String> getSupportedVendorParameters();
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;
@@ -20464,6 +20466,8 @@ package android.media {
method public void signalEndOfInputStream();
method public void start();
method public void stop();
method public void subscribeToVendorParameters(@NonNull java.util.List<java.lang.String>);
method public void unsubscribeFromVendorParameters(@NonNull java.util.List<java.lang.String>);
field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
@@ -20585,6 +20589,11 @@ package android.media {
method public long getPresentationTimeUs();
}
public class MediaCodec.ParameterDescriptor {
method @NonNull public String getName();
method public int getType();
}
public final class MediaCodec.QueueRequest {
method public void queue();
method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);

View File

@@ -45,6 +45,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -4554,6 +4555,128 @@ final public class MediaCodec {
private native void native_enableOnFrameRenderedListener(boolean enable);
/**
* Returns a list of vendor parameter names.
* <p>
* This method can be called in any codec state except for released state.
*
* @return a list containing supported vendor parameters; an empty
* list if no vendor parameters are supported. The order of the
* parameters is arbitrary.
* @throws IllegalStateException if in the Released state.
*/
@NonNull
public List<String> getSupportedVendorParameters() {
return native_getSupportedVendorParameters();
}
@NonNull
private native List<String> native_getSupportedVendorParameters();
/**
* Contains description of a parameter.
*/
public class ParameterDescriptor {
private ParameterDescriptor() {}
/**
* Returns the name of the parameter.
*/
@NonNull
public String getName() {
return mName;
}
/**
* Returns the type of the parameter.
* {@link MediaFormat#TYPE_NULL} is never returned.
*/
@MediaFormat.Type
public int getType() {
return mType;
}
private String mName;
private @MediaFormat.Type int mType;
}
/**
* Describe a parameter with the name.
* <p>
* This method can be called in any codec state except for released state.
*
* @param name name of the parameter to describe, typically one from
* {@link #getSupportedVendorParameters}.
* @return {@link ParameterDescriptor} object that describes the parameter.
* {@code null} if unrecognized / not able to describe.
* @throws IllegalStateException if in the Released state.
*/
@Nullable
public ParameterDescriptor getParameterDescriptor(@NonNull String name) {
return native_getParameterDescriptor(name);
}
@Nullable
private native ParameterDescriptor native_getParameterDescriptor(@NonNull String name);
/**
* Subscribe to vendor parameters, so that changes to these parameters generate
* output format change event.
* <p>
* Unrecognized parameter names or standard (non-vendor) parameter names will be ignored.
* {@link #reset} also resets the list of subscribed parameters.
* If a parameter in {@code names} is already subscribed, it will remain subscribed.
* <p>
* This method can be called in any codec state except for released state. When called in
* running state with newly subscribed parameters, it takes effect no later than the
* processing of the subsequently queued buffer. For the new parameters, the codec will generate
* output format change event.
* <p>
* Note that any vendor parameters set in a {@link #configure} or
* {@link #setParameters} call are automatically subscribed.
* <p>
* See also {@link #INFO_OUTPUT_FORMAT_CHANGED} or {@link Callback#onOutputFormatChanged}
* for output format change events.
*
* @param names names of the vendor parameters to subscribe. This may be an empty list,
* and in that case this method will not change the list of subscribed parameters.
* @throws IllegalStateException if in the Released state.
*/
public void subscribeToVendorParameters(@NonNull List<String> names) {
native_subscribeToVendorParameters(names);
}
private native void native_subscribeToVendorParameters(@NonNull List<String> names);
/**
* Unsubscribe from vendor parameters, so that changes to these parameters
* no longer generate output format change event.
* <p>
* Unrecognized parameter names, standard (non-vendor) parameter names will be ignored.
* {@link #reset} also resets the list of subscribed parameters.
* If a parameter in {@code names} is already unsubscribed, it will remain unsubscribed.
* <p>
* This method can be called in any codec state except for released state. When called in
* running state with newly unsubscribed parameters, it takes effect no later than the
* processing of the subsequently queued buffer.
* <p>
* Note that any vendor parameters set in a {@link #configure} or
* {@link #setParameters} call are automatically subscribed, and with this method
* they can be unsubscribed.
* <p>
* See also {@link #INFO_OUTPUT_FORMAT_CHANGED} or {@link Callback#onOutputFormatChanged}
* for output format change events.
*
* @param names names of the vendor parameters to unsubscribe. This may be an empty list,
* and in that case this method will not change the list of subscribed parameters.
* @throws IllegalStateException if in the Released state.
*/
public void unsubscribeFromVendorParameters(@NonNull List<String> names) {
native_unsubscribeFromVendorParameters(names);
}
private native void native_unsubscribeFromVendorParameters(@NonNull List<String> names);
private EventHandler getEventHandlerOn(
@Nullable Handler handler, @NonNull EventHandler lastHandler) {
if (handler == null) {

View File

@@ -53,6 +53,7 @@
#include <media/MediaCodecBuffer.h>
#include <media/hardware/VideoAPI.h>
#include <media/stagefright/CodecBase.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -82,6 +83,16 @@ enum {
EVENT_FRAME_RENDERED = 3,
};
// From MediaFormat.java
enum {
TYPE_NULL = 0,
TYPE_INTEGER = 1,
TYPE_LONG = 2,
TYPE_FLOAT = 3,
TYPE_STRING = 4,
TYPE_BYTE_BUFFER = 5,
};
static struct CryptoErrorCodes {
jint cryptoErrorNoKey;
jint cryptoErrorKeyExpired;
@@ -138,6 +149,8 @@ static struct {
} gByteBufferInfo;
static struct {
jclass clazz;
jmethodID ctorId;
jmethodID sizeId;
jmethodID getId;
jmethodID addId;
@@ -152,6 +165,13 @@ static struct {
jfieldID lockId;
} gLinearBlockInfo;
static struct {
jclass clazz;
jmethodID ctorId;
jfieldID nameId;
jfieldID typeId;
} gDescriptorInfo;
struct fields_t {
jmethodID postEventFromNativeID;
jmethodID lockAndGetContextID;
@@ -922,6 +942,74 @@ void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const in
(void)mCodec->setParameters(msg);
}
status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
std::vector<std::string> names;
status_t status = mCodec->querySupportedVendorParameters(&names);
if (status != OK) {
return status;
}
*namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
for (const std::string &name : names) {
ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
(void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
}
return OK;
}
status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
const char *tmp = env->GetStringUTFChars(name, nullptr);
CodecParameterDescriptor desc;
status_t status = mCodec->describeParameter(tmp, &desc);
env->ReleaseStringUTFChars(name, tmp);
if (status != OK) {
return status;
}
jint type = TYPE_NULL;
switch (desc.type) {
case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
case AMessage::kTypeSize:
case AMessage::kTypeInt64: type = TYPE_LONG; break;
case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
case AMessage::kTypeString: type = TYPE_STRING; break;
case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
default: type = TYPE_NULL; break;
}
if (type == TYPE_NULL) {
return BAD_VALUE;
}
*descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
return OK;
}
static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
jobject it = env->CallObjectMethod(
list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
while (env->CallBooleanMethod(it, hasNextID)) {
jstring name = (jstring)env->CallObjectMethod(it, nextID);
const char *tmp = env->GetStringUTFChars(name, nullptr);
vec->push_back(tmp);
env->ReleaseStringUTFChars(name, tmp);
}
}
status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
std::vector<std::string> names;
BuildVectorFromList(env, namesObj, &names);
return mCodec->subscribeToVendorParameters(names);
}
status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
std::vector<std::string> names;
BuildVectorFromList(env, namesObj, &names);
return mCodec->unsubscribeFromVendorParameters(names);
}
static jthrowable createCodecException(
JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
ScopedLocalRef<jclass> clazz(
@@ -2602,6 +2690,73 @@ static void android_media_MediaCodec_setAudioPresentation(
codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
}
static jobject android_media_MediaCodec_getSupportedVendorParameters(
JNIEnv *env, jobject thiz) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
jobject ret = NULL;
status_t status = codec->querySupportedVendorParameters(env, &ret);
if (status != OK) {
throwExceptionAsNecessary(env, status);
}
return ret;
}
static jobject android_media_MediaCodec_getParameterDescriptor(
JNIEnv *env, jobject thiz, jstring name) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
jobject ret = NULL;
status_t status = codec->describeParameter(env, name, &ret);
if (status != OK) {
ret = NULL;
}
return ret;
}
static void android_media_MediaCodec_subscribeToVendorParameters(
JNIEnv *env, jobject thiz, jobject names) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
status_t status = codec->subscribeToVendorParameters(env, names);
if (status != OK) {
throwExceptionAsNecessary(env, status);
}
return;
}
static void android_media_MediaCodec_unsubscribeFromVendorParameters(
JNIEnv *env, jobject thiz, jobject names) {
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
status_t status = codec->unsubscribeFromVendorParameters(env, names);
if (status != OK) {
throwExceptionAsNecessary(env, status);
}
return;
}
static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
ScopedLocalRef<jclass> clazz(
env, env->FindClass("android/media/MediaCodec"));
@@ -2861,6 +3016,10 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
clazz.reset(env->FindClass("java/util/ArrayList"));
CHECK(clazz.get() != NULL);
gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
CHECK(gArrayListInfo.ctorId != NULL);
gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
CHECK(gArrayListInfo.sizeId != NULL);
@@ -2891,6 +3050,19 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
CHECK(gLinearBlockInfo.lockId != NULL);
clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
CHECK(clazz.get() != NULL);
gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
CHECK(gDescriptorInfo.ctorId != NULL);
gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
CHECK(gDescriptorInfo.nameId != NULL);
gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
CHECK(gDescriptorInfo.typeId != NULL);
}
static void android_media_MediaCodec_native_setup(
@@ -3217,6 +3389,21 @@ static const JNINativeMethod gMethods[] = {
{ "native_setAudioPresentation", "(II)V",
(void *)android_media_MediaCodec_setAudioPresentation },
{ "native_getSupportedVendorParameters", "()Ljava/util/List;",
(void *)android_media_MediaCodec_getSupportedVendorParameters },
{ "native_getParameterDescriptor",
"(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
(void *)android_media_MediaCodec_getParameterDescriptor },
{ "native_subscribeToVendorParameters",
"(Ljava/util/List;)V",
(void *)android_media_MediaCodec_subscribeToVendorParameters},
{ "native_unsubscribeFromVendorParameters",
"(Ljava/util/List;)V",
(void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
{ "native_init", "()V", (void *)android_media_MediaCodec_native_init },
{ "native_setup", "(Ljava/lang/String;ZZ)V",

View File

@@ -162,6 +162,14 @@ struct JMediaCodec : public AHandler {
void selectAudioPresentation(const int32_t presentationId, const int32_t programId);
status_t querySupportedVendorParameters(JNIEnv *env, jobject *names);
status_t describeParameter(JNIEnv *env, jstring name, jobject *desc);
status_t subscribeToVendorParameters(JNIEnv *env, jobject names);
status_t unsubscribeFromVendorParameters(JNIEnv *env, jobject names);
bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }
protected: