Taking a screenshot via shell command

murdoch1976

Member
Licensed User
Longtime User
Hi all,

Forgive me if this is a bit of a noob question, but I'm trying to use the shell function in the "Phone" library to take a screenshot of the Android screen (the whole current screen, not my own activity).

I set the object up as normal...

Dim cmdShell As Phone
Dim strFilePath As String

strFilePath = pthDefaultPath & "/" & pthImageCache


... I've tried two shell commands, both "screencap" and "fbtool" (I'm presuming it'll pick them up and run them from the /system/bin/ folder).

This line seems to pass without error, but does nothing...

cmdShell.Shell("screencap", Array As String("p", strFilePath & "/img.png"),Null,Null)


This one gives me a full-on java exception...

cmdShell.Shell("fbtool", Array As String("d", strFilePath & "/img.png"),Null,Null)


Could someone possibly point out what I'm doing wrong please? My phone is not rooted, I'm trying to do this without having the user need to root the device.

Cheers :)
 

murdoch1976

Member
Licensed User
Longtime User
As a quick update, if I run this...

cmdShell.Shell("/system/bin/screencap", Array As String("-p", strFilePath & "/img.png"),Null,Null)

(and include the path to the screencap.exe) then it fails with the error

"Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 5731 (screencap)"

The file img.png is actually created in the right folder as well, but when I try and open it I get the message "unable to load photo".

I'm beginning to get the feeling this is a 'root access' thing. However, someone out there must know a way of doing this without root access?
 
Upvote 0

murdoch1976

Member
Licensed User
Longtime User
Many thanks for your response Erel. This site seems to keep you extremely busy :)

If it is truly impossible to take a screenshot outside of the activity on an un-rooted device. Are there any code snippets anywhere to show me how to do it on a rooted device?

Many thanks!
 
Upvote 0

murdoch1976

Member
Licensed User
Longtime User
It's not as though I've not tried, btw. I've gone through this whole forum, and I've managed to give my app root access (yay), and I've tried the following code...

This...
B4X:
   Log(File.ListFiles("/dev/graphics"))
... nicely produces a list of the files in this 'root access only' folder. They are 'f0, f1, f2, f3, f4' etc. This proves to me that I have root permissions.

... I've tried this, but it appears to do nothing at all
B4X:
Dim cmdShell As Phone    
cmdShell.Shell("/system/bin/cat", Array As String("/dev/graphics/fb0 > " & pthImageCache & "/frame.raw"),Null,Null)

... I've tried this ...
B4X:
If File.Exists("/dev/graphics","fb0") = True Then
   File.Copy("/dev/graphics","fb0",pthImageCache,"frame.raw")
End If
... but it throws a JavaException (EACCES) saying that it couldn't open the file, as permission was denied. This is odd to me, as the application is granted SU access.

:sign0085:
 
Upvote 0

murdoch1976

Member
Licensed User
Longtime User
Thanks for your reply.

It's a galaxy note s2 running 4.1.1

I'm afraid I'm trying to do this programmatically within my android app as part of a service, I was already aware there is a user-driven method of doing it - however, the api, command or executable it fires is not exposed to programmers. I need to screen-grab fast enough from whatever is on display on the android device screen (not just within my own app) to generate a movie file of some sort which contiunually contains the last 10 seconds of footage (like how programs like tversity transcode)

I've now managed to copy the fb0 frame buffer file programmatically from the /dev/graphics folder using the mlfiles library. However, this has presented few more problems...

1) The raw frame-buffer image is 7mb big at anyone time, so at most is only copyable a few times a second - this is miles away from the 25 frames per second I need.

2) There is a distinct lack of libraries out there that will decode the raw file. I have no idea where to start.

3) this file could potentially be in a different raw format per device make and model depending on the gpu hardware, I would really like to convert it on the fly rather than repeatedly copy the fb0 file to a working folder.

Perhaps I'm going about this entirely the wrong way, but there are a glut of vncserver style applications out there for rooted and unrooted devices so it must be possible.

Perhaps I've aimed far too high for a first outing. I'm a competent programmer, but I'm not used to this framework yet.
 
Upvote 0

murdoch1976

Member
Licensed User
Longtime User
I appreciate this, and I know you mentioned this before, but I want to do this all "on device" without need to connect to a pc. Essentially I'm trying to capture a video of the screen 'on device' and transcode to avi 'on device' in realtime.

I think I'm going to have to use eclipse and get a bit deeper into this. Thank you everyone for your suggestions.
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
I appreciate this, and I know you mentioned this before, but I want to do this all "on device" without need to connect to a pc. Essentially I'm trying to capture a video of the screen 'on device' and transcode to avi 'on device' in realtime.
This is a big ask. Firstly, it requires special conditions (root or usb pc connected). Secondly, the performance you need just to read from the frame buffer. The formats. And last of all re-encoding it to AVI on device by SW? Not possible unless you decrease the resolution. Maybe you can invoke the HW encoder instead.
Either way, maybe you should look at JNI, .so, and code closer to drivers. But that makes your app too HW dependent and it will run on lesser devices.
 
Upvote 0

murdoch1976

Member
Licensed User
Longtime User
Hi,

Thanks for the reply. I was kinda thinking along those lines as well. As the fb0 file generated is 7mb big there's no way I can copy it to a temp folder, have it converted and the resolution dropped, and then transcode it to an AVI file 25 times a second - especially if I want to add sound as well.

Talking directly to the hardware via the drivers would be ideal, but like you say, it'd be hardware specific so I'd end up having to somehow write code for all different GPUs on Android devices.

Essentially, I'm trying to screencast via DLNA (Android already natively supports broadcasting over DLNA) - so that people would not have to spend money on screencast dongles for their TV etc...

However, I guess the reason these dongles exist is because there simply isn't the power at device software level to do all the transcoding, so the wi-fi dongle does all of the image processing instead.

Miracast is coming out soon anyway, but again this means getting a compatible TV or buying a plug-in USB dongle. I think it's a rip.

Thanks again.

Murdoch.
:BangHead:
 
Upvote 0
Top