Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

Sunday, November 20, 2016

Activity does not have the latest intent information put in the pending intent extras

It happens when the activity is resumed.

You need to:

1. In the intent:
    intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
  PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
        PendingIntent.FLAG_UPDATE_CURRENT);


  If you have more then one notification at a time, set the request code uniquely

  PendingIntent pendingIntent = PendingIntent.getActivity(this, uniqueIntForName, intent, PendingIntent.FLAG_UPDATE_CURRENT);

  
  This way you will have the correct extras for the specific notification when lunching the 
  Activity. 




2. In the Activity the pending intent is calling:

   @Override
   public void onNewIntent(Intent newIntent) {
    Log.i(P.Tag, "===onNewIntent called===");
    this.setIntent(newIntent);
   }

Friday, November 11, 2016

How to uninstall an app from wearable



Android wear connect via Bluetooth

adb forward tcp:4444 localabstract:/adb-hub
adb connect 127.0.0.1:4444


Uninstall a standalone app


adb -s 127.0.0.1:4444 uninstall com.netcompss.fl_groups


If you want to uninstall a regular app, then just uninstall the phone app, and the wearable app will uninstall automaticly

Friday, October 28, 2016

OK Google beep sound fix

Google decided to remove the beep sound from the OK Google assistant.
Lots of users hate this decision, giving the Google app bad reviews, but Google will not fold.

Here is how to get the beep sound back in a few easy steps:

Setting, accessibility, switch access to on.

Here is a video that shows, the issue, and how to solve it:

https://youtu.be/NFws1vnKJ0M

Sunday, September 18, 2016

Simple Java Timer (Can be used in Android)

With the default fixed-period execution, each successive run of a task is scheduled relative to the start time of the previous run, so two runs are never fired closer together in time than the specified period. With fixed-rate execution, the start time of each successive run of a task is scheduled without regard for when the previous run took place. This may result in a series of bunched-up runs (one launched immediately after another) if delays prevent the timer from starting tasks on time.

// First run after 2000ms, next run after 1000ms
public static void testTimer() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
int i = 0;
@Override
public void run() {
Random rand = new Random();
int randInt5000 = rand.nextInt(5000);
System.out.println("working : " + randInt5000);
try {
Thread.sleep(randInt5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
i++;
if (i == 5) timer.cancel();
}

}, 2000, 1000);

}

Tuesday, May 31, 2016

Google play Error 505

This is a nasty one,
It happens when trying to install an app for some unknown reason,
I heard of some users that did factory reset to solve this.

Basically all you have to do is to use adb to uninstall the app, and you will be able to install again the app from Google Play.

Install Google Android SDK.
Open Command Console
run:
adb uninstall <the app full package name>

Wednesday, March 9, 2016

Custom Dialog that access its own UI elements

public boolean onContextItemSelected(MenuItem item) {
    switch (item.getItemId()) {
case RENAME_ID:

final MenuItem itemF = item;
AlertDialog.Builder renameDialogBuilder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_group_rename, null);
renameDialogBuilder.setView(dialogView);
final View dialogViewF = dialogView;

renameDialogBuilder.setTitle(getString(R.string.rename_group)).

        setPositiveButton(getString(R.string.OK), new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                Log.d(P.Tag, "OK clicked");

                EditText groupName = (EditText)dialogViewF.findViewById(R.id.group_rename);
                String groupNameStr = groupName.getText().toString();
                if (groupNameStr.length() < 5) {
                    Toast.makeText(getActivity().getApplicationContext(), getString(R.string.groupname_invalid), Toast.LENGTH_LONG).show();
                    return;
                }


                AdapterView.AdapterContextMenuInfo info= (AdapterView.AdapterContextMenuInfo)itemF.getMenuInfo();
                Log.d(P.TAG, "Renaming ID: " + info.id);
                int position = (new Long(info.id)).intValue();
                try {
                    String groupId = ((JSONObject)jsonGroupArray.get(position)).get("id").toString();
                    String adminId = ((JSONObject)jsonGroupArray.get(position)).get("admin_id").toString();
                    String userId = P.getUserId(getActivity().getApplicationContext());
                    if (userId.equals(adminId)) {
                        Log.d(P.TAG, "Renaming groupId: " + groupId);
                        new HttpCallAsyncTask(getActivity()).execute("oper", "rename_group", "user_id", userId, "group_id", groupId, "group_name", groupNameStr);
                    }


                } catch (JSONException e) {
                    Log.e(P.TAG, "JSONException when trying to leave position: " + position );
                    Toast.makeText(getActivity().getApplicationContext(), getString(R.string.delete_failed), Toast.LENGTH_LONG).show();
                }


            }
        }).
        setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                Log.i(P.TAG, "cancel clicked, doing nothing");
            }
        });
AlertDialog alert  = renameDialogBuilder.create();
alert.show();

Tuesday, August 26, 2014

Use Android hidden and internal methods

Its possible to use android hidden and internal methods by using the device android.jar instead the ADT's
It will work because the device have a version of android.jar (framework.zip) that have access to this methods.

Steps are (version 4.4.4):

1. copy: C:\Program Files\Android\android-sdk\platforms\android-19 to C:\Program Files\Android\android-sdk\platforms\android-19-internals

2. Download open android.jar and replace the android.jar in the android-19-internals folder. I created this jar from nexus 5 device framework.zip with 4.4.4 OS using a utility that converts dex file to regular classes.

3. Edit build.prop, change ro.build.version.sdk=19 to ro.build.version.sdk=-19 and ro.build.version.release=4.4 to ro.build.version.release=4.4.extended

4. restart eclipse, you will now see the 4.4.extended which you can select for your projects.


* Note that its highly recommended to verify the hidden/internal methods exists before you make such a call, you can do a simple verification using reflaction, here is an example:

 private boolean isRequestPestitentInfoMethodExists() {
        java.lang.reflect.Method method;
        try {
            Class cls = Class.forName("android.net.wifi.p2p.WifiP2pManager");
            method = cls.getMethod("requestPersistentGroupInfo",  Class.forName("android.net.wifi.p2p.WifiP2pManager$Channel"), Class.forName("android.net.wifi.p2p.WifiP2pManager$PersistentGroupInfoListener"));
            Log.i(P.TAG, "isRequestPestitentInfo Method Exists");
            return true;
        } catch (ClassNotFoundException e) {
            Log.e(P.TAG, "ClassNotFoundException: " + e.getMessage());
            return false;
        } catch (NoSuchMethodException e) {
            Log.e(P.TAG, "NoSuchMethodException: " + e.getMessage());
            return false;
        }

    }

Sunday, August 10, 2014

CPU Hog process dictonary

https://play.google.com/store/apps/details?id=com.netcompss.cpu_hog.free&hl=en

         short name           ->  Full Name               ->  Related app    ->  recommendation

  • dboxed_process  -> sandboxed_process -> Chrome           -> Stop Chrome
  • kworker                -> kworker                    -> Kernel              -> Restart device
  • mediaserver         -> mediaserver             -> Android            -> clean gallery cache
  • surfaceflinger       -> surfaceflinger           -> Android            -> Restart device
  • earchbox:search  -> searchbox:search    -> Android            -> Restart device
  • d.process.media -> android.process.media -> clear download manager app cache and data.

Saturday, August 9, 2014

CPU Hog best practice

https://play.google.com/store/apps/details?id=com.netcompss.cpu_hog.free&hl=en



  • Check from time to time the Main screen for last known battery temperature, and Usage, and adjust your preferences for better hog discovery.
  • When you get a notification, click on the top icon
    first to see if the hog process is still draining your battery, if it is, click on it, and click on the stop, then re-check the top to verify its gone.

Tuesday, December 6, 2011

FFmpeg4Android




FFmpeg4Android is a way your application can run FFmpeg commands,  only Java, no need for C code, or NDK.

* Performance oriented. 
* Small Footprint
* Android 14 (and below) support.
* 64-bit full support.


Android Studio full demo (GIF Maker) with ffmpeg4android_lib (working with personal license)

Download version 6.1

You can download GifMaker from Google play:

Add ffmpeg4android support to your project:
1. Open the project using Android developer studio.
2. Copy ffmpeg4android_lib to the project root (you can use the code from GifMaker).
3. Add: include ':ffmpeg4android_lib' to the settings.gradle.
4. Add the line: api project(":ffmpeg4android_lib") to the dependencies in the app build.gradle
in older gradle versions use: 
implementation (":ffmpeg4android_lib").
5. Add: 
ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
        }
   To defaultConfig in app build.gradle
6. Copy ffmpeg4android_lib/jniLibs/arm64-v8a content to your app assets folder
   (create on if you don't have), unders app/src/main
7. Add the lines: 
GeneralUtils.setup(this)
        Log.i(Prefs.TAG, "FFmpeg4Android setup done")
   To your main activity make sure the: "FFmpeg4Android setup done" appears in your app log.


Commands Examples

This commands verified to work with FFmpeg4Android:

This are only some basic examples, a lot more is possible...


Video Compress:

// simple regular command
ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -s 160x120 -r 25 -vcodec mpeg4 -b 150k -ab 48000 -ac 2 -ar 22050 /sdcard/videokit/out.mp4

 

// compress with h264 (to support chrome)

// Note that you will need to use the Extras (see below) distribution to use this command.

ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -vcodec libx264 -preset ultrafast -crf 24 -acodec aac -ar 44100 -ac 2 -b:a 96k -s 320x240 -aspect 4:3 /sdcard/videokit/out3.mp4


// As complex command, don't forget to use setCommandComplex(complexCommand)

// Use this format to support files that contains spaces and special characters

String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/video kit/in.mp4","-strict","experimental","-s", "160x120","-r","25", "-vcodec", "mpeg4", "-b", "150k", "-ab","48000", "-ac", "2", "-ar", "22050", "/sdcard/video kit/out.mp4"};


// running compression command, while keeping metadata information (including rotation metadata):
ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -map_metadata 0:g -s 160x120 -r 25 -vcodec mpeg4 -b 150k -ab 48000 -ac 2 -ar 22050 /sdcard/videokit/out1.mp4


The parameters that control the quality are the -s (resolution, currently set on 160x120) and the -b (the bitrate, currently set on 150k).
Increase them, e.g -s 480x320
And -b 900k
To improve quality (and get less compression).



Audio Compression

 

String commandStr = "ffmpeg -y -i /sdcard/vk2/in.wav -ar 44100 -ac 2 -ab 64k -f mp3 /sdcard/videokit/out.mp3";


Audio Trim (Crop)

String commandStr ={"ffmpeg","-y","-i","/storage/emulated/0/vk2/in.mp3","-strict","experimental","-acodec","copy","-ss","00:00:00","-t","00:00:03.000","/storage/emulated/0/videokit/out.mp3"};

 

Video Rotate (90 degrees cw):

ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -vf transpose=1 -s 160x120 -r 30 -aspect 4:3 -ab 48000 -ac 2 -ar 22050 -b 2097k /sdcard/video_output/out.mp4

 

Video Crop:

ffmpeg -y -i /sdcard/videokit/short.mp4 -strict experimental -vf crop=100:100:0:0 -s 320x240 -r 15 -aspect 3:4 -ab 12288 -vcodec mpeg4 -b 2097152 /sdcard/videokit/out.mp4

 

Extract Picture from Video:

ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -an -r 1/2 -ss 00:00:00.000 -t 00:00:03 /sdcard/videokit/filename%03d.jpg

 

Extract Sound from Video:

ffmpeg -y -i /sdcard/videokit/in.avi -strict experimental -acodec copy /sdcard/videokit/out.mp3

ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -vn -ar 44100 -ac 2 -ab 256k -f mp3 /sdcard/videokit/out.mp3

 

Re-encode Audio in Video:

ffmpeg -y -i /sdcard/in.mp4 -strict experimental -vcodec copy -acodec libmp3lame -ab 64k -ac 2 -b 1200000 -ar 22050 /sdcard/out.mp4


Change Video Resolution:

ffmpeg -y -i /sdcard/in.mp4 -strict experimental -vf transpose=3 -s 320x240 -r 15 -aspect 3:4 -ab 12288 -vcodec mpeg4 -b 2097152 -sample_fmt s16 /sdcard/out.mp4


Cut time segment from Video:

ffmpeg -ss 00:00:01.000 -y -i /sdcard/videokit/in.mp4 -strict experimental -t 00:00:02.000 -s 320x240 -r 15 -vcodec mpeg4 -b 2097152 -ab 48000 -ac 2 -b 2097152 -ar 22050 /sdcard/videokit/out.mp4


Transcode Audio:

ffmpeg -y -i /sdcard/videokit/big.wav /sdcard/videokit/small.mp3


WaterMark:

 //  test with watermark.png 128x128, add it to /sdcard/videokit/

String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/videokit/in.mp4","-strict","experimental", "-vf", "movie=/sdcard/videokit/watermark.png [watermark]; [in][watermark] overlay=main_w-overlay_w-10:10 [out]","-s", "320x240","-r", "30", "-b", "15496k", "-vcodec", "mpeg4","-ab", "48000", "-ac", "2", "-ar", "22050", "/sdcard/videokit/out.mp4"}; 


Streaming simple:

Stream from Android device to a PC

 

* note that all streaming examples will need to add internet permission to the Android project Manifest file ( <uses-permission android:name="android.permission.INTERNET" />  )

 
// use this command on ffmpeg4android ( 192.168.1.11 is the PC IP)
ffmpeg -i /sdcard/videokit/2.mpg -strict experimental -f mpegts udp://192.168.1.11:8090

// You can use any player that supports streaming, on the target machine, to play the stream, in this case we used ffplay

// (192.168.1.14 is the Android device IP)

ffplay -f mpegts -ast 1 -vst 0 -ar 48000 udp://192.168.1.14:8090 



Stream raw video from camera preview:

  

getting the raw stream from the camera preview:


Parameters parameters = camera.getParameters();
imageFormat = parameters.getPreviewFormat();
if (imageFormat == ImageFormat.NV21) {
                Camera.Size previewSize = parameters.getPreviewSize();
                frameWidth = previewSize.width;
                frameHeight = previewSize.height;
                Rect rect = new Rect(0, 0, frameWidth, frameHeight);
                YuvImage img = new YuvImage(data, ImageFormat.NV21, frameWidth, frameHeight, null);
                try {
                                outStream.write(data);
                                outStream.flush();
                }
}



Encode and stream using FFmpeg4Android: 

"ffmpeg -f rawvideo -pix_fmt nv21 -s 640x480 -r 15 -i " + Environment.getExternalStorageDirectory().getAbsolutePath().toString() + "/yuv.data rtmp://host/stream.flv"


Stream on one device, receive a steam on second device and save it:

on the first device:

ffmpeg -i /sdcard/one3.mp4 -f mpegts udp://192.168.0.107:8090


on the second device:

String[] complexCommand = {"ffmpeg","-y" ,"-i", "udp://192.168.0.108:8090","-strict","experimental","-crf", "30","-preset", "ultrafast", "-acodec", "aac", "-ar", "44100", "-ac", "2", "-b:a", "96k", "-vcodec", "libx264", "-r", "25", "-b:v", "500k", "-f", "flv", "/sdcard/videokit/t.flv"};

* this needs internet permission in the manifest. 

H264 encoding (Needs Extras):
ffmpeg -y -i /sdcard/Video/1.MTS -strict experimental -vcodec libx264 -preset ultrafast -crf 24 /sdcard/videokit/out.mp4

ffmpeg -y -i /sdcard/videokit/m.mkv -strict experimental -vcodec libx264 -preset ultrafast -crf 24 -sn /sdcard/videokit/m2.mkv

Subtitles:
ffmpeg -y -i /sdcard/videokit/m2.mkv -i /sdcard/videokit/in.srt -strict experimental -vcodec libx264 -preset ultrafast -crf 24 -scodec copy /sdcard/videokit/mo.mkv

ffmpeg -y -i /sdcard/videokit/m2.mkv -i /sdcard/videokit/in.srt -strict experimental -scodec copy /sdcard/videokit/outm3.mkv

Convert Audio file to m4a
ffmpeg -i /sdcard/videokit/in.mp3 /sdcard/videokit/out.m4a

Encode h264 video and aac audio in one command (Needs Extras)
ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -vcodec libx264 -crf 24 -acodec aac /sdcard/videokit/out.mkv


Vintage filter

commandStr = "ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -vf curves=vintage -s 640x480 -r 30 -aspect 4:3 -ab 48000 -ac 2 -ar 22050 -b 2097k -vcodec mpeg4 /sdcard/videokit/curve.mp4";

Black & White filter (Gray Scale):

commandStr = "ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -vf hue=s=0 -vcodec mpeg4 -b 2097152 -s 320x240 -r 30 /sdcard/videokit/out.mp4";


Sepia using colorchannelmixer

String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/videokit/sample.mp4","-strict", "experimental", "-filter_complex",
"[0:v]colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131[colorchannelmixed];[colorchannelmixed]eq=1.0:0:1.3:2.4:1.0:1.0:1.0:1.0[color_effect]",
 "-map", "[color_effect]","-map", "0:a", "-vcodec", "mpeg4","-b", "15496k", "-ab", "48000", "-ac", "2", "-ar", "22050","/sdcard/videokit/out.mp4"};

Create filter using Photoshop curves 

You can create some effects using Photoshop curves operation (Image, Adjustments, Curves (CNTL + M)), export the curves acv file, and apply it using this command:

String[]
complexCommand={"ffmpeg","-y","-i","/storage/emulated/0/vk2/in.mp4","-strict","experimental","-vf","curves=psfile=/storage/emulated/0/videokit/sepia.acv","-b","2097k","-vcodec","mpeg4","-ab","48000","-ac","2","-ar","22050","/storage/emulated/0/videokit/out.mp4"}

Fade in and out transition
String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/videokit/in.m4v","-acodec", "copy", "-vf", "fade=t=in:st=0:d=5, fade=t=out:st=20:d=5", "/sdcard/videokit/out.mp4"};


Join 2 files using of the same size using filter_complex
String[] complexCommand = {"ffmpeg","-y","-i", "/sdcard/videokit/in1.mp4", "-i", "/sdcard/videokit/in2.mp4", "-strict","experimental", "-filter_complex", "[0:0] [0:1] [1:0] [1:1] concat=n=2:v=1:a=1", "/sdcard/videokit/out.mp4"};



// concat videos with different codecs, and different sizes, different rate and different aspect ratio:

String[] complexCommand = {"ffmpeg","-y","-i","/storage/emulated/0/videokit/sample.mp4",
    "-i","/storage/emulated/0/videokit/in.mp4","-strict","experimental",
    "-filter_complex",
    "[0:v]scale=640x480,setsar=1:1[v0];[1:v]scale=640x480,setsar=1:1[v1];[v0][0:a][v1][1:a] concat=n=2:v=1:a=1",
    "-ab","48000","-ac","2","-ar","22050","-s","640x480","-r","30","-vcodec","mpeg4","-b","2097k","/storage/emulated/0/vk2_out/out.mp4"}



Create a video from pictures

// note that this commands are sensitive to the pictures size.
// all pictures should be with the same size, and correspond to -s particular video resolution.
// e.g hd video is: 1280x720, and this should be the pictures size 
commandStr = "ffmpeg -y -r 1/5 -i /sdcard/videokit/pic00%d.jpg /sdcard/videokit/out.mp4";


// with audio. (Works on all players) png also works, pictures size in this case should be 320x240
ffmpeg -y -r 1 -i /sdcard/videokit/pic00%d.jpg -i /sdcard/videokit/in.mp3 -strict experimental -ar 44100 -ac 2 -ab 256k -b 2097152 -ar 22050 -vcodec mpeg4 -b 2097152 -s 320x240 /sdcard/videokit/out.mp4


Advanced filtering
String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/videokit/in.mp4","-strict","experimental", "-vf", "crop=iw/2:ih:0:0,split[tmp],pad=2*iw[left]; [tmp]hflip[right]; [left][right] overlay=W/2", "-vb", "20M", "-r", "23.956", "/sdcard/videokit/out.mp4"};

Increase video and audio speed
String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/videokit/in.mp4","-strict","experimental", "-filter_complex", "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]","-map","[v]","-map","[a]", "-b", "2097k","-r","60", "-vcodec", "mpeg4", "/sdcard/videokit/out.mp4"};

Overlay 2 videos side by side
 
     String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/Movies/sample.mp4","-i", "/sdcard/Movies/sample2.mp4", "-strict","experimental",
                "-filter_complex",
                "[0:v:0]pad=iw*2:ih[bg];" +
                "[bg][1:v:0]overlay=w",
                "-s", "320x240","-r", "30", "-b", "15496k", "-vcodec", "mpeg4","-ab", "48000", "-ac", "2", "-ar", "22050",
                "/sdcard/videokit/out.mp4"};  



  vintage + watermark
 
      String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/Movies/sample.mp4","-strict","experimental",
                "-vf",
                "movie=/sdcard/videokit/watermark002.png [watermark];" +
                "[in][watermark] overlay=main_w-overlay_w-10:10 [out_overlay];" +
                "[out_overlay]curves=vintage[out]", 
                "-s", "320x240","-r", "30", "-b", "15496k", "-vcodec", "mpeg4","-ab", "48000", "-ac", "2", "-ar", "22050",
                "/sdcard/videokit/out_water_vinta.mp4"};



Watermark + audio replace
 
    String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/Movies/sample.mp4","-i", "/sdcard/videokit/in.mp3", "-strict","experimental",
                "-filter_complex",
                "[1:a]atempo=1.0[a1];" +
                "movie=/sdcard/videokit/watermark002.png [watermark];" +
                "[0:v][watermark] overlay=main_w-overlay_w-10:10 [outv]",
                "-map", "[outv]", "-map", "[a1]",
                "-s", "320x240","-r", "30", "-b", "15496k", "-vcodec", "mpeg4","-ab", "48000", "-ac", "2", "-ar", "22050",
                "-shortest","/sdcard/videokit/out_water.mp4"};


Looping on a picture and adding audio with audio encoding support
 
      String commandStr = "ffmpeg -y -loop 1 -i /sdcard/videokit/pic001.jpg -i /sdcard/videokit/in.mp3 -strict experimental -s 1270x720 -r 25 -aspect 16:9 -vcodec mpeg4 -vcodec mpeg4 -ab 48000 -ac 2 -b 2097152 -ar 22050 -shortest /sdcard/videokit/out2.mp4";


Replacing video audio track, using the shotest (video or audio)

String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/videokit/sample.mp4","-i", "/sdcard/videokit/in.mp3", "-strict","experimental",
                "-map", "0:v", "-map", "1:a",
                "-s", "320x240","-r", "30", "-b", "15496k", "-vcodec", "mpeg4","-ab", "48000", "-ac", "2", "-ar", "22050","-shortest","/sdcard/videokit/out.mp4"};

Animated GIF

//Compress animated gif:
fmpeg -f gif -i /sdcard/videokit/pic1.gif -strict experimental -r 10 /sdcard/videokit/pic1_1.gif

//Convert mp4 to animated gif:
ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -r 20 /sdcard/videokit/out.gif

//Convert animated gif to mp4:
ffmpeg -y -f gif -i /sdcard/videokit/infile.gif /sdcard/videokit/outfile.mp4


Flash Support

//converting mp4 to swf:
ffmpeg -y -i sdcard/videokit/in.mp4 -strict experimental -acodec mp3 -ab 128000 -ar 44100 -vcodec flv1 -s 352x288 sdcard/videokit/out.swf

// converting mp4 to flv (Need extras):
ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -vcodec libx264 -preset ultrafast -crf 24 -acodec aac -ar 44100 -ac 2 -b:a 96k -s 320x240 -aspect 4:3 /sdcard/videokit/out3.flv


Karaoke

/phase cancellation on a stereo track with centered vocals
{"ffmpeg","-y","-i","/storage/emulated/0/videokit/in.mp3,"-af", "pan=stereo|c0=c0|c1=-1*c1", "-ac","2", "/storage/emulated/0/videokit/karaoke.mp3"}





ARM64-v8a support

Fully supported in the latest version.







Using complex commands

A complex command is a command that contains embedded elements (in most cases it uses quotations for that.
Here is an example:
ffmpeg -i /sdcard/videokit/in.mp4 -aspect 1:1 -vf split "[main][tmp];[tmp] crop=iw/2:ih:0:0, hflip[tp],[tp] pad=2*iw[left]; [main] crop=iw/2:ih:iw/2:0[right]; [left][right] overlay=W/2" -vb 20M -r 23.956 /sdcard/videokit/outs.mp4

To set a complex command you should create a String array and use the method:
setCommandComplex()

Like this:
String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/videokit/mo.mkv","-strict","experimental", "-vf", "crop=iw/2:ih:0:0,split[tmp],pad=2*iw[left]; [tmp]hflip[right]; [left][right] overlay=W/2", "-vb", "20M", "-r", "23.956", "/sdcard/videokit/out.mp4"};

setCommandComplex(complexCommand);


Size Tuning - Keeping your app apk small

FFmpeg4Android lib contains a build specifically to tackle this issue - Small App Size.
This build contains a subset of FFmpeg4Android that contains features (filters, coders, encoders, muxers etc), That are the most commonly used - the "essentials build".
This build is great for apps that need to keep small size.
All the performance benefits of the full ffmpeg4android are kept.

  
To use this build, goto ffmpeg_lib libs/armeabi-v7a folder,
simply rename libvideokit.so to libvideokit.so.full, 
and rename libvideokit.so.ess to libvideokit.so
Refresh the ffmpeg_lib project, and build your project (that use the ffmpeg_lib).
Your project will now use the essentials build, and you will see that the apk created is much smaller in size.

You can also remove the  libs/x86 folder, x86 devices will still work using the Houdini ARM real time translation, of course it will be slower then using the native.

You can also remove the libs/arm64-v8a folder since currently most devices does not support this platform, and all that do have backward compatibility with armeabi-v7a.

Make sure you test and see that all the functionality you need is still there.


Performance Tuning

  • Prefer mpeg4 codec (-codec mpeg4), since with this codec, ffmpeg4android can utilize all device cores.
Here is an example of command that use mpeg4 codec (in this case this command is doing a video compression):

String[] complexCommand = {"ffmpeg","-y" ,"-i", "/sdcard/video kit/in.mp4","-strict","experimental","-s", "160x120","-r","25", "-vcodec", "mpeg4", "-b", "150k", "-ab","48000", "-ac", "2", "-ar", "22050", "/sdcard/video kit/out.mp4"};


  • If its possible, reduce output video resolution (-s) and bitrate (-b), the lower the video quality is, the faster it will take to produce.
  • Encoding using h264 can't utilize all device cores, and thus is much slower. If you must use it, use the -preset ultrafast flag.
  • Using the -threads flag can only degrade the performance, as ffmpeg4android automatically detects the number of cores your device has, and set the optimal number of threads for the command used. 

 


Audio Pack

If Your app needs Audio only support, we have a very small compilation (2.9M), that contain only the audio part of ffmpeg4android.
You can download it from here:
https://drive.google.com/open?id=1k_FmZeZZjEZ9se-cO6IMG-MagkTqRGja

To use it, simply replace the jniLibs/armeabi-v7a with the one in this zip.

FFmpeg Command Correctness

FFmpeg command can be quite complex, and in some cases, getting it right can be hard.
To help you with that, FFmpeg4Android will create a file called vk.log that contains the ffmpeg log in the device demo folder (by default /sdcard/videokit) This log can be very useful when understanding what is wrong with the FFmpeg command, and in most cases it will pinpoint you to the section in the command that is wrong.
If you still don't understand what is wrong with your command, make sure the command works on a windows machine, and you can email us the command for inspection.

Known issues & TroubleShooting

* If you use only armeabi-v7a you must make sure all your other JNI libs are restricted to this architecture,  If not the loader will fail to find the library so file (it will try to find it in x64 folders).
To do it, add this configuration in your module build.gradle (under defaultConfig):

ndk {
    abiFilter "armeabi-v7a"
}



Latest version release notes

6.1
----
* Moved to FFmpeg4Android version 5.5
* Runtime permissions supported.