--- tags: Android Studio, FFMPEG --- # 簡易步驟將浮水印或圖片加到影片上(AndroidStudio+FFmpeg) ### 在自己的Android project中導入ffmpeg (Only use Java) 1. 下載 https://drive.google.com/file/d/0B2aT0QoEmtuaN0VJZ2Z4ODY3T2s/view 並且用AndroidStudio開啟載好的project, 然後將它要你裝的東西裝一裝或者更新一些套件 2. 回到你自己的project, 點選File => New => import module => 選擇步驟1.載好的資料夾: ``` ffmpeg4android_demo_studio\ffmpeg4android_lib ``` 3. 在AndroidManifest.xml中加上permission ```xml <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WAKE_LOCK" /> ``` 若是Android 6以上, 請在MainActivity的onCreate()中, 加上 ```java GeneralUtils.checkForPermissionsMAndAbove(MainActivity.this, false); ``` 遇到紅字則Alt+Enter 它會幫你改build.gradle(App)檔 4. \(不確定是否必要\) 在build.gradle(App)中 ``` Android{ ....... defaultConfig{ .... targetSdkVersion ... 後面加入 ndk{ abiFilter "armeabi-v7a" } } } ..... dependencies{ ... 若沒有下面這行則加入 compile project(':ffmpeg4android_lib') } ``` 5. 在gradle.properties加入 ``` android.useDeprecatedNdk=true ``` 然後async project ### 使用WaterMarkHelper 將影片加上浮水印/圖片 6. 導入WaterMarkHelper.java之後, 在Activity底下宣告 ```java WaterMarkHelper myHelper; ``` 7. 在要使用浮水印功能的地方初始化myHelper並設定參數 參數說明: ```java String inputVideoPath 輸入影片的檔名路徑(ex:"/sdcard/input.mp4") String inputWaterMarkPath 輸入浮水印圖片的檔名路徑(ex:"/sdcard/waterMark.png") String outputVideoPath 輸出影片的檔名路徑(ex:"/sdcard/output.mp4") String waterMarkX 浮水印在影片裡的橫向位置(左側為0), 可利用影片以及浮水印寬度及高度的參數 影片寬度: main_w, 影片高度: main_h, 圖片寬度: overlay_w, 圖片高度: overlay_h String waterMarkY 浮水印在影片裡的直向位置(上方為0), 同樣可利用寬高參數 ``` 範例code: ```java myHelper = new WaterMarkHelper("/sdcard/in.mp4", //請確保in.mp4存在/sdcard/ "/sdcard/watermark.png", //請確保watermark.png存在/sdcard/ "/sdcard/testOut.mp4", // "main_w/2 - overlay_w/2", // x軸的正中間 "main_h/2 - overlay_h/2"); // y軸的正中間 ``` 8. 執行浮水印功能 ```java myHelper.addVideoWaterMark(MainActivity.this); //MainActivity改成你自己的Activity ``` 上面那行的外面要包try/catch, 按Alt+Enter它應該會幫你包 範例code: ```java try { myHelper.addVideoWaterMark(MainActivity.this); } catch (CommandValidationException e) { e.printStackTrace(); } ``` ### 參考資料: [Android Warzone - FFmpeg4Android](http://androidwarzone.blogspot.tw/2011/12/ffmpeg4android.html) # Easy steps to watermark a video(AS+FFmpeg) ### How to import FFmpeg in Android project (Only use Java) 1. Download this https://drive.google.com/file/d/0B2aT0QoEmtuaN0VJZ2Z4ODY3T2s/view 2. File => New => import module => go find the folder downloaded at step1: ``` ffmpeg4android_demo_studio\ffmpeg4android_lib ``` 3. Add permission in AndroidManifest.xml ```xml <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WAKE_LOCK" /> ``` if the version is higher than Android 6, add the following code in onCreate() of your Activity ```java GeneralUtils.checkForPermissionsMAndAbove(MainActivity.this, false); ``` Alt+Enter if encounter red font, AndroidStudio would help you to modify "build.gradle(Module)" 4. \(Not sure if necessary\) In build.gradle(Module) ``` Android{ ....... defaultConfig{ .... targetSdkVersion ... <Add the following code> ndk{ abiFilter "armeabi-v7a" } } } ..... dependencies{ ... <Add the following code if doesn't exist> compile project(':ffmpeg4android_lib') } ``` 5. add following code in "gradle.properties" ``` android.useDeprecatedNdk=true ``` and then async project ### How to use WaterMarkHelper(by Johnny Tu) to add watermark on video 6. After import "WaterMarkHelper.java" in your project, declare the following in your Activity ```java WaterMarkHelper myHelper; ``` 7. initialize myHelper with arguments Arguments description: ```java String inputVideoPath (ex:"/sdcard/input.mp4") String inputWaterMarkPath (ex:"/sdcard/waterMark.png") String outputVideoPath (ex:"/sdcard/output.mp4") String waterMarkX the X-coordinate Video width: main_w, Video height: main_h, Image Width: overlay_w, Image Height: overlay_h String waterMarkY ``` example code: ```java myHelper = new WaterMarkHelper("/sdcard/in.mp4", //be sure that in.mp4 exist in /sdcard/ "/sdcard/watermark.png", //be sure that watermark.png exist in /sdcard/ "/sdcard/testOut.mp4", // "main_w/2 - overlay_w/2", // in the middle of X-axis "main_h/2 - overlay_h/2"); // in the middle of Y-axis ``` 8. adding watermark on video ```java myHelper.addVideoWaterMark(MainActivity.this); //MainActivity改成你自己的Activity ``` there should be try/catch exception outside the above code, press Alt+Enter should work. example code: ```java try { myHelper.addVideoWaterMark(MainActivity.this); } catch (CommandValidationException e) { e.printStackTrace(); } ``` ### References: [Android Warzone - FFmpeg4Android](http://androidwarzone.blogspot.tw/2011/12/ffmpeg4android.html) # WaterMarkHelper.java ```java import android.content.Context; import android.util.Log; import com.netcompss.ffmpeg4android.CommandValidationException; import com.netcompss.loader.LoadJNI; /** * Created by johnnytu on 2017/5/26. */ public class WaterMarkHelper { private String videoPath; //可任意 private String waterMarkPath; //可任意 private String overlayX;//影片寬=main_w, 浮水印寬=overlay_w private String overlayY;//影片高=main_h, 浮水印寬=overlay_h private String videoOutputPath; //可任意 private String videoOutputWidth; private String videoOutputHeight; private String videoOutputFps; private String imgBiteRate; private String voiceBiteRate; private String voiceChannelAmount; private String voiceSampleFrequency;// 聲音的取樣頻率 // 以下參數產生自 以上參數 private String videoOutputSize; private String waterMarkSettings; private String[] complexCommand; WaterMarkHelper(String inputVideoPath,String inputWaterMarkPath,String outputVideoPath,String waterMarkX,String waterMarkY){ videoPath = inputVideoPath; waterMarkPath = inputWaterMarkPath; videoOutputPath = outputVideoPath; overlayX = waterMarkX; overlayY = waterMarkY; videoOutputWidth = ""; videoOutputHeight = ""; videoOutputFps = ""; imgBiteRate = ""; voiceBiteRate = ""; voiceChannelAmount = ""; voiceSampleFrequency = "";// 聲音的取樣頻率 videoOutputSize = videoOutputWidth+"x"+videoOutputHeight; //= "320x240"; waterMarkSettings = "movie="+waterMarkPath+" [watermark]; [in][watermark] overlay=" +overlayX+":"+overlayY+" [out]"; // overlay = 寬:高, 影片寬main_w, 浮水印寬overlay_w //String waterMarkSettings = "movie=/sdcard/videokit/watermark.png [watermark]; [in][watermark] overlay=main_w-overlay_w-10:10 [out]"; complexCommand = new String[]{"ffmpeg", "-y", "-i", videoPath, "-strict", "experimental", "-vf", waterMarkSettings, "-vcodec", "mpeg4", videoOutputPath}; //vk.run(complexCommand,workFolder,getApplicationContext()); } public void addVideoWaterMark(Context context) throws CommandValidationException { Log.d("WaterMarkHelper","starting addVideoWaterMark"); long startTime = System.currentTimeMillis(); LoadJNI vk = new LoadJNI(); String workFolder = context.getApplicationContext().getFilesDir() + "/"; vk.run(complexCommand,workFolder,context.getApplicationContext()); Log.d("WaterMarkHelper","finish addVideoWaterMark, took "+ (System.currentTimeMillis()-startTime)/1000+"seconds."); } } ``` # Usage Example 範例程式 ### MainActivity.java ```java import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import com.netcompss.ffmpeg4android.CommandValidationException; import com.netcompss.ffmpeg4android.GeneralUtils; import com.netcompss.loader.LoadJNI; public class MainActivity extends AppCompatActivity { Button btnTest; WaterMarkHelper myHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // for Android 6 and above, add permission GeneralUtils.checkForPermissionsMAndAbove(MainActivity.this, false); btnTest = (Button)findViewById(R.id.btnTest); btnTest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // try { // waterMarkVideo(); // } catch (CommandValidationException e) { // e.printStackTrace(); // } myHelper = new WaterMarkHelper("/sdcard/videokit/in.mp4", "/sdcard/videokit/watermark.png", "/sdcard/testOut.mp4", "main_w/2 - overlay_w/2", "main_h/2 - overlay_h/2"); try { myHelper.addVideoWaterMark(MainActivity.this); } catch (CommandValidationException e) { e.printStackTrace(); } } }); } /* private void test(){ GeneralUtils.checkForPermissionsMAndAbove(MainActivity.this, true); LoadJNI vk = new LoadJNI(); try { String workFolder = getApplicationContext().getFilesDir().getAbsolutePath(); String[] complexCommand = {"ffmpeg","-i", "/sdcard/videokit/in.mp4"}; vk.run(complexCommand , workFolder , getApplicationContext()); Log.i("test", "ffmpeg4android finished successfully"); } catch (Throwable e) { Log.e("test", "vk run exception.", e); } } private void waterMarkVideo() throws CommandValidationException { LoadJNI vk = new LoadJNI(); String workFolder = getApplicationContext().getFilesDir() + "/"; String videoPath = "/sdcard/videokit/in2.mp4"; //可任意 String videoOutputWidth = "320"; String videoOutputHeight = "240"; String waterMarkPath = "/sdcard/videokit/watermark.png"; //可任意 String overlayX = "main_w/2 - overlay_w/2";//影片寬=main_w, 浮水印寬=overlay_w String overlayY = "main_h/2 - overlay_h/2";//影片高=main_h, 浮水印寬=overlay_h String videoOutputPath = "/sdcard/videokit/testOut.mp4"; //可任意 String videoOutputFps = "30"; String imgBiteRate = "15496k"; String voiceBiteRate = "48000"; String voiceChannelAmount = "2"; String voiceSampleFrequency = "22050";// 聲音的取樣頻率 String videoOutputSize = videoOutputWidth+"x"+videoOutputHeight; //= "320x240"; String waterMarkSettings = "movie="+waterMarkPath+" [watermark]; [in][watermark] overlay=" +overlayX+":"+overlayY+" [out]"; // overlay = 寬:高, 影片寬main_w, 浮水印寬overlay_w //String waterMarkSettings = "movie=/sdcard/videokit/watermark.png [watermark]; [in][watermark] overlay=main_w-overlay_w-10:10 [out]"; String[] complexCommand = {"ffmpeg","-y" ,"-i", videoPath,"-strict","experimental", "-vf", waterMarkSettings,"-s", videoOutputSize,"-r", videoOutputFps, "-b", imgBiteRate, "-vcodec", "mpeg4","-ab", voiceBiteRate, "-ac", voiceChannelAmount, "-ar", voiceSampleFrequency, videoOutputPath}; //vk.run(complexCommand,workFolder,getApplicationContext()); vk.run(complexCommand,workFolder,getApplicationContext()); } */ } ``` ### activity_main.xml ```xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.yutouch.watermarkapp.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical"> <Button android:id="@+id/btnTest" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Button" /> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </LinearLayout> </LinearLayout> ``` ### AndroidManifest.xml ```xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yutouch.watermarkapp"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> ```