Merge "Bug fixes and cleanup for video codec profiles"
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