-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add option to mirror camera #4213
Conversation
if (cameraManager == null) { | ||
try { | ||
fillBaseContext(); | ||
cameraManager = CameraManager.class.getDeclaredConstructor(Context.class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Android 11 requires correct Context.getOpPackageName()
. getSystemContext().getService("camera")
doesn't work.
I bought a Meizu mblu 10 (Android 11) for testing. It turns out that, unlike audio capture, camera capture requires the app to keep being at foreground. The capture session stops once the foreground workaround was stopped. That's a pretty huge inconvenience for Android 11 users. |
I know two other methods to become foreground:
|
IMO, it is totally ok to require Android 12+ for the camera feature (the workaround for audio was "simple" and not too intrusive, so it was worth it). |
OK, now I bail out camera mirroring on Android 11 and older, and reverted changes to the foreground workaround. To be precise, the camera capturing stops when either:
So, it's barely usable, if the user doesn't use the device while mirroring. However, I have to admit it's too much a restriction. |
Thanks for working on this! It's been working very well for me (Android 13 + Google Pixel 7 Pro). I've made an additional change in my branch to add support for specifying the camera resolution and frame rate: chenxiaolong@edb8f5b. In particular, this also adds support for the constrained high speed capture mode, allowing 120 and 240 fps camera streams. (This makes scrcpy the only program capable of streaming the camera at a high frame rate on Android 🙂) |
Just a small message to say that, despite the lack of feedback for 1 month, the feature from this PR has the highest priority for the next scrcpy version. 😉 I'm just quite busy currently on other subjects at work, which require learning new stuff (which is very interesting, but leaves less time/effort available for scrcpy on my free time). So it may take some time, but it will be merged 😄 Thank you again for your work 👍 (Recently, I just started to review/rebase/adapt some of your refactor commits, branch camera.2) |
This is such a cool feature, thanks for making it! I just gave it a try on my Pixel 5a (Android 13) and it works nicely with |
@yume-chan about
One dirty way to get rid of these messages is: diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java
index a8e8e36a2..89b800225 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Server.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Server.java
@@ -3,7 +3,9 @@ package com.genymobile.scrcpy;
import android.os.BatteryManager;
import android.os.Build;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
@@ -222,7 +224,14 @@ public final class Server {
}
if (options.getListCameras() || options.getListCameraSizes()) {
Workarounds.apply(false, true);
- Ln.i(LogUtils.buildCameraListMessage(options.getListCameraSizes()));
+ PrintStream out = System.out;
+ PrintStream err = System.err;
+ System.setOut(new PrintStream(new ByteArrayOutputStream()));
+ System.setErr(new PrintStream(new ByteArrayOutputStream()));
+ String s = LogUtils.buildCameraListMessage(options.getListCameraSizes());
+ System.setOut(out);
+ System.setErr(err);
+ Ln.i(s);
}
// Just print the requested data, do not mirror
return; Not sure if we can leverage this to improve |
Add --video-source=camera, and related options: - --camera-id=<id>: select the camera by its id (see --list-cameras); - --camera-size=<width>x<height>: select the capture size. Fixed #241 <#241> PR #4213 <#4213> Co-authored-by: Romain Vimont <rom@rom1v.com> Signed-off-by: Romain Vimont <rom@rom1v.com>
In addition to --camera-size to specify an explicit size, make it possible to select the camera size automatically, respecting the maximum size (already used for display mirroring) and an aspect ratio. For example, "scrcpy --video-source=camera" followed by: - (no additional arguments) : mirrors at the maximum size, any a-r - -m1920 : only consider valid sizes having both dimensions not above 1920 - --camera-ar=4:3 : only consider valid sizes having an aspect ratio of 4:3 (+/- 10%) - -m2048 --camera-ar=1.6 : only consider valid sizes having both dimensions not above 2048 and an aspect ratio of 1.6 (+/- 10%) PR #4213 <#4213> Co-authored-by: Simon Chan <1330321+yume-chan@users.noreply.github.com>
@yume-chan I propose this to get rid of all internal errors printed to the console on Xiaomi devices: 3c7a6d3. Maybe it could be the behavior on all devices instead. What do you think? |
I can confirm my workaround works on my Mi 11 running stock MIUI 14 and Android 13. But again, my workaround only hides one of the two system outputs, so your method of replacing output streams looks like a better solution. I also checked all your changes on the |
Merged and published scrcpy v2.2 🚀 Thank you very much @yume-chan and @chenxiaolong ❤️ |
I was testing #4392, but since 2 of my 4 devices are running Android 11, I enabled foreground workaround. But then I found this: diff --git a/server/src/main/java/com/genymobile/scrcpy/CameraCapture.java b/server/src/main/java/com/genymobile/scrcpy/CameraCapture.java
index b9da3658..ee25663e 100644
--- a/server/src/main/java/com/genymobile/scrcpy/CameraCapture.java
+++ b/server/src/main/java/com/genymobile/scrcpy/CameraCapture.java
@@ -4,6 +4,8 @@ import com.genymobile.scrcpy.wrappers.ServiceManager;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Intent;
import android.graphics.Rect;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
@@ -64,6 +66,34 @@ public class CameraCapture extends SurfaceCapture {
this.highSpeed = highSpeed;
}
+ private CameraDevice retryOpenCamera(String id) throws InterruptedException{
+ Ln.i("Waiting for audio capture to start");
+ Thread.sleep(2000);
+
+ Ln.w("Hacking into your device to forcefully enable camera...");
+ int retry = 0;
+ while (true) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.setComponent(new ComponentName(FakeContext.PACKAGE_NAME, "com.android.shell.HeapDumpActivity"));
+ ServiceManager.getActivityManager().startActivityAsUserWithFeature(intent);
+ ServiceManager.getActivityManager().startActivityAsUserWithFeature(intent);
+ ServiceManager.getActivityManager().forceStopPackage(FakeContext.PACKAGE_NAME);
+
+ Thread.sleep(100);
+
+ CameraDevice device = openCamera(id);
+ Ln.i("Your device has been hacked after " + retry + " retries");
+ return device;
+ } catch (Throwable e) {
+ Thread.sleep(1000);
+ retry += 1;
+ }
+ }
+ }
+
@Override
public void init() throws IOException {
cameraThread = new HandlerThread("camera");
@@ -83,7 +113,11 @@ public class CameraCapture extends SurfaceCapture {
}
Ln.i("Using camera '" + cameraId + "'");
- cameraDevice = openCamera(cameraId);
+ if(Build.VERSION.SDK_INT==Build.VERSION_CODES.R) {
+ cameraDevice = retryOpenCamera(cameraId);
+ }else{
+ cameraDevice=openCamera(cameraId);
+ }
} catch (CameraAccessException | InterruptedException e) {
throw new IOException(e);
} By starting foreground workaround twice, then kill it once, then wait for some time, I can open the camera without any restrictions. I don't need to keep foreground workaround running, I can switch to other apps, the camera capture won't stop. This thing can also work for audio capture, but the success rate is much lower. I can't explain why it works, and I don't think it should be included into Scrcpy. Just a funny story. |
I tried to create a transparent and not touchable floaty window in scrcpy-server to make camera mirroring work for Android 11 devices. I tested it in AVD and it works fine, but I don't have any more Android 11 devices to test it on, and I can't find any reason in the AOSP why such a design would work. Here are some of the changes I made: |
@Mufanc It works on Meizu Mblu 10 (Flyme 9, Android 11), but on OnePlus 6 (HydrogenOS, Android 11) it throws an error:
IIRC there is no way for creating content provider in shell process yet. |
Closes #241
I can imagine this becoming another compatibility hell.
I can only test on emulators and XiaoMi devices, so there isn't much more I can do, for example to the bug report in #241 (comment).