SkCodec: Add Android-only CodecPreference

This allows the Android framework to choose a priority for HW or
SW codecs for formats for which Android has both options (e.g.
HEIF).

Bug: b/240347107
Change-Id: Ia804027d729dc0ff3b2dea947642df64fbc32bbc
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/573639
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h
index 5af847a..fe34f94 100644
--- a/include/codec/SkCodec.h
+++ b/include/codec/SkCodec.h
@@ -284,6 +284,40 @@
     };
 
     /**
+     * Codec selection order for H/W first, H/W only, S/W first, or S/W only.
+     *
+     * Currently this is only used for HEIF decoding.
+     *
+     * The default is kNoPreference, representing no order preference and the decision order
+     * will be device specific.
+     */
+    enum class CodecPreference {
+        /**
+         * No order preference specified, and decoder/encoder will be selected according to the
+         * default order, which is decided by devices.
+         */
+        kNoPreference = 0,
+        /**
+         * Prefer software codec first. Software codec will be checked first, if no software
+         * codec can decode the given content format, hardware codec will then be checked.
+         */
+        kPreferSoftwareCodecs = 1,
+        /**
+         * Only use hardware codec.
+         */
+        kOnlyHardwareCodecs = 2,
+        /**
+         * Prefer hardware codec first. Hardware codec will be checked first, if no hardware
+         * codec can decode the given content format, software codec will then be checked.
+         */
+        kPreferHardwareCodecs = 4,
+        /**
+         * Only use software codec.
+         */
+        kOnlySoftwareCodecs = 8,
+    };
+
+    /**
      *  Additional options to pass to getPixels.
      */
     struct Options {
@@ -292,6 +326,7 @@
             , fSubset(nullptr)
             , fFrameIndex(0)
             , fPriorFrame(kNoFrame)
+            , fCodecPreference(CodecPreference::kNoPreference)
         {}
 
         ZeroInitialized            fZeroInitialized;
@@ -335,6 +370,16 @@
          *  If set to kNoFrame, the codec will decode any necessary required frame(s) first.
          */
         int                        fPriorFrame;
+
+        /**
+         * Codec selection order for H/W first, H/W only, S/W first, or S/W only.
+         *
+         * Currently this is only used for HEIF decoding.
+         *
+         * The default is kNoPreference, representing no order preference and the decision order
+         * will be device specific.
+         */
+        CodecPreference            fCodecPreference;
     };
 
     /**
diff --git a/src/codec/SkHeifCodec.cpp b/src/codec/SkHeifCodec.cpp
index 63bd9bd..583e156 100644
--- a/src/codec/SkHeifCodec.cpp
+++ b/src/codec/SkHeifCodec.cpp
@@ -19,6 +19,17 @@
 #define FOURCC(c1, c2, c3, c4) \
     ((c1) << 24 | (c2) << 16 | (c3) << 8 | (c4))
 
+static_assert((int)SkCodec::CodecPreference::kNoPreference ==
+    kHeifCodecPreference_none, "CodecPreference mismatch!");
+static_assert((int)SkCodec::CodecPreference::kPreferSoftwareCodecs ==
+    kHeifCodecPreference_preferSoftwareCodecs, "CodecPreference mismatch!");
+static_assert((int)SkCodec::CodecPreference::kOnlyHardwareCodecs ==
+    kHeifCodecPreference_onlyHardwareCodecs, "CodecPreference mismatch!");
+static_assert((int)SkCodec::CodecPreference::kPreferHardwareCodecs ==
+    kHeifCodecPreference_preferHardwareCodecs, "CodecPreference mismatch!");
+static_assert((int)SkCodec::CodecPreference::kOnlySoftwareCodecs ==
+    kHeifCodecPreference_onlySoftwareCodecs, "CodecPreference mismatch!");
+
 bool SkHeifCodec::IsSupported(const void* buffer, size_t bytesRead,
                               SkEncodedImageFormat* format) {
     // Parse the ftyp box up to bytesRead to determine if this is HEIF or AVIF.
@@ -390,6 +401,8 @@
         return kUnimplemented;
     }
 
+    fHeifDecoder->setCodecPreference((int)options.fCodecPreference);
+
     bool success;
     if (fUseAnimation) {
         success = fHeifDecoder->decodeSequence(options.fFrameIndex, &fFrameInfo);
diff --git a/src/codec/SkStubHeifDecoderAPI.h b/src/codec/SkStubHeifDecoderAPI.h
index 3fcdc94..510efe6 100644
--- a/src/codec/SkStubHeifDecoderAPI.h
+++ b/src/codec/SkStubHeifDecoderAPI.h
@@ -22,6 +22,14 @@
     kHeifColorFormat_RGBA_1010102,
 };
 
+enum HeifCodecPreference {
+    kHeifCodecPreference_none                     = 0,
+    kHeifCodecPreference_preferSoftwareCodecs     = 1,
+    kHeifCodecPreference_onlyHardwareCodecs       = 2,
+    kHeifCodecPreference_preferHardwareCodecs     = 4,
+    kHeifCodecPreference_onlySoftwareCodecs       = 8,
+};
+
 struct HeifStream {
     virtual ~HeifStream() {}
 
@@ -74,6 +82,10 @@
     uint32_t getColorDepth() {
         return 0;
     }
+
+    void setCodecPreference(int codecPreference) {
+
+    }
 };
 
 static inline HeifDecoder* createHeifDecoder() { return new HeifDecoder; }