寻找Android的FFmpeg Wrappers

时间:2014-04-04 13:59:17

标签: android video ffmpeg wrapper codec

stackoverflow ers,

我需要使用FFmpeg将视频和一些照片组合在一起制作视频。 我已经设法在我的系统上编译FFmpeg并静态链接它。 现在我正在寻找利用ffmpeg完成任务的包装/图书馆,用于 Android

我尝试了什么:

  • Guardian项目代码,Awesome api,简单而且很好,但是当运行createSlideshowFromImagesAndAudio时,我得到了一个很好的返回代码,但是我的设备上从未创建过该文件(如果您有使用此代码的经验,我得到的返回代码是11)
  • JCodec,慢地狱。
  • FMJ,不支持我需要的功能。

所以问题仍然存在,Android的FFmpeg包装有什么好处?

2 个答案:

答案 0 :(得分:2)

如果没有可用的包装器/不符合您的要求,您可以创建一个描述应用程序需求的高级C API(而不是为Java提供完整的ffmpeg API),然后实现API,即大部分功能,在C / C ++中使用C调用ffmpeg API。

这种方法可能比为ffmpeg

创建完整包装器更简单

答案 1 :(得分:2)

这是FFMPEG的Wrapper完美运行:你必须按照这些步骤为android制作FFMPEG Wrapper。你必须创建几个classess,如下所示:

<强> ShellUtils.java

package com.example.processvideo;

public class ShellUtils {

    //various console cmds
        public final static String SHELL_CMD_CHMOD = "chmod";
        public final static String SHELL_CMD_KILL = "kill -9";
        public final static String SHELL_CMD_RM = "rm";
        public final static String SHELL_CMD_PS = "ps";
        public final static String SHELL_CMD_PIDOF = "pidof";

        public final static String CHMOD_EXE_VALUE = "700";

    public static boolean isRootPossible()
    {

        StringBuilder log = new StringBuilder();

        try {

            // Check if Superuser.apk exists
            File fileSU = new File("/system/app/Superuser.apk");
            if (fileSU.exists())
                return true;

            fileSU = new File("/system/bin/su");
            if (fileSU.exists())
                return true;

            //Check for 'su' binary 
            String[] cmd = {"which su"};
            int exitCode = ShellUtils.doShellCommand(cmd, new ShellCallback ()
            {

                @Override
                public void shellOut(char[] msg) {

                    //System.out.print(msg);

                }

            }, false, true);

            if (exitCode == 0) {
                logMessage("Can acquire root permissions");
                 return true;

            }

        } catch (IOException e) {
            //this means that there is no root to be had (normally) so we won't log anything
            logException("Error checking for root access",e);

        }
        catch (Exception e) {
            logException("Error checking for root access",e);
            //this means that there is no root to be had (normally)
        }

        logMessage("Could not acquire root permissions");


        return false;
    }


    public static int findProcessId(String command) 
    {
        int procId = -1;

        try
        {
            procId = findProcessIdWithPidOf(command);

            if (procId == -1)
                procId = findProcessIdWithPS(command);
        }
        catch (Exception e)
        {
            try
            {
                procId = findProcessIdWithPS(command);
            }
            catch (Exception e2)
            {
                logException("Unable to get proc id for: " + command,e2);
            }
        }

        return procId;
    }

    //use 'pidof' command
    public static int findProcessIdWithPidOf(String command) throws Exception
    {

        int procId = -1;

        Runtime r = Runtime.getRuntime();

        Process procPs = null;

        String baseName = new File(command).getName();
        //fix contributed my mikos on 2010.12.10
        procPs = r.exec(new String[] {SHELL_CMD_PIDOF, baseName});
        //procPs = r.exec(SHELL_CMD_PIDOF);

        BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
        String line = null;

        while ((line = reader.readLine())!=null)
        {

            try
            {
                //this line should just be the process id
                procId = Integer.parseInt(line.trim());
                break;
            }
            catch (NumberFormatException e)
            {
                logException("unable to parse process pid: " + line,e);
            }
        }


        return procId;

    }

    //use 'ps' command
    public static int findProcessIdWithPS(String command) throws Exception
    {

        int procId = -1;

        Runtime r = Runtime.getRuntime();

        Process procPs = null;

        procPs = r.exec(SHELL_CMD_PS);

        BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
        String line = null;

        while ((line = reader.readLine())!=null)
        {
            if (line.indexOf(' ' + command)!=-1)
            {

                StringTokenizer st = new StringTokenizer(line," ");
                st.nextToken(); //proc owner

                procId = Integer.parseInt(st.nextToken().trim());

                break;
            }
        }



        return procId;

    }


    public static int doShellCommand(String[] cmds, ShellCallback sc, boolean runAsRoot, boolean waitFor) throws Exception
    {

        Process proc = null;
        int exitCode = -1;

        if (runAsRoot)
            proc = Runtime.getRuntime().exec("su");
        else
            proc = Runtime.getRuntime().exec("sh");


        OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream());

        for (int i = 0; i < cmds.length; i++)
        {
            logMessage("executing shell cmd: " + cmds[i] + "; runAsRoot=" + runAsRoot + ";waitFor=" + waitFor);

            out.write(cmds[i]);
            out.write("\n");
        }

        out.flush();
        out.write("exit\n");
        out.flush();

        if (waitFor)
        {

            final char buf[] = new char[20];

            // Consume the "stdout"
            InputStreamReader reader = new InputStreamReader(proc.getInputStream());
            int read=0;
            while ((read=reader.read(buf)) != -1) {
                if (sc != null) sc.shellOut(buf);
            }

            // Consume the "stderr"
            reader = new InputStreamReader(proc.getErrorStream());
            read=0;
            while ((read=reader.read(buf)) != -1) {
                if (sc != null) sc.shellOut(buf);
            }

            exitCode = proc.waitFor();

        }


        return exitCode;

    }

    public static void logMessage (String msg)
    {

    }

    public static void logException (String msg, Exception e)
    {

    }

    public interface ShellCallback
    {
        public void shellOut (char[] msg);
    }
}

<强> RegionTrail.java     公共类RegionTrail {

    private HashMap<Integer,ObscureRegion> regionMap = new HashMap<Integer,ObscureRegion>();

    private int startTime = 0;
    private int endTime = 0;


    public static final String OBSCURE_MODE_REDACT = "black";
    public static final String OBSCURE_MODE_PIXELATE = "pixel";

    private String obscureMode = OBSCURE_MODE_PIXELATE;

    private boolean doTweening = true;

    public boolean isDoTweening() {
        return doTweening;
    }

    public void setDoTweening(boolean doTweening) {
        this.doTweening = doTweening;
    }

    public String getObscureMode() {
        return obscureMode;
    }

    public void setObscureMode(String obscureMode) {
        this.obscureMode = obscureMode;
    }

    public RegionTrail (int startTime, int endTime)
    {
        this.startTime = startTime;
        this.endTime = endTime;
    }

    public int getStartTime() {
        return startTime;
    }

    public void setStartTime(int startTime) {
        this.startTime = startTime;
    }

    public int getEndTime() {
        return endTime;
    }

    public void setEndTime(int endTime) {
        this.endTime = endTime;
    }

    public void addRegion (ObscureRegion or)
    {
        regionMap.put(or.timeStamp,or);
        or.setRegionTrail(this);
    }

    public void removeRegion (ObscureRegion or)
    {
        regionMap.remove(or.timeStamp);
    }

    public Iterator<ObscureRegion> getRegionsIterator ()
    {
        return regionMap.values().iterator();
    }

    public ObscureRegion getRegion (Integer key)
    {
        return regionMap.get(key);
    }

    public TreeSet<Integer> getRegionKeys ()
    {
        TreeSet<Integer> regionKeys = new TreeSet<Integer>(regionMap.keySet());

        return regionKeys;
    }

    public boolean isWithinTime (int time)
    {

        if (time < startTime || time > endTime)
            return false;
        else
            return true;
    }

    public ObscureRegion getCurrentRegion (int time, boolean doTween)
    {

        ObscureRegion regionResult = null;

        if (time < startTime || time > endTime)
            return null;
        else if (regionMap.size() > 0)
        {


            TreeSet<Integer> regionKeys = new TreeSet<Integer>(regionMap.keySet());

            Integer lastRegionKey = -1, regionKey = -1;

            Iterator<Integer> itKeys = regionKeys.iterator();

            while (itKeys.hasNext())
            {
                regionKey = itKeys.next();
                int comp = regionKey.compareTo(time);

                if (comp == 0 || comp == 1)
                {
                    ObscureRegion regionThis = regionMap.get(regionKey);

                    if (lastRegionKey != -1 && doTween)
                    {
                        ObscureRegion regionLast = regionMap.get(lastRegionKey);

                        float sx, sy, ex, ey;

                        int timeDiff = regionThis.timeStamp - regionLast.timeStamp;
                        int timePassed = time - regionLast.timeStamp;

                        float d = ((float)timePassed) / ((float)timeDiff);

                        sx = regionLast.sx + ((regionThis.sx-regionLast.sx)*d);
                        sy = regionLast.sy + ((regionThis.sy-regionLast.sy)*d);

                        ex = regionLast.ex + ((regionThis.ex-regionLast.ex)*d);
                        ey = regionLast.ey + ((regionThis.ey-regionLast.ey)*d);

                        regionResult = new ObscureRegion(time, sx, sy, ex, ey);

                    }
                    else
                        regionResult = regionThis;


                    break; //it is a match!
                }


                lastRegionKey = regionKey;

            }

            if (regionResult == null)
                regionResult = regionMap.get(lastRegionKey);


        }

        return regionResult;
    }
}

<强> ObscureRegion.java

 public class ObscureRegion  {

    /*
     * Thinking about whether or not a region should contain multiple start/end times
     * realizing that doing this would make editing a real pita
     * Of course, it would make displaying be a 1000x better though.
    class PositionTime {

        int sx = 0; 
        int sy = 0; 
        int ex = 0;
        int ey = 0;
        int startTime = 0; 
        int endTime = 0;

        PositionTime(int _sx, int _sy, int _ex, int _ey, int _startTime, int _endTime) {

        }
    }
    */



    public static final float DEFAULT_X_SIZE = 150;
    public static final float DEFAULT_Y_SIZE = 150;

    public float sx = 0;
    public float sy = 0;

    public float ex = 0;
    public float ey = 0;

    public int timeStamp = 0;

    public RegionTrail regionTrail;

    private RectF rectF;

    public ObscureRegion(int _timeStamp, float _sx, float _sy, float _ex, float _ey) {

        timeStamp = _timeStamp;
        sx = _sx;
        sy = _sy;
        ex = _ex;
        ey = _ey;

        if (sx < 0) { 
            sx = 0;
        } else if (sy < 0) {
            sy = 0;
        }


    }

    public ObscureRegion(int _startTime, float _sx, float _sy) {
        this(_startTime, _sx - DEFAULT_X_SIZE/2, _sy - DEFAULT_Y_SIZE/2, _sx + DEFAULT_X_SIZE/2, _sy + DEFAULT_Y_SIZE/2);
    }


    public void moveRegion(float _sx, float _sy) {
        moveRegion(_sx - DEFAULT_X_SIZE/2, _sy - DEFAULT_Y_SIZE/2, _sx + DEFAULT_X_SIZE/2, _sy + DEFAULT_Y_SIZE/2);
    }

    public void moveRegion(float _sx, float _sy, float _ex, float _ey) {
        sx = _sx;
        sy = _sy;
        ex = _ex;
        ey = _ey;

        rectF = null;
    }

    public RectF getRectF() {

        if (rectF == null)
            rectF = new RectF(sx, sy, ex, ey);

        return rectF;
    }

    public RectF getBounds() {
        return getRectF();
    }


    public String getStringData(float widthMod, float heightMod, int startTime, int duration, String currentMode) {
        //left, right, top, bottom
        return "" + (float)startTime/(float)1000 + ',' + (float)(startTime+duration)/(float)1000 + ',' + (int)(sx*widthMod) + ',' + (int)(ex*widthMod) + ',' + (int)(sy*heightMod) + ',' + (int)(ey*heightMod) + ',' + currentMode;
    }

    public RegionTrail getRegionTrail() {
        return regionTrail;
    }

    public void setRegionTrail(RegionTrail regionTrail) {
        this.regionTrail = regionTrail;
    }
}

<强> FFMPEGWrapper.java

public class FFMPEGWrapper {

    String[] libraryAssets = {"ffmpeg"};
    public File fileBinDir;
    Context context;

    private final static String FFMPEG_BINARY_VERSION = "0.10.4.1";
    private final static String FFMPEG_VERSION_KEY = "ffmpegkey";

    public FFMPEGWrapper(Context _context) throws FileNotFoundException, IOException {
        context = _context;
        fileBinDir = context.getDir("bin",0);

        checkBinary();
    }

    private void checkBinary () throws FileNotFoundException, IOException
    {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        String currTorBinary = prefs.getString(FFMPEG_VERSION_KEY, null);

        if ((currTorBinary == null || (!currTorBinary.equals(FFMPEG_BINARY_VERSION))) 
                || !new File(fileBinDir,libraryAssets[0]).exists())
        {
            BinaryInstaller bi = new BinaryInstaller(context,fileBinDir);
            bi.installFromRaw();
        }
    }

    public void execProcess( String[] cmds, ShellCallback sc) throws Exception {        


            ProcessBuilder pb = new ProcessBuilder(cmds);
            pb.redirectErrorStream(true);
            Process process = pb.start();      

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

            String line;


            /*switch(command_call_type)
            {
            case Keys.KEY_COMMANDEXE_TYPE_MERGEFRAME:

            //  refincereference.updateLoadingbar(30);
                break;

            }*/

            while ((line = reader.readLine()) != null)
            {
                if (sc != null)
                {
                    sc.shellOut(line.toCharArray());

                Log.d("FFMPEG", line.toCharArray()+"");


                }
            }



            /*switch(command_call_type)
            {
            case Keys.KEY_COMMANDEXE_TYPE_MERGEFRAME:

                //refincereference.updateLoadingbar(40);
                break;

            case Keys.KEY_COMMANDEXE_TYPE_CLIPMP3:
                //refincereference.updateLoadingbar(60);
                break;
            case Keys.KEY_COMMANDEXE_TYPE_MP3TOM4A:
                //refincereference.updateLoadingbar(80);
            break;

            }*/


            /*
            if (process != null) {
                process.destroy();        
            }*/

    }

    public class FFMPEGArg
    {
        String key;
        String value;

        public static final String ARG_VIDEOCODEC = "vcodec";
        public static final String ARG_VERBOSITY = "v";
        public static final String ARG_FILE_INPUT = "i";
        public static final String ARG_SIZE = "-s";
        public static final String ARG_FRAMERATE = "-r";
        public static final String ARG_FORMAT = "-f";

    }

    public void processVideo(File redactSettingsFile, 
            ArrayList<RegionTrail> obscureRegionTrails, File inputFile, File outputFile, String format, int mDuration,
            int iWidth, int iHeight, int oWidth, int oHeight, int frameRate, int kbitRate, String vcodec, String acodec, ShellCallback sc) throws Exception {

        float widthMod = ((float)oWidth)/((float)iWidth);
        float heightMod = ((float)oHeight)/((float)iHeight);

        writeRedactData(redactSettingsFile, obscureRegionTrails, widthMod, heightMod, mDuration);

        if (vcodec == null)
            vcodec = "copy";//"libx264"

        if (acodec == null)
            acodec = "copy";

        String ffmpegBin = new File(fileBinDir,"ffmpeg").getAbsolutePath();
        Runtime.getRuntime().exec("chmod 700 " +ffmpegBin);



        String[]    ffmpegCommand=new String[]{
                ffmpegBin, "-h"
            };
   /*   String[] ffmpegCommand = {ffmpegBin, "-y", "-i", inputFile.getPath(), 
                "-vcodec", vcodec, 
                "-b", kbitRate+"k", 
                "-s",  oWidth + "x" + oHeight, 
                "-r", ""+frameRate,
                "-acodec", acodec,
                "-f", format,
                "-vf","redact=" + redactSettingsFile.getAbsolutePath(),
                outputFile.getPath()};*/

        //./ffmpeg -y -i test.mp4 -vframes 999999  -vf 'redact=blurbox.txt [out] [d], [d]nullsink' -acodec copy outputa.mp4

        //ffmpeg -v 10 -y -i /sdcard/org.witness.sscvideoproto/videocapture1042744151.mp4 -vcodec libx264
        //-b 3000k -s 720x480 -r 30 -acodec copy -f mp4 -vf 'redact=/data/data/org.witness.sscvideoproto/redact_unsort.txt'
        ///sdcard/org.witness.sscvideoproto/new.mp4

        //"-vf" , "redact=" + Utils.getAvailiableStorageLocation() + "/" + PACKAGENAME + "/redact_unsort.txt",


        // Need to make sure this will create a legitimate mp4 file
        //"-acodec", "ac3", "-ac", "1", "-ar", "16000", "-ab", "32k",


        /*
        String[] ffmpegCommand = {"/data/data/"+PACKAGENAME+"/ffmpeg", "-v", "10", "-y", "-i", recordingFile.getPath(), 
                        "-vcodec", "libx264", "-b", "3000k", "-vpre", "baseline", "-s", "720x480", "-r", "30",
                        //"-vf", "drawbox=10:20:200:60:red@0.5",
                        "-vf" , "\"movie="+ overlayImage.getPath() +" [logo];[in][logo] overlay=0:0 [out]\"",
                        "-acodec", "copy",
                        "-f", "mp4", savePath.getPath()+"/output.mp4"};
        */

    //  execProcess(ffmpegCommand, sc);






    }

    private void writeRedactData(File redactSettingsFile, ArrayList<RegionTrail> regionTrails, float widthMod, float heightMod, int mDuration) throws IOException {
        // Write out the finger data

        FileWriter redactSettingsFileWriter = new FileWriter(redactSettingsFile);
        PrintWriter redactSettingsPrintWriter = new PrintWriter(redactSettingsFileWriter);
        ObscureRegion or = null, lastOr = null;
        String orData = "";

        for (RegionTrail trail : regionTrails)
        {

            if (trail.isDoTweening())
            {
                int timeInc = 100;

                for (int i = 0; i < mDuration; i = i+timeInc)
                {
                    or = trail.getCurrentRegion(i, trail.isDoTweening());
                    if (or != null)
                    {
                        orData = or.getStringData(widthMod, heightMod,i,timeInc, trail.getObscureMode());
                        redactSettingsPrintWriter.println(orData);
                    }
                }

            }
            else
            {

                for (Integer orKey : trail.getRegionKeys())
                {
                    or = trail.getRegion(orKey);

                    if (lastOr != null)
                    {

                        orData = lastOr.getStringData(widthMod, heightMod,or.timeStamp,or.timeStamp-lastOr.timeStamp, trail.getObscureMode());
                    }

                    redactSettingsPrintWriter.println(orData);

                    lastOr = or;
                }

                if (or != null)
                {
                    orData = lastOr.getStringData(widthMod, heightMod,or.timeStamp,or.timeStamp-lastOr.timeStamp, trail.getObscureMode());
                    redactSettingsPrintWriter.println(orData);
                }
            }
        }

        redactSettingsPrintWriter.flush();

        redactSettingsPrintWriter.close();


    }

    class FileMover {

        InputStream inputStream;
        File destination;

        public FileMover(InputStream _inputStream, File _destination) {
            inputStream = _inputStream;
            destination = _destination;
        }

        public void moveIt() throws IOException {

            OutputStream destinationOut = new BufferedOutputStream(new FileOutputStream(destination));

            int numRead;
            byte[] buf = new byte[1024];
            while ((numRead = inputStream.read(buf) ) >= 0) {
                destinationOut.write(buf, 0, numRead);
            }

            destinationOut.flush();
            destinationOut.close();
        }
    }

}

<强> BinaryInstaller.java

public class BinaryInstaller  {


    File installFolder;
    Context context;

    private static int isARMv6 = -1;
    private static String CHMOD_EXEC = "700";

    private final static int FILE_WRITE_BUFFER_SIZE = 32256;

    public BinaryInstaller (Context context, File installFolder)
    {
        this.installFolder = installFolder;

        this.context = context;
    }

    //      
    /*
     * Extract the Tor binary from the APK file using ZIP
     */
    public boolean installFromRaw () throws IOException, FileNotFoundException
    {

        InputStream is;
        File outFile;

        is = context.getResources().openRawResource(R.raw.ffmpeg);          
        outFile = new File(installFolder, "ffmpeg");
        streamToFile(is, outFile, false, false, "700");


        return true;
    }


    private static void copyAssetFile(Context ctx, String asset, File file) throws IOException, InterruptedException
    {

        DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
        InputStream is = new GZIPInputStream(ctx.getAssets().open(asset));

        byte buf[] = new byte[8172];
        int len;
        while ((len = is.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        out.close();
        is.close();
    }
    /*
     * Write the inputstream contents to the file
     */
    private static boolean streamToFile(InputStream stm, File outFile, boolean append, boolean zip, String mode) throws IOException

    {
        byte[] buffer = new byte[FILE_WRITE_BUFFER_SIZE];

        int bytecount;


        OutputStream stmOut = new FileOutputStream(outFile, append);

        if (zip)
        {
            ZipInputStream zis = new ZipInputStream(stm);           
            ZipEntry ze = zis.getNextEntry();
            stm = zis;

        }

        while ((bytecount = stm.read(buffer)) > 0)
        {

            stmOut.write(buffer, 0, bytecount);

        }

        stmOut.close();
        stm.close();

        Runtime.getRuntime().exec("chmod "+mode+" "+outFile.getAbsolutePath());


        return true;

    }

    //copy the file from inputstream to File output - alternative impl
    public void copyFile (InputStream is, File outputFile)
    {

        try {
            outputFile.createNewFile();
            DataOutputStream out = new DataOutputStream(new FileOutputStream(outputFile));
            DataInputStream in = new DataInputStream(is);

            int b = -1;
            byte[] data = new byte[1024];

            while ((b = in.read(data)) != -1) {
                out.write(data);
            }

            if (b == -1); //rejoice

            //
            out.flush();
            out.close();
            in.close();
            // chmod?



        } catch (IOException ex) {
            Log.e("SLIDEAGRAM", "error copying binary", ex);
        }

    }



    /**
     * Check if this is an ARMv6 device
     * @return true if this is ARMv6
     */
    private static boolean isARMv6() {
        if (isARMv6 == -1) {
            BufferedReader r = null;
            try {
                isARMv6 = 0;
                r = new BufferedReader(new FileReader("/proc/cpuinfo"));
                for (String line = r.readLine(); line != null; line = r.readLine()) {
                    if (line.startsWith("Processor") && line.contains("ARMv6")) {
                        isARMv6 = 1;
                        break;
                    } else if (line.startsWith("CPU architecture") && (line.contains("6TE") || line.contains("5TE"))) {
                        isARMv6 = 1;
                        break;
                    }
                }
            } catch (Exception ex) {
            } finally {
                if (r != null) try {r.close();} catch (Exception ex) {}
            }
        }
        return (isARMv6 == 1);
    }


    private static void copyRawFile(Context ctx, int resid, File file, String mode, boolean isZipd) throws IOException, InterruptedException
    {
        final String abspath = file.getAbsolutePath();
        // Write the iptables binary
        final FileOutputStream out = new FileOutputStream(file);
        InputStream is = ctx.getResources().openRawResource(resid);

        if (isZipd)
        {
            ZipInputStream zis = new ZipInputStream(is);            
            ZipEntry ze = zis.getNextEntry();
            is = zis;
        }

        byte buf[] = new byte[1024];
        int len;
        while ((len = is.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        out.close();
        is.close();
        // Change the permissions
        Runtime.getRuntime().exec("chmod "+mode+" "+abspath).waitFor();
    }


}

<强> FFMpegVideoProcess.java

public class FFMpegVideoProcess
{

    public static void mergeFramesIntoVideo(Activity context,String duration_per_frame,String input_frame_path,String out_video_path)throws Exception
    {
        //Looper.prepare();

         String  ffmpegBin;
         FFMPEGWrapper ffmpeg = null;
         ShellUtils.ShellCallback sc;

                if (ffmpeg == null)
                    ffmpeg = new FFMPEGWrapper(context);


                 sc = new ShellUtils.ShellCallback ()
                {
                    int total = 0;
                    int current = 0;

                    @Override
                    public void shellOut(char[] shellout) {

                        String line = new String(shellout);


                        int idx1;
                        String newStatus = null;
                        int progress = 0;

                        if ((idx1 = line.indexOf("Duration:"))!=-1)
                        {
                            int idx2 = line.indexOf(",", idx1);
                            String time = line.substring(idx1+10,idx2);

                            int hour = Integer.parseInt(time.substring(0,2));
                            int min = Integer.parseInt(time.substring(3,5));
                            int sec = Integer.parseInt(time.substring(6,8));

                            total = (hour * 60 * 60) + (min * 60) + sec;

                            newStatus = line;
                            progress = 0;
                        }
                        else if ((idx1 = line.indexOf("time="))!=-1)
                        {
                            int idx2 = line.indexOf(" ", idx1);
                            String time = line.substring(idx1+5,idx2);
                            newStatus = line;

                            int hour = Integer.parseInt(time.substring(0,2));
                            int min = Integer.parseInt(time.substring(3,5));
                            int sec = Integer.parseInt(time.substring(6,8));

                            current = (hour * 60 * 60) + (min * 60) + sec;

                            progress = (int)( ((float)current) / ((float)total) *100f );
                        }

                        if (newStatus != null)
                        {
                        // Message msg = mHandler.obtainMessage(1);
                     //    msg.getData().putInt("progress", progress);
                       //  msg.getData().putString("status", newStatus);

                       //  mHandler.sendMessage(msg);
                        }
                    }

                };



                 ffmpegBin = new File(ffmpeg.fileBinDir,"ffmpeg").getAbsolutePath();
                Runtime.getRuntime().exec("chmod 700 " +ffmpegBin);


            //  refincereference.updateLoadingbar(20);



        ffmpeg.execProcess(new String[]{

                ffmpegBin,
                "-f",
                "image2",
                "-r",
                duration_per_frame,
                "-i",
                input_frame_path,
                "-s",
                "640x640",
                //"640x388",
                "-vcodec",
                "libx264",
                "-y",
                out_video_path




            },sc);
        //Looper.loop();    

}


}

将所有文件放在一起后,如果要将帧合并到视频中,请调用此函数

  FFMpegVideoProcess.createFramesinFolder(this,DIR_IN_WHICH_YOU_WANT_TO_KEEP_FRAMES, "frame_%03d.jpg");
        FFMpegVideoProcess.mergeFramesIntoVideo(args1,DIR_IN_WHICH_YOU_WANT_TO_KEEP_FRAMES/frame_%3d.jpg",argN...);

如果您有任何查询,请随时提问。谢谢