Skip to content
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

Is it possible to redirect the stream to another application ? #1073

Open
Darkroll76 opened this issue Jan 10, 2020 · 46 comments
Open

Is it possible to redirect the stream to another application ? #1073

Darkroll76 opened this issue Jan 10, 2020 · 46 comments

Comments

@Darkroll76
Copy link

Hi,

Currently, scrpcy opens independent windows to render video stream but I'm trying to integrate it inside an application. Is there any way to do it? By redirecting the stream?

It could be a Unity App or Java App or C# UWP App but I would like to be able to share android-based VR headset screen (Oculus Go, Quest, PICO, etc) inside a desktop application.

Thanks for your time,
Killian

@iiasceri
Copy link

72148353-7c333e00-3398-11ea-8db7-cac9a1826762
https://github.com/barry-ran/QtScrcpy

@Darkroll76
Copy link
Author

72148353-7c333e00-3398-11ea-8db7-cac9a1826762
https://github.com/barry-ran/QtScrcpy

Thanks, I will try if I could find what I need with this project. For now, it just seems to offer the same features.

@rom1v
Copy link
Collaborator

rom1v commented Jan 10, 2020

Currently, scrpcy opens independent windows to render video stream but I'm trying to integrate it inside an application. Is there any way to do it?

The proper way would be to split scrcpy in two parts: libscrcpy and the UI (#707 (comment)). But this is not done.

Another way could be to use only the .jar on your side, and write your client which mimic the protocol used between the client and the server (but this protocol should be considered private, i.e. it may change at any time).

Alternatively, you could fork current master and replace some parts…

@LBensman
Copy link

That's pretty much what I did - just take the Java portion that already sends back H.264 stream (with initial custom header), and just handle H.264 stream inside your desktop application (or where ever you want to consume it). Basically reuse the server jar, but dump viewer in favor of your own stream handling and visualization.

On a separate note, @rom1v , did you notice from screenshots above that QtScrcpy seems to be supporting audio? I know you tried USBAudio (I'm looking into it now myself), but quick look (really, probably not even 2 min spent on it) at QtScrcpy source, I couldn't see much for audio handling. Have you looked into it and see if it something more solid than USBAudio?

@rom1v
Copy link
Collaborator

rom1v commented Jan 10, 2020

did you notice from screenshots above that QtScrcpy seems to be supporting audio?

I don't think so. They're just shortcut for volume up/down on the device. Also see #612.

Have you looked into it and see if it something more solid than USBAudio?

The real solution will be the Playback Capture API introduced in Android Q. See #933.

@LBensman
Copy link

Yeah, I know about Playback Capture API (I've been all over the threads, esp #14 one) - unfortunately it is insufficient for what I need...

@rom1v
Copy link
Collaborator

rom1v commented Jan 10, 2020

unfortunately it is insufficient for what I need...

Why?

@LBensman
Copy link

I mean it would "help somewhat" in that it will allow for a small sliver of audio to be captured, but it is a co-operative solution between apps and the capturing app (the app has to explicitly allow for its audio to be captured), and, as far as I understand, would only work with a small subset of apps and none of the system sounds. It seems PCAPI was designed for a very very narrow use case like streaming of game playing, rather than general-purpose API. In other words, in scrcpy analogy, only being able to capture screen when a co-operating game is being played, but otherwise getting a blank screen in all other cases - much more limited and thus much less useful.

@rom1v
Copy link
Collaborator

rom1v commented Jan 11, 2020

I did not investigated yet, but by calling private API with shell permissions, it is maybe possible to capture the audio from any app (I'm not sure).

For example, the MediaProjection API requires to get an authorization from the user, but scrcpy does not.

@Darkroll76
Copy link
Author

Darkroll76 commented Jan 20, 2020

Hi @LBensman ,

That's pretty much what I did - just take the Java portion that already sends back H.264 stream (with initial custom header), and just handle H.264 stream inside your desktop application (or where ever you want to consume it). Basically reuse the server jar, but dump viewer in favor of your own stream handling and visualization.

Could you help me with that part? Should it work if I'm just launching server .jar? Because, I guess, it requires to modify the scrcpy code, but It could be very helpful if you help me where.

I want to display the video stream in a Unity app, I can handle H.264 stream from the "receiver" side, but I'm just stuck trying to find a way to modify scrcpy to send back H264 to it.

Thanks,

@rom1v
Copy link
Collaborator

rom1v commented Jan 20, 2020

A proper solution could be to implement an option --serve, which would wait for a client to connect before starting the mirroring, and it would forward the video stream.

For example, it would be used like this:

scrcpy --serve=tcp:localhost:1234

That way, once implemented, anyone could receive the raw video stream.

It's not a priority for me, but if you work on something that requires it, you could implement it that way and submit a pull request. 😉

@Darkroll76
Copy link
Author

Yes, this solution could be great and easy to use. Thanks for the suggestion!

I can for sure understand that isn't a priority for you ;).

Since I'm not an expert in java development, I'm not sure I will be able to do it properly but I'm still going to start investigating the code and try (If anyone who is reading this post wants to join ;) ).

Have you any tips? I have read the developer readme but it would be helpful to know which IDE (for example) should be used to edit your project. I'm using Android Studio for the server-side but which IDE are you using for the client development and to build scrcpy.exe?

Thanks for your time,

@rom1v
Copy link
Collaborator

rom1v commented Jan 23, 2020

Since I'm not an expert in java development

This feature has to be implemented on the client-side, which is in C 😉

Basically, when you receive a packet, it is decoded + recorded (if necessary):

scrcpy/app/src/stream.c

Lines 81 to 97 in 3935660

static bool
process_frame(struct stream *stream, AVPacket *packet) {
if (stream->decoder && !decoder_push(stream->decoder, packet)) {
return false;
}
if (stream->recorder) {
packet->dts = packet->pts;
if (!recorder_push(stream->recorder, packet)) {
LOGE("Could not send packet to recorder");
return false;
}
}
return true;
}

We can, in addition, write it to a socket.

But in fact, it could even be written earlier (without even parsing it):

bool ok = stream_recv_packet(stream, &packet);

I have read the developer readme but it would be helpful to know which IDE (for example) should be used to edit your project.

Whatever you want. I use vi.

@Darkroll76
Copy link
Author

Hi,

I don't know if I should create another topic about creating an --serve option to forward video stream. I just want to be sure I'm doing the right thing since I only started to manage and understand the scrcpy client source code.

First in scrcpy/app/scr/cli.c, I added the option {"serve", required_argument, NULL, OPT_SERVE}, then into the switch I added

case OPT_SERVE:
                opts->serve = optarg;
                break;

Then in scrcpy/app/scr/scrcpy.c : scrcpy(const struct scrcpy_options *options)

if (!stream_start(&stream)) {
        goto end;
    }
    stream_started = true;

if (!serve_init(options->serve)){
        goto end;
    }

I would like to split the args 'tcp:localhost:1234' and use net_connect function from net.c to create a socket. Then the idea is to send the packet through this socket each time process_frame is called. But in code, I don't know the best way I should do it. Create another class? Or just create a function serve_packet(AVPacket *packet) in stream.c ?

Thanks again for your time,
Killian

@qaisbayabani
Copy link

qaisbayabani commented May 18, 2020

https://github.com/qaisbayabani/SCRCPY-C-Sharp-Client is a demo to show a self made application for scrcpy output

@Darkroll76
Copy link
Author

Hi @qaisbayabani !

Thanks for the demo ! I tried but I got a java.io.IOException: Connection refused
Any idea ?

@qaisbayabani
Copy link

qaisbayabani commented May 26, 2020

i have made 100% working clients for both c# and java is available on request if the party needs it so deperetly a one page 100 line code.

@qaisbayabani
Copy link

qaisbayabani commented May 27, 2020

mr darkroll u r using an emulator?
are you connecting your phoen directly via USB?
and confirm u are using scrcpy 1.12.1 version?

adb commands must be reconfigured according to your own environment other things will work fine. i have deleted this demo repository because i have developed a flawless full alpha version now which is working 100% fine soon i will load it to repository

if you could get me screenshots of output window than may i could understand that will be a thanks for your response.

@overvox
Copy link

overvox commented Jun 4, 2020

i have made 100% working clients for both c# and java is available on request if the party needs it so deperetly a one page 100 line code.

Hey, any chance you could share the C# Code or are you still working on a functioning version?

@Darkroll76
Copy link
Author

@qaisbayabani I'm interested to see it too.

@qaisbayabani
Copy link

i have made 100% working clients for both c# and java is available on request if the party needs it so deperetly a one page 100 line code.

Hey, any chance you could share the C# Code or are you still working on a functioning version?

the version mr.darkroll was downloaded is also a working one.

@qaisbayabani
Copy link

mr darkroll u r using an emulator?
are you connecting your phoen directly via USB?
and confirm u are using scrcpy 1.12.1 version?

adb commands must be reconfigured according to your own environment other things will work fine. i have deleted this demo repository because i have developed a flawless full alpha version now which is working 100% fine soon i will load it to repository

if you could get me screenshots of output window than may i could understand that will be a thanks for your response.

is it working or still error

@qaisbayabani
Copy link

qaisbayabani commented Jun 5, 2020

mr darkroll u r using an emulator?
are you connecting your phoen directly via USB?
and confirm u are using scrcpy 1.12.1 version?
adb commands must be reconfigured according to your own environment other things will work fine. i have deleted this demo repository because i have developed a flawless full alpha version now which is working 100% fine soon i will load it to repository
if you could get me screenshots of output window than may i could understand that will be a thanks for your response.

is it working or still error

as i guess u were using an emulator u should use a phone and tell the room is it working at ur side

@Darkroll76
Copy link
Author

@qaisbayabani I'm using it with a VR Headset based on Android. I still have a Connection refused with the first demo you posted.
It's not directly connected by USB but I added the adb tcpip 5555 and adb connect command in your script.
I was using 1.12.1 then I changed it by the new one (1.13).

My version allows forwarding the packet received on another socket. In your demo, you directly push the scrcpy-server and connect to it. It is very helpful to understand how you integrated it into a C# solution.

@qaisbayabani
Copy link

qaisbayabani commented Jun 5, 2020

https://github.com/qaisbayabani/SCRCPY-C-Sharp-Client
it covers.
multithreading
a single file program.cs converting smooth capture from scrcpy-server to c# client
adb commands using c#
server port opening
listening to stream and forwarding the stream to other port.
opencv capture from network stream and disply H264 stream from android screen capture.
cross plateform stuff.
enjoy

@qaisbayabani
Copy link

Mr. Overvox

Hey, any chance you could share the C# Code or are you still working on a functioning version?

its here

@Darkroll76
Copy link
Author

@qaisbayabani I don't have the connection refused any more. But It's still not working for me. I always have a gray screen with "Empty" outputs.
I'm using it on Windows with an Android VR Headset.

@qaisbayabani
Copy link

qaisbayabani commented Jun 10, 2020

@qaisbayabani I don't have the connection refused any more. But It's still not working for me. I always have a gray screen with "Empty" outputs.
I'm using it on Windows with an Android VR Headset.
i have prepared it and tested with android mobile phone and working perfect. may be its needs fine tunning for VR Headset. try to attach VR with USB Cable may be a Network ports speed issue. try it tell me if its working on android phone as its working fine here on 50 sets i have tried form andorid 6.0 to 9.0.

@Darkroll76
Copy link
Author

@qaisbayabani
i have prepared it and tested with android mobile phone and working perfect. may be its needs fine tunning for VR Headset. try to attach VR with USB Cable may be a Network ports speed issue. try it tell me if its working on android phone as its working fine here on 50 sets i have tried form andorid 6.0 to 9.0.

I tried using USB Cable on VR Headset (Android 8) and my phone too (Android 10). I got the "Third is Gneeal" error and receiving "Empty" outputs each time.

@hgedik
Copy link

hgedik commented Jun 10, 2020

@qaisbayabani hi,

I have Android 9 (samsung galaxy s8+). I tried over wifi and usb cable. And same result. just "empty" outputs.

@Darkroll76
Copy link
Author

Darkroll76 commented Jun 11, 2020

Hi @hgedik,

I manage to make it works for me. I change from http://127.0.0.1:27184 to tcp://localhost:27184. Then I changed Cv2.WaitKey to wait only 1 sec instead of sleepTime because the framerate was slow for me with it.

@qaisbayabani
Copy link

qaisbayabani commented Jun 11, 2020

@qaisbayabani hi,

I have Android 9 (samsung galaxy s8+). I tried over wifi and usb cable. And same result. just "empty" outputs.

I guess that u just have to just start the screen of mobile (or play some thing youtube etc) before running the debug. and as drakol may u have to adjust Cv2.Waitkey(1). if u change the waitkey than u may have not even to start the screen before debug. waiting from ur side. :)

@qaisbayabani
Copy link

Hi @hgedik,

I manage to make it works for me. I change from http://127.0.0.1:27184 to tcp://localhost:27184. Then I changed Cv2.WaitKey to wait only 1 sec instead of sleepTime because the framerate was slow for me with it.

its good to listen that its working for u. u can see its just taking few lines of codes and needs just few more for universal plug and play. Cv2.WaitKey(1) is the best and ideal for all.

@qaisbayabani
Copy link

I think the basic question is solved that yes it is possible to redirect the stream to another application.

  • you can made that another application which can read that stream.
    the challenge was for me that that application would be a one page simple code easy to understand.
    unlike jumbled classes as used by scrcpy org.
    now its a challenge to write a simple server that can serve the stream from android phone to this application.

@rom1v
Copy link
Collaborator

rom1v commented Jun 11, 2020

Hi @qaisbayabani,

I don't really know C#, but just a few remarks.

https://github.com/qaisbayabani/SCRCPY-C-Sharp-Client/blob/b356aae19dd1e0a348ffd75866f951f43c5f3504/Program.cs#L203

I don't know how BufferedStream behaves, but in theory you want to consume the video stream as soon as it is available. I guess it could delay frames, especially "small" frames (when the changes compared to the previous frame are minimal).

https://github.com/qaisbayabani/SCRCPY-C-Sharp-Client/blob/b356aae19dd1e0a348ffd75866f951f43c5f3504/Program.cs#L325

The framerate of the video is very variable: a new frame is produces whenever the screen content changes. If it does not change for 10 seconds, there are no frames. If it changes 90 times per second, then the framerate is 90fps. The WaitKey will also delay the frame.

@hgedik
Copy link

hgedik commented Jun 11, 2020

image
@qaisbayabani i cant fix this. :) maybe i missed something. I set to Cv2.WaitKey(1) but same.

and video: https://www.screencast.com/t/bPdjdgkD9

@qaisbayabani
Copy link

image
@qaisbayabani i cant fix this. :) maybe i missed something. I set to Cv2.WaitKey(1) but same.

and video: https://www.screencast.com/t/bPdjdgkD
this error indicates that your opencv is not working well

you have to just add nuget package opencvsharp4 from nuget manager in visual studio.

and try with http://localhost:27184 why i see tcp://localhost:27184 in your outputimage
its error from your opencv if your opencv repond well then this "third is geneal " will not appear.
it means that receiver application is not receiving the stream from server and denied the connection if you want me the detail how to instal opencv in visual studio then i can help out more.

@qaisbayabani
Copy link

Hi @qaisbayabani,

I don't really know C#, but just a few remarks.

https://github.com/qaisbayabani/SCRCPY-C-Sharp-Client/blob/b356aae19dd1e0a348ffd75866f951f43c5f3504/Program.cs#L203

I don't know how BufferedStream behaves, but in theory you want to consume the video stream as soon as it is available. I guess it could delay frames, especially "small" frames (when the changes compared to the previous frame are minimal).

https://github.com/qaisbayabani/SCRCPY-C-Sharp-Client/blob/b356aae19dd1e0a348ffd75866f951f43c5f3504/Program.cs#L325

The framerate of the video is very variable: a new frame is produces whenever the screen content changes. If it does not change for 10 seconds, there are no frames. If it changes 90 times per second, then the framerate is 90fps. The WaitKey will also delay the frame.

thanks for remarks but i strongly rely on "WYSIWYG" WHAT YOU SEE IS WHAT YOU GET.
if the frame rate is higher than its good for game stream. and the Waitkey is resolved as per previous comments that Cv2.WaitKey(1) is the best perfroming at most devices.

i have checked it with stop watch app running in mobile that there is no delay at all.

thaks for your input and i want your point to be elebortated more that i can learn more from your input.

@Darkroll76
Copy link
Author

@qaisbayabani I don't get why http://localhost:27184 doesn't work for me (Empty outputs) but tcp://localhost:27184 did. I'm on Windows.

Also, if you want to upgrade using scrcpy-server.jar 1.13 instead 1.12.1, here is my command with the new arguments :

ps.Arguments = "shell " + "CLASSPATH=/data/local/tmp/scrcpy-server.jar " +
         "app_process " + "/ " + "com.genymobile.scrcpy.Server " +
        "1.13 " + "1024 " + "2000000 " + "0 " + "1 " + "false " + "563:1000:800:470 " + "true " + "true" + " 0"; 

@qaisbayabani
Copy link

qaisbayabani commented Jun 11, 2020

@qaisbayabani I don't get why http://localhost:27184 doesn't work for me (Empty outputs) but tcp://localhost:27184 did. I'm on Windows.

Also, if you want to upgrade using scrcpy-server.jar 1.13 instead 1.12.1, here is my command with the new arguments :

ps.Arguments = "shell " + "CLASSPATH=/data/local/tmp/scrcpy-server.jar " +
         "app_process " + "/ " + "com.genymobile.scrcpy.Server " +
        "1.13 " + "1024 " + "2000000 " + "0 " + "1 " + "false " + "563:1000:800:470 " + "true " + "true" + " 0"; 

you may have to instal IIS for windows and start it
for http://localhost:27184
but if u are getting it via tcp than its fine. cuz u may have a linux based server installed on pc.

u can also use ip address assigned by your local wifi router to your pc
as mine http://192.168.0.3:27184

@qaisbayabani
Copy link

qaisbayabani commented Jun 11, 2020

there are thousands of pages written on web about ffmpeg conversion, listening H264 stream and conversion, encoders decoders bla bla.... i have just here to cover as written in my repository readme

it covers.

multithreading

a single file program.cs converting smooth capture from scrcpy-server to c# client

adb commands using c#

server port opening

reading server received data and forwarding the stream to other port.

opencv capture from network stream and disply H264 stream from android screen capture. cross plateform stuff. enjoy

only for teaching purpose.

and a real world working example of serving that purposes.

@ahmed-shariff
Copy link

@qaisbayabani Thanks for sharing the script man. I am trying to run this and I am getting a similar issue as the other. When throw the exception that results in "Third is Gneeal" I get the following:

.
.
.
Connected!========>2
Third is Gneeal 

Unhandled Exception: System.IO.IOException: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
   at System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   --- End of inner exception stack trace ---
   at Program.ForFun.Fun() in F:\temp\scrcpytest\Program.cs:line 251
   at Program.<>c__DisplayClass0_0.<Main>b__0() in F:\temp\scrcpytest\Program.cs:line 41
   at System.Threading.Thread.ThreadMain_ThreadStart()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

I tried what others had suggested and am still getting the same issue.

@Darkroll76 would you be able to share your version of the working script?

@ahmed-shariff
Copy link

I recreated the same script as @qaisbayabani in python, which seems to work. The python script:

import cv2
import socket
from multiprocessing import Process
from tqdm import tqdm

def main():
    s_input = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s_input.bind(('127.0.0.1', 27183))
    s_input.listen(1)
    conn, addr = s_input.accept()

    print("Connection details: ", conn, addr)
    print("Device: ", conn.recv(64).decode('utf-8'))
    print("Width? ", int.from_bytes(conn.recv(2), "big"))
    print("Height? ", int.from_bytes(conn.recv(2), "big"))

    s_output = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s_output.bind(('127.0.0.1', 27184))
    s_output.listen(1)

    p = Process(target=client)
    p.start()

    out_conn, addr = s_output.accept()

    print("\n", "Connection details: ", out_conn, addr)
    while True:
        out_conn.send(conn.recv(1))
    p.join()
    

def client():
    cap = cv2.VideoCapture("tcp://127.0.0.1:27184")
    print(cap)

    for _ in tqdm(range(1000)):
        r, img = cap.read()
        if not r:
            continue
        cv2.imshow("", img)
        cv2.waitKey(20)
    

if __name__ == "__main__":
    main()
    # client()

I tried removing the ForFun3 line https://github.com/qaisbayabani/SCRCPY-C-Sharp-Client/blob/91717b1faefec31854111919329431004396e0e3/Program.cs#L194 from the csharp script and try connect to the tcp server using only the client function in the python script, and I still get the same issue as I mentioned above.

@qaisbayabani
Copy link

@Darkroll76 would you be able to share your version of the working script?

correct question

@qaisbayabani
Copy link

qaisbayabani commented Apr 2, 2022

the flawless version as promised is updated on 02.04.2022 and posted on my repo hope u will find it help full https://github.com/qaisbayabani/SCRCPY-C-Sharp-Client this is to make all the previous issues void and have a cutting edge tech to decode stream at pc client. new code making all previous issues void.

@qaisbayabani
Copy link

i have done it for android 13 also but not uploaded yet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants