BnCrypto: fix use-before-init in CREATE_PLUGIN am: 4bbfb6d881 am: a9296786e3 am: 245e44d9cf am: d8d4e80384
Change-Id: I61799ad95db7c74c031f633a6ec19c27f491bd4b
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index e4f12c8..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,7 +0,0 @@
-subdirs = [
- "camera",
- "drm/*",
- "media/*",
- "services/*",
- "soundtrigger",
-]
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 793cbf4..e584ffb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -81,6 +81,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libstagefright_xmlparser@1.0.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libstagefright_soft_*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk/libstagefright_soft_*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudiopolicyengineconfig*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..42a620b
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,121 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+apex_defaults {
+ name: "com.android.media-defaults",
+ java_libs: ["updatable-media"],
+ multilib: {
+ first: {
+ // Extractor process runs only with the primary ABI.
+ native_shared_libs: [
+ // Extractor plugins
+ "libaacextractor",
+ "libamrextractor",
+ "libflacextractor",
+ "libmidiextractor",
+ "libmkvextractor",
+ "libmp3extractor",
+ "libmp4extractor",
+ "libmpeg2extractor",
+ "liboggextractor",
+ "libwavextractor",
+ ],
+ },
+ },
+ prebuilts: [
+ "mediaextractor.policy",
+ ],
+ key: "com.android.media.key",
+ certificate: ":com.android.media.certificate",
+
+ // Use a custom AndroidManifest.xml used for API targeting.
+ androidManifest: ":com.android.media-androidManifest",
+}
+
+apex {
+ name: "com.android.media",
+ manifest: "manifest.json",
+ defaults: ["com.android.media-defaults"],
+}
+
+filegroup {
+ name: "com.android.media-androidManifest",
+ srcs: ["AndroidManifest-media.xml"],
+}
+
+filegroup {
+ name: "com.android.media.swcodec-androidManifest",
+ srcs: ["AndroidManifest-swcodec.xml"],
+}
+
+apex_defaults {
+ name: "com.android.media.swcodec-defaults",
+ binaries: [
+ "mediaswcodec",
+ ],
+ prebuilts: [
+ "com.android.media.swcodec-mediaswcodec.rc",
+ "com.android.media.swcodec-ld.config.txt",
+ "mediaswcodec.policy",
+ "mediaswcodec.xml",
+ ],
+ use_vendor: true,
+ key: "com.android.media.swcodec.key",
+ certificate: ":com.android.media.swcodec.certificate",
+
+ // Use a custom AndroidManifest.xml used for API targeting.
+ androidManifest: ":com.android.media.swcodec-androidManifest",
+}
+
+prebuilt_etc {
+ name: "com.android.media.swcodec-mediaswcodec.rc",
+ src: "mediaswcodec.rc",
+ filename: "init.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "com.android.media.swcodec-ld.config.txt",
+ src: "ld.config.txt",
+ filename: "ld.config.txt",
+ installable: false,
+}
+
+apex {
+ name: "com.android.media.swcodec",
+ manifest: "manifest_codec.json",
+ defaults: ["com.android.media.swcodec-defaults"],
+}
+
+apex_key {
+ name: "com.android.media.key",
+ public_key: "com.android.media.avbpubkey",
+ private_key: "com.android.media.pem",
+}
+
+apex_key {
+ name: "com.android.media.swcodec.key",
+ public_key: "com.android.media.swcodec.avbpubkey",
+ private_key: "com.android.media.swcodec.pem",
+}
+
+android_app_certificate {
+ name: "com.android.media.certificate",
+ certificate: "com.android.media",
+}
+
+android_app_certificate {
+ name: "com.android.media.swcodec.certificate",
+ certificate: "com.android.media.swcodec",
+}
diff --git a/apex/AndroidManifest-media.xml b/apex/AndroidManifest-media.xml
new file mode 100644
index 0000000..1af4586
--- /dev/null
+++ b/apex/AndroidManifest-media.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media">
+ <!-- APEX does not have classes.dex -->
+ <application android:hasCode="false" />
+ <!-- Setting maxSdk to lock the module to Q. minSdk is auto-set by build system -->
+ <uses-sdk
+ android:maxSdkVersion="29"
+ android:targetSdkVersion="29"
+ />
+</manifest>
diff --git a/apex/AndroidManifest-swcodec.xml b/apex/AndroidManifest-swcodec.xml
new file mode 100644
index 0000000..de50864
--- /dev/null
+++ b/apex/AndroidManifest-swcodec.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media.swcodec">
+ <!-- APEX does not have classes.dex -->
+ <application android:hasCode="false" />
+ <!-- Setting maxSdk to lock the module to Q. minSdk is auto-set by build system -->
+ <uses-sdk
+ android:maxSdkVersion="29"
+ android:targetSdkVersion="29"
+ />
+</manifest>
diff --git a/apex/OWNERS b/apex/OWNERS
new file mode 100644
index 0000000..5587f5f
--- /dev/null
+++ b/apex/OWNERS
@@ -0,0 +1,6 @@
+chz@google.com
+dwkang@google.com
+jiyong@google.com
+lajos@google.com
+marcone@google.com
+wjia@google.com
diff --git a/apex/TEST_MAPPING b/apex/TEST_MAPPING
new file mode 100644
index 0000000..a2e98cc
--- /dev/null
+++ b/apex/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "system/apex/tests"
+ }
+ ]
+}
diff --git a/apex/com.android.media.avbpubkey b/apex/com.android.media.avbpubkey
new file mode 100644
index 0000000..c0c8fd3
--- /dev/null
+++ b/apex/com.android.media.avbpubkey
Binary files differ
diff --git a/apex/com.android.media.pem b/apex/com.android.media.pem
new file mode 100644
index 0000000..8daa50e
--- /dev/null
+++ b/apex/com.android.media.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEA06dKiF+xQp36Xcosmac+DzJTXC9nbHy0Yqfy+zEC5hlwXbHZ
+1gAZZu8zL9p7kbBkmtSCulU0M+cTHr74gkG9UDkM/S7Z+957FzHMqWXY03gupFP7
+lcCnKtpkzsyQrABavynoxyY6dfmKZNtEFQrikK1zs80CppRoMwZS2dLogX8qO5LU
+gLe7/0PZBdbQSVA5AARE+AO6pR5Px/8QAere9TCLcm1aK9BUVOJvaAZAf7bD2f8s
+3J/lANQ1tvXXZrFL1i26H6sNja11u5/M0odg3SfqKI0x/317nLkYx8QSSHVKEjBs
+nzsyoFry4INEh/q7zSEX5+S1VA6ORjyof3u7CrGavrYwI2k6x3t+Dkc2dfNDaNY9
+9vGYD1nMyRqUzSIqaOz8q78tc1A391Lua8SB1E0Tx/FnsPjxPee0wZ1taGddkZxD
+cvMdQJhLyE6EloimFiOhkVjnAnlPYiiPEQkwJomE9kCsP9aMmyhwBOpbbRISj1ua
+edESrpTC5DHpt1owjtAfHvD8TfmPWT1KSN1iCQAuh5hnEM5LLDljc/AYvJV4L5uR
+l/6t5dE8deg9ksY6lVRrUwHsXxUtBPhM82PWSrpAPNJCHLuBBVx+zDD//kOmt5oe
+OyYJ2RcDsnLmDfFLHbPcAwuyfmxQ+pbFBfiL4NaKoUWRy0viR4/3zulysCsCAwEA
+AQKCAgAphaNIl8VVtVpdtgED79xr7MqPxjj6/ogA5sPzZY0VCR6TMwXyRri1Ce43
+0Bv32+wQt+ohlf+UwxtsJ7jnDPCP4XFb5iobkG0DguCMxw8/hU9ZK6Sqn03sSUYH
+j/g91h/3ashg8W38oQT2flGf8y+5hF2zg1+mwGykvfPZCdhVN1ZYs5h+3AzEqlHU
+JG1eRJ+6EhxZr5mZNRYfvTkttx8gaPKiczOCbu9sa7PBa6CRrZBEnxv0+GVbwUX8
+a8RjQBsJnJTsC4mwJrx3H4V2M9rb6C224ORTJBHxEBr9bcjMcD4kzV0x69IlxVHq
+m7YBGz5morxm4OZ15BkjTFkeEW8C8bdpRrYoY8ocmybWUf6g5IxpE33M699lWzdn
++xwPloJOA5sqsDIXGXt4+KPb2hjHLpqS4V9Rw1JQErBgB9/0EHqK4u1kwI1/djea
+Ny26esGgjmupq+M+G3vQysKEX8m/KhYZKw8yqG4LrzUKp1uosEXEeE+FBnPW1fwU
+OapJTAKLDAeItz2YsZ+82oTMREKR6gNoAw3yF3dxo/E4sk3IDG4y3w7A8D5dlBBM
+hx2fDqnieS/OffGndbbbIIGH0Sb1MBURNlZlXwXz1hbACc8FMYmn4iyQUJfKlCfU
+Rp1jOR4silFxEGYhSi0Jw7+AJe1prZRyZYp2ZQQ+trGvqQNhwQKCAQEA7CsaDxvP
+L9GI8yFVznAG5SZvIut3/lLA7hd4F0LKJ277hW8YMENLjvmrtEQW1dyQqQXV+CpL
+QErvgRuVj9DyV6qOKDimmpqhT+YZlbxp98N9Ba8RJ4ckw07vPNvglTjAeIZyUbRP
+VX5Onr/OFw66GLzOIhsOnRlqviOKg2wm1kfBF3OBAwVczqh4PJ4gc3rbW9jPN3pn
+eaouV4CdGIooXckV6XtQCGjWFNNzxmuknn1GbLbHslGuDUX89rQsRsk9qZGpi1M1
+Cf2yaQY0d+AjDdPslXKZ92EbDAmo3KGtoxy2hWWytZHbUhtWgguEwxDMkJhJ0yCM
+ZSLQZ2TXlC/iCwKCAQEA5W0xuNTozb2UrwqEaDCkogxgdv5NdQvlvBM7+fD4RpOY
+ItDFcudhuapnpxdbPrdl3F5bgTXZJ4jKMIKePVveugI7wNCQX7aSET3U0Qj47RzA
+vVVHb0K3SZsicpK7K067Ejk1esxrPreaTnUj14jUle20Cq+3iysJnwMFs2DkmE1B
+UK6MiBJ1+MbFuBATw7TWxu8yPyfa3JzUAEsfP8NqqIlXrK26DdGefd8C0hysiq4X
+3matZ3SDck1mCk4LS9PCZZlDqdxLM6/UIoy4cj0qbSPdFMop8zjB8lF/1OABowkT
+e/9L0dpG08G35aEJJ6vKSGnFLbstgly165PlGapeYQKCAQEAwoShuw4BsXYZIYA0
+Z4sX8secRBvDwoKwi6pi7G3DiYU8v2OIfb//zOxRg3GNiWpY8A5xdSyIvJS7/hAV
+ONY1tQUyf2hhuPdhpCh2rED62up14CeYroD+Q6uRGwRTTzTmOp8qK6eirF0TLmf2
+vEESAGwKMEcu2zBjHeayIJsExftlzAYDndRd440ZM3xeaB8p69WAn0Y/UhNchg/V
+1K9+nfiRBrTdb3/BzHd5ZVWlyjCOv94wTuw9uosJ1r0Btu/rzO2/wpSvG+KMfzpw
+HshKtwn1VAaHUBz4JQsTvV2hYba1ktv3vNs81LzVnNkV6YC9rN7x92ZYnLh3BKIn
+edOSjwKCAQAP51zeAixNLsoixCjfjBetgAwj04cNCREY04CB1/lt8wdFypEVYQK+
+OxjKVW0m0NHHz+ap81ClU+8oI7XSbQ7oeAUqXYrUh7Ria5XYE7Ylwat+tG2qQcaw
+3IcryA4fd2qyXbLeW1NH2rRgofAlHcAW0I59eybPB+G32x7HC31tLVXMwPzO5fC1
+mRnVo4+rLlsBGU2zYRDj4B82Ef8NjX9URYkFWFmgYZqKAS6R4Bj52A2hhh6ZIFOI
+VeMv7a8Mx5YfMtuk57dy0spyxqx2htTtEeJecZEs4g9Xu9yPpiOW6KcoHk9kMaxd
+O32C9oHK9TalhGd9vw7tjX2y4eKsv8mhAoIBABEtJSjQ571YUbELvJgnVILWKExj
+nURnbQ8C2j2lLdb20fi8UGJDei9g2b2oCs3SfCaMcRqoOs4uy8ZJzofPelwWY1B7
+SZezn/2d1Q/cXpaXew++krhFvJFVxya6eLD7pvEVQAsGtkp9BTi2CFIhcGo5UQdc
+pym7XjFsW0LCI8mOAleuYe7DEpEU79RdsfxgQpeh1NgFJRpupHT6I2BkVijD/TI4
+kbwz11SuznkUTB4QePIwnEzV+gqDtlny4M1Qvsk8hqcU6JUOu+MOT1qnI6ZGSsdS
+D6RhPukordC9y/cbiV6qqKBVZ39O8ydWvpto/g7G7fSL5SddFuVRnwAV7Vg=
+-----END RSA PRIVATE KEY-----
diff --git a/apex/com.android.media.pk8 b/apex/com.android.media.pk8
new file mode 100644
index 0000000..6df741e
--- /dev/null
+++ b/apex/com.android.media.pk8
Binary files differ
diff --git a/apex/com.android.media.swcodec.avbpubkey b/apex/com.android.media.swcodec.avbpubkey
new file mode 100644
index 0000000..0459723
--- /dev/null
+++ b/apex/com.android.media.swcodec.avbpubkey
Binary files differ
diff --git a/apex/com.android.media.swcodec.pem b/apex/com.android.media.swcodec.pem
new file mode 100644
index 0000000..e379cd3
--- /dev/null
+++ b/apex/com.android.media.swcodec.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEAvB6lOEEOR58KMcFlayEZjsXuPgcfHi/OPxcvfpiGLCpOcK3l
+OPChWUvDRcIHMB7BO+Csfxs0HgsHvvZfNyoNIm99WcjFbboiO7WrBBArIszPr14X
+cfY2NxzT9LBj+EqAnbdL+4OQW1/npLHNE0qtDcxL71ipbjSuKNb58E9qGL0KwvkS
+fwwueWj++bg/iz7dq0mz7iKpnxYscNm4RhJjqcG2Usmg4Ejhr8h5UmOUmTJbObC/
+vzClXQqeeuzS8NTtGVgQ/CI9gC2WN9upq2p/2T7P4U3o3CWvBytUoLKR0UyC83ey
+S8XJgOa42uWR3T/eJOI1ZS4H6Srg1o2XC8Yb8EprFI/NM6/+/5DX/FgDimsslAP6
+Qq4+pSte9v/FjWGqy7QBQaefFRGRuS63xHcSZhXC9J2CFdnxo8+65QT8r4yfQEei
+Ax/0Q94yB7VIL1pIJxHEonKjtd3iKdFEKQzADJ3edsmtHybERdJKCxcm9QIrDCsC
+4YVT9nX0OoC9RD5d5EVD7W5I6eEnRu6igrKIKgUVppeYFQNZD+o+eiNJa4yoggRl
+h8sT0/xLKjMRxAQ7fafi1j+LB2O7UgJmIDDAnidq8Aoz7h3pNi139rNWrjNfwhus
+nMcZvL9dTVv26JWeESHP/zAfAX7j1rfkDwR02ocRLquwEUs1+UHA27Wi1bMCAwEA
+AQKCAgAO3PT83tb7/arWh4s1zaWxTB4otHNW9Tv8bB6KiA6Bys3rxTGJMCnvXjcN
+eekLekKWMoguer3BaemwwtJ/D0l+YQSsZVqD8uLliNL8PTLLSxdVqb98d5GNBTAR
+8yXS5kAHNgZA1wI+1fL9ZjbnwUyu/Gc7f+vTE0J3Y5TX0c52KemBwiAd/Z5mZU9P
+96i9nbfx4p7ev8pbEWttdyZCEw3gybdYDyowzlFWjCZZxhhlij7+7eIYfwVxtncT
+C0cXVBtvly+wXBwz1mY5/5cGPiHfzkCqcndlfWy4ykmjcLhoqvzls51Ys0Xac2BD
+m0PNEVDB5UWGuv5RA9xD12gJvBtU3D7ggMw6C5RcXJT+jSYmSFtD2klWi+It8A/N
+Hv42soKskt6JqYAWE1cvJ3PEqH9ASEJNq2R0Z/PmuM000UJyzU9KId3SNwjXA1Xc
+Kn9hRga4uf9elHTjkTDt79/8+Xv7hjer9sF/S/np7g04rUjIWkuFkC/7NK2tQSh1
+mljV1sD9SF4DPfVK75LwJJaQUlI7TtGd5KJ7FzZwvb+w8ODrpW3hkt6FcI6KwE/a
+QT1T2Z9DknXJSYNdWGrj6vMHsYMiyz8IdAHSCrOB6eXCQxpitbn6W71Raw7f9UaZ
+VDK5AhTU493hkGj1no4cJwecXInMigg/c4ywk2Ibh6IV8O0nkQKCAQEA2+dQQ0IF
+vvVgmQ2WxHBD7M2mbOyf43YBY6Ka6oPBNGPVpZE8X8LoTavQLV+SgCkH8T6gY7XS
+5L4Ze0JFxfua0o1rm6+L2XrOx5F/A2Y40YcPclEik5h1woSwH/J1iHGiEhY8Nqeu
+9GCvjQojkgXx/Rn3Nz+lpvZ329O3H85RWWGF0l60RwLOkig0ZwUb619t8affmGIl
+sxdDv2nfy7OtJX8iGDua7Kf64dvVWQKKtACWkARrlkcWX3uoESxkpSDxue+z7ndH
+o7uHLfM8Tx+Rn+QvYWuRW5TPLbEDMbIYrX65ISt2r/T7v/04XdAC8YpCQRytlqPI
+fpDm15htyHBizQKCAQEA2v+5otRoY56JduISaVGlsJ/IbvKzDAIyWmM14EpRCR5E
+lu+MpTcRAiFQAbHGXr1tMlTFdVFD090WAzIKaKtADFVLXobIHeGspnRCq5OpVp9W
+RvLtVwLxflHAc2yN9/LNtnBqHUgt+S01LBPElybdGHQRTtqAKXhkp31sM21O34Go
+Pri/IxgupWxykMaW44Kig1Cr5DKvc8cwUsGuyDdJm8oBQeNPTMWqSnXtqoTWSaYg
+2kxiMTFokrkSXgufb8wng6OXt/QelywrhG3hAsldPO3GdKidDSxhWZSgpUXXFdAX
+y4GO0IcRJBF/WJtYTYtR+l84nQA2/1Ye4ujFlT0afwKCAQEAmXrXpSm2cvI2CnzW
+hqJIdkWOa6W3bn1VOOIrt5Rfy54GZnl4pumVU2igcpqq2HJKzdDFBvLHj8kyZbn6
+ktUp2NzFhzK9q/uvyNA+0vOMoojeeg4w0MzvG+WaO6Hw8FtHH9KPEiJ01LGKtSin
+bOpjXCC8T75HcsHBJBefTz6jvnt3eD2LG6jU3mPbNy/0rZG8XZaqU2PlJhsNuNI/
+VaBBL9OMy1cGqTgQvYS+YlKI1ls2uqurH4bcEaZvxhSy5iGZNQodDkoIITnofmSu
+6haBgBQ2EYuPN1kkRKKwNQY1fRneQk1gmCynbPdiWO+urkCuP12xtlr3u4aM51rG
+/Meb3QKCAQEA12SxZm9XhLOHLIBJ74A4YLGm50iZxXPbpn7xnHo7naZBe9p8EHtK
+pTeygxggrUnOPrSVyT92YMiQP/BVwIC+a+LwUDZsWMd/ke/DKxH+eY4Zw4pm2S+x
+6bXqfRwFvhr3LTr/g3FcljlalNGUh73Xs5dk9pN9fkxFY16+rw4Rh0709Uur4o6E
+QnuZar+H5Ji10kXj6nvXiR4ebybEC3QlV66k8fLqKe44AShf61jfkmxs34hFA3E/
+EyAn6ouv8rtvGdArBuh5teHho0yXBLCcnbKXgGHepfhCf2LpZeR9GZ0j6iqxFnPh
+7gGvqKyReyNOK9y/x9tQPG6tzit3OcNxbQKCAQEAuDheDOSkXPopXMvLAKOHBIdZ
+rbQ7oFTDHt59gbucM7U8/l2YtaxuKOQFBLnzQa/amIkkrtklYwOsz8E24d7Nm39w
+ykLHwX0XrmjAm6M4XKmDv66a+kSnSV6LEbKZdjvXP02DV+tGeZ5VsnNvJDquxMsD
+fvRTspB8j8CpU96szekxl/tCRhqbdw/4kVTSj5BF++OaRRcJrAyj1B2qf1ynAZE1
+gUvVPkEYa914zcrxg9XIXT4M7yqB7i8KJegOtOtcWjJ7uTiP+638AvygJLMJnSrV
++HjFZWG6P9btZmLHSEBRvwGOAilp0qejXo866l0fmnlGy7ehKz8u3PzvnlPYjQ==
+-----END RSA PRIVATE KEY-----
diff --git a/apex/com.android.media.swcodec.pk8 b/apex/com.android.media.swcodec.pk8
new file mode 100644
index 0000000..05a4216
--- /dev/null
+++ b/apex/com.android.media.swcodec.pk8
Binary files differ
diff --git a/apex/com.android.media.swcodec.x509.pem b/apex/com.android.media.swcodec.x509.pem
new file mode 100644
index 0000000..67b9b4f
--- /dev/null
+++ b/apex/com.android.media.swcodec.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF3jCCA8agAwIBAgIJAIM72JpD4v6XMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g
+VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEiMCAGA1UE
+AwwZY29tLmFuZHJvaWQubWVkaWEuc3djb2RlYzAgFw0xOTAyMTEwMjExMTFaGA80
+NzU3MDEwNzAyMTExMVowgYIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y
+bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw
+DgYDVQQLDAdBbmRyb2lkMSIwIAYDVQQDDBljb20uYW5kcm9pZC5tZWRpYS5zd2Nv
+ZGVjMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsqXE0AIWpLW9Tgq2
+nQGph7KZ6L2Q9oxviqCVHxIaPqfhM2SwTbycADIQeqrrlRxhddVkjLuMUkJa7mev
+fERmgpiOfnPIlGK6PTs2gljCkskZhF3bgfeyuHt0tsYO+UaN8MVoZD7/QdiE46w2
+OMDClG1UqgiqOBhLTEN/cHXObnUiiVXUYqN8aYZf6L6Fs3yQi2ZZgfbxTVFewqdv
+aLLOqCYnVYXZH+ZxbXESA0M+WXKgRKsYTj2GYs3eko1rFi4Y6uHVLx45yaoT5u/i
+SxPEkocyMCKvGJWu4XlSOd3EjSOMaqCOYVyGLxdlnQWQU7PZDqBSJ0SysWgpFHpB
+I15c2jhRdXOCfQ9ZtDfPZkE0a2A8kJDAoF1mzTp6IvBAWUsl5nHPw5CWkFpNad/h
+tqqGCScWbiKZuvrQ4/RQNm3f1K+mxX9TrjFigpqNO6d4pGAo1fa6sHR3xWPw/myq
+h5ZJjVnXU5Yq64S4xWOssfjpOg7RfNuvzuk3ok3MYs1mbx3vhZOj5km1f3qrgX9c
+mXjYnyXD0jJBm4uAJWXLdK9PlZvlXbztMCzYj832Io4pFLCtSxkzX75t1em36Nv0
+mNp6NtSSy6SFSq8l7IsXV2FNyUiyHWxS/UQm8pYg5Q5dWHvEEF78P6lV0wRa6FQl
+BBSgpqTAI092KIjDDtB7GQCgV5ECAwEAAaNTMFEwHQYDVR0OBBYEFAFIdFTDEDft
+ewSSAS7Fa3OZ5TXzMB8GA1UdIwQYMBaAFAFIdFTDEDftewSSAS7Fa3OZ5TXzMA8G
+A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAC5e3zXythJCGmz1FmAV
+8Y/UI+Glg6G0x/k04WaRG0DPLLjlJ1F0LM1/IReBSgXcYAL0CAgPycf/rGPOgMFm
+tQxYyjBUxKdjpIqU5DJoV1feanGveIRpto1YRKNgHuzG9rZGR4AgPnt6X4Yxlq04
+lI7QpWadXe1myARJhj3niSNY9+2wEInkx4ZuCO1LtIGqnbdc8jQ8YoVqIE5N4kuM
+ccyPYgsdABtopbjN92rueu8sfF8R6ROy+tNgb6OjpAAevtnBfZ2LXqfObKirHCK+
+k6w4WSB1UUoZ3Xgz8sJtXgokvYeInkN8tHuTagHYU2VQTcA0rdBGMN/1OljJpWlN
+0UUq4fAYU6cN4lHxr2LM9If4WvAzdLAWvaIZrDqaU4i/zYT9l6rR4lC2KW3EHWov
+nPXfgEJJ8AP1iRGibvew3i3SB6XTWFQYTUIBeJfDz/KDXQabP+yzXWISdZCUMUpx
+f+Raqsb5MoKaJdVgnSL0mBunjCyJDzzg34J7oGx6/BnwoiOrwLN4Qaz5U8jbrPSx
+p9LfleCcO7ZdeE8GKqx0X1T4d7tradtmxOS8Iwr4niskkHGRkzozvVvuyGKmoN2k
+162Vfjq+ddj7qEpSh3BS6hHU+vlMbC9L0trGxPxFEAHDrwu0KwGNduTkiu/3jvfB
+JTgH8P9mD1loYxRdo+vet8eQ
+-----END CERTIFICATE-----
diff --git a/apex/com.android.media.x509.pem b/apex/com.android.media.x509.pem
new file mode 100644
index 0000000..e7908fa6
--- /dev/null
+++ b/apex/com.android.media.x509.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFzDCCA7SgAwIBAgIJAO05DBBusaaLMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRyb2lkMRowGAYDVQQD
+DBFjb20uYW5kcm9pZC5tZWRpYTAgFw0xOTAxMjUxNzE3MTdaGA80NzU2MTIyMTE3
+MTcxN1owejELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNV
+BAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNVBAsMB0Fu
+ZHJvaWQxGjAYBgNVBAMMEWNvbS5hbmRyb2lkLm1lZGlhMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAmNkVxUbp/bLbeGbvKqYXzwBycSDpmOhh///lNGYQ
+/AMUD0q6EaZzU2bd4aL0rOGqfoYlhKd0kMVmMUmfdE9ODAfKxleEeEaRl2GJS8a9
+ABi770l3GHbB2xMI2sEWeOD9xsPFF6+ByPZmoUuNhMr4pUbXsDpE3h8ljrgXHtIg
+bh7ofbvddruwBV0lS1k9OZ9jPVGhEKkJnhgQa67cwgdjizAMbI0Dcz9gtMMawsDj
+Z2aQd1r+vxgh1/XkI/NMmXCnG2ERytXcJeC5S4gEtHfTTPoP0FuVgSB6y6dalMuZ
+F0NBZw8Mvgdy3QJip0uNa36J63CMZKTJWbTdlFpPL2hk0PgaYvje8C5Xtk5282wT
+dMocc8n2zIXbzbnSXGvjcNZib3Pfu55YUnX6eTqZ1BxlJ0FHZAsC4quFFWXxYBYD
+LCRoNNFEtIDQpuvuHF2DuHNDULpAQjy2y6+7eot0KEsVoDmZ4H8BpuAVVu2SxYNb
+gYflR9SmM0tmYeAcRT48q3xrocGyEHMqvgQRUpPfvct/8l8xVcDzOI/sJVDqmYzM
+u0Cj3fkSypGDJOMF/esFSmVvoI01tS7kaNS5vvtKYib//xqKRC9f0dCsGfFLnuUK
+o4KYbYWYwMyJqEd/5/ZvXyKIPAEeJL174L9+wTkc3cQpoBwJN4t+2E5MnhOEq6do
+5L0CAwEAAaNTMFEwHQYDVR0OBBYEFHjNK/GZko1RdZp+8iavWXL5xz9wMB8GA1Ud
+IwQYMBaAFHjNK/GZko1RdZp+8iavWXL5xz9wMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQELBQADggIBACmPQMksuLrNV1vbI44S1f70I0FHdBxchFGB39zuLbcn
+SsYom/LPtYJiD0Dl4bB4eb+ZnxkQP2XeP6pycmUH2j1EWexFwvdUvlfe8Qz+wAec
+ap4AxiX4Z2Ke2ivYotIZFUHdZOLkX20js8Wex1mzY43MLQn5APl9gK1VZTxDggeR
+EObH1S+JVjGwQqYZj2e6gNZH34Q25NQ698RL85GDkYtSISAifJtaJsU/B3vKm82I
+k9xMiCooCH6bRdGHG1jze4SRpidjxEm8cxkiaQagfcuXeCLziXJr3qAMKYiEY6bp
+0+bAqCt3S8OrrN3RQZfQrnlwitsM1jJJ/+C+WoDg4eY5AFrXDLvNeKh1qO/f8xv+
+fCXkQPcVVphLfRH9oxNrSgOWBP5/qIDH4s1YUL9luGT6H+08dlue3RkbzDbBqsQu
+7fQ/BbrIG/GuVKgyEM+a7C9gv7zc86YlueVYJEyxKidnn7RxOqyDBqyyfXA3zvme
+Rro7xIrMHPL7Nu3AWjwjXzbp/w0z+tEFPsfVB+OOHKsWPcUG0HUTJGkyeO/uHRjN
+qPEkkf7BHHUO4V2gjOIdCsELxKwHf7vsZTOk40EV751fZ7FDHMr1eddQkgH4eqAb
+DB79uP+SLfUo+42n4q6eMmoqw8d76bBXRoUhIo/Ms4sebhV0sRtAS67OQioc9UUg
+-----END CERTIFICATE-----
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
new file mode 100644
index 0000000..a5937fd
--- /dev/null
+++ b/apex/ld.config.txt
@@ -0,0 +1,131 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Bionic loader config file for the media swcodec APEX.
+#
+# There are no versioned APEX paths here - this APEX module does not support
+# having several versions mounted.
+
+dir.swcodec = /apex/com.android.media.swcodec/bin/
+
+[swcodec]
+additional.namespaces = platform,sphal
+
+###############################################################################
+# "default" namespace
+#
+# This namespace is for the binaries and libraries on the swcodec APEX.
+###############################################################################
+
+namespace.default.isolated = true
+namespace.default.visible = true
+
+namespace.default.search.paths = /apex/com.android.media.swcodec/${LIB}
+namespace.default.asan.search.paths = /apex/com.android.media.swcodec/${LIB}
+
+namespace.default.links = platform
+
+# TODO: replace the following when apex has a way to auto-generate this list
+# namespace.default.link.platform.shared_libs = %LLNDK_LIBRARIES%
+# namespace.default.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libdl_android.so:libvulkan.so
+
+###############################################################################
+# "platform" namespace
+#
+# This namespace is for linking to LLNDK and ASAN libraries on the system.
+###############################################################################
+
+namespace.platform.isolated = true
+
+namespace.platform.search.paths = /system/${LIB}
+namespace.platform.asan.search.paths = /data/asan/system/${LIB}
+namespace.platform.asan.search.paths += /system/${LIB}
+
+# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
+# Add /apex/... pat to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib. We could add this to search.paths
+# instead but that makes the resolution of bionic libs be dependent on
+# the order of /system/lib and /apex/... in search.paths. If /apex/...
+# is after /system/lib, then /apex/... is never tried because libc.so
+# is always found in /system/lib but fails to pass the accessibility test
+# because of its realpath. It's better to not depend on the ordering if
+# possible.
+namespace.platform.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
+namespace.platform.asan.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
+
+###############################################################################
+# "sphal" namespace
+#
+###############################################################################
+namespace.sphal.isolated = true
+namespace.sphal.visible = true
+
+# Keep the below in sync with "sphal" namespace in system's /etc/ld.config.txt
+# Codec2 has dependencies on some SP-hals (eg. android.hardware.graphics.mapper@2.0)
+# These are dlopen'ed by libvndksupport.so.
+namespace.sphal.search.paths = /odm/${LIB}
+namespace.sphal.search.paths += /vendor/${LIB}
+
+namespace.sphal.permitted.paths = /odm/${LIB}
+namespace.sphal.permitted.paths += /vendor/${LIB}
+namespace.sphal.permitted.paths += /vendor/${LIB}/hw
+namespace.sphal.permitted.paths += /system/vendor/${LIB}
+
+namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}
+namespace.sphal.asan.search.paths += /odm/${LIB}
+namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.sphal.asan.search.paths += /vendor/${LIB}
+
+namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}
+namespace.sphal.asan.permitted.paths += /odm/${LIB}
+namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.sphal.asan.permitted.paths += /vendor/${LIB}
+
+# Keep the below in sync with "vndk" namespace in system's /etc/ld.config.txt
+# System's sphal namespace links to vndk namespace for %VNDK_SAMEPROCESS_LIBRARIES%,
+# since we don't have a good way to auto-expand %VNDK_SAMEPROCESS_LIBRARIES%,
+# we'll add the vndk paths below.
+
+namespace.sphal.search.paths += /odm/${LIB}/vndk-sp
+namespace.sphal.search.paths += /vendor/${LIB}/vndk-sp
+namespace.sphal.search.paths += /system/${LIB}/vndk-sp${VNDK_VER}
+
+namespace.sphal.permitted.paths += /odm/${LIB}/hw
+namespace.sphal.permitted.paths += /odm/${LIB}/egl
+namespace.sphal.permitted.paths += /vendor/${LIB}/hw
+namespace.sphal.permitted.paths += /vendor/${LIB}/egl
+namespace.sphal.permitted.paths += /system/vendor/${LIB}/hw
+namespace.sphal.permitted.paths += /system/vendor/${LIB}/egl
+# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
+namespace.sphal.permitted.paths += /system/${LIB}/vndk-sp${VNDK_VER}/hw
+
+namespace.sphal.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
+namespace.sphal.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.sphal.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.sphal.asan.search.paths += /data/asan/system/${LIB}/vndk-sp${VNDK_VER}
+namespace.sphal.asan.search.paths += /system/${LIB}/vndk-sp${VNDK_VER}
+
+namespace.sphal.asan.permitted.paths += /data/asan/odm/${LIB}/hw
+namespace.sphal.asan.permitted.paths += /odm/${LIB}/hw
+namespace.sphal.asan.permitted.paths += /data/asan/odm/${LIB}/egl
+namespace.sphal.asan.permitted.paths += /odm/${LIB}/egl
+namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
+namespace.sphal.asan.permitted.paths += /vendor/${LIB}/hw
+namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
+namespace.sphal.asan.permitted.paths += /vendor/${LIB}/egl
+
+namespace.sphal.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp${VNDK_VER}/hw
+namespace.sphal.asan.permitted.paths += /system/${LIB}/vndk-sp${VNDK_VER}/hw
+
+# Once in this namespace, access to libraries in /system/lib is restricted. Only
+# libs listed here can be used.
+namespace.sphal.links = platform
+
+# TODO: replace the following when apex has a way to auto-generate this list
+# namespace.sphal.link.platform.shared_libs = %LLNDK_LIBRARIES%
+# namespace.sphal.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+namespace.sphal.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so
+
+# Add a link for libz.so which is llndk on devices where VNDK is not enforced.
+namespace.sphal.link.platform.shared_libs += libz.so
diff --git a/apex/manifest.json b/apex/manifest.json
new file mode 100644
index 0000000..3011ee8
--- /dev/null
+++ b/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.media",
+ "version": 290000000
+}
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
new file mode 100644
index 0000000..83a5178
--- /dev/null
+++ b/apex/manifest_codec.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.media.swcodec",
+ "version": 290000000
+}
diff --git a/apex/mediaswcodec.rc b/apex/mediaswcodec.rc
new file mode 100644
index 0000000..d17481b
--- /dev/null
+++ b/apex/mediaswcodec.rc
@@ -0,0 +1,7 @@
+service media.swcodec /apex/com.android.media.swcodec/bin/mediaswcodec
+ class main
+ user mediacodec
+ group camera drmrpc mediadrm
+ override
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
new file mode 100644
index 0000000..701ced7
--- /dev/null
+++ b/apex/testing/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+apex {
+ name: "test_com.android.media",
+ manifest: "test_manifest.json",
+ file_contexts: "com.android.media",
+ defaults: ["com.android.media-defaults"],
+ installable: false,
+}
+
+apex {
+ name: "test_com.android.media.swcodec",
+ manifest: "test_manifest_codec.json",
+ file_contexts: "com.android.media.swcodec",
+ defaults: ["com.android.media.swcodec-defaults"],
+ installable: false,
+}
diff --git a/apex/testing/test_manifest.json b/apex/testing/test_manifest.json
new file mode 100644
index 0000000..ddd642e
--- /dev/null
+++ b/apex/testing/test_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.media",
+ "version": 300000000
+}
diff --git a/apex/testing/test_manifest_codec.json b/apex/testing/test_manifest_codec.json
new file mode 100644
index 0000000..2320fd7
--- /dev/null
+++ b/apex/testing/test_manifest_codec.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.media.swcodec",
+ "version": 300000000
+}
diff --git a/camera/Android.bp b/camera/Android.bp
index 24b3918..2800595 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-subdirs = ["ndk"]
-
cc_library_shared {
name: "libcamera_client",
@@ -43,6 +41,7 @@
"ICameraRecordingProxyListener.cpp",
"camera2/CaptureRequest.cpp",
"camera2/OutputConfiguration.cpp",
+ "camera2/SessionConfiguration.cpp",
"camera2/SubmitInfo.cpp",
"CameraBase.cpp",
"CameraUtils.cpp",
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index e143e05..92fe84b 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -22,7 +22,6 @@
#include <binder/Parcel.h>
#include <camera/CameraMetadata.h>
-#include <camera/VendorTagDescriptor.h>
namespace android {
@@ -409,6 +408,79 @@
return res;
}
+status_t CameraMetadata::removePermissionEntries(metadata_vendor_id_t vendorId,
+ std::vector<int32_t> *tagsRemoved) {
+ uint32_t tagCount = 0;
+ std::vector<uint32_t> tagsToRemove;
+
+ if (tagsRemoved == nullptr) {
+ return BAD_VALUE;
+ }
+
+ sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+ if ((nullptr == vTags.get()) || (0 >= vTags->getTagCount())) {
+ sp<VendorTagDescriptorCache> cache =
+ VendorTagDescriptorCache::getGlobalVendorTagCache();
+ if (cache.get()) {
+ cache->getVendorTagDescriptor(vendorId, &vTags);
+ }
+ }
+
+ if ((nullptr != vTags.get()) && (vTags->getTagCount() > 0)) {
+ tagCount = vTags->getTagCount();
+ uint32_t *vendorTags = new uint32_t[tagCount];
+ if (nullptr == vendorTags) {
+ return NO_MEMORY;
+ }
+ vTags->getTagArray(vendorTags);
+
+ tagsToRemove.reserve(tagCount);
+ tagsToRemove.insert(tagsToRemove.begin(), vendorTags, vendorTags + tagCount);
+
+ delete [] vendorTags;
+ tagCount = 0;
+ }
+
+ auto tagsNeedingPermission = get_camera_metadata_permission_needed(&tagCount);
+ if (tagCount > 0) {
+ tagsToRemove.reserve(tagsToRemove.capacity() + tagCount);
+ tagsToRemove.insert(tagsToRemove.end(), tagsNeedingPermission,
+ tagsNeedingPermission + tagCount);
+ }
+
+ tagsRemoved->reserve(tagsToRemove.size());
+ for (const auto &it : tagsToRemove) {
+ if (exists(it)) {
+ auto rc = erase(it);
+ if (NO_ERROR != rc) {
+ ALOGE("%s: Failed to erase tag: %x", __func__, it);
+ return rc;
+ }
+ tagsRemoved->push_back(it);
+ }
+ }
+
+ // Update the available characterstics accordingly
+ if (exists(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS)) {
+ std::vector<uint32_t> currentKeys;
+
+ std::sort(tagsRemoved->begin(), tagsRemoved->end());
+ auto keys = find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ currentKeys.reserve(keys.count);
+ currentKeys.insert(currentKeys.end(), keys.data.i32, keys.data.i32 + keys.count);
+ std::sort(currentKeys.begin(), currentKeys.end());
+
+ std::vector<int32_t> newKeys(keys.count);
+ auto end = std::set_difference(currentKeys.begin(), currentKeys.end(), tagsRemoved->begin(),
+ tagsRemoved->end(), newKeys.begin());
+ newKeys.resize(end - newKeys.begin());
+
+ update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, newKeys.data(), newKeys.size());
+ }
+
+ return NO_ERROR;
+}
+
void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
}
diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp
index 928a6bc..1d8e8c4 100644
--- a/camera/CaptureResult.cpp
+++ b/camera/CaptureResult.cpp
@@ -39,6 +39,16 @@
parcel->readInt64(&frameNumber);
parcel->readInt32(&partialResultCount);
parcel->readInt32(&errorStreamId);
+ auto physicalCameraIdPresent = parcel->readBool();
+ if (physicalCameraIdPresent) {
+ String16 cameraId;
+ status_t res = OK;
+ if ((res = parcel->readString16(&cameraId)) != OK) {
+ ALOGE("%s: Failed to read camera id: %d", __FUNCTION__, res);
+ return res;
+ }
+ errorPhysicalCameraId = cameraId;
+ }
return OK;
}
@@ -56,6 +66,16 @@
parcel->writeInt64(frameNumber);
parcel->writeInt32(partialResultCount);
parcel->writeInt32(errorStreamId);
+ if (errorPhysicalCameraId.size() > 0) {
+ parcel->writeBool(true);
+ status_t res = OK;
+ if ((res = parcel->writeString16(errorPhysicalCameraId)) != OK) {
+ ALOGE("%s: Failed to write physical camera ID to parcel: %d", __FUNCTION__, res);
+ return res;
+ }
+ } else {
+ parcel->writeBool(false);
+ }
return OK;
}
diff --git a/camera/OWNERS b/camera/OWNERS
index 18acfee..d6b95da 100644
--- a/camera/OWNERS
+++ b/camera/OWNERS
@@ -1,6 +1,8 @@
-cychen@google.com
epeev@google.com
etalvala@google.com
+jchowdhary@google.com
shuzhenwang@google.com
yinchiayeh@google.com
+# backup owner
+cychen@google.com
zhijunhe@google.com
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
index 4c28789..d713d2d 100644
--- a/camera/VendorTagDescriptor.cpp
+++ b/camera/VendorTagDescriptor.cpp
@@ -315,6 +315,10 @@
return OK;
}
+ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const {
+ return mTagToSectionMap.valueFor(tag);
+}
+
void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
size_t size = mTagToNameMap.size();
@@ -407,6 +411,11 @@
return res;
}
+const std::unordered_map<metadata_vendor_id_t, sp<android::VendorTagDescriptor>> &
+ VendorTagDescriptorCache::getVendorIdsAndTagDescriptors() {
+ return mVendorMap;
+}
+
int VendorTagDescriptorCache::getTagCount(metadata_vendor_id_t id) const {
int ret = 0;
auto desc = mVendorMap.find(id);
@@ -566,7 +575,7 @@
for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
uint32_t tag = tagArray[i];
- String8 sectionString = tagToSectionMap.valueFor(tag);
+ const String8& sectionString = tagToSectionMap.valueFor(tag);
// Set up tag to section index map
ssize_t index = sections.indexOf(sectionString);
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 9c0f28b..3e8992a 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -108,7 +108,7 @@
*
* Also returns the set of currently-known camera IDs and state of each device.
* Adding a listener will trigger the torch status listener to fire for all
- * devices that have a flash unit
+ * devices that have a flash unit.
*/
CameraStatus[] addListener(ICameraServiceListener listener);
@@ -149,8 +149,10 @@
const int API_VERSION_1 = 1;
const int API_VERSION_2 = 2;
- // Determines if a particular API version is supported directly
+ // Determines if a particular API version is supported directly for a cameraId.
boolean supportsCameraApi(String cameraId, int apiVersion);
+ // Determines if a cameraId is a hidden physical camera of a logical multi-camera.
+ boolean isHiddenPhysicalCamera(String cameraId);
void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);
@@ -160,6 +162,28 @@
* Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
*/
const int EVENT_NONE = 0;
- const int EVENT_USER_SWITCHED = 1;
+ const int EVENT_USER_SWITCHED = 1; // The argument is the set of new foreground user IDs.
oneway void notifySystemEvent(int eventId, in int[] args);
+
+ /**
+ * Notify the camera service of a device physical status change. May only be called from
+ * a privileged process.
+ *
+ * newState is a bitfield consisting of DEVICE_STATE_* values combined together. Valid state
+ * combinations are device-specific. At device startup, the camera service will assume the device
+ * state is NORMAL until otherwise notified.
+ *
+ * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
+ */
+ oneway void notifyDeviceStateChange(long newState);
+
+ // Bitfield constants for notifyDeviceStateChange
+ // All bits >= 32 are for custom vendor states
+ // Written as ints since AIDL does not support long constants.
+ const int DEVICE_STATE_NORMAL = 0;
+ const int DEVICE_STATE_BACK_COVERED = 1;
+ const int DEVICE_STATE_FRONT_COVERED = 2;
+ const int DEVICE_STATE_FOLDED = 4;
+ const int DEVICE_STATE_LAST_FRAMEWORK_BIT = 0x80000000; // 1 << 31;
+
}
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index f871ce4..e9dcbdb 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -76,4 +76,11 @@
const int TORCH_STATUS_UNKNOWN = -1;
oneway void onTorchStatusChanged(int status, String cameraId);
+
+ /**
+ * Notify registered clients about camera access priority changes.
+ * Clients which were previously unable to open a certain camera device
+ * can retry after receiving this callback.
+ */
+ oneway void onCameraAccessPrioritiesChanged();
}
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 4ced08c..49dfde8 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -19,6 +19,7 @@
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.utils.SubmitInfo;
import android.view.Surface;
@@ -83,6 +84,16 @@
*/
void endConfigure(int operatingMode, in CameraMetadataNative sessionParams);
+ /**
+ * Check whether a particular session configuration has camera device
+ * support.
+ *
+ * @param sessionConfiguration Specific session configuration to be verified.
+ * @return true - in case the stream combination is supported.
+ * false - in case there is no device support.
+ */
+ boolean isSessionConfigurationSupported(in SessionConfiguration sessionConfiguration);
+
void deleteStream(int streamId);
/**
diff --git a/camera/aidl/android/hardware/camera2/params/SessionConfiguration.aidl b/camera/aidl/android/hardware/camera2/params/SessionConfiguration.aidl
new file mode 100644
index 0000000..abf1556
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/params/SessionConfiguration.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+/** @hide */
+parcelable SessionConfiguration cpp_header "camera/camera2/SessionConfiguration.h";
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index feb04c2..4e9b27d 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -167,14 +167,24 @@
}
OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+ const String16& physicalId,
int surfaceSetID, bool isShared) {
mGbps.push_back(gbp);
mRotation = rotation;
mSurfaceSetID = surfaceSetID;
mIsDeferred = false;
mIsShared = isShared;
+ mPhysicalCameraId = physicalId;
}
+OutputConfiguration::OutputConfiguration(
+ const std::vector<sp<IGraphicBufferProducer>>& gbps,
+ int rotation, const String16& physicalCameraId, int surfaceSetID, int surfaceType,
+ int width, int height, bool isShared)
+ : mGbps(gbps), mRotation(rotation), mSurfaceSetID(surfaceSetID), mSurfaceType(surfaceType),
+ mWidth(width), mHeight(height), mIsDeferred(false), mIsShared(isShared),
+ mPhysicalCameraId(physicalCameraId) { }
+
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
if (parcel == nullptr) return BAD_VALUE;
diff --git a/camera/camera2/SessionConfiguration.cpp b/camera/camera2/SessionConfiguration.cpp
new file mode 100644
index 0000000..a431a33
--- /dev/null
+++ b/camera/camera2/SessionConfiguration.cpp
@@ -0,0 +1,133 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "SessionConfiguration"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include <camera/camera2/SessionConfiguration.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+status_t SessionConfiguration::readFromParcel(const android::Parcel* parcel) {
+ status_t err = OK;
+ int operatingMode = 0;
+
+ if (parcel == nullptr) return BAD_VALUE;
+
+ if ((err = parcel->readInt32(&operatingMode)) != OK) {
+ ALOGE("%s: Failed to read operating mode from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int inputWidth = 0;
+ if ((err = parcel->readInt32(&inputWidth)) != OK) {
+ ALOGE("%s: Failed to read input width from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int inputHeight = 0;
+ if ((err = parcel->readInt32(&inputHeight)) != OK) {
+ ALOGE("%s: Failed to read input height from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int inputFormat = -1;
+ if ((err = parcel->readInt32(&inputFormat)) != OK) {
+ ALOGE("%s: Failed to read input format from parcel", __FUNCTION__);
+ return err;
+ }
+
+ std::vector<OutputConfiguration> outputStreams;
+ if ((err = parcel->readParcelableVector(&outputStreams)) != OK) {
+ ALOGE("%s: Failed to read output configurations from parcel", __FUNCTION__);
+ return err;
+ }
+
+ mOperatingMode = operatingMode;
+ mInputWidth = inputWidth;
+ mInputHeight = inputHeight;
+ mInputFormat = inputFormat;
+ for (auto& stream : outputStreams) {
+ mOutputStreams.push_back(stream);
+ }
+
+
+ return err;
+}
+
+status_t SessionConfiguration::writeToParcel(android::Parcel* parcel) const {
+
+ if (parcel == nullptr) return BAD_VALUE;
+ status_t err = OK;
+
+ err = parcel->writeInt32(mOperatingMode);
+ if (err != OK) return err;
+
+ err = parcel->writeInt32(mInputWidth);
+ if (err != OK) return err;
+
+ err = parcel->writeInt32(mInputHeight);
+ if (err != OK) return err;
+
+ err = parcel->writeInt32(mInputFormat);
+ if (err != OK) return err;
+
+ err = parcel->writeParcelableVector(mOutputStreams);
+ if (err != OK) return err;
+
+ return OK;
+}
+
+bool SessionConfiguration::outputsEqual(const SessionConfiguration& other) const {
+ const std::vector<OutputConfiguration>& otherOutputStreams =
+ other.getOutputConfigurations();
+
+ if (mOutputStreams.size() != otherOutputStreams.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ if (mOutputStreams[i] != otherOutputStreams[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool SessionConfiguration::outputsLessThan(const SessionConfiguration& other) const {
+ const std::vector<OutputConfiguration>& otherOutputStreams =
+ other.getOutputConfigurations();
+
+ if (mOutputStreams.size() != otherOutputStreams.size()) {
+ return mOutputStreams.size() < otherOutputStreams.size();
+ }
+
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ if (mOutputStreams[i] != otherOutputStreams[i]) {
+ return mOutputStreams[i] < otherOutputStreams[i];
+ }
+ }
+
+ return false;
+}
+
+}; // namespace android
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
new file mode 100644
index 0000000..ecaba3a
--- /dev/null
+++ b/camera/cameraserver/Android.bp
@@ -0,0 +1,49 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+ name: "cameraserver",
+
+ srcs: ["main_cameraserver.cpp"],
+
+ shared_libs: [
+ "libcameraservice",
+ "liblog",
+ "libutils",
+ "libui",
+ "libgui",
+ "libbinder",
+ "libhidlbase",
+ "libhidltransport",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.provider@2.5",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.4",
+ ],
+ compile_multilib: "32",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+
+ init_rc: ["cameraserver.rc"],
+
+ vintf_fragments: [
+ "manifest_android.frameworks.cameraservice.service@2.0.xml",
+ ],
+}
diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
deleted file mode 100644
index b8c94e6..0000000
--- a/camera/cameraserver/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- main_cameraserver.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcameraservice \
- liblog \
- libutils \
- libui \
- libgui \
- libbinder \
- libhidltransport \
- android.hardware.camera.common@1.0 \
- android.hardware.camera.provider@2.4 \
- android.hardware.camera.device@1.0 \
- android.hardware.camera.device@3.2
-
-LOCAL_MODULE:= cameraserver
-LOCAL_32_BIT_ONLY := true
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter
-
-LOCAL_INIT_RC := cameraserver.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
index 3972436..53b3d84 100644
--- a/camera/cameraserver/main_cameraserver.cpp
+++ b/camera/cameraserver/main_cameraserver.cpp
@@ -26,8 +26,9 @@
{
signal(SIGPIPE, SIG_IGN);
- // Set 3 threads for HIDL calls
- hardware::configureRpcThreadpool(3, /*willjoin*/ false);
+ // Set 5 threads for HIDL calls. Now cameraserver will serve HIDL calls in
+ // addition to consuming them from the Camera HAL as well.
+ hardware::configureRpcThreadpool(5, /*willjoin*/ false);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml
new file mode 100644
index 0000000..601c717
--- /dev/null
+++ b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.0.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.frameworks.cameraservice.service</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>ICameraService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/camera/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h
index d284477..844bb80 100644
--- a/camera/include/camera/CameraMetadata.h
+++ b/camera/include/camera/CameraMetadata.h
@@ -22,6 +22,7 @@
#include <utils/String8.h>
#include <utils/Vector.h>
#include <binder/Parcelable.h>
+#include <camera/VendorTagDescriptor.h>
namespace android {
@@ -170,6 +171,12 @@
status_t erase(uint32_t tag);
/**
+ * Remove metadata entries that need additional permissions.
+ */
+ status_t removePermissionEntries(metadata_vendor_id_t vendorId,
+ std::vector<int32_t> *tagsRemoved /*out*/);
+
+ /**
* Swap the underlying camera metadata between this and the other
* metadata object.
*/
diff --git a/camera/include/camera/CaptureResult.h b/camera/include/camera/CaptureResult.h
index 56fa178..ef830b5 100644
--- a/camera/include/camera/CaptureResult.h
+++ b/camera/include/camera/CaptureResult.h
@@ -70,6 +70,13 @@
int32_t errorStreamId;
/**
+ * For capture result errors, the physical camera ID in case the respective request contains
+ * a reference to physical camera device.
+ * Empty otherwise.
+ */
+ String16 errorPhysicalCameraId;
+
+ /**
* Constructor initializes object as invalid by setting requestId to be -1.
*/
CaptureResultExtras()
@@ -79,7 +86,8 @@
precaptureTriggerId(0),
frameNumber(0),
partialResultCount(0),
- errorStreamId(-1) {
+ errorStreamId(-1),
+ errorPhysicalCameraId() {
}
/**
diff --git a/camera/include/camera/VendorTagDescriptor.h b/camera/include/camera/VendorTagDescriptor.h
index 904fba2..6f55890 100644
--- a/camera/include/camera/VendorTagDescriptor.h
+++ b/camera/include/camera/VendorTagDescriptor.h
@@ -99,6 +99,11 @@
void dump(int fd, int verbosity, int indentation) const;
/**
+ * Get Section for corresponding tag.
+ */
+ ssize_t getSectionIndex(uint32_t tag) const;
+
+ /**
* Read values VendorTagDescriptor object from the given parcel.
*
* Returns OK on success, or a negative error code.
@@ -206,6 +211,9 @@
*/
void dump(int fd, int verbosity, int indentation) const;
+ const std::unordered_map<metadata_vendor_id_t, sp<android::VendorTagDescriptor>> &
+ getVendorIdsAndTagDescriptors();
+
protected:
std::unordered_map<metadata_vendor_id_t, sp<android::VendorTagDescriptor>> mVendorMap;
struct vendor_tag_cache_ops mVendorCacheOps;
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index a80f44b..95c4f39 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -65,8 +65,15 @@
OutputConfiguration(const android::Parcel& parcel);
OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+ const String16& physicalCameraId,
int surfaceSetID = INVALID_SET_ID, bool isShared = false);
+ OutputConfiguration(const std::vector<sp<IGraphicBufferProducer>>& gbps,
+ int rotation, const String16& physicalCameraId,
+ int surfaceSetID = INVALID_SET_ID,
+ int surfaceType = OutputConfiguration::SURFACE_TYPE_UNKNOWN, int width = 0,
+ int height = 0, bool isShared = false);
+
bool operator == (const OutputConfiguration& other) const {
return ( mRotation == other.mRotation &&
mSurfaceSetID == other.mSurfaceSetID &&
diff --git a/camera/include/camera/camera2/SessionConfiguration.h b/camera/include/camera/camera2/SessionConfiguration.h
new file mode 100644
index 0000000..64288ed
--- /dev/null
+++ b/camera/include/camera/camera2/SessionConfiguration.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA2_SESSIONCONFIGURATION_H
+#define ANDROID_HARDWARE_CAMERA2_SESSIONCONFIGURATION_H
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+class OutputConfiguration;
+
+class SessionConfiguration : public android::Parcelable {
+public:
+
+ const std::vector<OutputConfiguration>& getOutputConfigurations() const {
+ return mOutputStreams;
+ }
+
+ int getInputWidth() const { return mInputWidth; }
+ int getInputHeight() const { return mInputHeight; }
+ int getInputFormat() const { return mInputFormat; }
+ int getOperatingMode() const { return mOperatingMode; }
+
+ virtual status_t writeToParcel(android::Parcel* parcel) const override;
+ virtual status_t readFromParcel(const android::Parcel* parcel) override;
+
+ SessionConfiguration() :
+ mInputWidth(0),
+ mInputHeight(0),
+ mInputFormat(-1),
+ mOperatingMode(-1) {}
+
+ SessionConfiguration(const android::Parcel& parcel) {
+ readFromParcel(&parcel);
+ }
+
+ SessionConfiguration(int inputWidth, int inputHeight, int inputFormat, int operatingMode) :
+ mInputWidth(inputWidth), mInputHeight(inputHeight), mInputFormat(inputFormat),
+ mOperatingMode(operatingMode) {}
+
+ bool operator == (const SessionConfiguration& other) const {
+ return (outputsEqual(other) &&
+ mInputWidth == other.mInputWidth &&
+ mInputHeight == other.mInputHeight &&
+ mInputFormat == other.mInputFormat &&
+ mOperatingMode == other.mOperatingMode);
+ }
+
+ bool operator != (const SessionConfiguration& other) const {
+ return !(*this == other);
+ }
+
+ bool operator < (const SessionConfiguration& other) const {
+ if (*this == other) return false;
+
+ if (mInputWidth != other.mInputWidth) {
+ return mInputWidth < other.mInputWidth;
+ }
+
+ if (mInputHeight != other.mInputHeight) {
+ return mInputHeight < other.mInputHeight;
+ }
+
+ if (mInputFormat != other.mInputFormat) {
+ return mInputFormat < other.mInputFormat;
+ }
+
+ if (mOperatingMode != other.mOperatingMode) {
+ return mOperatingMode < other.mOperatingMode;
+ }
+
+ return outputsLessThan(other);
+ }
+
+ bool operator > (const SessionConfiguration& other) const {
+ return (*this != other && !(*this < other));
+ }
+
+ bool outputsEqual(const SessionConfiguration& other) const;
+ bool outputsLessThan(const SessionConfiguration& other) const;
+ void addOutputConfiguration(const OutputConfiguration &config) {
+ mOutputStreams.push_back(config);
+ }
+
+private:
+
+ std::vector<OutputConfiguration> mOutputStreams;
+ int mInputWidth, mInputHeight, mInputFormat, mOperatingMode;
+};
+} // namespace params
+} // namespace camera2
+} // namespace hardware
+
+using hardware::camera2::params::SessionConfiguration;
+
+}; // namespace android
+
+#endif
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 97cf6bf..a2ee65d 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -30,3 +30,133 @@
srcs: ["include/camera/**/*.h"],
license: "NOTICE",
}
+
+cc_library_shared {
+ name: "libcamera2ndk",
+ srcs: [
+ "NdkCameraManager.cpp",
+ "NdkCameraMetadata.cpp",
+ "NdkCameraDevice.cpp",
+ "NdkCaptureRequest.cpp",
+ "NdkCameraCaptureSession.cpp",
+ "impl/ACameraManager.cpp",
+ "impl/ACameraMetadata.cpp",
+ "impl/ACameraDevice.cpp",
+ "impl/ACameraCaptureSession.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libgui",
+ "libutils",
+ "libandroid_runtime",
+ "libcamera_client",
+ "libstagefright_foundation",
+ "libcutils",
+ "libcamera_metadata",
+ "libmediandk",
+ "libnativewindow",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ "-DEXPORT=__attribute__ ((visibility (\"default\")))",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ // TODO: jchowdhary@, use header_libs instead b/131165718
+ include_dirs: [
+ "system/media/private/camera/include",
+ ],
+ export_include_dirs: ["include"],
+ export_shared_lib_headers: [
+ "libnativewindow",
+ ],
+ version_script: "libcamera2ndk.map.txt",
+}
+
+cc_library_shared {
+ name: "libcamera2ndk_vendor",
+ vendor: true,
+ srcs: [
+ "ndk_vendor/impl/ACameraDevice.cpp",
+ "ndk_vendor/impl/ACameraManager.cpp",
+ "ndk_vendor/impl/utils.cpp",
+ "impl/ACameraMetadata.cpp",
+ "impl/ACameraCaptureSession.cpp",
+ "NdkCameraMetadata.cpp",
+ "NdkCameraCaptureSession.cpp",
+ "NdkCameraManager.cpp",
+ "NdkCameraDevice.cpp",
+ "NdkCaptureRequest.cpp",
+ ],
+
+ export_include_dirs: ["include"],
+ export_shared_lib_headers: [
+ "libcutils",
+ ],
+ local_include_dirs: [
+ ".",
+ "include",
+ "impl",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ "-DEXPORT=__attribute__((visibility(\"default\")))",
+ "-D__ANDROID_VNDK__",
+ ],
+
+ shared_libs: [
+ "libhwbinder",
+ "libfmq",
+ "libhidlbase",
+ "libhardware",
+ "libnativewindow",
+ "liblog",
+ "libutils",
+ "libstagefright_foundation",
+ "libcutils",
+ "libcamera_metadata",
+ "libmediandk",
+ "android.frameworks.cameraservice.device@2.0",
+ "android.frameworks.cameraservice.common@2.0",
+ "android.frameworks.cameraservice.service@2.0",
+ ],
+
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ "libarect",
+ ],
+ // TODO: jchowdhary@, use header_libs instead b/131165718
+ include_dirs: [
+ "system/media/private/camera/include",
+ ],
+ product_variables: {
+ pdk: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test {
+ name: "AImageReaderVendorTest",
+ vendor: true,
+ srcs: ["ndk_vendor/tests/AImageReaderVendorTest.cpp"],
+ shared_libs: [
+ "libhwbinder",
+ "libcamera2ndk_vendor",
+ "libcamera_metadata",
+ "libmediandk",
+ "libnativewindow",
+ "libutils",
+ "libui",
+ "libcutils",
+ "liblog",
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ ],
+ cflags: [
+ "-D__ANDROID_VNDK__",
+ ],
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
deleted file mode 100644
index f5ff69d..0000000
--- a/camera/ndk/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-ifneq ($(TARGET_BUILD_PDK), true)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- NdkCameraManager.cpp \
- NdkCameraMetadata.cpp \
- NdkCameraDevice.cpp \
- NdkCaptureRequest.cpp \
- NdkCameraCaptureSession.cpp \
- impl/ACameraManager.cpp \
- impl/ACameraMetadata.cpp \
- impl/ACameraDevice.cpp \
- impl/ACameraCaptureSession.cpp
-
-LOCAL_MODULE:= libcamera2ndk
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- liblog \
- libgui \
- libutils \
- libandroid_runtime \
- libcamera_client \
- libstagefright_foundation \
- libcutils \
- libcamera_metadata \
- libmediandk
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index fd95296..1ac8482 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -28,6 +28,8 @@
#include <camera/NdkCameraCaptureSession.h>
#include "impl/ACameraCaptureSession.h"
+#include "impl/ACameraCaptureSession.inc"
+
using namespace android;
EXPORT
@@ -78,11 +80,39 @@
if (session->isClosed()) {
ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ if (captureSequenceId != nullptr) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
return ACAMERA_ERROR_SESSION_CLOSED;
}
- return session->capture(cbs, numRequests, requests, captureSequenceId);
+ return session->capture(
+ cbs, numRequests, requests, captureSequenceId);
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_logicalCamera_capture(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || requests == nullptr || numRequests < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+ __FUNCTION__, session, numRequests, requests);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ return session->capture(
+ lcbs, numRequests, requests, captureSequenceId);
}
EXPORT
@@ -99,7 +129,9 @@
if (session->isClosed()) {
ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
return ACAMERA_ERROR_SESSION_CLOSED;
}
@@ -107,6 +139,30 @@
}
EXPORT
+camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequest(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || requests == nullptr || numRequests < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+ __FUNCTION__, session, numRequests, requests);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ return session->setRepeatingRequest(lcbs, numRequests, requests, captureSequenceId);
+}
+
+EXPORT
camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession* session) {
ATRACE_CALL();
if (session == nullptr) {
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 812a312..691996b 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -24,7 +24,15 @@
#include <camera/NdkCameraDevice.h>
#include "impl/ACameraCaptureSession.h"
-using namespace android;
+using namespace android::acam;
+
+bool areWindowTypesEqual(ACameraWindowType *a, ACameraWindowType *b) {
+#ifdef __ANDROID_VNDK__
+ return utils::isWindowNativeHandleEqual(a, b);
+#else
+ return a == b;
+#endif
+}
EXPORT
camera_status_t ACameraDevice_close(ACameraDevice* device) {
@@ -70,7 +78,34 @@
ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- return device->createCaptureRequest(templateId, request);
+ return device->createCaptureRequest(templateId, nullptr /*physicalIdList*/, request);
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureRequest_withPhysicalIds(
+ const ACameraDevice* device,
+ ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
+ ACaptureRequest** request) {
+ ATRACE_CALL();
+ if (device == nullptr || request == nullptr || physicalCameraIdList == nullptr) {
+ ALOGE("%s: invalid argument! device %p request %p, physicalCameraIdList %p",
+ __FUNCTION__, device, request, physicalCameraIdList);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ switch (templateId) {
+ case TEMPLATE_PREVIEW:
+ case TEMPLATE_STILL_CAPTURE:
+ case TEMPLATE_RECORD:
+ case TEMPLATE_VIDEO_SNAPSHOT:
+ case TEMPLATE_ZERO_SHUTTER_LAG:
+ case TEMPLATE_MANUAL:
+ break;
+ default:
+ ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return device->createCaptureRequest(templateId, physicalCameraIdList, request);
}
EXPORT
@@ -96,7 +131,7 @@
EXPORT
camera_status_t ACaptureSessionOutput_create(
- ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
+ ACameraWindowType* window, /*out*/ACaptureSessionOutput** out) {
ATRACE_CALL();
if (window == nullptr || out == nullptr) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -109,7 +144,7 @@
EXPORT
camera_status_t ACaptureSessionSharedOutput_create(
- ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
+ ACameraWindowType* window, /*out*/ACaptureSessionOutput** out) {
ATRACE_CALL();
if (window == nullptr || out == nullptr) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -121,8 +156,22 @@
}
EXPORT
+camera_status_t ACaptureSessionPhysicalOutput_create(
+ ACameraWindowType* window, const char* physicalId,
+ /*out*/ACaptureSessionOutput** out) {
+ ATRACE_CALL();
+ if (window == nullptr || physicalId == nullptr || out == nullptr) {
+ ALOGE("%s: Error: bad argument. window %p, physicalId %p, out %p",
+ __FUNCTION__, window, physicalId, out);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ *out = new ACaptureSessionOutput(window, false, physicalId);
+ return ACAMERA_OK;
+}
+
+EXPORT
camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *out,
- ANativeWindow* window) {
+ ACameraWindowType* window) {
ATRACE_CALL();
if ((window == nullptr) || (out == nullptr)) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -134,7 +183,7 @@
__FUNCTION__);
return ACAMERA_ERROR_INVALID_OPERATION;
}
- if (out->mWindow == window) {
+ if (areWindowTypesEqual(out->mWindow, window)) {
ALOGE("%s: Error trying to add the same window associated with the output configuration",
__FUNCTION__);
return ACAMERA_ERROR_INVALID_PARAMETER;
@@ -147,7 +196,7 @@
EXPORT
camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *out,
- ANativeWindow* window) {
+ ACameraWindowType* window) {
ATRACE_CALL();
if ((window == nullptr) || (out == nullptr)) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -159,7 +208,7 @@
__FUNCTION__);
return ACAMERA_ERROR_INVALID_OPERATION;
}
- if (out->mWindow == window) {
+ if (areWindowTypesEqual(out->mWindow, window)) {
ALOGE("%s: Error trying to remove the same window associated with the output configuration",
__FUNCTION__);
return ACAMERA_ERROR_INVALID_PARAMETER;
@@ -238,3 +287,16 @@
}
return device->createCaptureSession(outputs, sessionParameters, callbacks, session);
}
+
+EXPORT
+camera_status_t ACameraDevice_isSessionConfigurationSupported(
+ const ACameraDevice* device,
+ const ACaptureSessionOutputContainer* sessionOutputContainer) {
+ ATRACE_CALL();
+ if (device == nullptr || sessionOutputContainer == nullptr) {
+ ALOGE("%s: Error: invalid input: device %p, sessionOutputContainer %p",
+ __FUNCTION__, device, sessionOutputContainer);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return device->isSessionConfigurationSupported(sessionOutputContainer);
+}
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 60b4763..3d231a8 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -22,9 +22,15 @@
#include <utils/Trace.h>
#include <camera/NdkCameraManager.h>
-#include "impl/ACameraManager.h"
-using namespace android;
+#ifdef __ANDROID_VNDK__
+#include "ndk_vendor/impl/ACameraManager.h"
+#else
+#include "impl/ACameraManager.h"
+#endif
+#include "impl/ACameraMetadata.h"
+
+using namespace android::acam;
EXPORT
ACameraManager* ACameraManager_create() {
@@ -99,6 +105,60 @@
}
EXPORT
+camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
+ ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if ((callback->availabilityCallbacks.onCameraAvailable == nullptr) ||
+ (callback->availabilityCallbacks.onCameraUnavailable == nullptr) ||
+ (callback->onCameraAccessPrioritiesChanged == nullptr)) {
+ ALOGE("%s: invalid argument! callback %p, "
+ "onCameraAvailable %p, onCameraUnavailable %p onCameraAccessPrioritiesChanged %p",
+ __FUNCTION__, callback,
+ callback->availabilityCallbacks.onCameraAvailable,
+ callback->availabilityCallbacks.onCameraUnavailable,
+ callback->onCameraAccessPrioritiesChanged);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ auto reservedEntriesCount = sizeof(callback->reserved) / sizeof(callback->reserved[0]);
+ for (size_t i = 0; i < reservedEntriesCount; i++) {
+ if (callback->reserved[i] != nullptr) {
+ ALOGE("%s: invalid argument! callback reserved entries must be set to NULL",
+ __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+ CameraManagerGlobal::getInstance().registerExtendedAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
+ ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if ((callback->availabilityCallbacks.onCameraAvailable == nullptr) ||
+ (callback->availabilityCallbacks.onCameraUnavailable == nullptr) ||
+ (callback->onCameraAccessPrioritiesChanged == nullptr)) {
+ ALOGE("%s: invalid argument! callback %p, "
+ "onCameraAvailable %p, onCameraUnavailable %p onCameraAccessPrioritiesChanged %p",
+ __FUNCTION__, callback,
+ callback->availabilityCallbacks.onCameraAvailable,
+ callback->availabilityCallbacks.onCameraUnavailable,
+ callback->onCameraAccessPrioritiesChanged);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ CameraManagerGlobal::getInstance().unregisterExtendedAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
camera_status_t ACameraManager_getCameraCharacteristics(
ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){
ATRACE_CALL();
@@ -107,7 +167,14 @@
__FUNCTION__, mgr, cameraId, chars);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- return mgr->getCameraCharacteristics(cameraId, chars);
+ sp<ACameraMetadata> spChars;
+ camera_status_t status = mgr->getCameraCharacteristics(cameraId, &spChars);
+ if (status != ACAMERA_OK) {
+ return status;
+ }
+ spChars->incStrong((void*) ACameraManager_getCameraCharacteristics);
+ *chars = spChars.get();
+ return ACAMERA_OK;
}
EXPORT
@@ -123,3 +190,17 @@
}
return mgr->openCamera(cameraId, callback, device);
}
+
+#ifdef __ANDROID_VNDK__
+EXPORT
+camera_status_t ACameraManager_getTagFromName(ACameraManager *mgr, const char* cameraId,
+ const char *name, /*out*/uint32_t *tag) {
+ ATRACE_CALL();
+ if (mgr == nullptr || cameraId == nullptr || name == nullptr) {
+ ALOGE("%s: invalid argument! mgr %p cameraId %p name %p",
+ __FUNCTION__, mgr, cameraId, name);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return mgr->getTagFromName(cameraId, name, tag);
+}
+#endif
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
index 65de81f..9a39ed8 100644
--- a/camera/ndk/NdkCameraMetadata.cpp
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -57,13 +57,32 @@
ALOGE("%s: src is null!", __FUNCTION__);
return nullptr;
}
- return new ACameraMetadata(*src);
+ ACameraMetadata* copy = new ACameraMetadata(*src);
+ copy->incStrong((void*) ACameraMetadata_copy);
+ return copy;
}
EXPORT
void ACameraMetadata_free(ACameraMetadata* metadata) {
ATRACE_CALL();
if (metadata != nullptr) {
- delete metadata;
+ metadata->decStrong((void*) ACameraMetadata_free);
}
}
+
+EXPORT
+bool ACameraMetadata_isLogicalMultiCamera(const ACameraMetadata* staticMetadata,
+ /*out*/size_t* numPhysicalCameras, /*out*/const char*const** physicalCameraIds) {
+ ATRACE_CALL();
+ if (numPhysicalCameras == nullptr || physicalCameraIds == nullptr) {
+ ALOGE("%s: Invalid input: numPhysicalCameras %p, physicalCameraIds %p",
+ __FUNCTION__, numPhysicalCameras, physicalCameraIds);
+ return false;
+ }
+ if (staticMetadata == nullptr) {
+ ALOGE("%s: Invalid input: staticMetadata is null.", __FUNCTION__);
+ return false;
+ }
+
+ return staticMetadata->isLogicalMultiCamera(numPhysicalCameras, physicalCameraIds);
+}
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index ac1856b..87de4a9 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -27,7 +27,7 @@
EXPORT
camera_status_t ACameraOutputTarget_create(
- ANativeWindow* window, ACameraOutputTarget** out) {
+ ACameraWindowType* window, ACameraOutputTarget** out) {
ATRACE_CALL();
if (window == nullptr) {
ALOGE("%s: Error: input window is null", __FUNCTION__);
@@ -98,6 +98,27 @@
}
EXPORT
+camera_status_t ACaptureRequest_getConstEntry_physicalCamera(
+ const ACaptureRequest* req, const char* physicalId,
+ uint32_t tag, ACameraMetadata_const_entry* entry) {
+ ATRACE_CALL();
+ if (req == nullptr || entry == nullptr || physicalId == nullptr) {
+ ALOGE("%s: invalid argument! req %p, tag 0x%x, entry %p, physicalId %p",
+ __FUNCTION__, req, tag, entry, physicalId);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ const auto& physicalSettings = req->physicalSettings.find(physicalId);
+ if (physicalSettings == req->physicalSettings.end()) {
+ ALOGE("%s: Failed to find metadata for physical camera id %s",
+ __FUNCTION__, physicalId);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ return physicalSettings->second->getConstEntry(tag, entry);
+}
+
+EXPORT
camera_status_t ACaptureRequest_getAllTags(
const ACaptureRequest* req, /*out*/int32_t* numTags, /*out*/const uint32_t** tags) {
ATRACE_CALL();
@@ -131,13 +152,42 @@
#undef SET_ENTRY
+#define SET_PHYSICAL_ENTRY(NAME,NDK_TYPE) \
+EXPORT \
+camera_status_t ACaptureRequest_setEntry_physicalCamera_##NAME( \
+ ACaptureRequest* req, const char* physicalId, uint32_t tag, \
+ uint32_t count, const NDK_TYPE* data) { \
+ ATRACE_CALL(); \
+ if (req == nullptr || (count > 0 && data == nullptr) || physicalId == nullptr) { \
+ ALOGE("%s: invalid argument! req %p, tag 0x%x, count %d, data 0x%p, physicalId %p", \
+ __FUNCTION__, req, tag, count, data, physicalId); \
+ return ACAMERA_ERROR_INVALID_PARAMETER; \
+ } \
+ if (req->physicalSettings.find(physicalId) == req->physicalSettings.end()) { \
+ ALOGE("%s: Failed to find metadata for physical camera id %s", \
+ __FUNCTION__, physicalId); \
+ return ACAMERA_ERROR_INVALID_PARAMETER; \
+ } \
+ return req->physicalSettings[physicalId]->update(tag, count, data); \
+}
+
+SET_PHYSICAL_ENTRY(u8,uint8_t)
+SET_PHYSICAL_ENTRY(i32,int32_t)
+SET_PHYSICAL_ENTRY(float,float)
+SET_PHYSICAL_ENTRY(double,double)
+SET_PHYSICAL_ENTRY(i64,int64_t)
+SET_PHYSICAL_ENTRY(rational,ACameraMetadata_rational)
+
+#undef SET_PHYSICAL_ENTRY
+
EXPORT
void ACaptureRequest_free(ACaptureRequest* request) {
ATRACE_CALL();
if (request == nullptr) {
return;
}
- delete request->settings;
+ request->settings.clear();
+ request->physicalSettings.clear();
delete request->targets;
delete request;
return;
@@ -174,6 +224,9 @@
ACaptureRequest* pRequest = new ACaptureRequest();
pRequest->settings = new ACameraMetadata(*(src->settings));
+ for (const auto& entry : src->physicalSettings) {
+ pRequest->physicalSettings[entry.first] = new ACameraMetadata(*(entry.second));
+ }
pRequest->targets = new ACameraOutputTargets();
*(pRequest->targets) = *(src->targets);
pRequest->context = src->context;
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index f60e5fd..d6f1412 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -23,7 +23,7 @@
ACameraCaptureSession::~ACameraCaptureSession() {
ALOGV("~ACameraCaptureSession: %p notify device end of life", this);
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev != nullptr && !dev->isClosed()) {
dev->lockDeviceForSessionOps();
{
@@ -48,7 +48,7 @@
mClosedByApp = true;
}
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev != nullptr) {
dev->lockDeviceForSessionOps();
}
@@ -73,7 +73,7 @@
camera_status_t
ACameraCaptureSession::stopRepeating() {
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -91,7 +91,7 @@
camera_status_t
ACameraCaptureSession::abortCaptures() {
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -107,49 +107,8 @@
return ret;
}
-camera_status_t
-ACameraCaptureSession::setRepeatingRequest(
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
- int numRequests, ACaptureRequest** requests,
- /*optional*/int* captureSequenceId) {
- sp<CameraDevice> dev = getDeviceSp();
- if (dev == nullptr) {
- ALOGE("Error: Device associated with session %p has been closed!", this);
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
-
- camera_status_t ret;
- dev->lockDeviceForSessionOps();
- {
- Mutex::Autolock _l(mSessionLock);
- ret = dev->setRepeatingRequestsLocked(
- this, cbs, numRequests, requests, captureSequenceId);
- }
- dev->unlockDevice();
- return ret;
-}
-
-camera_status_t ACameraCaptureSession::capture(
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
- int numRequests, ACaptureRequest** requests,
- /*optional*/int* captureSequenceId) {
- sp<CameraDevice> dev = getDeviceSp();
- if (dev == nullptr) {
- ALOGE("Error: Device associated with session %p has been closed!", this);
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
- camera_status_t ret;
- dev->lockDeviceForSessionOps();
- {
- Mutex::Autolock _l(mSessionLock);
- ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
- }
- dev->unlockDevice();
- return ret;
-}
-
camera_status_t ACameraCaptureSession::updateOutputConfiguration(ACaptureSessionOutput *output) {
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -168,7 +127,7 @@
ACameraDevice*
ACameraCaptureSession::getDevice() {
Mutex::Autolock _l(mSessionLock);
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return nullptr;
@@ -182,9 +141,9 @@
mIsClosed = true;
}
-sp<CameraDevice>
+sp<acam::CameraDevice>
ACameraCaptureSession::getDeviceSp() {
- sp<CameraDevice> device = mDevice.promote();
+ sp<acam::CameraDevice> device = mDevice.promote();
if (device == nullptr || device->isClosed()) {
ALOGW("Device is closed but session %d is not notified", mId);
return nullptr;
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index a2068e7..08a9226 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -17,15 +17,22 @@
#define _ACAMERA_CAPTURE_SESSION_H
#include <set>
+#include <string>
#include <hardware/camera3.h>
#include <camera/NdkCameraDevice.h>
+
+#ifdef __ANDROID_VNDK__
+#include "ndk_vendor/impl/ACameraDevice.h"
+#include "ndk_vendor/impl/ACameraCaptureSessionVendor.h"
+#else
#include "ACameraDevice.h"
using namespace android;
struct ACaptureSessionOutput {
- explicit ACaptureSessionOutput(ANativeWindow* window, bool isShared = false) :
- mWindow(window), mIsShared(isShared) {};
+ explicit ACaptureSessionOutput(ACameraWindowType* window, bool isShared = false,
+ const char* physicalCameraId = "") :
+ mWindow(window), mIsShared(isShared), mPhysicalCameraId(physicalCameraId) {};
bool operator == (const ACaptureSessionOutput& other) const {
return mWindow == other.mWindow;
@@ -40,11 +47,13 @@
return mWindow > other.mWindow;
}
- ANativeWindow* mWindow;
- std::set<ANativeWindow *> mSharedWindows;
+ ACameraWindowType* mWindow;
+ std::set<ACameraWindowType *> mSharedWindows;
bool mIsShared;
int mRotation = CAMERA3_STREAM_ROTATION_0;
+ std::string mPhysicalCameraId;
};
+#endif
struct ACaptureSessionOutputContainer {
std::set<ACaptureSessionOutput> mOutputs;
@@ -60,7 +69,7 @@
int id,
const ACaptureSessionOutputContainer* outputs,
const ACameraCaptureSession_stateCallbacks* cb,
- CameraDevice* device) :
+ android::acam::CameraDevice* device) :
mId(id), mOutput(*outputs), mUserSessionCallback(*cb),
mDevice(device) {}
@@ -82,13 +91,15 @@
camera_status_t abortCaptures();
+ template<class T>
camera_status_t setRepeatingRequest(
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ /*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
+ template<class T>
camera_status_t capture(
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ /*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
@@ -97,18 +108,18 @@
ACameraDevice* getDevice();
private:
- friend class CameraDevice;
+ friend class android::acam::CameraDevice;
// Close session because app close camera device, camera device got ERROR_DISCONNECTED,
// or a new session is replacing this session.
void closeByDevice();
- sp<CameraDevice> getDeviceSp();
+ sp<android::acam::CameraDevice> getDeviceSp();
const int mId;
const ACaptureSessionOutputContainer mOutput;
const ACameraCaptureSession_stateCallbacks mUserSessionCallback;
- const wp<CameraDevice> mDevice;
+ const wp<android::acam::CameraDevice> mDevice;
bool mIsClosed = false;
bool mClosedByApp = false;
Mutex mSessionLock;
diff --git a/camera/ndk/impl/ACameraCaptureSession.inc b/camera/ndk/impl/ACameraCaptureSession.inc
new file mode 100644
index 0000000..86bf8a5
--- /dev/null
+++ b/camera/ndk/impl/ACameraCaptureSession.inc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ACameraCaptureSession.h"
+
+#ifdef __ANDROID_VNDK__
+#include "ndk_vendor/impl/ACameraDeviceVendor.inc"
+#else
+#include "ACameraDevice.inc"
+#endif
+
+using namespace android;
+
+template <class T>
+camera_status_t
+ACameraCaptureSession::setRepeatingRequest(
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ sp<acam::CameraDevice> dev = getDeviceSp();
+ if (dev == nullptr) {
+ ALOGE("Error: Device associated with session %p has been closed!", this);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ camera_status_t ret;
+ dev->lockDeviceForSessionOps();
+ {
+ Mutex::Autolock _l(mSessionLock);
+ ret = dev->setRepeatingRequestsLocked(
+ this, cbs, numRequests, requests, captureSequenceId);
+ }
+ dev->unlockDevice();
+ return ret;
+}
+
+template <class T>
+camera_status_t ACameraCaptureSession::capture(
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ sp<acam::CameraDevice> dev = getDeviceSp();
+ if (dev == nullptr) {
+ ALOGE("Error: Device associated with session %p has been closed!", this);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+ camera_status_t ret;
+ dev->lockDeviceForSessionOps();
+ {
+ Mutex::Autolock _l(mSessionLock);
+ ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
+ }
+ dev->unlockDevice();
+ return ret;
+}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 907debc..d24cb81 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -20,16 +20,21 @@
#include <vector>
#include <inttypes.h>
#include <android/hardware/ICameraService.h>
-#include <camera2/SubmitInfo.h>
#include <gui/Surface.h>
#include "ACameraDevice.h"
#include "ACameraMetadata.h"
#include "ACaptureRequest.h"
#include "ACameraCaptureSession.h"
-using namespace android;
+#include "ACameraCaptureSession.inc"
+
+ACameraDevice::~ACameraDevice() {
+ mDevice->stopLooper();
+}
namespace android {
+namespace acam {
+
// Static member definitions
const char* CameraDevice::kContextKey = "Context";
const char* CameraDevice::kDeviceKey = "Device";
@@ -39,10 +44,12 @@
const char* CameraDevice::kCaptureRequestKey = "CaptureRequest";
const char* CameraDevice::kTimeStampKey = "TimeStamp";
const char* CameraDevice::kCaptureResultKey = "CaptureResult";
+const char* CameraDevice::kPhysicalCaptureResultKey = "PhysicalCaptureResult";
const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
const char* CameraDevice::kSequenceIdKey = "SequenceId";
const char* CameraDevice::kFrameNumberKey = "FrameNumber";
const char* CameraDevice::kAnwKey = "Anw";
+const char* CameraDevice::kFailingPhysicalCameraId= "FailingPhysicalCameraId";
/**
* CameraDevice Implementation
@@ -50,11 +57,11 @@
CameraDevice::CameraDevice(
const char* id,
ACameraDevice_StateCallbacks* cb,
- std::unique_ptr<ACameraMetadata> chars,
+ sp<ACameraMetadata> chars,
ACameraDevice* wrapper) :
mCameraId(id),
mAppCallbacks(*cb),
- mChars(std::move(chars)),
+ mChars(chars),
mServiceCallback(new ServiceCallback(this)),
mWrapper(wrapper),
mInError(false),
@@ -74,7 +81,7 @@
__FUNCTION__, strerror(-err), err);
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
}
- mHandler = new CallbackHandler();
+ mHandler = new CallbackHandler(id);
mCbLooper->registerHandler(mHandler);
const CameraMetadata& metadata = mChars->getInternalData();
@@ -95,6 +102,14 @@
mShadingMapSize[0] = entry.data.i32[0];
mShadingMapSize[1] = entry.data.i32[1];
}
+
+ size_t physicalIdCnt = 0;
+ const char*const* physicalCameraIds;
+ if (mChars->isLogicalMultiCamera(&physicalIdCnt, &physicalCameraIds)) {
+ for (size_t i = 0; i < physicalIdCnt; i++) {
+ mPhysicalIds.push_back(physicalCameraIds[i]);
+ }
+ }
}
// Device close implementaiton
@@ -105,14 +120,10 @@
if (!isClosed()) {
disconnectLocked(session);
}
+ LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
+ "CameraDevice looper should've been stopped before ~CameraDevice");
mCurrentSession = nullptr;
- if (mCbLooper != nullptr) {
- mCbLooper->unregisterHandler(mHandler->id());
- mCbLooper->stop();
- }
}
- mCbLooper.clear();
- mHandler.clear();
}
void
@@ -127,8 +138,29 @@
camera_status_t
CameraDevice::createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalIdList,
ACaptureRequest** request) const {
Mutex::Autolock _l(mDeviceLock);
+
+ if (physicalIdList != nullptr) {
+ if (physicalIdList->numCameras > static_cast<int>(mPhysicalIds.size())) {
+ ALOGE("%s: physicalIdList size %d exceeds number of available physical cameras %zu",
+ __FUNCTION__, physicalIdList->numCameras, mPhysicalIds.size());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ for (auto i = 0; i < physicalIdList->numCameras; i++) {
+ if (physicalIdList->cameraIds[i] == nullptr) {
+ ALOGE("%s: physicalId is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (mPhysicalIds.end() == std::find(
+ mPhysicalIds.begin(), mPhysicalIds.end(), physicalIdList->cameraIds[i])) {
+ ALOGE("%s: Invalid physicalId %s!", __FUNCTION__, physicalIdList->cameraIds[i]);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+ }
+
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
return ret;
@@ -149,6 +181,12 @@
}
ACaptureRequest* outReq = new ACaptureRequest();
outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ if (physicalIdList != nullptr) {
+ for (auto i = 0; i < physicalIdList->numCameras; i++) {
+ outReq->physicalSettings.emplace(physicalIdList->cameraIds[i],
+ new ACameraMetadata(*(outReq->settings)));
+ }
+ }
outReq->targets = new ACameraOutputTargets();
*request = outReq;
return ACAMERA_OK;
@@ -190,104 +228,53 @@
return ACAMERA_OK;
}
-camera_status_t
-CameraDevice::captureLocked(
- sp<ACameraCaptureSession> session,
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
- int numRequests, ACaptureRequest** requests,
- /*optional*/int* captureSequenceId) {
- return submitRequestsLocked(
- session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
-}
-
-camera_status_t
-CameraDevice::setRepeatingRequestsLocked(
- sp<ACameraCaptureSession> session,
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
- int numRequests, ACaptureRequest** requests,
- /*optional*/int* captureSequenceId) {
- return submitRequestsLocked(
- session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
-}
-
-camera_status_t
-CameraDevice::submitRequestsLocked(
- sp<ACameraCaptureSession> session,
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
- int numRequests, ACaptureRequest** requests,
- /*optional*/int* captureSequenceId,
- bool isRepeating) {
+camera_status_t CameraDevice::isSessionConfigurationSupported(
+ const ACaptureSessionOutputContainer* sessionOutputContainer) const {
+ Mutex::Autolock _l(mDeviceLock);
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
- ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
return ret;
}
- // Form two vectors of capture request, one for internal tracking
- std::vector<hardware::camera2::CaptureRequest> requestList;
- Vector<sp<CaptureRequest> > requestsV;
- requestsV.setCapacity(numRequests);
- for (int i = 0; i < numRequests; i++) {
- sp<CaptureRequest> req;
- ret = allocateCaptureRequest(requests[i], req);
+ SessionConfiguration sessionConfiguration(0 /*inputWidth*/, 0 /*inputHeight*/,
+ -1 /*inputFormat*/, CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE);
+ for (const auto& output : sessionOutputContainer->mOutputs) {
+ sp<IGraphicBufferProducer> iGBP(nullptr);
+ ret = getIGBPfromAnw(output.mWindow, iGBP);
if (ret != ACAMERA_OK) {
- ALOGE("Convert capture request to internal format failure! ret %d", ret);
+ ALOGE("Camera device %s failed to extract graphic producer from native window",
+ getId());
return ret;
}
- if (req->mSurfaceList.empty()) {
- ALOGE("Capture request without output target cannot be submitted!");
- return ACAMERA_ERROR_INVALID_PARAMETER;
+
+ String16 physicalId16(output.mPhysicalCameraId.c_str());
+ OutputConfiguration outConfig(iGBP, output.mRotation, physicalId16,
+ OutputConfiguration::INVALID_SET_ID, true);
+
+ for (auto& anw : output.mSharedWindows) {
+ ret = getIGBPfromAnw(anw, iGBP);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s failed to extract graphic producer from native window",
+ getId());
+ return ret;
+ }
+ outConfig.addGraphicProducer(iGBP);
}
- requestList.push_back(*(req.get()));
- requestsV.push_back(req);
+
+ sessionConfiguration.addOutputConfiguration(outConfig);
}
- if (isRepeating) {
- ret = stopRepeatingLocked();
- if (ret != ACAMERA_OK) {
- ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
- return ret;
- }
- }
-
- binder::Status remoteRet;
- hardware::camera2::utils::SubmitInfo info;
- remoteRet = mRemote->submitRequestList(requestList, isRepeating, &info);
- int sequenceId = info.mRequestId;
- int64_t lastFrameNumber = info.mLastFrameNumber;
- if (sequenceId < 0) {
- ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
+ bool supported = false;
+ binder::Status remoteRet = mRemote->isSessionConfigurationSupported(
+ sessionConfiguration, &supported);
+ if (remoteRet.serviceSpecificErrorCode() ==
+ hardware::ICameraService::ERROR_INVALID_OPERATION) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ } else if (!remoteRet.isOk()) {
return ACAMERA_ERROR_UNKNOWN;
- }
-
- CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
- mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
-
- if (isRepeating) {
- // stopRepeating above should have cleanup repeating sequence id
- if (mRepeatingSequenceId != REQUEST_ID_NONE) {
- setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
- return ACAMERA_ERROR_CAMERA_DEVICE;
- }
- mRepeatingSequenceId = sequenceId;
} else {
- mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+ return supported ? ACAMERA_OK : ACAMERA_ERROR_STREAM_CONFIGURE_FAIL;
}
-
- if (mIdle) {
- sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
- msg->setPointer(kContextKey, session->mUserSessionCallback.context);
- msg->setObject(kSessionSpKey, session);
- msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
- postSessionMsgAndCleanup(msg);
- }
- mIdle = false;
- mBusySession = session;
-
- if (captureSequenceId) {
- *captureSequenceId = sequenceId;
- }
- return ACAMERA_OK;
}
camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
@@ -325,8 +312,9 @@
return ret;
}
- OutputConfiguration outConfig(iGBP, output->mRotation, OutputConfiguration::INVALID_SET_ID,
- true);
+ String16 physicalId16(output->mPhysicalCameraId.c_str());
+ OutputConfiguration outConfig(iGBP, output->mRotation, physicalId16,
+ OutputConfiguration::INVALID_SET_ID, true);
for (auto& anw : output->mSharedWindows) {
ret = getIGBPfromAnw(anw, iGBP);
@@ -372,8 +360,12 @@
const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
camera_status_t ret;
sp<CaptureRequest> req(new CaptureRequest());
- req->mPhysicalCameraSettings.push_back({std::string(mCameraId.string()),
+ req->mPhysicalCameraSettings.push_back({getId(),
request->settings->getInternalData()});
+ for (auto& entry : request->physicalSettings) {
+ req->mPhysicalCameraSettings.push_back({entry.first,
+ entry.second->getInternalData()});
+ }
req->mIsReprocess = false; // NDK does not support reprocessing yet
req->mContext = request->context;
req->mSurfaceConverted = true; // set to true, and fill in stream/surface idx to speed up IPC
@@ -417,10 +409,17 @@
}
ACaptureRequest*
-CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req, const std::string& deviceId) {
ACaptureRequest* pRequest = new ACaptureRequest();
- CameraMetadata clone = req->mPhysicalCameraSettings.begin()->settings;
- pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+ for (auto& entry : req->mPhysicalCameraSettings) {
+ CameraMetadata clone = entry.settings;
+ if (entry.id == deviceId) {
+ pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+ } else {
+ pRequest->physicalSettings.emplace(entry.id,
+ new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST));
+ }
+ }
pRequest->targets = new ACameraOutputTargets();
for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
ANativeWindow* anw = static_cast<ANativeWindow*>(req->mSurfaceList[i].get());
@@ -436,7 +435,8 @@
if (req == nullptr) {
return;
}
- delete req->settings;
+ req->settings.clear();
+ req->physicalSettings.clear();
delete req->targets;
delete req;
}
@@ -633,15 +633,16 @@
}
std::set<std::pair<ANativeWindow*, OutputConfiguration>> outputSet;
- for (auto outConfig : outputs->mOutputs) {
+ for (const auto& outConfig : outputs->mOutputs) {
ANativeWindow* anw = outConfig.mWindow;
sp<IGraphicBufferProducer> iGBP(nullptr);
ret = getIGBPfromAnw(anw, iGBP);
if (ret != ACAMERA_OK) {
return ret;
}
+ String16 physicalId16(outConfig.mPhysicalCameraId.c_str());
outputSet.insert(std::make_pair(
- anw, OutputConfiguration(iGBP, outConfig.mRotation,
+ anw, OutputConfiguration(iGBP, outConfig.mRotation, physicalId16,
OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared)));
}
auto addSet = outputSet;
@@ -706,7 +707,7 @@
}
// add new streams
- for (auto outputPair : addSet) {
+ for (const auto& outputPair : addSet) {
int streamId;
remoteRet = mRemote->createStream(outputPair.second, &streamId);
if (!remoteRet.isOk()) {
@@ -829,7 +830,7 @@
if (errorCode == hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER) {
int32_t streamId = resultExtras.errorStreamId;
ACameraCaptureSession_captureCallback_bufferLost onBufferLost =
- cbh.mCallbacks.onCaptureBufferLost;
+ cbh.mOnCaptureBufferLost;
auto outputPairIt = mConfiguredOutputs.find(streamId);
if (outputPairIt == mConfiguredOutputs.end()) {
ALOGE("%s: Error: stream id %d does not exist", __FUNCTION__, streamId);
@@ -839,14 +840,14 @@
const auto& gbps = outputPairIt->second.second.getGraphicBufferProducers();
for (const auto& outGbp : gbps) {
- for (auto surface : request->mSurfaceList) {
+ for (const auto& surface : request->mSurfaceList) {
if (surface->getIGraphicBufferProducer() == outGbp) {
ANativeWindow* anw = static_cast<ANativeWindow*>(surface.get());
ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
getId(), anw, frameNumber);
sp<AMessage> msg = new AMessage(kWhatCaptureBufferLost, mHandler);
- msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onBufferLost);
msg->setObject(kCaptureRequestKey, request);
@@ -858,7 +859,7 @@
}
} else { // Handle other capture failures
// Fire capture failure callback if there is one registered
- ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
+ ACameraCaptureSession_captureCallback_failed onError = cbh.mOnCaptureFailed;
sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
failure->frameNumber = frameNumber;
// TODO: refine this when implementing flush
@@ -867,10 +868,19 @@
failure->wasImageCaptured = (errorCode ==
hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT);
- sp<AMessage> msg = new AMessage(kWhatCaptureFail, mHandler);
- msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ sp<AMessage> msg = new AMessage(cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureFail :
+ kWhatCaptureFail, mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
- msg->setPointer(kCallbackFpKey, (void*) onError);
+ if (cbh.mIsLogicalCameraCallback) {
+ if (resultExtras.errorPhysicalCameraId.size() > 0) {
+ String8 cameraId(resultExtras.errorPhysicalCameraId);
+ msg->setString(kFailingPhysicalCameraId, cameraId.string(), cameraId.size());
+ }
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mOnLogicalCameraCaptureFailed);
+ } else {
+ msg->setPointer(kCallbackFpKey, (void*) onError);
+ }
msg->setObject(kCaptureRequestKey, request);
msg->setObject(kCaptureFailureKey, failure);
postSessionMsgAndCleanup(msg);
@@ -882,6 +892,19 @@
return;
}
+void CameraDevice::stopLooper() {
+ Mutex::Autolock _l(mDeviceLock);
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+}
+
+CameraDevice::CallbackHandler::CallbackHandler(const char* id) : mId(id) {
+}
+
void CameraDevice::CallbackHandler::onMessageReceived(
const sp<AMessage> &msg) {
switch (msg->what()) {
@@ -890,7 +913,9 @@
case kWhatSessionStateCb:
case kWhatCaptureStart:
case kWhatCaptureResult:
+ case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
+ case kWhatLogicalCaptureFail:
case kWhatCaptureSeqEnd:
case kWhatCaptureSeqAbort:
case kWhatCaptureBufferLost:
@@ -960,7 +985,9 @@
case kWhatSessionStateCb:
case kWhatCaptureStart:
case kWhatCaptureResult:
+ case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
+ case kWhatLogicalCaptureFail:
case kWhatCaptureSeqEnd:
case kWhatCaptureSeqAbort:
case kWhatCaptureBufferLost:
@@ -977,7 +1004,9 @@
switch (msg->what()) {
case kWhatCaptureStart:
case kWhatCaptureResult:
+ case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
+ case kWhatLogicalCaptureFail:
case kWhatCaptureBufferLost:
found = msg->findObject(kCaptureRequestKey, &obj);
if (!found) {
@@ -1020,7 +1049,7 @@
ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
return;
}
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onStart)(context, session.get(), request, timestamp);
freeACaptureRequest(request);
break;
@@ -1043,11 +1072,69 @@
return;
}
sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onResult)(context, session.get(), request, result.get());
freeACaptureRequest(request);
break;
}
+ case kWhatLogicalCaptureResult:
+ {
+ ACameraCaptureSession_logicalCamera_captureCallback_result onResult;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
+ if (!found) {
+ ALOGE("%s: Cannot find logicalCamera capture result callback!",
+ __FUNCTION__);
+ return;
+ }
+ if (onResult == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureResultKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
+
+ found = msg->findObject(kPhysicalCaptureResultKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find physical capture result!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraPhysicalCaptureResultInfo> physicalResult(
+ static_cast<ACameraPhysicalCaptureResultInfo*>(obj.get()));
+ std::vector<PhysicalCaptureResultInfo>& physicalResultInfo =
+ physicalResult->mPhysicalResultInfo;
+
+ std::vector<std::string> physicalCameraIds;
+ std::vector<sp<ACameraMetadata>> physicalMetadataCopy;
+ for (size_t i = 0; i < physicalResultInfo.size(); i++) {
+ String8 physicalId8(physicalResultInfo[i].mPhysicalCameraId);
+ physicalCameraIds.push_back(physicalId8.c_str());
+
+ CameraMetadata clone = physicalResultInfo[i].mPhysicalCameraMetadata;
+ clone.update(ANDROID_SYNC_FRAME_NUMBER,
+ &physicalResult->mFrameNumber, /*data_count*/1);
+ sp<ACameraMetadata> metadata =
+ new ACameraMetadata(clone.release(), ACameraMetadata::ACM_RESULT);
+ physicalMetadataCopy.push_back(metadata);
+ }
+
+ std::vector<const char*> physicalCameraIdPtrs;
+ std::vector<const ACameraMetadata*> physicalMetadataCopyPtrs;
+ for (size_t i = 0; i < physicalResultInfo.size(); i++) {
+ physicalCameraIdPtrs.push_back(physicalCameraIds[i].c_str());
+ physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
+ }
+
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
+ (*onResult)(context, session.get(), request, result.get(),
+ physicalResultInfo.size(), physicalCameraIdPtrs.data(),
+ physicalMetadataCopyPtrs.data());
+ freeACaptureRequest(request);
+ break;
+ }
case kWhatCaptureFail:
{
ACameraCaptureSession_captureCallback_failed onFail;
@@ -1069,11 +1156,44 @@
static_cast<CameraCaptureFailure*>(obj.get()));
ACameraCaptureFailure* failure =
static_cast<ACameraCaptureFailure*>(failureSp.get());
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onFail)(context, session.get(), request, failure);
freeACaptureRequest(request);
break;
}
+ case kWhatLogicalCaptureFail:
+ {
+ ACameraCaptureSession_logicalCamera_captureCallback_failed onFail;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onFail);
+ if (!found) {
+ ALOGE("%s: Cannot find capture fail callback!", __FUNCTION__);
+ return;
+ }
+ if (onFail == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureFailureKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture failure!", __FUNCTION__);
+ return;
+ }
+ sp<CameraCaptureFailure> failureSp(
+ static_cast<CameraCaptureFailure*>(obj.get()));
+ ALogicalCameraCaptureFailure failure;
+ AString physicalCameraId;
+ found = msg->findString(kFailingPhysicalCameraId, &physicalCameraId);
+ if (found && !physicalCameraId.empty()) {
+ failure.physicalCameraId = physicalCameraId.c_str();
+ } else {
+ failure.physicalCameraId = nullptr;
+ }
+ failure.captureFailure = *failureSp;
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
+ (*onFail)(context, session.get(), request, &failure);
+ freeACaptureRequest(request);
+ break;
+ }
case kWhatCaptureSeqEnd:
{
ACameraCaptureSession_captureCallback_sequenceEnd onSeqEnd;
@@ -1146,7 +1266,7 @@
return;
}
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onBufferLost)(context, session.get(), request, anw, frameNumber);
freeACaptureRequest(request);
break;
@@ -1158,12 +1278,36 @@
}
CameraDevice::CallbackHolder::CallbackHolder(
- sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest> >& requests,
- bool isRepeating,
- ACameraCaptureSession_captureCallbacks* cbs) :
- mSession(session), mRequests(requests),
- mIsRepeating(isRepeating), mCallbacks(fillCb(cbs)) {}
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacks* cbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIsLogicalCameraCallback(false) {
+ initCaptureCallbacks(cbs);
+
+ if (cbs != nullptr) {
+ mOnCaptureCompleted = cbs->onCaptureCompleted;
+ mOnCaptureFailed = cbs->onCaptureFailed;
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIsLogicalCameraCallback(true) {
+ initCaptureCallbacks(lcbs);
+
+ if (lcbs != nullptr) {
+ mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
+ mOnLogicalCameraCaptureFailed = lcbs->onLogicalCameraCaptureFailed;
+ }
+}
void
CameraDevice::checkRepeatingSequenceCompleteLocked(
@@ -1180,9 +1324,9 @@
mSequenceCallbackMap.erase(cbIt);
// send seq aborted callback
sp<AMessage> msg = new AMessage(kWhatCaptureSeqAbort, mHandler);
- msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, cbh.mSession);
- msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceAborted);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceAborted);
msg->setInt32(kSequenceIdKey, sequenceId);
postSessionMsgAndCleanup(msg);
} else {
@@ -1230,9 +1374,9 @@
mSequenceCallbackMap.erase(cbIt);
// send seq complete callback
sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
- msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, cbh.mSession);
- msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceCompleted);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
msg->setInt32(kSequenceIdKey, sequenceId);
msg->setInt64(kFrameNumberKey, lastFrameNumber);
@@ -1290,16 +1434,21 @@
}
default:
ALOGE("Unknown error from camera device: %d", errorCode);
- // no break
+ [[fallthrough]];
case ERROR_CAMERA_DEVICE:
case ERROR_CAMERA_SERVICE:
{
+ int32_t errorVal = ::ERROR_CAMERA_DEVICE;
+ // We keep this switch since this block might be encountered with
+ // more than just 2 states. The default fallthrough could have us
+ // handling more unmatched error cases.
switch (errorCode) {
case ERROR_CAMERA_DEVICE:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
break;
case ERROR_CAMERA_SERVICE:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ errorVal = ::ERROR_CAMERA_SERVICE;
break;
default:
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
@@ -1309,7 +1458,7 @@
msg->setPointer(kContextKey, dev->mAppCallbacks.context);
msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
- msg->setInt32(kErrorCodeKey, errorCode);
+ msg->setInt32(kErrorCodeKey, errorVal);
msg->post();
break;
}
@@ -1384,7 +1533,7 @@
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
- ACameraCaptureSession_captureCallback_start onStart = cbh.mCallbacks.onCaptureStarted;
+ ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@@ -1393,7 +1542,7 @@
}
sp<CaptureRequest> request = cbh.mRequests[burstId];
sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
- msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onStart);
msg->setObject(kCaptureRequestKey, request);
@@ -1408,7 +1557,6 @@
const CameraMetadata& metadata,
const CaptureResultExtras& resultExtras,
const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
- (void) physicalResultInfos;
binder::Status ret = binder::Status::ok();
sp<CameraDevice> dev = mDevice.promote();
@@ -1444,9 +1592,6 @@
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
- ACameraCaptureSession_captureCallback_result onResult = isPartialResult ?
- cbh.mCallbacks.onCaptureProgressed :
- cbh.mCallbacks.onCaptureCompleted;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@@ -1456,13 +1601,27 @@
sp<CaptureRequest> request = cbh.mRequests[burstId];
sp<ACameraMetadata> result(new ACameraMetadata(
metadataCopy.release(), ACameraMetadata::ACM_RESULT));
+ sp<ACameraPhysicalCaptureResultInfo> physicalResult(
+ new ACameraPhysicalCaptureResultInfo(physicalResultInfos, frameNumber));
- sp<AMessage> msg = new AMessage(kWhatCaptureResult, dev->mHandler);
- msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ sp<AMessage> msg = new AMessage(
+ cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureResult : kWhatCaptureResult,
+ dev->mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
- msg->setPointer(kCallbackFpKey, (void*) onResult);
msg->setObject(kCaptureRequestKey, request);
msg->setObject(kCaptureResultKey, result);
+ if (isPartialResult) {
+ msg->setPointer(kCallbackFpKey,
+ (void *)cbh.mOnCaptureProgressed);
+ } else if (cbh.mIsLogicalCameraCallback) {
+ msg->setPointer(kCallbackFpKey,
+ (void *)cbh.mOnLogicalCameraCaptureCompleted);
+ msg->setObject(kPhysicalCaptureResultKey, physicalResult);
+ } else {
+ msg->setPointer(kCallbackFpKey,
+ (void *)cbh.mOnCaptureCompleted);
+ }
dev->postSessionMsgAndCleanup(msg);
}
@@ -1508,5 +1667,5 @@
return ret;
}
-
+} // namespace acam
} // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 1369148..7a35bf0 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -21,6 +21,7 @@
#include <set>
#include <atomic>
#include <utility>
+#include <vector>
#include <utils/StrongPointer.h>
#include <utils/Mutex.h>
#include <utils/String8.h>
@@ -34,6 +35,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <camera/CaptureResult.h>
#include <camera/camera2/OutputConfiguration.h>
+#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/CaptureRequest.h>
#include <camera/NdkCameraManager.h>
@@ -41,14 +43,25 @@
#include "ACameraMetadata.h"
namespace android {
+namespace acam {
// Wrap ACameraCaptureFailure so it can be ref-counted
struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
+// Wrap PhysicalCaptureResultInfo so that it can be ref-counted
+struct ACameraPhysicalCaptureResultInfo: public RefBase {
+ ACameraPhysicalCaptureResultInfo(const std::vector<PhysicalCaptureResultInfo>& info,
+ int64_t frameNumber) :
+ mPhysicalResultInfo(info), mFrameNumber(frameNumber) {}
+
+ std::vector<PhysicalCaptureResultInfo> mPhysicalResultInfo;
+ int64_t mFrameNumber;
+};
+
class CameraDevice final : public RefBase {
public:
CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
- std::unique_ptr<ACameraMetadata> chars,
+ sp<ACameraMetadata> chars,
ACameraDevice* wrapper);
~CameraDevice();
@@ -56,6 +69,7 @@
camera_status_t createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalIdList,
ACaptureRequest** request) const;
camera_status_t createCaptureSession(
@@ -64,6 +78,9 @@
const ACameraCaptureSession_stateCallbacks* callbacks,
/*out*/ACameraCaptureSession** session);
+ camera_status_t isSessionConfigurationSupported(
+ const ACaptureSessionOutputContainer* sessionOutputContainer) const;
+
// Callbacks from camera service
class ServiceCallback : public hardware::camera2::BnCameraDeviceCallbacks {
public:
@@ -92,6 +109,9 @@
inline ACameraDevice* getWrapper() const { return mWrapper; };
+ // Stop the looper thread and unregister the handler
+ void stopLooper();
+
private:
friend ACameraCaptureSession;
camera_status_t checkCameraClosedOrErrorLocked() const;
@@ -108,19 +128,22 @@
camera_status_t waitUntilIdleLocked();
+ template<class T>
camera_status_t captureLocked(sp<ACameraCaptureSession> session,
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ /*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
+ template<class T>
camera_status_t setRepeatingRequestsLocked(sp<ACameraCaptureSession> session,
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ /*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
+ template<class T>
camera_status_t submitRequestsLocked(
sp<ACameraCaptureSession> session,
- /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ /*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*out*/int* captureSequenceId,
bool isRepeating);
@@ -130,7 +153,8 @@
camera_status_t allocateCaptureRequest(
const ACaptureRequest* request, sp<CaptureRequest>& outReq);
- static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+ static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req,
+ const std::string& deviceId);
static void freeACaptureRequest(ACaptureRequest*);
// only For session to hold device lock
@@ -156,7 +180,7 @@
mutable Mutex mDeviceLock;
const String8 mCameraId; // Camera ID
const ACameraDevice_StateCallbacks mAppCallbacks; // Callback to app
- const std::unique_ptr<ACameraMetadata> mChars; // Camera characteristics
+ const sp<ACameraMetadata> mChars; // Camera characteristics
const sp<ServiceCallback> mServiceCallback;
ACameraDevice* mWrapper;
@@ -191,7 +215,9 @@
// Capture callbacks
kWhatCaptureStart, // onCaptureStarted
kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
+ kWhatLogicalCaptureResult, // onLogicalCameraCaptureCompleted
kWhatCaptureFail, // onCaptureFailed
+ kWhatLogicalCaptureFail, // onLogicalCameraCaptureFailed
kWhatCaptureSeqEnd, // onCaptureSequenceCompleted
kWhatCaptureSeqAbort, // onCaptureSequenceAborted
kWhatCaptureBufferLost,// onCaptureBufferLost
@@ -206,16 +232,20 @@
static const char* kCaptureRequestKey;
static const char* kTimeStampKey;
static const char* kCaptureResultKey;
+ static const char* kPhysicalCaptureResultKey;
static const char* kCaptureFailureKey;
static const char* kSequenceIdKey;
static const char* kFrameNumberKey;
static const char* kAnwKey;
+ static const char* kFailingPhysicalCameraId;
class CallbackHandler : public AHandler {
public:
+ explicit CallbackHandler(const char* id);
void onMessageReceived(const sp<AMessage> &msg) override;
private:
+ std::string mId;
// This handler will cache all capture session sp until kWhatCleanUpSessions
// is processed. This is used to guarantee the last session reference is always
// being removed in callback thread without holding camera device lock
@@ -244,19 +274,47 @@
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs);
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
- static ACameraCaptureSession_captureCallbacks fillCb(
- ACameraCaptureSession_captureCallbacks* cbs) {
+ template <class T>
+ void initCaptureCallbacks(T* cbs) {
+ mContext = nullptr;
+ mOnCaptureStarted = nullptr;
+ mOnCaptureProgressed = nullptr;
+ mOnCaptureCompleted = nullptr;
+ mOnLogicalCameraCaptureCompleted = nullptr;
+ mOnLogicalCameraCaptureFailed = nullptr;
+ mOnCaptureFailed = nullptr;
+ mOnCaptureSequenceCompleted = nullptr;
+ mOnCaptureSequenceAborted = nullptr;
+ mOnCaptureBufferLost = nullptr;
if (cbs != nullptr) {
- return *cbs;
+ mContext = cbs->context;
+ mOnCaptureStarted = cbs->onCaptureStarted;
+ mOnCaptureProgressed = cbs->onCaptureProgressed;
+ mOnCaptureSequenceCompleted = cbs->onCaptureSequenceCompleted;
+ mOnCaptureSequenceAborted = cbs->onCaptureSequenceAborted;
+ mOnCaptureBufferLost = cbs->onCaptureBufferLost;
}
- return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
}
-
sp<ACameraCaptureSession> mSession;
Vector<sp<CaptureRequest> > mRequests;
const bool mIsRepeating;
- ACameraCaptureSession_captureCallbacks mCallbacks;
+ const bool mIsLogicalCameraCallback;
+
+ void* mContext;
+ ACameraCaptureSession_captureCallback_start mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_result mOnCaptureProgressed;
+ ACameraCaptureSession_captureCallback_result mOnCaptureCompleted;
+ ACameraCaptureSession_logicalCamera_captureCallback_result mOnLogicalCameraCaptureCompleted;
+ ACameraCaptureSession_logicalCamera_captureCallback_failed mOnLogicalCameraCaptureFailed;
+ ACameraCaptureSession_captureCallback_failed mOnCaptureFailed;
+ ACameraCaptureSession_captureCallback_sequenceEnd mOnCaptureSequenceCompleted;
+ ACameraCaptureSession_captureCallback_sequenceAbort mOnCaptureSequenceAborted;
+ ACameraCaptureSession_captureCallback_bufferLost mOnCaptureBufferLost;
};
// sequence id -> callbacks map
std::map<int, CallbackHolder> mSequenceCallbackMap;
@@ -283,9 +341,11 @@
// Misc variables
int32_t mShadingMapSize[2]; // const after constructor
int32_t mPartialResultCount; // const after constructor
+ std::vector<std::string> mPhysicalIds; // const after constructor
};
+} // namespace acam;
} // namespace android;
/**
@@ -294,10 +354,10 @@
*/
struct ACameraDevice {
ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
- std::unique_ptr<ACameraMetadata> chars) :
- mDevice(new CameraDevice(id, cb, std::move(chars), this)) {}
+ sp<ACameraMetadata> chars) :
+ mDevice(new android::acam::CameraDevice(id, cb, chars, this)) {}
- ~ACameraDevice() {};
+ ~ACameraDevice();
/*******************
* NDK public APIs *
@@ -306,8 +366,9 @@
camera_status_t createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
ACaptureRequest** request) const {
- return mDevice->createCaptureRequest(templateId, request);
+ return mDevice->createCaptureRequest(templateId, physicalCameraIdList, request);
}
camera_status_t createCaptureSession(
@@ -318,6 +379,11 @@
return mDevice->createCaptureSession(outputs, sessionParameters, callbacks, session);
}
+ camera_status_t isSessionConfigurationSupported(
+ const ACaptureSessionOutputContainer* sessionOutputContainer) const {
+ return mDevice->isSessionConfigurationSupported(sessionOutputContainer);
+ }
+
/***********************
* Device interal APIs *
***********************/
@@ -331,7 +397,7 @@
}
private:
- android::sp<android::CameraDevice> mDevice;
+ android::sp<android::acam::CameraDevice> mDevice;
};
#endif // _ACAMERA_DEVICE_H
diff --git a/camera/ndk/impl/ACameraDevice.inc b/camera/ndk/impl/ACameraDevice.inc
new file mode 100644
index 0000000..1fc5352
--- /dev/null
+++ b/camera/ndk/impl/ACameraDevice.inc
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+#include <inttypes.h>
+#include "ACameraDevice.h"
+#include "ACameraMetadata.h"
+#include "ACaptureRequest.h"
+#include "ACameraCaptureSession.h"
+
+namespace android {
+namespace acam {
+
+template<class T>
+camera_status_t
+CameraDevice::captureLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ return submitRequestsLocked(
+ session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
+}
+
+template<class T>
+camera_status_t
+CameraDevice::setRepeatingRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ return submitRequestsLocked(
+ session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
+}
+
+template<class T>
+camera_status_t CameraDevice::submitRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId,
+ bool isRepeating) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ // Form two vectors of capture request, one for internal tracking
+ std::vector<hardware::camera2::CaptureRequest> requestList;
+ Vector<sp<CaptureRequest> > requestsV;
+ requestsV.setCapacity(numRequests);
+ for (int i = 0; i < numRequests; i++) {
+ sp<CaptureRequest> req;
+ ret = allocateCaptureRequest(requests[i], req);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Convert capture request to internal format failure! ret %d", ret);
+ return ret;
+ }
+ if (req->mSurfaceList.empty()) {
+ ALOGE("Capture request without output target cannot be submitted!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ requestList.push_back(*(req.get()));
+ requestsV.push_back(req);
+ }
+
+ if (isRepeating) {
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+ }
+
+ binder::Status remoteRet;
+ hardware::camera2::utils::SubmitInfo info;
+ remoteRet = mRemote->submitRequestList(requestList, isRepeating, &info);
+ int sequenceId = info.mRequestId;
+ int64_t lastFrameNumber = info.mLastFrameNumber;
+ if (sequenceId < 0) {
+ ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
+ mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+
+ if (isRepeating) {
+ // stopRepeating above should have cleanup repeating sequence id
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ mRepeatingSequenceId = sequenceId;
+ } else {
+ mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+ }
+
+ if (mIdle) {
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+ postSessionMsgAndCleanup(msg);
+ }
+ mIdle = false;
+ mBusySession = session;
+
+ if (captureSequenceId) {
+ *captureSequenceId = sequenceId;
+ }
+ return ACAMERA_OK;
+}
+
+} // namespace acam
+} // namespace android
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index c59d0e7..9d40fd7 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -26,9 +26,10 @@
#include <stdlib.h>
#include <camera/VendorTagDescriptor.h>
-using namespace android;
+using namespace android::acam;
namespace android {
+namespace acam {
// Static member definitions
const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
@@ -192,6 +193,20 @@
}
}
+void CameraManagerGlobal::registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.insert(cb);
+}
+
+void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.erase(cb);
+}
+
void CameraManagerGlobal::registerAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback) {
Mutex::Autolock _l(mLock);
@@ -288,12 +303,40 @@
(*cb)(context, cameraId.c_str());
break;
}
+ case kWhatSendSingleAccessCallback:
+ {
+ ACameraManager_AccessPrioritiesChangedCallback cb;
+ void* context;
+ AString cameraId;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+ if (!found) {
+ ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ (*cb)(context);
+ break;
+ }
default:
ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
break;
}
}
+binder::Status CameraManagerGlobal::CameraServiceListener::onCameraAccessPrioritiesChanged() {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ cm->onCameraAccessPrioritiesChanged();
+ } else {
+ ALOGE("Cannot deliver camera access priority callback. Global camera manager died");
+ }
+ return binder::Status::ok();
+}
+
binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
int32_t status, const String16& cameraId) {
sp<CameraManagerGlobal> cm = mCameraManager.promote();
@@ -305,6 +348,19 @@
return binder::Status::ok();
}
+void CameraManagerGlobal::onCameraAccessPrioritiesChanged() {
+ Mutex::Autolock _l(mLock);
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSingleAccessCallback, mHandler);
+ ACameraManager_AccessPrioritiesChangedCallback cbFp = cb.mAccessPriorityChanged;
+ if (cbFp != nullptr) {
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->post();
+ }
+ }
+}
+
void CameraManagerGlobal::onStatusChanged(
int32_t status, const String8& cameraId) {
Mutex::Autolock _l(mLock);
@@ -345,6 +401,7 @@
}
}
+} // namespace acam
} // namespace android
/**
@@ -402,7 +459,7 @@
}
camera_status_t ACameraManager::getCameraCharacteristics(
- const char *cameraIdStr, ACameraMetadata **characteristics) {
+ const char* cameraIdStr, sp<ACameraMetadata>* characteristics) {
Mutex::Autolock _l(mLock);
sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
@@ -437,18 +494,16 @@
const char* cameraId,
ACameraDevice_StateCallbacks* callback,
/*out*/ACameraDevice** outDevice) {
- ACameraMetadata* rawChars;
- camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
+ sp<ACameraMetadata> chars;
+ camera_status_t ret = getCameraCharacteristics(cameraId, &chars);
Mutex::Autolock _l(mLock);
if (ret != ACAMERA_OK) {
ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
__FUNCTION__, cameraId, ret);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- std::unique_ptr<ACameraMetadata> chars(rawChars);
- rawChars = nullptr;
- ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(chars));
+ ACameraDevice* device = new ACameraDevice(cameraId, callback, chars);
sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
if (cs == nullptr) {
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index cc42f77..8c1da36 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -35,6 +35,7 @@
#include <map>
namespace android {
+namespace acam {
/**
* Per-process singleton instance of CameraManger. Shared by all ACameraManager
@@ -53,6 +54,11 @@
void unregisterAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback);
+ void registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+ void unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+
/**
* Return camera IDs that support camera2
*/
@@ -85,6 +91,8 @@
return binder::Status::ok();
}
+ virtual binder::Status onCameraAccessPrioritiesChanged();
+
private:
const wp<CameraManagerGlobal> mCameraManager;
};
@@ -95,11 +103,19 @@
explicit Callback(const ACameraManager_AvailabilityCallbacks *callback) :
mAvailable(callback->onCameraAvailable),
mUnavailable(callback->onCameraUnavailable),
+ mAccessPriorityChanged(nullptr),
mContext(callback->context) {}
+ explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) :
+ mAvailable(callback->availabilityCallbacks.onCameraAvailable),
+ mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
+ mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
+ mContext(callback->availabilityCallbacks.context) {}
+
bool operator == (const Callback& other) const {
return (mAvailable == other.mAvailable &&
mUnavailable == other.mUnavailable &&
+ mAccessPriorityChanged == other.mAccessPriorityChanged &&
mContext == other.mContext);
}
bool operator != (const Callback& other) const {
@@ -108,6 +124,9 @@
bool operator < (const Callback& other) const {
if (*this == other) return false;
if (mContext != other.mContext) return mContext < other.mContext;
+ if (mAccessPriorityChanged != other.mAccessPriorityChanged) {
+ return mAccessPriorityChanged < other.mAccessPriorityChanged;
+ }
if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
return mUnavailable < other.mUnavailable;
}
@@ -116,13 +135,15 @@
}
ACameraManager_AvailabilityCallback mAvailable;
ACameraManager_AvailabilityCallback mUnavailable;
+ ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged;
void* mContext;
};
std::set<Callback> mCallbacks;
// definition of handler and message
enum {
- kWhatSendSingleCallback
+ kWhatSendSingleCallback,
+ kWhatSendSingleAccessCallback,
};
static const char* kCameraIdKey;
static const char* kCallbackFpKey;
@@ -135,6 +156,7 @@
sp<CallbackHandler> mHandler;
sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+ void onCameraAccessPrioritiesChanged();
void onStatusChanged(int32_t status, const String8& cameraId);
void onStatusChangedLocked(int32_t status, const String8& cameraId);
// Utils for status
@@ -172,6 +194,7 @@
~CameraManagerGlobal();
};
+} // namespace acam;
} // namespace android;
/**
@@ -180,13 +203,13 @@
*/
struct ACameraManager {
ACameraManager() :
- mGlobalManager(&(android::CameraManagerGlobal::getInstance())) {}
+ mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}
~ACameraManager();
camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
static void deleteCameraIdList(ACameraIdList* cameraIdList);
camera_status_t getCameraCharacteristics(
- const char *cameraId, ACameraMetadata **characteristics);
+ const char* cameraId, android::sp<ACameraMetadata>* characteristics);
camera_status_t openCamera(const char* cameraId,
ACameraDevice_StateCallbacks* callback,
/*out*/ACameraDevice** device);
@@ -196,7 +219,7 @@
kCameraIdListNotInit = -1
};
android::Mutex mLock;
- android::sp<android::CameraManagerGlobal> mGlobalManager;
+ android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
};
#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index fc00a2d..77dcd48 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -32,6 +32,14 @@
if (mType == ACM_CHARACTERISTICS) {
filterUnsupportedFeatures();
filterStreamConfigurations();
+ filterDurations(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+ filterDurations(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
+ filterDurations(ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
+ filterDurations(ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
+ filterDurations(ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS);
+ filterDurations(ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS);
+ filterDurations(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
+ filterDurations(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
}
// TODO: filter request/result keys
}
@@ -39,23 +47,14 @@
bool
ACameraMetadata::isNdkSupportedCapability(int32_t capability) {
switch (capability) {
- case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE:
- case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
- case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
- case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW:
- case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS:
- case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE:
- case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT:
- return true;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING:
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING:
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO:
return false;
default:
- // Newly defined capabilities will be unsupported by default (blacklist)
- // TODO: Should we do whitelist or blacklist here?
- ALOGE("%s: Unknonwn capability %d", __FUNCTION__, capability);
- return false;
+ // Assuming every capability passed to this function is actually a
+ // valid capability.
+ return true;
}
}
@@ -75,11 +74,128 @@
uint8_t capability = entry.data.u8[i];
if (isNdkSupportedCapability(capability)) {
capabilities.push(capability);
+
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+ derivePhysicalCameraIds();
+ }
}
}
mData.update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities);
}
+void
+ACameraMetadata::derivePhysicalCameraIds() {
+ ACameraMetadata_const_entry entry;
+ auto ret = getConstEntry(ACAMERA_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS, &entry);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: Get ACAMERA_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS key failed. ret %d",
+ __FUNCTION__, ret);
+ return;
+ }
+
+ const uint8_t* ids = entry.data.u8;
+ size_t start = 0;
+ for (size_t i = 0; i < entry.count; ++i) {
+ if (ids[i] == '\0') {
+ if (start != i) {
+ mStaticPhysicalCameraIdValues.push_back(String8((const char *)ids+start));
+ mStaticPhysicalCameraIds.push_back(mStaticPhysicalCameraIdValues.back().string());
+ }
+ start = i+1;
+ }
+ }
+
+ if (mStaticPhysicalCameraIds.size() < 2) {
+ ALOGW("%s: Logical multi-camera device only has %zu physical cameras",
+ __FUNCTION__, mStaticPhysicalCameraIds.size());
+ }
+}
+
+void
+ACameraMetadata::filterDurations(uint32_t tag) {
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_DURATION_OFFSET = 3;
+ camera_metadata_entry entry = mData.find(tag);
+ if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT64) {
+ ALOGE("%s: malformed duration key %d! count %zu, type %d",
+ __FUNCTION__, tag, entry.count, entry.type);
+ return;
+ }
+ Vector<int64_t> filteredDurations;
+ filteredDurations.setCapacity(entry.count * 2);
+
+ for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int64_t format = entry.data.i64[i + STREAM_FORMAT_OFFSET];
+ int64_t width = entry.data.i64[i + STREAM_WIDTH_OFFSET];
+ int64_t height = entry.data.i64[i + STREAM_HEIGHT_OFFSET];
+ int64_t duration = entry.data.i32[i + STREAM_DURATION_OFFSET];
+
+ // Leave the unfiltered format in so apps depending on previous wrong
+ // filter behavior continue to work
+ filteredDurations.push_back(format);
+ filteredDurations.push_back(width);
+ filteredDurations.push_back(height);
+ filteredDurations.push_back(duration);
+
+ // Translate HAL formats to NDK format
+ switch (tag) {
+ case ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS:
+ case ANDROID_SCALER_AVAILABLE_STALL_DURATIONS:
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ format = AIMAGE_FORMAT_JPEG;
+ filteredDurations.push_back(format);
+ filteredDurations.push_back(width);
+ filteredDurations.push_back(height);
+ filteredDurations.push_back(duration);
+ }
+ break;
+ case ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:
+ case ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ format = AIMAGE_FORMAT_DEPTH_POINT_CLOUD;
+ filteredDurations.push_back(format);
+ filteredDurations.push_back(width);
+ filteredDurations.push_back(height);
+ filteredDurations.push_back(duration);
+ } else if (format == HAL_PIXEL_FORMAT_Y16) {
+ format = AIMAGE_FORMAT_DEPTH16;
+ filteredDurations.push_back(format);
+ filteredDurations.push_back(width);
+ filteredDurations.push_back(height);
+ filteredDurations.push_back(duration);
+ }
+ break;
+ case ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS:
+ case ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS:
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ format = AIMAGE_FORMAT_HEIC;
+ filteredDurations.push_back(format);
+ filteredDurations.push_back(width);
+ filteredDurations.push_back(height);
+ filteredDurations.push_back(duration);
+ }
+ break;
+ case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS:
+ case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS:
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ format = AIMAGE_FORMAT_DEPTH_JPEG;
+ filteredDurations.push_back(format);
+ filteredDurations.push_back(width);
+ filteredDurations.push_back(height);
+ filteredDurations.push_back(duration);
+ }
+ break;
+ default:
+ // Should not reach here
+ ALOGE("%s: Unkown tag 0x%x", __FUNCTION__, tag);
+ }
+ }
+
+ mData.update(tag, filteredDurations);
+}
void
ACameraMetadata::filterStreamConfigurations() {
@@ -89,7 +205,7 @@
const int STREAM_HEIGHT_OFFSET = 2;
const int STREAM_IS_INPUT_OFFSET = 3;
camera_metadata_entry entry = mData.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
- if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT32) {
+ if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) {
ALOGE("%s: malformed available stream configuration key! count %zu, type %d",
__FUNCTION__, entry.count, entry.type);
return;
@@ -117,9 +233,17 @@
filteredStreamConfigs.push_back(isInput);
}
- mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+ if (filteredStreamConfigs.size() > 0) {
+ mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+ }
entry = mData.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+ if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) {
+ ALOGE("%s: malformed available depth stream configuration key! count %zu, type %d",
+ __FUNCTION__, entry.count, entry.type);
+ return;
+ }
+
Vector<int32_t> filteredDepthStreamConfigs;
filteredDepthStreamConfigs.setCapacity(entry.count);
@@ -144,7 +268,62 @@
filteredDepthStreamConfigs.push_back(height);
filteredDepthStreamConfigs.push_back(isInput);
}
- mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, filteredDepthStreamConfigs);
+
+ if (filteredDepthStreamConfigs.size() > 0) {
+ mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+ filteredDepthStreamConfigs);
+ }
+
+ entry = mData.find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
+ Vector<int32_t> filteredHeicStreamConfigs;
+ filteredHeicStreamConfigs.setCapacity(entry.count);
+
+ for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_INPUT) {
+ // Hide input streams
+ continue;
+ }
+ // Translate HAL formats to NDK format
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ format = AIMAGE_FORMAT_HEIC;
+ }
+
+ filteredHeicStreamConfigs.push_back(format);
+ filteredHeicStreamConfigs.push_back(width);
+ filteredHeicStreamConfigs.push_back(height);
+ filteredHeicStreamConfigs.push_back(isInput);
+ }
+ mData.update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, filteredHeicStreamConfigs);
+
+ entry = mData.find(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
+ Vector<int32_t> filteredDynamicDepthStreamConfigs;
+ filteredDynamicDepthStreamConfigs.setCapacity(entry.count);
+
+ for (size_t i = 0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_INPUT) {
+ // Hide input streams
+ continue;
+ }
+ // Translate HAL formats to NDK format
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ format = AIMAGE_FORMAT_DEPTH_JPEG;
+ }
+
+ filteredDynamicDepthStreamConfigs.push_back(format);
+ filteredDynamicDepthStreamConfigs.push_back(width);
+ filteredDynamicDepthStreamConfigs.push_back(height);
+ filteredDynamicDepthStreamConfigs.push_back(isInput);
+ }
+ mData.update(ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS,
+ filteredDynamicDepthStreamConfigs);
}
bool
@@ -239,6 +418,27 @@
return mData;
}
+bool
+ACameraMetadata::isLogicalMultiCamera(size_t* count, const char*const** physicalCameraIds) const {
+ if (mType != ACM_CHARACTERISTICS) {
+ ALOGE("%s must be called for a static metadata!", __FUNCTION__);
+ return false;
+ }
+ if (count == nullptr || physicalCameraIds == nullptr) {
+ ALOGE("%s: Invalid input count: %p, physicalCameraIds: %p", __FUNCTION__,
+ count, physicalCameraIds);
+ return false;
+ }
+
+ if (mStaticPhysicalCameraIds.size() >= 2) {
+ *count = mStaticPhysicalCameraIds.size();
+ *physicalCameraIds = mStaticPhysicalCameraIds.data();
+ return true;
+ }
+
+ return false;
+}
+
// TODO: some of key below should be hidden from user
// ex: ACAMERA_REQUEST_ID and ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
@@ -360,7 +560,10 @@
ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT,
ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE,
ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE,
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION,
ANDROID_DEPTH_MAX_DEPTH_SAMPLES,
+ ANDROID_HEIC_INFO_SUPPORTED,
+ ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT,
});
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
index 0fd7efa..97f7f48 100644
--- a/camera/ndk/impl/ACameraMetadata.h
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -17,12 +17,19 @@
#define _ACAMERA_METADATA_H
#include <unordered_set>
+#include <vector>
#include <sys/types.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
+
+#ifdef __ANDROID_VNDK__
+#include <CameraMetadata.h>
+using CameraMetadata = android::hardware::camera::common::V1_0::helper::CameraMetadata;
+#else
#include <camera/CameraMetadata.h>
+#endif
#include <camera/NdkCameraMetadata.h>
@@ -58,13 +65,20 @@
camera_status_t getTags(/*out*/int32_t* numTags,
/*out*/const uint32_t** tags) const;
+ const CameraMetadata& getInternalData() const;
+ bool isLogicalMultiCamera(size_t* count, const char* const** physicalCameraIds) const;
+
+ private:
+
+ // This function does not check whether the capability passed to it is valid.
+ // The caller must make sure that it is.
bool isNdkSupportedCapability(const int32_t capability);
static inline bool isVendorTag(const uint32_t tag);
static bool isCaptureRequestTag(const uint32_t tag);
void filterUnsupportedFeatures(); // Hide features not yet supported by NDK
void filterStreamConfigurations(); // Hide input streams, translate hal format to NDK formats
-
- const CameraMetadata& getInternalData() const;
+ void filterDurations(uint32_t tag); // translate hal format to NDK formats
+ void derivePhysicalCameraIds(); // Derive array of physical ids.
template<typename INTERNAL_T, typename NDK_T>
camera_status_t updateImpl(uint32_t tag, uint32_t count, const NDK_T* data) {
@@ -96,7 +110,6 @@
}
}
- private:
// guard access of public APIs: get/update/getTags
mutable Mutex mLock;
CameraMetadata mData;
@@ -104,6 +117,9 @@
const ACAMERA_METADATA_TYPE mType;
static std::unordered_set<uint32_t> sSystemTags;
+
+ std::vector<const char*> mStaticPhysicalCameraIds;
+ std::vector<String8> mStaticPhysicalCameraIdValues;
};
#endif // _ACAMERA_METADATA_H
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
index 06b2cc3..2ffcafe 100644
--- a/camera/ndk/impl/ACaptureRequest.h
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -18,11 +18,15 @@
#include <camera/NdkCaptureRequest.h>
#include <set>
+#include <unordered_map>
using namespace android;
+#ifdef __ANDROID_VNDK__
+#include "ndk_vendor/impl/ACaptureRequestVendor.h"
+#else
struct ACameraOutputTarget {
- explicit ACameraOutputTarget(ANativeWindow* window) : mWindow(window) {};
+ explicit ACameraOutputTarget(ACameraWindowType* window) : mWindow(window) {};
bool operator == (const ACameraOutputTarget& other) const {
return mWindow == other.mWindow;
@@ -37,8 +41,9 @@
return mWindow > other.mWindow;
}
- ANativeWindow* mWindow;
+ ACameraWindowType* mWindow;
};
+#endif
struct ACameraOutputTargets {
std::set<ACameraOutputTarget> mOutputs;
@@ -55,7 +60,8 @@
return ACAMERA_OK;
}
- ACameraMetadata* settings;
+ sp<ACameraMetadata> settings;
+ std::unordered_map<std::string, sp<ACameraMetadata>> physicalSettings;
ACameraOutputTargets* targets;
void* context;
};
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 51cef8c..07176cf 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -35,9 +35,10 @@
#include <sys/cdefs.h>
#include <stdbool.h>
-#include <android/native_window.h>
#include "NdkCameraError.h"
#include "NdkCameraMetadata.h"
+#include "NdkCaptureRequest.h"
+#include "NdkCameraWindowType.h"
#ifndef _NDK_CAMERA_CAPTURE_SESSION_H
#define _NDK_CAMERA_CAPTURE_SESSION_H
@@ -245,7 +246,7 @@
*/
typedef void (*ACameraCaptureSession_captureCallback_bufferLost)(
void* context, ACameraCaptureSession* session,
- ACaptureRequest* request, ANativeWindow* window, int64_t frameNumber);
+ ACaptureRequest* request, ACameraWindowType* window, int64_t frameNumber);
typedef struct ACameraCaptureSession_captureCallbacks {
/// optional application context.
@@ -433,7 +434,7 @@
*
*/
camera_status_t ACameraCaptureSession_getDevice(
- ACameraCaptureSession* session, /*out*/ACameraDevice** device);
+ ACameraCaptureSession* session, /*out*/ACameraDevice** device) __INTRODUCED_IN(24);
/**
* Submit an array of requests to be captured in sequence as a burst in the minimum of time possible.
@@ -471,7 +472,7 @@
ACameraCaptureSession* session,
/*optional*/ACameraCaptureSession_captureCallbacks* callbacks,
int numRequests, ACaptureRequest** requests,
- /*optional*/int* captureSequenceId);
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(24);
/**
* Request endlessly repeating capture of a sequence of images by this capture session.
@@ -525,7 +526,7 @@
ACameraCaptureSession* session,
/*optional*/ACameraCaptureSession_captureCallbacks* callbacks,
int numRequests, ACaptureRequest** requests,
- /*optional*/int* captureSequenceId);
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(24);
/**
* Cancel any ongoing repeating capture set by {@link ACameraCaptureSession_setRepeatingRequest}.
@@ -548,7 +549,8 @@
* <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error</li>
* <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li></ul>
*/
-camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession* session);
+camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession* session)
+ __INTRODUCED_IN(24);
/**
* Discard all captures currently pending and in-progress as fast as possible.
@@ -588,7 +590,8 @@
* <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error</li>
* <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li></ul>
*/
-camera_status_t ACameraCaptureSession_abortCaptures(ACameraCaptureSession* session);
+camera_status_t ACameraCaptureSession_abortCaptures(ACameraCaptureSession* session)
+ __INTRODUCED_IN(24);
#endif /* __ANDROID_API__ >= 24 */
@@ -637,9 +640,156 @@
* <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li></ul>
*/
camera_status_t ACameraCaptureSession_updateSharedOutput(ACameraCaptureSession* session,
- ACaptureSessionOutput* output);
+ ACaptureSessionOutput* output) __INTRODUCED_IN(28);
#endif /* __ANDROID_API__ >= 28 */
+#if __ANDROID_API__ >= 29
+/**
+ * The definition of final capture result callback with logical multi-camera support.
+ *
+ * This has the same functionality as final ACameraCaptureSession_captureCallback_result, with
+ * added ability to return physical camera result metadata within a logical multi-camera.
+ *
+ * For a logical multi-camera, this function will be called with the Id and result metadata
+ * of the underlying physical cameras, which the corresponding capture request contains targets for.
+ * If the capture request doesn't contain targets specific to any physical camera, or the current
+ * camera device isn't a logical multi-camera, physicalResultCount will be 0.
+ *
+ * @param context The optional application context provided by user in
+ * {@link ACameraCaptureSession_captureCallbacks}.
+ * @param session The camera capture session of interest.
+ * @param request The capture request of interest. Note that this pointer points to a copy of
+ * capture request sent by application, so the address is different to what
+ * application sent but the content will match. This request will be freed by
+ * framework immediately after this callback returns.
+ * @param result The capture result metadata reported by camera device. The memory is managed by
+ * camera framework. Do not access this pointer after this callback returns.
+ * @param physicalResultCount The number of physical camera result metadata
+ * @param physicalCameraIds The array of physical camera IDs on which the
+ * physical result metadata are reported.
+ * @param physicalResults The array of capture result metadata reported by the
+ * physical camera devices.
+ */
+typedef void (*ACameraCaptureSession_logicalCamera_captureCallback_result)(
+ void* context, ACameraCaptureSession* session,
+ ACaptureRequest* request, const ACameraMetadata* result,
+ size_t physicalResultCount, const char** physicalCameraIds,
+ const ACameraMetadata** physicalResults);
+
+/// Struct to describe a logical camera capture failure
+typedef struct ALogicalCameraCaptureFailure {
+ /**
+ * The {@link ACameraCaptureFailure} contains information about regular logical device capture
+ * failure.
+ */
+ struct ACameraCaptureFailure captureFailure;
+
+ /**
+ * The physical camera device ID in case the capture failure comes from a capture request
+ * with configured physical camera streams for a logical camera. physicalCameraId will be set
+ * to NULL in case the capture request has no associated physical camera device.
+ *
+ */
+ const char* physicalCameraId;
+} ALogicalCameraCaptureFailure;
+
+/**
+ * The definition of logical camera capture failure callback.
+ *
+ * @param context The optional application context provided by user in
+ * {@link ACameraCaptureSession_captureCallbacks}.
+ * @param session The camera capture session of interest.
+ * @param request The capture request of interest. Note that this pointer points to a copy of
+ * capture request sent by application, so the address is different to what
+ * application sent but the content will match. This request will be freed by
+ * framework immediately after this callback returns.
+ * @param failure The {@link ALogicalCameraCaptureFailure} desribes the capture failure. The memory
+ * is managed by camera framework. Do not access this pointer after this callback
+ * returns.
+ */
+typedef void (*ACameraCaptureSession_logicalCamera_captureCallback_failed)(
+ void* context, ACameraCaptureSession* session,
+ ACaptureRequest* request, ALogicalCameraCaptureFailure* failure);
+
+/**
+ * This has the same functionality as ACameraCaptureSession_captureCallbacks,
+ * with the exception that an onLogicalCameraCaptureCompleted callback is
+ * used, instead of onCaptureCompleted, to support logical multi-camera.
+ */
+typedef struct ACameraCaptureSession_logicalCamera_captureCallbacks {
+ /**
+ * Same as ACameraCaptureSession_captureCallbacks
+ */
+ void* context;
+ ACameraCaptureSession_captureCallback_start onCaptureStarted;
+ ACameraCaptureSession_captureCallback_result onCaptureProgressed;
+
+ /**
+ * This callback is called when an image capture has fully completed and all the
+ * result metadata is available. For a logical multi-camera, this callback
+ * also returns the result metadata for all physical cameras being
+ * explicitly requested on.
+ *
+ * <p>This callback will always fire after the last {@link onCaptureProgressed};
+ * in other words, no more partial results will be delivered once the completed result
+ * is available.</p>
+ *
+ * <p>For performance-intensive use-cases where latency is a factor, consider
+ * using {@link onCaptureProgressed} instead.</p>
+ *
+ * <p>Note that the ACaptureRequest pointer in the callback will not match what application has
+ * submitted, but the contents the ACaptureRequest will match what application submitted.</p>
+ */
+ ACameraCaptureSession_logicalCamera_captureCallback_result onLogicalCameraCaptureCompleted;
+
+ /**
+ * This callback is called instead of {@link onLogicalCameraCaptureCompleted} when the
+ * camera device failed to produce a capture result for the
+ * request.
+ *
+ * <p>Other requests are unaffected, and some or all image buffers from
+ * the capture may have been pushed to their respective output
+ * streams.</p>
+ *
+ * <p>Note that the ACaptureRequest pointer in the callback will not match what application has
+ * submitted, but the contents the ACaptureRequest will match what application submitted.</p>
+ *
+ * @see ALogicalCameraCaptureFailure
+ */
+ ACameraCaptureSession_logicalCamera_captureCallback_failed onLogicalCameraCaptureFailed;
+
+ /**
+ * Same as ACameraCaptureSession_captureCallbacks
+ */
+ ACameraCaptureSession_captureCallback_sequenceEnd onCaptureSequenceCompleted;
+ ACameraCaptureSession_captureCallback_sequenceAbort onCaptureSequenceAborted;
+ ACameraCaptureSession_captureCallback_bufferLost onCaptureBufferLost;
+} ACameraCaptureSession_logicalCamera_captureCallbacks;
+
+/**
+ * This has the same functionality as ACameraCaptureSession_capture, with added
+ * support for logical multi-camera where the capture callbacks supports result metadata for
+ * physical cameras.
+ */
+camera_status_t ACameraCaptureSession_logicalCamera_capture(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacks* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(29);
+
+/**
+ * This has the same functionality as ACameraCaptureSession_setRepeatingRequest, with added
+ * support for logical multi-camera where the capture callbacks supports result metadata for
+ * physical cameras.
+ */
+camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequest(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacks* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 92dad1c..1537bde 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -34,10 +34,10 @@
*/
#include <sys/cdefs.h>
-#include <android/native_window.h>
#include "NdkCameraError.h"
#include "NdkCaptureRequest.h"
#include "NdkCameraCaptureSession.h"
+#include "NdkCameraWindowType.h"
#ifndef _NDK_CAMERA_DEVICE_H
#define _NDK_CAMERA_DEVICE_H
@@ -53,6 +53,17 @@
*/
typedef struct ACameraDevice ACameraDevice;
+/**
+ * Struct to hold list of camera device Ids. This can refer to either the Ids
+ * of connected camera devices returned from {@link ACameraManager_getCameraIdList},
+ * or the physical camera Ids passed into
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ */
+typedef struct ACameraIdList {
+ int numCameras; ///< Number of camera device Ids
+ const char** cameraIds; ///< list of camera device Ids
+} ACameraIdList;
+
/// Enum for ACameraDevice_ErrorStateCallback error code
enum {
/**
@@ -176,7 +187,7 @@
* <li>{@link ACAMERA_OK} if the method call succeeds.</li>
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if device is NULL.</li></ul>
*/
-camera_status_t ACameraDevice_close(ACameraDevice* device);
+camera_status_t ACameraDevice_close(ACameraDevice* device) __INTRODUCED_IN(24);
/**
* Return the camera id associated with this camera device.
@@ -187,7 +198,7 @@
* delete/free by the application. Also the returned string must not be used after the device
* has been closed.
*/
-const char* ACameraDevice_getId(const ACameraDevice* device);
+const char* ACameraDevice_getId(const ACameraDevice* device) __INTRODUCED_IN(24);
typedef enum {
/**
@@ -290,7 +301,7 @@
*/
camera_status_t ACameraDevice_createCaptureRequest(
const ACameraDevice* device, ACameraDevice_request_template templateId,
- /*out*/ACaptureRequest** request);
+ /*out*/ACaptureRequest** request) __INTRODUCED_IN(24);
typedef struct ACaptureSessionOutputContainer ACaptureSessionOutputContainer;
@@ -313,7 +324,7 @@
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if container is NULL.</li></ul>
*/
camera_status_t ACaptureSessionOutputContainer_create(
- /*out*/ACaptureSessionOutputContainer** container);
+ /*out*/ACaptureSessionOutputContainer** container) __INTRODUCED_IN(24);
/**
* Free a capture session output container.
@@ -322,7 +333,8 @@
*
* @see ACaptureSessionOutputContainer_create
*/
-void ACaptureSessionOutputContainer_free(ACaptureSessionOutputContainer* container);
+void ACaptureSessionOutputContainer_free(ACaptureSessionOutputContainer* container)
+ __INTRODUCED_IN(24);
/**
* Create a ACaptureSessionOutput object.
@@ -344,7 +356,7 @@
* @see ACaptureSessionOutputContainer_add
*/
camera_status_t ACaptureSessionOutput_create(
- ANativeWindow* anw, /*out*/ACaptureSessionOutput** output);
+ ACameraWindowType* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(24);
/**
* Free a ACaptureSessionOutput object.
@@ -353,7 +365,7 @@
*
* @see ACaptureSessionOutput_create
*/
-void ACaptureSessionOutput_free(ACaptureSessionOutput* output);
+void ACaptureSessionOutput_free(ACaptureSessionOutput* output) __INTRODUCED_IN(24);
/**
* Add an {@link ACaptureSessionOutput} object to {@link ACaptureSessionOutputContainer}.
@@ -366,7 +378,8 @@
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if container or output is NULL.</li></ul>
*/
camera_status_t ACaptureSessionOutputContainer_add(
- ACaptureSessionOutputContainer* container, const ACaptureSessionOutput* output);
+ ACaptureSessionOutputContainer* container, const ACaptureSessionOutput* output)
+ __INTRODUCED_IN(24);
/**
* Remove an {@link ACaptureSessionOutput} object from {@link ACaptureSessionOutputContainer}.
@@ -382,7 +395,8 @@
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if container or output is NULL.</li></ul>
*/
camera_status_t ACaptureSessionOutputContainer_remove(
- ACaptureSessionOutputContainer* container, const ACaptureSessionOutput* output);
+ ACaptureSessionOutputContainer* container, const ACaptureSessionOutput* output)
+ __INTRODUCED_IN(24);
/**
* Create a new camera capture session by providing the target output set of {@link ANativeWindow}
@@ -671,7 +685,7 @@
ACameraDevice* device,
const ACaptureSessionOutputContainer* outputs,
const ACameraCaptureSession_stateCallbacks* callbacks,
- /*out*/ACameraCaptureSession** session);
+ /*out*/ACameraCaptureSession** session) __INTRODUCED_IN(24);
#endif /* __ANDROID_API__ >= 24 */
@@ -699,7 +713,7 @@
* @see ACaptureSessionOutputContainer_add
*/
camera_status_t ACaptureSessionSharedOutput_create(
- ANativeWindow* anw, /*out*/ACaptureSessionOutput** output);
+ ACameraWindowType* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(28);
/**
* Add a native window to shared ACaptureSessionOutput.
@@ -716,7 +730,8 @@
* window associated with ACaptureSessionOutput; or anw is already present inside
* ACaptureSessionOutput.</li></ul>
*/
-camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *output, ANativeWindow *anw);
+camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *output,
+ ACameraWindowType *anw) __INTRODUCED_IN(28);
/**
* Remove a native window from shared ACaptureSessionOutput.
@@ -732,7 +747,7 @@
* ACaptureSessionOutput.</li></ul>
*/
camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *output,
- ANativeWindow* anw);
+ ACameraWindowType* anw) __INTRODUCED_IN(28);
/**
* Create a new camera capture session similar to {@link ACameraDevice_createCaptureSession}. This
@@ -765,10 +780,118 @@
const ACaptureSessionOutputContainer* outputs,
const ACaptureRequest* sessionParameters,
const ACameraCaptureSession_stateCallbacks* callbacks,
- /*out*/ACameraCaptureSession** session);
+ /*out*/ACameraCaptureSession** session) __INTRODUCED_IN(28);
#endif /* __ANDROID_API__ >= 28 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Create a ACaptureSessionOutput object used for streaming from a physical
+ * camera as part of a logical camera device.
+ *
+ * <p>The ACaptureSessionOutput is used in {@link ACaptureSessionOutputContainer_add} method to add
+ * an output {@link ANativeWindow} to ACaptureSessionOutputContainer. Use
+ * {@link ACaptureSessionOutput_free} to free the object and its memory after application no longer
+ * needs the {@link ACaptureSessionOutput}.</p>
+ *
+ * @param anw the {@link ANativeWindow} to be associated with the {@link ACaptureSessionOutput}
+ * @param physicalId the Id of the physical camera this output is associated
+ * with.
+ * @param output the output {@link ACaptureSessionOutput} will be stored here if the
+ * method call succeeds.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds. The created container will be
+ * filled in the output argument.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if anw, physicalId or output is NULL.</li></ul>
+ *
+ * @see ACaptureSessionOutputContainer_add
+ */
+camera_status_t ACaptureSessionPhysicalOutput_create(
+ ACameraWindowType* anw, const char* physicalId,
+ /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(29);
+
+/**
+ * Create a logical multi-camera ACaptureRequest for capturing images, initialized with template
+ * for a target use case, with the ability to specify physical camera settings.
+ *
+ * <p>The settings are chosen to be the best options for this camera device,
+ * so it is not recommended to reuse the same request for a different camera device.</p>
+ *
+ * <p>Note that for all keys in physical camera settings, only the keys
+ * advertised in ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS are
+ * applicable. All other keys are ignored by the camera device.</p>
+ *
+ * @param device the camera device of interest
+ * @param templateId the type of capture request to be created.
+ * See {@link ACameraDevice_request_template}.
+ * @param physicalIdList The list of physical camera Ids that can be used to
+ * customize the request for a specific physical camera.
+ * @param request the output request will be stored here if the method call succeeds.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds. The created capture request will be
+ * filled in request argument.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if device, physicalIdList, or request is
+ * NULL, templateId is undefined or camera device does not support
+ * requested template, or if some Ids in physicalIdList isn't a
+ * valid physical camera backing the current camera device.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error.</li>
+ * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
+ *
+ * @see TEMPLATE_PREVIEW
+ * @see TEMPLATE_RECORD
+ * @see TEMPLATE_STILL_CAPTURE
+ * @see TEMPLATE_VIDEO_SNAPSHOT
+ * @see TEMPLATE_MANUAL
+ */
+camera_status_t ACameraDevice_createCaptureRequest_withPhysicalIds(
+ const ACameraDevice* device, ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalIdList,
+ /*out*/ACaptureRequest** request) __INTRODUCED_IN(29);
+
+/**
+ * Check whether a particular {@ACaptureSessionOutputContainer} is supported by
+ * the camera device.
+ *
+ * <p>This method performs a runtime check of a given {@link
+ * ACaptureSessionOutputContainer}. The result confirms whether or not the
+ * passed CaptureSession outputs can be successfully used to create a camera
+ * capture session using {@link ACameraDevice_createCaptureSession}.</p>
+ *
+ * <p>This method can be called at any point before, during and after active
+ * capture session. It must not impact normal camera behavior in any way and
+ * must complete significantly faster than creating a capture session.</p>
+ *
+ * <p>Although this method is faster than creating a new capture session, it is not intended
+ * to be used for exploring the entire space of supported stream combinations.</p>
+ *
+ * @param device the camera device of interest
+ * @param sessionOutputContainer the {@link ACaptureSessionOutputContainer} of
+ * interest.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the given {@link ACaptureSessionOutputContainer}
+ * is supported by the camera device.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if device, or sessionOutputContainer
+ * is NULL.</li>
+ * <li>{@link ACAMERA_ERROR_STREAM_CONFIGURE_FAIL} if the given
+ * {@link ACaptureSessionOutputContainer}
+ * is not supported by
+ * the camera
+ * device.</li>
+ * <li>{@link ACAMERA_ERROR_UNSUPPORTED_OPERATION} if the query operation is not
+ * supported by the camera device.</li>
+ */
+camera_status_t ACameraDevice_isSessionConfigurationSupported(
+ const ACameraDevice* device,
+ const ACaptureSessionOutputContainer* sessionOutputContainer) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif /* _NDK_CAMERA_DEVICE_H */
diff --git a/camera/ndk/include/camera/NdkCameraError.h b/camera/ndk/include/camera/NdkCameraError.h
index 6b58155..fc618ee 100644
--- a/camera/ndk/include/camera/NdkCameraError.h
+++ b/camera/ndk/include/camera/NdkCameraError.h
@@ -106,7 +106,8 @@
/**
* Camera device does not support the stream configuration provided by application in
- * {@link ACameraDevice_createCaptureSession}.
+ * {@link ACameraDevice_createCaptureSession} or {@link
+ * ACameraDevice_isSessionConfigurationSupported}.
*/
ACAMERA_ERROR_STREAM_CONFIGURE_FAIL = ACAMERA_ERROR_BASE - 9,
@@ -130,6 +131,11 @@
* The application does not have permission to open camera.
*/
ACAMERA_ERROR_PERMISSION_DENIED = ACAMERA_ERROR_BASE - 13,
+
+ /**
+ * The operation is not supported by the camera device.
+ */
+ ACAMERA_ERROR_UNSUPPORTED_OPERATION = ACAMERA_ERROR_BASE - 14,
} camera_status_t;
#endif /* __ANDROID_API__ >= 24 */
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index e5b3ad8..2cc8a97 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -65,20 +65,14 @@
* @return a {@link ACameraManager} instance.
*
*/
-ACameraManager* ACameraManager_create();
+ACameraManager* ACameraManager_create() __INTRODUCED_IN(24);
/**
* <p>Delete the {@link ACameraManager} instance and free its resources. </p>
*
* @param manager the {@link ACameraManager} instance to be deleted.
*/
-void ACameraManager_delete(ACameraManager* manager);
-
-/// Struct to hold list of camera devices
-typedef struct ACameraIdList {
- int numCameras; ///< Number of connected camera devices
- const char** cameraIds; ///< list of identifier of connected camera devices
-} ACameraIdList;
+void ACameraManager_delete(ACameraManager* manager) __INTRODUCED_IN(24);
/**
* Create a list of currently connected camera devices, including
@@ -91,6 +85,11 @@
* <p>ACameraManager_getCameraIdList will allocate and return an {@link ACameraIdList}.
* The caller must call {@link ACameraManager_deleteCameraIdList} to free the memory</p>
*
+ * <p>Note: the returned camera list might be a subset to the output of <a href=
+ * "https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList()">
+ * SDK CameraManager#getCameraIdList API</a> as the NDK API does not support some legacy camera
+ * hardware.</p>
+ *
* @param manager the {@link ACameraManager} of interest
* @param cameraIdList the output {@link ACameraIdList} will be filled in here if the method call
* succeeds.
@@ -102,14 +101,14 @@
* <li>{@link ACAMERA_ERROR_NOT_ENOUGH_MEMORY} if allocating memory fails.</li></ul>
*/
camera_status_t ACameraManager_getCameraIdList(ACameraManager* manager,
- /*out*/ACameraIdList** cameraIdList);
+ /*out*/ACameraIdList** cameraIdList) __INTRODUCED_IN(24);
/**
* Delete a list of camera devices allocated via {@link ACameraManager_getCameraIdList}.
*
* @param cameraIdList the {@link ACameraIdList} to be deleted.
*/
-void ACameraManager_deleteCameraIdList(ACameraIdList* cameraIdList);
+void ACameraManager_deleteCameraIdList(ACameraIdList* cameraIdList) __INTRODUCED_IN(24);
/**
* Definition of camera availability callbacks.
@@ -120,7 +119,8 @@
* argument is owned by camera framework and will become invalid immediately after
* this callback returns.
*/
-typedef void (*ACameraManager_AvailabilityCallback)(void* context, const char* cameraId);
+typedef void (*ACameraManager_AvailabilityCallback)(void* context,
+ const char* cameraId);
/**
* A listener for camera devices becoming available or unavailable to open.
@@ -168,7 +168,8 @@
* {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
*/
camera_status_t ACameraManager_registerAvailabilityCallback(
- ACameraManager* manager, const ACameraManager_AvailabilityCallbacks* callback);
+ ACameraManager* manager,
+ const ACameraManager_AvailabilityCallbacks* callback) __INTRODUCED_IN(24);
/**
* Unregister camera availability callbacks.
@@ -185,7 +186,8 @@
* {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
*/
camera_status_t ACameraManager_unregisterAvailabilityCallback(
- ACameraManager* manager, const ACameraManager_AvailabilityCallbacks* callback);
+ ACameraManager* manager,
+ const ACameraManager_AvailabilityCallbacks* callback) __INTRODUCED_IN(24);
/**
* Query the capabilities of a camera device. These capabilities are
@@ -211,7 +213,7 @@
*/
camera_status_t ACameraManager_getCameraCharacteristics(
ACameraManager* manager, const char* cameraId,
- /*out*/ACameraMetadata** characteristics);
+ /*out*/ACameraMetadata** characteristics) __INTRODUCED_IN(24);
/**
* Open a connection to a camera with the given ID. The opened camera device will be
@@ -271,10 +273,126 @@
camera_status_t ACameraManager_openCamera(
ACameraManager* manager, const char* cameraId,
ACameraDevice_StateCallbacks* callback,
- /*out*/ACameraDevice** device);
+ /*out*/ACameraDevice** device) __INTRODUCED_IN(24);
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Definition of camera access permission change callback.
+ *
+ * <p>Notification that camera access priorities have changed and the camera may
+ * now be openable. An application that was previously denied camera access due to
+ * a higher-priority user already using the camera, or that was disconnected from an
+ * active camera session due to a higher-priority user trying to open the camera,
+ * should try to open the camera again if it still wants to use it. Note that
+ * multiple applications may receive this callback at the same time, and only one of
+ * them will succeed in opening the camera in practice, depending on exact access
+ * priority levels and timing. This method is useful in cases where multiple
+ * applications may be in the resumed state at the same time, and the user switches
+ * focus between them, or if the current camera-using application moves between
+ * full-screen and Picture-in-Picture (PiP) states. In such cases, the camera
+ * available/unavailable callbacks will not be invoked, but another application may
+ * now have higher priority for camera access than the current camera-using
+ * application.</p>
+
+ * @param context The optional application context provided by user in
+ * {@link ACameraManager_AvailabilityListener}.
+ */
+typedef void (*ACameraManager_AccessPrioritiesChangedCallback)(void* context);
+
+/**
+ * A listener for camera devices becoming available/unavailable to open or when
+ * the camera access permissions change.
+ *
+ * <p>Cameras become available when they are no longer in use, or when a new
+ * removable camera is connected. They become unavailable when some
+ * application or service starts using a camera, or when a removable camera
+ * is disconnected.</p>
+ *
+ * @see ACameraManager_registerExtendedAvailabilityCallback
+ */
+typedef struct ACameraManager_ExtendedAvailabilityListener {
+ ///
+ ACameraManager_AvailabilityCallbacks availabilityCallbacks;
+
+ /// Called when there is camera access permission change
+ ACameraManager_AccessPrioritiesChangedCallback onCameraAccessPrioritiesChanged;
+
+ /// Reserved for future use, please ensure that all entries are set to NULL
+ void *reserved[6];
+} ACameraManager_ExtendedAvailabilityCallbacks;
+
+/**
+ * Register camera extended availability callbacks.
+ *
+ * <p>onCameraUnavailable will be called whenever a camera device is opened by any camera API
+ * client. Other camera API clients may still be able to open such a camera device, evicting the
+ * existing client if they have higher priority than the existing client of a camera device.
+ * See {@link ACameraManager_openCamera} for more details.</p>
+ *
+ * <p>The callbacks will be called on a dedicated thread shared among all ACameraManager
+ * instances.</p>
+ *
+ * <p>Since this callback will be registered with the camera service, remember to unregister it
+ * once it is no longer needed; otherwise the callback will continue to receive events
+ * indefinitely and it may prevent other resources from being released. Specifically, the
+ * callbacks will be invoked independently of the general activity lifecycle and independently
+ * of the state of individual ACameraManager instances.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be registered.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if manager or callback is NULL, or
+ * {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged}
+ * or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or
+ * {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
+ */
+camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
+ ACameraManager* manager,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+/**
+ * Unregister camera extended availability callbacks.
+ *
+ * <p>Removing a callback that isn't registered has no effect.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be unregistered.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if callback,
+ * {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged}
+ * or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or
+ * {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
+ */
+camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
+ ACameraManager* manager,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+#ifdef __ANDROID_VNDK__
+/**
+ * Retrieve the tag value, given the tag name and camera id.
+ * This method is device specific since some metadata might be defined by device manufacturers
+ * and might only be accessible for specific cameras.
+ * @param manager The {@link ACameraManager} of interest.
+ * @param cameraId The cameraId, which is used to query camera characteristics.
+ * @param name The name of the tag being queried.
+ * @param tag The output tag assigned by this method.
+ *
+ * @return ACAMERA_OK only if the function call was successful.
+ */
+camera_status_t ACameraManager_getTagFromName(ACameraManager *manager, const char* cameraId,
+ const char *name, /*out*/uint32_t *tag)
+ __INTRODUCED_IN(29);
+#endif
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif /* _NDK_CAMERA_MANAGER_H */
diff --git a/camera/ndk/include/camera/NdkCameraMetadata.h b/camera/ndk/include/camera/NdkCameraMetadata.h
index f2aec98..9bbfb83 100644
--- a/camera/ndk/include/camera/NdkCameraMetadata.h
+++ b/camera/ndk/include/camera/NdkCameraMetadata.h
@@ -36,6 +36,7 @@
#ifndef _NDK_CAMERA_METADATA_H
#define _NDK_CAMERA_METADATA_H
+#include <stdint.h>
#include <sys/cdefs.h>
#include "NdkCameraError.h"
@@ -190,7 +191,8 @@
* of input tag value.</li></ul>
*/
camera_status_t ACameraMetadata_getConstEntry(
- const ACameraMetadata* metadata, uint32_t tag, /*out*/ACameraMetadata_const_entry* entry);
+ const ACameraMetadata* metadata,
+ uint32_t tag, /*out*/ACameraMetadata_const_entry* entry) __INTRODUCED_IN(24);
/**
* List all the entry tags in input {@link ACameraMetadata}.
@@ -207,7 +209,8 @@
* <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
*/
camera_status_t ACameraMetadata_getAllTags(
- const ACameraMetadata* metadata, /*out*/int32_t* numEntries, /*out*/const uint32_t** tags);
+ const ACameraMetadata* metadata,
+ /*out*/int32_t* numEntries, /*out*/const uint32_t** tags) __INTRODUCED_IN(24);
/**
* Create a copy of input {@link ACameraMetadata}.
@@ -219,17 +222,39 @@
*
* @return a valid ACameraMetadata pointer or NULL if the input metadata cannot be copied.
*/
-ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src);
+ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src) __INTRODUCED_IN(24);
/**
* Free a {@link ACameraMetadata} structure.
*
* @param metadata the {@link ACameraMetadata} to be freed.
*/
-void ACameraMetadata_free(ACameraMetadata* metadata);
+void ACameraMetadata_free(ACameraMetadata* metadata) __INTRODUCED_IN(24);
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Helper function to check if a camera is logical multi-camera.
+ *
+ * <p> Check whether a camera device is a logical multi-camera based on its
+ * static metadata. If it is, also returns its physical sub camera Ids.</p>
+ *
+ * @param staticMetadata the static metadata of the camera being checked.
+ * @param numPhysicalCameras returns the number of physical cameras.
+ * @param physicalCameraIds returns the array of physical camera Ids backing this logical
+ * camera device. Note that this pointer is only valid
+ * during the lifetime of the staticMetadata object.
+ *
+ * @return true if this is a logical multi-camera, false otherwise.
+ */
+bool ACameraMetadata_isLogicalMultiCamera(const ACameraMetadata* staticMetadata,
+ /*out*/size_t* numPhysicalCameras, /*out*/const char* const** physicalCameraIds)
+ __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif /* _NDK_CAMERA_METADATA_H */
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index bee1a46..8dd6e00 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -71,6 +71,8 @@
ACAMERA_DEPTH,
ACAMERA_LOGICAL_MULTI_CAMERA,
ACAMERA_DISTORTION_CORRECTION,
+ ACAMERA_HEIC,
+ ACAMERA_HEIC_INFO,
ACAMERA_SECTION_COUNT,
ACAMERA_VENDOR = 0x8000
@@ -112,6 +114,8 @@
ACAMERA_DISTORTION_CORRECTION_START
= ACAMERA_DISTORTION_CORRECTION
<< 16,
+ ACAMERA_HEIC_START = ACAMERA_HEIC << 16,
+ ACAMERA_HEIC_INFO_START = ACAMERA_HEIC_INFO << 16,
ACAMERA_VENDOR_START = ACAMERA_VENDOR << 16
} acamera_metadata_section_start_t;
@@ -1912,6 +1916,7 @@
* <li>ACaptureRequest</li>
* </ul></p>
*
+ * <p>This tag is also used for HEIC image capture.</p>
*/
ACAMERA_JPEG_GPS_COORDINATES = // double[3]
ACAMERA_JPEG_START,
@@ -1927,6 +1932,7 @@
* <li>ACaptureRequest</li>
* </ul></p>
*
+ * <p>This tag is also used for HEIC image capture.</p>
*/
ACAMERA_JPEG_GPS_PROCESSING_METHOD = // byte
ACAMERA_JPEG_START + 1,
@@ -1942,6 +1948,7 @@
* <li>ACaptureRequest</li>
* </ul></p>
*
+ * <p>This tag is also used for HEIC image capture.</p>
*/
ACAMERA_JPEG_GPS_TIMESTAMP = // int64
ACAMERA_JPEG_START + 2,
@@ -1986,6 +1993,10 @@
* </code></pre>
* <p>For EXTERNAL cameras the sensor orientation will always be set to 0 and the facing will
* also be set to EXTERNAL. The above code is not relevant in such case.</p>
+ * <p>This tag is also used to describe the orientation of the HEIC image capture, in which
+ * case the rotation is reflected by
+ * <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>, and not by
+ * rotating the image data itself.</p>
*
* @see ACAMERA_SENSOR_ORIENTATION
*/
@@ -2003,7 +2014,8 @@
* <li>ACaptureRequest</li>
* </ul></p>
*
- * <p>85-95 is typical usage range.</p>
+ * <p>85-95 is typical usage range. This tag is also used to describe the quality
+ * of the HEIC image capture.</p>
*/
ACAMERA_JPEG_QUALITY = // byte
ACAMERA_JPEG_START + 4,
@@ -2019,6 +2031,7 @@
* <li>ACaptureRequest</li>
* </ul></p>
*
+ * <p>This tag is also used to describe the quality of the HEIC image capture.</p>
*/
ACAMERA_JPEG_THUMBNAIL_QUALITY = // byte
ACAMERA_JPEG_START + 5,
@@ -2055,6 +2068,10 @@
* orientation is requested. LEGACY device will always report unrotated thumbnail
* size.</li>
* </ul>
+ * <p>The tag is also used as thumbnail size for HEIC image format capture, in which case the
+ * the thumbnail rotation is reflected by
+ * <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>, and not by
+ * rotating the thumbnail data itself.</p>
*
* @see ACAMERA_JPEG_ORIENTATION
*/
@@ -2088,6 +2105,7 @@
* and vice versa.</li>
* <li>All non-<code>(0, 0)</code> sizes will have non-zero widths and heights.</li>
* </ul>
+ * <p>This list is also used as supported thumbnail sizes for HEIC image format capture.</p>
*
* @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
*/
@@ -2783,7 +2801,7 @@
* {@link AIMAGE_FORMAT_RAW12 RAW12}.</li>
* <li>Processed (but not-stalling): any non-RAW format without a stall duration. Typically
* {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888},
- * <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>, or <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>.</li>
+ * <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>, <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>, or {@link AIMAGE_FORMAT_Y8 Y8} .</li>
* </ul>
*
* @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
@@ -3028,6 +3046,28 @@
*/
ACAMERA_REQUEST_AVAILABLE_SESSION_KEYS = // int32[n]
ACAMERA_REQUEST_START + 16,
+ /**
+ * <p>A subset of the available request keys that can be overridden for
+ * physical devices backing a logical multi-camera.</p>
+ *
+ * <p>Type: int32[n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This is a subset of ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS which contains a list
+ * of keys that can be overridden using <a href="https://developer.android.com/reference/CaptureRequest/Builder.html#setPhysicalCameraKey">Builder#setPhysicalCameraKey</a>.
+ * The respective value of such request key can be obtained by calling
+ * <a href="https://developer.android.com/reference/CaptureRequest/Builder.html#getPhysicalCameraKey">Builder#getPhysicalCameraKey</a>. Capture requests that contain
+ * individual physical device requests must be built via
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureRequest(int,">Set)</a>.</p>
+ *
+ * @see ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS
+ */
+ ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS = // int32[n]
+ ACAMERA_REQUEST_START + 17,
ACAMERA_REQUEST_END,
/**
@@ -3257,6 +3297,7 @@
* <li>{@link AIMAGE_FORMAT_YUV_420_888 }</li>
* <li>{@link AIMAGE_FORMAT_RAW10 }</li>
* <li>{@link AIMAGE_FORMAT_RAW12 }</li>
+ * <li>{@link AIMAGE_FORMAT_Y8 }</li>
* </ul>
* <p>All other formats may or may not have an allowed stall duration on
* a per-capability basis; refer to ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
@@ -3294,6 +3335,81 @@
*/
ACAMERA_SCALER_CROPPING_TYPE = // byte (acamera_metadata_enum_android_scaler_cropping_type_t)
ACAMERA_SCALER_START + 13,
+ /**
+ * <p>Recommended stream configurations for common client use cases.</p>
+ *
+ * <p>Type: int32[n*5] (acamera_metadata_enum_android_scaler_available_recommended_stream_configurations_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Optional subset of the ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS that contains
+ * similar tuples listed as
+ * (i.e. width, height, format, output/input stream, usecase bit field).
+ * Camera devices will be able to suggest particular stream configurations which are
+ * power and performance efficient for specific use cases. For more information about
+ * retrieving the suggestions see
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getRecommendedStreamConfigurationMap">CameraCharacteristics#getRecommendedStreamConfigurationMap</a>.</p>
+ * <p>The data representation is int[5], which maps to
+ * (width, height, format, output/input stream, usecase bit field). The array can be
+ * parsed using the following pseudo code:</p>
+ * <p>struct StreamConfiguration {
+ * int32_t format;
+ * int32_t width;
+ * int32_t height;
+ * int32_t isInput; };</p>
+ * <p>void getPreferredStreamConfigurations(
+ * int32_t *array, size_t count, int32_t usecaseId,
+ * Vector < StreamConfiguration > * scs) {
+ * const size_t STREAM_CONFIGURATION_SIZE = 5;
+ * const size_t STREAM_WIDTH_OFFSET = 0;
+ * const size_t STREAM_HEIGHT_OFFSET = 1;
+ * const size_t STREAM_FORMAT_OFFSET = 2;
+ * const size_t STREAM_IS_INPUT_OFFSET = 3;
+ * const size_t STREAM_USECASE_BITMAP_OFFSET = 4;</p>
+ * <pre><code>for (size_t i = 0; i < count; i+= STREAM_CONFIGURATION_SIZE) {
+ * int32_t width = array[i + STREAM_WIDTH_OFFSET];
+ * int32_t height = array[i + STREAM_HEIGHT_OFFSET];
+ * int32_t format = array[i + STREAM_FORMAT_OFFSET];
+ * int32_t isInput = array[i + STREAM_IS_INPUT_OFFSET];
+ * int32_t supportedUsecases = array[i + STREAM_USECASE_BITMAP_OFFSET];
+ * if (supportedUsecases & (1 << usecaseId)) {
+ * StreamConfiguration sc = {format, width, height, isInput};
+ * scs->add(sc);
+ * }
+ * }
+ * </code></pre>
+ * <p>}</p>
+ *
+ * @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS =
+ // int32[n*5] (acamera_metadata_enum_android_scaler_available_recommended_stream_configurations_t)
+ ACAMERA_SCALER_START + 14,
+ /**
+ * <p>Recommended mappings of image formats that are supported by this
+ * camera device for input streams, to their corresponding output formats.</p>
+ *
+ * <p>Type: int32</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This is a recommended subset of the complete list of mappings found in
+ * android.scaler.availableInputOutputFormatsMap. The same requirements apply here as well.
+ * The list however doesn't need to contain all available and supported mappings. Instead of
+ * this developers must list only recommended and efficient entries.
+ * If set, the information will be available in the ZERO_SHUTTER_LAG recommended stream
+ * configuration see
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getRecommendedStreamConfigurationMap">CameraCharacteristics#getRecommendedStreamConfigurationMap</a>.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP =
+ // int32
+ ACAMERA_SCALER_START + 15,
ACAMERA_SCALER_END,
/**
@@ -3454,6 +3570,8 @@
* <p>Some devices may choose to provide a second set of calibration
* information for improved quality, including
* ACAMERA_SENSOR_REFERENCE_ILLUMINANT2 and its corresponding matrices.</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*
* @see ACAMERA_SENSOR_CALIBRATION_TRANSFORM1
* @see ACAMERA_SENSOR_COLOR_TRANSFORM1
@@ -3483,6 +3601,8 @@
* <p>If this key is present, then ACAMERA_SENSOR_COLOR_TRANSFORM2,
* ACAMERA_SENSOR_CALIBRATION_TRANSFORM2, and
* ACAMERA_SENSOR_FORWARD_MATRIX2 will also be present.</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*
* @see ACAMERA_SENSOR_CALIBRATION_TRANSFORM2
* @see ACAMERA_SENSOR_COLOR_TRANSFORM2
@@ -3510,6 +3630,8 @@
* colorspace) into this camera device's native sensor color
* space under the first reference illuminant
* (ACAMERA_SENSOR_REFERENCE_ILLUMINANT1).</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*
* @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
*/
@@ -3537,6 +3659,8 @@
* (ACAMERA_SENSOR_REFERENCE_ILLUMINANT2).</p>
* <p>This matrix will only be present if the second reference
* illuminant is present.</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*
* @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT2
*/
@@ -3565,6 +3689,8 @@
* and the CIE XYZ colorspace when calculating this transform will
* match the standard white point for the first reference illuminant
* (i.e. no chromatic adaptation will be applied by this transform).</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*
* @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
*/
@@ -3595,6 +3721,8 @@
* (i.e. no chromatic adaptation will be applied by this transform).</p>
* <p>This matrix will only be present if the second reference
* illuminant is present.</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*
* @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT2
*/
@@ -3621,6 +3749,8 @@
* this matrix is chosen so that the standard white point for this reference
* illuminant in the reference sensor colorspace is mapped to D50 in the
* CIE XYZ colorspace.</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*
* @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
*/
@@ -3649,6 +3779,8 @@
* CIE XYZ colorspace.</p>
* <p>This matrix will only be present if the second reference
* illuminant is present.</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*
* @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT2
*/
@@ -3681,6 +3813,7 @@
* level values. For raw capture in particular, it is recommended to use
* pixels from ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS to calculate black
* level values for each frame.</p>
+ * <p>For a MONOCHROME camera device, all of the 2x2 channels must have the same values.</p>
*
* @see ACAMERA_SENSOR_DYNAMIC_BLACK_LEVEL
* @see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
@@ -3775,6 +3908,8 @@
* used to interpolate between the provided color transforms when
* processing raw sensor data.</p>
* <p>The order of the values is R, G, B; where R is in the lowest index.</p>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*/
ACAMERA_SENSOR_NEUTRAL_COLOR_POINT = // rational[3]
ACAMERA_SENSOR_START + 18,
@@ -3805,6 +3940,8 @@
* that channel.</p>
* <p>A more detailed description of the noise model can be found in the
* Adobe DNG specification for the NoiseProfile tag.</p>
+ * <p>For a MONOCHROME camera, there is only one color channel. So the noise model coefficients
+ * will only contain one S and one O.</p>
*
* @see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
*/
@@ -3850,6 +3987,8 @@
* <li>R > 1.20 will require strong software correction to produce
* a usuable image (>20% divergence).</li>
* </ul>
+ * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
+ * the camera device has RAW capability.</p>
*/
ACAMERA_SENSOR_GREEN_SPLIT = // float
ACAMERA_SENSOR_START + 22,
@@ -4002,6 +4141,7 @@
* layout key (see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT), i.e. the
* nth value given corresponds to the black level offset for the nth
* color channel listed in the CFA.</p>
+ * <p>For a MONOCHROME camera, all of the 2x2 channels must have the same values.</p>
* <p>This key will be available if ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS is available or the
* camera device advertises this key via {@link ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS }.</p>
*
@@ -4104,7 +4244,8 @@
/**
* <p>The arrangement of color filters on sensor;
* represents the colors in the top-left 2x2 section of
- * the sensor, in reading order.</p>
+ * the sensor, in reading order, for a Bayer camera, or the
+ * light spectrum it captures for MONOCHROME camera.</p>
*
* <p>Type: byte (acamera_metadata_enum_android_sensor_info_color_filter_arrangement_t)</p>
*
@@ -4573,13 +4714,13 @@
* (x,y) ϵ (0 ... N-1, 0 ... M-1) is the value of the shading map at
* pixel ( ((W-1)/(N-1)) * x, ((H-1)/(M-1)) * y) for the four color channels.
* The map is assumed to be bilinearly interpolated between the sample points.</p>
- * <p>The channel order is [R, Geven, Godd, B], where Geven is the green
- * channel for the even rows of a Bayer pattern, and Godd is the odd rows.
+ * <p>For a Bayer camera, the channel order is [R, Geven, Godd, B], where Geven is
+ * the green channel for the even rows of a Bayer pattern, and Godd is the odd rows.
* The shading map is stored in a fully interleaved format, and its size
* is provided in the camera static metadata by ACAMERA_LENS_INFO_SHADING_MAP_SIZE.</p>
* <p>The shading map will generally have on the order of 30-40 rows and columns,
* and will be smaller than 64x64.</p>
- * <p>As an example, given a very small map defined as:</p>
+ * <p>As an example, given a very small map for a Bayer camera defined as:</p>
* <pre><code>ACAMERA_LENS_INFO_SHADING_MAP_SIZE = [ 4, 3 ]
* ACAMERA_STATISTICS_LENS_SHADING_MAP =
* [ 1.3, 1.2, 1.15, 1.2, 1.2, 1.2, 1.15, 1.2,
@@ -4599,6 +4740,17 @@
* image of a gray wall (using bicubic interpolation for visual quality)
* as captured by the sensor gives:</p>
* <p><img alt="Image of a uniform white wall (inverse shading map)" src="../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+ * <p>For a MONOCHROME camera, all of the 2x2 channels must have the same values. An example
+ * shading map for such a camera is defined as:</p>
+ * <pre><code>ACAMERA_LENS_INFO_SHADING_MAP_SIZE = [ 4, 3 ]
+ * ACAMERA_STATISTICS_LENS_SHADING_MAP =
+ * [ 1.3, 1.3, 1.3, 1.3, 1.2, 1.2, 1.2, 1.2,
+ * 1.1, 1.1, 1.1, 1.1, 1.3, 1.3, 1.3, 1.3,
+ * 1.2, 1.2, 1.2, 1.2, 1.1, 1.1, 1.1, 1.1,
+ * 1.0, 1.0, 1.0, 1.0, 1.2, 1.2, 1.2, 1.2,
+ * 1.3, 1.3, 1.3, 1.3, 1.2, 1.2, 1.2, 1.2,
+ * 1.2, 1.2, 1.2, 1.2, 1.3, 1.3, 1.3, 1.3 ]
+ * </code></pre>
* <p>Note that the RAW image data might be subject to lens shading
* correction not reported on this map. Query
* ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED to see if RAW image data has subject
@@ -4942,8 +5094,8 @@
* of points can be less than max (that is, the request doesn't have to
* always provide a curve with number of points equivalent to
* ACAMERA_TONEMAP_MAX_CURVE_POINTS).</p>
- * <p>For devices with MONOCHROME capability, only red channel is used. Green and blue channels
- * are ignored.</p>
+ * <p>For devices with MONOCHROME capability, all three channels must have the same set of
+ * control points.</p>
* <p>A few examples, and their corresponding graphical mappings; these
* only specify the red channel and the precision is limited to 4
* digits, for conciseness.</p>
@@ -5417,9 +5569,121 @@
*/
ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE = // byte (acamera_metadata_enum_android_depth_depth_is_exclusive_t)
ACAMERA_DEPTH_START + 4,
+ /**
+ * <p>Recommended depth stream configurations for common client use cases.</p>
+ *
+ * <p>Type: int32[n*5]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Optional subset of the ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS that
+ * contains similar tuples listed as
+ * (i.e. width, height, format, output/input stream, usecase bit field).
+ * Camera devices will be able to suggest particular depth stream configurations which are
+ * power and performance efficient for specific use cases. For more information about
+ * retrieving the suggestions see
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getRecommendedStreamConfigurationMap">CameraCharacteristics#getRecommendedStreamConfigurationMap</a>.</p>
+ * <p>For data representation please refer to
+ * ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS</p>
+ *
+ * @see ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS
+ * @see ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS
+ */
+ ACAMERA_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS =
+ // int32[n*5]
+ ACAMERA_DEPTH_START + 5,
+ /**
+ * <p>The available dynamic depth dataspace stream
+ * configurations that this camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>These are output stream configurations for use with
+ * dataSpace DYNAMIC_DEPTH. The configurations are
+ * listed as <code>(format, width, height, input?)</code> tuples.</p>
+ * <p>Only devices that support depth output for at least
+ * the HAL_PIXEL_FORMAT_Y16 dense depth map along with
+ * HAL_PIXEL_FORMAT_BLOB with the same size or size with
+ * the same aspect ratio can have dynamic depth dataspace
+ * stream configuration. ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE also
+ * needs to be set to FALSE.</p>
+ *
+ * @see ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE
+ */
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS =
+ // int32[n*4] (acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_t)
+ ACAMERA_DEPTH_START + 6,
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for dynamic depth output streams.</p>
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This should correspond to the frame duration when only that
+ * stream is active, with all processing (typically in android.*.mode)
+ * set to either OFF or FAST.</p>
+ * <p>When multiple streams are used in a request, the minimum frame
+ * duration will be max(individual stream min durations).</p>
+ * <p>The minimum frame duration of a stream (of a particular format, size)
+ * is the same regardless of whether the stream is input or output.</p>
+ */
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS = // int64[4*n]
+ ACAMERA_DEPTH_START + 7,
+ /**
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for dynamic depth streams.</p>
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>A stall duration is how much extra time would get added
+ * to the normal minimum frame duration for a repeating request
+ * that has streams with non-zero stall.</p>
+ * <p>All dynamic depth output streams may have a nonzero stall
+ * duration.</p>
+ */
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS = // int64[4*n]
+ ACAMERA_DEPTH_START + 8,
ACAMERA_DEPTH_END,
/**
+ * <p>String containing the ids of the underlying physical cameras.</p>
+ *
+ * <p>Type: byte[n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>For a logical camera, this is concatenation of all underlying physical camera IDs.
+ * The null terminator for physical camera ID must be preserved so that the whole string
+ * can be tokenized using '\0' to generate list of physical camera IDs.</p>
+ * <p>For example, if the physical camera IDs of the logical camera are "2" and "3", the
+ * value of this tag will be ['2', '\0', '3', '\0'].</p>
+ * <p>The number of physical camera IDs must be no less than 2.</p>
+ */
+ ACAMERA_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS = // byte[n]
+ ACAMERA_LOGICAL_MULTI_CAMERA_START,
+ /**
* <p>The accuracy of frame timestamp synchronization between physical cameras</p>
*
* <p>Type: byte (acamera_metadata_enum_android_logical_multi_camera_sensor_sync_type_t)</p>
@@ -5437,9 +5701,37 @@
* <p>In both cases, all images generated for a particular capture request still carry the same
* timestamps, so that they can be used to look up the matching frame number and
* onCaptureStarted callback.</p>
+ * <p>This tag is only applicable if the logical camera device supports concurrent physical
+ * streams from different physical cameras.</p>
*/
ACAMERA_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE = // byte (acamera_metadata_enum_android_logical_multi_camera_sensor_sync_type_t)
ACAMERA_LOGICAL_MULTI_CAMERA_START + 1,
+ /**
+ * <p>String containing the ID of the underlying active physical camera.</p>
+ *
+ * <p>Type: byte</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+ * </ul></p>
+ *
+ * <p>The ID of the active physical camera that's backing the logical camera. All camera
+ * streams and metadata that are not physical camera specific will be originating from this
+ * physical camera.</p>
+ * <p>For a logical camera made up of physical cameras where each camera's lenses have
+ * different characteristics, the camera device may choose to switch between the physical
+ * cameras when application changes FOCAL_LENGTH or SCALER_CROP_REGION.
+ * At the time of lens switch, this result metadata reflects the new active physical camera
+ * ID.</p>
+ * <p>This key will be available if the camera device advertises this key via {@link ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS }.
+ * When available, this must be one of valid physical IDs backing this logical multi-camera.
+ * If this key is not available for a logical multi-camera, the camera device implementation
+ * may still switch between different active physical cameras based on use case, but the
+ * current active physical camera information won't be available to the application.</p>
+ */
+ ACAMERA_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID = // byte
+ ACAMERA_LOGICAL_MULTI_CAMERA_START + 2,
ACAMERA_LOGICAL_MULTI_CAMERA_END,
/**
@@ -5463,8 +5755,8 @@
* will not slow down capture rate when applying correction. FAST may be the same as OFF if
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
- * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output.</p>
+ * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is
+ * not applied to any RAW output.</p>
* <p>This control will be on by default on devices that support this control. Applications
* disabling distortion correction need to pay extra attention with the coordinate system of
* metering regions, crop region, and face rectangles. When distortion correction is OFF,
@@ -5517,6 +5809,80 @@
ACAMERA_DISTORTION_CORRECTION_START + 1,
ACAMERA_DISTORTION_CORRECTION_END,
+ /**
+ * <p>The available HEIC (ISO/IEC 23008-12) stream
+ * configurations that this camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_heic_available_heic_stream_configurations_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>The configurations are listed as <code>(format, width, height, input?)</code> tuples.</p>
+ * <p>If the camera device supports HEIC image format, it will support identical set of stream
+ * combinations involving HEIC image format, compared to the combinations involving JPEG
+ * image format as required by the device's hardware level and capabilities.</p>
+ * <p>All the static, control, and dynamic metadata tags related to JPEG apply to HEIC formats.
+ * Configuring JPEG and HEIC streams at the same time is not supported.</p>
+ * <p>All the configuration tuples <code>(format, width, height, input?)</code> will contain
+ * AIMAGE_FORMAT_HEIC format as OUTPUT only.</p>
+ */
+ ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS = // int32[n*4] (acamera_metadata_enum_android_heic_available_heic_stream_configurations_t)
+ ACAMERA_HEIC_START,
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for HEIC output formats.</p>
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This should correspond to the frame duration when only that
+ * stream is active, with all processing (typically in android.*.mode)
+ * set to either OFF or FAST.</p>
+ * <p>When multiple streams are used in a request, the minimum frame
+ * duration will be max(individual stream min durations).</p>
+ * <p>See ACAMERA_SENSOR_FRAME_DURATION and
+ * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS for more details about
+ * calculating the max frame rate.</p>
+ *
+ * @see ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS
+ * @see ACAMERA_SENSOR_FRAME_DURATION
+ */
+ ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS = // int64[4*n]
+ ACAMERA_HEIC_START + 1,
+ /**
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for HEIC streams.</p>
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>A stall duration is how much extra time would get added
+ * to the normal minimum frame duration for a repeating request
+ * that has streams with non-zero stall.</p>
+ * <p>This functions similarly to
+ * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS for HEIC
+ * streams.</p>
+ * <p>All HEIC output stream formats may have a nonzero stall
+ * duration.</p>
+ *
+ * @see ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS
+ */
+ ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS = // int64[4*n]
+ ACAMERA_HEIC_START + 2,
+ ACAMERA_HEIC_END,
+
} acamera_metadata_tag_t;
/**
@@ -6333,7 +6699,7 @@
/**
* <p>Optimized for dim settings where the main light source
- * is a flame.</p>
+ * is a candle.</p>
*/
ACAMERA_CONTROL_SCENE_MODE_CANDLELIGHT = 15,
@@ -7011,6 +7377,10 @@
* <p>If this is supported, android.scaler.streamConfigurationMap will
* additionally return a min frame duration that is greater than
* zero for each supported size-format combination.</p>
+ * <p>For camera devices with LOGICAL_MULTI_CAMERA capability, when the underlying active
+ * physical camera switches, exposureTime, sensitivity, and lens properties may change
+ * even if AE/AF is locked. However, the overall auto exposure and auto focus experience
+ * for users will be consistent. Refer to LOGICAL_MULTI_CAMERA capability for details.</p>
*
* @see ACAMERA_BLACK_LEVEL_LOCK
* @see ACAMERA_CONTROL_AE_LOCK
@@ -7066,6 +7436,10 @@
* will accurately report the values applied by AWB in the result.</p>
* <p>A given camera device may also support additional post-processing
* controls, but this capability only covers the above list of controls.</p>
+ * <p>For camera devices with LOGICAL_MULTI_CAMERA capability, when underlying active
+ * physical camera switches, tonemap, white balance, and shading map may change even if
+ * awb is locked. However, the overall post-processing experience for users will be
+ * consistent. Refer to LOGICAL_MULTI_CAMERA capability for details.</p>
*
* @see ACAMERA_COLOR_CORRECTION_ABERRATION_MODE
* @see ACAMERA_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES
@@ -7137,19 +7511,20 @@
/**
* <p>The camera device supports capturing high-resolution images at >= 20 frames per
- * second, in at least the uncompressed YUV format, when post-processing settings are set
- * to FAST. Additionally, maximum-resolution images can be captured at >= 10 frames
- * per second. Here, 'high resolution' means at least 8 megapixels, or the maximum
- * resolution of the device, whichever is smaller.</p>
+ * second, in at least the uncompressed YUV format, when post-processing settings are
+ * set to FAST. Additionally, all image resolutions less than 24 megapixels can be
+ * captured at >= 10 frames per second. Here, 'high resolution' means at least 8
+ * megapixels, or the maximum resolution of the device, whichever is smaller.</p>
* <p>More specifically, this means that at least one output {@link AIMAGE_FORMAT_YUV_420_888 } size listed in
* {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS }
* is larger or equal to the 'high resolution' defined above, and can be captured at at
* least 20 fps. For the largest {@link AIMAGE_FORMAT_YUV_420_888 } size listed in
* {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS },
- * camera device can capture this size for at least 10 frames per second. Also the
- * ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES entry lists at least one FPS range where
- * the minimum FPS is >= 1 / minimumFrameDuration for the largest YUV_420_888 size.</p>
- * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, then those can also be
+ * camera device can capture this size for at least 10 frames per second if the size is
+ * less than 24 megapixels. Also the ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES entry
+ * lists at least one FPS range where the minimum FPS is >= 1 / minimumFrameDuration
+ * for the largest YUV_420_888 size.</p>
+ * <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, {@link AIMAGE_FORMAT_Y8 }, then those can also be
* captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
* <p>In addition, the ACAMERA_SYNC_MAX_LATENCY field is guaranted to have a value between 0
* and 4, inclusive. ACAMERA_CONTROL_AE_LOCK_AVAILABLE and ACAMERA_CONTROL_AWB_LOCK_AVAILABLE
@@ -7183,8 +7558,8 @@
* <li>The ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE entry is listed by this device.</li>
* <li>As of Android P, the ACAMERA_LENS_POSE_REFERENCE entry is listed by this device.</li>
* <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support
- * normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16
- * format.</li>
+ * normal YUV_420_888, Y8, JPEG, and PRIV-format outputs. It only has to support the
+ * DEPTH16 format.</li>
* </ul>
* <p>Generally, depth output operates at a slower frame rate than standard color capture,
* so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
@@ -7215,8 +7590,23 @@
ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10,
/**
- * <p>The camera device is a logical camera backed by two or more physical cameras that are
- * also exposed to the application.</p>
+ * <p>The camera device is a logical camera backed by two or more physical cameras.</p>
+ * <p>In API level 28, the physical cameras must also be exposed to the application via
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList">CameraManager#getCameraIdList</a>.</p>
+ * <p>Starting from API level 29, some or all physical cameras may not be independently
+ * exposed to the application, in which case the physical camera IDs will not be
+ * available in <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList">CameraManager#getCameraIdList</a>. But the
+ * application can still query the physical cameras' characteristics by calling
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraCharacteristics">CameraManager#getCameraCharacteristics</a>. Additionally,
+ * if a physical camera is hidden from camera ID list, the mandatory stream combinations
+ * for that physical camera must be supported through the logical camera using physical
+ * streams.</p>
+ * <p>Combinations of logical and physical streams, or physical streams from different
+ * physical cameras are not guaranteed. However, if the camera device supports
+ * {@link ACameraDevice_isSessionConfigurationSupported },
+ * application must be able to query whether a stream combination involving physical
+ * streams is supported by calling
+ * {@link ACameraDevice_isSessionConfigurationSupported }.</p>
* <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
* camera in the system. For an application that switches between front and back cameras,
* the recommendation is to switch between the first rear camera and the first front
@@ -7239,42 +7629,128 @@
* </li>
* <li>The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be
* the same.</li>
- * <li>The logical camera device must be LIMITED or higher device.</li>
+ * <li>The logical camera must be LIMITED or higher device.</li>
* </ul>
- * <p>Both the logical camera device and its underlying physical devices support the
- * mandatory stream combinations required for their device levels.</p>
- * <p>Additionally, for each guaranteed stream combination, the logical camera supports:</p>
+ * <p>A logical camera device's dynamic metadata may contain
+ * ACAMERA_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID to notify the application of the current
+ * active physical camera Id. An active physical camera is the physical camera from which
+ * the logical camera's main image data outputs (YUV or RAW) and metadata come from.
+ * In addition, this serves as an indication which physical camera is used to output to
+ * a RAW stream, or in case only physical cameras support RAW, which physical RAW stream
+ * the application should request.</p>
+ * <p>Logical camera's static metadata tags below describe the default active physical
+ * camera. An active physical camera is default if it's used when application directly
+ * uses requests built from a template. All templates will default to the same active
+ * physical camera.</p>
* <ul>
- * <li>For each guaranteed stream combination, the logical camera supports replacing one
- * logical {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888}
- * or raw stream with two physical streams of the same size and format, each from a
- * separate physical camera, given that the size and format are supported by both
- * physical cameras.</li>
- * <li>If the logical camera doesn't advertise RAW capability, but the underlying physical
- * cameras do, the logical camera will support guaranteed stream combinations for RAW
- * capability, except that the RAW streams will be physical streams, each from a separate
- * physical camera. This is usually the case when the physical cameras have different
- * sensor sizes.</li>
+ * <li>ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE</li>
+ * <li>ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT</li>
+ * <li>ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE</li>
+ * <li>ACAMERA_SENSOR_INFO_MAX_FRAME_DURATION</li>
+ * <li>ACAMERA_SENSOR_INFO_PHYSICAL_SIZE</li>
+ * <li>ACAMERA_SENSOR_INFO_WHITE_LEVEL</li>
+ * <li>ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED</li>
+ * <li>ACAMERA_SENSOR_REFERENCE_ILLUMINANT1</li>
+ * <li>ACAMERA_SENSOR_REFERENCE_ILLUMINANT2</li>
+ * <li>ACAMERA_SENSOR_CALIBRATION_TRANSFORM1</li>
+ * <li>ACAMERA_SENSOR_CALIBRATION_TRANSFORM2</li>
+ * <li>ACAMERA_SENSOR_COLOR_TRANSFORM1</li>
+ * <li>ACAMERA_SENSOR_COLOR_TRANSFORM2</li>
+ * <li>ACAMERA_SENSOR_FORWARD_MATRIX1</li>
+ * <li>ACAMERA_SENSOR_FORWARD_MATRIX2</li>
+ * <li>ACAMERA_SENSOR_BLACK_LEVEL_PATTERN</li>
+ * <li>ACAMERA_SENSOR_MAX_ANALOG_SENSITIVITY</li>
+ * <li>ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS</li>
+ * <li>ACAMERA_SENSOR_AVAILABLE_TEST_PATTERN_MODES</li>
+ * <li>ACAMERA_LENS_INFO_HYPERFOCAL_DISTANCE</li>
+ * <li>ACAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE</li>
+ * <li>ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION</li>
+ * <li>ACAMERA_LENS_POSE_ROTATION</li>
+ * <li>ACAMERA_LENS_POSE_TRANSLATION</li>
+ * <li>ACAMERA_LENS_INTRINSIC_CALIBRATION</li>
+ * <li>ACAMERA_LENS_POSE_REFERENCE</li>
+ * <li>ACAMERA_LENS_DISTORTION</li>
* </ul>
- * <p>Using physical streams in place of a logical stream of the same size and format will
- * not slow down the frame rate of the capture, as long as the minimum frame duration
- * of the physical and logical streams are the same.</p>
+ * <p>The field of view of all non-RAW physical streams must be the same or as close as
+ * possible to that of non-RAW logical streams. If the requested FOV is outside of the
+ * range supported by the physical camera, the physical stream for that physical camera
+ * will use either the maximum or minimum scaler crop region, depending on which one is
+ * closer to the requested FOV. For example, for a logical camera with wide-tele lens
+ * configuration where the wide lens is the default, if the logical camera's crop region
+ * is set to maximum, the physical stream for the tele lens will be configured to its
+ * maximum crop region. On the other hand, if the logical camera has a normal-wide lens
+ * configuration where the normal lens is the default, when the logical camera's crop
+ * region is set to maximum, the FOV of the logical streams will be that of the normal
+ * lens. The FOV of the physical streams for the wide lens will be the same as the
+ * logical stream, by making the crop region smaller than its active array size to
+ * compensate for the smaller focal length.</p>
+ * <p>Even if the underlying physical cameras have different RAW characteristics (such as
+ * size or CFA pattern), a logical camera can still advertise RAW capability. In this
+ * case, when the application configures a RAW stream, the camera device will make sure
+ * the active physical camera will remain active to ensure consistent RAW output
+ * behavior, and not switch to other physical cameras.</p>
+ * <p>The capture request and result metadata tags required for backward compatible camera
+ * functionalities will be solely based on the logical camera capabiltity. On the other
+ * hand, the use of manual capture controls (sensor or post-processing) with a
+ * logical camera may result in unexpected behavior when the HAL decides to switch
+ * between physical cameras with different characteristics under the hood. For example,
+ * when the application manually sets exposure time and sensitivity while zooming in,
+ * the brightness of the camera images may suddenly change because HAL switches from one
+ * physical camera to the other.</p>
*
* @see ACAMERA_LENS_DISTORTION
+ * @see ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+ * @see ACAMERA_LENS_INFO_HYPERFOCAL_DISTANCE
+ * @see ACAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE
* @see ACAMERA_LENS_INTRINSIC_CALIBRATION
* @see ACAMERA_LENS_POSE_REFERENCE
* @see ACAMERA_LENS_POSE_ROTATION
* @see ACAMERA_LENS_POSE_TRANSLATION
+ * @see ACAMERA_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID
* @see ACAMERA_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
+ * @see ACAMERA_SENSOR_AVAILABLE_TEST_PATTERN_MODES
+ * @see ACAMERA_SENSOR_BLACK_LEVEL_PATTERN
+ * @see ACAMERA_SENSOR_CALIBRATION_TRANSFORM1
+ * @see ACAMERA_SENSOR_CALIBRATION_TRANSFORM2
+ * @see ACAMERA_SENSOR_COLOR_TRANSFORM1
+ * @see ACAMERA_SENSOR_COLOR_TRANSFORM2
+ * @see ACAMERA_SENSOR_FORWARD_MATRIX1
+ * @see ACAMERA_SENSOR_FORWARD_MATRIX2
+ * @see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+ * @see ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE
+ * @see ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED
+ * @see ACAMERA_SENSOR_INFO_MAX_FRAME_DURATION
+ * @see ACAMERA_SENSOR_INFO_PHYSICAL_SIZE
+ * @see ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE
+ * @see ACAMERA_SENSOR_INFO_WHITE_LEVEL
+ * @see ACAMERA_SENSOR_MAX_ANALOG_SENSITIVITY
+ * @see ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS
+ * @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
+ * @see ACAMERA_SENSOR_REFERENCE_ILLUMINANT2
*/
ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11,
/**
* <p>The camera device is a monochrome camera that doesn't contain a color filter array,
- * and the pixel values on U and V planes are all 128.</p>
+ * and for YUV_420_888 stream, the pixel values on U and V planes are all 128.</p>
+ * <p>A MONOCHROME camera must support the guaranteed stream combinations required for
+ * its device level and capabilities. Additionally, if the monochrome camera device
+ * supports Y8 format, all mandatory stream combination requirements related to {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888} apply
+ * to {@link AIMAGE_FORMAT_Y8 Y8} as well. There are no
+ * mandatory stream combination requirements with regard to
+ * {@link AIMAGE_FORMAT_Y8 Y8} for Bayer camera devices.</p>
+ * <p>Starting from Android Q, the SENSOR_INFO_COLOR_FILTER_ARRANGEMENT of a MONOCHROME
+ * camera will be either MONO or NIR.</p>
*/
ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12,
+ /**
+ * <p>The camera device is capable of writing image data into a region of memory
+ * inaccessible to Android userspace or the Android kernel, and only accessible to
+ * trusted execution environments (TEE).</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA = 13,
+
} acamera_metadata_enum_android_request_available_capabilities_t;
@@ -7300,6 +7776,81 @@
} acamera_metadata_enum_android_scaler_cropping_type_t;
+// ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_scaler_available_recommended_stream_configurations {
+ /**
+ * <p>Preview must only include non-stalling processed stream configurations with
+ * output formats like
+ * {@link AIMAGE_FORMAT_YUV_420_888 },
+ * {@link AIMAGE_FORMAT_PRIVATE }, etc.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PREVIEW
+ = 0x0,
+
+ /**
+ * <p>Video record must include stream configurations that match the advertised
+ * supported media profiles <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> with
+ * IMPLEMENTATION_DEFINED format.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RECORD
+ = 0x1,
+
+ /**
+ * <p>Video snapshot must include stream configurations at least as big as
+ * the maximum RECORD resolutions and only with
+ * {@link AIMAGE_FORMAT_JPEG JPEG output format}.
+ * Additionally the configurations shouldn't cause preview glitches and also be able to
+ * run at 30 fps.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VIDEO_SNAPSHOT
+ = 0x2,
+
+ /**
+ * <p>Recommended snapshot stream configurations must include at least one with
+ * size close to ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE and
+ * {@link AIMAGE_FORMAT_JPEG JPEG output format}.
+ * Taking into account restrictions on aspect ratio, alignment etc. the area of the
+ * maximum suggested size shouldn’t be less than 97% of the sensor array size area.</p>
+ *
+ * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_SNAPSHOT
+ = 0x3,
+
+ /**
+ * <p>If supported, recommended input stream configurations must only be advertised with
+ * ZSL along with other processed and/or stalling output formats.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_ZSL = 0x4,
+
+ /**
+ * <p>If supported, recommended raw stream configurations must only include RAW based
+ * output formats.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RAW = 0x5,
+
+ /**
+ * <p>If supported, the recommended low latency stream configurations must have
+ * end-to-end latency that does not exceed 200 ms. under standard operating conditions
+ * (reasonable light levels, not loaded system) and using template
+ * TEMPLATE_STILL_CAPTURE. This is primarily for listing configurations for the
+ * {@link AIMAGE_FORMAT_JPEG JPEG output format}
+ * however other supported output formats can be added as well.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_LOW_LATENCY_SNAPSHOT
+ = 0x6,
+
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END
+ = 0x7,
+
+ /**
+ * <p>Vendor defined use cases. These depend on the vendor implementation.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START
+ = 0x18,
+
+} acamera_metadata_enum_android_scaler_available_recommended_stream_configurations_t;
+
// ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
typedef enum acamera_metadata_enum_acamera_sensor_reference_illuminant1 {
@@ -7476,6 +8027,21 @@
*/
ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB = 4,
+ /**
+ * <p>Sensor doesn't have any Bayer color filter.
+ * Such sensor captures visible light in monochrome. The exact weighting and
+ * wavelengths captured is not specified, but generally only includes the visible
+ * frequencies. This value implies a MONOCHROME camera.</p>
+ */
+ ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO = 5,
+
+ /**
+ * <p>Sensor has a near infrared filter capturing light with wavelength between
+ * roughly 750nm and 1400nm, and the same filter covers the whole sensor array. This
+ * value implies a MONOCHROME camera.</p>
+ */
+ ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR = 6,
+
} acamera_metadata_enum_android_sensor_info_color_filter_arrangement_t;
// ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE
@@ -7764,6 +8330,7 @@
* fire the flash for flash power metering during precapture, and then fire the flash
* for the final capture, if a flash is available on the device and the AE mode is set to
* enable the flash.</p>
+ * <p>Devices that initially shipped with Android version <a href="https://developer.android.com/reference/android/os/Build/VERSION_CODES.html#Q">Q</a> or newer will not include any LEGACY-level devices.</p>
*
* @see ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
* @see ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
@@ -7904,6 +8471,16 @@
} acamera_metadata_enum_android_depth_depth_is_exclusive_t;
+// ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_depth_available_dynamic_depth_stream_configurations {
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_OUTPUT
+ = 0,
+
+ ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_INPUT
+ = 1,
+
+} acamera_metadata_enum_android_depth_available_dynamic_depth_stream_configurations_t;
+
// ACAMERA_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
typedef enum acamera_metadata_enum_acamera_logical_multi_camera_sensor_sync_type {
@@ -7947,6 +8524,16 @@
} acamera_metadata_enum_android_distortion_correction_mode_t;
+// ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_heic_available_heic_stream_configurations {
+ ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT = 0,
+
+ ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_INPUT = 1,
+
+} acamera_metadata_enum_android_heic_available_heic_stream_configurations_t;
+
+
+
#endif /* __ANDROID_API__ >= 24 */
__END_DECLS
diff --git a/camera/ndk/include/camera/NdkCameraWindowType.h b/camera/ndk/include/camera/NdkCameraWindowType.h
new file mode 100644
index 0000000..99f67e9
--- /dev/null
+++ b/camera/ndk/include/camera/NdkCameraWindowType.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDK_CAMERA_WINDOW_TYPE_H
+#define _NDK_CAMERA_WINDOW_TYPE_H
+
+/**
+ * @addtogroup Camera
+ * @{
+ */
+
+/**
+ * @file NdkCameraWindowType.h
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+/**
+ * This file defines the window type used by NDK and the VNDK variants of the
+ * camera2 NDK. This enables us to share the api definition headers and avoid
+ * code duplication (since the VNDK variant doesn't use ANativeWindow unlike the
+ * NDK variant).
+ */
+#ifdef __ANDROID_VNDK__
+#include <cutils/native_handle.h>
+typedef native_handle_t ACameraWindowType;
+#else
+#include <android/native_window.h>
+typedef ANativeWindow ACameraWindowType;
+#endif
+
+#endif //_NDK_CAMERA_WINDOW_TYPE_H
diff --git a/camera/ndk/include/camera/NdkCaptureRequest.h b/camera/ndk/include/camera/NdkCaptureRequest.h
index 4961ce3..d3f8826 100644
--- a/camera/ndk/include/camera/NdkCaptureRequest.h
+++ b/camera/ndk/include/camera/NdkCaptureRequest.h
@@ -35,9 +35,9 @@
#include <sys/cdefs.h>
-#include <android/native_window.h>
#include "NdkCameraError.h"
#include "NdkCameraMetadata.h"
+#include "NdkCameraWindowType.h"
#ifndef _NDK_CAPTURE_REQUEST_H
#define _NDK_CAPTURE_REQUEST_H
@@ -101,7 +101,8 @@
*
* @see ACaptureRequest_addTarget
*/
-camera_status_t ACameraOutputTarget_create(ANativeWindow* window, ACameraOutputTarget** output);
+camera_status_t ACameraOutputTarget_create(ACameraWindowType* window,
+ ACameraOutputTarget** output) __INTRODUCED_IN(24);
/**
* Free a ACameraOutputTarget object.
@@ -110,7 +111,7 @@
*
* @see ACameraOutputTarget_create
*/
-void ACameraOutputTarget_free(ACameraOutputTarget* output);
+void ACameraOutputTarget_free(ACameraOutputTarget* output) __INTRODUCED_IN(24);
/**
* Add an {@link ACameraOutputTarget} object to {@link ACaptureRequest}.
@@ -123,7 +124,7 @@
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or output is NULL.</li></ul>
*/
camera_status_t ACaptureRequest_addTarget(ACaptureRequest* request,
- const ACameraOutputTarget* output);
+ const ACameraOutputTarget* output) __INTRODUCED_IN(24);
/**
* Remove an {@link ACameraOutputTarget} object from {@link ACaptureRequest}.
@@ -138,7 +139,7 @@
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or output is NULL.</li></ul>
*/
camera_status_t ACaptureRequest_removeTarget(ACaptureRequest* request,
- const ACameraOutputTarget* output);
+ const ACameraOutputTarget* output) __INTRODUCED_IN(24);
/**
* Get a metadata entry from input {@link ACaptureRequest}.
@@ -158,7 +159,7 @@
* entry of input tag value.</li></ul>
*/
camera_status_t ACaptureRequest_getConstEntry(
- const ACaptureRequest* request, uint32_t tag, ACameraMetadata_const_entry* entry);
+ const ACaptureRequest* request, uint32_t tag, ACameraMetadata_const_entry* entry) __INTRODUCED_IN(24);
/*
* List all the entry tags in input {@link ACaptureRequest}.
@@ -179,7 +180,7 @@
* <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
*/
camera_status_t ACaptureRequest_getAllTags(
- const ACaptureRequest* request, /*out*/int32_t* numTags, /*out*/const uint32_t** tags);
+ const ACaptureRequest* request, /*out*/int32_t* numTags, /*out*/const uint32_t** tags) __INTRODUCED_IN(24);
/**
* Set/change a camera capture control entry with unsigned 8 bits data type.
@@ -198,7 +199,7 @@
* the tag is not controllable by application.</li></ul>
*/
camera_status_t ACaptureRequest_setEntry_u8(
- ACaptureRequest* request, uint32_t tag, uint32_t count, const uint8_t* data);
+ ACaptureRequest* request, uint32_t tag, uint32_t count, const uint8_t* data) __INTRODUCED_IN(24);
/**
* Set/change a camera capture control entry with signed 32 bits data type.
@@ -217,7 +218,7 @@
* the tag is not controllable by application.</li></ul>
*/
camera_status_t ACaptureRequest_setEntry_i32(
- ACaptureRequest* request, uint32_t tag, uint32_t count, const int32_t* data);
+ ACaptureRequest* request, uint32_t tag, uint32_t count, const int32_t* data) __INTRODUCED_IN(24);
/**
* Set/change a camera capture control entry with float data type.
@@ -236,7 +237,7 @@
* the tag is not controllable by application.</li></ul>
*/
camera_status_t ACaptureRequest_setEntry_float(
- ACaptureRequest* request, uint32_t tag, uint32_t count, const float* data);
+ ACaptureRequest* request, uint32_t tag, uint32_t count, const float* data) __INTRODUCED_IN(24);
/**
* Set/change a camera capture control entry with signed 64 bits data type.
@@ -255,7 +256,7 @@
* the tag is not controllable by application.</li></ul>
*/
camera_status_t ACaptureRequest_setEntry_i64(
- ACaptureRequest* request, uint32_t tag, uint32_t count, const int64_t* data);
+ ACaptureRequest* request, uint32_t tag, uint32_t count, const int64_t* data) __INTRODUCED_IN(24);
/**
* Set/change a camera capture control entry with double data type.
@@ -274,7 +275,7 @@
* the tag is not controllable by application.</li></ul>
*/
camera_status_t ACaptureRequest_setEntry_double(
- ACaptureRequest* request, uint32_t tag, uint32_t count, const double* data);
+ ACaptureRequest* request, uint32_t tag, uint32_t count, const double* data) __INTRODUCED_IN(24);
/**
* Set/change a camera capture control entry with rational data type.
@@ -294,14 +295,14 @@
*/
camera_status_t ACaptureRequest_setEntry_rational(
ACaptureRequest* request, uint32_t tag, uint32_t count,
- const ACameraMetadata_rational* data);
+ const ACameraMetadata_rational* data) __INTRODUCED_IN(24);
/**
* Free a {@link ACaptureRequest} structure.
*
* @param request the {@link ACaptureRequest} to be freed.
*/
-void ACaptureRequest_free(ACaptureRequest* request);
+void ACaptureRequest_free(ACaptureRequest* request) __INTRODUCED_IN(24);
#endif /* __ANDROID_API__ >= 24 */
@@ -325,7 +326,7 @@
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request is NULL.</li></ul>
*/
camera_status_t ACaptureRequest_setUserContext(
- ACaptureRequest* request, void* context);
+ ACaptureRequest* request, void* context) __INTRODUCED_IN(28);
/**
* Get the user context pointer of the {@link ACaptureRequest}
@@ -341,7 +342,7 @@
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request is NULL.</li></ul>
*/
camera_status_t ACaptureRequest_getUserContext(
- const ACaptureRequest* request, /*out*/void** context);
+ const ACaptureRequest* request, /*out*/void** context) __INTRODUCED_IN(28);
/**
* Create a copy of input {@link ACaptureRequest}.
@@ -353,10 +354,223 @@
*
* @return a valid ACaptureRequest pointer or NULL if the input request cannot be copied.
*/
-ACaptureRequest* ACaptureRequest_copy(const ACaptureRequest* src);
+ACaptureRequest* ACaptureRequest_copy(const ACaptureRequest* src) __INTRODUCED_IN(28);
#endif /* __ANDROID_API__ >= 28 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Get a metadata entry from input {@link ACaptureRequest} for
+ * a physical camera backing a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_getConstEntry, except that if the key is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * returns the entry set by ACaptureRequest_setEntry_physicalCamera_* class of
+ * functions on the particular physical camera.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag the capture request metadata tag in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}
+ * that is set by ACaptureRequest_setEntry_physicalCamera_* class of functions.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if metadata, physicalId, or entry is NULL,
+ * physicalId is not one of the Ids used in creating the request, or if the capture
+ * request is a regular request with no physical Ids at all.</li>
+ * <li>{@link ACAMERA_ERROR_METADATA_NOT_FOUND} if the capture request does not contain an
+ * entry of input tag value.</li></ul>
+ */
+camera_status_t ACaptureRequest_getConstEntry_physicalCamera(
+ const ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ ACameraMetadata_const_entry* entry) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with unsigned 8 bits data type for
+ * a physical camera backing a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_u8, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not unsigned 8 bits,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_u8(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const uint8_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with signed 32 bits data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_i32, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not signed 32 bits,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_i32(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const int32_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with float data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_float, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not float,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_float(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const float* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with signed 64 bits data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_i64, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not signed 64 bits,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_i64(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const int64_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with double data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_double, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not double,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_double(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const double* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with rational data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_rational, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not rational,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_rational(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const ACameraMetadata_rational* data) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif /* _NDK_CAPTURE_REQUEST_H */
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index d179aa0..b6f1553 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -2,15 +2,19 @@
global:
ACameraCaptureSession_abortCaptures;
ACameraCaptureSession_capture;
+ ACameraCaptureSession_logicalCamera_capture; # introduced=29
ACameraCaptureSession_close;
ACameraCaptureSession_getDevice;
ACameraCaptureSession_setRepeatingRequest;
+ ACameraCaptureSession_logicalCamera_setRepeatingRequest; # introduced=29
ACameraCaptureSession_stopRepeating;
- ACameraCaptureSession_updateSharedOutput;
+ ACameraCaptureSession_updateSharedOutput; # introduced=28
ACameraDevice_close;
ACameraDevice_createCaptureRequest;
+ ACameraDevice_createCaptureRequest_withPhysicalIds; # introduced=29
ACameraDevice_createCaptureSession;
- ACameraDevice_createCaptureSessionWithSessionParameters;
+ ACameraDevice_createCaptureSessionWithSessionParameters; # introduced=28
+ ACameraDevice_isSessionConfigurationSupported; # introduced=29
ACameraDevice_getId;
ACameraManager_create;
ACameraManager_delete;
@@ -20,34 +24,45 @@
ACameraManager_openCamera;
ACameraManager_registerAvailabilityCallback;
ACameraManager_unregisterAvailabilityCallback;
+ ACameraManager_registerExtendedAvailabilityCallback; # introduced=29
+ ACameraManager_unregisterExtendedAvailabilityCallback; # introduced=29
ACameraMetadata_copy;
ACameraMetadata_free;
ACameraMetadata_getAllTags;
ACameraMetadata_getConstEntry;
+ ACameraMetadata_isLogicalMultiCamera; # introduced=29
ACameraOutputTarget_create;
ACameraOutputTarget_free;
ACaptureRequest_addTarget;
- ACaptureRequest_copy;
+ ACaptureRequest_copy; # introduced=28
ACaptureRequest_free;
ACaptureRequest_getAllTags;
ACaptureRequest_getConstEntry;
- ACaptureRequest_getUserContext;
+ ACaptureRequest_getConstEntry_physicalCamera; # introduced=29
+ ACaptureRequest_getUserContext; # introduced=28
ACaptureRequest_removeTarget;
ACaptureRequest_setEntry_double;
+ ACaptureRequest_setEntry_physicalCamera_double; # introduced=29
ACaptureRequest_setEntry_float;
+ ACaptureRequest_setEntry_physicalCamera_float; # introduced=29
ACaptureRequest_setEntry_i32;
+ ACaptureRequest_setEntry_physicalCamera_i32; # introduced=29
ACaptureRequest_setEntry_i64;
+ ACaptureRequest_setEntry_physicalCamera_i64; # introduced=29
ACaptureRequest_setEntry_rational;
+ ACaptureRequest_setEntry_physicalCamera_rational; # introduced=29
ACaptureRequest_setEntry_u8;
- ACaptureRequest_setUserContext;
+ ACaptureRequest_setEntry_physicalCamera_u8; # introduced=29
+ ACaptureRequest_setUserContext; # introduced=28
ACaptureSessionOutputContainer_add;
ACaptureSessionOutputContainer_create;
ACaptureSessionOutputContainer_free;
ACaptureSessionOutputContainer_remove;
ACaptureSessionOutput_create;
- ACaptureSessionSharedOutput_create;
- ACaptureSessionSharedOutput_add;
- ACaptureSessionSharedOutput_remove;
+ ACaptureSessionSharedOutput_create; # introduced=28
+ ACaptureSessionSharedOutput_add; # introduced=28
+ ACaptureSessionSharedOutput_remove; # introduced=28
+ ACaptureSessionPhysicalOutput_create; # introduced=29
ACaptureSessionOutput_free;
local:
*;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h b/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
new file mode 100644
index 0000000..e1af8c1
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include "utils.h"
+
+struct ACaptureSessionOutput {
+ explicit ACaptureSessionOutput(native_handle_t* window, bool isShared = false,
+ const char* physicalCameraId = "") :
+ mWindow(window), mIsShared(isShared), mPhysicalCameraId(physicalCameraId) {};
+
+ bool operator == (const ACaptureSessionOutput& other) const {
+ return (mWindow == other.mWindow);
+ }
+
+ bool operator != (const ACaptureSessionOutput& other) const {
+ return mWindow != other.mWindow;
+ }
+
+ bool operator < (const ACaptureSessionOutput& other) const {
+ return mWindow < other.mWindow;
+ }
+
+ bool operator > (const ACaptureSessionOutput& other) const {
+ return mWindow > other.mWindow;
+ }
+
+ android::acam::utils::native_handle_ptr_wrapper mWindow;
+ std::set<android::acam::utils::native_handle_ptr_wrapper> mSharedWindows;
+ bool mIsShared;
+ int mRotation = CAMERA3_STREAM_ROTATION_0;
+ std::string mPhysicalCameraId;
+};
+
+
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
new file mode 100644
index 0000000..35c8355
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -0,0 +1,1719 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ACameraDeviceVendor"
+
+#include <vector>
+#include <inttypes.h>
+#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/device/2.0/types.h>
+#include <CameraMetadata.h>
+
+#include "ndk_vendor/impl/ACameraDevice.h"
+#include "ACameraCaptureSession.h"
+#include "ACameraMetadata.h"
+#include "ACaptureRequest.h"
+#include "utils.h"
+
+#include "ACameraCaptureSession.inc"
+
+#define CHECK_TRANSACTION_AND_RET(remoteRet, status, callName) \
+ if (!remoteRet.isOk()) { \
+ ALOGE("%s: Transaction error during %s call %s", __FUNCTION__, callName, \
+ remoteRet.description().c_str()); \
+ return ACAMERA_ERROR_UNKNOWN; \
+ } \
+ if (status != Status::NO_ERROR) { \
+ ALOGE("%s: %s call failed", __FUNCTION__, callName); \
+ return utils::convertFromHidl(status); \
+ }
+
+using namespace android;
+
+ACameraDevice::~ACameraDevice() {
+ mDevice->stopLooper();
+}
+
+namespace android {
+namespace acam {
+
+using HCameraMetadata = frameworks::cameraservice::device::V2_0::CameraMetadata;
+using OutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
+using SessionConfiguration = frameworks::cameraservice::device::V2_0::SessionConfiguration;
+using hardware::Void;
+
+// Static member definitions
+const char* CameraDevice::kContextKey = "Context";
+const char* CameraDevice::kDeviceKey = "Device";
+const char* CameraDevice::kErrorCodeKey = "ErrorCode";
+const char* CameraDevice::kCallbackFpKey = "Callback";
+const char* CameraDevice::kSessionSpKey = "SessionSp";
+const char* CameraDevice::kCaptureRequestKey = "CaptureRequest";
+const char* CameraDevice::kTimeStampKey = "TimeStamp";
+const char* CameraDevice::kCaptureResultKey = "CaptureResult";
+const char* CameraDevice::kPhysicalCaptureResultKey = "PhysicalCaptureResult";
+const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
+const char* CameraDevice::kSequenceIdKey = "SequenceId";
+const char* CameraDevice::kFrameNumberKey = "FrameNumber";
+const char* CameraDevice::kAnwKey = "Anw";
+const char* CameraDevice::kFailingPhysicalCameraId= "FailingPhysicalCameraId";
+
+/**
+ * CameraDevice Implementation
+ */
+CameraDevice::CameraDevice(
+ const char* id,
+ ACameraDevice_StateCallbacks* cb,
+ sp<ACameraMetadata> chars,
+ ACameraDevice* wrapper) :
+ mCameraId(id),
+ mAppCallbacks(*cb),
+ mChars(std::move(chars)),
+ mServiceCallback(new ServiceCallback(this)),
+ mWrapper(wrapper),
+ mInError(false),
+ mError(ACAMERA_OK),
+ mIdle(true),
+ mCurrentSession(nullptr) {
+ mClosing = false;
+ // Setup looper thread to perfrom device callbacks to app
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-dev-looper");
+ status_t err = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ if (err != OK) {
+ ALOGE("%s: Unable to start camera device callback looper: %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ }
+ mHandler = new CallbackHandler(id);
+ mCbLooper->registerHandler(mHandler);
+
+ const CameraMetadata& metadata = mChars->getInternalData();
+ camera_metadata_ro_entry entry = metadata.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+ if (entry.count != 1) {
+ ALOGW("%s: bad count %zu for partial result count", __FUNCTION__, entry.count);
+ mPartialResultCount = 1;
+ } else {
+ mPartialResultCount = entry.data.i32[0];
+ }
+
+ entry = metadata.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+ if (entry.count != 2) {
+ ALOGW("%s: bad count %zu for shading map size", __FUNCTION__, entry.count);
+ mShadingMapSize[0] = 0;
+ mShadingMapSize[1] = 0;
+ } else {
+ mShadingMapSize[0] = entry.data.i32[0];
+ mShadingMapSize[1] = entry.data.i32[1];
+ }
+}
+
+// Device close implementaiton
+CameraDevice::~CameraDevice() {
+ sp<ACameraCaptureSession> session = mCurrentSession.promote();
+ {
+ Mutex::Autolock _l(mDeviceLock);
+ if (!isClosed()) {
+ disconnectLocked(session);
+ }
+ mCurrentSession = nullptr;
+ LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
+ "CameraDevice looper should've been stopped before ~CameraDevice");
+ }
+}
+
+void
+CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
+ msg->post();
+ msg.clear();
+ sp<AMessage> cleanupMsg = new AMessage(kWhatCleanUpSessions, mHandler);
+ cleanupMsg->post();
+}
+
+// TODO: cached created request?
+camera_status_t
+CameraDevice::createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
+ ACaptureRequest** request) const {
+ Mutex::Autolock _l(mDeviceLock);
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+ if (mRemote == nullptr) {
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ CameraMetadata rawRequest;
+ Status status = Status::UNKNOWN_ERROR;
+ auto remoteRet = mRemote->createDefaultRequest(
+ utils::convertToHidl(templateId),
+ [&status, &rawRequest](auto s, const hidl_vec<uint8_t> &metadata) {
+ status = s;
+ if (status == Status::NO_ERROR && utils::convertFromHidlCloned(metadata, &rawRequest)) {
+ } else {
+ ALOGE("%s: Couldn't create default request", __FUNCTION__);
+ }
+ });
+ CHECK_TRANSACTION_AND_RET(remoteRet, status, "createDefaultRequest()")
+ ACaptureRequest* outReq = new ACaptureRequest();
+ outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ if (physicalCameraIdList != nullptr) {
+ for (auto i = 0; i < physicalCameraIdList->numCameras; i++) {
+ outReq->physicalSettings.emplace(physicalCameraIdList->cameraIds[i],
+ new ACameraMetadata(*(outReq->settings)));
+ }
+ }
+ outReq->targets = new ACameraOutputTargets();
+ *request = outReq;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session) {
+ sp<ACameraCaptureSession> currentSession = mCurrentSession.promote();
+ Mutex::Autolock _l(mDeviceLock);
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ if (currentSession != nullptr) {
+ currentSession->closeByDevice();
+ stopRepeatingLocked();
+ }
+
+ // Create new session
+ ret = configureStreamsLocked(outputs, sessionParameters);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Fail to create new session. cannot configure streams");
+ return ret;
+ }
+
+ ACameraCaptureSession* newSession = new ACameraCaptureSession(
+ mNextSessionId++, outputs, callbacks, this);
+
+ // set new session as current session
+ newSession->incStrong((void *) ACameraDevice_createCaptureSession);
+ mCurrentSession = newSession;
+ mFlushing = false;
+ *session = newSession;
+ return ACAMERA_OK;
+}
+
+camera_status_t CameraDevice::isSessionConfigurationSupported(
+ const ACaptureSessionOutputContainer* sessionOutputContainer) const {
+ Mutex::Autolock _l(mDeviceLock);
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ SessionConfiguration sessionConfig;
+ sessionConfig.inputWidth = 0;
+ sessionConfig.inputHeight = 0;
+ sessionConfig.inputFormat = -1;
+ sessionConfig.operationMode = StreamConfigurationMode::NORMAL_MODE;
+ sessionConfig.outputStreams.resize(sessionOutputContainer->mOutputs.size());
+ size_t index = 0;
+ for (const auto& output : sessionOutputContainer->mOutputs) {
+ sessionConfig.outputStreams[index].rotation = utils::convertToHidl(output.mRotation);
+ sessionConfig.outputStreams[index].windowGroupId = -1;
+ sessionConfig.outputStreams[index].windowHandles.resize(output.mSharedWindows.size() + 1);
+ sessionConfig.outputStreams[index].windowHandles[0] = output.mWindow;
+ sessionConfig.outputStreams[index].physicalCameraId = output.mPhysicalCameraId;
+ index++;
+ }
+
+ bool configSupported = false;
+ Status status = Status::UNKNOWN_ERROR;
+ auto remoteRet = mRemote->isSessionConfigurationSupported(sessionConfig,
+ [&status, &configSupported](auto s, auto supported) {
+ status = s;
+ configSupported = supported;
+ });
+
+ CHECK_TRANSACTION_AND_RET(remoteRet, status, "isSessionConfigurationSupported()");
+ return configSupported ? ACAMERA_OK : ACAMERA_ERROR_STREAM_CONFIGURE_FAIL;
+}
+
+static void addMetadataToPhysicalCameraSettings(const CameraMetadata *metadata,
+ const std::string &cameraId, PhysicalCameraSettings *physicalCameraSettings) {
+ CameraMetadata metadataCopy = *metadata;
+ camera_metadata_t *camera_metadata = metadataCopy.release();
+ HCameraMetadata hCameraMetadata;
+ utils::convertToHidl(camera_metadata, &hCameraMetadata, /*shouldOwn*/ true);
+ physicalCameraSettings->settings.metadata(std::move(hCameraMetadata));
+ physicalCameraSettings->id = cameraId;
+}
+
+void CameraDevice::addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest,
+ sp<CaptureRequest> &req) {
+ req->mPhysicalCameraSettings.resize(1 + aCaptureRequest->physicalSettings.size());
+ addMetadataToPhysicalCameraSettings(&(aCaptureRequest->settings->getInternalData()), getId(),
+ &(req->mPhysicalCameraSettings[0]));
+ size_t i = 1;
+ for (auto &physicalSetting : aCaptureRequest->physicalSettings) {
+ addMetadataToPhysicalCameraSettings(&(physicalSetting.second->getInternalData()),
+ physicalSetting.first, &(req->mPhysicalCameraSettings[i]));
+ i++;
+ }
+}
+
+camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ if (output == nullptr) {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!output->mIsShared) {
+ ALOGE("Error output configuration is not shared");
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+
+ int32_t streamId = -1;
+ for (auto& kvPair : mConfiguredOutputs) {
+ if (utils::isWindowNativeHandleEqual(kvPair.second.first, output->mWindow)) {
+ streamId = kvPair.first;
+ break;
+ }
+ }
+ if (streamId < 0) {
+ ALOGE("Error: Invalid output configuration");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ OutputConfigurationWrapper outConfigW;
+ OutputConfiguration &outConfig = outConfigW.mOutputConfiguration;
+ outConfig.rotation = utils::convertToHidl(output->mRotation);
+ outConfig.windowHandles.resize(output->mSharedWindows.size() + 1);
+ outConfig.windowHandles[0] = output->mWindow;
+ outConfig.physicalCameraId = output->mPhysicalCameraId;
+ int i = 1;
+ for (auto& anw : output->mSharedWindows) {
+ outConfig.windowHandles[i++] = anw;
+ }
+
+ auto remoteRet = mRemote->updateOutputConfiguration(streamId, outConfig);
+ if (!remoteRet.isOk()) {
+ ALOGE("%s: Transaction error in updating OutputConfiguration: %s", __FUNCTION__,
+ remoteRet.description().c_str());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ switch (remoteRet) {
+ case Status::NO_ERROR:
+ break;
+ case Status::INVALID_OPERATION:
+ ALOGE("Camera device %s invalid operation", getId());
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ case Status::ALREADY_EXISTS:
+ ALOGE("Camera device %s output surface already exists", getId());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ case Status::ILLEGAL_ARGUMENT:
+ ALOGE("Camera device %s invalid input argument", getId());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ default:
+ ALOGE("Camera device %s failed to add shared output", getId());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ mConfiguredOutputs[streamId] = std::make_pair(output->mWindow, outConfigW);
+
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::allocateCaptureRequestLocked(
+ const ACaptureRequest* request, /*out*/sp<CaptureRequest> &outReq) {
+ sp<CaptureRequest> req(new CaptureRequest());
+ req->mCaptureRequest.physicalCameraSettings.resize(1 + request->physicalSettings.size());
+
+ size_t index = 0;
+ allocateOneCaptureRequestMetadata(
+ req->mCaptureRequest.physicalCameraSettings[index++], mCameraId, request->settings);
+
+ for (auto& physicalEntry : request->physicalSettings) {
+ allocateOneCaptureRequestMetadata(
+ req->mCaptureRequest.physicalCameraSettings[index++],
+ physicalEntry.first, physicalEntry.second);
+ }
+
+ std::vector<int32_t> requestStreamIdxList;
+ std::vector<int32_t> requestSurfaceIdxList;
+ for (auto outputTarget : request->targets->mOutputs) {
+ native_handle_t* anw = outputTarget.mWindow;
+ bool found = false;
+ req->mSurfaceList.push_back(anw);
+ // lookup stream/surface ID
+ for (const auto& kvPair : mConfiguredOutputs) {
+ int streamId = kvPair.first;
+ const OutputConfigurationWrapper& outConfig = kvPair.second.second;
+ const auto& windowHandles = outConfig.mOutputConfiguration.windowHandles;
+ for (int surfaceId = 0; surfaceId < (int) windowHandles.size(); surfaceId++) {
+ // If two native handles are equivalent, so are their surfaces.
+ if (utils::isWindowNativeHandleEqual(windowHandles[surfaceId].getNativeHandle(),
+ anw)) {
+ found = true;
+ requestStreamIdxList.push_back(streamId);
+ requestSurfaceIdxList.push_back(surfaceId);
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("Unconfigured output target %p in capture request!", anw);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+ req->mCaptureRequest.streamAndWindowIds.resize(requestStreamIdxList.size());
+ for (int i = 0; i < requestStreamIdxList.size(); i++) {
+ req->mCaptureRequest.streamAndWindowIds[i].streamId = requestStreamIdxList[i];
+ req->mCaptureRequest.streamAndWindowIds[i].windowId = requestSurfaceIdxList[i];
+ }
+ outReq = req;
+ return ACAMERA_OK;
+}
+
+void CameraDevice::allocateOneCaptureRequestMetadata(
+ PhysicalCameraSettings& cameraSettings,
+ const std::string& id, const sp<ACameraMetadata>& metadata) {
+ cameraSettings.id = id;
+ // TODO: Do we really need to copy the metadata here ?
+ CameraMetadata metadataCopy = metadata->getInternalData();
+ camera_metadata_t *cameraMetadata = metadataCopy.release();
+ HCameraMetadata hCameraMetadata;
+ utils::convertToHidl(cameraMetadata, &hCameraMetadata, true);
+ if (metadata != nullptr) {
+ if (hCameraMetadata.data() != nullptr &&
+ mCaptureRequestMetadataQueue != nullptr &&
+ mCaptureRequestMetadataQueue->write(
+ reinterpret_cast<const uint8_t *>(hCameraMetadata.data()),
+ hCameraMetadata.size())) {
+ // The metadata field of the union would've been destructued, so no need
+ // to re-size it.
+ cameraSettings.settings.fmqMetadataSize(hCameraMetadata.size());
+ } else {
+ ALOGE("Fmq write capture result failed, falling back to hwbinder");
+ cameraSettings.settings.metadata(std::move(hCameraMetadata));
+ }
+ }
+}
+
+
+ACaptureRequest*
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req, const char* deviceId) {
+ ACaptureRequest* pRequest = new ACaptureRequest();
+ for (size_t i = 0; i < req->mPhysicalCameraSettings.size(); i++) {
+ const std::string& id = req->mPhysicalCameraSettings[i].id;
+ CameraMetadata clone;
+ utils::convertFromHidlCloned(req->mPhysicalCameraSettings[i].settings.metadata(), &clone);
+ camera_metadata_t *clonep = clone.release();
+ if (id == deviceId) {
+ pRequest->settings = new ACameraMetadata(clonep, ACameraMetadata::ACM_REQUEST);
+ } else {
+ pRequest->physicalSettings[req->mPhysicalCameraSettings[i].id] =
+ new ACameraMetadata(clonep, ACameraMetadata::ACM_REQUEST);
+ }
+ }
+ pRequest->targets = new ACameraOutputTargets();
+ for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
+ native_handle_t* anw = req->mSurfaceList[i];
+ ACameraOutputTarget outputTarget(anw);
+ pRequest->targets->mOutputs.insert(outputTarget);
+ }
+ return pRequest;
+}
+
+void
+CameraDevice::freeACaptureRequest(ACaptureRequest* req) {
+ if (req == nullptr) {
+ return;
+ }
+ req->settings.clear();
+ delete req->targets;
+ delete req;
+}
+
+void
+CameraDevice::notifySessionEndOfLifeLocked(ACameraCaptureSession* session) {
+ if (isClosed()) {
+ // Device is closing already. do nothing
+ return;
+ }
+
+ if (mCurrentSession != session) {
+ // Session has been replaced by other seesion or device is closed
+ return;
+ }
+ mCurrentSession = nullptr;
+
+ // Should not happen
+ if (!session->mIsClosed) {
+ ALOGE("Error: unclosed session %p reaches end of life!", session);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return;
+ }
+
+ // No new session, unconfigure now
+ camera_status_t ret = configureStreamsLocked(nullptr, nullptr);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Unconfigure stream failed. Device might still be configured! ret %d", ret);
+ }
+}
+
+void
+CameraDevice::disconnectLocked(sp<ACameraCaptureSession>& session) {
+ if (mClosing.exchange(true)) {
+ // Already closing, just return
+ ALOGW("Camera device %s is already closing.", getId());
+ return;
+ }
+
+ if (mRemote != nullptr) {
+ auto ret = mRemote->disconnect();
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error while disconnecting device %s", __FUNCTION__,
+ ret.description().c_str());
+ }
+ }
+ mRemote = nullptr;
+
+ if (session != nullptr) {
+ session->closeByDevice();
+ }
+}
+
+camera_status_t
+CameraDevice::stopRepeatingLocked() {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ int repeatingSequenceId = mRepeatingSequenceId;
+ mRepeatingSequenceId = REQUEST_ID_NONE;
+
+ int64_t lastFrameNumber;
+ Status status = Status::UNKNOWN_ERROR;
+ auto remoteRet = mRemote->cancelRepeatingRequest(
+ [&status, &lastFrameNumber](Status s, auto frameNumber) {
+ status = s;
+ lastFrameNumber = frameNumber;
+ });
+ CHECK_TRANSACTION_AND_RET(remoteRet, status, "cancelRepeatingRequest()");
+ checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
+ }
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::flushLocked(ACameraCaptureSession* session) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s abort captures failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ // This should never happen because creating a new session will close
+ // previous one and thus reject any API call from previous session.
+ // But still good to check here in case something unexpected happen.
+ if (mCurrentSession != session) {
+ ALOGE("Camera %s session %p is not current active session!", getId(), session);
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+
+ if (mFlushing) {
+ ALOGW("Camera %s is already aborting captures", getId());
+ return ACAMERA_OK;
+ }
+
+ mFlushing = true;
+
+ // Send onActive callback to guarantee there is always active->ready transition
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+ postSessionMsgAndCleanup(msg);
+
+ // If device is already idling, send callback and exit early
+ if (mIdle) {
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onReady);
+ postSessionMsgAndCleanup(msg);
+ mFlushing = false;
+ return ACAMERA_OK;
+ }
+
+ int64_t lastFrameNumber;
+ Status status = Status::UNKNOWN_ERROR;
+ auto remoteRet = mRemote->flush([&status, &lastFrameNumber](auto s, auto frameNumber) {
+ status = s;
+ lastFrameNumber = frameNumber;
+ });
+ CHECK_TRANSACTION_AND_RET(remoteRet, status, "flush()")
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ checkRepeatingSequenceCompleteLocked(mRepeatingSequenceId, lastFrameNumber);
+ }
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::waitUntilIdleLocked() {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Wait until camera %s idle failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ ALOGE("Camera device %s won't go to idle when there is repeating request!", getId());
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+
+ auto remoteRet = mRemote->waitUntilIdle();
+ CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "waitUntilIdle()")
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters) {
+ ACaptureSessionOutputContainer emptyOutput;
+ if (outputs == nullptr) {
+ outputs = &emptyOutput;
+ }
+
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ std::set<std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> outputSet;
+ for (auto outConfig : outputs->mOutputs) {
+ native_handle_t* anw = outConfig.mWindow;
+ OutputConfigurationWrapper outConfigInsertW;
+ OutputConfiguration &outConfigInsert = outConfigInsertW.mOutputConfiguration;
+ outConfigInsert.rotation = utils::convertToHidl(outConfig.mRotation);
+ outConfigInsert.windowGroupId = -1;
+ outConfigInsert.windowHandles.resize(outConfig.mSharedWindows.size() + 1);
+ outConfigInsert.windowHandles[0] = anw;
+ outConfigInsert.physicalCameraId = outConfig.mPhysicalCameraId;
+ native_handle_ptr_wrapper wrap(anw);
+ outputSet.insert(std::make_pair(anw, outConfigInsertW));
+ }
+ std::set<std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> addSet = outputSet;
+ std::vector<int32_t> deleteList;
+
+ // Determine which streams need to be created, which to be deleted
+ for (auto& kvPair : mConfiguredOutputs) {
+ int32_t streamId = kvPair.first;
+ auto& outputPair = kvPair.second;
+ if (outputSet.count(outputPair)) {
+ deleteList.push_back(streamId); // Need to delete a no longer needed stream
+ } else {
+ addSet.erase(outputPair); // No need to add already existing stream
+ }
+ }
+
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s stop repeating failed, ret %d", getId(), ret);
+ return ret;
+ }
+
+ ret = waitUntilIdleLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
+ return ret;
+ }
+
+ // Send onReady to previous session
+ // CurrentSession will be updated after configureStreamLocked, so here
+ // mCurrentSession is the session to be replaced by a new session
+ if (!mIdle && mCurrentSession != nullptr) {
+ if (mBusySession != mCurrentSession) {
+ ALOGE("Current session != busy session");
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, mBusySession->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, mBusySession);
+ msg->setPointer(kCallbackFpKey, (void*) mBusySession->mUserSessionCallback.onReady);
+ mBusySession.clear();
+ postSessionMsgAndCleanup(msg);
+ }
+ mIdle = true;
+
+ auto remoteRet = mRemote->beginConfigure();
+ CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "beginConfigure()")
+
+ // delete to-be-deleted streams
+ for (auto streamId : deleteList) {
+ remoteRet = mRemote->deleteStream(streamId);
+ CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "deleteStream()")
+ mConfiguredOutputs.erase(streamId);
+ }
+
+ // add new streams
+ for (auto outputPair : addSet) {
+ int streamId;
+ Status status = Status::UNKNOWN_ERROR;
+ auto ret = mRemote->createStream(outputPair.second,
+ [&status, &streamId](Status s, auto stream_id) {
+ status = s;
+ streamId = stream_id;
+ });
+ CHECK_TRANSACTION_AND_RET(ret, status, "createStream()")
+ mConfiguredOutputs.insert(std::make_pair(streamId, outputPair));
+ }
+
+ CameraMetadata params;
+ HCameraMetadata hidlParams;
+ if ((sessionParameters != nullptr) && (sessionParameters->settings != nullptr)) {
+ params.append(sessionParameters->settings->getInternalData());
+ const camera_metadata_t *params_metadata = params.getAndLock();
+ utils::convertToHidl(params_metadata, &hidlParams);
+ params.unlock(params_metadata);
+ }
+ remoteRet = mRemote->endConfigure(StreamConfigurationMode::NORMAL_MODE, hidlParams);
+ CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "endConfigure()")
+ return ACAMERA_OK;
+}
+
+void
+CameraDevice::setRemoteDevice(sp<ICameraDeviceUser> remote) {
+ Mutex::Autolock _l(mDeviceLock);
+ mRemote = remote;
+}
+
+bool
+CameraDevice::setDeviceMetadataQueues() {
+ if (mRemote == nullptr) {
+ ALOGE("mRemote must not be null while trying to fetch metadata queues");
+ return false;
+ }
+ std::shared_ptr<RequestMetadataQueue> &reqQueue = mCaptureRequestMetadataQueue;
+ auto ret =
+ mRemote->getCaptureRequestMetadataQueue(
+ [&reqQueue](const auto &mqDescriptor) {
+ reqQueue = std::make_shared<RequestMetadataQueue>(mqDescriptor);
+ if (!reqQueue->isValid() || reqQueue->availableToWrite() <=0) {
+ ALOGE("Empty fmq from cameraserver");
+ reqQueue = nullptr;
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("Transaction error trying to get capture request metadata queue");
+ return false;
+ }
+ std::shared_ptr<ResultMetadataQueue> &resQueue = mCaptureResultMetadataQueue;
+ ret =
+ mRemote->getCaptureResultMetadataQueue(
+ [&resQueue](const auto &mqDescriptor) {
+ resQueue = std::make_shared<ResultMetadataQueue>(mqDescriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <=0) {
+ ALOGE("Empty fmq from cameraserver");
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("Transaction error trying to get capture result metadata queue");
+ return false;
+ }
+ return true;
+}
+
+camera_status_t
+CameraDevice::checkCameraClosedOrErrorLocked() const {
+ if (mRemote == nullptr) {
+ ALOGE("%s: camera device already closed", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ if (mInError) {// triggered by onDeviceError
+ ALOGE("%s: camera device has encountered a serious error", __FUNCTION__);
+ return mError;
+ }
+ return ACAMERA_OK;
+}
+
+void
+CameraDevice::setCameraDeviceErrorLocked(camera_status_t error) {
+ mInError = true;
+ mError = error;
+ return;
+}
+
+void
+CameraDevice::FrameNumberTracker::updateTracker(int64_t frameNumber, bool isError) {
+ ALOGV("updateTracker frame %" PRId64 " isError %d", frameNumber, isError);
+ if (isError) {
+ mFutureErrorSet.insert(frameNumber);
+ } else if (frameNumber <= mCompletedFrameNumber) {
+ ALOGE("Frame number %" PRId64 " decreased! current fn %" PRId64,
+ frameNumber, mCompletedFrameNumber);
+ return;
+ } else {
+ if (frameNumber != mCompletedFrameNumber + 1) {
+ ALOGE("Frame number out of order. Expect %" PRId64 " but get %" PRId64,
+ mCompletedFrameNumber + 1, frameNumber);
+ // Do not assert as in java implementation
+ }
+ mCompletedFrameNumber = frameNumber;
+ }
+ update();
+}
+
+void
+CameraDevice::FrameNumberTracker::update() {
+ for (auto it = mFutureErrorSet.begin(); it != mFutureErrorSet.end();) {
+ int64_t errorFrameNumber = *it;
+ if (errorFrameNumber == mCompletedFrameNumber + 1) {
+ mCompletedFrameNumber++;
+ it = mFutureErrorSet.erase(it);
+ } else if (errorFrameNumber <= mCompletedFrameNumber) {
+ // This should not happen, but deal with it anyway
+ ALOGE("Completd frame number passed through current frame number!");
+ // erase the old error since it's no longer useful
+ it = mFutureErrorSet.erase(it);
+ } else {
+ // Normal requests hasn't catched up error frames, just break
+ break;
+ }
+ }
+ ALOGV("Update complete frame %" PRId64, mCompletedFrameNumber);
+}
+
+void
+CameraDevice::onCaptureErrorLocked(
+ ErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ int sequenceId = resultExtras.requestId;
+ int64_t frameNumber = resultExtras.frameNumber;
+ int32_t burstId = resultExtras.burstId;
+ auto it = mSequenceCallbackMap.find(sequenceId);
+ if (it == mSequenceCallbackMap.end()) {
+ ALOGE("%s: Error: capture sequence index %d not found!",
+ __FUNCTION__, sequenceId);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ return;
+ }
+
+ CallbackHolder cbh = (*it).second;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ return;
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+
+ // Handle buffer error
+ if (errorCode == ErrorCode::CAMERA_BUFFER) {
+ int32_t streamId = resultExtras.errorStreamId;
+ ACameraCaptureSession_captureCallback_bufferLost onBufferLost =
+ cbh.mOnCaptureBufferLost;
+ auto outputPairIt = mConfiguredOutputs.find(streamId);
+ if (outputPairIt == mConfiguredOutputs.end()) {
+ ALOGE("%s: Error: stream id %d does not exist", __FUNCTION__, streamId);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ return;
+ }
+
+ const auto& windowHandles = outputPairIt->second.second.mOutputConfiguration.windowHandles;
+ for (const auto& outHandle : windowHandles) {
+ for (auto streamAndWindowId : request->mCaptureRequest.streamAndWindowIds) {
+ int32_t windowId = streamAndWindowId.windowId;
+ if (utils::isWindowNativeHandleEqual(windowHandles[windowId],outHandle)) {
+ native_handle_t* anw =
+ const_cast<native_handle_t *>(windowHandles[windowId].getNativeHandle());
+ ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
+ getId(), anw, frameNumber);
+
+ sp<AMessage> msg = new AMessage(kWhatCaptureBufferLost, mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onBufferLost);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setPointer(kAnwKey, (void*) anw);
+ msg->setInt64(kFrameNumberKey, frameNumber);
+ postSessionMsgAndCleanup(msg);
+ }
+ }
+ }
+ } else { // Handle other capture failures
+ // Fire capture failure callback if there is one registered
+ ACameraCaptureSession_captureCallback_failed onError = cbh.mOnCaptureFailed;
+ sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
+ failure->frameNumber = frameNumber;
+ // TODO: refine this when implementing flush
+ failure->reason = CAPTURE_FAILURE_REASON_ERROR;
+ failure->sequenceId = sequenceId;
+ failure->wasImageCaptured = (errorCode == ErrorCode::CAMERA_RESULT);
+
+ sp<AMessage> msg = new AMessage(cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureFail :
+ kWhatCaptureFail, mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
+ msg->setObject(kSessionSpKey, session);
+ if (cbh.mIsLogicalCameraCallback) {
+ if (resultExtras.errorPhysicalCameraId.size() > 0) {
+ msg->setString(kFailingPhysicalCameraId, resultExtras.errorPhysicalCameraId.c_str(),
+ resultExtras.errorPhysicalCameraId.size());
+ }
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mOnLogicalCameraCaptureFailed);
+ } else {
+ msg->setPointer(kCallbackFpKey, (void*) onError);
+ }
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setObject(kCaptureFailureKey, failure);
+ postSessionMsgAndCleanup(msg);
+
+ // Update tracker
+ mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
+ checkAndFireSequenceCompleteLocked();
+ }
+ return;
+}
+
+CameraDevice::CallbackHandler::CallbackHandler(const char *id) : mId(id) { }
+
+void CameraDevice::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ case kWhatOnError:
+ case kWhatSessionStateCb:
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatLogicalCaptureResult:
+ case kWhatCaptureFail:
+ case kWhatLogicalCaptureFail:
+ case kWhatCaptureSeqEnd:
+ case kWhatCaptureSeqAbort:
+ case kWhatCaptureBufferLost:
+ ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
+ break;
+ case kWhatCleanUpSessions:
+ mCachedSessions.clear();
+ return;
+ default:
+ ALOGE("%s:Error: unknown device callback %d", __FUNCTION__, msg->what());
+ return;
+ }
+ // Check the common part of all message
+ void* context;
+ bool found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ {
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found || dev == nullptr) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice_StateCallback onDisconnected;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onDisconnected);
+ if (!found) {
+ ALOGE("%s: Cannot find onDisconnected!", __FUNCTION__);
+ return;
+ }
+ if (onDisconnected == nullptr) {
+ return;
+ }
+ (*onDisconnected)(context, dev);
+ break;
+ }
+ case kWhatOnError:
+ {
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found || dev == nullptr) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice_ErrorStateCallback onError;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onError);
+ if (!found) {
+ ALOGE("%s: Cannot find onError!", __FUNCTION__);
+ return;
+ }
+ int errorCode;
+ found = msg->findInt32(kErrorCodeKey, &errorCode);
+ if (!found) {
+ ALOGE("%s: Cannot find error code!", __FUNCTION__);
+ return;
+ }
+ if (onError == nullptr) {
+ return;
+ }
+ (*onError)(context, dev, errorCode);
+ break;
+ }
+ case kWhatSessionStateCb:
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatLogicalCaptureResult:
+ case kWhatCaptureFail:
+ case kWhatLogicalCaptureFail:
+ case kWhatCaptureSeqEnd:
+ case kWhatCaptureSeqAbort:
+ case kWhatCaptureBufferLost:
+ {
+ sp<RefBase> obj;
+ found = msg->findObject(kSessionSpKey, &obj);
+ if (!found || obj == nullptr) {
+ ALOGE("%s: Cannot find session pointer!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
+ mCachedSessions.push(session);
+ sp<CaptureRequest> requestSp = nullptr;
+ const char *id_cstr = mId.c_str();
+ switch (msg->what()) {
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatLogicalCaptureResult:
+ case kWhatCaptureFail:
+ case kWhatLogicalCaptureFail:
+ case kWhatCaptureBufferLost:
+ found = msg->findObject(kCaptureRequestKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture request!", __FUNCTION__);
+ return;
+ }
+ requestSp = static_cast<CaptureRequest*>(obj.get());
+ break;
+ }
+
+ switch (msg->what()) {
+ case kWhatSessionStateCb:
+ {
+ ACameraCaptureSession_stateCallback onState;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onState);
+ if (!found) {
+ ALOGE("%s: Cannot find state callback!", __FUNCTION__);
+ return;
+ }
+ if (onState == nullptr) {
+ return;
+ }
+ (*onState)(context, session.get());
+ break;
+ }
+ case kWhatCaptureStart:
+ {
+ ACameraCaptureSession_captureCallback_start onStart;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onStart);
+ if (!found) {
+ ALOGE("%s: Cannot find capture start callback!", __FUNCTION__);
+ return;
+ }
+ if (onStart == nullptr) {
+ return;
+ }
+ int64_t timestamp;
+ found = msg->findInt64(kTimeStampKey, ×tamp);
+ if (!found) {
+ ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
+ return;
+ }
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
+ (*onStart)(context, session.get(), request, timestamp);
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatCaptureResult:
+ {
+ ACameraCaptureSession_captureCallback_result onResult;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result callback!", __FUNCTION__);
+ return;
+ }
+ if (onResult == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureResultKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
+ (*onResult)(context, session.get(), request, result.get());
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatLogicalCaptureResult:
+ {
+ ACameraCaptureSession_logicalCamera_captureCallback_result onResult;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result callback!", __FUNCTION__);
+ return;
+ }
+ if (onResult == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureResultKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
+
+ found = msg->findObject(kPhysicalCaptureResultKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find physical capture result!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraPhysicalCaptureResultInfo> physicalResult(
+ static_cast<ACameraPhysicalCaptureResultInfo*>(obj.get()));
+ std::vector<PhysicalCaptureResultInfoLocal>& physicalResultInfo =
+ physicalResult->mPhysicalResultInfo;
+
+ std::vector<std::string> physicalCameraIds;
+ std::vector<sp<ACameraMetadata>> physicalMetadataCopy;
+ for (size_t i = 0; i < physicalResultInfo.size(); i++) {
+ physicalCameraIds.push_back(physicalResultInfo[i].physicalCameraId);
+
+ CameraMetadata clone = physicalResultInfo[i].physicalMetadata;
+ clone.update(ANDROID_SYNC_FRAME_NUMBER,
+ &physicalResult->mFrameNumber, /*data_count*/1);
+ sp<ACameraMetadata> metadata =
+ new ACameraMetadata(clone.release(), ACameraMetadata::ACM_RESULT);
+ physicalMetadataCopy.push_back(metadata);
+ }
+ std::vector<const char*> physicalCameraIdPtrs;
+ std::vector<const ACameraMetadata*> physicalMetadataCopyPtrs;
+ for (size_t i = 0; i < physicalResultInfo.size(); i++) {
+ physicalCameraIdPtrs.push_back(physicalCameraIds[i].c_str());
+ physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
+ }
+
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
+ (*onResult)(context, session.get(), request, result.get(),
+ physicalResultInfo.size(), physicalCameraIdPtrs.data(),
+ physicalMetadataCopyPtrs.data());
+ freeACaptureRequest(request);
+ break;
+ }
+
+ case kWhatCaptureFail:
+ {
+ ACameraCaptureSession_captureCallback_failed onFail;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onFail);
+ if (!found) {
+ ALOGE("%s: Cannot find capture fail callback!", __FUNCTION__);
+ return;
+ }
+ if (onFail == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureFailureKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture failure!", __FUNCTION__);
+ return;
+ }
+ sp<CameraCaptureFailure> failureSp(
+ static_cast<CameraCaptureFailure*>(obj.get()));
+ ACameraCaptureFailure* failure =
+ static_cast<ACameraCaptureFailure*>(failureSp.get());
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
+ (*onFail)(context, session.get(), request, failure);
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatLogicalCaptureFail:
+ {
+ ACameraCaptureSession_logicalCamera_captureCallback_failed onFail;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onFail);
+ if (!found) {
+ ALOGE("%s: Cannot find capture fail callback!", __FUNCTION__);
+ return;
+ }
+ if (onFail == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureFailureKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture failure!", __FUNCTION__);
+ return;
+ }
+ sp<CameraCaptureFailure> failureSp(
+ static_cast<CameraCaptureFailure*>(obj.get()));
+ ALogicalCameraCaptureFailure failure;
+ AString physicalCameraId;
+ found = msg->findString(kFailingPhysicalCameraId, &physicalCameraId);
+ if (found && !physicalCameraId.empty()) {
+ failure.physicalCameraId = physicalCameraId.c_str();
+ } else {
+ failure.physicalCameraId = nullptr;
+ }
+ failure.captureFailure = *failureSp;
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
+ (*onFail)(context, session.get(), request, &failure);
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatCaptureSeqEnd:
+ {
+ ACameraCaptureSession_captureCallback_sequenceEnd onSeqEnd;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onSeqEnd);
+ if (!found) {
+ ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
+ return;
+ }
+ if (onSeqEnd == nullptr) {
+ return;
+ }
+ int seqId;
+ found = msg->findInt32(kSequenceIdKey, &seqId);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ (*onSeqEnd)(context, session.get(), seqId, frameNumber);
+ break;
+ }
+ case kWhatCaptureSeqAbort:
+ {
+ ACameraCaptureSession_captureCallback_sequenceAbort onSeqAbort;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onSeqAbort);
+ if (!found) {
+ ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
+ return;
+ }
+ if (onSeqAbort == nullptr) {
+ return;
+ }
+ int seqId;
+ found = msg->findInt32(kSequenceIdKey, &seqId);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ (*onSeqAbort)(context, session.get(), seqId);
+ break;
+ }
+ case kWhatCaptureBufferLost:
+ {
+ ACameraCaptureSession_captureCallback_bufferLost onBufferLost;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onBufferLost);
+ if (!found) {
+ ALOGE("%s: Cannot find buffer lost callback!", __FUNCTION__);
+ return;
+ }
+ if (onBufferLost == nullptr) {
+ return;
+ }
+
+ native_handle_t* anw;
+ found = msg->findPointer(kAnwKey, (void**) &anw);
+ if (!found) {
+ ALOGE("%s: Cannot find native_handle_t!", __FUNCTION__);
+ return;
+ }
+
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
+ (*onBufferLost)(context, session.get(), request, anw, frameNumber);
+ freeACaptureRequest(request);
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacks* cbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIsLogicalCameraCallback(false) {
+ initCaptureCallbacks(cbs);
+
+ if (cbs != nullptr) {
+ mOnCaptureCompleted = cbs->onCaptureCompleted;
+ mOnCaptureFailed = cbs->onCaptureFailed;
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIsLogicalCameraCallback(true) {
+ initCaptureCallbacks(lcbs);
+
+ if (lcbs != nullptr) {
+ mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
+ mOnLogicalCameraCaptureFailed = lcbs->onLogicalCameraCaptureFailed;
+ }
+}
+
+void
+CameraDevice::checkRepeatingSequenceCompleteLocked(
+ const int sequenceId, const int64_t lastFrameNumber) {
+ ALOGV("Repeating seqId %d lastFrameNumer %" PRId64, sequenceId, lastFrameNumber);
+ if (lastFrameNumber == NO_FRAMES_CAPTURED) {
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ return;
+ }
+ // remove callback holder from callback map
+ auto cbIt = mSequenceCallbackMap.find(sequenceId);
+ CallbackHolder cbh = cbIt->second;
+ mSequenceCallbackMap.erase(cbIt);
+ // send seq aborted callback
+ sp<AMessage> msg = new AMessage(kWhatCaptureSeqAbort, mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
+ msg->setObject(kSessionSpKey, cbh.mSession);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceAborted);
+ msg->setInt32(kSequenceIdKey, sequenceId);
+ postSessionMsgAndCleanup(msg);
+ } else {
+ // Use mSequenceLastFrameNumberMap to track
+ mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+
+ // Last frame might have arrived. Check now
+ checkAndFireSequenceCompleteLocked();
+ }
+}
+
+void
+CameraDevice::checkAndFireSequenceCompleteLocked() {
+ int64_t completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
+ auto it = mSequenceLastFrameNumberMap.begin();
+ while (it != mSequenceLastFrameNumberMap.end()) {
+ int sequenceId = it->first;
+ int64_t lastFrameNumber = it->second;
+ bool seqCompleted = false;
+ bool hasCallback = true;
+
+ if (mRemote == nullptr) {
+ ALOGW("Camera %s closed while checking sequence complete", getId());
+ return;
+ }
+
+ // Check if there is callback for this sequence
+ // This should not happen because we always register callback (with nullptr inside)
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ hasCallback = false;
+ }
+
+ if (lastFrameNumber <= completedFrameNumber) {
+ ALOGV("seq %d reached last frame %" PRId64 ", completed %" PRId64,
+ sequenceId, lastFrameNumber, completedFrameNumber);
+ seqCompleted = true;
+ }
+
+ if (seqCompleted && hasCallback) {
+ // remove callback holder from callback map
+ auto cbIt = mSequenceCallbackMap.find(sequenceId);
+ CallbackHolder cbh = cbIt->second;
+ mSequenceCallbackMap.erase(cbIt);
+ // send seq complete callback
+ sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
+ msg->setObject(kSessionSpKey, cbh.mSession);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
+ msg->setInt32(kSequenceIdKey, sequenceId);
+ msg->setInt64(kFrameNumberKey, lastFrameNumber);
+
+ // Clear the session sp before we send out the message
+ // This will guarantee the rare case where the message is processed
+ // before cbh goes out of scope and causing we call the session
+ // destructor while holding device lock
+ cbh.mSession.clear();
+ postSessionMsgAndCleanup(msg);
+ }
+
+ // No need to track sequence complete if there is no callback registered
+ if (seqCompleted || !hasCallback) {
+ it = mSequenceLastFrameNumberMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void CameraDevice::stopLooper() {
+ Mutex::Autolock _l(mDeviceLock);
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+}
+
+/**
+ * Camera service callback implementation
+ */
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onDeviceError(
+ ErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ ALOGD("Device error received, code %d, frame number %" PRId64 ", request ID %d, subseq ID %d"
+ " physical camera ID %s", errorCode, resultExtras.frameNumber, resultExtras.requestId,
+ resultExtras.burstId, resultExtras.errorPhysicalCameraId.c_str());
+ auto ret = Void();
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+
+ sp<ACameraCaptureSession> session = dev->mCurrentSession.promote();
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return ret; // device has been closed
+ }
+ switch (errorCode) {
+ case ErrorCode::CAMERA_DISCONNECTED:
+ {
+ // Camera is disconnected, close the session and expect no more callbacks
+ if (session != nullptr) {
+ session->closeByDevice();
+ }
+ dev->mCurrentSession = nullptr;
+ sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onDisconnected);
+ msg->post();
+ break;
+ }
+ default:
+ ALOGE("Unknown error from camera device: %d", errorCode);
+ [[fallthrough]];
+ case ErrorCode::CAMERA_DEVICE:
+ case ErrorCode::CAMERA_SERVICE:
+ {
+ int32_t errorVal = ::ERROR_CAMERA_DEVICE;
+ // We keep this switch since this block might be encountered with
+ // more than just 2 states. The default fallthrough could have us
+ // handling more unmatched error cases.
+ switch (errorCode) {
+ case ErrorCode::CAMERA_DEVICE:
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ break;
+ case ErrorCode::CAMERA_SERVICE:
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ errorVal = ::ERROR_CAMERA_SERVICE;
+ break;
+ default:
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
+ break;
+ }
+ sp<AMessage> msg = new AMessage(kWhatOnError, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
+ msg->setInt32(kErrorCodeKey, errorVal);
+ msg->post();
+ break;
+ }
+ case ErrorCode::CAMERA_REQUEST:
+ case ErrorCode::CAMERA_RESULT:
+ case ErrorCode::CAMERA_BUFFER:
+ dev->onCaptureErrorLocked(errorCode, resultExtras);
+ break;
+ }
+ return ret;
+}
+
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onDeviceIdle() {
+ ALOGV("Camera is now idle");
+ auto ret = Void();
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return ret;
+ }
+
+ if (dev->mIdle) {
+ // Already in idle state. Possibly other thread did waitUntilIdle
+ return ret;
+ }
+
+ if (dev->mCurrentSession != nullptr) {
+ ALOGE("onDeviceIdle sending state cb");
+ if (dev->mBusySession != dev->mCurrentSession) {
+ ALOGE("Current session != busy session");
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ret;
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mBusySession->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, dev->mBusySession);
+ msg->setPointer(kCallbackFpKey, (void*) dev->mBusySession->mUserSessionCallback.onReady);
+ // Make sure we clear the sp first so the session destructor can
+ // only happen on handler thread (where we don't hold device/session lock)
+ dev->mBusySession.clear();
+ dev->postSessionMsgAndCleanup(msg);
+ }
+ dev->mIdle = true;
+ dev->mFlushing = false;
+ return ret;
+}
+
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onCaptureStarted(
+ const CaptureResultExtras& resultExtras,
+ uint64_t timestamp) {
+ auto ret = Void();
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return ret;
+ }
+
+ int32_t sequenceId = resultExtras.requestId;
+ int32_t burstId = resultExtras.burstId;
+
+ auto it = dev->mSequenceCallbackMap.find(sequenceId);
+ if (it != dev->mSequenceCallbackMap.end()) {
+ CallbackHolder cbh = (*it).second;
+ ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+ sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onStart);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setInt64(kTimeStampKey, timestamp);
+ dev->postSessionMsgAndCleanup(msg);
+ }
+ return ret;
+}
+
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onResultReceived(
+ const FmqSizeOrMetadata& resultMetadata,
+ const CaptureResultExtras& resultExtras,
+ const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) {
+ auto ret = Void();
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+ int32_t sequenceId = resultExtras.requestId;
+ int64_t frameNumber = resultExtras.frameNumber;
+ int32_t burstId = resultExtras.burstId;
+ bool isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
+
+ if (!isPartialResult) {
+ ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return ret; // device has been disconnected
+ }
+
+ if (dev->isClosed()) {
+ if (!isPartialResult) {
+ dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
+ }
+ // early return to avoid callback sent to closed devices
+ return ret;
+ }
+
+ CameraMetadata metadataCopy;
+ camera_status_t status = readOneResultMetadata(resultMetadata,
+ dev->mCaptureResultMetadataQueue.get(), &metadataCopy);
+ if (status != ACAMERA_OK) {
+ ALOGE("%s: result metadata couldn't be converted", __FUNCTION__);
+ return ret;
+ }
+
+ metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
+ metadataCopy.update(ANDROID_SYNC_FRAME_NUMBER, &frameNumber, /*data_count*/1);
+
+ auto it = dev->mSequenceCallbackMap.find(sequenceId);
+ if (it != dev->mSequenceCallbackMap.end()) {
+ CallbackHolder cbh = (*it).second;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+ sp<ACameraMetadata> result(new ACameraMetadata(
+ metadataCopy.release(), ACameraMetadata::ACM_RESULT));
+
+ std::vector<PhysicalCaptureResultInfoLocal> localPhysicalResult;
+ localPhysicalResult.resize(physicalResultInfos.size());
+ for (size_t i = 0; i < physicalResultInfos.size(); i++) {
+ localPhysicalResult[i].physicalCameraId = physicalResultInfos[i].physicalCameraId;
+ status = readOneResultMetadata(physicalResultInfos[i].physicalCameraMetadata,
+ dev->mCaptureResultMetadataQueue.get(),
+ &localPhysicalResult[i].physicalMetadata);
+ if (status != ACAMERA_OK) {
+ ALOGE("%s: physical camera result metadata couldn't be converted", __FUNCTION__);
+ return ret;
+ }
+ }
+ sp<ACameraPhysicalCaptureResultInfo> physicalResult(
+ new ACameraPhysicalCaptureResultInfo(localPhysicalResult, frameNumber));
+
+ sp<AMessage> msg = new AMessage(
+ cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureResult : kWhatCaptureResult,
+ dev->mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
+ msg->setObject(kSessionSpKey, session);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setObject(kCaptureResultKey, result);
+ if (isPartialResult) {
+ msg->setPointer(kCallbackFpKey,
+ (void *)cbh.mOnCaptureProgressed);
+ } else if (cbh.mIsLogicalCameraCallback) {
+ msg->setPointer(kCallbackFpKey,
+ (void *)cbh.mOnLogicalCameraCaptureCompleted);
+ msg->setObject(kPhysicalCaptureResultKey, physicalResult);
+ } else {
+ msg->setPointer(kCallbackFpKey,
+ (void *)cbh.mOnCaptureCompleted);
+ }
+ dev->postSessionMsgAndCleanup(msg);
+ }
+
+ if (!isPartialResult) {
+ dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
+ dev->checkAndFireSequenceCompleteLocked();
+ }
+
+ return ret;
+}
+
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onRepeatingRequestError(
+ uint64_t lastFrameNumber, int32_t stoppedSequenceId) {
+ auto ret = Void();
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+
+ int repeatingSequenceId = dev->mRepeatingSequenceId;
+ if (stoppedSequenceId == repeatingSequenceId) {
+ dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+ }
+
+ dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
+
+ return ret;
+}
+
+camera_status_t CameraDevice::ServiceCallback::readOneResultMetadata(
+ const FmqSizeOrMetadata& fmqSizeOrMetadata, ResultMetadataQueue* metadataQueue,
+ CameraMetadata* metadata) {
+ if (metadataQueue == nullptr || metadata == nullptr) {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ bool converted;
+ HCameraMetadata hCameraMetadata;
+ if (fmqSizeOrMetadata.getDiscriminator() ==
+ FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
+ hCameraMetadata.resize(fmqSizeOrMetadata.fmqMetadataSize());
+ bool read = metadataQueue->read(
+ hCameraMetadata.data(), fmqSizeOrMetadata.fmqMetadataSize());
+ if (!read) {
+ ALOGE("%s capture request settings could't be read from fmq", __FUNCTION__);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ // TODO: Do we actually need to clone here ?
+ converted = utils::convertFromHidlCloned(hCameraMetadata, metadata);
+ } else {
+ converted = utils::convertFromHidlCloned(fmqSizeOrMetadata.metadata(), metadata);
+ }
+
+ return converted ? ACAMERA_OK : ACAMERA_ERROR_UNKNOWN;
+}
+
+} // namespace acam
+} // namespace android
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
new file mode 100644
index 0000000..3328a85
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _ACAMERA_DEVICE_H
+#define _ACAMERA_DEVICE_H
+
+#include <memory>
+#include <map>
+#include <set>
+#include <atomic>
+#include <utility>
+#include <vector>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
+#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceCallback.h>
+#include <android/frameworks/cameraservice/device/2.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <camera/NdkCameraManager.h>
+#include <camera/NdkCameraCaptureSession.h>
+#include "ACameraMetadata.h"
+#include "utils.h"
+
+namespace android {
+namespace acam {
+
+using ICameraDeviceCallback = frameworks::cameraservice::device::V2_0::ICameraDeviceCallback;
+using ICameraDeviceUser = frameworks::cameraservice::device::V2_0::ICameraDeviceUser;
+using CaptureResultExtras = frameworks::cameraservice::device::V2_0::CaptureResultExtras;
+using PhysicalCaptureResultInfo = frameworks::cameraservice::device::V2_0::PhysicalCaptureResultInfo;
+using PhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
+using SubmitInfo = frameworks::cameraservice::device::V2_0::SubmitInfo;
+using CaptureResultExtras = frameworks::cameraservice::device::V2_0::CaptureResultExtras;
+using ErrorCode = frameworks::cameraservice::device::V2_0::ErrorCode;
+using FmqSizeOrMetadata = frameworks::cameraservice::device::V2_0::FmqSizeOrMetadata;
+using StreamConfigurationMode = frameworks::cameraservice::device::V2_0::StreamConfigurationMode;
+using Status = frameworks::cameraservice::common::V2_0::Status;
+using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+
+using hardware::hidl_vec;
+using hardware::hidl_string;
+using utils::native_handle_ptr_wrapper;
+using utils::CaptureRequest;
+using utils::OutputConfigurationWrapper;
+
+// Wrap ACameraCaptureFailure so it can be ref-counted
+struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure { };
+
+// Wrap PhysicalCaptureResultInfo so that it can be ref-counted
+struct PhysicalCaptureResultInfoLocal {
+ std::string physicalCameraId;
+ CameraMetadata physicalMetadata;
+};
+
+struct ACameraPhysicalCaptureResultInfo: public RefBase {
+ ACameraPhysicalCaptureResultInfo(const std::vector<PhysicalCaptureResultInfoLocal>& info,
+ int64_t frameNumber) :
+ mPhysicalResultInfo(info), mFrameNumber(frameNumber) {}
+
+ std::vector<PhysicalCaptureResultInfoLocal> mPhysicalResultInfo;
+ int64_t mFrameNumber;
+};
+
+class CameraDevice final : public RefBase {
+ public:
+ CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+ sp<ACameraMetadata> chars,
+ ACameraDevice* wrapper);
+ ~CameraDevice();
+
+ inline const char* getId() const { return mCameraId.c_str(); }
+
+ camera_status_t createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
+ ACaptureRequest** request) const;
+
+ camera_status_t createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session);
+
+ camera_status_t isSessionConfigurationSupported(
+ const ACaptureSessionOutputContainer* sessionOutputContainer) const;
+
+ // Callbacks from camera service
+ class ServiceCallback : public ICameraDeviceCallback {
+ public:
+ explicit ServiceCallback(CameraDevice* device) : mDevice(device) {}
+ android::hardware::Return<void> onDeviceError(ErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) override;
+ android::hardware::Return<void> onDeviceIdle() override;
+ android::hardware::Return<void> onCaptureStarted(const CaptureResultExtras& resultExtras,
+ uint64_t timestamp) override;
+ android::hardware::Return<void> onResultReceived(const FmqSizeOrMetadata& result,
+ const CaptureResultExtras& resultExtras,
+ const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) override;
+ android::hardware::Return<void> onRepeatingRequestError(uint64_t lastFrameNumber,
+ int32_t stoppedSequenceId) override;
+ private:
+ camera_status_t readOneResultMetadata(const FmqSizeOrMetadata& fmqSizeOrMetadata,
+ ResultMetadataQueue* metadataQueue, CameraMetadata* metadata);
+ const wp<CameraDevice> mDevice;
+ };
+ inline sp<ICameraDeviceCallback> getServiceCallback() {
+ return mServiceCallback;
+ };
+
+ // Camera device is only functional after remote being set
+ void setRemoteDevice(sp<ICameraDeviceUser> remote);
+
+ bool setDeviceMetadataQueues();
+ inline ACameraDevice* getWrapper() const { return mWrapper; };
+
+ // Stop the looper thread and unregister the handler
+ void stopLooper();
+
+ private:
+ friend ACameraCaptureSession;
+
+ camera_status_t checkCameraClosedOrErrorLocked() const;
+
+ // device goes into fatal error state after this
+ void setCameraDeviceErrorLocked(camera_status_t error);
+
+ void disconnectLocked(sp<ACameraCaptureSession>& session); // disconnect from camera service
+
+ camera_status_t stopRepeatingLocked();
+
+ camera_status_t flushLocked(ACameraCaptureSession*);
+
+ camera_status_t waitUntilIdleLocked();
+
+ template<class T>
+ camera_status_t captureLocked(sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+ template<class T>
+ camera_status_t setRepeatingRequestsLocked(sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+ template<class T>
+ camera_status_t submitRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*out*/int* captureSequenceId,
+ bool isRepeating);
+
+ void addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest, sp<CaptureRequest> &req);
+
+ camera_status_t updateOutputConfigurationLocked(ACaptureSessionOutput *output);
+
+ // Since this writes to ICameraDeviceUser's fmq, clients must take care that:
+ // a) This function is called serially.
+ // b) This function is called in accordance with ICameraDeviceUser.submitRequestList,
+ // otherwise, the wrong capture request might have the wrong settings
+ // metadata associated with it.
+ camera_status_t allocateCaptureRequestLocked(
+ const ACaptureRequest* request, sp<CaptureRequest>& outReq);
+ void allocateOneCaptureRequestMetadata(
+ PhysicalCameraSettings& cameraSettings,
+ const std::string& id, const sp<ACameraMetadata>& metadata);
+
+ static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req, const char* deviceId);
+ static void freeACaptureRequest(ACaptureRequest*);
+
+ // only For session to hold device lock
+ // Always grab device lock before grabbing session lock
+ void lockDeviceForSessionOps() const { mDeviceLock.lock(); };
+ void unlockDevice() const { mDeviceLock.unlock(); };
+
+ // For capture session to notify its end of life
+ void notifySessionEndOfLifeLocked(ACameraCaptureSession* session);
+
+ camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters);
+
+ // Input message will be posted and cleared after this returns
+ void postSessionMsgAndCleanup(sp<AMessage>& msg);
+
+ mutable Mutex mDeviceLock;
+ const hidl_string mCameraId; // Camera ID
+ const ACameraDevice_StateCallbacks mAppCallbacks; // Callback to app
+ const sp<ACameraMetadata> mChars; // Camera characteristics
+ const sp<ServiceCallback> mServiceCallback;
+ ACameraDevice* mWrapper;
+
+ // stream id -> pair of (ACameraWindowType* from application, OutputConfiguration used for
+ // camera service)
+ std::map<int, std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> mConfiguredOutputs;
+
+ // TODO: maybe a bool will suffice for synchronous implementation?
+ std::atomic_bool mClosing;
+ inline bool isClosed() { return mClosing; }
+
+ bool mInError = false;
+ camera_status_t mError = ACAMERA_OK;
+ void onCaptureErrorLocked(
+ ErrorCode errorCode,
+ const CaptureResultExtras& resultExtras);
+
+ bool mIdle = true;
+ // This will avoid a busy session being deleted before it's back to idle state
+ sp<ACameraCaptureSession> mBusySession;
+
+ sp<ICameraDeviceUser> mRemote;
+
+ // Looper thread to handle callback to app
+ sp<ALooper> mCbLooper;
+ // definition of handler and message
+ enum {
+ // Device state callbacks
+ kWhatOnDisconnected, // onDisconnected
+ kWhatOnError, // onError
+ // Session state callbacks
+ kWhatSessionStateCb, // onReady, onActive
+ // Capture callbacks
+ kWhatCaptureStart, // onCaptureStarted
+ kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
+ kWhatLogicalCaptureResult, // onLogicalCameraCaptureCompleted
+ kWhatCaptureFail, // onCaptureFailed
+ kWhatLogicalCaptureFail, // onLogicalCameraCaptureFailed
+ kWhatCaptureSeqEnd, // onCaptureSequenceCompleted
+ kWhatCaptureSeqAbort, // onCaptureSequenceAborted
+ kWhatCaptureBufferLost,// onCaptureBufferLost
+ // Internal cleanup
+ kWhatCleanUpSessions // Cleanup cached sp<ACameraCaptureSession>
+ };
+ static const char* kContextKey;
+ static const char* kDeviceKey;
+ static const char* kErrorCodeKey;
+ static const char* kCallbackFpKey;
+ static const char* kSessionSpKey;
+ static const char* kCaptureRequestKey;
+ static const char* kTimeStampKey;
+ static const char* kCaptureResultKey;
+ static const char* kPhysicalCaptureResultKey;
+ static const char* kCaptureFailureKey;
+ static const char* kSequenceIdKey;
+ static const char* kFrameNumberKey;
+ static const char* kAnwKey;
+ static const char* kFailingPhysicalCameraId;
+
+ class CallbackHandler : public AHandler {
+ public:
+ explicit CallbackHandler(const char *id);
+ void onMessageReceived(const sp<AMessage> &msg) override;
+
+ private:
+ std::string mId;
+ // This handler will cache all capture session sp until kWhatCleanUpSessions
+ // is processed. This is used to guarantee the last session reference is always
+ // being removed in callback thread without holding camera device lock
+ Vector<sp<ACameraCaptureSession>> mCachedSessions;
+ };
+ sp<CallbackHandler> mHandler;
+
+ /***********************************
+ * Capture session related members *
+ ***********************************/
+ // The current active session
+ wp<ACameraCaptureSession> mCurrentSession;
+ bool mFlushing = false;
+
+ int mNextSessionId = 0;
+ // TODO: might need another looper/handler to handle callbacks from service
+
+ static const int REQUEST_ID_NONE = -1;
+ int mRepeatingSequenceId = REQUEST_ID_NONE;
+
+ // sequence id -> last frame number map
+ std::map<int32_t, int64_t> mSequenceLastFrameNumberMap;
+
+ struct CallbackHolder {
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest>>& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacks* cbs);
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest>>& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
+
+ template <class T>
+ void initCaptureCallbacks(T* cbs) {
+ mContext = nullptr;
+ mOnCaptureStarted = nullptr;
+ mOnCaptureProgressed = nullptr;
+ mOnCaptureCompleted = nullptr;
+ mOnLogicalCameraCaptureCompleted = nullptr;
+ mOnLogicalCameraCaptureFailed = nullptr;
+ mOnCaptureFailed = nullptr;
+ mOnCaptureSequenceCompleted = nullptr;
+ mOnCaptureSequenceAborted = nullptr;
+ mOnCaptureBufferLost = nullptr;
+ if (cbs != nullptr) {
+ mContext = cbs->context;
+ mOnCaptureStarted = cbs->onCaptureStarted;
+ mOnCaptureProgressed = cbs->onCaptureProgressed;
+ mOnCaptureSequenceCompleted = cbs->onCaptureSequenceCompleted;
+ mOnCaptureSequenceAborted = cbs->onCaptureSequenceAborted;
+ mOnCaptureBufferLost = cbs->onCaptureBufferLost;
+ }
+ }
+
+ sp<ACameraCaptureSession> mSession;
+ Vector<sp<CaptureRequest>> mRequests;
+ const bool mIsRepeating;
+ const bool mIsLogicalCameraCallback;
+
+ void* mContext;
+ ACameraCaptureSession_captureCallback_start mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_result mOnCaptureProgressed;
+ ACameraCaptureSession_captureCallback_result mOnCaptureCompleted;
+ ACameraCaptureSession_logicalCamera_captureCallback_result mOnLogicalCameraCaptureCompleted;
+ ACameraCaptureSession_logicalCamera_captureCallback_failed mOnLogicalCameraCaptureFailed;
+ ACameraCaptureSession_captureCallback_failed mOnCaptureFailed;
+ ACameraCaptureSession_captureCallback_sequenceEnd mOnCaptureSequenceCompleted;
+ ACameraCaptureSession_captureCallback_sequenceAbort mOnCaptureSequenceAborted;
+ ACameraCaptureSession_captureCallback_bufferLost mOnCaptureBufferLost;
+ };
+ // sequence id -> callbacks map
+ std::map<int, CallbackHolder> mSequenceCallbackMap;
+
+ static const int64_t NO_FRAMES_CAPTURED = -1;
+ class FrameNumberTracker {
+ public:
+ // TODO: Called in onResultReceived and onCaptureErrorLocked
+ void updateTracker(int64_t frameNumber, bool isError);
+ inline int64_t getCompletedFrameNumber() { return mCompletedFrameNumber; }
+ private:
+ void update();
+ void updateCompletedFrameNumber(int64_t frameNumber);
+
+ int64_t mCompletedFrameNumber = NO_FRAMES_CAPTURED;
+ List<int64_t> mSkippedFrameNumbers;
+ std::set<int64_t> mFutureErrorSet;
+ };
+ FrameNumberTracker mFrameNumberTracker;
+
+ void checkRepeatingSequenceCompleteLocked(const int sequenceId, const int64_t lastFrameNumber);
+ void checkAndFireSequenceCompleteLocked();
+
+ // Misc variables
+ int32_t mShadingMapSize[2]; // const after constructor
+ int32_t mPartialResultCount; // const after constructor
+ std::shared_ptr<ResultMetadataQueue> mCaptureRequestMetadataQueue = nullptr;
+ std::shared_ptr<ResultMetadataQueue> mCaptureResultMetadataQueue = nullptr;
+};
+
+} // namespace acam;
+} // namespace android;
+
+/**
+ * ACameraDevice opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraDevice {
+ ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+ sp<ACameraMetadata> chars) :
+ mDevice(new android::acam::CameraDevice(id, cb, std::move(chars), this)) {}
+
+ ~ACameraDevice();
+
+ /*******************
+ * NDK public APIs *
+ *******************/
+ inline const char* getId() const { return mDevice->getId(); }
+
+ camera_status_t createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
+ ACaptureRequest** request) const {
+ return mDevice->createCaptureRequest(templateId, physicalCameraIdList, request);
+ }
+
+ camera_status_t createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session) {
+ return mDevice->createCaptureSession(outputs, sessionParameters, callbacks, session);
+ }
+
+ camera_status_t isSessionConfigurationSupported(
+ const ACaptureSessionOutputContainer* sessionOutputContainer) const {
+ return mDevice->isSessionConfigurationSupported(sessionOutputContainer);
+ }
+
+ /***********************
+ * Device interal APIs *
+ ***********************/
+ inline android::sp<android::acam::ICameraDeviceCallback> getServiceCallback() {
+ return mDevice->getServiceCallback();
+ };
+
+ // Camera device is only functional after remote being set
+ inline void setRemoteDevice(android::sp<android::acam::ICameraDeviceUser> remote) {
+ mDevice->setRemoteDevice(remote);
+ }
+ inline bool setDeviceMetadataQueues() {
+ return mDevice->setDeviceMetadataQueues();
+ }
+ private:
+ android::sp<android::acam::CameraDevice> mDevice;
+};
+
+#endif // _ACAMERA_DEVICE_H
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
new file mode 100644
index 0000000..8bd5a52
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+#include <inttypes.h>
+#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/device/2.0/types.h>
+#include <CameraMetadata.h>
+
+#include "ndk_vendor/impl/ACameraDevice.h"
+#include "ACameraCaptureSession.h"
+#include "ACameraMetadata.h"
+#include "ACaptureRequest.h"
+#include "utils.h"
+
+using namespace android;
+
+namespace android {
+namespace acam {
+
+template<class T>
+camera_status_t
+CameraDevice::captureLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ return submitRequestsLocked(
+ session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
+}
+
+template<class T>
+camera_status_t
+CameraDevice::setRepeatingRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ return submitRequestsLocked(
+ session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
+}
+
+template<class T>
+camera_status_t CameraDevice::submitRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/T* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*out*/int* captureSequenceId,
+ bool isRepeating)
+{
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ // Form two vectors of capture request, one for internal tracking
+ std::vector<frameworks::cameraservice::device::V2_0::CaptureRequest> requestList;
+ Vector<sp<CaptureRequest>> requestsV;
+ requestsV.setCapacity(numRequests);
+ for (int i = 0; i < numRequests; i++) {
+ sp<CaptureRequest> req;
+ ret = allocateCaptureRequestLocked(requests[i], req);
+ // We need to call this method since after submitRequestList is called,
+ // the request metadata queue might have removed the capture request
+ // metadata. Therefore we simply add the metadata to its wrapper class,
+ // so that it can be retrieved later.
+ addRequestSettingsMetadata(requests[i], req);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Convert capture request to internal format failure! ret %d", ret);
+ return ret;
+ }
+ if (req->mCaptureRequest.streamAndWindowIds.size() == 0) {
+ ALOGE("Capture request without output target cannot be submitted!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ requestList.push_back(utils::convertToHidl(req.get()));
+ requestsV.push_back(req);
+ }
+ if (isRepeating) {
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+ }
+
+ SubmitInfo info;
+ Status status;
+ auto remoteRet = mRemote->submitRequestList(requestList, isRepeating,
+ [&status, &info](auto s, auto &submitInfo) {
+ status = s;
+ info = submitInfo;
+ });
+ if (!remoteRet.isOk()) {
+ ALOGE("%s: Transaction error for submitRequestList call: %s", __FUNCTION__,
+ remoteRet.description().c_str());
+ }
+ if (status != Status::NO_ERROR) {
+ return utils::convertFromHidl(status);
+ }
+ int32_t sequenceId = info.requestId;
+ int64_t lastFrameNumber = info.lastFrameNumber;
+ if (sequenceId < 0) {
+ ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
+ mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+ if (isRepeating) {
+ // stopRepeating above should have cleanup repeating sequence id
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ mRepeatingSequenceId = sequenceId;
+ } else {
+ mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+ }
+
+ if (mIdle) {
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+ postSessionMsgAndCleanup(msg);
+ }
+ mIdle = false;
+ mBusySession = session;
+
+ if (captureSequenceId) {
+ *captureSequenceId = sequenceId;
+ }
+ return ACAMERA_OK;
+}
+
+} // namespace acam
+} // namespace android
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
new file mode 100644
index 0000000..70c887a
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ACameraManagerVendor"
+
+#include <memory>
+#include "ndk_vendor/impl/ACameraManager.h"
+#include "ACameraMetadata.h"
+#include "ndk_vendor/impl/ACameraDevice.h"
+#include "utils.h"
+#include <CameraMetadata.h>
+#include <camera_metadata_hidden.h>
+
+#include <utils/Vector.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+
+#include <VendorTagDescriptor.h>
+
+using namespace android::acam;
+
+namespace android {
+namespace acam {
+
+using frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+using frameworks::cameraservice::common::V2_0::ProviderIdAndVendorTagSections;
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
+
+// Static member definitions
+const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
+const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
+const char* CameraManagerGlobal::kContextKey = "CallbackContext";
+Mutex CameraManagerGlobal::sLock;
+CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
+
+/**
+ * The vendor tag descriptor class that takes HIDL vendor tag information as
+ * input. Not part of vendor available VendorTagDescriptor class because that class is used by
+ * default HAL implementation code as well.
+ */
+class HidlVendorTagDescriptor : public VendorTagDescriptor {
+public:
+ /**
+ * Create a VendorTagDescriptor object from the HIDL VendorTagSection
+ * vector.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ static status_t createDescriptorFromHidl(const hidl_vec<VendorTagSection>& vts,
+ /*out*/ sp<VendorTagDescriptor> *descriptor);
+};
+
+status_t HidlVendorTagDescriptor::createDescriptorFromHidl(const hidl_vec<VendorTagSection> &vts,
+ sp<VendorTagDescriptor> *descriptor) {
+ int tagCount = 0;
+
+ for (size_t s = 0; s < vts.size(); s++) {
+ tagCount += vts[s].tags.size();
+ }
+
+ if (tagCount < 0 || tagCount > INT32_MAX) {
+ ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
+ return BAD_VALUE;
+ }
+
+ Vector<uint32_t> tagArray;
+ LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+ "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+ sp<HidlVendorTagDescriptor> desc = new HidlVendorTagDescriptor();
+ desc->mTagCount = tagCount;
+
+ KeyedVector<uint32_t, String8> tagToSectionMap;
+
+ int idx = 0;
+ for (size_t s = 0; s < vts.size(); s++) {
+ const VendorTagSection& section = vts[s];
+ const char *sectionName = section.sectionName.c_str();
+ if (sectionName == NULL) {
+ ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
+ return BAD_VALUE;
+ }
+ String8 sectionString(sectionName);
+ desc->mSections.add(sectionString);
+
+ for (size_t j = 0; j < section.tags.size(); j++) {
+ uint32_t tag = section.tags[j].tagId;
+ if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+ ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+
+ tagArray.editItemAt(idx++) = section.tags[j].tagId;
+
+ const char *tagName = section.tags[j].tagName.c_str();
+ if (tagName == NULL) {
+ ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ desc->mTagToNameMap.add(tag, String8(tagName));
+ tagToSectionMap.add(tag, sectionString);
+
+ int tagType = (int) section.tags[j].tagType;
+ if (tagType < 0 || tagType >= NUM_TYPES) {
+ ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+ return BAD_VALUE;
+ }
+ desc->mTagToTypeMap.emplace(tag, tagType);
+ }
+ }
+
+ for (size_t i = 0; i < tagArray.size(); ++i) {
+ uint32_t tag = tagArray[i];
+ String8 sectionString = tagToSectionMap.valueFor(tag);
+
+ // Set up tag to section index map
+ ssize_t index = desc->mSections.indexOf(sectionString);
+ LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+ desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+ // Set up reverse mapping
+ ssize_t reverseIndex = -1;
+ if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+ KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+ reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+ }
+ desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+ }
+
+ *descriptor = std::move(desc);
+ return OK;
+}
+
+CameraManagerGlobal&
+CameraManagerGlobal::getInstance() {
+ Mutex::Autolock _l(sLock);
+ CameraManagerGlobal* instance = sInstance;
+ if (instance == nullptr) {
+ instance = new CameraManagerGlobal();
+ sInstance = instance;
+ }
+ return *instance;
+}
+
+CameraManagerGlobal::~CameraManagerGlobal() {
+ // clear sInstance so next getInstance call knows to create a new one
+ Mutex::Autolock _sl(sLock);
+ sInstance = nullptr;
+ Mutex::Autolock _l(mLock);
+ if (mCameraService != nullptr) {
+ mCameraService->unlinkToDeath(mDeathNotifier);
+ mCameraService->removeListener(mCameraServiceListener);
+ }
+ mDeathNotifier.clear();
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+ mCameraServiceListener.clear();
+ mCameraService.clear();
+}
+
+static bool isCameraServiceDisabled() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("config.disable_cameraservice", value, "0");
+ return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0);
+}
+
+bool CameraManagerGlobal::setupVendorTags() {
+ sp<VendorTagDescriptorCache> tagCache = new VendorTagDescriptorCache();
+ Status status = Status::NO_ERROR;
+ std::vector<ProviderIdAndVendorTagSections> providerIdsAndVts;
+ auto remoteRet = mCameraService->getCameraVendorTagSections([&status, &providerIdsAndVts]
+ (Status s,
+ auto &IdsAndVts) {
+ status = s;
+ providerIdsAndVts = IdsAndVts; });
+
+ if (!remoteRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("Failed to retrieve VendorTagSections %s", remoteRet.description().c_str());
+ return false;
+ }
+ // Convert each providers VendorTagSections into a VendorTagDescriptor and
+ // add it to the cache
+ for (auto &providerIdAndVts : providerIdsAndVts) {
+ sp<VendorTagDescriptor> vendorTagDescriptor;
+ if (HidlVendorTagDescriptor::createDescriptorFromHidl(providerIdAndVts.vendorTagSections,
+ &vendorTagDescriptor) != OK) {
+ ALOGE("Failed to convert from Hidl: VendorTagDescriptor");
+ return false;
+ }
+ tagCache->addVendorDescriptor(providerIdAndVts.providerId, vendorTagDescriptor);
+ }
+ VendorTagDescriptorCache::setAsGlobalVendorTagCache(tagCache);
+ return true;
+}
+
+sp<ICameraService> CameraManagerGlobal::getCameraService() {
+ Mutex::Autolock _l(mLock);
+ if (mCameraService.get() == nullptr) {
+ if (isCameraServiceDisabled()) {
+ return mCameraService;
+ }
+
+ sp<ICameraService> cameraServiceBinder;
+ do {
+ cameraServiceBinder = ICameraService::getService();
+ if (cameraServiceBinder != nullptr) {
+ break;
+ }
+ ALOGW("CameraService not published, waiting...");
+ usleep(kCameraServicePollDelay);
+ } while(true);
+ if (mDeathNotifier == nullptr) {
+ mDeathNotifier = new DeathNotifier(this);
+ }
+ cameraServiceBinder->linkToDeath(mDeathNotifier, 0);
+ mCameraService = cameraServiceBinder;
+
+ // Setup looper thread to perfrom availiability callbacks
+ if (mCbLooper == nullptr) {
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-mgr-looper");
+ status_t err = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ if (err != OK) {
+ ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ mCbLooper.clear();
+ return nullptr;
+ }
+ if (mHandler == nullptr) {
+ mHandler = new CallbackHandler();
+ }
+ mCbLooper->registerHandler(mHandler);
+ }
+
+ // register ICameraServiceListener
+ if (mCameraServiceListener == nullptr) {
+ mCameraServiceListener = new CameraServiceListener(this);
+ }
+ hidl_vec<CameraStatusAndId> cameraStatuses{};
+ Status status = Status::NO_ERROR;
+ auto remoteRet = mCameraService->addListener(mCameraServiceListener,
+ [&status, &cameraStatuses](Status s,
+ auto &retStatuses) {
+ status = s;
+ cameraStatuses = retStatuses;
+ });
+ if (!remoteRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("Failed to add listener to camera service %s", remoteRet.description().c_str());
+ }
+
+ // Setup vendor tags
+ if (!setupVendorTags()) {
+ ALOGE("Unable to set up vendor tags");
+ return nullptr;
+ }
+
+ for (auto& c : cameraStatuses) {
+ onStatusChangedLocked(c);
+ }
+ }
+ return mCameraService;
+}
+
+void CameraManagerGlobal::DeathNotifier::serviceDied(uint64_t cookie, const wp<IBase> &who) {
+ (void) cookie;
+ (void) who;
+ ALOGE("Camera service binderDied!");
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ AutoMutex lock(cm->mLock);
+ for (auto& pair : cm->mDeviceStatusMap) {
+ CameraStatusAndId cameraStatusAndId;
+ cameraStatusAndId.cameraId = pair.first;
+ cameraStatusAndId.deviceStatus = pair.second;
+ cm->onStatusChangedLocked(cameraStatusAndId);
+ }
+ cm->mCameraService.clear();
+ // TODO: consider adding re-connect call here?
+ }
+}
+
+void CameraManagerGlobal::registerAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ auto pair = mCallbacks.insert(cb);
+ // Send initial callbacks if callback is newly registered
+ if (pair.second) {
+ for (auto& pair : mDeviceStatusMap) {
+ const hidl_string& cameraId = pair.first;
+ CameraDeviceStatus status = pair.second;
+
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
+ callback->onCameraAvailable : callback->onCameraUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cb);
+ msg->setPointer(kContextKey, callback->context);
+ msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+ msg->post();
+ }
+ }
+}
+
+void CameraManagerGlobal::unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.erase(cb);
+}
+
+void CameraManagerGlobal::getCameraIdList(std::vector<hidl_string>* cameraIds) {
+ // Ensure that we have initialized/refreshed the list of available devices
+ auto cs = getCameraService();
+ Mutex::Autolock _l(mLock);
+
+ for(auto& deviceStatus : mDeviceStatusMap) {
+ if (deviceStatus.second == CameraDeviceStatus::STATUS_NOT_PRESENT ||
+ deviceStatus.second == CameraDeviceStatus::STATUS_ENUMERATING) {
+ continue;
+ }
+ cameraIds->push_back(deviceStatus.first);
+ }
+}
+
+bool CameraManagerGlobal::validStatus(CameraDeviceStatus status) {
+ switch (status) {
+ case CameraDeviceStatus::STATUS_NOT_PRESENT:
+ case CameraDeviceStatus::STATUS_PRESENT:
+ case CameraDeviceStatus::STATUS_ENUMERATING:
+ case CameraDeviceStatus::STATUS_NOT_AVAILABLE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool CameraManagerGlobal::isStatusAvailable(CameraDeviceStatus status) {
+ switch (status) {
+ case CameraDeviceStatus::STATUS_PRESENT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void CameraManagerGlobal::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatSendSingleCallback:
+ {
+ ACameraManager_AvailabilityCallback cb;
+ void* context;
+ AString cameraId;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+ if (!found) {
+ ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ found = msg->findString(kCameraIdKey, &cameraId);
+ if (!found) {
+ ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
+ return;
+ }
+ (*cb)(context, cameraId.c_str());
+ break;
+ }
+ default:
+ ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
+ break;
+ }
+}
+
+hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onStatusChanged(
+ const CameraStatusAndId &statusAndId) {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ cm->onStatusChanged(statusAndId);
+ } else {
+ ALOGE("Cannot deliver status change. Global camera manager died");
+ }
+ return Void();
+}
+
+void CameraManagerGlobal::onStatusChanged(
+ const CameraStatusAndId &statusAndId) {
+ Mutex::Autolock _l(mLock);
+ onStatusChangedLocked(statusAndId);
+}
+
+void CameraManagerGlobal::onStatusChangedLocked(
+ const CameraStatusAndId &statusAndId) {
+ hidl_string cameraId = statusAndId.cameraId;
+ CameraDeviceStatus status = statusAndId.deviceStatus;
+ if (!validStatus(status)) {
+ ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+ return;
+ }
+
+ bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
+ CameraDeviceStatus oldStatus = firstStatus ?
+ status : // first status
+ mDeviceStatusMap[cameraId];
+
+ if (!firstStatus &&
+ isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
+ // No status update. No need to send callback
+ return;
+ }
+
+ // Iterate through all registered callbacks
+ mDeviceStatusMap[cameraId] = status;
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
+ cb.mAvailable : cb.mUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+ msg->post();
+ }
+ if (status == CameraDeviceStatus::STATUS_NOT_PRESENT) {
+ mDeviceStatusMap.erase(cameraId);
+ }
+}
+
+} // namespace acam
+} // namespace android
+
+/**
+ * ACameraManger Implementation
+ */
+camera_status_t
+ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
+ Mutex::Autolock _l(mLock);
+
+ std::vector<hidl_string> idList;
+ CameraManagerGlobal::getInstance().getCameraIdList(&idList);
+
+ int numCameras = idList.size();
+ ACameraIdList *out = new ACameraIdList;
+ if (!out) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ out->numCameras = numCameras;
+ out->cameraIds = new const char*[numCameras];
+ if (!out->cameraIds) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ deleteCameraIdList(out);
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ for (int i = 0; i < numCameras; i++) {
+ const char* src = idList[i].c_str();
+ size_t dstSize = strlen(src) + 1;
+ char* dst = new char[dstSize];
+ if (!dst) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ deleteCameraIdList(out);
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ strlcpy(dst, src, dstSize);
+ out->cameraIds[i] = dst;
+ }
+ *cameraIdList = out;
+ return ACAMERA_OK;
+}
+
+void
+ACameraManager::deleteCameraIdList(ACameraIdList* cameraIdList) {
+ if (cameraIdList != nullptr) {
+ if (cameraIdList->cameraIds != nullptr) {
+ for (int i = 0; i < cameraIdList->numCameras; i ++) {
+ if (cameraIdList->cameraIds[i] != nullptr) {
+ delete[] cameraIdList->cameraIds[i];
+ }
+ }
+ delete[] cameraIdList->cameraIds;
+ }
+ delete cameraIdList;
+ }
+}
+
+camera_status_t ACameraManager::getCameraCharacteristics(
+ const char *cameraIdStr, sp<ACameraMetadata> *characteristics) {
+ Mutex::Autolock _l(mLock);
+
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ CameraMetadata rawMetadata;
+ Status status = Status::NO_ERROR;
+ auto serviceRet =
+ cs->getCameraCharacteristics(cameraIdStr,
+ [&status, &rawMetadata] (auto s ,
+ const hidl_vec<uint8_t> &metadata) {
+ status = s;
+ if (status == Status::NO_ERROR) {
+ utils::convertFromHidlCloned(metadata, &rawMetadata);
+ }
+ });
+ if (!serviceRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("Get camera characteristics from camera service failed");
+ return ACAMERA_ERROR_UNKNOWN; // should not reach here
+ }
+
+ *characteristics = new ACameraMetadata(
+ rawMetadata.release(), ACameraMetadata::ACM_CHARACTERISTICS);
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::openCamera(
+ const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** outDevice) {
+ sp<ACameraMetadata> rawChars;
+ camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
+ Mutex::Autolock _l(mLock);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
+ __FUNCTION__, cameraId, ret);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars));
+
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ delete device;
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+
+ sp<ICameraDeviceCallback> callbacks = device->getServiceCallback();
+ sp<ICameraDeviceUser> deviceRemote;
+
+ // No way to get package name from native.
+ // Send a zero length package name and let camera service figure it out from UID
+ Status status = Status::NO_ERROR;
+ auto serviceRet = cs->connectDevice(
+ callbacks, cameraId, [&status, &deviceRemote](auto s, auto &device) {
+ status = s;
+ deviceRemote = device;
+ });
+
+ if (!serviceRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("%s: connect camera device failed", __FUNCTION__);
+ // TODO: Convert serviceRet to camera_status_t
+ delete device;
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ if (deviceRemote == nullptr) {
+ ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
+ delete device;
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ device->setRemoteDevice(deviceRemote);
+ device->setDeviceMetadataQueues();
+ *outDevice = device;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::getTagFromName(const char *cameraId, const char *name, uint32_t *tag) {
+ sp<ACameraMetadata> rawChars;
+ camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s, Cannot retrieve camera characteristics for camera id %s", __FUNCTION__,
+ cameraId);
+ return ACAMERA_ERROR_METADATA_NOT_FOUND;
+ }
+ const CameraMetadata& metadata = rawChars->getInternalData();
+ const camera_metadata_t *rawMetadata = metadata.getAndLock();
+ metadata_vendor_id_t vendorTagId = get_camera_metadata_vendor_id(rawMetadata);
+ metadata.unlock(rawMetadata);
+ sp<VendorTagDescriptorCache> vtCache = VendorTagDescriptorCache::getGlobalVendorTagCache();
+ sp<VendorTagDescriptor> vTags = nullptr;
+ vtCache->getVendorTagDescriptor(vendorTagId, &vTags);
+ status_t status= metadata.getTagFromName(name, vTags.get(), tag);
+ return status == OK ? ACAMERA_OK : ACAMERA_ERROR_METADATA_NOT_FOUND;
+}
+
+ACameraManager::~ACameraManager() {
+
+}
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
new file mode 100644
index 0000000..2c62d44
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACAMERA_MANAGER_H
+#define _ACAMERA_MANAGER_H
+
+#include <camera/NdkCameraManager.h>
+
+#include <android-base/parseint.h>
+#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+
+#include <CameraMetadata.h>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <set>
+#include <map>
+
+namespace android {
+namespace acam {
+
+using ICameraService = frameworks::cameraservice::service::V2_0::ICameraService;
+using CameraDeviceStatus = frameworks::cameraservice::service::V2_0::CameraDeviceStatus;
+using ICameraServiceListener = frameworks::cameraservice::service::V2_0::ICameraServiceListener;
+using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+using Status = frameworks::cameraservice::common::V2_0::Status;
+using VendorTagSection = frameworks::cameraservice::common::V2_0::VendorTagSection;
+using VendorTag = frameworks::cameraservice::common::V2_0::VendorTag;
+using IBase = android::hidl::base::V1_0::IBase;
+using android::hardware::hidl_string;
+using hardware::Void;
+
+/**
+ * Per-process singleton instance of CameraManger. Shared by all ACameraManager
+ * instances. Created when first ACameraManager is created and destroyed when
+ * all ACameraManager instances are deleted.
+ *
+ * TODO: maybe CameraManagerGlobal is better suited in libcameraclient?
+ */
+class CameraManagerGlobal final : public RefBase {
+ public:
+ static CameraManagerGlobal& getInstance();
+ sp<ICameraService> getCameraService();
+
+ void registerAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback);
+ void unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback);
+
+ void registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+ void unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+
+ /**
+ * Return camera IDs that support camera2
+ */
+ void getCameraIdList(std::vector<hidl_string> *cameraIds);
+
+ private:
+ sp<ICameraService> mCameraService;
+ const int kCameraServicePollDelay = 500000; // 0.5s
+ Mutex mLock;
+ class DeathNotifier : public android::hardware::hidl_death_recipient {
+ public:
+ explicit DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+ protected:
+ // IBinder::DeathRecipient implementation
+ virtual void serviceDied(uint64_t cookie, const wp<IBase> &who);
+ private:
+ const wp<CameraManagerGlobal> mCameraManager;
+ };
+ sp<DeathNotifier> mDeathNotifier;
+
+ class CameraServiceListener final : public ICameraServiceListener {
+ public:
+ explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+ android::hardware::Return<void> onStatusChanged(
+ const CameraStatusAndId &statusAndId) override;
+
+ private:
+ const wp<CameraManagerGlobal> mCameraManager;
+ };
+ sp<CameraServiceListener> mCameraServiceListener;
+
+ // Wrapper of ACameraManager_AvailabilityCallbacks so we can store it in std::set
+ struct Callback {
+ explicit Callback(const ACameraManager_AvailabilityCallbacks *callback) :
+ mAvailable(callback->onCameraAvailable),
+ mUnavailable(callback->onCameraUnavailable),
+ mContext(callback->context) {}
+
+ bool operator == (const Callback& other) const {
+ return (mAvailable == other.mAvailable &&
+ mUnavailable == other.mUnavailable &&
+ mContext == other.mContext);
+ }
+ bool operator != (const Callback& other) const {
+ return !(*this == other);
+ }
+ bool operator < (const Callback& other) const {
+ if (*this == other) return false;
+ if (mContext != other.mContext) return mContext < other.mContext;
+ if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
+ return mUnavailable < other.mUnavailable;
+ }
+ bool operator > (const Callback& other) const {
+ return (*this != other && !(*this < other));
+ }
+ ACameraManager_AvailabilityCallback mAvailable;
+ ACameraManager_AvailabilityCallback mUnavailable;
+ void* mContext;
+ };
+ std::set<Callback> mCallbacks;
+
+ // definition of handler and message
+ enum {
+ kWhatSendSingleCallback
+ };
+ static const char* kCameraIdKey;
+ static const char* kCallbackFpKey;
+ static const char* kContextKey;
+ class CallbackHandler : public AHandler {
+ public:
+ CallbackHandler() {}
+ void onMessageReceived(const sp<AMessage> &msg) override;
+ };
+ sp<CallbackHandler> mHandler;
+ sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+
+ void onStatusChanged(const CameraStatusAndId &statusAndId);
+ void onStatusChangedLocked(const CameraStatusAndId &statusAndId);
+ bool setupVendorTags();
+
+ // Utils for status
+ static bool validStatus(CameraDeviceStatus status);
+ static bool isStatusAvailable(CameraDeviceStatus status);
+
+ // The sort logic must match the logic in
+ // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
+ struct CameraIdComparator {
+ bool operator()(const hidl_string& a, const hidl_string& b) const {
+ uint32_t aUint = 0, bUint = 0;
+ bool aIsUint = base::ParseUint(a.c_str(), &aUint);
+ bool bIsUint = base::ParseUint(b.c_str(), &bUint);
+
+ // Uint device IDs first
+ if (aIsUint && bIsUint) {
+ return aUint < bUint;
+ } else if (aIsUint) {
+ return true;
+ } else if (bIsUint) {
+ return false;
+ }
+ // Simple string compare if both id are not uint
+ return a < b;
+ }
+ };
+
+ // Map camera_id -> status
+ std::map<hidl_string, CameraDeviceStatus, CameraIdComparator> mDeviceStatusMap;
+
+ // For the singleton instance
+ static Mutex sLock;
+ static CameraManagerGlobal* sInstance;
+ CameraManagerGlobal() {};
+ ~CameraManagerGlobal();
+};
+
+} // namespace acam;
+} // namespace android;
+
+/**
+ * ACameraManager opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraManager {
+ ACameraManager() :
+ mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}
+ ~ACameraManager();
+ camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
+ static void deleteCameraIdList(ACameraIdList* cameraIdList);
+
+ camera_status_t getCameraCharacteristics(
+ const char* cameraId, android::sp<ACameraMetadata>* characteristics);
+
+ camera_status_t openCamera(const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device);
+ camera_status_t getTagFromName(const char *cameraId, const char *name, uint32_t *tag);
+
+ private:
+ enum {
+ kCameraIdListNotInit = -1
+ };
+ android::Mutex mLock;
+ android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
+};
+
+#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h b/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
new file mode 100644
index 0000000..ed67615
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+
+struct ACameraOutputTarget {
+ explicit ACameraOutputTarget(native_handle_t* window) : mWindow(window) {};
+
+ bool operator == (const ACameraOutputTarget& other) const {
+ return mWindow == other.mWindow;
+ }
+ bool operator != (const ACameraOutputTarget& other) const {
+ return mWindow != other.mWindow;
+ }
+ bool operator < (const ACameraOutputTarget& other) const {
+ return mWindow < other.mWindow;
+ }
+ bool operator > (const ACameraOutputTarget& other) const {
+ return mWindow > other.mWindow;
+ }
+
+ android::acam::utils::native_handle_ptr_wrapper mWindow;
+};
diff --git a/camera/ndk/ndk_vendor/impl/utils.cpp b/camera/ndk/ndk_vendor/impl/utils.cpp
new file mode 100644
index 0000000..e4fb204
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/utils.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ACameraVendorUtils"
+
+#include <utils/Log.h>
+
+#include "utils.h"
+
+namespace android {
+namespace acam {
+namespace utils {
+
+// Convert CaptureRequest wrappable by sp<> to hidl CaptureRequest.
+frameworks::cameraservice::device::V2_0::CaptureRequest
+convertToHidl(const CaptureRequest *captureRequest) {
+ frameworks::cameraservice::device::V2_0::CaptureRequest hCaptureRequest;
+ hCaptureRequest.physicalCameraSettings = captureRequest->mCaptureRequest.physicalCameraSettings;
+ hCaptureRequest.streamAndWindowIds = captureRequest->mCaptureRequest.streamAndWindowIds;
+ return hCaptureRequest;
+}
+
+HRotation convertToHidl(int rotation) {
+ HRotation hRotation = HRotation::R0;
+ switch(rotation) {
+ case CAMERA3_STREAM_ROTATION_90:
+ hRotation = HRotation::R90;
+ break;
+ case CAMERA3_STREAM_ROTATION_180:
+ hRotation = HRotation::R180;
+ break;
+ case CAMERA3_STREAM_ROTATION_270:
+ hRotation = HRotation::R270;
+ break;
+ default:
+ break;
+ }
+ return hRotation;
+}
+
+bool convertFromHidlCloned(const HCameraMetadata &metadata, CameraMetadata *rawMetadata) {
+ const camera_metadata *buffer = (camera_metadata_t*)(metadata.data());
+ size_t expectedSize = metadata.size();
+ int ret = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ *rawMetadata = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from caller", __FUNCTION__);
+ return false;
+ }
+ return true;
+}
+
+// Note: existing data in dst will be gone. dst owns memory if shouldOwn is set
+// to true.
+void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst, bool shouldOwn) {
+ if (src == nullptr) {
+ return;
+ }
+ size_t size = get_camera_metadata_size(src);
+ dst->setToExternal((uint8_t *) src, size, shouldOwn);
+ return;
+}
+
+TemplateId convertToHidl(ACameraDevice_request_template templateId) {
+ switch(templateId) {
+ case TEMPLATE_STILL_CAPTURE:
+ return TemplateId::STILL_CAPTURE;
+ case TEMPLATE_RECORD:
+ return TemplateId::RECORD;
+ case TEMPLATE_VIDEO_SNAPSHOT:
+ return TemplateId::VIDEO_SNAPSHOT;
+ case TEMPLATE_ZERO_SHUTTER_LAG:
+ return TemplateId::ZERO_SHUTTER_LAG;
+ case TEMPLATE_MANUAL:
+ return TemplateId::MANUAL;
+ default:
+ return TemplateId::PREVIEW;
+ }
+}
+
+camera_status_t convertFromHidl(Status status) {
+ camera_status_t ret = ACAMERA_OK;
+ switch(status) {
+ case Status::NO_ERROR:
+ break;
+ case Status::DISCONNECTED:
+ ret = ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ break;
+ case Status::CAMERA_IN_USE:
+ ret = ACAMERA_ERROR_CAMERA_IN_USE;
+ break;
+ case Status::MAX_CAMERAS_IN_USE:
+ ret = ACAMERA_ERROR_MAX_CAMERA_IN_USE;
+ break;
+ case Status::ILLEGAL_ARGUMENT:
+ ret = ACAMERA_ERROR_INVALID_PARAMETER;
+ break;
+ case Status::DEPRECATED_HAL:
+ // Should not reach here since we filtered legacy HALs earlier
+ ret = ACAMERA_ERROR_INVALID_PARAMETER;
+ break;
+ case Status::DISABLED:
+ ret = ACAMERA_ERROR_CAMERA_DISABLED;
+ break;
+ case Status::PERMISSION_DENIED:
+ ret = ACAMERA_ERROR_PERMISSION_DENIED;
+ break;
+ case Status::INVALID_OPERATION:
+ ret = ACAMERA_ERROR_INVALID_OPERATION;
+ break;
+ default:
+ ret = ACAMERA_ERROR_UNKNOWN;
+ break;
+ }
+ return ret;
+}
+
+bool isWindowNativeHandleEqual(const native_handle_t *nh1, const native_handle_t *nh2) {
+ if (nh1->numFds !=0 || nh2->numFds !=0) {
+ ALOGE("Invalid window native handles being compared");
+ return false;
+ }
+ if (nh1->version != nh2->version || nh1->numFds != nh2->numFds ||
+ nh1->numInts != nh2->numInts) {
+ return false;
+ }
+ for (int i = 0; i < nh1->numInts; i++) {
+ if(nh1->data[i] != nh2->data[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool isWindowNativeHandleLessThan(const native_handle_t *nh1, const native_handle_t *nh2) {
+ if (isWindowNativeHandleEqual(nh1, nh2)) {
+ return false;
+ }
+ if (nh1->numInts != nh2->numInts) {
+ return nh1->numInts < nh2->numInts;
+ }
+
+ for (int i = 0; i < nh1->numInts; i++) {
+ if (nh1->data[i] != nh2->data[i]) {
+ return nh1->data[i] < nh2->data[i];
+ }
+ }
+ return false;
+}
+
+bool isWindowNativeHandleGreaterThan(const native_handle_t *nh1, const native_handle_t *nh2) {
+ return !isWindowNativeHandleLessThan(nh1, nh2) && !isWindowNativeHandleEqual(nh1, nh2);
+}
+
+bool areWindowNativeHandlesEqual(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle> handles2) {
+ if (handles1.size() != handles2.size()) {
+ return false;
+ }
+ for (int i = 0; i < handles1.size(); i++) {
+ if (!isWindowNativeHandleEqual(handles1[i], handles2[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool areWindowNativeHandlesLessThan(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2) {
+ if (handles1.size() != handles2.size()) {
+ return handles1.size() < handles2.size();
+ }
+ for (int i = 0; i < handles1.size(); i++) {
+ const native_handle_t *handle1 = handles1[i].getNativeHandle();
+ const native_handle_t *handle2 = handles2[i].getNativeHandle();
+ if (!isWindowNativeHandleEqual(handle1, handle2)) {
+ return isWindowNativeHandleLessThan(handle1, handle2);
+ }
+ }
+ return false;
+}
+
+} // namespace utils
+} // namespace acam
+} // namespace android
diff --git a/camera/ndk/ndk_vendor/impl/utils.h b/camera/ndk/ndk_vendor/impl/utils.h
new file mode 100644
index 0000000..f389f03
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/utils.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
+#include <android/frameworks/cameraservice/device/2.0/types.h>
+#include <camera/NdkCameraDevice.h>
+#include <CameraMetadata.h>
+#include <hardware/camera3.h>
+
+#ifndef CAMERA_NDK_VENDOR_H
+#define CAMERA_NDK_VENDOR_H
+
+using android::hardware::hidl_vec;
+using android::hardware::hidl_handle;
+
+namespace android {
+namespace acam {
+namespace utils {
+
+using CameraMetadata = hardware::camera::common::V1_0::helper::CameraMetadata;
+using HCameraMetadata = frameworks::cameraservice::service::V2_0::CameraMetadata;
+using Status = frameworks::cameraservice::common::V2_0::Status;
+using TemplateId = frameworks::cameraservice::device::V2_0::TemplateId;
+using PhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
+using HRotation = frameworks::cameraservice::device::V2_0::OutputConfiguration::Rotation;
+using OutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
+
+// Utility class so that CaptureRequest can be stored by sp<>
+struct CaptureRequest : public RefBase {
+ frameworks::cameraservice::device::V2_0::CaptureRequest mCaptureRequest;
+ std::vector<native_handle_t *> mSurfaceList;
+ //Physical camera settings metadata is stored here, since the capture request
+ //might not contain it. That's since, fmq might have consumed it.
+ hidl_vec<PhysicalCameraSettings> mPhysicalCameraSettings;
+};
+
+bool areWindowNativeHandlesEqual(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2);
+
+bool areWindowNativeHandlesLessThan(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2);
+
+bool isWindowNativeHandleEqual(const native_handle_t *nh1, const native_handle_t *nh2);
+
+bool isWindowNativeHandleLessThan(const native_handle_t *nh1, const native_handle_t *nh2);
+
+// Convenience wrapper over isWindowNativeHandleLessThan and isWindowNativeHandleEqual
+bool isWindowNativeHandleGreaterThan(const native_handle_t *nh1, const native_handle_t *nh2);
+
+// Utility class so the native_handle_t can be compared with its contents instead
+// of just raw pointer comparisons.
+struct native_handle_ptr_wrapper {
+ native_handle_t *mWindow = nullptr;
+
+ native_handle_ptr_wrapper(native_handle_t *nh) : mWindow(nh) { }
+
+ native_handle_ptr_wrapper() = default;
+
+ operator native_handle_t *() const { return mWindow; }
+
+ bool operator ==(const native_handle_ptr_wrapper other) const {
+ return isWindowNativeHandleEqual(mWindow, other.mWindow);
+ }
+
+ bool operator != (const native_handle_ptr_wrapper& other) const {
+ return !isWindowNativeHandleEqual(mWindow, other.mWindow);
+ }
+
+ bool operator < (const native_handle_ptr_wrapper& other) const {
+ return isWindowNativeHandleLessThan(mWindow, other.mWindow);
+ }
+
+ bool operator > (const native_handle_ptr_wrapper& other) const {
+ return !isWindowNativeHandleGreaterThan(mWindow, other.mWindow);
+ }
+
+};
+
+// Wrapper around OutputConfiguration. This is needed since HIDL
+// OutputConfiguration is auto-generated and marked final. Therefore, operator
+// overloads outside the class, will not get picked by clang while trying to
+// store OutputConfiguration in maps/sets.
+struct OutputConfigurationWrapper {
+ OutputConfiguration mOutputConfiguration;
+
+ operator const OutputConfiguration &() const {
+ return mOutputConfiguration;
+ }
+
+ OutputConfigurationWrapper() {
+ mOutputConfiguration.rotation = OutputConfiguration::Rotation::R0;
+ // The ndk currently doesn't support deferred surfaces
+ mOutputConfiguration.isDeferred = false;
+ mOutputConfiguration.width = 0;
+ mOutputConfiguration.height = 0;
+ // ndk doesn't support inter OutputConfiguration buffer sharing.
+ mOutputConfiguration.windowGroupId = -1;
+ };
+
+ OutputConfigurationWrapper(OutputConfiguration &outputConfiguration)
+ : mOutputConfiguration((outputConfiguration)) { }
+
+ bool operator ==(const OutputConfiguration &other) const {
+ const OutputConfiguration &self = mOutputConfiguration;
+ return self.rotation == other.rotation && self.windowGroupId == other.windowGroupId &&
+ self.physicalCameraId == other.physicalCameraId && self.width == other.width &&
+ self.height == other.height && self.isDeferred == other.isDeferred &&
+ areWindowNativeHandlesEqual(self.windowHandles, other.windowHandles);
+ }
+
+ bool operator < (const OutputConfiguration &other) const {
+ if (*this == other) {
+ return false;
+ }
+ const OutputConfiguration &self = mOutputConfiguration;
+ if (self.windowGroupId != other.windowGroupId) {
+ return self.windowGroupId < other.windowGroupId;
+ }
+
+ if (self.width != other.width) {
+ return self.width < other.width;
+ }
+
+ if (self.height != other.height) {
+ return self.height < other.height;
+ }
+
+ if (self.rotation != other.rotation) {
+ return static_cast<uint32_t>(self.rotation) < static_cast<uint32_t>(other.rotation);
+ }
+
+ if (self.isDeferred != other.isDeferred) {
+ return self.isDeferred < other.isDeferred;
+ }
+
+ if (self.physicalCameraId != other.physicalCameraId) {
+ return self.physicalCameraId < other.physicalCameraId;
+ }
+ return areWindowNativeHandlesLessThan(self.windowHandles, other.windowHandles);
+ }
+
+ bool operator != (const OutputConfiguration &other) const {
+ return !(*this == other);
+ }
+
+ bool operator > (const OutputConfiguration &other) const {
+ return (*this != other) && !(*this < other);
+ }
+};
+
+// Convert CaptureRequest wrappable by sp<> to hidl CaptureRequest.
+frameworks::cameraservice::device::V2_0::CaptureRequest convertToHidl(
+ const CaptureRequest *captureRequest);
+
+HRotation convertToHidl(int rotation);
+
+bool convertFromHidlCloned(const HCameraMetadata &metadata, CameraMetadata *rawMetadata);
+
+// Note: existing data in dst will be gone.
+void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst, bool shouldOwn = false);
+
+TemplateId convertToHidl(ACameraDevice_request_template templateId);
+
+camera_status_t convertFromHidl(Status status);
+
+} // namespace utils
+} // namespace acam
+} // namespace android
+
+#endif // CAMERA_NDK_VENDOR_H
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
new file mode 100644
index 0000000..37de30a
--- /dev/null
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AImageReaderVendorTest"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <unistd.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <mutex>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include <stdio.h>
+#include <stdio.h>
+
+#include <android/log.h>
+#include <camera/NdkCameraError.h>
+#include <camera/NdkCameraManager.h>
+#include <camera/NdkCameraDevice.h>
+#include <camera/NdkCameraCaptureSession.h>
+#include <media/NdkImage.h>
+#include <media/NdkImageReader.h>
+#include <cutils/native_handle.h>
+#include <VendorTagDescriptor.h>
+
+namespace {
+
+static constexpr int kDummyFenceFd = -1;
+static constexpr int kCaptureWaitUs = 100 * 1000;
+static constexpr int kCaptureWaitRetry = 10;
+static constexpr int kTestImageWidth = 640;
+static constexpr int kTestImageHeight = 480;
+static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888;
+
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
+
+class CameraHelper {
+ public:
+ CameraHelper(const char* id, ACameraManager *manager) :
+ mImgReaderAnw(nullptr), mCameraId(id), mCameraManager(manager) {}
+ ~CameraHelper() { closeCamera(); }
+
+ struct PhysicalImgReaderInfo {
+ const char* physicalCameraId;
+ native_handle_t* anw;
+ };
+ int initCamera(native_handle_t* imgReaderAnw,
+ const std::vector<PhysicalImgReaderInfo>& physicalImgReaders,
+ bool usePhysicalSettings) {
+ if (imgReaderAnw == nullptr) {
+ ALOGE("Cannot initialize camera before image reader get initialized.");
+ return -1;
+ }
+ if (mIsCameraReady) {
+ ALOGE("initCamera should only be called once.");
+ return -1;
+ }
+
+ int ret;
+ mImgReaderAnw = imgReaderAnw;
+
+ ret = ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice);
+ if (ret != AMEDIA_OK || mDevice == nullptr) {
+ ALOGE("Failed to open camera, ret=%d, mDevice=%p.", ret, mDevice);
+ return -1;
+ }
+
+ // Create capture session
+ ret = ACaptureSessionOutputContainer_create(&mOutputs);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureSessionOutputContainer_create failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACaptureSessionOutput_create(mImgReaderAnw, &mImgReaderOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureSessionOutput_create failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACaptureSessionOutputContainer_add(mOutputs, mImgReaderOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
+ return ret;
+ }
+
+ std::vector<const char*> idPointerList;
+ for (auto& physicalStream : physicalImgReaders) {
+ ACaptureSessionOutput* sessionOutput = nullptr;
+ ret = ACaptureSessionPhysicalOutput_create(physicalStream.anw,
+ physicalStream.physicalCameraId, &sessionOutput);
+ if (ret != ACAMERA_OK) {
+ ALOGE("ACaptureSessionPhysicalOutput_create failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACaptureSessionOutputContainer_add(mOutputs, sessionOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
+ return ret;
+ }
+ mExtraOutputs.push_back(sessionOutput);
+ // Assume that at most one physical stream per physical camera.
+ mPhysicalCameraIds.push_back(physicalStream.physicalCameraId);
+ idPointerList.push_back(physicalStream.physicalCameraId);
+ }
+ ACameraIdList cameraIdList;
+ cameraIdList.numCameras = idPointerList.size();
+ cameraIdList.cameraIds = idPointerList.data();
+
+ ret = ACameraDevice_isSessionConfigurationSupported(mDevice, mOutputs);
+ if (ret != ACAMERA_OK && ret != ACAMERA_ERROR_UNSUPPORTED_OPERATION) {
+ ALOGE("ACameraDevice_isSessionConfigurationSupported failed, ret=%d", ret);
+ return ret;
+ }
+
+ ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret);
+ return ret;
+ }
+
+ // Create capture request
+ if (usePhysicalSettings) {
+ ret = ACameraDevice_createCaptureRequest_withPhysicalIds(mDevice,
+ TEMPLATE_STILL_CAPTURE, &cameraIdList, &mStillRequest);
+ } else {
+ ret = ACameraDevice_createCaptureRequest(mDevice,
+ TEMPLATE_STILL_CAPTURE, &mStillRequest);
+ }
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACameraDevice_createCaptureRequest failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACameraOutputTarget_create(mImgReaderAnw, &mReqImgReaderOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACameraOutputTarget_create failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACaptureRequest_addTarget(mStillRequest, mReqImgReaderOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret);
+ return ret;
+ }
+
+ for (auto& physicalStream : physicalImgReaders) {
+ ACameraOutputTarget* outputTarget = nullptr;
+ ret = ACameraOutputTarget_create(physicalStream.anw, &outputTarget);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACameraOutputTarget_create failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACaptureRequest_addTarget(mStillRequest, outputTarget);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret);
+ return ret;
+ }
+ mReqExtraOutputs.push_back(outputTarget);
+ }
+
+ mIsCameraReady = true;
+ return 0;
+ }
+
+
+ bool isCameraReady() { return mIsCameraReady; }
+
+ void closeCamera() {
+ // Destroy capture request
+ if (mReqImgReaderOutput) {
+ ACameraOutputTarget_free(mReqImgReaderOutput);
+ mReqImgReaderOutput = nullptr;
+ }
+ for (auto& outputTarget : mReqExtraOutputs) {
+ ACameraOutputTarget_free(outputTarget);
+ }
+ mReqExtraOutputs.clear();
+ if (mStillRequest) {
+ ACaptureRequest_free(mStillRequest);
+ mStillRequest = nullptr;
+ }
+ // Destroy capture session
+ if (mSession != nullptr) {
+ ACameraCaptureSession_close(mSession);
+ mSession = nullptr;
+ }
+ if (mImgReaderOutput) {
+ ACaptureSessionOutput_free(mImgReaderOutput);
+ mImgReaderOutput = nullptr;
+ }
+ for (auto& extraOutput : mExtraOutputs) {
+ ACaptureSessionOutput_free(extraOutput);
+ }
+ mExtraOutputs.clear();
+ if (mOutputs) {
+ ACaptureSessionOutputContainer_free(mOutputs);
+ mOutputs = nullptr;
+ }
+ // Destroy camera device
+ if (mDevice) {
+ ACameraDevice_close(mDevice);
+ mDevice = nullptr;
+ }
+ mIsCameraReady = false;
+ }
+
+ int takePicture() {
+ int seqId;
+ return ACameraCaptureSession_capture(mSession, &mCaptureCallbacks, 1, &mStillRequest,
+ &seqId);
+ }
+
+ int takeLogicalCameraPicture() {
+ int seqId;
+ return ACameraCaptureSession_logicalCamera_capture(mSession, &mLogicalCaptureCallbacks,
+ 1, &mStillRequest, &seqId);
+ }
+
+ bool checkCallbacks(int pictureCount) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mCompletedCaptureCallbackCount != pictureCount) {
+ ALOGE("Completed capture callaback count not as expected. expected %d actual %d",
+ pictureCount, mCompletedCaptureCallbackCount);
+ return false;
+ }
+ return true;
+ }
+
+ static void onDeviceDisconnected(void* /*obj*/, ACameraDevice* /*device*/) {}
+
+ static void onDeviceError(void* /*obj*/, ACameraDevice* /*device*/, int /*errorCode*/) {}
+
+ static void onSessionClosed(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
+
+ static void onSessionReady(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
+
+ static void onSessionActive(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
+
+ private:
+ ACameraDevice_StateCallbacks mDeviceCb{this, onDeviceDisconnected,
+ onDeviceError};
+ ACameraCaptureSession_stateCallbacks mSessionCb{
+ this, onSessionClosed, onSessionReady, onSessionActive};
+
+ native_handle_t* mImgReaderAnw = nullptr; // not owned by us.
+
+ // Camera device
+ ACameraDevice* mDevice = nullptr;
+ // Capture session
+ ACaptureSessionOutputContainer* mOutputs = nullptr;
+ ACaptureSessionOutput* mImgReaderOutput = nullptr;
+ std::vector<ACaptureSessionOutput*> mExtraOutputs;
+
+ ACameraCaptureSession* mSession = nullptr;
+ // Capture request
+ ACaptureRequest* mStillRequest = nullptr;
+ ACameraOutputTarget* mReqImgReaderOutput = nullptr;
+ std::vector<ACameraOutputTarget*> mReqExtraOutputs;
+
+ bool mIsCameraReady = false;
+ const char* mCameraId;
+ ACameraManager* mCameraManager;
+ int mCompletedCaptureCallbackCount = 0;
+ std::mutex mMutex;
+ ACameraCaptureSession_captureCallbacks mCaptureCallbacks = {
+ // TODO: Add tests for other callbacks
+ this, // context
+ nullptr, // onCaptureStarted
+ nullptr, // onCaptureProgressed
+ [](void* ctx , ACameraCaptureSession *, ACaptureRequest *,
+ const ACameraMetadata *) {
+ CameraHelper *ch = static_cast<CameraHelper *>(ctx);
+ std::lock_guard<std::mutex> lock(ch->mMutex);
+ ch->mCompletedCaptureCallbackCount++;
+ },
+ nullptr, // onCaptureFailed
+ nullptr, // onCaptureSequenceCompleted
+ nullptr, // onCaptureSequenceAborted
+ nullptr, // onCaptureBufferLost
+ };
+
+ std::vector<std::string> mPhysicalCameraIds;
+ ACameraCaptureSession_logicalCamera_captureCallbacks mLogicalCaptureCallbacks = {
+ // TODO: Add tests for other callbacks
+ this, // context
+ nullptr, // onCaptureStarted
+ nullptr, // onCaptureProgressed
+ [](void* ctx , ACameraCaptureSession *, ACaptureRequest *,
+ const ACameraMetadata *, size_t physicalResultCount,
+ const char** physicalCameraIds, const ACameraMetadata** physicalResults) {
+ CameraHelper *ch = static_cast<CameraHelper *>(ctx);
+ std::lock_guard<std::mutex> lock(ch->mMutex);
+ ASSERT_EQ(physicalResultCount, ch->mPhysicalCameraIds.size());
+ for (size_t i = 0; i < physicalResultCount; i++) {
+ ASSERT_TRUE(physicalCameraIds[i] != nullptr);
+ ASSERT_TRUE(physicalResults[i] != nullptr);
+ ASSERT_NE(std::find(ch->mPhysicalCameraIds.begin(),
+ ch->mPhysicalCameraIds.end(), physicalCameraIds[i]),
+ ch->mPhysicalCameraIds.end());
+
+ // Verify frameNumber and sensorTimestamp exist in physical
+ // result metadata
+ ACameraMetadata_const_entry entry;
+ ACameraMetadata_getConstEntry(
+ physicalResults[i], ACAMERA_SYNC_FRAME_NUMBER, &entry);
+ ASSERT_EQ(entry.count, 1);
+ ACameraMetadata_getConstEntry(
+ physicalResults[i], ACAMERA_SENSOR_TIMESTAMP, &entry);
+ ASSERT_EQ(entry.count, 1);
+ }
+ ch->mCompletedCaptureCallbackCount++;
+ },
+ [] (void * /*ctx*/, ACameraCaptureSession* /*session*/, ACaptureRequest* /*request*/,
+ ALogicalCameraCaptureFailure* failure) {
+ if (failure->physicalCameraId) {
+ ALOGD("%s: Physical camera id: %s result failure", __FUNCTION__,
+ failure->physicalCameraId);
+ }
+ },
+ nullptr, // onCaptureSequenceCompleted
+ nullptr, // onCaptureSequenceAborted
+ nullptr, // onCaptureBufferLost
+ };
+};
+
+class ImageReaderTestCase {
+ public:
+ ImageReaderTestCase(int32_t width,
+ int32_t height,
+ int32_t format,
+ uint64_t usage,
+ int32_t maxImages,
+ bool async)
+ : mWidth(width),
+ mHeight(height),
+ mFormat(format),
+ mUsage(usage),
+ mMaxImages(maxImages),
+ mAsync(async) {}
+
+ ~ImageReaderTestCase() {
+ if (mImgReaderAnw) {
+ AImageReader_delete(mImgReader);
+ // No need to call native_handle_t_release on imageReaderAnw
+ }
+ }
+
+ int initImageReader() {
+ if (mImgReader != nullptr || mImgReaderAnw != nullptr) {
+ ALOGE("Cannot re-initalize image reader, mImgReader=%p, mImgReaderAnw=%p", mImgReader,
+ mImgReaderAnw);
+ return -1;
+ }
+
+ media_status_t ret = AImageReader_newWithUsage(
+ mWidth, mHeight, mFormat, mUsage, mMaxImages, &mImgReader);
+ if (ret != AMEDIA_OK || mImgReader == nullptr) {
+ ALOGE("Failed to create new AImageReader, ret=%d, mImgReader=%p", ret, mImgReader);
+ return -1;
+ }
+
+ ret = AImageReader_setImageListener(mImgReader, &mReaderAvailableCb);
+ if (ret != AMEDIA_OK) {
+ ALOGE("Failed to set image available listener, ret=%d.", ret);
+ return ret;
+ }
+
+ ret = AImageReader_setBufferRemovedListener(mImgReader, &mReaderDetachedCb);
+ if (ret != AMEDIA_OK) {
+ ALOGE("Failed to set buffer detaching listener, ret=%d.", ret);
+ return ret;
+ }
+
+ ret = AImageReader_getWindowNativeHandle(mImgReader, &mImgReaderAnw);
+ if (ret != AMEDIA_OK || mImgReaderAnw == nullptr) {
+ ALOGE("Failed to get native_handle_t from AImageReader, ret=%d, mImgReaderAnw=%p.", ret,
+ mImgReaderAnw);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ native_handle_t* getNativeWindow() { return mImgReaderAnw; }
+
+ int getAcquiredImageCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mAcquiredImageCount;
+ }
+
+ void HandleImageAvailable(AImageReader* reader) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ AImage* outImage = nullptr;
+ media_status_t ret;
+
+ // Make sure AImage will be deleted automatically when it goes out of
+ // scope.
+ auto imageDeleter = [this](AImage* img) {
+ if (mAsync) {
+ AImage_deleteAsync(img, kDummyFenceFd);
+ } else {
+ AImage_delete(img);
+ }
+ };
+ std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
+
+ if (mAsync) {
+ int outFenceFd = 0;
+ // Verity that outFenceFd's value will be changed by
+ // AImageReader_acquireNextImageAsync.
+ ret = AImageReader_acquireNextImageAsync(reader, &outImage, &outFenceFd);
+ if (ret != AMEDIA_OK || outImage == nullptr || outFenceFd == 0) {
+ ALOGE("Failed to acquire image, ret=%d, outIamge=%p, outFenceFd=%d.", ret, outImage,
+ outFenceFd);
+ return;
+ }
+ img.reset(outImage);
+ } else {
+ ret = AImageReader_acquireNextImage(reader, &outImage);
+ if (ret != AMEDIA_OK || outImage == nullptr) {
+ ALOGE("Failed to acquire image, ret=%d, outIamge=%p.", ret, outImage);
+ return;
+ }
+ img.reset(outImage);
+ }
+
+ AHardwareBuffer* outBuffer = nullptr;
+ ret = AImage_getHardwareBuffer(img.get(), &outBuffer);
+ if (ret != AMEDIA_OK || outBuffer == nullptr) {
+ ALOGE("Faild to get hardware buffer, ret=%d, outBuffer=%p.", ret, outBuffer);
+ return;
+ }
+
+ // No need to release AHardwareBuffer, since we don't acquire additional
+ // reference to it.
+ AHardwareBuffer_Desc outDesc;
+ AHardwareBuffer_describe(outBuffer, &outDesc);
+ int32_t imageWidth = 0;
+ int32_t imageHeight = 0;
+ int32_t bufferWidth = static_cast<int32_t>(outDesc.width);
+ int32_t bufferHeight = static_cast<int32_t>(outDesc.height);
+
+ AImage_getWidth(outImage, &imageWidth);
+ AImage_getHeight(outImage, &imageHeight);
+ if (imageWidth != mWidth || imageHeight != mHeight) {
+ ALOGE("Mismatched output image dimension: expected=%dx%d, actual=%dx%d", mWidth,
+ mHeight, imageWidth, imageHeight);
+ return;
+ }
+
+ if (mFormat == AIMAGE_FORMAT_RGBA_8888 ||
+ mFormat == AIMAGE_FORMAT_RGBX_8888 ||
+ mFormat == AIMAGE_FORMAT_RGB_888 ||
+ mFormat == AIMAGE_FORMAT_RGB_565 ||
+ mFormat == AIMAGE_FORMAT_RGBA_FP16 ||
+ mFormat == AIMAGE_FORMAT_YUV_420_888 ||
+ mFormat == AIMAGE_FORMAT_Y8) {
+ // Check output buffer dimension for certain formats. Don't do this for blob based
+ // formats.
+ if (bufferWidth != mWidth || bufferHeight != mHeight) {
+ ALOGE("Mismatched output buffer dimension: expected=%dx%d, actual=%dx%d", mWidth,
+ mHeight, bufferWidth, bufferHeight);
+ return;
+ }
+ }
+
+ if ((outDesc.usage & mUsage) != mUsage) {
+ ALOGE("Mismatched output buffer usage: actual (%" PRIu64 "), expected (%" PRIu64 ")",
+ outDesc.usage, mUsage);
+ return;
+ }
+
+ uint8_t* data = nullptr;
+ int dataLength = 0;
+ ret = AImage_getPlaneData(img.get(), 0, &data, &dataLength);
+ if (mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) {
+ // When we have CPU_READ_OFTEN usage bits, we can lock the image.
+ if (ret != AMEDIA_OK || data == nullptr || dataLength < 0) {
+ ALOGE("Failed to access CPU data, ret=%d, data=%p, dataLength=%d", ret, data,
+ dataLength);
+ return;
+ }
+ } else {
+ if (ret != AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE || data != nullptr || dataLength != 0) {
+ ALOGE("Shouldn't be able to access CPU data, ret=%d, data=%p, dataLength=%d", ret,
+ data, dataLength);
+ return;
+ }
+ }
+ // Only increase mAcquiredImageCount if all checks pass.
+ mAcquiredImageCount++;
+ }
+
+ static void onImageAvailable(void* obj, AImageReader* reader) {
+ ImageReaderTestCase* thiz = reinterpret_cast<ImageReaderTestCase*>(obj);
+ thiz->HandleImageAvailable(reader);
+ }
+
+ static void
+ onBufferRemoved(void* /*obj*/, AImageReader* /*reader*/, AHardwareBuffer* /*buffer*/) {
+ // No-op, just to check the listener can be set properly.
+ }
+
+ private:
+ int32_t mWidth;
+ int32_t mHeight;
+ int32_t mFormat;
+ uint64_t mUsage;
+ int32_t mMaxImages;
+ bool mAsync;
+
+ std::mutex mMutex;
+ int mAcquiredImageCount{0};
+
+ AImageReader* mImgReader = nullptr;
+ native_handle_t* mImgReaderAnw = nullptr;
+
+ AImageReader_ImageListener mReaderAvailableCb{this, onImageAvailable};
+ AImageReader_BufferRemovedListener mReaderDetachedCb{this, onBufferRemoved};
+};
+
+
+class AImageReaderVendorTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ mCameraManager = ACameraManager_create();
+ if (mCameraManager == nullptr) {
+ ALOGE("Failed to create ACameraManager.");
+ return;
+ }
+
+ camera_status_t ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Failed to get cameraIdList: ret=%d", ret);
+ return;
+ }
+ // TODO: Add more rigorous tests for vendor tags
+ ASSERT_NE(VendorTagDescriptorCache::getGlobalVendorTagCache(), nullptr);
+ if (mCameraIdList->numCameras < 1) {
+ ALOGW("Device has no camera on board.");
+ return;
+ }
+ }
+ void TearDown() override {
+ // Destroy camera manager
+ if (mCameraIdList) {
+ ACameraManager_deleteCameraIdList(mCameraIdList);
+ mCameraIdList = nullptr;
+ }
+ if (mCameraManager) {
+ ACameraManager_delete(mCameraManager);
+ mCameraManager = nullptr;
+ }
+ }
+
+ bool takePictures(const char* id, uint64_t readerUsage, int readerMaxImages,
+ bool readerAsync, int pictureCount) {
+ int ret = 0;
+
+ ImageReaderTestCase testCase(
+ kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage, readerMaxImages,
+ readerAsync);
+ ret = testCase.initImageReader();
+ if (ret < 0) {
+ ALOGE("Unable to initialize ImageReader");
+ return false;
+ }
+
+ CameraHelper cameraHelper(id, mCameraManager);
+ ret = cameraHelper.initCamera(testCase.getNativeWindow(),
+ {}/*physicalImageReaders*/, false/*usePhysicalSettings*/);
+ if (ret < 0) {
+ ALOGE("Unable to initialize camera helper");
+ return false;
+ }
+
+ if (!cameraHelper.isCameraReady()) {
+ ALOGW("Camera is not ready after successful initialization. It's either due to camera "
+ "on board lacks BACKWARDS_COMPATIBLE capability or the device does not have "
+ "camera on board.");
+ return true;
+ }
+
+ for (int i = 0; i < pictureCount; i++) {
+ ret = cameraHelper.takePicture();
+ if (ret < 0) {
+ ALOGE("Unable to take picture");
+ return false;
+ }
+ }
+
+ // Sleep until all capture finished
+ for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
+ usleep(kCaptureWaitUs);
+ if (testCase.getAcquiredImageCount() == pictureCount) {
+ ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
+ pictureCount);
+ break;
+ }
+ }
+ return testCase.getAcquiredImageCount() == pictureCount &&
+ cameraHelper.checkCallbacks(pictureCount);
+ }
+
+ bool testTakePicturesNative(const char* id) {
+ for (auto& readerUsage :
+ {AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN}) {
+ for (auto& readerMaxImages : {1, 4, 8}) {
+ for (auto& readerAsync : {true, false}) {
+ for (auto& pictureCount : {1, 4, 8}) {
+ if (!takePictures(id, readerUsage, readerMaxImages,
+ readerAsync, pictureCount)) {
+ ALOGE("Test takePictures failed for test case usage=%" PRIu64
+ ", maxImages=%d, async=%d, pictureCount=%d",
+ readerUsage, readerMaxImages, readerAsync, pictureCount);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ // Camera manager
+ ACameraManager* mCameraManager = nullptr;
+ ACameraIdList* mCameraIdList = nullptr;
+
+ bool isCapabilitySupported(ACameraMetadata* staticInfo,
+ acamera_metadata_enum_android_request_available_capabilities_t cap) {
+ ACameraMetadata_const_entry entry;
+ ACameraMetadata_getConstEntry(
+ staticInfo, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ for (uint32_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == cap) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool isSizeSupportedForFormat(ACameraMetadata* staticInfo,
+ int32_t format, int32_t width, int32_t height) {
+ ACameraMetadata_const_entry entry;
+ ACameraMetadata_getConstEntry(staticInfo,
+ ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
+ for (uint32_t i = 0; i < entry.count; i += 4) {
+ if (entry.data.i32[i] == format &&
+ entry.data.i32[i+3] == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ entry.data.i32[i+1] == width &&
+ entry.data.i32[i+2] == height) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void findCandidateLogicalCamera(const char **cameraId,
+ ACameraMetadata** staticMetadata,
+ std::vector<const char*>* candidatePhysicalIds) {
+ // Find first available logical camera
+ for (int i = 0; i < mCameraIdList->numCameras; i++) {
+ camera_status_t ret;
+ ret = ACameraManager_getCameraCharacteristics(
+ mCameraManager, mCameraIdList->cameraIds[i], staticMetadata);
+ ASSERT_EQ(ret, ACAMERA_OK);
+ ASSERT_NE(*staticMetadata, nullptr);
+
+ if (!isCapabilitySupported(*staticMetadata,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) {
+ ACameraMetadata_free(*staticMetadata);
+ *staticMetadata = nullptr;
+ continue;
+ }
+
+ // Check returned physical camera Ids are valid
+ size_t physicalCameraIdCnt = 0;
+ const char*const* physicalCameraIds = nullptr;
+ bool isLogicalCamera = ACameraMetadata_isLogicalMultiCamera(*staticMetadata,
+ &physicalCameraIdCnt, &physicalCameraIds);
+ ASSERT_TRUE(isLogicalCamera);
+ ASSERT_GE(physicalCameraIdCnt, 2);
+ ACameraMetadata* physicalCameraMetadata = nullptr;
+ candidatePhysicalIds->clear();
+ for (size_t j = 0; j < physicalCameraIdCnt && candidatePhysicalIds->size() < 2; j++) {
+ ASSERT_GT(strlen(physicalCameraIds[j]), 0);
+ ret = ACameraManager_getCameraCharacteristics(
+ mCameraManager, physicalCameraIds[j], &physicalCameraMetadata);
+ ASSERT_EQ(ret, ACAMERA_OK);
+ ASSERT_NE(physicalCameraMetadata, nullptr);
+
+ if (isSizeSupportedForFormat(physicalCameraMetadata, kTestImageFormat,
+ kTestImageWidth, kTestImageHeight)) {
+ candidatePhysicalIds->push_back(physicalCameraIds[j]);
+ }
+ ACameraMetadata_free(physicalCameraMetadata);
+ }
+ if (candidatePhysicalIds->size() == 2) {
+ *cameraId = mCameraIdList->cameraIds[i];
+ return;
+ } else {
+ ACameraMetadata_free(*staticMetadata);
+ *staticMetadata = nullptr;
+ }
+ }
+ *cameraId = nullptr;
+ return;
+ }
+
+ void testLogicalCameraPhysicalStream(bool usePhysicalSettings) {
+ const char* cameraId = nullptr;
+ ACameraMetadata* staticMetadata = nullptr;
+ std::vector<const char*> physicalCameraIds;
+
+ findCandidateLogicalCamera(&cameraId, &staticMetadata, &physicalCameraIds);
+ if (cameraId == nullptr) {
+ // Couldn't find logical camera to test
+ return;
+ }
+
+ // Test streaming the logical multi-camera
+ uint64_t readerUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
+ int32_t readerMaxImages = 8;
+ bool readerAsync = false;
+ const int pictureCount = 6;
+ std::vector<ImageReaderTestCase*> testCases;
+ for (size_t i = 0; i < 3; i++) {
+ ImageReaderTestCase* testCase = new ImageReaderTestCase(
+ kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage,
+ readerMaxImages, readerAsync);
+ ASSERT_EQ(testCase->initImageReader(), 0);
+ testCases.push_back(testCase);
+ }
+
+ CameraHelper cameraHelper(cameraId, mCameraManager);
+ std::vector<CameraHelper::PhysicalImgReaderInfo> physicalImgReaderInfo;
+ physicalImgReaderInfo.push_back({physicalCameraIds[0], testCases[1]->getNativeWindow()});
+ physicalImgReaderInfo.push_back({physicalCameraIds[1], testCases[2]->getNativeWindow()});
+
+ int ret = cameraHelper.initCamera(testCases[0]->getNativeWindow(),
+ physicalImgReaderInfo, usePhysicalSettings);
+ ASSERT_EQ(ret, 0);
+
+ if (!cameraHelper.isCameraReady()) {
+ ALOGW("Camera is not ready after successful initialization. It's either due to camera "
+ "on board lacks BACKWARDS_COMPATIBLE capability or the device does not have "
+ "camera on board.");
+ return;
+ }
+
+ for (int i = 0; i < pictureCount; i++) {
+ ret = cameraHelper.takeLogicalCameraPicture();
+ ASSERT_EQ(ret, 0);
+ }
+
+ // Sleep until all capture finished
+ for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
+ usleep(kCaptureWaitUs);
+ if (testCases[0]->getAcquiredImageCount() == pictureCount) {
+ ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
+ pictureCount);
+ break;
+ }
+ }
+ ASSERT_EQ(testCases[0]->getAcquiredImageCount(), pictureCount);
+ ASSERT_EQ(testCases[1]->getAcquiredImageCount(), pictureCount);
+ ASSERT_EQ(testCases[2]->getAcquiredImageCount(), pictureCount);
+ ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
+
+ ACameraMetadata_free(staticMetadata);
+ }
+};
+
+TEST_F(AImageReaderVendorTest, CreateWindowNativeHandle) {
+ // We always use the first camera.
+ const char* cameraId = mCameraIdList->cameraIds[0];
+ ASSERT_TRUE(cameraId != nullptr);
+
+ ACameraMetadata* staticMetadata = nullptr;
+ camera_status_t ret = ACameraManager_getCameraCharacteristics(
+ mCameraManager, cameraId, &staticMetadata);
+ ASSERT_EQ(ret, ACAMERA_OK);
+ ASSERT_NE(staticMetadata, nullptr);
+
+ bool isBC = isCapabilitySupported(staticMetadata,
+ ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
+
+ uint32_t namedTag = 0;
+ // Test that ACameraMetadata_getTagFromName works as expected for public tag
+ // names
+ camera_status_t status = ACameraManager_getTagFromName(mCameraManager, cameraId,
+ "android.control.aeMode", &namedTag);
+
+ ASSERT_EQ(status, ACAMERA_OK);
+ ASSERT_EQ(namedTag, ACAMERA_CONTROL_AE_MODE);
+
+ ACameraMetadata_free(staticMetadata);
+
+ if (!isBC) {
+ ALOGW("Camera does not support BACKWARD_COMPATIBLE.");
+ return;
+ }
+
+ EXPECT_TRUE(testTakePicturesNative(cameraId));
+}
+
+TEST_F(AImageReaderVendorTest, LogicalCameraPhysicalStream) {
+ testLogicalCameraPhysicalStream(false/*usePhysicalSettings*/);
+ testLogicalCameraPhysicalStream(true/*usePhysicalSettings*/);
+}
+
+} // namespace
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
index 659484f..e5c1631 100644
--- a/camera/tests/Android.mk
+++ b/camera/tests/Android.mk
@@ -19,7 +19,8 @@
LOCAL_SRC_FILES:= \
VendorTagDescriptorTests.cpp \
CameraBinderTests.cpp \
- CameraZSLTests.cpp
+ CameraZSLTests.cpp \
+ CameraCharacteristicsPermission.cpp
LOCAL_SHARED_LIBRARIES := \
liblog \
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 1de7013..8fe029a 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -29,6 +29,7 @@
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <system/graphics.h>
+#include <hardware/camera3.h>
#include <hardware/gralloc.h>
#include <camera/CameraMetadata.h>
@@ -40,6 +41,7 @@
#include <android/hardware/camera2/BnCameraDeviceCallbacks.h>
#include <camera/camera2/CaptureRequest.h>
#include <camera/camera2/OutputConfiguration.h>
+#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/SubmitInfo.h>
#include <gui/BufferItemConsumer.h>
@@ -55,6 +57,8 @@
#include <algorithm>
using namespace android;
+using ::android::hardware::ICameraServiceDefault;
+using ::android::hardware::camera2::ICameraDeviceUser;
#define ASSERT_NOT_NULL(x) \
ASSERT_TRUE((x) != nullptr)
@@ -86,6 +90,11 @@
return binder::Status::ok();
};
+ virtual binder::Status onCameraAccessPrioritiesChanged() {
+ // No op
+ return binder::Status::ok();
+ }
+
bool waitForNumCameras(size_t num) const {
Mutex::Autolock l(mLock);
@@ -476,7 +485,8 @@
sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false));
- OutputConfiguration output(gbProducer, /*rotation*/0);
+ String16 noPhysicalId;
+ OutputConfiguration output(gbProducer, /*rotation*/0, noPhysicalId);
// Can we configure?
res = device->beginConfigure();
@@ -490,6 +500,19 @@
EXPECT_TRUE(res.isOk()) << res;
EXPECT_FALSE(callbacks->hadError());
+ // Session configuration must also be supported in this case
+ SessionConfiguration sessionConfiguration = { /*inputWidth*/ 0, /*inputHeight*/0,
+ /*inputFormat*/ -1, CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE};
+ sessionConfiguration.addOutputConfiguration(output);
+ bool queryStatus;
+ res = device->isSessionConfigurationSupported(sessionConfiguration, &queryStatus);
+ EXPECT_TRUE(res.isOk() ||
+ (res.serviceSpecificErrorCode() == ICameraServiceDefault::ERROR_INVALID_OPERATION))
+ << res;
+ if (res.isOk()) {
+ EXPECT_TRUE(queryStatus);
+ }
+
// Can we make requests?
CameraMetadata requestTemplate;
res = device->createDefaultRequest(/*preview template*/1,
diff --git a/camera/tests/CameraCharacteristicsPermission.cpp b/camera/tests/CameraCharacteristicsPermission.cpp
new file mode 100644
index 0000000..135d2a3
--- /dev/null
+++ b/camera/tests/CameraCharacteristicsPermission.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "CameraCharacteristicsPermission"
+
+#include <gtest/gtest.h>
+
+#include <binder/ProcessState.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <camera/CameraMetadata.h>
+#include <camera/Camera.h>
+#include <android/hardware/ICameraService.h>
+
+using namespace android;
+using namespace android::hardware;
+
+class CameraCharacteristicsPermission : public ::testing::Test {
+protected:
+
+ CameraCharacteristicsPermission() : numCameras(0){}
+ //Gtest interface
+ void SetUp() override;
+ void TearDown() override;
+
+ int32_t numCameras;
+ sp<ICameraService> mCameraService;
+};
+
+void CameraCharacteristicsPermission::SetUp() {
+ ::android::binder::Status rc;
+ ProcessState::self()->startThreadPool();
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.camera"));
+ mCameraService = interface_cast<ICameraService>(binder);
+ rc = mCameraService->getNumberOfCameras(
+ hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras);
+ EXPECT_TRUE(rc.isOk());
+}
+
+void CameraCharacteristicsPermission::TearDown() {
+ mCameraService.clear();
+}
+
+// Revoking and acquiring permissions automatically might not be possible.
+// Test the functionality for removal of camera characteristics needing
+// a camera permission.
+TEST_F(CameraCharacteristicsPermission, TestCameraPermission) {
+ for (int32_t cameraId = 0; cameraId < numCameras; cameraId++) {
+
+ String16 cameraIdStr = String16(String8::format("%d", cameraId));
+ bool isSupported = false;
+ auto rc = mCameraService->supportsCameraApi(cameraIdStr,
+ hardware::ICameraService::API_VERSION_2, &isSupported);
+ EXPECT_TRUE(rc.isOk());
+ if (!isSupported) {
+ continue;
+ }
+
+ CameraMetadata metadata;
+ std::vector<int32_t> tagsNeedingPermission;
+ rc = mCameraService->getCameraCharacteristics(cameraIdStr, &metadata);
+ ASSERT_TRUE(rc.isOk());
+ EXPECT_FALSE(metadata.isEmpty());
+ EXPECT_EQ(metadata.removePermissionEntries(CAMERA_METADATA_INVALID_VENDOR_ID,
+ &tagsNeedingPermission), NO_ERROR);
+ camera_metadata_entry_t availableCharacteristics =
+ metadata.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ EXPECT_TRUE(0 < availableCharacteristics.count);
+
+ std::vector<uint32_t> availableKeys;
+ availableKeys.reserve(availableCharacteristics.count);
+ availableKeys.insert(availableKeys.begin(), availableCharacteristics.data.i32,
+ availableCharacteristics.data.i32 + availableCharacteristics.count);
+
+ for (const auto &key : tagsNeedingPermission) {
+ ASSERT_FALSE(metadata.exists(key));
+ auto it = std::find(availableKeys.begin(), availableKeys.end(), key);
+ ASSERT_TRUE(it == availableKeys.end());
+ }
+ }
+}
diff --git a/cmds/screenrecord/Android.bp b/cmds/screenrecord/Android.bp
new file mode 100644
index 0000000..86476cd
--- /dev/null
+++ b/cmds/screenrecord/Android.bp
@@ -0,0 +1,55 @@
+// Copyright 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+ name: "screenrecord",
+
+ srcs: [
+ "screenrecord.cpp",
+ "EglWindow.cpp",
+ "FrameOutput.cpp",
+ "TextRenderer.cpp",
+ "Overlay.cpp",
+ "Program.cpp",
+ ],
+
+ shared_libs: [
+ "libstagefright",
+ "libmedia",
+ "libmedia_omx",
+ "libutils",
+ "libbinder",
+ "libstagefright_foundation",
+ "libjpeg",
+ "libui",
+ "libgui",
+ "libcutils",
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright",
+ "frameworks/av/media/libstagefright/include",
+ "frameworks/native/include/media/openmax",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-multichar",
+ //"-UNDEBUG",
+ ]
+}
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
deleted file mode 100644
index 5e83ed6..0000000
--- a/cmds/screenrecord/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- screenrecord.cpp \
- EglWindow.cpp \
- FrameOutput.cpp \
- TextRenderer.cpp \
- Overlay.cpp \
- Program.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmedia_omx libutils libbinder libstagefright_foundation \
- libjpeg libui libgui libcutils liblog libEGL libGLESv2
-
-LOCAL_C_INCLUDES := \
- frameworks/av/media/libstagefright \
- frameworks/av/media/libstagefright/include \
- frameworks/native/include/media/openmax \
- external/jpeg
-
-LOCAL_CFLAGS := -Werror -Wall
-LOCAL_CFLAGS += -Wno-multichar
-#LOCAL_CFLAGS += -UNDEBUG
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= screenrecord
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index d1859d1..7aa655f 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -48,6 +48,7 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaMuxer.h>
#include <media/stagefright/PersistentSurface.h>
@@ -58,7 +59,35 @@
#include "Overlay.h"
#include "FrameOutput.h"
-using namespace android;
+using android::ABuffer;
+using android::ALooper;
+using android::AMessage;
+using android::AString;
+using android::DisplayInfo;
+using android::FrameOutput;
+using android::IBinder;
+using android::IGraphicBufferProducer;
+using android::ISurfaceComposer;
+using android::MediaCodec;
+using android::MediaCodecBuffer;
+using android::MediaMuxer;
+using android::Overlay;
+using android::PersistentSurface;
+using android::ProcessState;
+using android::Rect;
+using android::String8;
+using android::SurfaceComposerClient;
+using android::Vector;
+using android::sp;
+using android::status_t;
+
+using android::DISPLAY_ORIENTATION_0;
+using android::DISPLAY_ORIENTATION_180;
+using android::DISPLAY_ORIENTATION_90;
+using android::INVALID_OPERATION;
+using android::NAME_NOT_FOUND;
+using android::NO_ERROR;
+using android::UNKNOWN_ERROR;
static const uint32_t kMinBitRate = 100000; // 0.1Mbps
static const uint32_t kMaxBitRate = 200 * 1000000; // 200Mbps
@@ -73,7 +102,7 @@
static bool gMonotonicTime = false; // use system monotonic time for timestamps
static bool gPersistentSurface = false; // use persistent surface
static enum {
- FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES
+ FORMAT_MP4, FORMAT_H264, FORMAT_WEBM, FORMAT_3GPP, FORMAT_FRAMES, FORMAT_RAW_FRAMES
} gOutputFormat = FORMAT_MP4; // data format for output
static AString gCodecName = ""; // codec name override
static bool gSizeSpecified = false; // was size explicitly requested?
@@ -83,6 +112,7 @@
static uint32_t gVideoHeight = 0;
static uint32_t gBitRate = 20000000; // 20Mbps
static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
+static uint32_t gBframes = 0;
// Set by signal handler to stop recording.
static volatile bool gStopRequested = false;
@@ -154,15 +184,20 @@
}
sp<AMessage> format = new AMessage;
- format->setInt32("width", gVideoWidth);
- format->setInt32("height", gVideoHeight);
- format->setString("mime", kMimeTypeAvc);
- format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
- format->setInt32("bitrate", gBitRate);
- format->setFloat("frame-rate", displayFps);
- format->setInt32("i-frame-interval", 10);
+ format->setInt32(KEY_WIDTH, gVideoWidth);
+ format->setInt32(KEY_HEIGHT, gVideoHeight);
+ format->setString(KEY_MIME, kMimeTypeAvc);
+ format->setInt32(KEY_COLOR_FORMAT, OMX_COLOR_FormatAndroidOpaque);
+ format->setInt32(KEY_BIT_RATE, gBitRate);
+ format->setFloat(KEY_FRAME_RATE, displayFps);
+ format->setInt32(KEY_I_FRAME_INTERVAL, 10);
+ format->setInt32(KEY_MAX_B_FRAMES, gBframes);
+ if (gBframes > 0) {
+ format->setInt32(KEY_PROFILE, AVCProfileMain);
+ format->setInt32(KEY_LEVEL, AVCLevel41);
+ }
- sp<ALooper> looper = new ALooper;
+ sp<android::ALooper> looper = new android::ALooper;
looper->setName("screenrecord_looper");
looper->start();
ALOGV("Creating codec");
@@ -235,10 +270,10 @@
// Set the region of the layer stack we're interested in, which in our
// case is "all of it".
- Rect layerStackRect(mainDpyInfo.w, mainDpyInfo.h);
+ Rect layerStackRect(mainDpyInfo.viewportW, mainDpyInfo.viewportH);
// We need to preserve the aspect ratio of the display.
- float displayAspect = (float) mainDpyInfo.h / (float) mainDpyInfo.w;
+ float displayAspect = (float) mainDpyInfo.viewportH / (float) mainDpyInfo.viewportW;
// Set the way we map the output onto the display surface (which will
@@ -315,22 +350,6 @@
}
/*
- * Set the main display width and height to the actual width and height
- */
-static status_t getActualDisplaySize(const sp<IBinder>& mainDpy, DisplayInfo* mainDpyInfo) {
- Rect viewport;
- status_t err = SurfaceComposerClient::getDisplayViewport(mainDpy, &viewport);
- if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: unable to get display viewport\n");
- return err;
- }
- mainDpyInfo->w = viewport.width();
- mainDpyInfo->h = viewport.height();
-
- return NO_ERROR;
-}
-
-/*
* Runs the MediaCodec encoder, sending the output to the MediaMuxer. The
* input frames are coming from the virtual display as fast as SurfaceFlinger
* wants to send them.
@@ -400,22 +419,14 @@
// useful stuff is hard to get at without a Dalvik VM.
err = SurfaceComposerClient::getDisplayInfo(mainDpy,
&mainDpyInfo);
- if (err == NO_ERROR) {
- err = getActualDisplaySize(mainDpy, &mainDpyInfo);
- if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: unable to set actual display size\n");
- return err;
- }
-
- if (orientation != mainDpyInfo.orientation) {
- ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
- SurfaceComposerClient::Transaction t;
- setDisplayProjection(t, virtualDpy, mainDpyInfo);
- t.apply();
- orientation = mainDpyInfo.orientation;
- }
- } else {
+ if (err != NO_ERROR) {
ALOGW("getDisplayInfo(main) failed: %d", err);
+ } else if (orientation != mainDpyInfo.orientation) {
+ ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
+ SurfaceComposerClient::Transaction t;
+ setDisplayProjection(t, virtualDpy, mainDpyInfo);
+ t.apply();
+ orientation = mainDpyInfo.orientation;
}
}
@@ -472,7 +483,7 @@
case -EAGAIN: // INFO_TRY_AGAIN_LATER
ALOGV("Got -EAGAIN, looping");
break;
- case INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED
+ case android::INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED
{
// Format includes CSD, which we must provide to muxer.
ALOGV("Encoder format changed");
@@ -489,7 +500,7 @@
}
}
break;
- case INFO_OUTPUT_BUFFERS_CHANGED: // INFO_OUTPUT_BUFFERS_CHANGED
+ case android::INFO_OUTPUT_BUFFERS_CHANGED: // INFO_OUTPUT_BUFFERS_CHANGED
// Not expected for an encoder; handle it anyway.
ALOGV("Encoder buffers changed");
err = encoder->getOutputBuffers(&buffers);
@@ -580,8 +591,12 @@
self->startThreadPool();
// Get main display parameters.
- sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain);
+ const sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
+ if (mainDpy == nullptr) {
+ fprintf(stderr, "ERROR: no display\n");
+ return NAME_NOT_FOUND;
+ }
+
DisplayInfo mainDpyInfo;
err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
if (err != NO_ERROR) {
@@ -589,25 +604,19 @@
return err;
}
- err = getActualDisplaySize(mainDpy, &mainDpyInfo);
- if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: unable to set actual display size\n");
- return err;
- }
-
if (gVerbose) {
printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
- mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
+ mainDpyInfo.viewportW, mainDpyInfo.viewportH, mainDpyInfo.fps,
mainDpyInfo.orientation);
fflush(stdout);
}
// Encoder can't take odd number as config
if (gVideoWidth == 0) {
- gVideoWidth = floorToEven(mainDpyInfo.w);
+ gVideoWidth = floorToEven(mainDpyInfo.viewportW);
}
if (gVideoHeight == 0) {
- gVideoHeight = floorToEven(mainDpyInfo.h);
+ gVideoHeight = floorToEven(mainDpyInfo.viewportH);
}
// Configure and start the encoder.
@@ -685,7 +694,9 @@
sp<MediaMuxer> muxer = NULL;
FILE* rawFp = NULL;
switch (gOutputFormat) {
- case FORMAT_MP4: {
+ case FORMAT_MP4:
+ case FORMAT_WEBM:
+ case FORMAT_3GPP: {
// Configure muxer. We have to wait for the CSD blob from the encoder
// before we can start it.
err = unlink(fileName);
@@ -698,7 +709,13 @@
fprintf(stderr, "ERROR: couldn't open file\n");
abort();
}
- muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ if (gOutputFormat == FORMAT_MP4) {
+ muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ } else if (gOutputFormat == FORMAT_WEBM) {
+ muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_WEBM);
+ } else {
+ muxer = new MediaMuxer(fd, MediaMuxer::OUTPUT_FORMAT_THREE_GPP);
+ }
close(fd);
if (gRotate) {
muxer->setOrientationHint(90); // TODO: does this do anything?
@@ -948,6 +965,7 @@
{ "codec-name", required_argument, NULL, 'N' },
{ "monotonic-time", no_argument, NULL, 'm' },
{ "persistent-surface", no_argument, NULL, 'p' },
+ { "bframes", required_argument, NULL, 'B' },
{ NULL, 0, NULL, 0 }
};
@@ -1018,6 +1036,10 @@
gOutputFormat = FORMAT_MP4;
} else if (strcmp(optarg, "h264") == 0) {
gOutputFormat = FORMAT_H264;
+ } else if (strcmp(optarg, "webm") == 0) {
+ gOutputFormat = FORMAT_WEBM;
+ } else if (strcmp(optarg, "3gpp") == 0) {
+ gOutputFormat = FORMAT_3GPP;
} else if (strcmp(optarg, "frames") == 0) {
gOutputFormat = FORMAT_FRAMES;
} else if (strcmp(optarg, "raw-frames") == 0) {
@@ -1036,6 +1058,11 @@
case 'p':
gPersistentSurface = true;
break;
+ case 'B':
+ if (parseValueWithUnit(optarg, &gBframes) != NO_ERROR) {
+ return 2;
+ }
+ break;
default:
if (ic != '?') {
fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index c7619af..6eb2e9f 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -8,7 +8,7 @@
SineSource.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmedia_omx libmediaextractor libutils libbinder \
+ libstagefright libmedia libmedia_omx libutils libbinder \
libstagefright_foundation libjpeg libui libgui libcutils liblog \
libhidlbase \
android.hardware.media.omx@1.0 \
@@ -36,7 +36,7 @@
record.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmediaextractor liblog libutils libbinder \
+ libstagefright libmedia liblog libutils libbinder \
libstagefright_foundation
LOCAL_C_INCLUDES:= \
@@ -61,7 +61,7 @@
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmediaextractor liblog libutils libbinder \
+ libstagefright libmedia liblog libutils libbinder \
libstagefright_foundation
LOCAL_C_INCLUDES:= \
@@ -87,7 +87,7 @@
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmediaextractor liblog libutils libbinder \
+ libstagefright libmedia liblog libutils libbinder \
libstagefright_foundation
LOCAL_C_INCLUDES:= \
@@ -111,7 +111,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libui libgui \
- libstagefright_foundation libmedia libcutils libmediaextractor
+ libstagefright_foundation libmedia libcutils
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -191,7 +191,6 @@
LOCAL_MODULE:= mediafilter
LOCAL_SANITIZE := cfi
-LOCAL_SANITIZE_DIAG := cfi
include $(BUILD_EXECUTABLE)
@@ -204,7 +203,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
- libcutils libc libmediaextractor
+ libcutils libc
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index 6a58467..e5a4337 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -138,7 +138,7 @@
CHECK(!stateByTrack.isEmpty());
- int64_t startTimeUs = ALooper::GetNowUs();
+ int64_t startTimeUs = android::ALooper::GetNowUs();
int64_t startTimeRender = -1;
for (size_t i = 0; i < stateByTrack.size(); ++i) {
@@ -307,7 +307,7 @@
}
}
- int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
+ int64_t elapsedTimeUs = android::ALooper::GetNowUs() - startTimeUs;
for (size_t i = 0; i < stateByTrack.size(); ++i) {
CodecState *state = &stateByTrack.editValueAt(i);
@@ -366,13 +366,13 @@
case 'T':
{
useTimestamp = true;
+ FALLTHROUGH_INTENDED;
}
- // fall through
case 'R':
{
renderSurface = true;
+ FALLTHROUGH_INTENDED;
}
- // fall through
case 'S':
{
useSurface = true;
@@ -400,7 +400,7 @@
ProcessState::self()->startThreadPool();
- sp<ALooper> looper = new ALooper;
+ sp<android::ALooper> looper = new android::ALooper;
looper->start();
sp<SurfaceComposerClient> composerClient;
@@ -411,10 +411,12 @@
composerClient = new SurfaceComposerClient;
CHECK_EQ(composerClient->initCheck(), (status_t)OK);
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ const sp<IBinder> display = SurfaceComposerClient::getInternalDisplayToken();
+ CHECK(display != nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ CHECK_EQ(SurfaceComposerClient::getDisplayInfo(display, &info), NO_ERROR);
+
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index f24d2dd..2cf6955 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -310,7 +310,7 @@
}
static int decode(
- const sp<ALooper> &looper,
+ const sp<android::ALooper> &looper,
const char *path,
const sp<Surface> &surface,
bool renderSurface,
@@ -465,7 +465,7 @@
filterState->mSignalledInputEOS = false;
filterState->mSawOutputEOS = false;
- int64_t startTimeUs = ALooper::GetNowUs();
+ int64_t startTimeUs = android::ALooper::GetNowUs();
int64_t startTimeRender = -1;
for (size_t i = 0; i < stateByTrack.size(); ++i) {
@@ -643,7 +643,7 @@
useTimestamp, &startTimeRender);
}
- int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
+ int64_t elapsedTimeUs = android::ALooper::GetNowUs() - startTimeUs;
for (size_t i = 0; i < stateByTrack.size(); ++i) {
CodecState *state = &stateByTrack.editValueAt(i);
@@ -706,13 +706,13 @@
case 'T':
{
useTimestamp = true;
+ FALLTHROUGH_INTENDED;
}
- // fall through
case 'R':
{
renderSurface = true;
+ FALLTHROUGH_INTENDED;
}
- // fall through
case 'S':
{
useSurface = true;
@@ -737,7 +737,7 @@
ProcessState::self()->startThreadPool();
- android::sp<ALooper> looper = new ALooper;
+ android::sp<android::ALooper> looper = new android::ALooper;
looper->start();
android::sp<SurfaceComposerClient> composerClient;
@@ -748,10 +748,12 @@
composerClient = new SurfaceComposerClient;
CHECK_EQ((status_t)OK, composerClient->initCheck());
- android::sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ const android::sp<IBinder> display = SurfaceComposerClient::getInternalDisplayToken();
+ CHECK(display != nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ CHECK_EQ(SurfaceComposerClient::getDisplayInfo(display, &info), NO_ERROR);
+
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 44b0015..95a16f3 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,7 +17,6 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
-#include <media/MediaExtractor.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -28,6 +27,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/SimpleDecodingSource.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 61fc897..bf36be0 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -32,7 +32,6 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/DataSource.h>
-#include <media/MediaExtractor.h>
#include <media/MediaSource.h>
#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
@@ -47,9 +46,11 @@
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/SimpleDecodingSource.h>
@@ -78,6 +79,7 @@
static bool gPlaybackAudio;
static bool gWriteMP4;
static bool gDisplayHistogram;
+static bool gVerbose = false;
static bool showProgress = true;
static String8 gWriteMP4Filename;
static String8 gComponentNameOverride;
@@ -159,6 +161,11 @@
break;
}
+ if (gVerbose) {
+ MetaDataBase &meta = mbuf->meta_data();
+ fprintf(stdout, "sample format: %s\n", meta.toString().c_str());
+ }
+
CHECK_EQ(
fwrite((const uint8_t *)mbuf->data() + mbuf->range_offset(),
1,
@@ -218,11 +225,15 @@
player->setSource(rawSource);
rawSource.clear();
- player->start(true /* sourceAlreadyStarted */);
+ err = player->start(true /* sourceAlreadyStarted */);
- status_t finalStatus;
- while (!player->reachedEOS(&finalStatus)) {
- usleep(100000ll);
+ if (err == OK) {
+ status_t finalStatus;
+ while (!player->reachedEOS(&finalStatus)) {
+ usleep(100000ll);
+ }
+ } else {
+ fprintf(stderr, "unable to start playback err=%d (0x%08x)\n", err, err);
}
delete player;
@@ -348,7 +359,10 @@
decodeTimesUs.push(delayDecodeUs);
}
- if (showProgress && (n++ % 16) == 0) {
+ if (gVerbose) {
+ MetaDataBase &meta = buffer->meta_data();
+ fprintf(stdout, "%ld sample format: %s\n", numFrames, meta.toString().c_str());
+ } else if (showProgress && (n++ % 16) == 0) {
printf(".");
fflush(stdout);
}
@@ -579,12 +593,12 @@
break;
}
+ CHECK(buffer != NULL);
+
if (buffer->range_length() > 0) {
break;
}
- CHECK(buffer != NULL);
-
buffer->release();
buffer = NULL;
}
@@ -615,7 +629,7 @@
fprintf(stderr, " -l(ist) components\n");
fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n");
fprintf(stderr, " -b bug to reproduce\n");
- fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n");
+ fprintf(stderr, " -i(nfo) dump codec info (profiles and color formats supported, details)\n");
fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n");
fprintf(stderr, " -s(oftware) prefer software codec\n");
fprintf(stderr, " -r(hardware) force to use hardware codec\n");
@@ -630,55 +644,134 @@
fprintf(stderr, " -T allocate buffers from a surface texture\n");
fprintf(stderr, " -d(ump) output_filename (raw stream data to a file)\n");
fprintf(stderr, " -D(ump) output_filename (decoded PCM data to a file)\n");
+ fprintf(stderr, " -v be more verbose\n");
}
-static void dumpCodecProfiles(bool queryDecoders) {
- const char *kMimeTypes[] = {
- MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
- MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
- MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
- MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
- MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
- MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
- MEDIA_MIMETYPE_VIDEO_DOLBY_VISION
- };
-
- const char *codecType = queryDecoders? "decoder" : "encoder";
- printf("%s profiles:\n", codecType);
+static void dumpCodecDetails(bool queryDecoders) {
+ const char *codecType = queryDecoders? "Decoder" : "Encoder";
+ printf("\n%s infos by media types:\n"
+ "=============================\n", codecType);
sp<IMediaCodecList> list = MediaCodecList::getInstance();
size_t numCodecs = list->countCodecs();
- for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++k) {
- printf("type '%s':\n", kMimeTypes[k]);
+ // gather all media types supported by codec class, and link to codecs that support them
+ KeyedVector<AString, Vector<sp<MediaCodecInfo>>> allMediaTypes;
+ for (size_t codec_ix = 0; codec_ix < numCodecs; ++codec_ix) {
+ sp<MediaCodecInfo> info = list->getCodecInfo(codec_ix);
+ if (info->isEncoder() == !queryDecoders) {
+ Vector<AString> supportedMediaTypes;
+ info->getSupportedMediaTypes(&supportedMediaTypes);
+ if (!supportedMediaTypes.size()) {
+ printf("warning: %s does not support any media types\n",
+ info->getCodecName());
+ } else {
+ for (const AString &mediaType : supportedMediaTypes) {
+ if (allMediaTypes.indexOfKey(mediaType) < 0) {
+ allMediaTypes.add(mediaType, Vector<sp<MediaCodecInfo>>());
+ }
+ allMediaTypes.editValueFor(mediaType).add(info);
+ }
+ }
+ }
+ }
- for (size_t index = 0; index < numCodecs; ++index) {
- sp<MediaCodecInfo> info = list->getCodecInfo(index);
- if (info == NULL || info->isEncoder() != !queryDecoders) {
- continue;
- }
- sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(kMimeTypes[k]);
+ KeyedVector<AString, bool> visitedCodecs;
+ for (size_t type_ix = 0; type_ix < allMediaTypes.size(); ++type_ix) {
+ const AString &mediaType = allMediaTypes.keyAt(type_ix);
+ printf("\nMedia type '%s':\n", mediaType.c_str());
+
+ for (const sp<MediaCodecInfo> &info : allMediaTypes.valueAt(type_ix)) {
+ sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(mediaType.c_str());
if (caps == NULL) {
+ printf("warning: %s does not have capabilities for type %s\n",
+ info->getCodecName(), mediaType.c_str());
continue;
}
- printf(" %s '%s' supports ",
+ printf(" %s \"%s\" supports\n",
codecType, info->getCodecName());
- Vector<MediaCodecInfo::ProfileLevel> profileLevels;
- caps->getSupportedProfileLevels(&profileLevels);
- if (profileLevels.size() == 0) {
- printf("NOTHING.\n");
- continue;
+ auto printList = [](const char *type, const Vector<AString> &values){
+ printf(" %s: [", type);
+ for (size_t j = 0; j < values.size(); ++j) {
+ printf("\n %s%s", values[j].c_str(),
+ j == values.size() - 1 ? " " : ",");
+ }
+ printf("]\n");
+ };
+
+ if (visitedCodecs.indexOfKey(info->getCodecName()) < 0) {
+ visitedCodecs.add(info->getCodecName(), true);
+ {
+ Vector<AString> aliases;
+ info->getAliases(&aliases);
+ // quote alias
+ for (AString &alias : aliases) {
+ alias.insert("\"", 1, 0);
+ alias.append('"');
+ }
+ printList("aliases", aliases);
+ }
+ {
+ uint32_t attrs = info->getAttributes();
+ Vector<AString> list;
+ list.add(AStringPrintf("encoder: %d", !!(attrs & MediaCodecInfo::kFlagIsEncoder)));
+ list.add(AStringPrintf("vendor: %d", !!(attrs & MediaCodecInfo::kFlagIsVendor)));
+ list.add(AStringPrintf("software-only: %d", !!(attrs & MediaCodecInfo::kFlagIsSoftwareOnly)));
+ list.add(AStringPrintf("hw-accelerated: %d", !!(attrs & MediaCodecInfo::kFlagIsHardwareAccelerated)));
+ printList(AStringPrintf("attributes: %#x", attrs).c_str(), list);
+ }
+
+ printf(" owner: \"%s\"\n", info->getOwnerName());
+ printf(" rank: %u\n", info->getRank());
+ } else {
+ printf(" aliases, attributes, owner, rank: see above\n");
}
- for (size_t j = 0; j < profileLevels.size(); ++j) {
- const MediaCodecInfo::ProfileLevel &profileLevel = profileLevels[j];
+ {
+ Vector<AString> list;
+ Vector<MediaCodecInfo::ProfileLevel> profileLevels;
+ caps->getSupportedProfileLevels(&profileLevels);
+ for (const MediaCodecInfo::ProfileLevel &pl : profileLevels) {
+ const char *niceProfile =
+ mediaType.equalsIgnoreCase(MIMETYPE_AUDIO_AAC) ? asString_AACObject(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2) ? asString_MPEG2Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263) ? asString_H263Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4) ? asString_MPEG4Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC) ? asString_AVCProfile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8) ? asString_VP8Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC) ? asString_HEVCProfile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9) ? asString_VP9Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1) ? asString_AV1Profile(pl.mProfile) :"??";
+ const char *niceLevel =
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2) ? asString_MPEG2Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263) ? asString_H263Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4) ? asString_MPEG4Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC) ? asString_AVCLevel(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8) ? asString_VP8Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC) ? asString_HEVCTierLevel(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9) ? asString_VP9Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1) ? asString_AV1Level(pl.mLevel) :
+ "??";
- printf("%s%u/%u", j > 0 ? ", " : "",
- profileLevel.mProfile, profileLevel.mLevel);
+ list.add(AStringPrintf("% 5u/% 5u (%s/%s)",
+ pl.mProfile, pl.mLevel, niceProfile, niceLevel));
+ }
+ printList("profile/levels", list);
}
- printf("\n");
+ {
+ Vector<AString> list;
+ Vector<uint32_t> colors;
+ caps->getSupportedColorFormats(&colors);
+ for (uint32_t color : colors) {
+ list.add(AStringPrintf("%#x (%s)", color,
+ asString_ColorFormat((int32_t)color)));
+ }
+ printList("colors", list);
+ }
+
+ printf(" details: %s\n", caps->getDetails()->debugString(6).c_str());
}
}
}
@@ -688,7 +781,7 @@
bool audioOnly = false;
bool listComponents = false;
- bool dumpProfiles = false;
+ bool dumpCodecInfo = false;
bool extractThumbnail = false;
bool seekTest = false;
bool useSurfaceAlloc = false;
@@ -705,10 +798,10 @@
gWriteMP4 = false;
gDisplayHistogram = false;
- sp<ALooper> looper;
+ sp<android::ALooper> looper;
int res;
- while ((res = getopt(argc, argv, "haqn:lm:b:ptsrow:kN:xSTd:D:")) >= 0) {
+ while ((res = getopt(argc, argv, "vhaqn:lm:b:itsrow:kN:xSTd:D:")) >= 0) {
switch (res) {
case 'a':
{
@@ -778,9 +871,9 @@
break;
}
- case 'p':
+ case 'i':
{
- dumpProfiles = true;
+ dumpCodecInfo = true;
break;
}
@@ -832,6 +925,12 @@
break;
}
+ case 'v':
+ {
+ gVerbose = true;
+ break;
+ }
+
case '?':
case 'h':
default:
@@ -915,9 +1014,9 @@
return 0;
}
- if (dumpProfiles) {
- dumpCodecProfiles(true /* queryDecoders */);
- dumpCodecProfiles(false /* queryDecoders */);
+ if (dumpCodecInfo) {
+ dumpCodecDetails(true /* queryDecoders */);
+ dumpCodecDetails(false /* queryDecoders */);
}
if (listComponents) {
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index b0199d8..35bdbc0 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -24,7 +24,6 @@
#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IStreamSource.h>
-#include <media/MediaExtractor.h>
#include <media/mediaplayer.h>
#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -32,6 +31,7 @@
#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
@@ -318,10 +318,12 @@
sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
CHECK_EQ(composerClient->initCheck(), (status_t)OK);
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ const sp<IBinder> display = SurfaceComposerClient::getInternalDisplayToken();
+ CHECK(display != nullptr);
+
DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
+ CHECK_EQ(SurfaceComposerClient::getDisplayInfo(display, &info), NO_ERROR);
+
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
diff --git a/drm/common/Android.bp b/drm/common/Android.bp
index 1552c3f..272684c 100644
--- a/drm/common/Android.bp
+++ b/drm/common/Android.bp
@@ -35,7 +35,7 @@
cflags: ["-Wall", "-Werror"],
- static_libs: ["libbinder"],
+ shared_libs: ["libbinder"],
export_include_dirs: ["include"],
}
diff --git a/drm/common/DrmEngineBase.cpp b/drm/common/DrmEngineBase.cpp
index f734905..aec5959 100644
--- a/drm/common/DrmEngineBase.cpp
+++ b/drm/common/DrmEngineBase.cpp
@@ -79,12 +79,12 @@
}
status_t DrmEngineBase::consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
return onConsumeRights(uniqueId, decryptHandle, action, reserve);
}
status_t DrmEngineBase::setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
return onSetPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
}
@@ -120,7 +120,7 @@
}
status_t DrmEngineBase::openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length, const char* mime) {
if (!mime || mime[0] == '\0') {
@@ -131,7 +131,7 @@
}
status_t DrmEngineBase::openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
const char* uri, const char* mime) {
if (!mime || mime[0] == '\0') {
return onOpenDecryptSession(uniqueId, decryptHandle, uri);
@@ -139,33 +139,33 @@
return onOpenDecryptSession(uniqueId, decryptHandle, uri, mime);
}
-status_t DrmEngineBase::openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmEngineBase::openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
const DrmBuffer& buf, const String8& mimeType) {
return onOpenDecryptSession(uniqueId, decryptHandle, buf, mimeType);
}
-status_t DrmEngineBase::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmEngineBase::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
return onCloseDecryptSession(uniqueId, decryptHandle);
}
status_t DrmEngineBase::initializeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
return onInitializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
}
status_t DrmEngineBase::decrypt(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
return onDecrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
}
status_t DrmEngineBase::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
return onFinalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
}
ssize_t DrmEngineBase::pread(
- int uniqueId, DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
return onPread(uniqueId, decryptHandle, buffer, numBytes, offset);
}
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index 44f98dd..a6d33b0 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -39,7 +39,7 @@
using namespace android;
static void writeDecryptHandleToParcelData(
- const DecryptHandle* handle, Parcel* data) {
+ const sp<DecryptHandle>& handle, Parcel* data) {
data->writeInt32(handle->decryptId);
data->writeString8(handle->mimeType);
data->writeInt32(handle->decryptApiType);
@@ -67,7 +67,7 @@
}
static void readDecryptHandleFromParcelData(
- DecryptHandle* handle, const Parcel& data) {
+ sp<DecryptHandle>& handle, const Parcel& data) {
if (0 == data.dataAvail()) {
return;
}
@@ -99,7 +99,7 @@
}
}
-static void clearDecryptHandle(DecryptHandle* handle) {
+static void clearDecryptHandle(sp<DecryptHandle> &handle) {
if (handle == NULL) {
return;
}
@@ -414,7 +414,7 @@
}
status_t BpDrmManagerService::consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
ALOGV("consumeRights");
Parcel data, reply;
@@ -431,7 +431,7 @@
}
status_t BpDrmManagerService::setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
ALOGV("setPlaybackStatus");
Parcel data, reply;
@@ -603,7 +603,7 @@
return reply.readInt32();
}
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
ALOGV("Entering BpDrmManagerService::openDecryptSession");
Parcel data, reply;
@@ -621,7 +621,7 @@
remote()->transact(OPEN_DECRYPT_SESSION, data, &reply);
- DecryptHandle* handle = NULL;
+ sp<DecryptHandle> handle;
if (0 != reply.dataAvail()) {
handle = new DecryptHandle();
readDecryptHandleFromParcelData(handle, reply);
@@ -629,7 +629,7 @@
return handle;
}
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
int uniqueId, const char* uri, const char* mime) {
ALOGV("Entering BpDrmManagerService::openDecryptSession: mime=%s", mime? mime: "NULL");
@@ -646,7 +646,7 @@
remote()->transact(OPEN_DECRYPT_SESSION_FROM_URI, data, &reply);
- DecryptHandle* handle = NULL;
+ sp<DecryptHandle> handle;
if (0 != reply.dataAvail()) {
handle = new DecryptHandle();
readDecryptHandleFromParcelData(handle, reply);
@@ -656,7 +656,7 @@
return handle;
}
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
ALOGV("Entering BpDrmManagerService::openDecryptSession");
Parcel data, reply;
@@ -673,7 +673,7 @@
remote()->transact(OPEN_DECRYPT_SESSION_FOR_STREAMING, data, &reply);
- DecryptHandle* handle = NULL;
+ sp<DecryptHandle> handle;
if (0 != reply.dataAvail()) {
handle = new DecryptHandle();
readDecryptHandleFromParcelData(handle, reply);
@@ -683,7 +683,7 @@
return handle;
}
-status_t BpDrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t BpDrmManagerService::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
ALOGV("closeDecryptSession");
Parcel data, reply;
@@ -698,7 +698,7 @@
}
status_t BpDrmManagerService::initializeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) {
ALOGV("initializeDecryptUnit");
Parcel data, reply;
@@ -718,7 +718,7 @@
}
status_t BpDrmManagerService::decrypt(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
ALOGV("decrypt");
Parcel data, reply;
@@ -754,7 +754,7 @@
}
status_t BpDrmManagerService::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
ALOGV("finalizeDecryptUnit");
Parcel data, reply;
@@ -770,7 +770,7 @@
}
ssize_t BpDrmManagerService::pread(
- int uniqueId, DecryptHandle* decryptHandle, void* buffer,
+ int uniqueId, sp<DecryptHandle>& decryptHandle, void* buffer,
ssize_t numBytes, off64_t offset) {
ALOGV("read");
Parcel data, reply;
@@ -1128,16 +1128,16 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
const int action = data.readInt32();
const bool reserve = static_cast<bool>(data.readInt32());
const status_t status
- = consumeRights(uniqueId, &handle, action, reserve);
+ = consumeRights(uniqueId, handle, action, reserve);
reply->writeInt32(status);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
@@ -1148,16 +1148,16 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
const int playbackStatus = data.readInt32();
const int64_t position = data.readInt64();
const status_t status
- = setPlaybackStatus(uniqueId, &handle, playbackStatus, position);
+ = setPlaybackStatus(uniqueId, handle, playbackStatus, position);
reply->writeInt32(status);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
@@ -1329,13 +1329,13 @@
const off64_t length = data.readInt64();
const String8 mime = data.readString8();
- DecryptHandle* handle
+ sp<DecryptHandle> handle
= openDecryptSession(uniqueId, fd, offset, length, mime.string());
- if (NULL != handle) {
- writeDecryptHandleToParcelData(handle, reply);
+ if (NULL != handle.get()) {
+ writeDecryptHandleToParcelData(handle.get(), reply);
clearDecryptHandle(handle);
- delete handle; handle = NULL;
+ handle.clear();
}
return DRM_NO_ERROR;
}
@@ -1349,13 +1349,13 @@
const String8 uri = data.readString8();
const String8 mime = data.readString8();
- DecryptHandle* handle = openDecryptSession(uniqueId, uri.string(), mime.string());
+ sp<DecryptHandle> handle = openDecryptSession(uniqueId, uri.string(), mime.string());
- if (NULL != handle) {
- writeDecryptHandleToParcelData(handle, reply);
+ if (NULL != handle.get()) {
+ writeDecryptHandleToParcelData(handle.get(), reply);
clearDecryptHandle(handle);
- delete handle; handle = NULL;
+ handle.clear();
} else {
ALOGV("NULL decryptHandle is returned");
}
@@ -1373,13 +1373,12 @@
bufferSize);
const String8 mimeType(data.readString8());
- DecryptHandle* handle = openDecryptSession(uniqueId, buf, mimeType);
+ sp<DecryptHandle> handle = openDecryptSession(uniqueId, buf, mimeType);
if (handle != NULL) {
writeDecryptHandleToParcelData(handle, reply);
clearDecryptHandle(handle);
- delete handle;
- handle = NULL;
+ handle.clear();
} else {
ALOGV("NULL decryptHandle is returned");
}
@@ -1393,7 +1392,7 @@
const int uniqueId = data.readInt32();
- DecryptHandle* handle = new DecryptHandle();
+ sp<DecryptHandle> handle = new DecryptHandle();
readDecryptHandleFromParcelData(handle, data);
const status_t status = closeDecryptSession(uniqueId, handle);
@@ -1408,8 +1407,8 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
const int decryptUnitId = data.readInt32();
@@ -1417,17 +1416,17 @@
const uint32_t bufferSize = data.readInt32();
if (bufferSize > data.dataAvail()) {
reply->writeInt32(BAD_VALUE);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
DrmBuffer* headerInfo = NULL;
headerInfo = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize);
const status_t status
- = initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
+ = initializeDecryptUnit(uniqueId, handle, decryptUnitId, headerInfo);
reply->writeInt32(status);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
delete headerInfo; headerInfo = NULL;
return DRM_NO_ERROR;
}
@@ -1439,8 +1438,8 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle;
+ readDecryptHandleFromParcelData(handle, data);
const int decryptUnitId = data.readInt32();
const uint32_t decBufferSize = data.readInt32();
@@ -1450,7 +1449,7 @@
decBufferSize > MAX_BINDER_TRANSACTION_SIZE) {
reply->writeInt32(BAD_VALUE);
reply->writeInt32(0);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
@@ -1470,7 +1469,7 @@
}
const status_t status
- = decrypt(uniqueId, &handle, decryptUnitId, encBuffer, &decBuffer, IV);
+ = decrypt(uniqueId, handle, decryptUnitId, encBuffer, &decBuffer, IV);
reply->writeInt32(status);
@@ -1480,7 +1479,7 @@
reply->write(decBuffer->data, size);
}
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
delete encBuffer; encBuffer = NULL;
delete decBuffer; decBuffer = NULL;
delete [] buffer; buffer = NULL;
@@ -1495,13 +1494,13 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
- const status_t status = finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
+ const status_t status = finalizeDecryptUnit(uniqueId, handle, data.readInt32());
reply->writeInt32(status);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
@@ -1512,8 +1511,8 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
const uint32_t numBytes = data.readInt32();
if (numBytes > MAX_BINDER_TRANSACTION_SIZE) {
@@ -1524,13 +1523,13 @@
const off64_t offset = data.readInt64();
- ssize_t result = pread(uniqueId, &handle, buffer, numBytes, offset);
+ ssize_t result = pread(uniqueId, handle, buffer, numBytes, offset);
reply->writeInt32(result);
if (0 < result) {
reply->write(buffer, result);
}
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
delete [] buffer, buffer = NULL;
return DRM_NO_ERROR;
}
diff --git a/drm/common/include/DrmEngineBase.h b/drm/common/include/DrmEngineBase.h
index 417107f..73f11a4 100644
--- a/drm/common/include/DrmEngineBase.h
+++ b/drm/common/include/DrmEngineBase.h
@@ -59,10 +59,11 @@
int checkRightsStatus(int uniqueId, const String8& path, int action);
- status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+ bool reserve);
status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -80,27 +81,28 @@
DrmSupportInfo* getSupportInfo(int uniqueId);
status_t openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length, const char* mime);
status_t openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
const char* uri, const char* mime);
- status_t openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+ status_t openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
const DrmBuffer& buf, const String8& mimeType);
- status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
- status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+ int decryptUnitId);
- ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset);
protected:
@@ -265,7 +267,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t onConsumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle,
int action, bool reserve) = 0;
/**
@@ -280,7 +282,8 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
virtual status_t onSetPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus,
+ int64_t position) = 0;
/**
* Validates whether an action on the DRM content is allowed or not.
@@ -381,7 +384,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length) = 0;
/**
@@ -398,7 +401,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+ int /* uniqueId */, sp<DecryptHandle>& /* decryptHandle */,
int /* fd */, off64_t /* offset */, off64_t /* length */,
const char* /* mime */) {
@@ -415,7 +418,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
const char* uri) = 0;
/**
@@ -430,7 +433,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+ int /* uniqueId */, sp<DecryptHandle>& /* decryptHandle */,
const char* /* uri */, const char* /* mime */) {
return DRM_ERROR_CANNOT_HANDLE;
@@ -447,7 +450,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(int /* uniqueId */,
- DecryptHandle* /* decryptHandle */,
+ sp<DecryptHandle>& /* decryptHandle */,
const DrmBuffer& /* buf */,
const String8& /* mimeType */) {
return DRM_ERROR_CANNOT_HANDLE;
@@ -461,7 +464,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t onCloseDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
/**
* Initialize decryption for the given unit of the protected content
@@ -473,7 +476,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t onInitializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
/**
@@ -493,7 +496,7 @@
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
- virtual status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ virtual status_t onDecrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
/**
@@ -506,7 +509,7 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
virtual status_t onFinalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
/**
* Reads the specified number of bytes from an open DRM file.
@@ -519,7 +522,7 @@
*
* @return Number of bytes read. Returns -1 for Failure.
*/
- virtual ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
+ virtual ssize_t onPread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) = 0;
};
diff --git a/drm/common/include/IDrmEngine.h b/drm/common/include/IDrmEngine.h
index acc8ed9..1837a11 100644
--- a/drm/common/include/IDrmEngine.h
+++ b/drm/common/include/IDrmEngine.h
@@ -210,7 +210,7 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
virtual status_t consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) = 0;
/**
* Informs the DRM Engine about the playback actions performed on the DRM files.
@@ -223,7 +223,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t setPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t setPlaybackStatus(int uniqueId, sp<DecryptHandle>& decryptHandle,
int playbackStatus, int64_t position) = 0;
/**
@@ -327,7 +327,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length, const char* mime) = 0;
/**
@@ -342,7 +342,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
const char* uri, const char* mime) = 0;
/**
@@ -355,7 +355,7 @@
* @return
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
- virtual status_t openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
const DrmBuffer& buf, const String8& mimeType) = 0;
/**
@@ -366,7 +366,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
/**
* Initialize decryption for the given unit of the protected content
@@ -378,7 +378,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
/**
@@ -398,7 +398,7 @@
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
/**
@@ -411,7 +411,7 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
virtual status_t finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
/**
* Reads the specified number of bytes from an open DRM file.
@@ -424,7 +424,7 @@
*
* @return Number of bytes read. Returns -1 for Failure.
*/
- virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) = 0;
};
diff --git a/drm/common/include/IDrmManagerService.h b/drm/common/include/IDrmManagerService.h
index 0376b49..836ae0a 100644
--- a/drm/common/include/IDrmManagerService.h
+++ b/drm/common/include/IDrmManagerService.h
@@ -115,10 +115,11 @@
virtual int checkRightsStatus(int uniqueId, const String8& path, int action) = 0;
virtual status_t consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) = 0;
virtual status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus,
+ int64_t position) = 0;
virtual bool validateAction(
int uniqueId, const String8& path,
@@ -138,28 +139,28 @@
virtual status_t getAllSupportInfo(
int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) = 0;
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, int fd, off64_t offset,
off64_t length, const char* mime) = 0;
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, const char* uri, const char* mime) = 0;
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) = 0;
- virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
- virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
virtual status_t finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
- virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes,off64_t offset) = 0;
};
@@ -203,10 +204,10 @@
virtual int checkRightsStatus(int uniqueId, const String8& path, int action);
virtual status_t consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve);
virtual status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
virtual bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -225,28 +226,28 @@
virtual status_t getAllSupportInfo(
int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length,
const char* mime);
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, const char* uri, const char* mime);
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType);
- virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
- virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
virtual status_t finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId);
- virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset);
};
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index bf04a89..afbcb39 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -267,7 +267,7 @@
}
status_t DrmManager::consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
status_t result = DRM_ERROR_UNKNOWN;
Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -278,7 +278,7 @@
}
status_t DrmManager::setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
status_t result = DRM_ERROR_UNKNOWN;
Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -396,15 +396,15 @@
return DRM_NO_ERROR;
}
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
Mutex::Autolock _l(mDecryptLock);
status_t result = DRM_ERROR_CANNOT_HANDLE;
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
- DecryptHandle* handle = new DecryptHandle();
- if (NULL != handle) {
+ sp<DecryptHandle> handle = new DecryptHandle();
+ if (NULL != handle.get()) {
handle->decryptId = mDecryptSessionId + 1;
for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -420,19 +420,19 @@
}
}
if (DRM_NO_ERROR != result) {
- delete handle; handle = NULL;
+ handle.clear();
}
return handle;
}
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
int uniqueId, const char* uri, const char* mime) {
Mutex::Autolock _l(mDecryptLock);
status_t result = DRM_ERROR_CANNOT_HANDLE;
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
- DecryptHandle* handle = new DecryptHandle();
- if (NULL != handle) {
+ sp<DecryptHandle> handle = new DecryptHandle();
+ if (NULL != handle.get()) {
handle->decryptId = mDecryptSessionId + 1;
for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -448,20 +448,20 @@
}
}
if (DRM_NO_ERROR != result) {
- delete handle; handle = NULL;
+ handle.clear();
ALOGV("DrmManager::openDecryptSession: no capable plug-in found");
}
return handle;
}
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
Mutex::Autolock _l(mDecryptLock);
status_t result = DRM_ERROR_CANNOT_HANDLE;
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
- DecryptHandle* handle = new DecryptHandle();
- if (NULL != handle) {
+ sp<DecryptHandle> handle = new DecryptHandle();
+ if (NULL != handle.get()) {
handle->decryptId = mDecryptSessionId + 1;
for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -477,20 +477,19 @@
}
}
if (DRM_NO_ERROR != result) {
- delete handle;
- handle = NULL;
+ handle.clear();
ALOGV("DrmManager::openDecryptSession: no capable plug-in found");
}
return handle;
}
-status_t DrmManager::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManager::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
Mutex::Autolock _l(mDecryptLock);
status_t result = DRM_ERROR_UNKNOWN;
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
result = drmEngine->closeDecryptSession(uniqueId, decryptHandle);
- if (DRM_NO_ERROR == result) {
+ if (DRM_NO_ERROR == result && NULL != decryptHandle.get()) {
mDecryptSessionMap.removeItem(decryptHandle->decryptId);
}
}
@@ -498,7 +497,8 @@
}
status_t DrmManager::initializeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
+ const DrmBuffer* headerInfo) {
status_t result = DRM_ERROR_UNKNOWN;
Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -508,7 +508,7 @@
return result;
}
-status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+status_t DrmManager::decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
status_t result = DRM_ERROR_UNKNOWN;
@@ -522,7 +522,7 @@
}
status_t DrmManager::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
status_t result = DRM_ERROR_UNKNOWN;
Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -532,7 +532,7 @@
return result;
}
-ssize_t DrmManager::pread(int uniqueId, DecryptHandle* decryptHandle,
+ssize_t DrmManager::pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) {
ssize_t result = DECRYPT_FILE_ERROR;
diff --git a/drm/drmserver/DrmManager.h b/drm/drmserver/DrmManager.h
index e7cdd36..26222bc 100644
--- a/drm/drmserver/DrmManager.h
+++ b/drm/drmserver/DrmManager.h
@@ -89,10 +89,11 @@
int checkRightsStatus(int uniqueId, const String8& path, int action);
- status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+ bool reserve);
status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -109,25 +110,26 @@
status_t getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
- DecryptHandle* openDecryptSession(
+ sp<DecryptHandle> openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime);
- DecryptHandle* openDecryptSession(int uniqueId, const char* uri, const char* mime);
+ sp<DecryptHandle> openDecryptSession(int uniqueId, const char* uri, const char* mime);
- DecryptHandle* openDecryptSession(int uniqueId, const DrmBuffer& buf,
+ sp<DecryptHandle> openDecryptSession(int uniqueId, const DrmBuffer& buf,
const String8& mimeType);
- status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
- status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+ int decryptUnitId);
- ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset);
void onInfo(const DrmInfoEvent& event);
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index dad599b..2600a2c 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -58,22 +58,26 @@
return drm_perm_labels[index];
}
-bool DrmManagerService::selinuxIsProtectedCallAllowed(pid_t spid, drm_perm_t perm) {
+bool DrmManagerService::selinuxIsProtectedCallAllowed(pid_t spid, const char* ssid, drm_perm_t perm) {
if (selinux_enabled <= 0) {
return true;
}
- char *sctx;
+ char *sctx = NULL;
const char *selinux_class = "drmservice";
const char *str_perm = get_perm_label(perm);
- if (getpidcon(spid, &sctx) != 0) {
- ALOGE("SELinux: getpidcon(pid=%d) failed.\n", spid);
- return false;
+ if (ssid == NULL) {
+ android_errorWriteLog(0x534e4554, "121035042");
+
+ if (getpidcon(spid, &sctx) != 0) {
+ ALOGE("SELinux: getpidcon(pid=%d) failed.\n", spid);
+ return false;
+ }
}
- bool allowed = (selinux_check_access(sctx, drmserver_context, selinux_class,
- str_perm, NULL) == 0);
+ bool allowed = (selinux_check_access(ssid ? ssid : sctx, drmserver_context,
+ selinux_class, str_perm, NULL) == 0);
freecon(sctx);
return allowed;
@@ -86,10 +90,11 @@
IPCThreadState* ipcState = IPCThreadState::self();
uid_t uid = ipcState->getCallingUid();
pid_t spid = ipcState->getCallingPid();
+ const char* ssid = ipcState->getCallingSid();
for (unsigned int i = 0; i < trustedUids.size(); ++i) {
if (trustedUids[i] == uid) {
- return selinuxIsProtectedCallAllowed(spid, perm);
+ return selinuxIsProtectedCallAllowed(spid, ssid, perm);
}
}
return false;
@@ -97,7 +102,9 @@
void DrmManagerService::instantiate() {
ALOGV("instantiate");
- defaultServiceManager()->addService(String16("drm.drmManager"), new DrmManagerService());
+ sp<DrmManagerService> service = new DrmManagerService();
+ service->setRequestingSid(true);
+ defaultServiceManager()->addService(String16("drm.drmManager"), service);
if (0 >= trustedUids.size()) {
// TODO
@@ -206,7 +213,7 @@
}
status_t DrmManagerService::consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
ALOGV("Entering consumeRights");
if (!isProtectedCallAllowed(CONSUME_RIGHTS)) {
return DRM_ERROR_NO_PERMISSION;
@@ -215,7 +222,7 @@
}
status_t DrmManagerService::setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
ALOGV("Entering setPlaybackStatus");
if (!isProtectedCallAllowed(SET_PLAYBACK_STATUS)) {
return DRM_ERROR_NO_PERMISSION;
@@ -262,7 +269,7 @@
return mDrmManager->getAllSupportInfo(uniqueId, length, drmSupportInfoArray);
}
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
ALOGV("Entering DrmManagerService::openDecryptSession");
if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -272,7 +279,7 @@
return NULL;
}
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
int uniqueId, const char* uri, const char* mime) {
ALOGV("Entering DrmManagerService::openDecryptSession with uri");
if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -282,7 +289,7 @@
return NULL;
}
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
ALOGV("Entering DrmManagerService::openDecryptSession for streaming");
if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -292,7 +299,7 @@
return NULL;
}
-status_t DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManagerService::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
ALOGV("Entering closeDecryptSession");
if (!isProtectedCallAllowed(CLOSE_DECRYPT_SESSION)) {
return DRM_ERROR_NO_PERMISSION;
@@ -300,7 +307,7 @@
return mDrmManager->closeDecryptSession(uniqueId, decryptHandle);
}
-status_t DrmManagerService::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmManagerService::initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) {
ALOGV("Entering initializeDecryptUnit");
if (!isProtectedCallAllowed(INITIALIZE_DECRYPT_UNIT)) {
@@ -310,7 +317,7 @@
}
status_t DrmManagerService::decrypt(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
ALOGV("Entering decrypt");
if (!isProtectedCallAllowed(DECRYPT)) {
@@ -320,7 +327,7 @@
}
status_t DrmManagerService::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
ALOGV("Entering finalizeDecryptUnit");
if (!isProtectedCallAllowed(FINALIZE_DECRYPT_UNIT)) {
return DRM_ERROR_NO_PERMISSION;
@@ -328,7 +335,7 @@
return mDrmManager->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
}
-ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle,
+ssize_t DrmManagerService::pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) {
ALOGV("Entering pread");
if (!isProtectedCallAllowed(PREAD)) {
diff --git a/drm/drmserver/DrmManagerService.h b/drm/drmserver/DrmManagerService.h
index 45cee2e..2e27a3c 100644
--- a/drm/drmserver/DrmManagerService.h
+++ b/drm/drmserver/DrmManagerService.h
@@ -60,7 +60,7 @@
static const char *get_perm_label(drm_perm_t perm);
- static bool selinuxIsProtectedCallAllowed(pid_t spid, drm_perm_t perm);
+ static bool selinuxIsProtectedCallAllowed(pid_t spid, const char* ssid, drm_perm_t perm);
static bool isProtectedCallAllowed(drm_perm_t perm);
@@ -95,10 +95,11 @@
int checkRightsStatus(int uniqueId, const String8& path,int action);
- status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+ bool reserve);
status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
bool validateAction(int uniqueId, const String8& path,
int action, const ActionDescription& description);
@@ -115,26 +116,27 @@