├── .gitignore
├── .gitmodules
├── .npmignore
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── Makefile
├── README.md
├── build-remote.sh
├── example
├── .gitignore
├── README.md
├── app.js
├── package.json
└── public
│ └── index.html
├── gdb.sh
├── jni
├── Android.mk
├── Application.mk
├── minicap-shared
│ ├── Android.mk
│ ├── README.md
│ ├── aosp
│ │ ├── .rsync-filter
│ │ ├── Android.mk
│ │ ├── Makefile
│ │ ├── include
│ │ │ ├── Minicap.hpp
│ │ │ └── mcdebug.h
│ │ ├── libs
│ │ │ ├── android-10
│ │ │ │ └── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-14
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-15
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-16
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-17
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-18
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-19
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-21
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-22
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-23
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-24
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-25
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-26
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-27
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-28
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ ├── android-29
│ │ │ │ ├── arm64-v8a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── armeabi-v7a
│ │ │ │ │ └── minicap.so
│ │ │ │ ├── x86
│ │ │ │ │ └── minicap.so
│ │ │ │ └── x86_64
│ │ │ │ │ └── minicap.so
│ │ │ └── android-9
│ │ │ │ └── armeabi-v7a
│ │ │ │ └── minicap.so
│ │ └── src
│ │ │ ├── minicap_14.cpp
│ │ │ ├── minicap_16.cpp
│ │ │ ├── minicap_17.cpp
│ │ │ ├── minicap_18.cpp
│ │ │ ├── minicap_19.cpp
│ │ │ ├── minicap_21.cpp
│ │ │ ├── minicap_22.cpp
│ │ │ ├── minicap_23.cpp
│ │ │ ├── minicap_24.cpp
│ │ │ ├── minicap_25.cpp
│ │ │ ├── minicap_26.cpp
│ │ │ ├── minicap_27.cpp
│ │ │ ├── minicap_28.cpp
│ │ │ ├── minicap_29.cpp
│ │ │ └── minicap_9.cpp
│ └── mock
│ │ └── Minicap.cpp
├── minicap
│ ├── Android.mk
│ ├── JpgEncoder.cpp
│ ├── JpgEncoder.hpp
│ ├── Projection.hpp
│ ├── SimpleServer.cpp
│ ├── SimpleServer.hpp
│ ├── minicap.cpp
│ └── util
│ │ ├── debug.h
│ │ └── formatter.hpp
└── vendor
│ └── Android.mk
├── package-lock.json
├── package.json
└── run.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.tgz
2 | /.env
3 | /gdb.setup
4 | /libs/
5 | /libs/
6 | /obj/
7 | /prebuilt/
8 | /temp/
9 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "libjpeg-turbo"]
2 | path = jni/vendor/libjpeg-turbo
3 | url = https://github.com/openstf/android-libjpeg-turbo.git
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /.env
2 | /.gitmodules
3 | /.npmignore
4 | /*.tgz
5 | /build-remote.sh
6 | /CONTRIBUTING.md
7 | /example/
8 | /gdb.setup
9 | /gdb.sh
10 | /jni/
11 | /libs/
12 | /Makefile
13 | /obj/
14 | /run.sh
15 | /temp/
16 | /yarn-error.log
17 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We are happy to accept any contributions that make sense and respect the rules listed below.
4 |
5 | ## How to contribute
6 |
7 | 1. Fork the repo.
8 | 2. Create a feature branch for your contribution out of the `master` branch. Only one contribution per branch is accepted.
9 | 3. Implement your contribution while respecting our rules (see below).
10 | 4. Make sure that your contribution builds and all necessary files have been committed.
11 | 5. Submit a pull request against our `master` branch!
12 |
13 | ## Rules
14 |
15 | * **Do** use feature branches.
16 | * **Do** conform to existing coding style so that your contribution fits in.
17 | * **Do** use [EditorConfig](http://editorconfig.org/) to enforce our [whitespace rules](.editorconfig). If your editor is not supported, enforce the settings manually.
18 | * **Do not** commit any generated files, unless already in the repo. If absolutely necessary, explain why.
19 | * **Do not** create any top level files or directories. If absolutely necessary, explain why and update [.gitignore](.gitignore) if appropriate.
20 |
21 | ## License
22 |
23 | By contributing your code, you agree to license your contribution under our [LICENSE](LICENSE).
24 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **What is the issue or idea you have?**
2 |
3 | **Have you tried STF?**
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright © 2013 CyberAgent, Inc.
2 | Copyright © 2016 The OpenSTF Project
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: default clean prebuilt
2 |
3 | NDKBUILT := \
4 | libs/arm64-v8a/minicap \
5 | libs/arm64-v8a/minicap-nopie \
6 | libs/armeabi-v7a/minicap \
7 | libs/armeabi-v7a/minicap-nopie \
8 | libs/x86/minicap \
9 | libs/x86/minicap-nopie \
10 | libs/x86_64/minicap \
11 | libs/x86_64/minicap-nopie \
12 |
13 | default: prebuilt
14 |
15 | clean:
16 | ndk-build clean
17 | rm -rf prebuilt
18 |
19 | $(NDKBUILT):
20 | ndk-build
21 |
22 | # It may feel a bit redundant to list everything here. However it also
23 | # acts as a safeguard to make sure that we really are including everything
24 | # that is supposed to be there.
25 | prebuilt: \
26 | prebuilt/armeabi-v7a/bin/minicap \
27 | prebuilt/armeabi-v7a/bin/minicap-nopie \
28 | prebuilt/armeabi-v7a/lib/android-9/minicap.so \
29 | prebuilt/armeabi-v7a/lib/android-10/minicap.so \
30 | prebuilt/armeabi-v7a/lib/android-14/minicap.so \
31 | prebuilt/armeabi-v7a/lib/android-15/minicap.so \
32 | prebuilt/armeabi-v7a/lib/android-16/minicap.so \
33 | prebuilt/armeabi-v7a/lib/android-17/minicap.so \
34 | prebuilt/armeabi-v7a/lib/android-18/minicap.so \
35 | prebuilt/armeabi-v7a/lib/android-19/minicap.so \
36 | prebuilt/armeabi-v7a/lib/android-21/minicap.so \
37 | prebuilt/armeabi-v7a/lib/android-22/minicap.so \
38 | prebuilt/armeabi-v7a/lib/android-23/minicap.so \
39 | prebuilt/armeabi-v7a/lib/android-24/minicap.so \
40 | prebuilt/armeabi-v7a/lib/android-25/minicap.so \
41 | prebuilt/armeabi-v7a/lib/android-26/minicap.so \
42 | prebuilt/armeabi-v7a/lib/android-27/minicap.so \
43 | prebuilt/armeabi-v7a/lib/android-28/minicap.so \
44 | prebuilt/armeabi-v7a/lib/android-29/minicap.so \
45 | prebuilt/arm64-v8a/bin/minicap \
46 | prebuilt/arm64-v8a/bin/minicap-nopie \
47 | prebuilt/arm64-v8a/lib/android-21/minicap.so \
48 | prebuilt/arm64-v8a/lib/android-22/minicap.so \
49 | prebuilt/arm64-v8a/lib/android-23/minicap.so \
50 | prebuilt/arm64-v8a/lib/android-24/minicap.so \
51 | prebuilt/arm64-v8a/lib/android-25/minicap.so \
52 | prebuilt/arm64-v8a/lib/android-26/minicap.so \
53 | prebuilt/arm64-v8a/lib/android-27/minicap.so \
54 | prebuilt/arm64-v8a/lib/android-28/minicap.so \
55 | prebuilt/arm64-v8a/lib/android-29/minicap.so \
56 | prebuilt/x86/bin/minicap \
57 | prebuilt/x86/bin/minicap-nopie \
58 | prebuilt/x86/lib/android-14/minicap.so \
59 | prebuilt/x86/lib/android-15/minicap.so \
60 | prebuilt/x86/lib/android-16/minicap.so \
61 | prebuilt/x86/lib/android-17/minicap.so \
62 | prebuilt/x86/lib/android-18/minicap.so \
63 | prebuilt/x86/lib/android-19/minicap.so \
64 | prebuilt/x86/lib/android-21/minicap.so \
65 | prebuilt/x86/lib/android-22/minicap.so \
66 | prebuilt/x86/lib/android-23/minicap.so \
67 | prebuilt/x86/lib/android-24/minicap.so \
68 | prebuilt/x86/lib/android-25/minicap.so \
69 | prebuilt/x86/lib/android-26/minicap.so \
70 | prebuilt/x86/lib/android-27/minicap.so \
71 | prebuilt/x86/lib/android-28/minicap.so \
72 | prebuilt/x86/lib/android-29/minicap.so \
73 | prebuilt/x86_64/bin/minicap \
74 | prebuilt/x86_64/bin/minicap-nopie \
75 | prebuilt/x86_64/lib/android-21/minicap.so \
76 | prebuilt/x86_64/lib/android-22/minicap.so \
77 | prebuilt/x86_64/lib/android-23/minicap.so \
78 | prebuilt/x86_64/lib/android-24/minicap.so \
79 | prebuilt/x86_64/lib/android-25/minicap.so \
80 | prebuilt/x86_64/lib/android-26/minicap.so \
81 | prebuilt/x86_64/lib/android-27/minicap.so \
82 | prebuilt/x86_64/lib/android-28/minicap.so \
83 | prebuilt/x86_64/lib/android-29/minicap.so \
84 |
85 | prebuilt/%/bin/minicap: libs/%/minicap
86 | mkdir -p $(@D)
87 | cp $^ $@
88 |
89 | prebuilt/%/bin/minicap-nopie: libs/%/minicap-nopie
90 | mkdir -p $(@D)
91 | cp $^ $@
92 |
93 | prebuilt/armeabi-v7a/lib/%/minicap.so: jni/minicap-shared/aosp/libs/%/armeabi-v7a/minicap.so
94 | mkdir -p $(@D)
95 | cp $^ $@
96 |
97 | prebuilt/arm64-v8a/lib/%/minicap.so: jni/minicap-shared/aosp/libs/%/arm64-v8a/minicap.so
98 | mkdir -p $(@D)
99 | cp $^ $@
100 |
101 | prebuilt/x86/lib/%/minicap.so: jni/minicap-shared/aosp/libs/%/x86/minicap.so
102 | mkdir -p $(@D)
103 | cp $^ $@
104 |
105 | prebuilt/x86_64/lib/%/minicap.so: jni/minicap-shared/aosp/libs/%/x86_64/minicap.so
106 | mkdir -p $(@D)
107 | cp $^ $@
108 |
--------------------------------------------------------------------------------
/build-remote.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -xueo pipefail
4 |
5 | builder=$1
6 |
7 | rsync \
8 | --recursive \
9 | --copy-links \
10 | --perms \
11 | --times \
12 | -FF ./jni/minicap-shared/aosp/ "$builder":minicap/
13 |
14 | ssh -T "$builder" "cd minicap && make -j 1"
15 |
16 | rsync \
17 | --recursive \
18 | --copy-links \
19 | --perms \
20 | --times \
21 | "$builder":minicap/libs/ ./jni/minicap-shared/aosp/libs/
22 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # Example: minicap over WebSockets
2 |
3 | A quick and dirty example to show how minicap might be used as part of an application. Also useful for testing.
4 |
5 | ## Requirements
6 |
7 | * [Node.js](https://nodejs.org/) >= 0.12 (for this example only)
8 | * [ADB](http://developer.android.com/intl/ja/tools/help/adb.html)
9 | * An Android device with USB debugging enabled.
10 |
11 | ## Running
12 |
13 | 1. Check that your device is connected and ADB is running with `adb devices`. The following steps may not work properly if you don't.
14 | ```
15 | adb devices
16 | ```
17 | 2. Set up a forward for the server we'll soon have running inside the device. Note that due to laziness the port is currently fixed to 1717.
18 | ```
19 | adb forward tcp:1717 localabstract:minicap
20 | ```
21 | 3. Get information about your display. Unfortunately the easy API methods we could use for automatic detection segfault on some Samsung devices, presumably due to maker customizations. You'll need to know the display width and height in pixels. Here are some ways to do it:
22 | ```
23 | adb shell wm size
24 | adb shell dumpsys display
25 | ```
26 | 4. Start the minicap server. The most convenient way is to use the helper script at the root of this repo.
27 | ```
28 | # Try ./run.sh -h for help
29 | ./run.sh -P 720x1280@720x1280/0
30 | ```
31 | The first set is the true size of your display, and the second set is the size of the desired projection. Larger projections require more processing power and bandwidth. The final argument is the rotation of the display. Note that this is not the rotation you want it to have, it simply specifies the display's current rotation, which is used to normalize the output frames between Android versions. If the rotation changes you have to restart the server.
32 | 5. Start the example app.
33 | ```
34 | PORT=9002 node app.js
35 | ```
36 | 6. Open http://localhost:9002 in your browser.
37 |
--------------------------------------------------------------------------------
/example/app.js:
--------------------------------------------------------------------------------
1 | var WebSocketServer = require('ws').Server
2 | , http = require('http')
3 | , express = require('express')
4 | , path = require('path')
5 | , net = require('net')
6 | , app = express()
7 |
8 | var PORT = process.env.PORT || 9002
9 |
10 | app.use(express.static(path.join(__dirname, '/public')))
11 |
12 | var server = http.createServer(app)
13 | var wss = new WebSocketServer({ server: server })
14 |
15 | wss.on('connection', function(ws) {
16 | console.info('Got a client')
17 |
18 | var stream = net.connect({
19 | port: 1717
20 | })
21 |
22 | stream.on('error', function() {
23 | console.error('Be sure to run `adb forward tcp:1717 localabstract:minicap`')
24 | process.exit(1)
25 | })
26 |
27 | var readBannerBytes = 0
28 | var bannerLength = 2
29 | var readFrameBytes = 0
30 | var frameBodyLength = 0
31 | var frameBody = new Buffer(0)
32 | var banner = {
33 | version: 0
34 | , length: 0
35 | , pid: 0
36 | , realWidth: 0
37 | , realHeight: 0
38 | , virtualWidth: 0
39 | , virtualHeight: 0
40 | , orientation: 0
41 | , quirks: 0
42 | }
43 |
44 | function tryRead() {
45 | for (var chunk; (chunk = stream.read());) {
46 | console.info('chunk(length=%d)', chunk.length)
47 | for (var cursor = 0, len = chunk.length; cursor < len;) {
48 | if (readBannerBytes < bannerLength) {
49 | switch (readBannerBytes) {
50 | case 0:
51 | // version
52 | banner.version = chunk[cursor]
53 | break
54 | case 1:
55 | // length
56 | banner.length = bannerLength = chunk[cursor]
57 | break
58 | case 2:
59 | case 3:
60 | case 4:
61 | case 5:
62 | // pid
63 | banner.pid +=
64 | (chunk[cursor] << ((readBannerBytes - 2) * 8)) >>> 0
65 | break
66 | case 6:
67 | case 7:
68 | case 8:
69 | case 9:
70 | // real width
71 | banner.realWidth +=
72 | (chunk[cursor] << ((readBannerBytes - 6) * 8)) >>> 0
73 | break
74 | case 10:
75 | case 11:
76 | case 12:
77 | case 13:
78 | // real height
79 | banner.realHeight +=
80 | (chunk[cursor] << ((readBannerBytes - 10) * 8)) >>> 0
81 | break
82 | case 14:
83 | case 15:
84 | case 16:
85 | case 17:
86 | // virtual width
87 | banner.virtualWidth +=
88 | (chunk[cursor] << ((readBannerBytes - 14) * 8)) >>> 0
89 | break
90 | case 18:
91 | case 19:
92 | case 20:
93 | case 21:
94 | // virtual height
95 | banner.virtualHeight +=
96 | (chunk[cursor] << ((readBannerBytes - 18) * 8)) >>> 0
97 | break
98 | case 22:
99 | // orientation
100 | banner.orientation += chunk[cursor] * 90
101 | break
102 | case 23:
103 | // quirks
104 | banner.quirks = chunk[cursor]
105 | break
106 | }
107 |
108 | cursor += 1
109 | readBannerBytes += 1
110 |
111 | if (readBannerBytes === bannerLength) {
112 | console.log('banner', banner)
113 | }
114 | }
115 | else if (readFrameBytes < 4) {
116 | frameBodyLength += (chunk[cursor] << (readFrameBytes * 8)) >>> 0
117 | cursor += 1
118 | readFrameBytes += 1
119 | console.info('headerbyte%d(val=%d)', readFrameBytes, frameBodyLength)
120 | }
121 | else {
122 | if (len - cursor >= frameBodyLength) {
123 | console.info('bodyfin(len=%d,cursor=%d)', frameBodyLength, cursor)
124 |
125 | frameBody = Buffer.concat([
126 | frameBody
127 | , chunk.slice(cursor, cursor + frameBodyLength)
128 | ])
129 |
130 | // Sanity check for JPG header, only here for debugging purposes.
131 | if (frameBody[0] !== 0xFF || frameBody[1] !== 0xD8) {
132 | console.error(
133 | 'Frame body does not start with JPG header', frameBody)
134 | process.exit(1)
135 | }
136 |
137 | ws.send(frameBody, {
138 | binary: true
139 | })
140 |
141 | cursor += frameBodyLength
142 | frameBodyLength = readFrameBytes = 0
143 | frameBody = new Buffer(0)
144 | }
145 | else {
146 | console.info('body(len=%d)', len - cursor)
147 |
148 | frameBody = Buffer.concat([
149 | frameBody
150 | , chunk.slice(cursor, len)
151 | ])
152 |
153 | frameBodyLength -= len - cursor
154 | readFrameBytes += len - cursor
155 | cursor = len
156 | }
157 | }
158 | }
159 | }
160 | }
161 |
162 | stream.on('readable', tryRead)
163 |
164 | ws.on('close', function() {
165 | console.info('Lost a client')
166 | stream.end()
167 | })
168 | })
169 |
170 | server.listen(PORT)
171 | console.info('Listening on port %d', PORT)
172 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "express": "^4.12.3",
4 | "ws": "^0.7.1"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
49 |
--------------------------------------------------------------------------------
/gdb.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Fail on error, verbose output
4 | set -exo pipefail
5 |
6 | # Check NDK setup
7 | if [ -z "$NDK_ROOT" ]; then
8 | echo 'Environment variable $NDK_ROOT required for operation' >&2
9 | exit 1
10 | fi
11 |
12 | # Figure out which ABIs the device supports
13 | abi=$(adb shell getprop ro.product.cpu.abi | tr -d '\r')
14 | sdk=$(adb shell getprop ro.build.version.sdk | tr -d '\r')
15 |
16 | # PIE is only supported since SDK 16
17 | if (($sdk >= 16)); then
18 | bin=minicap
19 | else
20 | bin=minicap-nopie
21 | fi
22 |
23 | # Check if we're debuggable
24 | gdb_setup=$(make --no-print-dir -f "$NDK_ROOT/build/core/build-local.mk" -C "$PWD" DUMP_NDK_APP_GDBSETUP APP_ABI=$abi)
25 | if [ ! -f "$gdb_setup" ]; then
26 | echo "Unable to find $gdb_setup, rebuild with 'ndk-build NDK_DEBUG=1'"
27 | exit 4
28 | fi
29 |
30 | # Get output directory
31 | out=$(make --no-print-dir -f "$NDK_ROOT/build/core/build-local.mk" -C "$PWD" DUMP_TARGET_OUT APP_ABI=$abi)
32 |
33 | # ABI-specific config
34 | prebabi=$abi
35 | libpath=lib
36 | case $abi in
37 | "armeabi" | "armeabi-v7a")
38 | prebabi=arm
39 | ;;
40 | "arm64-v8a")
41 | libpath=lib64
42 | prebabi=arm64
43 | ;;
44 | "x86_64")
45 | libpath=lib64
46 | ;;
47 | "mips64")
48 | libpath=lib64
49 | ;;
50 | esac
51 |
52 | # Validate prebuilt mapping
53 | if [ ! -e "$NDK_ROOT/prebuilt/android-$prebabi" ]; then
54 | echo "Unable to find prebuilts in $NDK_ROOT/prebuilt/android-$prebabi; incorrect mapping?" >&2
55 | exit 3
56 | fi
57 |
58 | # Find toolchain
59 | toolchain=$(make --no-print-dir -f "$NDK_ROOT/build/core/build-local.mk" -C "$PWD" DUMP_TOOLCHAIN_PREFIX APP_ABI=$abi)
60 | gdbclient="${toolchain}gdb"
61 | gdbserver="$NDK_ROOT/prebuilt/android-$prebabi/gdbserver"
62 |
63 | # Create a directory for our resources
64 | dir=/data/local/tmp/minicap-gdb
65 | adb shell "mkdir $dir 2>/dev/null"
66 |
67 | # Find pid
68 | pid=$(adb shell ps | tr -d '\r' | awk '$NF ~ /\/minicap$/ {print $2}' | tail -n1)
69 | if [ -z "$pid" ]; then
70 | echo 'Unable to find minicap pid' >&2
71 | exit 2
72 | fi
73 |
74 | # Upload gdbserver
75 | adb push "$gdbserver" $dir
76 |
77 | # Pull libs
78 | adb pull /system/bin/linker $out/linker
79 | adb pull /system/$libpath $out
80 |
81 | # Launch gdbserver
82 | adb shell $dir/gdbserver :5039 --attach $pid &
83 | gdbserver_pid=$!
84 | trap "kill $gdbserver_pid 2>/dev/null" EXIT
85 |
86 | # Set up the forward
87 | adb forward tcp:5039 tcp:5039
88 |
89 | # Find initial gdb.setup
90 | cp -f "$gdb_setup" gdb.setup
91 |
92 | # Augment gdb.setup
93 | cat <>gdb.setup
94 | file libs/$abi/$bin
95 | target remote :5039
96 | EOT
97 |
98 | # Launch gdb
99 | "$gdbclient" -x gdb.setup
100 |
101 | # Clean up
102 | adb shell rm -r $dir
103 |
--------------------------------------------------------------------------------
/jni/Android.mk:
--------------------------------------------------------------------------------
1 | include $(call all-subdir-makefiles)
2 |
--------------------------------------------------------------------------------
/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
2 |
3 | # Get C++11 working
4 | APP_CPPFLAGS += -std=c++11 -fexceptions
5 | APP_STL := c++_static
6 |
7 | # Disable PIE for SDK <16 support. Enable manually for >=5.0
8 | # where necessary.
9 | APP_PIE := false
10 |
11 | APP_CFLAGS += \
12 | -Ofast \
13 | -funroll-loops \
14 | -fno-strict-aliasing \
15 |
16 | ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
17 | # http://community.arm.com/groups/tools/blog/2013/04/15/arm-cortex-a-processors-and-gcc-command-lines
18 | APP_CFLAGS += \
19 | -march=armv7-a \
20 | -mfpu=neon \
21 | -mfloat-abi=softfp \
22 | -marm \
23 | -fprefetch-loop-arrays \
24 | -DHAVE_NEON=1 \
25 |
26 | else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard)
27 | # http://community.arm.com/groups/tools/blog/2013/04/15/arm-cortex-a-processors-and-gcc-command-lines
28 | APP_CFLAGS += \
29 | -march=armv7-a \
30 | -mfpu=neon \
31 | -mfloat-abi=hard \
32 | -marm \
33 | -fprefetch-loop-arrays \
34 | -DHAVE_NEON=1 \
35 | -mhard-float \
36 | -D_NDK_MATH_NO_SOFTFP=1 \
37 |
38 | APP_LDFLAGS += -lm_hard
39 |
40 | else ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
41 | # http://community.arm.com/groups/tools/blog/2013/04/15/arm-cortex-a-processors-and-gcc-command-lines
42 | APP_CFLAGS += \
43 | -mcpu=cortex-a15 \
44 | -mfpu=neon-vfpv4 \
45 | -mfloat-abi=softfp \
46 | -DHAVE_NEON=1 \
47 |
48 | else ifeq ($(TARGET_ARCH_ABI),x86)
49 | # From Android on x86: An Introduction to Optimizing for Intel® Architecture
50 | # Chapter 12
51 | APP_CFLAGS += \
52 | -fprefetch-loop-arrays \
53 | -fno-short-enums \
54 | -finline-limit=300 \
55 | -fomit-frame-pointer \
56 | -mssse3 \
57 | -mfpmath=sse \
58 | -masm=intel \
59 | -DHAVE_NEON=1 \
60 |
61 | endif
62 |
--------------------------------------------------------------------------------
/jni/minicap-shared/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(abspath $(call my-dir))
2 | include $(CLEAR_VARS)
3 |
4 | LOCAL_MODULE := minicap-shared
5 |
6 | LOCAL_MODULE_FILENAME := minicap
7 |
8 | LOCAL_SRC_FILES := \
9 | mock/Minicap.cpp \
10 |
11 | LOCAL_C_INCLUDES := \
12 | $(LOCAL_PATH)/aosp/include \
13 |
14 | LOCAL_EXPORT_C_INCLUDES := \
15 | $(LOCAL_PATH)/aosp/include \
16 |
17 | include $(BUILD_SHARED_LIBRARY)
18 |
--------------------------------------------------------------------------------
/jni/minicap-shared/README.md:
--------------------------------------------------------------------------------
1 | # minicap-shared
2 |
3 | This module provides the shared library used by minicap. Due to the use of private APIs, it must be built inside the AOSP source tree for each SDK level and architecture. We commit and ship prebuilt libraries inside the source tree for convenience purposes, as getting them compiled can be a major obstacle. The rest of this README assumes that you wish to compile the libraries by yourself, possibly due to trust issues and/or modifications.
4 |
5 | ## Requirements
6 |
7 | There are several ways to set everything up and build the libraries, so we'll just cover the way we've done it. You may adjust the process however you want, but don't expect us to hold your hand if something goes wrong. Overall getting everything set up takes a considerable amount of time, with moderate skill requirements as well. It would be best if you follow the guide unless you're very confident you can do it.
8 |
9 | ### Operating system
10 |
11 | Let's start by saying that **compiling under OS X will not work**. AOSP requires a case-sensitive file system. Furthermore, different branches of the AOSP source tree require different versions of Xcode and JDK, making the process nearly impossible. Try if you're crazy.
12 |
13 | What we use is Linux, latest stable CoreOS to be precise. Our process relies on Docker containers to do the actual compile. The source code is copied via rsync to the Linux machine and then compiled. Any artifacts are transmitted back and added to our source tree so that normal people will not have to go through the whole process.
14 |
15 | Using this setup, the minimum server-side machine requirements are:
16 |
17 | * [docker](https://www.docker.com/)
18 | * [SSH](http://www.openssh.com/)
19 | * A user account with SSH public key authentication and sudo-less access to docker
20 | * Depending on the SDK version, 25-60GB of disk space per built branch, and approximately 120GB for a full mirror. We'll get to the branches later. We recommend a 1TB SSD, possibly more if you wish to compile other things as well (i.e. not just minicap). With branch and mirror sizes ever growing, 512GB will soon not be enough, so don't bother if you want to keep everything on one disk.
21 |
22 | You'll also need [rsync](https://rsync.samba.org/) and [SSH](http://www.openssh.com/) properly set up on your development machine.
23 |
24 | ### Docker images
25 |
26 | Pull the required docker images on the build server as follows:
27 |
28 | ```bash
29 | docker pull openstf/aosp:jdk6
30 | docker pull openstf/aosp:jdk7
31 | docker pull openstf/aosp:jdk8
32 | ```
33 |
34 | These images will be used to both check out code as well as to compile it.
35 |
36 | **A note about security:** containers created from these images currently run under the root user by default. If this is not acceptable to you, you will need to modify the `Makefile` and most of the commands below as you see fit.
37 |
38 | ### AOSP branches
39 |
40 | Currently the following branches are required to build the libraries for all supported SDK levels and architectures:
41 |
42 | | Branch | SDK | Docker image to build with |
43 | |---------------------|-----|-------------------------------|
44 | | android-2.3_r1 | 9 | openstf/aosp:jdk6 |
45 | | android-2.3.3_r1 | 10 | openstf/aosp:jdk6 |
46 | | android-4.0.1_r1 | 14 | openstf/aosp:jdk6 |
47 | | android-4.0.3_r1 | 15 | openstf/aosp:jdk6 |
48 | | android-4.1.1_r1 | 16 | openstf/aosp:jdk6 |
49 | | android-4.2_r1 | 17 | openstf/aosp:jdk6 |
50 | | android-4.3_r1 | 18 | openstf/aosp:jdk6 |
51 | | android-4.4_r1 | 19 | openstf/aosp:jdk6 |
52 | | android-5.0.1_r1 | 21 | openstf/aosp:jdk7 |
53 | | android-5.1.0_r1 | 22 | openstf/aosp:jdk7 |
54 | | android-6.0.0_r1 | 23 | openstf/aosp:jdk7 |
55 | | android-7.0.0_r1 | 24 | openstf/aosp:jdk8 |
56 | | android-7.1.0_r1 | 25 | openstf/aosp:jdk8 |
57 | | android-8.0.0_r1 | 26 | openstf/aosp:jdk8 |
58 | | android-8.1.0_r1 | 27 | openstf/aosp:jdk8 |
59 | | android-9.0.0_r1 | 28 | openstf/aosp:jdk8 |
60 |
61 | Furthermore, to make use of our provided Makefile, you should check out the branches to `/media/aosp` for maximum ease of use.
62 |
63 | To check out the branches, you have two options. To reduce download time and avoid bandwidth caps (on the server side), it would be advisable to fetch a full local mirror and then checkout out the individual branches from there. What tends to happen, though, is that the mirror manifest does not get updated quickly enough for new branches, and may be missing a repository or two, making it practically impossible to check out the branch you want. Additionally, the mirror takes over 120GB of disk space in addition to the checkouts.
64 |
65 | You can also skip the mirror and download each branch directly, but that will stress the AOSP server unnecessarily.
66 |
67 | Our recommended solution is to use a mirror and use it for all the branches you can, and if a branch fails due to a missing repo, then checkout that branch directly from the server.
68 |
69 | ### AOSP authentication
70 |
71 | AOSP has fairly recently introduced heavy bandwidth caps on their repos. You may have to authenticate yourself [as explained](https://source.android.com/source/downloading.html#using-authentication) by the download guide. Use the link in the guide to get your `.gitcookies` file.
72 |
73 | You'll need to put the file on your build machine. It needs to have correct permissions (i.e. `0600`) and belong to the user checking out the code. Since our process uses the root user inside the containers, make sure to set the owner and group as well.
74 |
75 | ```bash
76 | chown root:root .gitcookies
77 | chmod 0600 .gitcookies
78 | ```
79 |
80 | Use sudo where required.
81 |
82 | We will later mount this file on our containers when checking out code. Note that if you still run into bandwidth caps you may just have to wait.
83 |
84 | ### Get familiar with the checkout/build wrapper script
85 |
86 | There are bundled helper scripts inside the docker images. To see what commands you have available, run the following command.
87 |
88 | ```bash
89 | docker run -ti --rm openstf/aosp:jdk7 /aosp.sh help
90 | ```
91 |
92 | ### Creating an AOSP mirror
93 |
94 | Now that we're a bit more familiar with the helper script, let's start fetching our mirror.
95 |
96 | ```bash
97 | docker run -ti --rm \
98 | -v /media/aosp/mirror:/mirror \
99 | -v $PWD/.gitcookies:/root/.gitcookies:ro \
100 | openstf/aosp:jdk7 \
101 | /aosp.sh create-mirror
102 | ```
103 |
104 | This will take a LONG time, easily several hours. You may wish to leave it running overnight. If an error occurs (it will tell you), run the same command again and again until it finishes without errors.
105 |
106 | When the command is done, you should have a copy of the latest mirror in `/media/aosp/mirror`. We will mount this mirror when checking out individual branches.
107 |
108 | You should rerun the command whenever a new branch you're interested in gets added to AOSP to sync the mirrored repos.
109 |
110 | ### Check out branches (using mirror)
111 |
112 | We had a table of the needed AOSP branches earlier. The docker image for each SDK level may be different, but it should not make much difference when simply checking out code, so you should be able to use one image to check out all branches. However, if you do run into problems, you may also wish to try using the proper JDK when checking out. Check out the branch table above to see which one to use for each branch.
113 |
114 | For each branch in the table, run the following command:
115 |
116 | ```bash
117 | docker run -ti --rm \
118 | -v /media/aosp/mirror:/mirror \
119 | -v /media/aosp/android-5.1.0_r1:/aosp \
120 | -v $PWD/.gitcookies:/root/.gitcookies:ro \
121 | openstf/aosp:jdk7 \
122 | /aosp.sh checkout-branch android-5.1.0_r1
123 | ```
124 |
125 | Note that the branch name is both in the mounted folder name and an option to the checkout-branch command. You have to replace both when checking out other branches.
126 |
127 | Checking out a single branch should not take that long, perhaps 10-20 minutes per branch. Use a faster disk for better results.
128 |
129 | Should an error occur, you can try running the command again. However, since we're using the mirror, errors shouldn't really happen. Like explained earlier, the mirror may be incomplete. If that's the case, you may have to try a direct download instead, explained next.
130 |
131 | ### Check out branches (using direct download)
132 |
133 | For each branch you wish to download directly from the AOSP servers, run the following command:
134 |
135 | ```bash
136 | docker run -ti --rm \
137 | -v /media/aosp/android-5.1.0_r1:/aosp \
138 | -v $PWD/.gitcookies:/root/.gitcookies:ro \
139 | openstf/aosp:jdk7 \
140 | /aosp.sh checkout-branch --no-mirror android-5.1.0_r1
141 | ```
142 |
143 | Note that the branch name is both in the mounted folder name and an option to the checkout-branch command. You have to replace both when checking out other branches.
144 |
145 | Should an error occur, you can try running the command again. Depending on your luck you may have to run the command several times, and if you hit a bandwidth cap, distribute your downloads over several days.
146 |
147 | Checking out a single branch will easily take a few hours, but it is considerably faster than setting up a full mirror.
148 |
149 | ### Saving disk space (optional)
150 |
151 | If you're sure that you'll never need to use the Android `repo` tool on a branch you've already checked out, you can save ~40-50% of disk space by deleting the `.repo` folder inside each branch. However, be very careful not to delete the mirror's `.repo`, since you'll probably want to update it at some point in the future.
152 |
153 | ### Building
154 |
155 | There's a `Makefile` in the `aosp` folder containing a build command for each SDK level and architecture we're interested in. If you're developing on Linux directly you may be able to `make` the libraries directly.
156 |
157 | More likely, though, you'll actually want to use the `build-remote.sh` script at the root of the minicap repo. It's not very pretty but it works. It transmits the source code to the target machine and uses one of the docker images to run `make` inside a docker container (which is done because CoreOS doesn't come with make).
158 |
159 | First, you'll need to tell the script where you're building.
160 |
161 | ```bash
162 | export BUILD_HOST=core@stf-build001
163 | ```
164 |
165 | This will be passed to SSH and rsync, and is able to benefit from your SSH config (which you must set up yourself as you like).
166 |
167 | Now, run the build script:
168 |
169 | ```bash
170 | ./build-remote.sh
171 | ```
172 |
173 | The first compile will take a long, long time, since it needs to compile all dependencies on the first run, for each architecture.
174 |
175 | ### Rebuilding
176 |
177 | Any recompile after the first time will benefit from the already build dependencies and will go a lot faster, although it will still take a considerable amount of time. The `Makefile` attemps to be intelligent about which branches need to be rebuilt, but touching the common code base or the `Android.mk` file will usually require a recompile on each SDK and architecture. That by itself is reasonably fast, but setting up the AOSP build takes the most time anyway. It may take 5-15 minutes in total to do an "empty run" for each branch and architecture.
178 |
179 | Our advice? Be damn sure your code compiles before actually compiling :)
180 |
181 | Alternatively, you may wish to temporarily remove other targets from the `Makefile` all target when working on bigger changes but focusing on a single branch.
182 |
183 | In any case, congratulations, you're done!
184 |
185 | ### Tips
186 |
187 | Here's a systemd unit to keep an external disk mounted in `/media/aosp`. It assumes you have a btrfs-formatted partition labeled `AOSP` on a disk somewhere, mine's on an external SSD. Example of how to create one:
188 |
189 | ```sh
190 | mkfs.btrfs -L AOSP /dev/sdc1
191 | ```
192 |
193 | And here's the corresponding unit:
194 |
195 | ```systemd
196 | [Mount]
197 | What=/dev/disk/by-label/AOSP
198 | Where=/media/aosp
199 | Type=btrfs
200 |
201 | [Install]
202 | WantedBy=multi-user.target
203 | ```
204 |
205 | Now just run `systemctl enable media-aosp.mount && systemctl start media-aosp.mount`.
206 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/.rsync-filter:
--------------------------------------------------------------------------------
1 | - .git
2 | - libs
3 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 | include $(CLEAR_VARS)
3 |
4 | LOCAL_MODULE := minicap
5 |
6 | LOCAL_MODULE_TAGS := optional
7 |
8 | ifneq ($(OVERRIDE_PLATFORM_SDK_VERSION),)
9 | LOCAL_SRC_FILES += src/minicap_$(OVERRIDE_PLATFORM_SDK_VERSION).cpp
10 | else ifeq ($(PLATFORM_SDK_VERSION),29)
11 | LOCAL_SRC_FILES += src/minicap_29.cpp
12 | else ifeq ($(PLATFORM_SDK_VERSION),28)
13 | LOCAL_SRC_FILES += src/minicap_28.cpp
14 | else ifeq ($(PLATFORM_SDK_VERSION),27)
15 | LOCAL_SRC_FILES += src/minicap_27.cpp
16 | else ifeq ($(PLATFORM_SDK_VERSION),26)
17 | LOCAL_SRC_FILES += src/minicap_26.cpp
18 | else ifeq ($(PLATFORM_SDK_VERSION),25)
19 | LOCAL_SRC_FILES += src/minicap_25.cpp
20 | else ifeq ($(PLATFORM_SDK_VERSION),24)
21 | LOCAL_SRC_FILES += src/minicap_24.cpp
22 | else ifeq ($(PLATFORM_SDK_VERSION),23)
23 | LOCAL_SRC_FILES += src/minicap_23.cpp
24 | else ifeq ($(PLATFORM_SDK_VERSION),22)
25 | LOCAL_SRC_FILES += src/minicap_22.cpp
26 | else ifeq ($(PLATFORM_SDK_VERSION),21)
27 | LOCAL_SRC_FILES += src/minicap_21.cpp
28 | else ifeq ($(PLATFORM_SDK_VERSION),19)
29 | LOCAL_SRC_FILES += src/minicap_19.cpp
30 | else ifeq ($(PLATFORM_SDK_VERSION),18)
31 | LOCAL_SRC_FILES += src/minicap_18.cpp
32 | else ifeq ($(PLATFORM_SDK_VERSION),17)
33 | LOCAL_SRC_FILES += src/minicap_17.cpp
34 | else ifeq ($(PLATFORM_SDK_VERSION),16)
35 | LOCAL_SRC_FILES += src/minicap_16.cpp
36 | else ifeq ($(PLATFORM_SDK_VERSION),15)
37 | LOCAL_SRC_FILES += src/minicap_14.cpp
38 | else ifeq ($(PLATFORM_SDK_VERSION),14)
39 | LOCAL_SRC_FILES += src/minicap_14.cpp
40 | else ifeq ($(PLATFORM_SDK_VERSION),10)
41 | LOCAL_SRC_FILES += src/minicap_9.cpp
42 | else ifeq ($(PLATFORM_SDK_VERSION),9)
43 | LOCAL_SRC_FILES += src/minicap_9.cpp
44 | endif
45 |
46 | LOCAL_PRELINK_MODULE := false
47 |
48 | LOCAL_SHARED_LIBRARIES := \
49 | libcutils \
50 | libutils \
51 | libbinder \
52 | libui \
53 | liblog \
54 |
55 | ifeq ($(PLATFORM_SDK_VERSION),$(filter $(PLATFORM_SDK_VERSION),10 9))
56 | LOCAL_SHARED_LIBRARIES += libsurfaceflinger_client
57 | else
58 | LOCAL_SHARED_LIBRARIES += libgui
59 | endif
60 |
61 | LOCAL_C_INCLUDES += \
62 | $(LOCAL_PATH)/include \
63 |
64 | LOCAL_CFLAGS += -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
65 |
66 | include $(BUILD_SHARED_LIBRARY)
67 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/include/Minicap.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MINICAP_HPP
2 | #define MINICAP_HPP
3 |
4 | #include
5 |
6 | class Minicap {
7 | public:
8 | enum CaptureMethod {
9 | METHOD_FRAMEBUFFER = 1,
10 | METHOD_SCREENSHOT = 2,
11 | METHOD_VIRTUAL_DISPLAY = 3,
12 | };
13 |
14 | enum Format {
15 | FORMAT_NONE = 0x01,
16 | FORMAT_CUSTOM = 0x02,
17 | FORMAT_TRANSLUCENT = 0x03,
18 | FORMAT_TRANSPARENT = 0x04,
19 | FORMAT_OPAQUE = 0x05,
20 | FORMAT_RGBA_8888 = 0x06,
21 | FORMAT_RGBX_8888 = 0x07,
22 | FORMAT_RGB_888 = 0x08,
23 | FORMAT_RGB_565 = 0x09,
24 | FORMAT_BGRA_8888 = 0x0a,
25 | FORMAT_RGBA_5551 = 0x0b,
26 | FORMAT_RGBA_4444 = 0x0c,
27 | FORMAT_UNKNOWN = 0x00,
28 | };
29 |
30 | enum Orientation {
31 | ORIENTATION_0 = 0,
32 | ORIENTATION_90 = 1,
33 | ORIENTATION_180 = 2,
34 | ORIENTATION_270 = 3,
35 | };
36 |
37 | struct DisplayInfo {
38 | uint32_t width;
39 | uint32_t height;
40 | float fps;
41 | float density;
42 | float xdpi;
43 | float ydpi;
44 | float size;
45 | uint8_t orientation;
46 | bool secure;
47 | };
48 |
49 | struct Frame {
50 | void const* data;
51 | Format format;
52 | uint32_t width;
53 | uint32_t height;
54 | uint32_t stride;
55 | uint32_t bpp;
56 | size_t size;
57 | };
58 |
59 | struct FrameAvailableListener {
60 | virtual
61 | ~FrameAvailableListener() {}
62 |
63 | virtual void
64 | onFrameAvailable() = 0;
65 | };
66 |
67 | Minicap() {}
68 |
69 | virtual
70 | ~Minicap() {}
71 |
72 | // Applies changes made by setDesiredInfo() and setRealInfo(). Must be
73 | // called before attempting to wait or consume frames.
74 | virtual int
75 | applyConfigChanges() = 0;
76 |
77 | // Consumes a frame. Must be called after waitForFrame().
78 | virtual int
79 | consumePendingFrame(Frame* frame) = 0;
80 |
81 | // Peek behind the scenes to see which capture method is actually
82 | // being used.
83 | virtual CaptureMethod
84 | getCaptureMethod() = 0;
85 |
86 | // Get display ID.
87 | virtual int32_t
88 | getDisplayId() = 0;
89 |
90 | // Release all resources.
91 | virtual void
92 | release() = 0;
93 |
94 | // Releases a consumed frame so that it can be reused by Android again.
95 | // Must be called before consumePendingFrame() is called again.
96 | virtual void
97 | releaseConsumedFrame(Frame* frame) = 0;
98 |
99 | // Set desired information about the display. Currently, only the
100 | // following properties are actually used: width, height and orientation.
101 | // After the configuration has been applied, new frames should satisfy
102 | // the requirements.
103 | virtual int
104 | setDesiredInfo(const DisplayInfo& info) = 0;
105 |
106 | // Sets the frame available listener.
107 | virtual void
108 | setFrameAvailableListener(FrameAvailableListener* listener) = 0;
109 |
110 | // Set the display's real information. This cannot be accessed automatically
111 | // due to manufacturers (mainly Samsung) having customized
112 | // android::DisplayInfo. The information has to be gathered somehow and then
113 | // passed on here. Currently only the following properties are actually
114 | // used: width and height.
115 | virtual int
116 | setRealInfo(const DisplayInfo& info) = 0;
117 | };
118 |
119 | // Attempt to get information about the given display. This may segfault
120 | // on some devices due to manufacturer (mainly Samsung) customizations.
121 | int
122 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info);
123 |
124 | // Creates a new Minicap instance for the current platform.
125 | Minicap*
126 | minicap_create(int32_t displayId);
127 |
128 | // Frees a Minicap instance. Don't call delete yourself as it won't have
129 | // access to the platform-specific modifications.
130 | void
131 | minicap_free(Minicap* mc);
132 |
133 | // Starts an Android thread pool. Must be called before doing anything else.
134 | void
135 | minicap_start_thread_pool();
136 |
137 | #endif
138 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/include/mcdebug.h:
--------------------------------------------------------------------------------
1 | #ifndef __minicap_dbg_h__
2 | #define __minicap_dbg_h__
3 |
4 | // These macros were originally from
5 | // http://c.learncodethehardway.org/book/ex20.html
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | #ifdef NDEBUG
12 | #define MCDEBUG(M, ...)
13 | #else
14 | #define MCDEBUG(M, ...) fprintf(stderr, "DEBUG: %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
15 | #endif
16 |
17 | #define MCCLEAN_ERRNO() (errno == 0 ? "None" : strerror(errno))
18 |
19 | #define MCERROR(M, ...) fprintf(stderr, "ERROR: (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, MCCLEAN_ERRNO(), ##__VA_ARGS__)
20 |
21 | #define MCWARN(M, ...) fprintf(stderr, "WARN: (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, MCCLEAN_ERRNO(), ##__VA_ARGS__)
22 |
23 | #define MCINFO(M, ...) fprintf(stderr, "INFO: (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
24 |
25 | #define MCCHECK(A, M, ...) if(!(A)) { MCERROR(M, ##__VA_ARGS__); errno=0; goto error; }
26 |
27 | #define MCSENTINEL(M, ...) { MCERROR(M, ##__VA_ARGS__); errno=0; goto error; }
28 |
29 | #define MCCHECK_MEM(A) check((A), "Out of memory.")
30 |
31 | #define MCCHECK_DEBUG(A, M, ...) if(!(A)) { MCDEBUG(M, ##__VA_ARGS__); errno=0; goto error; }
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-10/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-10/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-14/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-14/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-14/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-14/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-15/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-15/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-15/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-15/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-16/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-16/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-16/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-16/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-17/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-17/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-17/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-17/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-18/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-18/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-18/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-18/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-19/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-19/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-19/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-19/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-21/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-21/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-21/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-21/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-21/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-21/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-21/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-21/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-22/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-22/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-22/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-22/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-22/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-22/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-22/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-22/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-23/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-23/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-23/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-23/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-23/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-23/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-23/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-23/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-24/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-24/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-24/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-24/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-24/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-24/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-24/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-24/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-25/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-25/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-25/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-25/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-25/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-25/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-25/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-25/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-26/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-26/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-26/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-26/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-26/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-26/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-26/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-26/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-27/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-27/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-27/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-27/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-27/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-27/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-27/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-27/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-28/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-28/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-28/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-28/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-28/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-28/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-28/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-28/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-29/arm64-v8a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-29/arm64-v8a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-29/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-29/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-29/x86/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-29/x86/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-29/x86_64/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-29/x86_64/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/libs/android-9/armeabi-v7a/minicap.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstf/minicap/0ee92b4741e45660040c759fc63df75ce8c4c4b5/jni/minicap-shared/aosp/libs/android-9/armeabi-v7a/minicap.so
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_14.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 |
20 | #include "mcdebug.h"
21 |
22 | static const char*
23 | error_name(int32_t err) {
24 | switch (err) {
25 | case android::NO_ERROR: // also android::OK
26 | return "NO_ERROR";
27 | case android::UNKNOWN_ERROR:
28 | return "UNKNOWN_ERROR";
29 | case android::NO_MEMORY:
30 | return "NO_MEMORY";
31 | case android::INVALID_OPERATION:
32 | return "INVALID_OPERATION";
33 | case android::BAD_VALUE:
34 | return "BAD_VALUE";
35 | case android::BAD_TYPE:
36 | return "BAD_TYPE";
37 | case android::NAME_NOT_FOUND:
38 | return "NAME_NOT_FOUND";
39 | case android::PERMISSION_DENIED:
40 | return "PERMISSION_DENIED";
41 | case android::NO_INIT:
42 | return "NO_INIT";
43 | case android::ALREADY_EXISTS:
44 | return "ALREADY_EXISTS";
45 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
46 | return "DEAD_OBJECT";
47 | case android::FAILED_TRANSACTION:
48 | return "FAILED_TRANSACTION";
49 | case android::BAD_INDEX:
50 | return "BAD_INDEX";
51 | case android::NOT_ENOUGH_DATA:
52 | return "NOT_ENOUGH_DATA";
53 | case android::WOULD_BLOCK:
54 | return "WOULD_BLOCK";
55 | case android::TIMED_OUT:
56 | return "TIMED_OUT";
57 | case android::UNKNOWN_TRANSACTION:
58 | return "UNKNOWN_TRANSACTION";
59 | case android::FDS_NOT_ALLOWED:
60 | return "FDS_NOT_ALLOWED";
61 | default:
62 | return "UNMAPPED_ERROR";
63 | }
64 | }
65 |
66 | class MinicapImpl: public Minicap {
67 | public:
68 | MinicapImpl(int32_t displayId)
69 | : mDisplayId(displayId),
70 | mComposer(android::ComposerService::getComposerService()),
71 | mDesiredWidth(0),
72 | mDesiredHeight(0) {
73 | }
74 |
75 | virtual
76 | ~MinicapImpl() {
77 | release();
78 | }
79 |
80 | virtual int
81 | applyConfigChanges() {
82 | mUserFrameAvailableListener->onFrameAvailable();
83 | return 0;
84 | }
85 |
86 | virtual int
87 | consumePendingFrame(Minicap::Frame* frame) {
88 | uint32_t width, height;
89 | android::PixelFormat format;
90 | android::status_t err;
91 |
92 | mHeap = NULL;
93 | err = mComposer->captureScreen(mDisplayId, &mHeap,
94 | &width, &height, &format, mDesiredWidth, mDesiredHeight, 0, -1UL);
95 |
96 | if (err != android::NO_ERROR) {
97 | MCERROR("ComposerService::captureScreen() failed %s", error_name(err));
98 | return err;
99 | }
100 |
101 | frame->data = mHeap->getBase();
102 | frame->width = width;
103 | frame->height = height;
104 | frame->format = convertFormat(format);
105 | frame->stride = width;
106 | frame->bpp = android::bytesPerPixel(format);
107 | frame->size = mHeap->getSize();
108 |
109 | return 0;
110 | }
111 |
112 | virtual Minicap::CaptureMethod
113 | getCaptureMethod() {
114 | return METHOD_SCREENSHOT;
115 | }
116 |
117 | virtual int32_t
118 | getDisplayId() {
119 | return mDisplayId;
120 | }
121 |
122 | virtual void
123 | release() {
124 | mHeap = NULL;
125 | }
126 |
127 | virtual void
128 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
129 | mHeap = NULL;
130 | return mUserFrameAvailableListener->onFrameAvailable();
131 | }
132 |
133 | virtual int
134 | setDesiredInfo(const Minicap::DisplayInfo& info) {
135 | mDesiredWidth = info.width;
136 | mDesiredHeight = info.height;
137 | return 0;
138 | }
139 |
140 | virtual void
141 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
142 | mUserFrameAvailableListener = listener;
143 | }
144 |
145 | virtual int
146 | setRealInfo(const Minicap::DisplayInfo& info) {
147 | return 0;
148 | }
149 |
150 | private:
151 | int32_t mDisplayId;
152 | android::sp mComposer;
153 | android::sp mHeap;
154 | uint32_t mDesiredWidth;
155 | uint32_t mDesiredHeight;
156 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
157 |
158 | static Minicap::Format
159 | convertFormat(android::PixelFormat format) {
160 | switch (format) {
161 | case android::PIXEL_FORMAT_NONE:
162 | return FORMAT_NONE;
163 | case android::PIXEL_FORMAT_CUSTOM:
164 | return FORMAT_CUSTOM;
165 | case android::PIXEL_FORMAT_TRANSLUCENT:
166 | return FORMAT_TRANSLUCENT;
167 | case android::PIXEL_FORMAT_TRANSPARENT:
168 | return FORMAT_TRANSPARENT;
169 | case android::PIXEL_FORMAT_OPAQUE:
170 | return FORMAT_OPAQUE;
171 | case android::PIXEL_FORMAT_RGBA_8888:
172 | return FORMAT_RGBA_8888;
173 | case android::PIXEL_FORMAT_RGBX_8888:
174 | return FORMAT_RGBX_8888;
175 | case android::PIXEL_FORMAT_RGB_888:
176 | return FORMAT_RGB_888;
177 | case android::PIXEL_FORMAT_RGB_565:
178 | return FORMAT_RGB_565;
179 | case android::PIXEL_FORMAT_BGRA_8888:
180 | return FORMAT_BGRA_8888;
181 | case android::PIXEL_FORMAT_RGBA_5551:
182 | return FORMAT_RGBA_5551;
183 | case android::PIXEL_FORMAT_RGBA_4444:
184 | return FORMAT_RGBA_4444;
185 | default:
186 | return FORMAT_UNKNOWN;
187 | }
188 | }
189 | };
190 |
191 | int
192 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
193 | android::DisplayInfo dinfo;
194 | android::status_t err = android::SurfaceComposerClient::getDisplayInfo(displayId, &dinfo);
195 |
196 | if (err != android::NO_ERROR) {
197 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
198 | return err;
199 | }
200 |
201 | info->width = dinfo.w;
202 | info->height = dinfo.h;
203 | info->orientation = dinfo.orientation;
204 | info->fps = dinfo.fps;
205 | info->density = dinfo.density;
206 | info->xdpi = dinfo.xdpi;
207 | info->ydpi = dinfo.ydpi;
208 | info->secure = false;
209 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
210 |
211 | return 0;
212 | }
213 |
214 | Minicap*
215 | minicap_create(int32_t displayId) {
216 | return new MinicapImpl(displayId);
217 | }
218 |
219 | void
220 | minicap_free(Minicap* mc) {
221 | delete mc;
222 | }
223 |
224 | void
225 | minicap_start_thread_pool() {
226 | android::ProcessState::self()->startThreadPool();
227 | }
228 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_16.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 |
17 | #include
18 |
19 | #include
20 | #include
21 |
22 | #include "mcdebug.h"
23 |
24 | static const char*
25 | error_name(int32_t err) {
26 | switch (err) {
27 | case android::NO_ERROR: // also android::OK
28 | return "NO_ERROR";
29 | case android::UNKNOWN_ERROR:
30 | return "UNKNOWN_ERROR";
31 | case android::NO_MEMORY:
32 | return "NO_MEMORY";
33 | case android::INVALID_OPERATION:
34 | return "INVALID_OPERATION";
35 | case android::BAD_VALUE:
36 | return "BAD_VALUE";
37 | case android::BAD_TYPE:
38 | return "BAD_TYPE";
39 | case android::NAME_NOT_FOUND:
40 | return "NAME_NOT_FOUND";
41 | case android::PERMISSION_DENIED:
42 | return "PERMISSION_DENIED";
43 | case android::NO_INIT:
44 | return "NO_INIT";
45 | case android::ALREADY_EXISTS:
46 | return "ALREADY_EXISTS";
47 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
48 | return "DEAD_OBJECT";
49 | case android::FAILED_TRANSACTION:
50 | return "FAILED_TRANSACTION";
51 | case android::BAD_INDEX:
52 | return "BAD_INDEX";
53 | case android::NOT_ENOUGH_DATA:
54 | return "NOT_ENOUGH_DATA";
55 | case android::WOULD_BLOCK:
56 | return "WOULD_BLOCK";
57 | case android::TIMED_OUT:
58 | return "TIMED_OUT";
59 | case android::UNKNOWN_TRANSACTION:
60 | return "UNKNOWN_TRANSACTION";
61 | case android::FDS_NOT_ALLOWED:
62 | return "FDS_NOT_ALLOWED";
63 | default:
64 | return "UNMAPPED_ERROR";
65 | }
66 | }
67 |
68 | class MinicapImpl: public Minicap {
69 | public:
70 | MinicapImpl(int32_t displayId)
71 | : mDisplayId(displayId),
72 | mComposer(android::ComposerService::getComposerService()),
73 | mDesiredWidth(0),
74 | mDesiredHeight(0) {
75 | }
76 |
77 | virtual
78 | ~MinicapImpl() {
79 | release();
80 | }
81 |
82 | virtual int
83 | applyConfigChanges() {
84 | mUserFrameAvailableListener->onFrameAvailable();
85 | return 0;
86 | }
87 |
88 | virtual int
89 | consumePendingFrame(Minicap::Frame* frame) {
90 | uint32_t width, height;
91 | android::PixelFormat format;
92 | android::status_t err;
93 |
94 | mHeap = NULL;
95 | err = mComposer->captureScreen(mDisplayId, &mHeap,
96 | &width, &height, &format, mDesiredWidth, mDesiredHeight, 0, -1UL);
97 |
98 | if (err != android::NO_ERROR) {
99 | MCERROR("ComposerService::captureScreen() failed %s", error_name(err));
100 | return err;
101 | }
102 |
103 | frame->data = mHeap->getBase();
104 | frame->width = width;
105 | frame->height = height;
106 | frame->format = convertFormat(format);
107 | frame->stride = width;
108 | frame->bpp = android::bytesPerPixel(format);
109 | frame->size = mHeap->getSize();
110 |
111 | return 0;
112 | }
113 |
114 | virtual Minicap::CaptureMethod
115 | getCaptureMethod() {
116 | return METHOD_SCREENSHOT;
117 | }
118 |
119 | virtual int32_t
120 | getDisplayId() {
121 | return mDisplayId;
122 | }
123 |
124 | virtual void
125 | release() {
126 | mHeap = NULL;
127 | }
128 |
129 | virtual void
130 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
131 | mHeap = NULL;
132 | return mUserFrameAvailableListener->onFrameAvailable();
133 | }
134 |
135 | virtual int
136 | setDesiredInfo(const Minicap::DisplayInfo& info) {
137 | mDesiredWidth = info.width;
138 | mDesiredHeight = info.height;
139 | return 0;
140 | }
141 |
142 | virtual void
143 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
144 | mUserFrameAvailableListener = listener;
145 | }
146 |
147 | virtual int
148 | setRealInfo(const Minicap::DisplayInfo& info) {
149 | return 0;
150 | }
151 |
152 | private:
153 | int32_t mDisplayId;
154 | android::sp mComposer;
155 | android::sp mHeap;
156 | uint32_t mDesiredWidth;
157 | uint32_t mDesiredHeight;
158 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
159 |
160 | static Minicap::Format
161 | convertFormat(android::PixelFormat format) {
162 | switch (format) {
163 | case android::PIXEL_FORMAT_NONE:
164 | return FORMAT_NONE;
165 | case android::PIXEL_FORMAT_CUSTOM:
166 | return FORMAT_CUSTOM;
167 | case android::PIXEL_FORMAT_TRANSLUCENT:
168 | return FORMAT_TRANSLUCENT;
169 | case android::PIXEL_FORMAT_TRANSPARENT:
170 | return FORMAT_TRANSPARENT;
171 | case android::PIXEL_FORMAT_OPAQUE:
172 | return FORMAT_OPAQUE;
173 | case android::PIXEL_FORMAT_RGBA_8888:
174 | return FORMAT_RGBA_8888;
175 | case android::PIXEL_FORMAT_RGBX_8888:
176 | return FORMAT_RGBX_8888;
177 | case android::PIXEL_FORMAT_RGB_888:
178 | return FORMAT_RGB_888;
179 | case android::PIXEL_FORMAT_RGB_565:
180 | return FORMAT_RGB_565;
181 | case android::PIXEL_FORMAT_BGRA_8888:
182 | return FORMAT_BGRA_8888;
183 | case android::PIXEL_FORMAT_RGBA_5551:
184 | return FORMAT_RGBA_5551;
185 | case android::PIXEL_FORMAT_RGBA_4444:
186 | return FORMAT_RGBA_4444;
187 | default:
188 | return FORMAT_UNKNOWN;
189 | }
190 | }
191 | };
192 |
193 | int
194 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
195 | android::DisplayInfo dinfo;
196 | android::status_t err = android::SurfaceComposerClient::getDisplayInfo(displayId, &dinfo);
197 |
198 | if (err != android::NO_ERROR) {
199 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
200 | return err;
201 | }
202 |
203 | info->width = dinfo.w;
204 | info->height = dinfo.h;
205 | info->orientation = dinfo.orientation;
206 | info->fps = dinfo.fps;
207 | info->density = dinfo.density;
208 | info->xdpi = dinfo.xdpi;
209 | info->ydpi = dinfo.ydpi;
210 | info->secure = false;
211 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
212 |
213 | return 0;
214 | }
215 |
216 | Minicap*
217 | minicap_create(int32_t displayId) {
218 | return new MinicapImpl(displayId);
219 | }
220 |
221 | void
222 | minicap_free(Minicap* mc) {
223 | delete mc;
224 | }
225 |
226 | void
227 | minicap_start_thread_pool() {
228 | android::ProcessState::self()->startThreadPool();
229 | }
230 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_17.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #include "mcdebug.h"
27 |
28 | static const char*
29 | error_name(int32_t err) {
30 | switch (err) {
31 | case android::NO_ERROR: // also android::OK
32 | return "NO_ERROR";
33 | case android::UNKNOWN_ERROR:
34 | return "UNKNOWN_ERROR";
35 | case android::NO_MEMORY:
36 | return "NO_MEMORY";
37 | case android::INVALID_OPERATION:
38 | return "INVALID_OPERATION";
39 | case android::BAD_VALUE:
40 | return "BAD_VALUE";
41 | case android::BAD_TYPE:
42 | return "BAD_TYPE";
43 | case android::NAME_NOT_FOUND:
44 | return "NAME_NOT_FOUND";
45 | case android::PERMISSION_DENIED:
46 | return "PERMISSION_DENIED";
47 | case android::NO_INIT:
48 | return "NO_INIT";
49 | case android::ALREADY_EXISTS:
50 | return "ALREADY_EXISTS";
51 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
52 | return "DEAD_OBJECT";
53 | case android::FAILED_TRANSACTION:
54 | return "FAILED_TRANSACTION";
55 | case android::BAD_INDEX:
56 | return "BAD_INDEX";
57 | case android::NOT_ENOUGH_DATA:
58 | return "NOT_ENOUGH_DATA";
59 | case android::WOULD_BLOCK:
60 | return "WOULD_BLOCK";
61 | case android::TIMED_OUT:
62 | return "TIMED_OUT";
63 | case android::UNKNOWN_TRANSACTION:
64 | return "UNKNOWN_TRANSACTION";
65 | case android::FDS_NOT_ALLOWED:
66 | return "FDS_NOT_ALLOWED";
67 | default:
68 | return "UNMAPPED_ERROR";
69 | }
70 | }
71 |
72 | class FrameProxy: public android::ConsumerBase::FrameAvailableListener {
73 | public:
74 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
75 | }
76 |
77 | virtual void
78 | onFrameAvailable() {
79 | mUserListener->onFrameAvailable();
80 | }
81 |
82 | private:
83 | Minicap::FrameAvailableListener* mUserListener;
84 | };
85 |
86 | class MinicapImpl: public Minicap
87 | {
88 | public:
89 | MinicapImpl(int32_t displayId)
90 | : mDisplayId(displayId),
91 | mRealWidth(0),
92 | mRealHeight(0),
93 | mDesiredWidth(0),
94 | mDesiredHeight(0),
95 | mDesiredOrientation(0),
96 | mHaveBuffer(false),
97 | mHaveRunningDisplay(false) {
98 | }
99 |
100 | virtual
101 | ~MinicapImpl() {
102 | release();
103 | }
104 |
105 | virtual int
106 | applyConfigChanges() {
107 | if (mHaveRunningDisplay) {
108 | destroyVirtualDisplay();
109 | }
110 |
111 | return createVirtualDisplay();
112 | }
113 |
114 | virtual int
115 | consumePendingFrame(Minicap::Frame* frame) {
116 | android::status_t err;
117 |
118 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
119 | if (err == -EINTR) {
120 | return err;
121 | }
122 | else {
123 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
124 | return err;
125 | }
126 | }
127 |
128 | frame->data = mBuffer.data;
129 | frame->format = convertFormat(mBuffer.format);
130 | frame->width = mBuffer.width;
131 | frame->height = mBuffer.height;
132 | frame->stride = mBuffer.stride;
133 | frame->bpp = android::bytesPerPixel(mBuffer.format);
134 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
135 |
136 | mHaveBuffer = true;
137 |
138 | return 0;
139 | }
140 |
141 | virtual Minicap::CaptureMethod
142 | getCaptureMethod() {
143 | return METHOD_VIRTUAL_DISPLAY;
144 | }
145 |
146 | virtual int32_t
147 | getDisplayId() {
148 | return mDisplayId;
149 | }
150 |
151 | virtual void
152 | release() {
153 | destroyVirtualDisplay();
154 | }
155 |
156 | virtual void
157 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
158 | if (mHaveBuffer) {
159 | mConsumer->unlockBuffer(mBuffer);
160 | mHaveBuffer = false;
161 | }
162 | }
163 |
164 | virtual int
165 | setDesiredInfo(const Minicap::DisplayInfo& info) {
166 | mDesiredWidth = info.width;
167 | mDesiredHeight = info.height;
168 | mDesiredOrientation = info.orientation;
169 | return 0;
170 | }
171 |
172 | virtual void
173 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
174 | mUserFrameAvailableListener = listener;
175 | }
176 |
177 | virtual int
178 | setRealInfo(const Minicap::DisplayInfo& info) {
179 | mRealWidth = info.width;
180 | mRealHeight = info.height;
181 | return 0;
182 | }
183 |
184 | private:
185 | int32_t mDisplayId;
186 | uint32_t mRealWidth;
187 | uint32_t mRealHeight;
188 | uint32_t mDesiredWidth;
189 | uint32_t mDesiredHeight;
190 | uint8_t mDesiredOrientation;
191 | android::sp mBufferQueue;
192 | android::sp mConsumer;
193 | android::sp mVirtualDisplay;
194 | android::sp mFrameProxy;
195 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
196 | bool mHaveBuffer;
197 | bool mHaveRunningDisplay;
198 | android::CpuConsumer::LockedBuffer mBuffer;
199 |
200 | int
201 | createVirtualDisplay() {
202 | uint32_t sourceWidth, sourceHeight;
203 | uint32_t targetWidth, targetHeight;
204 | android::status_t err;
205 |
206 | switch (mDesiredOrientation) {
207 | case Minicap::ORIENTATION_90:
208 | sourceWidth = mRealHeight;
209 | sourceHeight = mRealWidth;
210 | targetWidth = mDesiredHeight;
211 | targetHeight = mDesiredWidth;
212 | break;
213 | case Minicap::ORIENTATION_270:
214 | sourceWidth = mRealHeight;
215 | sourceHeight = mRealWidth;
216 | targetWidth = mDesiredHeight;
217 | targetHeight = mDesiredWidth;
218 | break;
219 | case Minicap::ORIENTATION_180:
220 | sourceWidth = mRealWidth;
221 | sourceHeight = mRealHeight;
222 | targetWidth = mDesiredWidth;
223 | targetHeight = mDesiredHeight;
224 | break;
225 | case Minicap::ORIENTATION_0:
226 | default:
227 | sourceWidth = mRealWidth;
228 | sourceHeight = mRealHeight;
229 | targetWidth = mDesiredWidth;
230 | targetHeight = mDesiredHeight;
231 | break;
232 | }
233 |
234 | // Set up virtual display size.
235 | android::Rect layerStackRect(sourceWidth, sourceHeight);
236 | android::Rect visibleRect(targetWidth, targetHeight);
237 |
238 | // Create a Surface for the virtual display to write to.
239 | MCINFO("Creating SurfaceComposerClient");
240 | android::sp sc = new android::SurfaceComposerClient();
241 |
242 | MCINFO("Performing SurfaceComposerClient init check");
243 | if ((err = sc->initCheck()) != android::NO_ERROR) {
244 | MCERROR("Unable to initialize SurfaceComposerClient");
245 | return err;
246 | }
247 |
248 | // Create virtual display.
249 | MCINFO("Creating virtual display");
250 | mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
251 | /* const String8& displayName */ android::String8("minicap"),
252 | /* bool secure */ true
253 | );
254 |
255 | MCINFO("Creating CPU consumer");
256 | // Some devices have a modified, larger CpuConsumer. Try to account
257 | // for that by increasing the size.
258 | mConsumer = new(operator new(sizeof(android::CpuConsumer) + 100)) android::CpuConsumer(3);
259 | mConsumer->setName(android::String8("minicap"));
260 |
261 | MCINFO("Creating buffer queue");
262 | mBufferQueue = mConsumer->getBufferQueue();
263 | mBufferQueue->setSynchronousMode(false);
264 | mBufferQueue->setDefaultBufferSize(targetWidth, targetHeight);
265 | mBufferQueue->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);
266 |
267 | MCINFO("Creating frame waiter");
268 | mFrameProxy = new FrameProxy(mUserFrameAvailableListener);
269 | mConsumer->setFrameAvailableListener(mFrameProxy);
270 |
271 | MCINFO("Publishing virtual display");
272 | android::SurfaceComposerClient::openGlobalTransaction();
273 | android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferQueue);
274 | android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
275 | android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
276 | android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0); // default stack
277 | android::SurfaceComposerClient::closeGlobalTransaction();
278 |
279 | mHaveRunningDisplay = true;
280 |
281 | return 0;
282 | }
283 |
284 | void
285 | destroyVirtualDisplay() {
286 | MCINFO("Destroying virtual display");
287 |
288 | if (mHaveBuffer) {
289 | mConsumer->unlockBuffer(mBuffer);
290 | mHaveBuffer = false;
291 | }
292 |
293 | mBufferQueue = NULL;
294 | mConsumer = NULL;
295 | mFrameProxy = NULL;
296 | mVirtualDisplay = NULL;
297 |
298 | mHaveRunningDisplay = false;
299 | }
300 |
301 | static Minicap::Format
302 | convertFormat(android::PixelFormat format) {
303 | switch (format) {
304 | case android::PIXEL_FORMAT_NONE:
305 | return FORMAT_NONE;
306 | case android::PIXEL_FORMAT_CUSTOM:
307 | return FORMAT_CUSTOM;
308 | case android::PIXEL_FORMAT_TRANSLUCENT:
309 | return FORMAT_TRANSLUCENT;
310 | case android::PIXEL_FORMAT_TRANSPARENT:
311 | return FORMAT_TRANSPARENT;
312 | case android::PIXEL_FORMAT_OPAQUE:
313 | return FORMAT_OPAQUE;
314 | case android::PIXEL_FORMAT_RGBA_8888:
315 | return FORMAT_RGBA_8888;
316 | case android::PIXEL_FORMAT_RGBX_8888:
317 | return FORMAT_RGBX_8888;
318 | case android::PIXEL_FORMAT_RGB_888:
319 | return FORMAT_RGB_888;
320 | case android::PIXEL_FORMAT_RGB_565:
321 | return FORMAT_RGB_565;
322 | case android::PIXEL_FORMAT_BGRA_8888:
323 | return FORMAT_BGRA_8888;
324 | case android::PIXEL_FORMAT_RGBA_5551:
325 | return FORMAT_RGBA_5551;
326 | case android::PIXEL_FORMAT_RGBA_4444:
327 | return FORMAT_RGBA_4444;
328 | default:
329 | return FORMAT_UNKNOWN;
330 | }
331 | }
332 | };
333 |
334 | int
335 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
336 | android::sp dpy = android::SurfaceComposerClient::getBuiltInDisplay(displayId);
337 |
338 | android::DisplayInfo dinfo;
339 | android::status_t err = android::SurfaceComposerClient::getDisplayInfo(dpy, &dinfo);
340 |
341 | if (err != android::NO_ERROR) {
342 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
343 | return err;
344 | }
345 |
346 | info->width = dinfo.w;
347 | info->height = dinfo.h;
348 | info->orientation = dinfo.orientation;
349 | info->fps = dinfo.fps;
350 | info->density = dinfo.density;
351 | info->xdpi = dinfo.xdpi;
352 | info->ydpi = dinfo.ydpi;
353 | info->secure = dinfo.secure;
354 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
355 |
356 | return 0;
357 | }
358 |
359 | Minicap*
360 | minicap_create(int32_t displayId) {
361 | return new MinicapImpl(displayId);
362 | }
363 |
364 | void
365 | minicap_free(Minicap* mc) {
366 | delete mc;
367 | }
368 |
369 | void
370 | minicap_start_thread_pool() {
371 | android::ProcessState::self()->startThreadPool();
372 | }
373 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_18.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #include "mcdebug.h"
27 |
28 | static const char*
29 | error_name(int32_t err) {
30 | switch (err) {
31 | case android::NO_ERROR: // also android::OK
32 | return "NO_ERROR";
33 | case android::UNKNOWN_ERROR:
34 | return "UNKNOWN_ERROR";
35 | case android::NO_MEMORY:
36 | return "NO_MEMORY";
37 | case android::INVALID_OPERATION:
38 | return "INVALID_OPERATION";
39 | case android::BAD_VALUE:
40 | return "BAD_VALUE";
41 | case android::BAD_TYPE:
42 | return "BAD_TYPE";
43 | case android::NAME_NOT_FOUND:
44 | return "NAME_NOT_FOUND";
45 | case android::PERMISSION_DENIED:
46 | return "PERMISSION_DENIED";
47 | case android::NO_INIT:
48 | return "NO_INIT";
49 | case android::ALREADY_EXISTS:
50 | return "ALREADY_EXISTS";
51 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
52 | return "DEAD_OBJECT";
53 | case android::FAILED_TRANSACTION:
54 | return "FAILED_TRANSACTION";
55 | case android::BAD_INDEX:
56 | return "BAD_INDEX";
57 | case android::NOT_ENOUGH_DATA:
58 | return "NOT_ENOUGH_DATA";
59 | case android::WOULD_BLOCK:
60 | return "WOULD_BLOCK";
61 | case android::TIMED_OUT:
62 | return "TIMED_OUT";
63 | case android::UNKNOWN_TRANSACTION:
64 | return "UNKNOWN_TRANSACTION";
65 | case android::FDS_NOT_ALLOWED:
66 | return "FDS_NOT_ALLOWED";
67 | default:
68 | return "UNMAPPED_ERROR";
69 | }
70 | }
71 |
72 | class FrameProxy: public android::ConsumerBase::FrameAvailableListener {
73 | public:
74 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
75 | }
76 |
77 | virtual void
78 | onFrameAvailable() {
79 | mUserListener->onFrameAvailable();
80 | }
81 |
82 | private:
83 | Minicap::FrameAvailableListener* mUserListener;
84 | };
85 |
86 | class MinicapImpl: public Minicap
87 | {
88 | public:
89 | MinicapImpl(int32_t displayId)
90 | : mDisplayId(displayId),
91 | mRealWidth(0),
92 | mRealHeight(0),
93 | mDesiredWidth(0),
94 | mDesiredHeight(0),
95 | mDesiredOrientation(0),
96 | mHaveBuffer(false),
97 | mHaveRunningDisplay(false) {
98 | }
99 |
100 | virtual
101 | ~MinicapImpl() {
102 | release();
103 | }
104 |
105 | virtual int
106 | applyConfigChanges() {
107 | if (mHaveRunningDisplay) {
108 | destroyVirtualDisplay();
109 | }
110 |
111 | return createVirtualDisplay();
112 | }
113 |
114 | virtual int
115 | consumePendingFrame(Minicap::Frame* frame) {
116 | android::status_t err;
117 |
118 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
119 | if (err == -EINTR) {
120 | return err;
121 | }
122 | else {
123 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
124 | return err;
125 | }
126 | }
127 |
128 | frame->data = mBuffer.data;
129 | frame->format = convertFormat(mBuffer.format);
130 | frame->width = mBuffer.width;
131 | frame->height = mBuffer.height;
132 | frame->stride = mBuffer.stride;
133 | frame->bpp = android::bytesPerPixel(mBuffer.format);
134 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
135 |
136 | mHaveBuffer = true;
137 |
138 | return 0;
139 | }
140 |
141 | virtual Minicap::CaptureMethod
142 | getCaptureMethod() {
143 | return METHOD_VIRTUAL_DISPLAY;
144 | }
145 |
146 | virtual int32_t
147 | getDisplayId() {
148 | return mDisplayId;
149 | }
150 |
151 | virtual void
152 | release() {
153 | destroyVirtualDisplay();
154 | }
155 |
156 | virtual void
157 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
158 | if (mHaveBuffer) {
159 | mConsumer->unlockBuffer(mBuffer);
160 | mHaveBuffer = false;
161 | }
162 | }
163 |
164 | virtual int
165 | setDesiredInfo(const Minicap::DisplayInfo& info) {
166 | mDesiredWidth = info.width;
167 | mDesiredHeight = info.height;
168 | mDesiredOrientation = info.orientation;
169 | return 0;
170 | }
171 |
172 | virtual void
173 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
174 | mUserFrameAvailableListener = listener;
175 | }
176 |
177 | virtual int
178 | setRealInfo(const Minicap::DisplayInfo& info) {
179 | mRealWidth = info.width;
180 | mRealHeight = info.height;
181 | return 0;
182 | }
183 |
184 | private:
185 | int32_t mDisplayId;
186 | uint32_t mRealWidth;
187 | uint32_t mRealHeight;
188 | uint32_t mDesiredWidth;
189 | uint32_t mDesiredHeight;
190 | uint8_t mDesiredOrientation;
191 | android::sp mBufferQueue;
192 | android::sp mConsumer;
193 | android::sp mVirtualDisplay;
194 | android::sp mFrameProxy;
195 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
196 | bool mHaveBuffer;
197 | bool mHaveRunningDisplay;
198 | android::CpuConsumer::LockedBuffer mBuffer;
199 |
200 | int
201 | createVirtualDisplay() {
202 | uint32_t sourceWidth, sourceHeight;
203 | uint32_t targetWidth, targetHeight;
204 | android::status_t err;
205 |
206 | switch (mDesiredOrientation) {
207 | case Minicap::ORIENTATION_90:
208 | sourceWidth = mRealHeight;
209 | sourceHeight = mRealWidth;
210 | targetWidth = mDesiredHeight;
211 | targetHeight = mDesiredWidth;
212 | break;
213 | case Minicap::ORIENTATION_270:
214 | sourceWidth = mRealHeight;
215 | sourceHeight = mRealWidth;
216 | targetWidth = mDesiredHeight;
217 | targetHeight = mDesiredWidth;
218 | break;
219 | case Minicap::ORIENTATION_180:
220 | sourceWidth = mRealWidth;
221 | sourceHeight = mRealHeight;
222 | targetWidth = mDesiredWidth;
223 | targetHeight = mDesiredHeight;
224 | break;
225 | case Minicap::ORIENTATION_0:
226 | default:
227 | sourceWidth = mRealWidth;
228 | sourceHeight = mRealHeight;
229 | targetWidth = mDesiredWidth;
230 | targetHeight = mDesiredHeight;
231 | break;
232 | }
233 |
234 | // Set up virtual display size.
235 | android::Rect layerStackRect(sourceWidth, sourceHeight);
236 | android::Rect visibleRect(targetWidth, targetHeight);
237 |
238 | // Create a Surface for the virtual display to write to.
239 | MCINFO("Creating SurfaceComposerClient");
240 | android::sp sc = new android::SurfaceComposerClient();
241 |
242 | MCINFO("Performing SurfaceComposerClient init check");
243 | if ((err = sc->initCheck()) != android::NO_ERROR) {
244 | MCERROR("Unable to initialize SurfaceComposerClient");
245 | return err;
246 | }
247 |
248 | // Create virtual display.
249 | MCINFO("Creating virtual display");
250 | mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
251 | /* const String8& displayName */ android::String8("minicap"),
252 | /* bool secure */ true
253 | );
254 |
255 | MCINFO("Creating CPU consumer");
256 | mConsumer = new android::CpuConsumer(3, false);
257 | mConsumer->setName(android::String8("minicap"));
258 |
259 | MCINFO("Creating buffer queue");
260 | mBufferQueue = mConsumer->getBufferQueue();
261 | mBufferQueue->setDefaultBufferSize(targetWidth, targetHeight);
262 | mBufferQueue->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);
263 |
264 | MCINFO("Creating frame waiter");
265 | mFrameProxy = new FrameProxy(mUserFrameAvailableListener);
266 | mConsumer->setFrameAvailableListener(mFrameProxy);
267 |
268 | MCINFO("Publishing virtual display");
269 | android::SurfaceComposerClient::openGlobalTransaction();
270 | android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferQueue);
271 | android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
272 | android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
273 | android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0); // default stack
274 | android::SurfaceComposerClient::closeGlobalTransaction();
275 |
276 | mHaveRunningDisplay = true;
277 |
278 | return 0;
279 | }
280 |
281 | void
282 | destroyVirtualDisplay() {
283 | MCINFO("Destroying virtual display");
284 |
285 | if (mHaveBuffer) {
286 | mConsumer->unlockBuffer(mBuffer);
287 | mHaveBuffer = false;
288 | }
289 |
290 | mBufferQueue = NULL;
291 | mConsumer = NULL;
292 | mFrameProxy = NULL;
293 | mVirtualDisplay = NULL;
294 |
295 | mHaveRunningDisplay = false;
296 | }
297 |
298 | static Minicap::Format
299 | convertFormat(android::PixelFormat format) {
300 | switch (format) {
301 | case android::PIXEL_FORMAT_NONE:
302 | return FORMAT_NONE;
303 | case android::PIXEL_FORMAT_CUSTOM:
304 | return FORMAT_CUSTOM;
305 | case android::PIXEL_FORMAT_TRANSLUCENT:
306 | return FORMAT_TRANSLUCENT;
307 | case android::PIXEL_FORMAT_TRANSPARENT:
308 | return FORMAT_TRANSPARENT;
309 | case android::PIXEL_FORMAT_OPAQUE:
310 | return FORMAT_OPAQUE;
311 | case android::PIXEL_FORMAT_RGBA_8888:
312 | return FORMAT_RGBA_8888;
313 | case android::PIXEL_FORMAT_RGBX_8888:
314 | return FORMAT_RGBX_8888;
315 | case android::PIXEL_FORMAT_RGB_888:
316 | return FORMAT_RGB_888;
317 | case android::PIXEL_FORMAT_RGB_565:
318 | return FORMAT_RGB_565;
319 | case android::PIXEL_FORMAT_BGRA_8888:
320 | return FORMAT_BGRA_8888;
321 | case android::PIXEL_FORMAT_RGBA_5551:
322 | return FORMAT_RGBA_5551;
323 | case android::PIXEL_FORMAT_RGBA_4444:
324 | return FORMAT_RGBA_4444;
325 | default:
326 | return FORMAT_UNKNOWN;
327 | }
328 | }
329 | };
330 |
331 | int
332 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
333 | android::sp dpy = android::SurfaceComposerClient::getBuiltInDisplay(displayId);
334 |
335 | android::DisplayInfo dinfo;
336 | android::status_t err = android::SurfaceComposerClient::getDisplayInfo(dpy, &dinfo);
337 |
338 | if (err != android::NO_ERROR) {
339 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
340 | return err;
341 | }
342 |
343 | info->width = dinfo.w;
344 | info->height = dinfo.h;
345 | info->orientation = dinfo.orientation;
346 | info->fps = dinfo.fps;
347 | info->density = dinfo.density;
348 | info->xdpi = dinfo.xdpi;
349 | info->ydpi = dinfo.ydpi;
350 | info->secure = dinfo.secure;
351 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
352 |
353 | return 0;
354 | }
355 |
356 | Minicap*
357 | minicap_create(int32_t displayId) {
358 | return new MinicapImpl(displayId);
359 | }
360 |
361 | void
362 | minicap_free(Minicap* mc) {
363 | delete mc;
364 | }
365 |
366 | void
367 | minicap_start_thread_pool() {
368 | android::ProcessState::self()->startThreadPool();
369 | }
370 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_19.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | // Terrible hack to access ScreenshotClient's mBufferQueue. It's too risky
15 | // to do `new android::BufferQueue()` by ourselves, makers tend to customize
16 | // it.
17 | #define private public
18 | #include
19 | #undef private
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | #include "mcdebug.h"
33 |
34 | static const char*
35 | error_name(int32_t err) {
36 | switch (err) {
37 | case android::NO_ERROR: // also android::OK
38 | return "NO_ERROR";
39 | case android::UNKNOWN_ERROR:
40 | return "UNKNOWN_ERROR";
41 | case android::NO_MEMORY:
42 | return "NO_MEMORY";
43 | case android::INVALID_OPERATION:
44 | return "INVALID_OPERATION";
45 | case android::BAD_VALUE:
46 | return "BAD_VALUE";
47 | case android::BAD_TYPE:
48 | return "BAD_TYPE";
49 | case android::NAME_NOT_FOUND:
50 | return "NAME_NOT_FOUND";
51 | case android::PERMISSION_DENIED:
52 | return "PERMISSION_DENIED";
53 | case android::NO_INIT:
54 | return "NO_INIT";
55 | case android::ALREADY_EXISTS:
56 | return "ALREADY_EXISTS";
57 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
58 | return "DEAD_OBJECT";
59 | case android::FAILED_TRANSACTION:
60 | return "FAILED_TRANSACTION";
61 | case android::BAD_INDEX:
62 | return "BAD_INDEX";
63 | case android::NOT_ENOUGH_DATA:
64 | return "NOT_ENOUGH_DATA";
65 | case android::WOULD_BLOCK:
66 | return "WOULD_BLOCK";
67 | case android::TIMED_OUT:
68 | return "TIMED_OUT";
69 | case android::UNKNOWN_TRANSACTION:
70 | return "UNKNOWN_TRANSACTION";
71 | case android::FDS_NOT_ALLOWED:
72 | return "FDS_NOT_ALLOWED";
73 | default:
74 | return "UNMAPPED_ERROR";
75 | }
76 | }
77 |
78 | class FrameProxy: public android::ConsumerBase::FrameAvailableListener {
79 | public:
80 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
81 | }
82 |
83 | virtual void
84 | onFrameAvailable() {
85 | mUserListener->onFrameAvailable();
86 | }
87 |
88 | private:
89 | Minicap::FrameAvailableListener* mUserListener;
90 | };
91 |
92 | class MinicapImpl: public Minicap
93 | {
94 | public:
95 | MinicapImpl(int32_t displayId)
96 | : mDisplayId(displayId),
97 | mRealWidth(0),
98 | mRealHeight(0),
99 | mDesiredWidth(0),
100 | mDesiredHeight(0),
101 | mDesiredOrientation(0),
102 | mHaveBuffer(false),
103 | mHaveRunningDisplay(false) {
104 | }
105 |
106 | virtual
107 | ~MinicapImpl() {
108 | release();
109 | }
110 |
111 | virtual int
112 | applyConfigChanges() {
113 | if (mHaveRunningDisplay) {
114 | destroyVirtualDisplay();
115 | }
116 |
117 | return createVirtualDisplay();
118 | }
119 |
120 | virtual int
121 | consumePendingFrame(Minicap::Frame* frame) {
122 | android::status_t err;
123 |
124 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
125 | if (err == -EINTR) {
126 | return err;
127 | }
128 | else {
129 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
130 | return err;
131 | }
132 | }
133 |
134 | frame->data = mBuffer.data;
135 | frame->format = convertFormat(mBuffer.format);
136 | frame->width = mBuffer.width;
137 | frame->height = mBuffer.height;
138 | frame->stride = mBuffer.stride;
139 | frame->bpp = android::bytesPerPixel(mBuffer.format);
140 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
141 |
142 | mHaveBuffer = true;
143 |
144 | return 0;
145 | }
146 |
147 | virtual Minicap::CaptureMethod
148 | getCaptureMethod() {
149 | return METHOD_VIRTUAL_DISPLAY;
150 | }
151 |
152 | virtual int32_t
153 | getDisplayId() {
154 | return mDisplayId;
155 | }
156 |
157 | virtual void
158 | release() {
159 | destroyVirtualDisplay();
160 | }
161 |
162 | virtual void
163 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
164 | if (mHaveBuffer) {
165 | mConsumer->unlockBuffer(mBuffer);
166 | mHaveBuffer = false;
167 | }
168 | }
169 |
170 | virtual int
171 | setDesiredInfo(const Minicap::DisplayInfo& info) {
172 | mDesiredWidth = info.width;
173 | mDesiredHeight = info.height;
174 | mDesiredOrientation = info.orientation;
175 | return 0;
176 | }
177 |
178 | virtual void
179 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
180 | mUserFrameAvailableListener = listener;
181 | }
182 |
183 | virtual int
184 | setRealInfo(const Minicap::DisplayInfo& info) {
185 | mRealWidth = info.width;
186 | mRealHeight = info.height;
187 | return 0;
188 | }
189 |
190 | private:
191 | int32_t mDisplayId;
192 | uint32_t mRealWidth;
193 | uint32_t mRealHeight;
194 | uint32_t mDesiredWidth;
195 | uint32_t mDesiredHeight;
196 | uint8_t mDesiredOrientation;
197 | android::sp mBufferQueue;
198 | android::sp mConsumer;
199 | android::sp mVirtualDisplay;
200 | android::sp mFrameProxy;
201 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
202 | bool mHaveBuffer;
203 | bool mHaveRunningDisplay;
204 | android::CpuConsumer::LockedBuffer mBuffer;
205 | android::ScreenshotClient mScreenshotClient;
206 |
207 | int
208 | createVirtualDisplay() {
209 | uint32_t sourceWidth, sourceHeight;
210 | uint32_t targetWidth, targetHeight;
211 | android::status_t err;
212 |
213 | switch (mDesiredOrientation) {
214 | case Minicap::ORIENTATION_90:
215 | sourceWidth = mRealHeight;
216 | sourceHeight = mRealWidth;
217 | targetWidth = mDesiredHeight;
218 | targetHeight = mDesiredWidth;
219 | break;
220 | case Minicap::ORIENTATION_270:
221 | sourceWidth = mRealHeight;
222 | sourceHeight = mRealWidth;
223 | targetWidth = mDesiredHeight;
224 | targetHeight = mDesiredWidth;
225 | break;
226 | case Minicap::ORIENTATION_180:
227 | sourceWidth = mRealWidth;
228 | sourceHeight = mRealHeight;
229 | targetWidth = mDesiredWidth;
230 | targetHeight = mDesiredHeight;
231 | break;
232 | case Minicap::ORIENTATION_0:
233 | default:
234 | sourceWidth = mRealWidth;
235 | sourceHeight = mRealHeight;
236 | targetWidth = mDesiredWidth;
237 | targetHeight = mDesiredHeight;
238 | break;
239 | }
240 |
241 | // Set up virtual display size.
242 | android::Rect layerStackRect(sourceWidth, sourceHeight);
243 | android::Rect visibleRect(targetWidth, targetHeight);
244 |
245 | // Create a Surface for the virtual display to write to.
246 | MCINFO("Creating SurfaceComposerClient");
247 | android::sp sc = new android::SurfaceComposerClient();
248 |
249 | MCINFO("Performing SurfaceComposerClient init check");
250 | if ((err = sc->initCheck()) != android::NO_ERROR) {
251 | MCERROR("Unable to initialize SurfaceComposerClient");
252 | return err;
253 | }
254 |
255 | // Create virtual display.
256 | MCINFO("Creating virtual display");
257 | mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
258 | /* const String8& displayName */ android::String8("minicap"),
259 | /* bool secure */ true
260 | );
261 |
262 | MCINFO("Creating buffer queue");
263 | // Many devices fail if we create a BufferQueue by ourselves.
264 | // Fortunately, we can steal one from the very stable ScreenshotClient
265 | // and repurpose it.
266 | mScreenshotClient.getCpuConsumer();
267 | mBufferQueue = mScreenshotClient.mBufferQueue;
268 |
269 | MCINFO("Creating CPU consumer");
270 | // Some devices have a modified, larger CpuConsumer. Try to account
271 | // for that by increasing the size. Example devices include Asus MeMO
272 | // Pad 7 (ME176).
273 | mConsumer = new(operator new(sizeof(android::CpuConsumer) + 100)) android::CpuConsumer(mBufferQueue, 3, false);
274 | mConsumer->setName(android::String8("minicap"));
275 | mConsumer->setDefaultBufferSize(targetWidth, targetHeight);
276 | mConsumer->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);
277 |
278 | MCINFO("Creating frame waiter");
279 | mFrameProxy = new FrameProxy(mUserFrameAvailableListener);
280 | mConsumer->setFrameAvailableListener(mFrameProxy);
281 |
282 | MCINFO("Publishing virtual display");
283 | android::SurfaceComposerClient::openGlobalTransaction();
284 | android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferQueue);
285 | android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
286 | android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
287 | android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0); // default stack
288 | android::SurfaceComposerClient::closeGlobalTransaction();
289 |
290 | mHaveRunningDisplay = true;
291 |
292 | return 0;
293 | }
294 |
295 | void
296 | destroyVirtualDisplay() {
297 | MCINFO("Destroying virtual display");
298 | android::SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
299 |
300 | if (mHaveBuffer) {
301 | mConsumer->unlockBuffer(mBuffer);
302 | mHaveBuffer = false;
303 | }
304 |
305 | mBufferQueue = NULL;
306 | mConsumer = NULL;
307 | mFrameProxy = NULL;
308 | mVirtualDisplay = NULL;
309 |
310 | mHaveRunningDisplay = false;
311 | }
312 |
313 | static Minicap::Format
314 | convertFormat(android::PixelFormat format) {
315 | switch (format) {
316 | case android::PIXEL_FORMAT_NONE:
317 | return FORMAT_NONE;
318 | case android::PIXEL_FORMAT_CUSTOM:
319 | return FORMAT_CUSTOM;
320 | case android::PIXEL_FORMAT_TRANSLUCENT:
321 | return FORMAT_TRANSLUCENT;
322 | case android::PIXEL_FORMAT_TRANSPARENT:
323 | return FORMAT_TRANSPARENT;
324 | case android::PIXEL_FORMAT_OPAQUE:
325 | return FORMAT_OPAQUE;
326 | case android::PIXEL_FORMAT_RGBA_8888:
327 | return FORMAT_RGBA_8888;
328 | case android::PIXEL_FORMAT_RGBX_8888:
329 | return FORMAT_RGBX_8888;
330 | case android::PIXEL_FORMAT_RGB_888:
331 | return FORMAT_RGB_888;
332 | case android::PIXEL_FORMAT_RGB_565:
333 | return FORMAT_RGB_565;
334 | case android::PIXEL_FORMAT_BGRA_8888:
335 | return FORMAT_BGRA_8888;
336 | case android::PIXEL_FORMAT_RGBA_5551:
337 | return FORMAT_RGBA_5551;
338 | case android::PIXEL_FORMAT_RGBA_4444:
339 | return FORMAT_RGBA_4444;
340 | default:
341 | return FORMAT_UNKNOWN;
342 | }
343 | }
344 | };
345 |
346 | int
347 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
348 | android::sp dpy = android::SurfaceComposerClient::getBuiltInDisplay(displayId);
349 |
350 | android::DisplayInfo dinfo;
351 | android::status_t err = android::SurfaceComposerClient::getDisplayInfo(dpy, &dinfo);
352 |
353 | if (err != android::NO_ERROR) {
354 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
355 | return err;
356 | }
357 |
358 | info->width = dinfo.w;
359 | info->height = dinfo.h;
360 | info->orientation = dinfo.orientation;
361 | info->fps = dinfo.fps;
362 | info->density = dinfo.density;
363 | info->xdpi = dinfo.xdpi;
364 | info->ydpi = dinfo.ydpi;
365 | info->secure = dinfo.secure;
366 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
367 |
368 | return 0;
369 | }
370 |
371 | Minicap*
372 | minicap_create(int32_t displayId) {
373 | return new MinicapImpl(displayId);
374 | }
375 |
376 | void
377 | minicap_free(Minicap* mc) {
378 | delete mc;
379 | }
380 |
381 | void
382 | minicap_start_thread_pool() {
383 | android::ProcessState::self()->startThreadPool();
384 | }
385 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_21.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #include "mcdebug.h"
27 |
28 | static const char*
29 | error_name(int32_t err) {
30 | switch (err) {
31 | case android::NO_ERROR: // also android::OK
32 | return "NO_ERROR";
33 | case android::UNKNOWN_ERROR:
34 | return "UNKNOWN_ERROR";
35 | case android::NO_MEMORY:
36 | return "NO_MEMORY";
37 | case android::INVALID_OPERATION:
38 | return "INVALID_OPERATION";
39 | case android::BAD_VALUE:
40 | return "BAD_VALUE";
41 | case android::BAD_TYPE:
42 | return "BAD_TYPE";
43 | case android::NAME_NOT_FOUND:
44 | return "NAME_NOT_FOUND";
45 | case android::PERMISSION_DENIED:
46 | return "PERMISSION_DENIED";
47 | case android::NO_INIT:
48 | return "NO_INIT";
49 | case android::ALREADY_EXISTS:
50 | return "ALREADY_EXISTS";
51 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
52 | return "DEAD_OBJECT";
53 | case android::FAILED_TRANSACTION:
54 | return "FAILED_TRANSACTION";
55 | case android::BAD_INDEX:
56 | return "BAD_INDEX";
57 | case android::NOT_ENOUGH_DATA:
58 | return "NOT_ENOUGH_DATA";
59 | case android::WOULD_BLOCK:
60 | return "WOULD_BLOCK";
61 | case android::TIMED_OUT:
62 | return "TIMED_OUT";
63 | case android::UNKNOWN_TRANSACTION:
64 | return "UNKNOWN_TRANSACTION";
65 | case android::FDS_NOT_ALLOWED:
66 | return "FDS_NOT_ALLOWED";
67 | default:
68 | return "UNMAPPED_ERROR";
69 | }
70 | }
71 |
72 | class FrameProxy: public android::ConsumerBase::FrameAvailableListener {
73 | public:
74 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
75 | }
76 |
77 | virtual void
78 | onFrameAvailable() {
79 | mUserListener->onFrameAvailable();
80 | }
81 |
82 | private:
83 | Minicap::FrameAvailableListener* mUserListener;
84 | };
85 |
86 | class MinicapImpl: public Minicap
87 | {
88 | public:
89 | MinicapImpl(int32_t displayId)
90 | : mDisplayId(displayId),
91 | mRealWidth(0),
92 | mRealHeight(0),
93 | mDesiredWidth(0),
94 | mDesiredHeight(0),
95 | mDesiredOrientation(0),
96 | mHaveBuffer(false),
97 | mHaveRunningDisplay(false) {
98 | }
99 |
100 | virtual
101 | ~MinicapImpl() {
102 | release();
103 | }
104 |
105 | virtual int
106 | applyConfigChanges() {
107 | if (mHaveRunningDisplay) {
108 | destroyVirtualDisplay();
109 | }
110 |
111 | return createVirtualDisplay();
112 | }
113 |
114 | virtual int
115 | consumePendingFrame(Minicap::Frame* frame) {
116 | android::status_t err;
117 |
118 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
119 | if (err == -EINTR) {
120 | return err;
121 | }
122 | else {
123 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
124 | return err;
125 | }
126 | }
127 |
128 | frame->data = mBuffer.data;
129 | frame->format = convertFormat(mBuffer.format);
130 | frame->width = mBuffer.width;
131 | frame->height = mBuffer.height;
132 | frame->stride = mBuffer.stride;
133 | frame->bpp = android::bytesPerPixel(mBuffer.format);
134 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
135 |
136 | mHaveBuffer = true;
137 |
138 | return 0;
139 | }
140 |
141 | virtual Minicap::CaptureMethod
142 | getCaptureMethod() {
143 | return METHOD_VIRTUAL_DISPLAY;
144 | }
145 |
146 | virtual int32_t
147 | getDisplayId() {
148 | return mDisplayId;
149 | }
150 |
151 | virtual void
152 | release() {
153 | destroyVirtualDisplay();
154 | }
155 |
156 | virtual void
157 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
158 | if (mHaveBuffer) {
159 | mConsumer->unlockBuffer(mBuffer);
160 | mHaveBuffer = false;
161 | }
162 | }
163 |
164 | virtual int
165 | setDesiredInfo(const Minicap::DisplayInfo& info) {
166 | mDesiredWidth = info.width;
167 | mDesiredHeight = info.height;
168 | mDesiredOrientation = info.orientation;
169 | return 0;
170 | }
171 |
172 | virtual void
173 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
174 | mUserFrameAvailableListener = listener;
175 | }
176 |
177 | virtual int
178 | setRealInfo(const Minicap::DisplayInfo& info) {
179 | mRealWidth = info.width;
180 | mRealHeight = info.height;
181 | return 0;
182 | }
183 |
184 | private:
185 | int32_t mDisplayId;
186 | uint32_t mRealWidth;
187 | uint32_t mRealHeight;
188 | uint32_t mDesiredWidth;
189 | uint32_t mDesiredHeight;
190 | uint8_t mDesiredOrientation;
191 | android::sp mBufferProducer;
192 | android::sp mBufferConsumer;
193 | android::sp mConsumer;
194 | android::sp mVirtualDisplay;
195 | android::sp mFrameProxy;
196 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
197 | bool mHaveBuffer;
198 | bool mHaveRunningDisplay;
199 | android::CpuConsumer::LockedBuffer mBuffer;
200 |
201 | int
202 | createVirtualDisplay() {
203 | uint32_t sourceWidth, sourceHeight;
204 | uint32_t targetWidth, targetHeight;
205 | android::status_t err;
206 |
207 | switch (mDesiredOrientation) {
208 | case Minicap::ORIENTATION_90:
209 | sourceWidth = mRealHeight;
210 | sourceHeight = mRealWidth;
211 | targetWidth = mDesiredHeight;
212 | targetHeight = mDesiredWidth;
213 | break;
214 | case Minicap::ORIENTATION_270:
215 | sourceWidth = mRealHeight;
216 | sourceHeight = mRealWidth;
217 | targetWidth = mDesiredHeight;
218 | targetHeight = mDesiredWidth;
219 | break;
220 | case Minicap::ORIENTATION_180:
221 | sourceWidth = mRealWidth;
222 | sourceHeight = mRealHeight;
223 | targetWidth = mDesiredWidth;
224 | targetHeight = mDesiredHeight;
225 | break;
226 | case Minicap::ORIENTATION_0:
227 | default:
228 | sourceWidth = mRealWidth;
229 | sourceHeight = mRealHeight;
230 | targetWidth = mDesiredWidth;
231 | targetHeight = mDesiredHeight;
232 | break;
233 | }
234 |
235 | // Set up virtual display size.
236 | android::Rect layerStackRect(sourceWidth, sourceHeight);
237 | android::Rect visibleRect(targetWidth, targetHeight);
238 |
239 | // Create a Surface for the virtual display to write to.
240 | MCINFO("Creating SurfaceComposerClient");
241 | android::sp sc = new android::SurfaceComposerClient();
242 |
243 | MCINFO("Performing SurfaceComposerClient init check");
244 | if ((err = sc->initCheck()) != android::NO_ERROR) {
245 | MCERROR("Unable to initialize SurfaceComposerClient");
246 | return err;
247 | }
248 |
249 | // Create virtual display.
250 | MCINFO("Creating virtual display");
251 | mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
252 | /* const String8& displayName */ android::String8("minicap"),
253 | /* bool secure */ true
254 | );
255 |
256 | MCINFO("Creating buffer queue");
257 | android::BufferQueue::createBufferQueue(&mBufferProducer, &mBufferConsumer);
258 | mBufferConsumer->setDefaultBufferSize(targetWidth, targetHeight);
259 | mBufferConsumer->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);
260 |
261 | MCINFO("Creating CPU consumer");
262 | mConsumer = new android::CpuConsumer(mBufferConsumer, 3, false);
263 | mConsumer->setName(android::String8("minicap"));
264 |
265 | MCINFO("Creating frame waiter");
266 | mFrameProxy = new FrameProxy(mUserFrameAvailableListener);
267 | mConsumer->setFrameAvailableListener(mFrameProxy);
268 |
269 | MCINFO("Publishing virtual display");
270 | android::SurfaceComposerClient::openGlobalTransaction();
271 | android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferProducer);
272 | android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
273 | android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
274 | android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0); // default stack
275 | android::SurfaceComposerClient::closeGlobalTransaction();
276 |
277 | mHaveRunningDisplay = true;
278 |
279 | return 0;
280 | }
281 |
282 | void
283 | destroyVirtualDisplay() {
284 | MCINFO("Destroying virtual display");
285 | android::SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
286 |
287 | if (mHaveBuffer) {
288 | mConsumer->unlockBuffer(mBuffer);
289 | mHaveBuffer = false;
290 | }
291 |
292 | mBufferProducer = NULL;
293 | mBufferConsumer = NULL;
294 | mConsumer = NULL;
295 | mFrameProxy = NULL;
296 | mVirtualDisplay = NULL;
297 |
298 | mHaveRunningDisplay = false;
299 | }
300 |
301 | static Minicap::Format
302 | convertFormat(android::PixelFormat format) {
303 | switch (format) {
304 | case android::PIXEL_FORMAT_NONE:
305 | return FORMAT_NONE;
306 | case android::PIXEL_FORMAT_CUSTOM:
307 | return FORMAT_CUSTOM;
308 | case android::PIXEL_FORMAT_TRANSLUCENT:
309 | return FORMAT_TRANSLUCENT;
310 | case android::PIXEL_FORMAT_TRANSPARENT:
311 | return FORMAT_TRANSPARENT;
312 | case android::PIXEL_FORMAT_OPAQUE:
313 | return FORMAT_OPAQUE;
314 | case android::PIXEL_FORMAT_RGBA_8888:
315 | return FORMAT_RGBA_8888;
316 | case android::PIXEL_FORMAT_RGBX_8888:
317 | return FORMAT_RGBX_8888;
318 | case android::PIXEL_FORMAT_RGB_888:
319 | return FORMAT_RGB_888;
320 | case android::PIXEL_FORMAT_RGB_565:
321 | return FORMAT_RGB_565;
322 | case android::PIXEL_FORMAT_BGRA_8888:
323 | return FORMAT_BGRA_8888;
324 | case android::PIXEL_FORMAT_RGBA_5551:
325 | return FORMAT_RGBA_5551;
326 | case android::PIXEL_FORMAT_RGBA_4444:
327 | return FORMAT_RGBA_4444;
328 | default:
329 | return FORMAT_UNKNOWN;
330 | }
331 | }
332 | };
333 |
334 | int
335 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
336 | android::sp dpy = android::SurfaceComposerClient::getBuiltInDisplay(displayId);
337 |
338 | android::Vector configs;
339 | android::status_t err = android::SurfaceComposerClient::getDisplayConfigs(dpy, &configs);
340 |
341 | if (err != android::NO_ERROR) {
342 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
343 | return err;
344 | }
345 |
346 | int activeConfig = android::SurfaceComposerClient::getActiveConfig(dpy);
347 | if(static_cast(activeConfig) >= configs.size()) {
348 | MCERROR("Active config %d not inside configs (size %zu)\n", activeConfig, configs.size());
349 | return android::BAD_VALUE;
350 | }
351 | android::DisplayInfo dinfo = configs[activeConfig];
352 |
353 | info->width = dinfo.w;
354 | info->height = dinfo.h;
355 | info->orientation = dinfo.orientation;
356 | info->fps = dinfo.fps;
357 | info->density = dinfo.density;
358 | info->xdpi = dinfo.xdpi;
359 | info->ydpi = dinfo.ydpi;
360 | info->secure = dinfo.secure;
361 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
362 |
363 | return 0;
364 | }
365 |
366 | Minicap*
367 | minicap_create(int32_t displayId) {
368 | return new MinicapImpl(displayId);
369 | }
370 |
371 | void
372 | minicap_free(Minicap* mc) {
373 | delete mc;
374 | }
375 |
376 | void
377 | minicap_start_thread_pool() {
378 | android::ProcessState::self()->startThreadPool();
379 | }
380 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_22.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #include "mcdebug.h"
27 |
28 | static const char*
29 | error_name(int32_t err) {
30 | switch (err) {
31 | case android::NO_ERROR: // also android::OK
32 | return "NO_ERROR";
33 | case android::UNKNOWN_ERROR:
34 | return "UNKNOWN_ERROR";
35 | case android::NO_MEMORY:
36 | return "NO_MEMORY";
37 | case android::INVALID_OPERATION:
38 | return "INVALID_OPERATION";
39 | case android::BAD_VALUE:
40 | return "BAD_VALUE";
41 | case android::BAD_TYPE:
42 | return "BAD_TYPE";
43 | case android::NAME_NOT_FOUND:
44 | return "NAME_NOT_FOUND";
45 | case android::PERMISSION_DENIED:
46 | return "PERMISSION_DENIED";
47 | case android::NO_INIT:
48 | return "NO_INIT";
49 | case android::ALREADY_EXISTS:
50 | return "ALREADY_EXISTS";
51 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
52 | return "DEAD_OBJECT";
53 | case android::FAILED_TRANSACTION:
54 | return "FAILED_TRANSACTION";
55 | case android::BAD_INDEX:
56 | return "BAD_INDEX";
57 | case android::NOT_ENOUGH_DATA:
58 | return "NOT_ENOUGH_DATA";
59 | case android::WOULD_BLOCK:
60 | return "WOULD_BLOCK";
61 | case android::TIMED_OUT:
62 | return "TIMED_OUT";
63 | case android::UNKNOWN_TRANSACTION:
64 | return "UNKNOWN_TRANSACTION";
65 | case android::FDS_NOT_ALLOWED:
66 | return "FDS_NOT_ALLOWED";
67 | default:
68 | return "UNMAPPED_ERROR";
69 | }
70 | }
71 |
72 | // This trick is needed for many Samsung devices running 5.1. Examples include
73 | // Galaxy S5 Neo, Galaxy J1, Galaxy A8 and so on.
74 | struct CompatFrameAvailableListener : public virtual android::RefBase {
75 | virtual void onFrameAvailable(const android::BufferItem& item) = 0;
76 | virtual void onFrameReplaced() {};
77 | };
78 |
79 | class FrameProxy: public CompatFrameAvailableListener {
80 | public:
81 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
82 | }
83 |
84 | virtual void
85 | onFrameAvailable(const android::BufferItem& /* item */) {
86 | mUserListener->onFrameAvailable();
87 | }
88 |
89 | private:
90 | Minicap::FrameAvailableListener* mUserListener;
91 | };
92 |
93 | class MinicapImpl: public Minicap
94 | {
95 | public:
96 | MinicapImpl(int32_t displayId)
97 | : mDisplayId(displayId),
98 | mRealWidth(0),
99 | mRealHeight(0),
100 | mDesiredWidth(0),
101 | mDesiredHeight(0),
102 | mDesiredOrientation(0),
103 | mHaveBuffer(false),
104 | mHaveRunningDisplay(false) {
105 | }
106 |
107 | virtual
108 | ~MinicapImpl() {
109 | release();
110 | }
111 |
112 | virtual int
113 | applyConfigChanges() {
114 | if (mHaveRunningDisplay) {
115 | destroyVirtualDisplay();
116 | }
117 |
118 | return createVirtualDisplay();
119 | }
120 |
121 | virtual int
122 | consumePendingFrame(Minicap::Frame* frame) {
123 | android::status_t err;
124 |
125 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
126 | if (err == -EINTR) {
127 | return err;
128 | }
129 | else {
130 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
131 | return err;
132 | }
133 | }
134 |
135 | frame->data = mBuffer.data;
136 | frame->format = convertFormat(mBuffer.format);
137 | frame->width = mBuffer.width;
138 | frame->height = mBuffer.height;
139 | frame->stride = mBuffer.stride;
140 | frame->bpp = android::bytesPerPixel(mBuffer.format);
141 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
142 |
143 | mHaveBuffer = true;
144 |
145 | return 0;
146 | }
147 |
148 | virtual Minicap::CaptureMethod
149 | getCaptureMethod() {
150 | return METHOD_VIRTUAL_DISPLAY;
151 | }
152 |
153 | virtual int32_t
154 | getDisplayId() {
155 | return mDisplayId;
156 | }
157 |
158 | virtual void
159 | release() {
160 | destroyVirtualDisplay();
161 | }
162 |
163 | virtual void
164 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
165 | if (mHaveBuffer) {
166 | mConsumer->unlockBuffer(mBuffer);
167 | mHaveBuffer = false;
168 | }
169 | }
170 |
171 | virtual int
172 | setDesiredInfo(const Minicap::DisplayInfo& info) {
173 | mDesiredWidth = info.width;
174 | mDesiredHeight = info.height;
175 | mDesiredOrientation = info.orientation;
176 | return 0;
177 | }
178 |
179 | virtual void
180 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
181 | mUserFrameAvailableListener = listener;
182 | }
183 |
184 | virtual int
185 | setRealInfo(const Minicap::DisplayInfo& info) {
186 | mRealWidth = info.width;
187 | mRealHeight = info.height;
188 | return 0;
189 | }
190 |
191 | private:
192 | int32_t mDisplayId;
193 | uint32_t mRealWidth;
194 | uint32_t mRealHeight;
195 | uint32_t mDesiredWidth;
196 | uint32_t mDesiredHeight;
197 | uint8_t mDesiredOrientation;
198 | android::sp mBufferProducer;
199 | android::sp mBufferConsumer;
200 | android::sp mConsumer;
201 | android::sp mVirtualDisplay;
202 | android::sp mFrameProxy;
203 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
204 | bool mHaveBuffer;
205 | bool mHaveRunningDisplay;
206 | android::CpuConsumer::LockedBuffer mBuffer;
207 |
208 | int
209 | createVirtualDisplay() {
210 | uint32_t sourceWidth, sourceHeight;
211 | uint32_t targetWidth, targetHeight;
212 | android::status_t err;
213 |
214 | switch (mDesiredOrientation) {
215 | case Minicap::ORIENTATION_90:
216 | sourceWidth = mRealHeight;
217 | sourceHeight = mRealWidth;
218 | targetWidth = mDesiredHeight;
219 | targetHeight = mDesiredWidth;
220 | break;
221 | case Minicap::ORIENTATION_270:
222 | sourceWidth = mRealHeight;
223 | sourceHeight = mRealWidth;
224 | targetWidth = mDesiredHeight;
225 | targetHeight = mDesiredWidth;
226 | break;
227 | case Minicap::ORIENTATION_180:
228 | sourceWidth = mRealWidth;
229 | sourceHeight = mRealHeight;
230 | targetWidth = mDesiredWidth;
231 | targetHeight = mDesiredHeight;
232 | break;
233 | case Minicap::ORIENTATION_0:
234 | default:
235 | sourceWidth = mRealWidth;
236 | sourceHeight = mRealHeight;
237 | targetWidth = mDesiredWidth;
238 | targetHeight = mDesiredHeight;
239 | break;
240 | }
241 |
242 | // Set up virtual display size.
243 | android::Rect layerStackRect(sourceWidth, sourceHeight);
244 | android::Rect visibleRect(targetWidth, targetHeight);
245 |
246 | // Create a Surface for the virtual display to write to.
247 | MCINFO("Creating SurfaceComposerClient");
248 | android::sp sc = new android::SurfaceComposerClient();
249 |
250 | MCINFO("Performing SurfaceComposerClient init check");
251 | if ((err = sc->initCheck()) != android::NO_ERROR) {
252 | MCERROR("Unable to initialize SurfaceComposerClient");
253 | return err;
254 | }
255 |
256 | // Create virtual display.
257 | MCINFO("Creating virtual display");
258 | mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
259 | /* const String8& displayName */ android::String8("minicap"),
260 | /* bool secure */ true
261 | );
262 |
263 | MCINFO("Creating buffer queue");
264 | android::BufferQueue::createBufferQueue(&mBufferProducer, &mBufferConsumer);
265 | mBufferConsumer->setDefaultBufferSize(targetWidth, targetHeight);
266 | mBufferConsumer->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);
267 |
268 | MCINFO("Creating CPU consumer");
269 | mConsumer = new android::CpuConsumer(mBufferConsumer, 3, false);
270 | mConsumer->setName(android::String8("minicap"));
271 |
272 | MCINFO("Creating frame waiter");
273 | mFrameProxy = reinterpret_cast(new FrameProxy(mUserFrameAvailableListener));
274 | mConsumer->setFrameAvailableListener(mFrameProxy);
275 |
276 | MCINFO("Publishing virtual display");
277 | android::SurfaceComposerClient::openGlobalTransaction();
278 | android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferProducer);
279 | android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
280 | android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
281 | android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0); // default stack
282 | android::SurfaceComposerClient::closeGlobalTransaction();
283 |
284 | mHaveRunningDisplay = true;
285 |
286 | return 0;
287 | }
288 |
289 | void
290 | destroyVirtualDisplay() {
291 | MCINFO("Destroying virtual display");
292 | android::SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
293 |
294 | if (mHaveBuffer) {
295 | mConsumer->unlockBuffer(mBuffer);
296 | mHaveBuffer = false;
297 | }
298 |
299 | mBufferProducer = NULL;
300 | mBufferConsumer = NULL;
301 | mConsumer = NULL;
302 | mFrameProxy = NULL;
303 | mVirtualDisplay = NULL;
304 |
305 | mHaveRunningDisplay = false;
306 | }
307 |
308 | static Minicap::Format
309 | convertFormat(android::PixelFormat format) {
310 | switch (format) {
311 | case android::PIXEL_FORMAT_NONE:
312 | return FORMAT_NONE;
313 | case android::PIXEL_FORMAT_CUSTOM:
314 | return FORMAT_CUSTOM;
315 | case android::PIXEL_FORMAT_TRANSLUCENT:
316 | return FORMAT_TRANSLUCENT;
317 | case android::PIXEL_FORMAT_TRANSPARENT:
318 | return FORMAT_TRANSPARENT;
319 | case android::PIXEL_FORMAT_OPAQUE:
320 | return FORMAT_OPAQUE;
321 | case android::PIXEL_FORMAT_RGBA_8888:
322 | return FORMAT_RGBA_8888;
323 | case android::PIXEL_FORMAT_RGBX_8888:
324 | return FORMAT_RGBX_8888;
325 | case android::PIXEL_FORMAT_RGB_888:
326 | return FORMAT_RGB_888;
327 | case android::PIXEL_FORMAT_RGB_565:
328 | return FORMAT_RGB_565;
329 | case android::PIXEL_FORMAT_BGRA_8888:
330 | return FORMAT_BGRA_8888;
331 | case android::PIXEL_FORMAT_RGBA_5551:
332 | return FORMAT_RGBA_5551;
333 | case android::PIXEL_FORMAT_RGBA_4444:
334 | return FORMAT_RGBA_4444;
335 | default:
336 | return FORMAT_UNKNOWN;
337 | }
338 | }
339 | };
340 |
341 | int
342 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
343 | android::sp dpy = android::SurfaceComposerClient::getBuiltInDisplay(displayId);
344 |
345 | android::Vector configs;
346 | android::status_t err = android::SurfaceComposerClient::getDisplayConfigs(dpy, &configs);
347 |
348 | if (err != android::NO_ERROR) {
349 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
350 | return err;
351 | }
352 |
353 | int activeConfig = android::SurfaceComposerClient::getActiveConfig(dpy);
354 | if(static_cast(activeConfig) >= configs.size()) {
355 | MCERROR("Active config %d not inside configs (size %zu)\n", activeConfig, configs.size());
356 | return android::BAD_VALUE;
357 | }
358 | android::DisplayInfo dinfo = configs[activeConfig];
359 |
360 | info->width = dinfo.w;
361 | info->height = dinfo.h;
362 | info->orientation = dinfo.orientation;
363 | info->fps = dinfo.fps;
364 | info->density = dinfo.density;
365 | info->xdpi = dinfo.xdpi;
366 | info->ydpi = dinfo.ydpi;
367 | info->secure = dinfo.secure;
368 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
369 |
370 | return 0;
371 | }
372 |
373 | Minicap*
374 | minicap_create(int32_t displayId) {
375 | return new MinicapImpl(displayId);
376 | }
377 |
378 | void
379 | minicap_free(Minicap* mc) {
380 | delete mc;
381 | }
382 |
383 | void
384 | minicap_start_thread_pool() {
385 | android::ProcessState::self()->startThreadPool();
386 | }
387 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_23.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #include "mcdebug.h"
27 |
28 | static const char*
29 | error_name(int32_t err) {
30 | switch (err) {
31 | case android::NO_ERROR: // also android::OK
32 | return "NO_ERROR";
33 | case android::UNKNOWN_ERROR:
34 | return "UNKNOWN_ERROR";
35 | case android::NO_MEMORY:
36 | return "NO_MEMORY";
37 | case android::INVALID_OPERATION:
38 | return "INVALID_OPERATION";
39 | case android::BAD_VALUE:
40 | return "BAD_VALUE";
41 | case android::BAD_TYPE:
42 | return "BAD_TYPE";
43 | case android::NAME_NOT_FOUND:
44 | return "NAME_NOT_FOUND";
45 | case android::PERMISSION_DENIED:
46 | return "PERMISSION_DENIED";
47 | case android::NO_INIT:
48 | return "NO_INIT";
49 | case android::ALREADY_EXISTS:
50 | return "ALREADY_EXISTS";
51 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
52 | return "DEAD_OBJECT";
53 | case android::FAILED_TRANSACTION:
54 | return "FAILED_TRANSACTION";
55 | case android::BAD_INDEX:
56 | return "BAD_INDEX";
57 | case android::NOT_ENOUGH_DATA:
58 | return "NOT_ENOUGH_DATA";
59 | case android::WOULD_BLOCK:
60 | return "WOULD_BLOCK";
61 | case android::TIMED_OUT:
62 | return "TIMED_OUT";
63 | case android::UNKNOWN_TRANSACTION:
64 | return "UNKNOWN_TRANSACTION";
65 | case android::FDS_NOT_ALLOWED:
66 | return "FDS_NOT_ALLOWED";
67 | default:
68 | return "UNMAPPED_ERROR";
69 | }
70 | }
71 |
72 | class FrameProxy: public android::ConsumerBase::FrameAvailableListener {
73 | public:
74 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
75 | }
76 |
77 | virtual void
78 | onFrameAvailable(const android::BufferItem& /* item */) {
79 | mUserListener->onFrameAvailable();
80 | }
81 |
82 | private:
83 | Minicap::FrameAvailableListener* mUserListener;
84 | };
85 |
86 | class MinicapImpl: public Minicap
87 | {
88 | public:
89 | MinicapImpl(int32_t displayId)
90 | : mDisplayId(displayId),
91 | mRealWidth(0),
92 | mRealHeight(0),
93 | mDesiredWidth(0),
94 | mDesiredHeight(0),
95 | mDesiredOrientation(0),
96 | mHaveBuffer(false),
97 | mHaveRunningDisplay(false) {
98 | }
99 |
100 | virtual
101 | ~MinicapImpl() {
102 | release();
103 | }
104 |
105 | virtual int
106 | applyConfigChanges() {
107 | if (mHaveRunningDisplay) {
108 | destroyVirtualDisplay();
109 | }
110 |
111 | return createVirtualDisplay();
112 | }
113 |
114 | virtual int
115 | consumePendingFrame(Minicap::Frame* frame) {
116 | android::status_t err;
117 |
118 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
119 | if (err == -EINTR) {
120 | return err;
121 | }
122 | else {
123 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
124 | return err;
125 | }
126 | }
127 |
128 | frame->data = mBuffer.data;
129 | frame->format = convertFormat(mBuffer.format);
130 | frame->width = mBuffer.width;
131 | frame->height = mBuffer.height;
132 | frame->stride = mBuffer.stride;
133 | frame->bpp = android::bytesPerPixel(mBuffer.format);
134 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
135 |
136 | mHaveBuffer = true;
137 |
138 | return 0;
139 | }
140 |
141 | virtual Minicap::CaptureMethod
142 | getCaptureMethod() {
143 | return METHOD_VIRTUAL_DISPLAY;
144 | }
145 |
146 | virtual int32_t
147 | getDisplayId() {
148 | return mDisplayId;
149 | }
150 |
151 | virtual void
152 | release() {
153 | destroyVirtualDisplay();
154 | }
155 |
156 | virtual void
157 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
158 | if (mHaveBuffer) {
159 | mConsumer->unlockBuffer(mBuffer);
160 | mHaveBuffer = false;
161 | }
162 | }
163 |
164 | virtual int
165 | setDesiredInfo(const Minicap::DisplayInfo& info) {
166 | mDesiredWidth = info.width;
167 | mDesiredHeight = info.height;
168 | mDesiredOrientation = info.orientation;
169 | return 0;
170 | }
171 |
172 | virtual void
173 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
174 | mUserFrameAvailableListener = listener;
175 | }
176 |
177 | virtual int
178 | setRealInfo(const Minicap::DisplayInfo& info) {
179 | mRealWidth = info.width;
180 | mRealHeight = info.height;
181 | return 0;
182 | }
183 |
184 | private:
185 | int32_t mDisplayId;
186 | uint32_t mRealWidth;
187 | uint32_t mRealHeight;
188 | uint32_t mDesiredWidth;
189 | uint32_t mDesiredHeight;
190 | uint8_t mDesiredOrientation;
191 | android::sp mBufferProducer;
192 | android::sp mBufferConsumer;
193 | android::sp mConsumer;
194 | android::sp mVirtualDisplay;
195 | android::sp mFrameProxy;
196 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
197 | bool mHaveBuffer;
198 | bool mHaveRunningDisplay;
199 | android::CpuConsumer::LockedBuffer mBuffer;
200 |
201 | int
202 | createVirtualDisplay() {
203 | uint32_t sourceWidth, sourceHeight;
204 | uint32_t targetWidth, targetHeight;
205 | android::status_t err;
206 |
207 | switch (mDesiredOrientation) {
208 | case Minicap::ORIENTATION_90:
209 | sourceWidth = mRealHeight;
210 | sourceHeight = mRealWidth;
211 | targetWidth = mDesiredHeight;
212 | targetHeight = mDesiredWidth;
213 | break;
214 | case Minicap::ORIENTATION_270:
215 | sourceWidth = mRealHeight;
216 | sourceHeight = mRealWidth;
217 | targetWidth = mDesiredHeight;
218 | targetHeight = mDesiredWidth;
219 | break;
220 | case Minicap::ORIENTATION_180:
221 | sourceWidth = mRealWidth;
222 | sourceHeight = mRealHeight;
223 | targetWidth = mDesiredWidth;
224 | targetHeight = mDesiredHeight;
225 | break;
226 | case Minicap::ORIENTATION_0:
227 | default:
228 | sourceWidth = mRealWidth;
229 | sourceHeight = mRealHeight;
230 | targetWidth = mDesiredWidth;
231 | targetHeight = mDesiredHeight;
232 | break;
233 | }
234 |
235 | // Set up virtual display size.
236 | android::Rect layerStackRect(sourceWidth, sourceHeight);
237 | android::Rect visibleRect(targetWidth, targetHeight);
238 |
239 | // Create a Surface for the virtual display to write to.
240 | MCINFO("Creating SurfaceComposerClient");
241 | android::sp sc = new android::SurfaceComposerClient();
242 |
243 | MCINFO("Performing SurfaceComposerClient init check");
244 | if ((err = sc->initCheck()) != android::NO_ERROR) {
245 | MCERROR("Unable to initialize SurfaceComposerClient");
246 | return err;
247 | }
248 |
249 | // Create virtual display.
250 | MCINFO("Creating virtual display");
251 | mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
252 | /* const String8& displayName */ android::String8("minicap"),
253 | /* bool secure */ true
254 | );
255 |
256 | MCINFO("Creating buffer queue");
257 | android::BufferQueue::createBufferQueue(&mBufferProducer, &mBufferConsumer);
258 | mBufferConsumer->setDefaultBufferSize(targetWidth, targetHeight);
259 | mBufferConsumer->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);
260 |
261 | MCINFO("Creating CPU consumer");
262 | mConsumer = new android::CpuConsumer(mBufferConsumer, 3, false);
263 | mConsumer->setName(android::String8("minicap"));
264 |
265 | MCINFO("Creating frame waiter");
266 | mFrameProxy = new FrameProxy(mUserFrameAvailableListener);
267 | mConsumer->setFrameAvailableListener(mFrameProxy);
268 |
269 | MCINFO("Publishing virtual display");
270 | android::SurfaceComposerClient::openGlobalTransaction();
271 | android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferProducer);
272 | android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
273 | android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
274 | android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0); // default stack
275 | android::SurfaceComposerClient::closeGlobalTransaction();
276 |
277 | mHaveRunningDisplay = true;
278 |
279 | return 0;
280 | }
281 |
282 | void
283 | destroyVirtualDisplay() {
284 | MCINFO("Destroying virtual display");
285 | android::SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
286 |
287 | if (mHaveBuffer) {
288 | mConsumer->unlockBuffer(mBuffer);
289 | mHaveBuffer = false;
290 | }
291 |
292 | mBufferProducer = NULL;
293 | mBufferConsumer = NULL;
294 | mConsumer = NULL;
295 | mFrameProxy = NULL;
296 | mVirtualDisplay = NULL;
297 |
298 | mHaveRunningDisplay = false;
299 | }
300 |
301 | static Minicap::Format
302 | convertFormat(android::PixelFormat format) {
303 | switch (format) {
304 | case android::PIXEL_FORMAT_NONE:
305 | return FORMAT_NONE;
306 | case android::PIXEL_FORMAT_CUSTOM:
307 | return FORMAT_CUSTOM;
308 | case android::PIXEL_FORMAT_TRANSLUCENT:
309 | return FORMAT_TRANSLUCENT;
310 | case android::PIXEL_FORMAT_TRANSPARENT:
311 | return FORMAT_TRANSPARENT;
312 | case android::PIXEL_FORMAT_OPAQUE:
313 | return FORMAT_OPAQUE;
314 | case android::PIXEL_FORMAT_RGBA_8888:
315 | return FORMAT_RGBA_8888;
316 | case android::PIXEL_FORMAT_RGBX_8888:
317 | return FORMAT_RGBX_8888;
318 | case android::PIXEL_FORMAT_RGB_888:
319 | return FORMAT_RGB_888;
320 | case android::PIXEL_FORMAT_RGB_565:
321 | return FORMAT_RGB_565;
322 | case android::PIXEL_FORMAT_BGRA_8888:
323 | return FORMAT_BGRA_8888;
324 | case android::PIXEL_FORMAT_RGBA_5551:
325 | return FORMAT_RGBA_5551;
326 | case android::PIXEL_FORMAT_RGBA_4444:
327 | return FORMAT_RGBA_4444;
328 | default:
329 | return FORMAT_UNKNOWN;
330 | }
331 | }
332 | };
333 |
334 | int
335 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
336 | android::sp dpy = android::SurfaceComposerClient::getBuiltInDisplay(displayId);
337 |
338 | android::Vector configs;
339 | android::status_t err = android::SurfaceComposerClient::getDisplayConfigs(dpy, &configs);
340 |
341 | if (err != android::NO_ERROR) {
342 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
343 | return err;
344 | }
345 |
346 | int activeConfig = android::SurfaceComposerClient::getActiveConfig(dpy);
347 | if(static_cast(activeConfig) >= configs.size()) {
348 | MCERROR("Active config %d not inside configs (size %zu)\n", activeConfig, configs.size());
349 | return android::BAD_VALUE;
350 | }
351 | android::DisplayInfo dinfo = configs[activeConfig];
352 |
353 | info->width = dinfo.w;
354 | info->height = dinfo.h;
355 | info->orientation = dinfo.orientation;
356 | info->fps = dinfo.fps;
357 | info->density = dinfo.density;
358 | info->xdpi = dinfo.xdpi;
359 | info->ydpi = dinfo.ydpi;
360 | info->secure = dinfo.secure;
361 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
362 |
363 | return 0;
364 | }
365 |
366 | Minicap*
367 | minicap_create(int32_t displayId) {
368 | return new MinicapImpl(displayId);
369 | }
370 |
371 | void
372 | minicap_free(Minicap* mc) {
373 | delete mc;
374 | }
375 |
376 | void
377 | minicap_start_thread_pool() {
378 | android::ProcessState::self()->startThreadPool();
379 | }
380 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_24.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #include "mcdebug.h"
27 |
28 | static const char*
29 | error_name(int32_t err) {
30 | switch (err) {
31 | case android::NO_ERROR: // also android::OK
32 | return "NO_ERROR";
33 | case android::UNKNOWN_ERROR:
34 | return "UNKNOWN_ERROR";
35 | case android::NO_MEMORY:
36 | return "NO_MEMORY";
37 | case android::INVALID_OPERATION:
38 | return "INVALID_OPERATION";
39 | case android::BAD_VALUE:
40 | return "BAD_VALUE";
41 | case android::BAD_TYPE:
42 | return "BAD_TYPE";
43 | case android::NAME_NOT_FOUND:
44 | return "NAME_NOT_FOUND";
45 | case android::PERMISSION_DENIED:
46 | return "PERMISSION_DENIED";
47 | case android::NO_INIT:
48 | return "NO_INIT";
49 | case android::ALREADY_EXISTS:
50 | return "ALREADY_EXISTS";
51 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
52 | return "DEAD_OBJECT";
53 | case android::FAILED_TRANSACTION:
54 | return "FAILED_TRANSACTION";
55 | case android::BAD_INDEX:
56 | return "BAD_INDEX";
57 | case android::NOT_ENOUGH_DATA:
58 | return "NOT_ENOUGH_DATA";
59 | case android::WOULD_BLOCK:
60 | return "WOULD_BLOCK";
61 | case android::TIMED_OUT:
62 | return "TIMED_OUT";
63 | case android::UNKNOWN_TRANSACTION:
64 | return "UNKNOWN_TRANSACTION";
65 | case android::FDS_NOT_ALLOWED:
66 | return "FDS_NOT_ALLOWED";
67 | default:
68 | return "UNMAPPED_ERROR";
69 | }
70 | }
71 |
72 | class FrameProxy: public android::ConsumerBase::FrameAvailableListener {
73 | public:
74 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
75 | }
76 |
77 | virtual void
78 | onFrameAvailable(const android::BufferItem& /* item */) {
79 | mUserListener->onFrameAvailable();
80 | }
81 |
82 | private:
83 | Minicap::FrameAvailableListener* mUserListener;
84 | };
85 |
86 | class MinicapImpl: public Minicap
87 | {
88 | public:
89 | MinicapImpl(int32_t displayId)
90 | : mDisplayId(displayId),
91 | mRealWidth(0),
92 | mRealHeight(0),
93 | mDesiredWidth(0),
94 | mDesiredHeight(0),
95 | mDesiredOrientation(0),
96 | mHaveBuffer(false),
97 | mHaveRunningDisplay(false) {
98 | }
99 |
100 | virtual
101 | ~MinicapImpl() {
102 | release();
103 | }
104 |
105 | virtual int
106 | applyConfigChanges() {
107 | if (mHaveRunningDisplay) {
108 | destroyVirtualDisplay();
109 | }
110 |
111 | return createVirtualDisplay();
112 | }
113 |
114 | virtual int
115 | consumePendingFrame(Minicap::Frame* frame) {
116 | android::status_t err;
117 |
118 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
119 | if (err == -EINTR) {
120 | return err;
121 | }
122 | else {
123 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
124 | return err;
125 | }
126 | }
127 |
128 | frame->data = mBuffer.data;
129 | frame->format = convertFormat(mBuffer.format);
130 | frame->width = mBuffer.width;
131 | frame->height = mBuffer.height;
132 | frame->stride = mBuffer.stride;
133 | frame->bpp = android::bytesPerPixel(mBuffer.format);
134 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
135 |
136 | mHaveBuffer = true;
137 |
138 | return 0;
139 | }
140 |
141 | virtual Minicap::CaptureMethod
142 | getCaptureMethod() {
143 | return METHOD_VIRTUAL_DISPLAY;
144 | }
145 |
146 | virtual int32_t
147 | getDisplayId() {
148 | return mDisplayId;
149 | }
150 |
151 | virtual void
152 | release() {
153 | destroyVirtualDisplay();
154 | }
155 |
156 | virtual void
157 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
158 | if (mHaveBuffer) {
159 | mConsumer->unlockBuffer(mBuffer);
160 | mHaveBuffer = false;
161 | }
162 | }
163 |
164 | virtual int
165 | setDesiredInfo(const Minicap::DisplayInfo& info) {
166 | mDesiredWidth = info.width;
167 | mDesiredHeight = info.height;
168 | mDesiredOrientation = info.orientation;
169 | return 0;
170 | }
171 |
172 | virtual void
173 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
174 | mUserFrameAvailableListener = listener;
175 | }
176 |
177 | virtual int
178 | setRealInfo(const Minicap::DisplayInfo& info) {
179 | mRealWidth = info.width;
180 | mRealHeight = info.height;
181 | return 0;
182 | }
183 |
184 | private:
185 | int32_t mDisplayId;
186 | uint32_t mRealWidth;
187 | uint32_t mRealHeight;
188 | uint32_t mDesiredWidth;
189 | uint32_t mDesiredHeight;
190 | uint8_t mDesiredOrientation;
191 | android::sp mBufferProducer;
192 | android::sp mBufferConsumer;
193 | android::sp mConsumer;
194 | android::sp mVirtualDisplay;
195 | android::sp mFrameProxy;
196 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
197 | bool mHaveBuffer;
198 | bool mHaveRunningDisplay;
199 | android::CpuConsumer::LockedBuffer mBuffer;
200 |
201 | int
202 | createVirtualDisplay() {
203 | uint32_t sourceWidth, sourceHeight;
204 | uint32_t targetWidth, targetHeight;
205 | android::status_t err;
206 |
207 | switch (mDesiredOrientation) {
208 | case Minicap::ORIENTATION_90:
209 | sourceWidth = mRealHeight;
210 | sourceHeight = mRealWidth;
211 | targetWidth = mDesiredHeight;
212 | targetHeight = mDesiredWidth;
213 | break;
214 | case Minicap::ORIENTATION_270:
215 | sourceWidth = mRealHeight;
216 | sourceHeight = mRealWidth;
217 | targetWidth = mDesiredHeight;
218 | targetHeight = mDesiredWidth;
219 | break;
220 | case Minicap::ORIENTATION_180:
221 | sourceWidth = mRealWidth;
222 | sourceHeight = mRealHeight;
223 | targetWidth = mDesiredWidth;
224 | targetHeight = mDesiredHeight;
225 | break;
226 | case Minicap::ORIENTATION_0:
227 | default:
228 | sourceWidth = mRealWidth;
229 | sourceHeight = mRealHeight;
230 | targetWidth = mDesiredWidth;
231 | targetHeight = mDesiredHeight;
232 | break;
233 | }
234 |
235 | // Set up virtual display size.
236 | android::Rect layerStackRect(sourceWidth, sourceHeight);
237 | android::Rect visibleRect(targetWidth, targetHeight);
238 |
239 | // Create a Surface for the virtual display to write to.
240 | MCINFO("Creating SurfaceComposerClient");
241 | android::sp sc = new android::SurfaceComposerClient();
242 |
243 | MCINFO("Performing SurfaceComposerClient init check");
244 | if ((err = sc->initCheck()) != android::NO_ERROR) {
245 | MCERROR("Unable to initialize SurfaceComposerClient");
246 | return err;
247 | }
248 |
249 | // Create virtual display.
250 | MCINFO("Creating virtual display");
251 | mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
252 | /* const String8& displayName */ android::String8("minicap"),
253 | /* bool secure */ true
254 | );
255 |
256 | MCINFO("Creating buffer queue");
257 | android::BufferQueue::createBufferQueue(&mBufferProducer, &mBufferConsumer);
258 | mBufferConsumer->setDefaultBufferSize(targetWidth, targetHeight);
259 | mBufferConsumer->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);
260 |
261 | MCINFO("Creating CPU consumer");
262 | mConsumer = new android::CpuConsumer(mBufferConsumer, 3, false);
263 | mConsumer->setName(android::String8("minicap"));
264 |
265 | MCINFO("Creating frame waiter");
266 | mFrameProxy = new FrameProxy(mUserFrameAvailableListener);
267 | mConsumer->setFrameAvailableListener(mFrameProxy);
268 |
269 | MCINFO("Publishing virtual display");
270 | android::SurfaceComposerClient::openGlobalTransaction();
271 | android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferProducer);
272 | android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
273 | android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
274 | android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0); // default stack
275 | android::SurfaceComposerClient::closeGlobalTransaction();
276 |
277 | mHaveRunningDisplay = true;
278 |
279 | return 0;
280 | }
281 |
282 | void
283 | destroyVirtualDisplay() {
284 | MCINFO("Destroying virtual display");
285 | android::SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
286 |
287 | if (mHaveBuffer) {
288 | mConsumer->unlockBuffer(mBuffer);
289 | mHaveBuffer = false;
290 | }
291 |
292 | mBufferProducer = NULL;
293 | mBufferConsumer = NULL;
294 | mConsumer = NULL;
295 | mFrameProxy = NULL;
296 | mVirtualDisplay = NULL;
297 |
298 | mHaveRunningDisplay = false;
299 | }
300 |
301 | static Minicap::Format
302 | convertFormat(android::PixelFormat format) {
303 | switch (format) {
304 | case android::PIXEL_FORMAT_NONE:
305 | return FORMAT_NONE;
306 | case android::PIXEL_FORMAT_CUSTOM:
307 | return FORMAT_CUSTOM;
308 | case android::PIXEL_FORMAT_TRANSLUCENT:
309 | return FORMAT_TRANSLUCENT;
310 | case android::PIXEL_FORMAT_TRANSPARENT:
311 | return FORMAT_TRANSPARENT;
312 | case android::PIXEL_FORMAT_OPAQUE:
313 | return FORMAT_OPAQUE;
314 | case android::PIXEL_FORMAT_RGBA_8888:
315 | return FORMAT_RGBA_8888;
316 | case android::PIXEL_FORMAT_RGBX_8888:
317 | return FORMAT_RGBX_8888;
318 | case android::PIXEL_FORMAT_RGB_888:
319 | return FORMAT_RGB_888;
320 | case android::PIXEL_FORMAT_RGB_565:
321 | return FORMAT_RGB_565;
322 | case android::PIXEL_FORMAT_BGRA_8888:
323 | return FORMAT_BGRA_8888;
324 | case android::PIXEL_FORMAT_RGBA_5551:
325 | return FORMAT_RGBA_5551;
326 | case android::PIXEL_FORMAT_RGBA_4444:
327 | return FORMAT_RGBA_4444;
328 | default:
329 | return FORMAT_UNKNOWN;
330 | }
331 | }
332 | };
333 |
334 | int
335 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
336 | android::sp dpy = android::SurfaceComposerClient::getBuiltInDisplay(displayId);
337 |
338 | android::Vector configs;
339 | android::status_t err = android::SurfaceComposerClient::getDisplayConfigs(dpy, &configs);
340 |
341 | if (err != android::NO_ERROR) {
342 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
343 | return err;
344 | }
345 |
346 | int activeConfig = android::SurfaceComposerClient::getActiveConfig(dpy);
347 | if(static_cast(activeConfig) >= configs.size()) {
348 | MCERROR("Active config %d not inside configs (size %zu)\n", activeConfig, configs.size());
349 | return android::BAD_VALUE;
350 | }
351 | android::DisplayInfo dinfo = configs[activeConfig];
352 |
353 | info->width = dinfo.w;
354 | info->height = dinfo.h;
355 | info->orientation = dinfo.orientation;
356 | info->fps = dinfo.fps;
357 | info->density = dinfo.density;
358 | info->xdpi = dinfo.xdpi;
359 | info->ydpi = dinfo.ydpi;
360 | info->secure = dinfo.secure;
361 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
362 |
363 | return 0;
364 | }
365 |
366 | Minicap*
367 | minicap_create(int32_t displayId) {
368 | return new MinicapImpl(displayId);
369 | }
370 |
371 | void
372 | minicap_free(Minicap* mc) {
373 | delete mc;
374 | }
375 |
376 | void
377 | minicap_start_thread_pool() {
378 | android::ProcessState::self()->startThreadPool();
379 | }
380 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_26.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 |
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #include
22 |
23 | #include
24 | #include
25 | #include
26 |
27 | #include "mcdebug.h"
28 |
29 | static const char*
30 | error_name(int32_t err) {
31 | switch (err) {
32 | case android::NO_ERROR: // also android::OK
33 | return "NO_ERROR";
34 | case android::UNKNOWN_ERROR:
35 | return "UNKNOWN_ERROR";
36 | case android::NO_MEMORY:
37 | return "NO_MEMORY";
38 | case android::INVALID_OPERATION:
39 | return "INVALID_OPERATION";
40 | case android::BAD_VALUE:
41 | return "BAD_VALUE";
42 | case android::BAD_TYPE:
43 | return "BAD_TYPE";
44 | case android::NAME_NOT_FOUND:
45 | return "NAME_NOT_FOUND";
46 | case android::PERMISSION_DENIED:
47 | return "PERMISSION_DENIED";
48 | case android::NO_INIT:
49 | return "NO_INIT";
50 | case android::ALREADY_EXISTS:
51 | return "ALREADY_EXISTS";
52 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
53 | return "DEAD_OBJECT";
54 | case android::FAILED_TRANSACTION:
55 | return "FAILED_TRANSACTION";
56 | case android::BAD_INDEX:
57 | return "BAD_INDEX";
58 | case android::NOT_ENOUGH_DATA:
59 | return "NOT_ENOUGH_DATA";
60 | case android::WOULD_BLOCK:
61 | return "WOULD_BLOCK";
62 | case android::TIMED_OUT:
63 | return "TIMED_OUT";
64 | case android::UNKNOWN_TRANSACTION:
65 | return "UNKNOWN_TRANSACTION";
66 | case android::FDS_NOT_ALLOWED:
67 | return "FDS_NOT_ALLOWED";
68 | default:
69 | return "UNMAPPED_ERROR";
70 | }
71 | }
72 |
73 | class FrameProxy: public android::ConsumerBase::FrameAvailableListener {
74 | public:
75 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
76 | }
77 |
78 | virtual void
79 | onFrameAvailable(const android::BufferItem& /* item */) {
80 | mUserListener->onFrameAvailable();
81 | }
82 |
83 | private:
84 | Minicap::FrameAvailableListener* mUserListener;
85 | };
86 |
87 | class MinicapImpl: public Minicap
88 | {
89 | public:
90 | MinicapImpl(int32_t displayId)
91 | : mDisplayId(displayId),
92 | mRealWidth(0),
93 | mRealHeight(0),
94 | mDesiredWidth(0),
95 | mDesiredHeight(0),
96 | mDesiredOrientation(0),
97 | mHaveBuffer(false),
98 | mHaveRunningDisplay(false) {
99 | }
100 |
101 | virtual
102 | ~MinicapImpl() {
103 | release();
104 | }
105 |
106 | virtual int
107 | applyConfigChanges() {
108 | if (mHaveRunningDisplay) {
109 | destroyVirtualDisplay();
110 | }
111 |
112 | return createVirtualDisplay();
113 | }
114 |
115 | virtual int
116 | consumePendingFrame(Minicap::Frame* frame) {
117 | android::status_t err;
118 |
119 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
120 | if (err == -EINTR) {
121 | return err;
122 | }
123 | else {
124 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
125 | return err;
126 | }
127 | }
128 |
129 | frame->data = mBuffer.data;
130 | frame->format = convertFormat(mBuffer.format);
131 | frame->width = mBuffer.width;
132 | frame->height = mBuffer.height;
133 | frame->stride = mBuffer.stride;
134 | frame->bpp = android::bytesPerPixel(mBuffer.format);
135 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
136 |
137 | mHaveBuffer = true;
138 |
139 | return 0;
140 | }
141 |
142 | virtual Minicap::CaptureMethod
143 | getCaptureMethod() {
144 | return METHOD_VIRTUAL_DISPLAY;
145 | }
146 |
147 | virtual int32_t
148 | getDisplayId() {
149 | return mDisplayId;
150 | }
151 |
152 | virtual void
153 | release() {
154 | destroyVirtualDisplay();
155 | }
156 |
157 | virtual void
158 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
159 | if (mHaveBuffer) {
160 | mConsumer->unlockBuffer(mBuffer);
161 | mHaveBuffer = false;
162 | }
163 | }
164 |
165 | virtual int
166 | setDesiredInfo(const Minicap::DisplayInfo& info) {
167 | mDesiredWidth = info.width;
168 | mDesiredHeight = info.height;
169 | mDesiredOrientation = info.orientation;
170 | return 0;
171 | }
172 |
173 | virtual void
174 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
175 | mUserFrameAvailableListener = listener;
176 | }
177 |
178 | virtual int
179 | setRealInfo(const Minicap::DisplayInfo& info) {
180 | mRealWidth = info.width;
181 | mRealHeight = info.height;
182 | return 0;
183 | }
184 |
185 | private:
186 | int32_t mDisplayId;
187 | uint32_t mRealWidth;
188 | uint32_t mRealHeight;
189 | uint32_t mDesiredWidth;
190 | uint32_t mDesiredHeight;
191 | uint8_t mDesiredOrientation;
192 | android::sp mBufferProducer;
193 | android::sp mBufferConsumer;
194 | android::sp mConsumer;
195 | android::sp mVirtualDisplay;
196 | android::sp mFrameProxy;
197 | Minicap::FrameAvailableListener* mUserFrameAvailableListener;
198 | bool mHaveBuffer;
199 | bool mHaveRunningDisplay;
200 | android::CpuConsumer::LockedBuffer mBuffer;
201 |
202 | int
203 | createVirtualDisplay() {
204 | uint32_t sourceWidth, sourceHeight;
205 | uint32_t targetWidth, targetHeight;
206 | android::status_t err;
207 |
208 | switch (mDesiredOrientation) {
209 | case Minicap::ORIENTATION_90:
210 | sourceWidth = mRealHeight;
211 | sourceHeight = mRealWidth;
212 | targetWidth = mDesiredHeight;
213 | targetHeight = mDesiredWidth;
214 | break;
215 | case Minicap::ORIENTATION_270:
216 | sourceWidth = mRealHeight;
217 | sourceHeight = mRealWidth;
218 | targetWidth = mDesiredHeight;
219 | targetHeight = mDesiredWidth;
220 | break;
221 | case Minicap::ORIENTATION_180:
222 | sourceWidth = mRealWidth;
223 | sourceHeight = mRealHeight;
224 | targetWidth = mDesiredWidth;
225 | targetHeight = mDesiredHeight;
226 | break;
227 | case Minicap::ORIENTATION_0:
228 | default:
229 | sourceWidth = mRealWidth;
230 | sourceHeight = mRealHeight;
231 | targetWidth = mDesiredWidth;
232 | targetHeight = mDesiredHeight;
233 | break;
234 | }
235 |
236 | // Set up virtual display size.
237 | android::Rect layerStackRect(sourceWidth, sourceHeight);
238 | android::Rect visibleRect(targetWidth, targetHeight);
239 |
240 | // Create a Surface for the virtual display to write to.
241 | MCINFO("Creating SurfaceComposerClient");
242 | android::sp sc = new android::SurfaceComposerClient();
243 |
244 | MCINFO("Performing SurfaceComposerClient init check");
245 | if ((err = sc->initCheck()) != android::NO_ERROR) {
246 | MCERROR("Unable to initialize SurfaceComposerClient");
247 | return err;
248 | }
249 |
250 | // This is now REQUIRED in O Developer Preview 1 or there's a segfault
251 | // when the sp goes out of scope.
252 | sc = NULL;
253 |
254 | // Create virtual display.
255 | MCINFO("Creating virtual display");
256 | mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
257 | /* const String8& displayName */ android::String8("minicap"),
258 | /* bool secure */ true
259 | );
260 |
261 | MCINFO("Creating buffer queue");
262 | android::BufferQueue::createBufferQueue(&mBufferProducer, &mBufferConsumer, false);
263 |
264 | MCINFO("Setting buffer options");
265 | mBufferConsumer->setDefaultBufferSize(targetWidth, targetHeight);
266 | mBufferConsumer->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);
267 |
268 | MCINFO("Creating CPU consumer");
269 | mConsumer = new android::CpuConsumer(mBufferConsumer, 3, false);
270 | mConsumer->setName(android::String8("minicap"));
271 |
272 | MCINFO("Creating frame waiter");
273 | mFrameProxy = new FrameProxy(mUserFrameAvailableListener);
274 | mConsumer->setFrameAvailableListener(mFrameProxy);
275 |
276 | MCINFO("Publishing virtual display");
277 | android::SurfaceComposerClient::openGlobalTransaction();
278 | android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferProducer);
279 | android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
280 | android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
281 | android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0); // default stack
282 | android::SurfaceComposerClient::closeGlobalTransaction();
283 |
284 | mHaveRunningDisplay = true;
285 |
286 | return 0;
287 | }
288 |
289 | void
290 | destroyVirtualDisplay() {
291 | MCINFO("Destroying virtual display");
292 | android::SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
293 |
294 | if (mHaveBuffer) {
295 | mConsumer->unlockBuffer(mBuffer);
296 | mHaveBuffer = false;
297 | }
298 |
299 | mBufferProducer = NULL;
300 | mBufferConsumer = NULL;
301 | mConsumer = NULL;
302 | mFrameProxy = NULL;
303 | mVirtualDisplay = NULL;
304 |
305 | mHaveRunningDisplay = false;
306 | }
307 |
308 | static Minicap::Format
309 | convertFormat(android::PixelFormat format) {
310 | switch (format) {
311 | case android::PIXEL_FORMAT_NONE:
312 | return FORMAT_NONE;
313 | case android::PIXEL_FORMAT_CUSTOM:
314 | return FORMAT_CUSTOM;
315 | case android::PIXEL_FORMAT_TRANSLUCENT:
316 | return FORMAT_TRANSLUCENT;
317 | case android::PIXEL_FORMAT_TRANSPARENT:
318 | return FORMAT_TRANSPARENT;
319 | case android::PIXEL_FORMAT_OPAQUE:
320 | return FORMAT_OPAQUE;
321 | case android::PIXEL_FORMAT_RGBA_8888:
322 | return FORMAT_RGBA_8888;
323 | case android::PIXEL_FORMAT_RGBX_8888:
324 | return FORMAT_RGBX_8888;
325 | case android::PIXEL_FORMAT_RGB_888:
326 | return FORMAT_RGB_888;
327 | case android::PIXEL_FORMAT_RGB_565:
328 | return FORMAT_RGB_565;
329 | case android::PIXEL_FORMAT_BGRA_8888:
330 | return FORMAT_BGRA_8888;
331 | case android::PIXEL_FORMAT_RGBA_5551:
332 | return FORMAT_RGBA_5551;
333 | case android::PIXEL_FORMAT_RGBA_4444:
334 | return FORMAT_RGBA_4444;
335 | default:
336 | return FORMAT_UNKNOWN;
337 | }
338 | }
339 | };
340 |
341 | int
342 | minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) {
343 | android::sp dpy = android::SurfaceComposerClient::getBuiltInDisplay(displayId);
344 |
345 | android::Vector configs;
346 | android::status_t err = android::SurfaceComposerClient::getDisplayConfigs(dpy, &configs);
347 |
348 | if (err != android::NO_ERROR) {
349 | MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err);
350 | return err;
351 | }
352 |
353 | int activeConfig = android::SurfaceComposerClient::getActiveConfig(dpy);
354 | if(static_cast(activeConfig) >= configs.size()) {
355 | MCERROR("Active config %d not inside configs (size %zu)\n", activeConfig, configs.size());
356 | return android::BAD_VALUE;
357 | }
358 | android::DisplayInfo dinfo = configs[activeConfig];
359 |
360 | info->width = dinfo.w;
361 | info->height = dinfo.h;
362 | info->orientation = dinfo.orientation;
363 | info->fps = dinfo.fps;
364 | info->density = dinfo.density;
365 | info->xdpi = dinfo.xdpi;
366 | info->ydpi = dinfo.ydpi;
367 | info->secure = dinfo.secure;
368 | info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2));
369 |
370 | return 0;
371 | }
372 |
373 | Minicap*
374 | minicap_create(int32_t displayId) {
375 | return new MinicapImpl(displayId);
376 | }
377 |
378 | void
379 | minicap_free(Minicap* mc) {
380 | delete mc;
381 | }
382 |
383 | void
384 | minicap_start_thread_pool() {
385 | android::ProcessState::self()->startThreadPool();
386 | }
387 |
--------------------------------------------------------------------------------
/jni/minicap-shared/aosp/src/minicap_27.cpp:
--------------------------------------------------------------------------------
1 | #include "Minicap.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 |
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #include
22 |
23 | #include
24 | #include
25 | #include
26 |
27 | #include "mcdebug.h"
28 |
29 | static const char*
30 | error_name(int32_t err) {
31 | switch (err) {
32 | case android::NO_ERROR: // also android::OK
33 | return "NO_ERROR";
34 | case android::UNKNOWN_ERROR:
35 | return "UNKNOWN_ERROR";
36 | case android::NO_MEMORY:
37 | return "NO_MEMORY";
38 | case android::INVALID_OPERATION:
39 | return "INVALID_OPERATION";
40 | case android::BAD_VALUE:
41 | return "BAD_VALUE";
42 | case android::BAD_TYPE:
43 | return "BAD_TYPE";
44 | case android::NAME_NOT_FOUND:
45 | return "NAME_NOT_FOUND";
46 | case android::PERMISSION_DENIED:
47 | return "PERMISSION_DENIED";
48 | case android::NO_INIT:
49 | return "NO_INIT";
50 | case android::ALREADY_EXISTS:
51 | return "ALREADY_EXISTS";
52 | case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT
53 | return "DEAD_OBJECT";
54 | case android::FAILED_TRANSACTION:
55 | return "FAILED_TRANSACTION";
56 | case android::BAD_INDEX:
57 | return "BAD_INDEX";
58 | case android::NOT_ENOUGH_DATA:
59 | return "NOT_ENOUGH_DATA";
60 | case android::WOULD_BLOCK:
61 | return "WOULD_BLOCK";
62 | case android::TIMED_OUT:
63 | return "TIMED_OUT";
64 | case android::UNKNOWN_TRANSACTION:
65 | return "UNKNOWN_TRANSACTION";
66 | case android::FDS_NOT_ALLOWED:
67 | return "FDS_NOT_ALLOWED";
68 | default:
69 | return "UNMAPPED_ERROR";
70 | }
71 | }
72 |
73 | class FrameProxy: public android::ConsumerBase::FrameAvailableListener {
74 | public:
75 | FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) {
76 | }
77 |
78 | virtual void
79 | onFrameAvailable(const android::BufferItem& /* item */) {
80 | mUserListener->onFrameAvailable();
81 | }
82 |
83 | private:
84 | Minicap::FrameAvailableListener* mUserListener;
85 | };
86 |
87 | class MinicapImpl: public Minicap
88 | {
89 | public:
90 | MinicapImpl(int32_t displayId)
91 | : mDisplayId(displayId),
92 | mRealWidth(0),
93 | mRealHeight(0),
94 | mDesiredWidth(0),
95 | mDesiredHeight(0),
96 | mDesiredOrientation(0),
97 | mHaveBuffer(false),
98 | mHaveRunningDisplay(false) {
99 | }
100 |
101 | virtual
102 | ~MinicapImpl() {
103 | release();
104 | }
105 |
106 | virtual int
107 | applyConfigChanges() {
108 | if (mHaveRunningDisplay) {
109 | destroyVirtualDisplay();
110 | }
111 |
112 | return createVirtualDisplay();
113 | }
114 |
115 | virtual int
116 | consumePendingFrame(Minicap::Frame* frame) {
117 | android::status_t err;
118 |
119 | if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) {
120 | if (err == -EINTR) {
121 | return err;
122 | }
123 | else {
124 | MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err);
125 | return err;
126 | }
127 | }
128 |
129 | frame->data = mBuffer.data;
130 | frame->format = convertFormat(mBuffer.format);
131 | frame->width = mBuffer.width;
132 | frame->height = mBuffer.height;
133 | frame->stride = mBuffer.stride;
134 | frame->bpp = android::bytesPerPixel(mBuffer.format);
135 | frame->size = mBuffer.stride * mBuffer.height * frame->bpp;
136 |
137 | mHaveBuffer = true;
138 |
139 | return 0;
140 | }
141 |
142 | virtual Minicap::CaptureMethod
143 | getCaptureMethod() {
144 | return METHOD_VIRTUAL_DISPLAY;
145 | }
146 |
147 | virtual int32_t
148 | getDisplayId() {
149 | return mDisplayId;
150 | }
151 |
152 | virtual void
153 | release() {
154 | destroyVirtualDisplay();
155 | }
156 |
157 | virtual void
158 | releaseConsumedFrame(Minicap::Frame* /* frame */) {
159 | if (mHaveBuffer) {
160 | mConsumer->unlockBuffer(mBuffer);
161 | mHaveBuffer = false;
162 | }
163 | }
164 |
165 | virtual int
166 | setDesiredInfo(const Minicap::DisplayInfo& info) {
167 | mDesiredWidth = info.width;
168 | mDesiredHeight = info.height;
169 | mDesiredOrientation = info.orientation;
170 | return 0;
171 | }
172 |
173 | virtual void
174 | setFrameAvailableListener(Minicap::FrameAvailableListener* listener) {
175 | mUserFrameAvailableListener = listener;
176 | }
177 |
178 | virtual int
179 | setRealInfo(const Minicap::DisplayInfo& info) {
180 | mRealWidth = info.width;
181 | mRealHeight = info.height;
182 | return 0;
183 | }
184 |
185 | private:
186 | int32_t mDisplayId;
187 | uint32_t mRealWidth;
188 | uint32_t mRealHeight;
189 | uint32_t mDesiredWidth;
190 | uint32_t mDesiredHeight;
191 | uint8_t mDesiredOrientation;
192 | android::sp mBufferProducer;
193 | android::sp