Does the native code of the VideoView give access to the received packets of the video before or after decoding it? I need to access these packets in order to transmit them to another device. The initial solution is to modify the Android native code. Other possible solutions that I found are to use GStreamer or FFmpeg libraries.
I need bit guidance in order to achieve that goal.
Assume the phone is rooted.
Short answer is no, not that I know of.
Long answer is that you haven't given enough detail. What data exactly do you need access to? Are you writing an application, or modifying your OS to do this to other applications?
The code that actually fetches a remote video is in MediaPlayer and is native. See the following method in MediaPlayer:
private void setDataSource(/* snip */) throws /* snip */ {
/* snip */
else if (scheme != null) {
// handle non-file sources
nativeSetDataSource(
MediaHTTPService.createHttpServiceBinderIfNecessary(path),
path,
keys,
values);
return;
}
/* snip */
Unfortunately for you, almost all of the relevant MediaPlayer code is native, and if not, it is private (so subclassing will not work here).
However, depending on what you need to do, you could possibly override VideoView method setVideoURI(Uri, Map<String, String>), which is public. Here you can grab the URI and then proxy it through your own web service, or something. This isn't quite what you were asking, though.
Or, you could possibly look into modifying the Surface that is drawn to by MediaPlayer. Most of the relevant code is still native though.
The final possibility that I'll mention (there are probably hundreds of possible approaches) would be to modify the MediaHTTPService class. This appears to be used by MediaPlayer, but I can't be sure because if it's used, it's used in native code.
This answer recommends finding the native code at androidxref.com
Edit:
As requested, here is a little more detail about what the "proxy server" solution might look like. I don't know the implementation details on Android.
Basically, when you get a URL to play in the VideoView, you pass it to your own server instead. Something like startProxyServer(videoUrl). This starts a server, which downloads and then re-hosts the video. To get this working locally, start a webserver listening on localhost. The server just downloads the video at videoUrl, saves it locally, and then hosts it at localhost:port/?video=${videoUrl}.
So in very high-level pseudo-code the server could look like.
public void startProxyServer(String videoUrl) {
int PORT = 28641; // random port
File f = downloadFile(videoUrl);
saveFile(f, '/path/to/server/storage');
startWebServer('localhost', PORT);
}
So now you give localhost:port/?video=${videoUrl} as url to the videoView instead. Also, now other videoView instances can download from that same localhost url.
To make it work with other phones, your server of course couldn't run on localhost.
Of course I've not implemented this, but it's just one solution I can think of.
Related
I am developing an application for a DigitalPersona U.are.U 4500 fingerprint reader and using the U.are.U 2.2.3 SDK Java API.
The sample Java application that ships with the SDK works flawlessly.
However, when I try to do the same thing in my own sample application, the call to the Reader.Capture() method never returns, even though I can see the reader flashing when recording my fingerprint.
Below is a variation on the sample code I have tried with.
Other things I have tried:
Running the capture code in an instance of the class (i.e. not in a static context)
Running the capture operation in its own thread as well, but the results are the same.
Using the CaptureThread class from the demo application
The only difference I can see between my sample and the SDK sample app is that the latter is a graphical application. But why would that make a difference?
Unplugging the device causes the call to fail with an exception. That is about the only way I can get it to return.
import com.digitalpersona.uareu.*;
public class Main{
static Reader r;
public static void main(String[] args) {
try {
// Pick first available reader
ReaderCollection rc = UareUGlobal.GetReaderCollection();
rc.GetReaders();
r = rc.get(0);
if (r==null)
return;
// Open Reader
r.Open(Reader.Priority.COOPERATIVE);
System.out.println(r.GetStatus().status); // Outputs READY
// The following call just hangs and never returns...
Reader.CaptureResult
cr = r.Capture(Fid.Format.ISO_19794_4_2005, Reader.ImageProcessing.IMG_PROC_DEFAULT, 500, -1);
System.out.println(cr.quality.name()); // Just to test
} catch (UareUException e) {
e.printStackTrace();
}
}
}
The last two parameters, the two ints, passed to the Capture method are the resolution and the timeout respectively; passing -1 for the timeout blocks indefinitely. This is taken from the sample application as well.
I finally managed to get an example working.
Strange as it may seem, it only works in the context of a Java GUI application.
So, simply extending a JFrame and starting the reader capture on a separate thread seems to be sufficient.
This requirement is not specified anywhere in the SDK documentation that I can see.
UPDATE
It seems the problem is worse than I initially thought. Not only must the API be called in the context of a Java GUI application, but the GUI must also be in focus, otherwise the capture call simply does not return.
I have verified this with the example SDK applications. The Capture() method does not return if the apps are not in focus. This also applies to the C# examples, where the windows must be in focus, which suggests that this is built into the DLLs that ship with the solution.
This is terrible for our scenario, where we want to develop a local service that a browser can communicate with because, while the browser is in focus, obviously the Java application is not.
I faced the similar issue and it can be fixed by opening a reader in exclusive mode as below,
m_reader.Open(Reader.Priority.EXCLUSIVE);
Refer to below lines from documents,
public static final Reader.Priority COOPERATIVE
Client uses this priority to open reader in cooperative mode. Multiple clients with this priority are allowed. Client receives captured images if it has window with focus.
public static final Reader.Priority EXCLUSIVE
Client uses this priority to open reader exclusively. Only one client with this priority is allowed.
I'd like to prevent DownloadManager from downloading files for apps that are prohibited to access the internet by the NetworkPolicyManager. The custom ROM I use enforces this by writing an entry like this to iptables:
-A INPUT -i <interface> -m owner --uid-owner <UID> -j REJECT --reject-with icmp-port-unreachable
The DownloadManager is started under his own UID though and therefore can download files for apps that should not be able to access the internet. If I were to restrict the DownloadManager as well, other apps - that should be able to access the internet - cannot download files through the DownloadManager as a collateral damage. My (long term) goal is to contribute to this custom ROM by closing this (security) hole.
I looked at the source code of DownloadManager and do not understand where the actual download in the enqueue method starts. What code gets executed after this method? I couldn't find any clue in the other methods either.
public long enqueue(Request request) {
ContentValues values = request.toContentValues(mPackageName);
Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
long id = Long.parseLong(downloadUri.getLastPathSegment());
return id;
}
In the end I want to modify the DownloadManager in a way that downloads that got enqueued by restricted apps get their status set accordingly and stop without crashing the client app (the one that tried to start the download).
COLUMN_STATUS = STATUS_FAILED = 1 << 4 = 16
COLUMN_REASON = ERROR_UNKNOWN = 1000 or ERROR_BLOCKED = 1010
But I cannot do this if I don't understand what's going on. Please help me to understand the code or hint me in the right direction.
After some research and with CommonsWares help I found DownloadThread.java where the actual download is performed. As this post probably won't get any better answer I'll answer this myself now as good as I can: Checking if the requesting entity has the rights to download with help of
NetworkPolicyManager.getUidPolicy(int uid)
might do the job. But this requires android.permission.MANAGE_NETWORK_POLICY which is of protection level signature.
I'm trying to create an OSGi bundle that'd be installed on a eurotech gateway (reliagate 10 05).
This bundle would essentially connect the gateway to a BLE device.
To do so, I use a framework provided by eurotech called Everyware™ Software Framework (ESF) that adds up an extra layer on top of the kura v1.2.0 framework.
The catch is, the BLE device only accepts random static address type.
I managed to connect the gateway manually to the BLE device using the following commands in console:
hcitool -i hci0 lecc --random <BD_ADDR>
then
gatttool -i hci0 -b <BD_ADDR> --interactive
This works fine. The hard part is when I try to do the same thing in code using the ESF/kura framework.
Here's a snippet from a sample I use that I found on this page
public boolean connect(String adapterName) {
this.bluetoothGatt = this.device.getBluetoothGatt();
boolean connected = false;
try {
connected = this.bluetoothGatt.connect(adapterName);
} catch (KuraException e) {
logger.error(e.toString());
}
if (connected) {
this.bluetoothGatt.setBluetoothLeNotificationListener(this);
this.isConnected = true;
return true;
} else {
// If connect command is not executed, close gatttool
this.bluetoothGatt.disconnect();
this.isConnected = false;
return false;
}
}
Here is a list of some objects that the sample uses to scan and establish a connection:
org.eclipse.kura.bluetooth.BluetoothAdapter;
org.eclipse.kura.bluetooth.BluetoothDevice;
org.eclipse.kura.bluetooth.BluetoothGattSecurityLevel;
org.eclipse.kura.bluetooth.BluetoothGattService;
org.eclipse.kura.bluetooth.BluetoothLeScanListener;
org.eclipse.kura.bluetooth.BluetoothService;
org.eclipse.kura.bluetooth.BluetoothDevice;
org.eclipse.kura.bluetooth.BluetoothGatt;
org.eclipse.kura.bluetooth.BluetoothGattCharacteristic;
org.eclipse.kura.bluetooth.BluetoothLeNotificationListener;
So I searched through the api doc but didn't find anything.
Though, one interesting SO post mentions a command code to send to the device.
I found a method in kura framework that might help.
Here's the signature:
void ExecuteCmd(java.lang.String ogf, java.lang.String ocf, java.lang.String parameter)
but I couldn't figure out the OpCode Group Field (ogf) associated to the OpCode Command Field(ocf) in any documentation (I skimmed the ~2300 pages of the Bluetooth 4.0 core spec). If anyone knows where to search... :)
In the end, the question is: is there a way to set the address type to random (as with the hcitool command) with the kura framework ?
Or am I totally misleaded ? :/
Anyway, I'm really new to the kura and ble ecosystems so, sorry if it looks like an obvious thing to do but I feel like I'm running out of inspiration and could totally use a hand!
PS: Congrats if you made it to the end!
Haha lol. Kura seems to just start a gatttool process, send commands in text, and parse the output as its interface...
Here is where it is stated, using the address as parameter: https://github.com/eclipse/kura/blob/0339ac787f90debdfc270c1dee0c16de16ea6f7e/kura/org.eclipse.kura.linux.bluetooth/src/main/java/org/eclipse/kura/linux/bluetooth/util/BluetoothUtil.java#L319. Unfortunately the Kura developers seem to have missed that there is something called Random Address in the BLE standard and I don't see how that could be worked around using the current API.
Okay so for those who find themselves in my position in the future, I just received an answer from the Eurotech support team.
Dear Mr. Carneiro,
[...]
Regarding the random BD_ADDR, this is a configuration of the BLE device.
So, your BLE device is advertising an address of type random, not public, and you should specify the address type on the connection string, as you already did.
Unfortunately, current Kura Bluetooth API doesn't provide a way to specify the type of address into the connection string. We are developing a new set of APIs for BLE that will be available on preview on the next Kura/ESF release, but the Reliagate 10-05 will not support these yet.
I am writing a phoneGap plugin to allow multitouch on android devices (hoping to get this included in phonegap/callback eventually)
Event delegation is taking ~200ms using the plugin success callback and ~50ms with the WebView.loadUrl('javascript:somecodehere()') call
Unfortunately loadUrl has the side-effect of flickering the soft keyboard which isn't acceptable for a general solution.
Phonegap's Plugin.success uses an internal web server and an XmlHttpRequest object to send data, this method is way too slow.
Is there any 3rd method of sending javascript to the web browser? (or even sending a poke to the javascript engine to cause an event to happen, so that event could check a custom jsInterface object)
Take a look at addJavascriptInterface in the WebView class. It sounds more like what you are looking for.
In you plugin try calling:
this.ctx.sendJavascript(statement);
Not quite as fast as loadUrl but it may be a bit faster than returning a PluginResult.
You could roll your own stripped down message queue with a java object that is basically an arraylist and an accessor, then use addJavascriptInterface to bind it into the javascript context and inject a javascript polling loop that uses setTimeout to call the accessor method of your queue. Whenever you have javascript to execute, just add it to your arraylist. I'm not sure how it would perform, but perhaps it's worth a try?
class JSQueue {
private ArrayList<String> messages;
public String getMessage() {
String message = "";
if(messages.size() >0) {
message = messages.remove(0);
}
return message;
}
public void addMessage(String message) {
messages.add(message);
}
}
JSQueue jsq = new JSQueue();
dc.appMobiCanvas.hiddenView.addJavascriptInterface(jsq, "jsq");
dc.appMobiCanvas.hiddenView.loadUrl("javascript:(function checkJSQ(){eval(jsq.getMessage());setTimeout(checkJSQ, 50);}})();");
//add messages via jsq.addMessage();
It seems we have developed something similar
https://github.com/Philzen/webview-multitouch-polyfill
However, i have never experienced the issue you're describing before, but maybe you would like to test on your device or maybe contribute your expertise to the project. It has already been suggested on the Cordova (Phonegap) Roadmap, so we'll happy about every user and/or contributor to help this cause!
I'm trying to use vlcj to play live internet radio stations in a project. I've played around with some sample programs for a few hours, but I cannot get either the sample programs or programs that I've played around with to play the stream from the URL.
An example of a URL I'm trying to play is: http://network.absoluteradio.co.uk/core/audio/wmp/live.asx?service=vr
Is there anything special I have to do in order to get vlcj to play this stream? I couldn't find anything to help in the API. (Assuming it can because it can be played through the VLC media player!)
Thanks a lot
Ok, the MRL you have provided us http://network.absoluteradio.co.uk/core/audio/wmp/live.asx?service=vr is a MMS server that may pull a ASX (XML) metafile which may contain at least one sub-item.
http://all-streaming-media.com/faq/streaming-media/Metafiles-ASX-Advanced-Stream-Redirector.htm
To be able to play this type of streaming media and go through each sub-item, you need to do the following code snippet:
VideoPanel.getMediaPlayer().setRepeat(true);
VideoPanel.getMediaPlayer().setPlaySubItems(true);
VideoPanel.getMediaPlayer().prepareMedia(media, options);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(String s: VideoPanel.getMediaPlayer().subItems()) System.out.println(s);
VideoPanel.getMediaPlayer().play();
For the example MRL above, it will list down all sub-items as follows:
http://wms.absoluteradio.co.uk/g1/absoluteradio.co.uk/prerolls/ar_account_1310455302_hi.wma
mms://wms.absoluteradio.co.uk/absoluteradio.co.uk/vr_lo?u=
http://wms.absoluteradio.co.uk/absoluteradio.co.uk/vr_lo?u=
mmsu://wms.absoluteradio.co.uk/absoluteradio.co.uk/vr_lo?u=
mmst://wms.absoluteradio.co.uk/absoluteradio.co.uk/vr_lo?u=
mms://wms.absoluteradio.co.uk/absoluteradio.co.uk/prerolls/problems_lo.wma
To stop playing all of them, set the following code snippet:
VideoPanel.getMediaPlayer().setRepeat(false);
VideoPanel.getMediaPlayer().setPlaySubItems(false);
VideoPanel.getMediaPlayer().stop();
For a better explanation, refer to: http://code.google.com/p/vlcj/wiki/HowToHandleYouTubeMedia
You cannot use the http to play such link directly. You will ve to use the port number of the radio station router. this is because if i want to receive my home live video streaming from the internet at my workplace, i type the following on url: http://my dns server ip address:8080 The 8080 is the port number I opened on my router.