How to play back a byte stream in libVLC for Android - android

I would like to play back a byte stream with the media player in libVLC for Android. But I don't find any Interface or Class where I could "inject" a byte stream. Only chance I have for play back is providing a file descriptor, a path to a file, or an URI.
Android's native media player provides the interface setDataSource(MediaDataSource dataSource) where a byte stream can be injected by extending the class MediaDataSource. Do I have similar possibility in libVLC for Android?

The libVLC API you are looking for is libvlc_media_new_callbacks.
However, it seems it is not currently exposed to Java to be used with a Java stream parameter. This would need to be implemented by you in the libvlcjni bindings, I believe.
You could get inspiration from this existing code making use of that API
void
Java_org_videolan_libvlc_Media_nativeNewFromFdWithOffsetLength(
JNIEnv *env, jobject thiz, jobject libVlc, jobject jfd, jlong offset, jlong length)
{
vlcjni_object *p_obj;
int fd = FDObject_getInt(env, jfd);
if (fd == -1)
return;
p_obj = VLCJniObject_newFromJavaLibVlc(env, thiz, libVlc);
if (!p_obj)
return;
p_obj->u.p_m =
libvlc_media_new_callbacks(p_obj->p_libvlc,
media_cb_open,
media_cb_read,
media_cb_seek,
media_cb_close,
p_obj);
if (Media_nativeNewCommon(env, thiz, p_obj) == 0)
{
vlcjni_object_sys *p_sys = p_obj->p_sys;
p_sys->media_cb.fd = fd;
p_sys->media_cb.offset = offset;
p_sys->media_cb.length = length >= 0 ? length : UINT64_MAX;
}
}
https://github.com/videolan/vlc-android/blob/f05db3f9b51e64061ff73c794e6a7bfb44f34f65/libvlc/jni/libvlcjni-media.c#L284-L313
libvlcsharp has this implemented, including for Android platforms, but it's .NET.

Related

Gstreamer, how to play udp stream using C on android?

I'm trying to play udp stream using Gstreamer on android. (I've used this tutorial from the official Gstreamer website). I can play rtsp and https streams, but when I pass udp uri (like this: udp://#238.0.0.1:1234) nothing happens (there is a black screen). In the log I have: Error received from element uridecodebin1: Your GStreamer installation is missing a plug-in. I've found some documentation here about installing plugins, but I don't understand how to do that.
Here is the piece of the code I use:
data->context = g_main_context_new ();
g_main_context_push_thread_default (data->context);
/* Build pipeline */
data->pipeline = gst_parse_launch ("playbin", &error);
if (error) {
gchar *message =
g_strdup_printf ("Unable to build pipeline: %s", error->message);
g_clear_error (&error);
set_ui_message (message, data);
g_free (message);
return NULL;
}
and the 2nd one:
/* Set playbin2's URI */
void gst_native_set_uri (JNIEnv * env, jobject thiz, jstring uri)
{
CustomData *data = GET_CUSTOM_DATA (env, thiz, custom_data_field_id);
if (!data || !data->pipeline)
return;
const gchar *char_uri = (*env)->GetStringUTFChars (env, uri, NULL);
GST_DEBUG ("Setting URI to %s", char_uri);
if (data->target_state >= GST_STATE_READY)
gst_element_set_state (data->pipeline, GST_STATE_READY);
g_object_set (data->pipeline, "uri", char_uri, NULL);
(*env)->ReleaseStringUTFChars (env, uri, char_uri);
data->duration = GST_CLOCK_TIME_NONE;
data->is_live |=
(gst_element_set_state (data->pipeline,
data->target_state) == GST_STATE_CHANGE_NO_PREROLL);
}
Full code is here
This is the first thing I'm doing in C and JNI, so I would be grateful for working code snippet.
Ok, I've accidentaly found the solution. I just modified my Android.mk file by adding $(GSTREAMER_PLUGINS_CODECS_RESTRICTED) into GSTREAMER_PLUGINS line. Now udp streams works fine!

Send Array of Strings to Native Code in Android

I call a function in C++ from java. In java I have an array of Strings that I want to use in my C++-function.
I have in C++:
std::string names[6]; // Global variable
extern "C"
JNIEXPORT void JNICALL
Java_com_erikbylow_mycamera3_JNIUtils_updateStandingBoard(JNIEnv *env, jobject type, std::string *names, jint nbrElements){
memcpy(standingText, names, 6* sizeof(std::string));
nbrStandText = nbrElements;
}
In `Java`:
public static void updateStanding( String resultArray[]){
updateStandingBoard(resultArray, resultArray.length);
}
What is the simplest way of achieving what I want? When I try this and different variants it either crashes or yields nonsense data.
JNI is a primarily a C API, it doesn't know anything about std::string as you can validate by calling javah on the Java source file contained the native methods declaration.
Also Java isn't C, there is no need to pass the array size as additional parameter.
So your native void updateStandingBoard(String[] result, int size) should actually be native void updateStandingBoard(String[] result)
With this in mind, the JNI code should be
std::vector<std::string> names; // much safer or use std::array as alternative
extern "C"
JNIEXPORT void JNICALL
Java_com_erikbylow_mycamera3_JNIUtils_updateStandingBoard(JNIEnv *env, jobject type, jobjectArray names) {
jint nbrElements = env->GetArrayLength(names);
// now copy the strings into C++ world
for (int i = 0; i < nbrElements ; i++) {
// access the current string element
jobject elem = env->GetObjectArrayElement(names, i);
jsize length = env->GetStringLength(elem);
// pin it to avoid GC moving it around during the copy
const jchar *str = env->GetStringChars(elem, nullptr);
names.push_back(std::string(str, length));
// make it available again to the VM
env->ReleaseStringChars(elem, str);
}
}
This was just for the basic strings, if you are interested in UTF strings, then you should make use of std::wstring and the UTF variants of the above JNI functions.

How to read/write file slacks in Android with JNI?

I am building a forensic tool, that shall read and write from file slacks. At the moment I use JNI to call the C functions read() and write() to write a buffer to the FAT SD card (also EXT4 internal memory would be nice). I use those because you can pass the length to read/write thus ignoring EOF.
I already tried writing by using a standard write and then truncate it in order to write in the file slack, which works on ubuntu 14.04 but not on Android (API 21).
Reading more from a file than the actuall file size does not reflect the flie slack on the SD-card.
There are tools e.g. "bmap" or "slacker.exe" (for NTFS) that manage to access file slacks. I am in need of a way to ignore EOF or handle it myself. I would prefere not to change existing file system drivers.
I appreciate any suggestions.
here is some sample code (that does not work yet):
jstring
Java_com_example_hellojni_HelloJni_write(JNIEnv *env, jobject thiz, jstring path)
{
char *cpath = (*env)->GetStringUTFChars(env, path, NULL);
int raw_file_descriptor = open(cpath,O_WRONLY,0);
lseek(raw_file_descriptor,0,SEEK_END);
char block_buffer [4096] = "hidden";
int buffer_length = 6;
int wret = write(raw_file_descriptor,block_buffer,buffer_length); // increases file size and moves EOF - I don't want that
LOGD(" char written: %d", wret);
free(cpath);
return (*env)->NewStringUTF(env, "write ok ");
}
jbyteArray
Java_com_example_hellojni_HelloJni_read2(JNIEnv *env, jobject thiz, jstring path) {
char *cpath = (*env)->GetStringUTFChars(env, path, NULL);
LOGD("open %s with ", cpath);
int raw_file_descriptor = open(cpath,O_RDONLY,0);
char buffer [4096];
int readretval = read(raw_file_descriptor, buffer, 50); // stops at EOF - I want it to continue reading all 50 bytes from the SD-card - This gives me the file content until EOF and then I get some random characters from the uninitialized buffer.
LOGD("read (%d) buffer with length %d: %s", readretval, sizeof(buffer), buffer);
int i; // Debug code
for (i=0; i < 49; ++i) {
LOGD("%c",buffer[i]);
}
close(raw_file_descriptor);
free(cpath);
return NULL;
}
Apparently this way is impossible. But with root it is possible to write file slack via mounting a loop back device. Still, ignoring EOF is not possible without changing the driver or implementing your own kernel module.

Android Using tinyalsa in Java code

I built tinyalsa lib using the sources from tinyalsa-ndk and wrapped it with JNI calls and I'm trying to use it in my code.
I used Swig to generate Java wrappers (and modified output to comply with my package)
My native method declaration is:
public final static native long mixer_open(long jarg);
My JNI wrapper call is inside a wrapper class TinyAlsa.java under the root pacakge (for the example I'll use com.Example.App):
public static SWIGTYPE_p_mixer mixer_open(long card)
{
long cPtr = TinyAlsaJNI.mixer_open(card);
return (cPtr == 0) ? null : new SWIGTYPE_p_mixer(cPtr, false);
}
and my wrapper c method is:
SWIGEXPORT jlong JNICALL Java_com_Example_App_Native_TinyAlsaJNI_mixer_1open(JNIEnv *jenv, jclass jcls, jlong jarg1)
{
jlong jresult = 0 ;
unsigned int arg1 ;
struct mixer *result = 0 ;
(void)jenv;
(void)jcls;
arg1 = (unsigned int)jarg1;
result = (struct mixer *)mixer_open(arg1);
*(struct mixer **)&jresult = result;
return jresult;
}
The tinalsa library is loaded OK without exceptions but calls such as mixer_open(0) returns null pointers.
However If I execute the compiled tinymix mixer is open and mixer controls are listed as should.
Am I missing something? How can I make it work from my code?

JNI - transfer from jstring to byte, from byte to string issue

I have a problem with converting in JNI.
In C++ I'm creating some cipher using AES (Library CryptoPP). I'm converting result to string and returning it. This is how the code getting the string looks like:
JNIEXPORT jbyteArray JNICALL Java_com_example_androidake_MutualAuthenticateChip_prepareEncryptionCPP
(JNIEnv *env, jobject thisObj, jboolean hmm, jboolean jinit) {
string encryption= mac->EncryptCertKey();
jbyteArray returns = env->NewByteArray(encryption.size());
env->SetByteArrayRegion(returns, 0, encryption.length(), (jbyte*) encryption.c_str());
return returns;
};
Above string is converting to jbyteArray which is returned. First I wanted just return string using
env->NewStringUTF(encryption.c_str());
but the application has been crashing. I think it is caused by content of variable 'encryption'. I'm using env->NewStringUTF(encryption.c_str()); in other functions, where returned string is for example just a number or something like that.
Then in Java I'm doing conversion from byte to string:
byte[] cipher = mac_A.prepareEncryptionCPP(true, true);
string cipher_str = new String(cipher);
And I'm putting that string again to the C++ object and compare old cipher with the cipher which is sent from Java:
//Java
boolean result = mac_A.compareEncryption(true, cipher);
//JNI
JNIEXPORT jboolean JNICALL Java_com_example_androidake_MutualAuthenticateChip_compareEncryption
(JNIEnv * env, jobject thisObj, jboolean jinit, jstring cipher){
bool init = jinit;
bool result;
jsize length = env->GetStringUTFLength(cipher);
const char *inCStr_ek = env->GetStringUTFChars(cipher, 0);
string s(inCStr_ek, length);
result = mac->CompareCipher(s);
env->ReleaseStringUTFChars(cipher, inCStr_ek);
return result;
};
Comparing in C++ :
bool MyClass::CompareCipher(std::string cipher_2){
if(cipher == cipher_2){
return true;
}else{
return false;
}
}
And it always returns false. I do not know what I'm doing wrong. I've even sent this cipher from Java to C++ and take it back to Java and the strings are equals, but in C++ side are not.
on your java side code you have
byte[] cipher = mac_A.prepareEncryptionCPP(true, true);
boolean result = mac_A.compareEncryption(true, cipher);
compareEncryption jni function is defined with jstring , not jbytearray.
So from JNI side you are sending a byte array to java, and from java side you send back the same byte array to native side (but uses jstring in call), but then you are using env->GetStringUTFChars(cipher, 0) which converts that byte array into a modified UTF-8 string, so its technically not that same byte array anymore.
if you need strings do the conversions in java side, and just use with same plain byte arrays between jni and java. See this for string encoding issues in Android JNI.

Categories

Resources