From b2ef61cc53359973925380c59a628eab59790edd Mon Sep 17 00:00:00 2001
From: xufuji456 <839789740@qq.com>
Date: Wed, 24 Jan 2018 02:12:44 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=9F=B3=E8=A7=86=E9=A2=91?=
=?UTF-8?q?=E5=90=88=E6=88=90=E4=B8=8E=E5=88=86=E7=A6=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
使用FFmpeg实现音视频合成、抽取音频、抽取视频
---
.idea/vcs.xml | 6 +
README.md | 5 +-
app/src/main/AndroidManifest.xml | 8 +-
.../frank/ffmpeg/activity/MainActivity.java | 49 +++
.../ffmpeg/activity/MediaHandleActivity.java | 168 +++++++++++
.../ffmpeg/activity/VideoHandleActivity.java | 20 ++
.../com/frank/ffmpeg/util/FFmpegUtil.java | 42 +++
app/src/main/res/drawable/btn.xml | 4 +-
.../{btncircle.xml => btn_circle.xml} | 0
.../drawable/{btnpoint.xml => btn_point.xml} | 0
.../{whitebg.xml => white_background.xml} | 0
app/src/main/res/layout/activity_main.xml | 283 ++----------------
.../main/res/layout/activity_media_handle.xml | 34 +++
app/src/main/res/layout/activity_splash.xml | 26 --
.../main/res/layout/activity_video_handle.xml | 8 +
app/src/main/res/values/strings.xml | 19 ++
16 files changed, 384 insertions(+), 288 deletions(-)
create mode 100644 .idea/vcs.xml
create mode 100644 app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java
create mode 100644 app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.java
create mode 100644 app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java
rename app/src/main/res/drawable/{btncircle.xml => btn_circle.xml} (100%)
rename app/src/main/res/drawable/{btnpoint.xml => btn_point.xml} (100%)
rename app/src/main/res/drawable/{whitebg.xml => white_background.xml} (100%)
create mode 100644 app/src/main/res/layout/activity_media_handle.xml
delete mode 100644 app/src/main/res/layout/activity_splash.xml
create mode 100644 app/src/main/res/layout/activity_video_handle.xml
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 97b39b1..1d1f3f6 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,11 @@ android端基于FFmpeg库在中的使用。
- #### 音频剪切、拼接
- #### 音频混音
- #### 音频转码
+- #### 音视频合成
+- #### 音频抽取
+- #### 视频抽取
***
-后续会加上音视频编解码、合成与分离,视频水印、截图、转Gif动图、剪切、转码。
+后续会加上音视频编解码,视频水印、截图、转Gif动图、剪切、转码。
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 99878b2..93f494a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,13 +21,19 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java b/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java
new file mode 100644
index 0000000..01bd390
--- /dev/null
+++ b/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java
@@ -0,0 +1,49 @@
+package com.frank.ffmpeg.activity;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.Toast;
+
+import com.frank.ffmpeg.R;
+
+/**
+ * 使用ffmpeg进行音视频处理入口
+ * Created by frank on 2018/1/23.
+ */
+public class MainActivity extends AppCompatActivity implements View.OnClickListener{
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ initView();
+ }
+
+ private void initView() {
+ findViewById(R.id.btn_audio).setOnClickListener(this);
+ findViewById(R.id.btn_media).setOnClickListener(this);
+ findViewById(R.id.btn_video).setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()){
+ case R.id.btn_audio://音频处理
+ startActivity(new Intent(MainActivity.this, AudioHandleActivity.class));
+ break;
+ case R.id.btn_media://音视频处理
+ startActivity(new Intent(MainActivity.this, MediaHandleActivity.class));
+ break;
+ case R.id.btn_video://视频处理
+ Toast.makeText(this, "暂时还没完善该功能...", Toast.LENGTH_LONG).show();
+// startActivity(new Intent(MainActivity.this, VideoHandleActivity.class));
+ break;
+ default:
+ break;
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.java b/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.java
new file mode 100644
index 0000000..c223f09
--- /dev/null
+++ b/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.java
@@ -0,0 +1,168 @@
+package com.frank.ffmpeg.activity;
+
+import android.annotation.SuppressLint;
+import android.media.MediaMetadataRetriever;
+import android.media.MediaPlayer;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.frank.ffmpeg.FFmpegCmd;
+import com.frank.ffmpeg.R;
+import com.frank.ffmpeg.util.FFmpegUtil;
+
+import java.io.File;
+
+/**
+ * 使用ffmpeg进行音视频合成与分离
+ * Created by frank on 2018/1/23.
+ */
+public class MediaHandleActivity extends AppCompatActivity implements View.OnClickListener{
+
+ private final static String TAG = MediaHandleActivity.class.getSimpleName();
+ private static final String PATH = Environment.getExternalStorageDirectory().getPath();
+ private String srcFile = PATH + File.separator + "hello.mp4";
+ private String videoFile = PATH + File.separator + "flash-tree.mp4";//flash-tree.mp4
+ String temp = PATH + File.separator + "temp.mp4";
+ private boolean isMux;
+
+ @SuppressLint("HandlerLeak")
+ private Handler mHandler = new Handler(){
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ if(msg.what == 100){
+ String audioFile = PATH + File.separator + "tiger.mp3";//tiger.mp3
+ String muxFile = PATH + File.separator + "media-mux.mp4";
+
+ try {
+ //使用MediaPlayer获取视频时长
+ MediaPlayer mediaPlayer = new MediaPlayer();
+ mediaPlayer.setDataSource(videoFile);
+ mediaPlayer.prepare();
+ //单位为ms
+ int videoDuration = mediaPlayer.getDuration()/1000;
+ Log.i(TAG, "videoDuration=" + videoDuration);
+ mediaPlayer.release();
+ //使用MediaMetadataRetriever获取音频时长
+ MediaMetadataRetriever mediaRetriever = new MediaMetadataRetriever();
+ mediaRetriever.setDataSource(audioFile);
+ //单位为ms
+ String duration = mediaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
+ int audioDuration = (int)(Long.parseLong(duration)/1000);
+ Log.i(TAG, "audioDuration=" + audioDuration);
+ mediaRetriever.release();
+ //如果视频时长比音频长,采用音频时长,否则用视频时长
+ int mDuration = Math.min(audioDuration, videoDuration);
+ //使用纯视频与音频进行合成
+ String[] commandLine = FFmpegUtil.mediaMux(temp, audioFile, mDuration, muxFile);
+ executeFFmpegCmd(commandLine);
+ isMux = false;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_media_handle);
+
+ initView();
+ }
+
+ private void initView() {
+ findViewById(R.id.btn_mux).setOnClickListener(this);
+ findViewById(R.id.btn_extract_audio).setOnClickListener(this);
+ findViewById(R.id.btn_extract_video).setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ int handleType;
+ switch (v.getId()){
+ case R.id.btn_mux:
+ handleType = 0;
+ break;
+ case R.id.btn_extract_audio:
+ handleType = 1;
+ break;
+ case R.id.btn_extract_video:
+ handleType = 2;
+ break;
+ default:
+ handleType = 0;
+ break;
+ }
+ doHandleMedia(handleType);
+ }
+
+ /**
+ * 调用ffmpeg处理音视频
+ * @param handleType handleType
+ */
+ private void doHandleMedia(int handleType){
+ String[] commandLine = null;
+ switch (handleType){
+ case 0://音视频合成
+ try {
+ //视频文件有音频,先把纯视频文件抽取出来
+ commandLine = FFmpegUtil.extractVideo(videoFile, temp);
+ isMux = true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ break;
+ case 1://提取音频
+ String extractAudio = PATH + File.separator + "extractAudio.aac";
+ commandLine = FFmpegUtil.extractAudio(srcFile, extractAudio);
+ break;
+ case 2://提取视频
+ String extractVideo = PATH + File.separator + "extractVideo.mp4";
+ commandLine = FFmpegUtil.extractVideo(srcFile, extractVideo);
+ break;
+ default:
+ break;
+ }
+ executeFFmpegCmd(commandLine);
+ }
+
+ /**
+ * 执行ffmpeg命令行
+ * @param commandLine commandLine
+ */
+ private void executeFFmpegCmd(final String[] commandLine){
+ if(commandLine == null){
+ return;
+ }
+ FFmpegCmd.execute(commandLine, new FFmpegCmd.OnHandleListener() {
+ @Override
+ public void onBegin() {
+ Log.i(TAG, "handle media onBegin...");
+ }
+
+ @Override
+ public void onEnd(int result) {
+ Log.i(TAG, "handle media onEnd...");
+ if(isMux){
+ mHandler.obtainMessage(100).sendToTarget();
+ }else {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(MediaHandleActivity.this, "handle media finish...", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+ });
+ }
+
+}
diff --git a/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java b/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java
new file mode 100644
index 0000000..0e570f8
--- /dev/null
+++ b/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java
@@ -0,0 +1,20 @@
+package com.frank.ffmpeg.activity;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.frank.ffmpeg.R;
+
+/**
+ * 使用ffmpeg进行视频处理
+ * Created by frank on 2018/1/23.
+ */
+public class VideoHandleActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_video_handle);
+ }
+
+}
diff --git a/app/src/main/java/com/frank/ffmpeg/util/FFmpegUtil.java b/app/src/main/java/com/frank/ffmpeg/util/FFmpegUtil.java
index da57093..9e69292 100644
--- a/app/src/main/java/com/frank/ffmpeg/util/FFmpegUtil.java
+++ b/app/src/main/java/com/frank/ffmpeg/util/FFmpegUtil.java
@@ -64,4 +64,46 @@ public class FFmpegUtil {
//混音公式:value = sample1 + sample2 - (sample1 * sample2 / (pow(2, 16-1) - 1))
+ /**
+ * 使用ffmpeg命令行进行音视频合成
+ * @param videoFile 视频文件
+ * @param audioFile 音频文件
+ * @param duration 视频时长
+ * @param muxFile 目标文件
+ * @return 合成后的文件
+ */
+ @SuppressLint("DefaultLocale")
+ public static String[] mediaMux(String videoFile, String audioFile, int duration, String muxFile){
+ //-t:时长 如果忽略音视频时长,则把"-t %d"去掉
+ String mixAudioCmd = "ffmpeg -i %s -i %s -t %d -acodec copy %s";
+ mixAudioCmd = String.format(mixAudioCmd, videoFile, audioFile, duration, muxFile);
+ return mixAudioCmd.split(" ");//以空格分割为字符串数组
+ }
+
+ /**
+ * 使用ffmpeg命令行进行抽取音频
+ * @param srcFile 原文件
+ * @param targetFile 目标文件
+ * @return 抽取后的音频文件
+ */
+ public static String[] extractAudio(String srcFile, String targetFile){
+ //-vn:video not
+ String mixAudioCmd = "ffmpeg -i %s -acodec copy -vn %s";
+ mixAudioCmd = String.format(mixAudioCmd, srcFile, targetFile);
+ return mixAudioCmd.split(" ");//以空格分割为字符串数组
+ }
+
+ /**
+ * 使用ffmpeg命令行进行抽取视频
+ * @param srcFile 原文件
+ * @param targetFile 目标文件
+ * @return 抽取后的视频文件
+ */
+ public static String[] extractVideo(String srcFile, String targetFile){
+ //-an audio not
+ String mixAudioCmd = "ffmpeg -i %s -vcodec copy -an %s";
+ mixAudioCmd = String.format(mixAudioCmd, srcFile, targetFile);
+ return mixAudioCmd.split(" ");//以空格分割为字符串数组
+ }
+
}
diff --git a/app/src/main/res/drawable/btn.xml b/app/src/main/res/drawable/btn.xml
index 2f69bf7..d520f55 100644
--- a/app/src/main/res/drawable/btn.xml
+++ b/app/src/main/res/drawable/btn.xml
@@ -4,6 +4,6 @@
android:shape="rectangle" >
+ android:endColor="@color/colorPrimary"
+ android:startColor="@color/colorAccent" />
\ No newline at end of file
diff --git a/app/src/main/res/drawable/btncircle.xml b/app/src/main/res/drawable/btn_circle.xml
similarity index 100%
rename from app/src/main/res/drawable/btncircle.xml
rename to app/src/main/res/drawable/btn_circle.xml
diff --git a/app/src/main/res/drawable/btnpoint.xml b/app/src/main/res/drawable/btn_point.xml
similarity index 100%
rename from app/src/main/res/drawable/btnpoint.xml
rename to app/src/main/res/drawable/btn_point.xml
diff --git a/app/src/main/res/drawable/whitebg.xml b/app/src/main/res/drawable/white_background.xml
similarity index 100%
rename from app/src/main/res/drawable/whitebg.xml
rename to app/src/main/res/drawable/white_background.xml
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 4a472e7..a1749bc 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,265 +1,32 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="match_parent">
+
-
-
-
-
-
+
+
diff --git a/app/src/main/res/layout/activity_media_handle.xml b/app/src/main/res/layout/activity_media_handle.xml
new file mode 100644
index 0000000..57d7a07
--- /dev/null
+++ b/app/src/main/res/layout/activity_media_handle.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml
deleted file mode 100644
index 87eb57d..0000000
--- a/app/src/main/res/layout/activity_splash.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_video_handle.xml b/app/src/main/res/layout/activity_video_handle.xml
new file mode 100644
index 0000000..d526645
--- /dev/null
+++ b/app/src/main/res/layout/activity_video_handle.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index fecfb28..2d8cd2f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,4 +4,23 @@
音频剪切
音频合并
音频混合
+
+ 音频处理
+ 音视频处理
+ 视频处理
+
+ 音视频合成
+ 提取音频
+ 提取视频
+
+ 视频剪切
+ 视频拼接
+ 视频文字水印
+ 视频图片水印
+ 视频转Gif
+ 视频转码
+ 视频截图
+ 视频抽帧
+ 视频局部放大
+