Bug fixes and cleanup for video codec profiles
Bug fixes:
- removed the line VideoDecoderNbProfLevel[c] = 0;"
it could overwrite the MPEG2 entry if only one codec implementation,
or worse if there were multiple codec implementations
- android_videoCodec_getProfileLevelCombinationNb was returning success
and zero count if a decoder has zero profile/level combinations,
but OpenMAX AL 1.0.1 spec says it must fail in that case.
Minor cleanup:
- omx does not need to be global
- We only use the first codec implementation for a given
decoder ID / MIME type, so simplify the code that iterates through
the array of codec implementations
- Add some const
- Add some comments
Also includes #if 0 code to restrict reported video codec profiles,
as a placeholder -- disabled for now.
Change-Id: I81991f164efaf3606beb5789e1a79cf76ad033a0
diff --git a/src/android/VideoCodec_to_android.cpp b/src/android/VideoCodec_to_android.cpp
index e2d8295..20aad28 100644
--- a/src/android/VideoCodec_to_android.cpp
+++ b/src/android/VideoCodec_to_android.cpp
@@ -25,8 +25,6 @@
namespace android {
-static sp<IOMX> omx;
-
// listed in same order as VideoCodecIds[] in file "../devices.c" with ANDROID defined
static const char *kVideoMimeTypes[] = {
MEDIA_MIMETYPE_VIDEO_MPEG2,
@@ -35,9 +33,11 @@
MEDIA_MIMETYPE_VIDEO_AVC,
MEDIA_MIMETYPE_VIDEO_VPX
};
+// must == kMaxVideoDecoders
static const size_t kNbVideoMimeTypes = sizeof(kVideoMimeTypes) / sizeof(kVideoMimeTypes[0]);
// codec capabilities in the following arrays maps to the mime types defined in kVideoMimeTypes
+// CodecCapabilities is from OMXCodec.h
static Vector<CodecCapabilities> VideoDecoderCapabilities[kNbVideoMimeTypes];
static XAuint32 VideoDecoderNbProfLevel[kNbVideoMimeTypes];
@@ -63,7 +63,7 @@
return false;
}
- omx = service->getOMX();
+ sp<IOMX> omx(service->getOMX());
if (omx.get() == NULL) {
LOGE("android_videoCodec_expose() couldn't access OMX interface");
return false;
@@ -72,22 +72,37 @@
// used to check whether no codecs were found, which is a sign of failure
NbSupportedDecoderTypes = 0;
for (size_t m = 0 ; m < kNbVideoMimeTypes ; m++) {
+ // QueryCodecs is from OMXCodec.h
if (OK == QueryCodecs(omx, kVideoMimeTypes[m], true /* queryDecoders */,
true /* hwCodecOnly */, &VideoDecoderCapabilities[m])) {
- if (!VideoDecoderCapabilities[m].empty()) {
- NbSupportedDecoderTypes++;
- }
- // for each decoder of the given decoder ID, verify it is a hardware decoder
- for (size_t c = 0 ; c < VideoDecoderCapabilities[m].size() ; c++) {
- VideoDecoderNbProfLevel[c] = 0;
- const String8& compName =
- VideoDecoderCapabilities[m].itemAt(c).mComponentName;
- // get the number of profiles and levels for this decoder
- VideoDecoderNbProfLevel[m] =
- VideoDecoderCapabilities[m].itemAt(c).mProfileLevels.size();
- if (VideoDecoderNbProfLevel[m] != 0) {
- SL_LOGV("codec %d nb prof/level=%d", m, VideoDecoderNbProfLevel[m]);
- break;
+ if (VideoDecoderCapabilities[m].empty()) {
+ VideoDecoderNbProfLevel[m] = 0;
+ } else {
+ // get the number of profiles and levels for the first codec implementation
+ // for a given decoder ID / MIME type
+ Vector<CodecProfileLevel> &profileLevels =
+ VideoDecoderCapabilities[m].editItemAt(0).mProfileLevels;
+#if 0 // Intentionally disabled example of making modifications to profile / level combinations
+ if (VideoDecoderIds[m] == XA_VIDEOCODEC_AVC) {
+ // remove non-core profile / level combinations
+ for (size_t i = 0, size = profileLevels.size(); i < size; ) {
+ CodecProfileLevel profileLevel = profileLevels.itemAt(i);
+ if (profileLevel.mProfile == XA_VIDEOPROFILE_AVC_BASELINE) {
+ // either skip past this item and don't change vector size
+ ++i;
+ } else {
+ // or remove this item, decrement the vector size,
+ // and next time through the loop check a different item at same index
+ profileLevels.removeAt(i);
+ --size;
+ }
+ }
+ }
+#endif
+ if ((VideoDecoderNbProfLevel[m] = profileLevels.size()) > 0) {
+ NbSupportedDecoderTypes++;
+ } else {
+ VideoDecoderCapabilities[m].clear();
}
}
}
@@ -102,6 +117,9 @@
for (size_t m = 0 ; m < kNbVideoMimeTypes ; m++) {
VideoDecoderCapabilities[m].clear();
}
+ // not needed
+ // memset(VideoDecoderNbProfLevel, 0, sizeof(VideoDecoderNbProfLevel));
+ // NbSupportedDecoderTypes = 0;
}
@@ -131,16 +149,17 @@
{
// translate a decoder ID to an index in the codec table
size_t decoderIndex = 0;
- *pNb = 0;
while (decoderIndex < kNbVideoMimeTypes) {
if (decoderId == VideoDecoderIds[decoderIndex]) {
*pNb = VideoDecoderNbProfLevel[decoderIndex];
- break;
+ return XA_RESULT_SUCCESS;
}
decoderIndex++;
}
- return XA_RESULT_SUCCESS;
+ // spec doesn't allow a decoder to report zero profile/level combinations
+ *pNb = 0;
+ return XA_RESULT_PARAMETER_INVALID;
}
@@ -151,13 +170,13 @@
size_t decoderIndex = 0;
while (decoderIndex < kNbVideoMimeTypes) {
if (decoderId == VideoDecoderIds[decoderIndex]) {
+ // We only look at the first codec implementation for a given decoder ID / MIME type.
+ // OpenMAX AL doesn't let you expose the capabilities of multiple codec implementations.
if (!(plIndex < VideoDecoderCapabilities[decoderIndex].itemAt(0).mProfileLevels.size()))
{
// asking for invalid profile/level
return XA_RESULT_PARAMETER_INVALID;
}
- // we only look at the first codec, OpenMAX AL doesn't let you expose the capabilities
- // of multiple codecs
// set the fields we know about
pDescr->codecId = decoderId;
pDescr->profileSetting = convertOpenMaxIlToAl(VideoDecoderCapabilities[decoderIndex].
diff --git a/src/devices.c b/src/devices.c
index bb110f1..920dd5e 100644
--- a/src/devices.c
+++ b/src/devices.c
@@ -123,9 +123,10 @@
SL_AUDIOCODEC_VORBIS
};
-const SLuint32 *Decoder_IDs = Codec_IDs;
-const SLuint32 *Encoder_IDs = Codec_IDs;
+const SLuint32 * const Decoder_IDs = Codec_IDs;
+const SLuint32 * const Encoder_IDs = Codec_IDs;
+// for ANDROID, must match size and order of kVideoMimeTypes
static const SLuint32 VideoCodecIds[] = {
XA_VIDEOCODEC_MPEG2,
XA_VIDEOCODEC_H263,
@@ -139,8 +140,9 @@
#endif
};
-const SLuint32 *VideoDecoderIds = VideoCodecIds;
+const SLuint32 * const VideoDecoderIds = VideoCodecIds;
+// for ANDROID, must == kNbVideoMimeTypes
const XAuint32 kMaxVideoDecoders = sizeof(VideoCodecIds) / sizeof(VideoCodecIds[0]);
static const SLmilliHertz SamplingRates_A[] = {
diff --git a/src/devices.h b/src/devices.h
index 5dd99bd..bf2814e 100644
--- a/src/devices.h
+++ b/src/devices.h
@@ -51,11 +51,13 @@
#define MAX_DECODERS 9 ///< (sizeof(Decoder_IDs) / sizeof(Decoder_IDs[0]))
#define MAX_ENCODERS 9 ///< (sizeof(Encoder_IDs) / sizeof(Encoder_IDs[0]))
-extern const XAuint32 *VideoDecoderIds;
+extern const XAuint32 * const VideoDecoderIds;
+#ifndef ANDROID
extern const XAuint32 kMaxVideoDecoders;
+#endif
// For now, but encoders might be different than decoders later
-extern const SLuint32 *Decoder_IDs, *Encoder_IDs;
+extern const SLuint32 * const Decoder_IDs, * const Encoder_IDs;
extern const CodecDescriptor DecoderDescriptors[], EncoderDescriptors[];
diff --git a/src/itf/IVideoDecoderCapabilities.cpp b/src/itf/IVideoDecoderCapabilities.cpp
index 8f12cb2..c9649a9 100644
--- a/src/itf/IVideoDecoderCapabilities.cpp
+++ b/src/itf/IVideoDecoderCapabilities.cpp
@@ -42,16 +42,15 @@
// If pDecodersIds is non-NULL, as an input pNumDecoders specifies the size of the
// pDecoderIds array and as an output it specifies the number of decoder IDs available
// within the pDecoderIds array.
-#ifdef ANDROID
XAuint32 numDecoders = *pNumDecoders;
+#ifdef ANDROID
const XAuint32 androidNbDecoders = android::android_videoCodec_getNbDecoders();
- if (androidNbDecoders <= numDecoders) {
+ if (androidNbDecoders < numDecoders) {
*pNumDecoders = numDecoders = androidNbDecoders;
}
android::android_videoCodec_getDecoderIds(numDecoders, pDecoderIds);
#else
- XAuint32 numDecoders = *pNumDecoders;
- if (kMaxVideoDecoders <= numDecoders) {
+ if (kMaxVideoDecoders < numDecoders) {
*pNumDecoders = numDecoders = kMaxVideoDecoders;
}
memcpy(pDecoderIds, VideoDecoderIds, numDecoders * sizeof(XAuint32));
@@ -78,6 +77,11 @@
#ifdef ANDROID
result = android::android_videoCodec_getProfileLevelCombinationNb(decoderId, pIndex);
#else
+ // Generic implementation has zero profile/level combinations for all codecs,
+ // but this is not allowed per spec:
+ // "Each decoder must support at least one profile/mode pair
+ // and therefore have at least one Codec Descriptor."
+ *pIndex = 0;
SL_LOGE("Generic implementation has no video decoder capabilities");
result = XA_RESULT_PARAMETER_INVALID;
#endif
@@ -87,7 +91,10 @@
result = android::android_videoCodec_getProfileLevelCombination(decoderId, *pIndex,
pDescriptor);
#else
+ // For the generic implementation, any index >= 0 is out of range
+#if 1 // not sure if this is needed, it's not being done for the Android case
pDescriptor->codecId = decoderId;
+#endif
SL_LOGE("Generic implementation has no video decoder capabilities");
result = XA_RESULT_PARAMETER_INVALID;
#endif