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 @@ - - - - - - - - - - - - - -