安卓插件.so lib' s(UNITY)

时间:2017-03-23 11:08:41

标签: java android unity3d ffmpeg

所以我需要在android中使用ffmpeg。 (用于复用音频和视频)。 我找到了android studio的这个很棒的项目(链接在帖子的末尾,在rar中为ffmpeg4android_demo_studio2)。 我工作得很完美,复杂和整体令人敬畏的项目。所以我决定从该项目为anroid制作插件,所以我重新制作了这样的项目:(链接在帖子的末尾,在rar中为ffmpeg4android_demo_studio((pS是没有GeneralUtils代码,因为它的大,请下载rar并打开它。))

package com.netcompss.ffmpeg4android;

public class CommandValidationException extends Exception {
    private static final long serialVersionUID = 1L;
}

=============================================

 package com.netcompss.ffmpeg4android;

    import android.content.Context;
    import android.util.Log;
    import android.widget.Toast;    
    public class FFMpeg {
    private Context context;
    private static FFMpeg instance;
    public FFMpeg (){
        this.instance = this;
    }

    public static  FFMpeg instance(){
        if(instance == null){
            instance = new FFMpeg();
        }
        return instance;
    }

    public void setContext(Context context){
        this.context = context;
    }

    public void mux(String video,String audio,String out){
        //GeneralUtils.checkForPermissionsMAndAbove(currentActivity, true);
        LoadJNI vk = new LoadJNI();
        try {
            String workFolder = context.getFilesDir().getAbsolutePath()+ "/";
            String cmd = "ffmpeg -i "+video+" -i "+audio+" -c copy -map 0:v:0 -map 1:a:0 -shortest "+out;
            vk.run(GeneralUtils.utilConvertToComplex(cmd) , workFolder , context);
            Log.i("test", "ffmpeg4android finished successfully");
        } catch (Throwable e) {
            Log.e("test", "vk run exception.", e);
        }
    }

    public void showMessage(String message){
        Toast.makeText(this.context,message,Toast.LENGTH_SHORT).show();
    }

    }

==================

包com.netcompss.ffmpeg4android;

import android.app.Activity;
import android.content.Context;
import android.widget.TextView;
import android.os.Bundle;


public class LicenseCheckJNI
{

    public int licenseCheck(String path, Context ctx) {
       String rcStr = "-100";
          rcStr = licenseCheckComplexJNI(path);
       int rc =Integer.decode(rcStr);
       return rc;
    }


    public native String licenseCheckComplexJNI(String path);
    public native String licenseCheckSimpleJNI(String path);




    static {
        System.loadLibrary("license-jni");
    }
}

package com.netcompss.ffmpeg4android;

import java.io.File;
import android.content.Context;
import android.nfc.Tag;
import android.util.Log;

public final class LoadJNI {

   static {
      System.loadLibrary("loader-jni");
      System.loadLibrary("license-jni");
      System.loadLibrary("videokit");

   }

   /**
    *
    * @param args ffmpeg command
    * @param workFolder working directory
    * @param ctx Android context
    * @param isValidate apply validation to the command
    * @throws CommandValidationException
    */
   public void run(String[] args, String workFolder, Context ctx, boolean isValidate) throws CommandValidationException {
      Log.i(Prefs.TAG, "running ffmpeg4android_lib: " + Prefs.version);
      // delete previous log: this is essential for correct progress calculation
      String vkLogPath = workFolder + "vk.log";
      GeneralUtils.deleteFileUtil(vkLogPath);
      GeneralUtils.printCommand(args);

      //printInternalDirStructure(ctx);

      if (isValidate) {
         if (GeneralUtils.isValidCommand(args)) {
            Log.d(Prefs.TAG, "=LOAD================");
            load(args, workFolder, getVideokitLibPath(ctx), true);
         }
         else
            throw new CommandValidationException();
      }
      else {
         Log.d(Prefs.TAG, "=LOAD================");
         load(args, workFolder, getVideokitLibPath(ctx), true);
      }

   }

   /**
    *
    * @param args ffmpeg command
    * @param workFolder working directory
    * @param ctx Android context
    * @throws CommandValidationException
    */
   public void run(String[] args, String workFolder, Context ctx) throws CommandValidationException {
      run(args, workFolder, ctx, true);
   }


   private static void printInternalDirStructure(Context ctx) {
      Log.d(Prefs.TAG, "=printInternalDirStructure=");
      Log.d(Prefs.TAG, "==============================");
      File file = new File(ctx.getFilesDir().getParent());
      analyzeDir(file);
      Log.d(Prefs.TAG, "==============================");
   }

   private static void analyzeDir(File path) {
      if (path.isDirectory()) {
         Log.d(Prefs.TAG,"Scanning dir: " + path.getAbsolutePath());
         File[] files1 = path.listFiles();
         for (int i = 0; i < files1.length; i++) {
            analyzeDir(files1[i]);
         }
         Log.d(Prefs.TAG, "==========");
      }
      else {
         Log.d(Prefs.TAG, path.getAbsolutePath());

      }
   }

   private static String getVideokitLibPath(Context ctx) {

      //File file = new File(ctx.getFilesDir().getParent() + "/lib/");
      //analyzeDir(file);

      String videokitLibPath = ctx.getFilesDir().getParent()  + "/lib/libvideokit.so";

      File file = new File(videokitLibPath);
      if(file.exists())  {    
        Log.i(Prefs.TAG, "videokitLibPath exits");
      }
      else {
         Log.w(Prefs.TAG, "videokitLibPath not exits: " + videokitLibPath);
         videokitLibPath = ctx.getFilesDir().getParent()  + "/lib/arm64/libvideokit.so";
         Log.i(Prefs.TAG, "trying videokitLibPath: " + videokitLibPath);
         file = new File(videokitLibPath);
         if(file.exists())  {
            Log.i(Prefs.TAG, "videokitLibPath exits: " + videokitLibPath);
         }
         else {
            Log.w(Prefs.TAG, "videokitLibPath not exits: " + videokitLibPath);
            videokitLibPath = "/data/app/com.examples.ffmpeg4android_demo-1/lib/arm64/libvideokit.so";
            Log.i(Prefs.TAG, "trying videokitLibPath: " + videokitLibPath);
            file = new File(videokitLibPath);
            if(file.exists())  {
               Log.i(Prefs.TAG, "videokitLibPath exits: " + videokitLibPath);
            }
            else {
               Log.w(Prefs.TAG, "videokitLibPath not exits: " + videokitLibPath);
               videokitLibPath = "/data/app/com.examples.ffmpeg4android_demo-2/lib/arm64/libvideokit.so";
               Log.i(Prefs.TAG, "trying videokitLibPath: " + videokitLibPath);
               if(file.exists())  {
                  Log.i(Prefs.TAG, "videokitLibPath exits: " + videokitLibPath);
               }
               else {
                  Log.e(Prefs.TAG, "can't find path of lib");
               }
            }
         }
      }





      //String videokitLibPath = ctx.getFilesDir().getParent()  + "/lib/arm64/libvideokit.so";

      // only this works on Android M, and the number changes (demo-2, demo-1)
      //String videokitLibPath = "/data/app/com.examples.ffmpeg4android_demo-1/lib/arm64/libvideokit.so";


      //Log.i(Prefs.TAG, "videokitLibPath: " + videokitLibPath);
      return videokitLibPath;

   }



   public void fExit( Context ctx) {
      fexit(getVideokitLibPath(ctx));
   }

   public native String fexit(String videokitLibPath);
   public native String unload();
   public native String load(String[] args, String videokitSdcardPath, String videokitLibPath, boolean isComplex);
}

============================

package com.netcompss.ffmpeg4android;

public class Prefs {
   public static final String TAG = "ffmpeg4android";
   public static final String version = "322.00.00_LM322";
}
[/code]
[code=JavaScript]
package com.netcompss.ffmpeg4android;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import android.util.Log;

public class ProgressCalculator {

   private int _durationOfCurrentWaitIndex = 0;
   private final int DURATION_OF_CURRENT_WAIT_INDEX_LIMIT = 12;
   private String _durationOfCurrent;
   private long _lastVklogSize = -1;
   private int _vkLogNoChangeCounter = 0;
   private SimpleDateFormat _simpleDateFormat;
   long _timeRef = -1;
   int  _prevProgress = 0;
   private String vkLogPath = null;

   public ProgressCalculator(String vkLogPathIn) {
      vkLogPath = vkLogPathIn;
      _simpleDateFormat = new SimpleDateFormat("HH:mm:ss.SS");
      try {
         Date ref = _simpleDateFormat.parse("00:00:00.00");
         ref.setYear(112);
         _timeRef = ref.getTime();
      } catch (ParseException e) {
         Log.w(Prefs.TAG, "failed to set _timeRef");
      }
   }

   public void initCalcParamsForNextInter() {
      Log.i(Prefs.TAG, "initCalcParamsForNextInter");
      _lastVklogSize = -1;
      _vkLogNoChangeCounter = 0;
      _durationOfCurrent = null;

   }

   public int calcProgress() {
      return calcProgress(1);
   }


   public int calcProgress(int durationMultiplyer) {
      //Log.i(Prefs.TAG, "========calc progress======= " + durationMultiplyer);
      int progress  = 0;
      if (_durationOfCurrent == null) {
         String dur = GeneralUtils.getDutationFromVCLogRandomAccess(vkLogPath);
         Log.d(Prefs.TAG, "dur: " + dur);
         if (dur == null || dur.equals("") || dur.equals("null") ) {
            Log.i(Prefs.TAG, "dur is not good, not setting ");
            if (_durationOfCurrentWaitIndex < DURATION_OF_CURRENT_WAIT_INDEX_LIMIT) {
               Log.i(Prefs.TAG, "waiting for real duration, going out of calcProgress with 0");
               _durationOfCurrentWaitIndex ++;
               return 0;
            }
            else {
               Log.i(Prefs.TAG, "_durationOfCurrentWaitIndex is equal to: " + DURATION_OF_CURRENT_WAIT_INDEX_LIMIT + " reseting.");
               _durationOfCurrentWaitIndex = 0;
               Log.i(Prefs.TAG, "setting fake Prefs.durationOfCurrent");

               _durationOfCurrent = "00:03:00.00";
               Log.w(Prefs.TAG, "setting fake Prefs.durationOfCurrent (Cant get from file): " + _durationOfCurrent);

            }
         }
         else {
            _durationOfCurrent = GeneralUtils.getDutationFromVCLogRandomAccess(vkLogPath);
            Log.i(Prefs.TAG, "duration: " + _durationOfCurrent + " \nTranscoding...");
         }
      }


      if (_durationOfCurrent != null) {

         long currentVkLogSize = -1;
         currentVkLogSize = GeneralUtils.getVKLogSizeRandomAccess(vkLogPath);
         //Log.d(Prefs.TAG, "currentVkLogSize: " + currentVkLogSize + " _lastVklogSize: " + _lastVklogSize);

         if (currentVkLogSize > _lastVklogSize) {
            _lastVklogSize = currentVkLogSize;
            _vkLogNoChangeCounter = 0;
         }
         else {
            //Log.w(Prefs.TAG, "Looks like Vk log is not increasing in size");
            _vkLogNoChangeCounter++;
         }


         String currentTimeStr = GeneralUtils.readLastTimeFromVKLogUsingRandomAccess(vkLogPath);
         //Log.d(Prefs.TAG, "currentTimeStr: " + currentTimeStr);
         if (currentTimeStr.equals("exit")) {
            Log.d(Prefs.TAG, "============Found one of the exit tokens in the log============");
            return 100;
         }
         else if (currentTimeStr.equals("error") && _prevProgress == 0) {
            Log.d(Prefs.TAG, "============Found error in the log============");
            return 100;
         }
         else if (_vkLogNoChangeCounter > 16) {
            Log.e(Prefs.TAG, "VK log is not changing in size, and no exit token found");
            return 100;
         }
         try {
            Date durationDate = _simpleDateFormat.parse(_durationOfCurrent);
            Date currentTimeDate = _simpleDateFormat.parse(currentTimeStr);
            currentTimeDate.setYear(112);
            durationDate.setYear(112);
            //Log.d(Prefs.TAG, " durationDate: " + durationDate + " currentTimeDate: " + currentTimeDate);

            long durationLong = durationDate.getTime() - _timeRef;
            if (durationMultiplyer != 1) {
               //Log.i(Prefs.TAG, "====durationMultiplyer is not 1, handling===");
               //Log.i(Prefs.TAG, "durationLong before: " + durationLong);
               durationLong = durationLong * durationMultiplyer;
               //Log.i(Prefs.TAG, "durationLong after: " + durationLong);
            }
            long currentTimeLong = currentTimeDate.getTime() - _timeRef;
            //Log.d(Prefs.TAG, " durationLong: " + durationLong + " currentTimeLong: " + currentTimeLong + " diff: " + (durationLong - currentTimeLong));
            progress  = Math.round(((float)currentTimeLong / durationLong) * 100);
            if (progress >= 100) {
               Log.w(Prefs.TAG, "progress is 100, but can't find exit in the log, probably fake progress, still running...");
               progress = 99;
            }
            _prevProgress = progress;


         } catch (ParseException e) {
            Log.w(Prefs.TAG, e.getMessage());
         }
      }

      return progress;
   }


}

==================================

然后点击构建并在assets / Plugins / Android / libs /下的unity项目中复制ffmpeg4android_lib.aar 然后做了这个总结

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;


public class Test : MonoBehaviour {

    private AndroidJavaObject FFMpeg = null;
    private AndroidJavaObject activityContext = null;

    public string Path1;
    public string Path2;
    public string Out3;

    public string path;

    public Text File1;
    public Text File2;
    public Text Context;
    public Text End;

    public void Convert(){
        File1.text = File.Exists (path+Path1).ToString();
        File2.text = File.Exists (path+Path2).ToString();
        if (FFMpeg == null) {
            using(AndroidJavaClass activityclass = new AndroidJavaClass("com.unity3d.player.UnityPlayer")){
                activityContext = activityclass.GetStatic<AndroidJavaObject> ("currentActivity");
            }
            Context.text = "Context =" + activityContext;
        }
        using (AndroidJavaClass pluginClass = new AndroidJavaClass ("com.netcompss.ffmpeg4android.FFMpeg")) {
            if (pluginClass != null) {
                FFMpeg = pluginClass.CallStatic<AndroidJavaObject> ("instance");
                FFMpeg.Call ("setContext", activityContext);
                //activityContext.Call ("runOnUiThread", new AndroidJavaRunnable (() => {
                FFMpeg.Call ("mux", path+Path1,path+Path2,path+Out3);
                //}));
            }
        }
        End.text = "Done";

    }
}

=============================================

问题是: 当我在AndroidStudio中启动原始项目制作的apk时,一切正常。 当我推出统一制造的apk时,它的工作正常,直到这部分: load(args,workFolder,getVideokitLibPath(ctx),true);

IT确实加载了所有lib ok。 在尝试执行该代码时,它会在logcat中抛出此错误

03-23 10:43:17.293 28263-28277/? W/dalvikvm: No implementation found for native Lcom/netcompss/ffmpeg4android/LoadJNI;.load:([Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;
03-23 10:43:17.294 28263-28277/? E/test: vk run exception.
                                         java.lang.UnsatisfiedLinkError: Native method not found: com.netcompss.ffmpeg4android.LoadJNI.load:([Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;
                                             at com.netcompss.ffmpeg4android.LoadJNI.load(Native Method)
                                             at com.netcompss.ffmpeg4android.LoadJNI.run(LoadJNI.java:37)
                                             at com.netcompss.ffmpeg4android.LoadJNI.run(LoadJNI.java:57)
                                             at com.netcompss.ffmpeg4android.FFMpeg.mux(FFMpeg.java:36)
                                             at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
                                             at com.unity3d.player.UnityPlayer.a(Unknown Source)
                                             at com.unity3d.player.UnityPlayer$b$1.handleMessage(Unknown Source)
                                             at android.os.Handler.dispatchMessage(Handler.java:103)
                                             at android.os.Looper.loop(Looper.java:194)
                                             at com.unity3d.player.UnityPlayer$b.run(Unknown Source)

项目Dropbox链接: https://www.dropbox.com/s/6vglcw7xk2n8lwu/AndroidStudioProjects.rar?dl=0

0 个答案:

没有答案