I'm developing phonegap app and right now I'm trying to write a plugin to convert .amr files to .mp3 files. I'm using JAVE to do this conversion and while it's working on desktop it fails on android with this exception:
java.io.IOException: Error running exec().
Command: [/data/data/<my_package>/cache/jave-1/ffmpeg, -i, /sdcard/<my_filename>.amr, -vn, -acodec, libmp3lame, -f, mp3, -y, /sdcard/<my_filename>.mp3]
Working Directory: null Enviroment: null
I'm trying to do conversion like this:
private void convert(String input_file, CallbackContext callbackContext){
File input = new File(input_file);
File output = new File(input_file.replace(".amr", ".mp3"));
Encoder encoder = new Encoder();
EncodingAttributes encodingAttributes = new EncodingAttributes();
AudioAttributes audioAttributes = new AudioAttributes();
audioAttributes.setCodec("libmp3lame");
encodingAttributes.setAudioAttributes(audioAttributes);
encodingAttributes.setFormat("mp3");
try{
encoder.encode(input, output, encodingAttributes);
input.delete();
callbackContext.success("finished");
}
catch(Exception e){
callbackContext.error(e.getMessage());
}
}
I found this answer and I understand why error happens but the answer doesn't provide any solution. Is there a way to get this working in Phonegap project? Do I need to package ffmpeg library together with plugin and copy it to correct folder when app invokes the plugin?
/data/data/<my_package>/cache/jave-1
Stucked with same problem. For now i found that there is problem with file ffmpeg permissions. JAVE trying to set them, but for some reason it not working.
So i set this permission by myself like this:
Process process = null;
DataOutputStream dataOutputStream = null;
try {
process = Runtime.getRuntime().exec("su");
dataOutputStream = new DataOutputStream(process.getOutputStream());
dataOutputStream.writeBytes("chmod 0755 __AppCachePath__/jave-1/ffmpeg\n");
dataOutputStream.writeBytes("exit\n");
dataOutputStream.flush();
process.waitFor();
} catch (Exception e) {
} finally {
try {
if (dataOutputStream != null) {
dataOutputStream.close();
}
process.destroy();
} catch (Exception e) {
}
}
After this File permission problem goes away.
Related
My device has been rooted and now i want to run an .sh file from my android application. I tried with following code but it did't provide the intended output:
Process process = Runtime.getRuntime().exec("sh /data/local/tmp/xyz.sh");
If i run .sh file from adb it is working fine for me.
Try following code.
try{
Process root = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(root.getOutputStream());
os.writeBytes("sh /system/bin/xyz.sh \n");
os.flush();
}
catch (IOException e) {
e.printStackTrace();
}
catch (SecurityException se){
se.printStackTrace();
}
This snippet worked for me,I hope this may help you.
Process process = Runtime.getRuntime().exec("sh /data/local/tmp/xyz.sh");
Scanner stdout = new Scanner(process.getInputStream());
while (stdout.hasNextLine()) {
Log.i("stdout", stdout.nextLine());
}
stdout.close();
Scanner stderr = new Scanner(process.getErrorStream());
while (stderr.hasNextLine()) {
Log.e("stderr", stderr.nextLine());
}
stderr.close();
I'm working on an application which supposed to run on devices from API 8 to latest.
Actually I'm dealing with Mediaplayer. the code is in a fragment and is simply:
MediaPlayer mediaPlayer = null;
if (mediaPlayer = MediaPlayer.create(getActivity(), myAudioFileUri) != null) {
. . .
}
This code perfectly works on Android 4.4.2, MediaPlayer.create() returns a valid value and I can use Mediaplayer without problem.
Unfortunately, MediaPlayer.create() returns null on Android 2.3.7.
this is my problem and I didn't find on Internet a reason why it could cause problem this Android version neither a difference in the way to use it.
Both tests have benn done on GenyMotion emulator as I don't have such an old Android device.
Edit:
So I verified using the shell adb that the problem really comes from mp3 file permissions if I "chmod 777 myfile.mp3", I can succesfully read it.
My problem now is to know how to change permissions on Android 2.3
The code used to download the file from my remote server to copy it locally is the next one:
private Uri downloadFileFromURL(URL url, String fileName) {
try {
URLConnection conn = url.openConnection();
HttpURLConnection httpConnection = conn instanceof HttpURLConnection ? (HttpURLConnection ) conn : null;
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK){
int len, length = 0;
byte[] buf = new byte[8192];
InputStream is = httpConnection.getInputStream();
File file = new File(getActivity().getApplicationContext().getFilesDir().getParentFile().getPath(), fileName);
OutputStream os = new FileOutputStream(file);
try {
while((len = is.read(buf, 0, buf.length)) > 0) {
os.write(buf, 0, len);
length += len;
}
os.flush();
}
finally {
is.close();
os.close();
}
String chmodString = "chmod 777 " + getActivity().getApplicationContext().getFilesDir().getParentFile().getPath() +"/" + fileName;
Process sh = Runtime.getRuntime().exec("su", null, new File("/system/bin/"));
OutputStream osChgPerms = sh.getOutputStream();
osChgPerms.write((chmodString).getBytes("ASCII"));
osChgPerms.flush();
osChgPerms.close();
try {
sh.waitFor();
} catch (InterruptedException e) {
Log.d("2ndGuide", "InterruptedException." + e);
}
return Uri.fromFile(file);
}
}
catch(IOException e)
{
Log.d("2ndGuide", "IO Exception." + e);
}
return null;
}
But osChgPerms.write((chmodString).getBytes("ASCII")); generates an IOException: broken pipe.
I suppose I didn't understand how to execute the command.
What's wrong?
Regards,
I can point you 2 possible reasons behind that, not sure whether they can solve your issue.
Android can only allocate a certain amount of MediaPlayer objects, you need to release any MediaPlayer object by using mediaPlayer.release().
Android supports only 8- and 16-bit linear PCM, so check you audio
file. More: Supported Media Formats
So in fact the problem clearly comes from the fact that the media files must be readable for everybody to be readable by the media player.
This behaviour only occurs on pre HONEYCOMB devices.
I want to store 8 integers into a .csv file(the filename will be taken as an input from a EditText) and retrieve them when I want to.
To get the filename you can use this:
EditText fileNameEdit= (EditText) getActivity().findViewById(R.id.fileName);
String fileName = fileNameEdit.getText().toString();
Then write the file on disk:
try {
String content = "Separe here integers by semi-colon";
File file = new File(fileName +".csv");
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
To read the file:
BufferedReader br = null;
try {
String sCurrentLine;
br = new BufferedReader(new FileReader(fileName+".csv"));
while ((sCurrentLine = br.readLine()) != null) {
System.out.println(sCurrentLine);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
Then to have the Integers you can use split function:
String[] intArray = sCurrentLine.split(";");
Opencsv doesn't work on Android due to JDK issue.
If you see simular to the following:
05-04 16:13:31.821 25829-25829/? E/AndroidRuntime: FATAL EXCEPTION:
main Process: com.example.pk.opencsvpoc, PID: 25829
java.lang.NoClassDefFoundError: Failed resolution of:
Ljava/beans/Introspector;
It is because Android only ported over a subset of java.beans into its
version of java. You can see a list of what is support at
https://developer.android.com/reference/java/beans/package-summary
There are plans to switch over to reflection in opencsv 5.0 but I
doubt it will remove all our dependencies on java.beans. For now the
best suggestion for opencsv is to steer clear of the com.opencsv.bean
classes until Android fully supports java.beans or we are successful
in removing java.beans.
Another possibility is to try another csv library. I checked apache
commons csv and super-csv and apache does not convert to beans but
super-csv does using only reflection.
Source: https://sourceforge.net/p/opencsv/wiki/FAQ/#getting-noclassdeffounderror-when-using-android
CSV is normal text file, where values are divided by character ";" so, you can write it using BufferedWriter for example.
BufferedWriter
I have successfully compiled ffmpeg for android and have ported it.
I placed
libffmpeg.so in /system/lib directory
ffmpeg executable in /system/bin and /system/xbin directory (i was not sure where to place it). i directly copied ffmpeg executable from source directory (Not sure whether it's a correct way)
Now i am executing commands from android with following code !!
imports *
public class LatestActivity extends Activity {
private Process process;
String command,text;
static {
System.loadLibrary("ffmpeg");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_latest);
//Execute Command !!
try {
Execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void Execute() throws IOException, InterruptedException{
try {
File dir=new File("/system/bin");
String[] cmd= {"ffmpeg","-codecs"};
process=Runtime.getRuntime().exec(cmd,null,dir);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d("Process IOException starts:",e.getMessage());
e.printStackTrace();
Log.d("System Manual exit !!",e.getMessage());
System.exit(MODE_PRIVATE);
}
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()),16384);
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
// read the output from the command
Log.d("Application output: ","Output if any !");
while ((text = stdInput.readLine()) != null) {
Log.d("Output: ",text); //$NON-NLS-1$
}
text="";
// read any errors from the attempted command
Log.d("Application output: ","Errors if any !"); //$NON-NLS-1$
while ((text = stdError.readLine()) != null) {
Log.d("Error: ",text); //$NON-NLS-1$
}
stdInput.close();
stdError.close();
process.waitFor();
process.getOutputStream().close();
process.getInputStream().close();
process.getErrorStream().close();
destroyProcess(process);
//process.destroy();
}
private static void destroyProcess(Process process) {
try {
if (process != null) {
// use exitValue() to determine if process is still running.
process.exitValue();
}
} catch (IllegalThreadStateException e) {
// process is still running, kill it.
process.destroy();
}
}
}
And Here is the logcat output:
09-05 15:29:13.287: D/dalvikvm(2670): No JNI_OnLoad found in /system/lib/libffmpeg.so 0x44e7e910, skipping init
09-05 15:29:29.117: I/global(2670): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.
09-05 15:29:29.117: D/Application output:(2670): Output if any !
09-05 15:29:29.117: D/Application output:(2670): Errors if any !
09-05 15:29:29.127: D/Error:(2670): /system/bin/ffmpeg: 1: Syntax error: "(" unexpected
m neither getting any errors nor output of command. At the end it shows syntax error. I want to know what kind of syntax error it is. how to tackle it?
m i doing something wrong?
This Error occurs if the ffmpeg file does not compiled for your cpu architechture.
Your commands might be right but you need to find correct ffmpeg file.
FIXED
#Gaganpreet Singh
You are right after so much research on this, I have got to know that CPU Chip-set matters too, FFMPEG commands doesn't support INTEL ATOM processor.
Asus Memo Pad 7 using INTEL ATOM cpu chip-set and when trying running ffmpeg command on it, it crashes and throw error "SYNTAX ERROR"
My commands working perfectly on all the devices except the device using INTEL ATOM chipset.
Please review this and this link if it will be helpful for you.
If anyone finds a solution. Please share with us.
Finally Fixed this issue by creating ffmpeg lib for x64 & armv7 using NDK. And used this Library in my Andriod project. Now I have 2 lib and using this lib for different Android CPU ARCH.
Please check this link too. Very helpful.
UPDATE There are a number of other posts asking how to get a Screenshot in android but none seemed to have a full answer of how to do so. Originally I posted this as a question due to a particular issue I was running into while attempting to open a stream to the Frame Buffer. Now I've swapped over to dumping the Frame Buffer to a file so I've updated my post to show how I got there. For reference (and acknowledgement), I found the command to send the FrameBuffer to a file from this post (unfortunately he didn't provide how he got to that point). I'm just missing how to turn the raw data I pulled from the Frame Buffer into an actual image file.
My intention was to take a full dump of the actual screen on an Android Device. The only way I could find to do so without using the adb bridge was to directly access the Frame Buffer of the system. Obviously this approach will require root privileges on the device and for the app running it! Fortunately for my purposes I have control over how the Device is set up and having the device rooted with root privileges provided to my application is feasible. My testing is currently being done on an old Droid running 2.2.3.
I found my first hints of how to approach it from https://stackoverflow.com/a/6970338/1446554. After a bit more research I found another article that describes how to properly run shell commands as root. They were using it to execute a reboot, I use it to send the current frame buffer to an actual file. My current testing has only gotten as far as doing this via ADB and in a basic Activity (each being provided root). I will be doing further testing from a Service running in the background, updates to come! Here is my entire test activity that can export the current screen to a file:
public class ScreenshotterActivity extends Activity {
public static final String TAG = "ScreenShotter";
private Button _SSButton;
private PullScreenAsyncTask _Puller;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_SSButton = (Button)findViewById(R.id.main_screenshotButton);
_SSButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (_Puller != null)
return;
//TODO: Verify that external storage is available! Could always use internal instead...
_Puller = new PullScreenAsyncTask();
_Puller.execute((Void[])null);
}
});
}
private void runSuShellCommand(String cmd) {
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
StringBuilder sbstdOut = new StringBuilder();
StringBuilder sbstdErr = new StringBuilder();
try { // Run Script
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(cmd);
osw.flush();
osw.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
if (proc != null)
proc.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
sbstdOut.append(readBufferedReader(new InputStreamReader(proc.getInputStream())));
sbstdErr.append(readBufferedReader(new InputStreamReader(proc.getErrorStream())));
}
private String readBufferedReader(InputStreamReader input) {
BufferedReader reader = new BufferedReader(input);
StringBuilder found = new StringBuilder();
String currLine = null;
String sep = System.getProperty("line.separator");
try {
// Read it all in, line by line.
while ((currLine = reader.readLine()) != null) {
found.append(currLine);
found.append(sep);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
class PullScreenAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
File ssDir = new File(Environment.getExternalStorageDirectory(), "/screenshots");
if (ssDir.exists() == false) {
Log.i(TAG, "Screenshot directory doesn't already exist, creating...");
if (ssDir.mkdirs() == false) {
//TODO: We're kinda screwed... what can be done?
Log.w(TAG, "Failed to create directory structure necessary to work with screenshots!");
return null;
}
}
File ss = new File(ssDir, "ss.raw");
if (ss.exists() == true) {
ss.delete();
Log.i(TAG, "Deleted old Screenshot file.");
}
String cmd = "/system/bin/cat /dev/graphics/fb0 > "+ ss.getAbsolutePath();
runSuShellCommand(cmd);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
_Puller = null;
}
}
}
This also requires adding the android.permission.WRITE_EXTERNAL_STORAGE permission to the Manifest. As suggested in this post. Otherwise it runs, doesn't complain, doesn't create the directories nor the file.
Originally I couldn't get usable data from the Frame Buffer due to not understanding how to properly run shell commands. Now that I've swapped to using the streams for executing commands I can use '>' to send the Frame Buffer's current data to an actual file...
Programmatically you can run "adb shell /system/bin/screencap -p /sdcard/img.png" as below :
Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
An easy solution for ICS devices is to use the following from the command line
adb shell /system/bin/screencap -p /sdcard/screenshot.png
adb pull /sdcard/screenshot.png screenshot.png
This'll save the screenshot.png file in the current directory.
Tested on a Samsung Galaxy SII running 4.0.3.
That would be different for different phones. It depends on the underlying graphics format of your device. You can poll what the graphics format is using system calls. If you are only going to run this on devices that you know the graphics format of you can write a converter that turns it into a known format.
You can have a look at the following project: http://code.google.com/p/android-fb2png/
If you look at the source code for fb2png.c you can see that they poll FBIOGET_VSCREENINFO which contains info about how the device stores the screen image in memory. Once you know that, you should be able to convert it into a format you can use.
I hope this helps.