From da13535830fc75cc5bd86cee86dd5c567240ed55 Mon Sep 17 00:00:00 2001 From: xufuji456 <839789740@qq.com> Date: Thu, 25 Jan 2018 01:27:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A7=86=E9=A2=91=E5=89=AA?= =?UTF-8?q?=E5=88=87=E3=80=81=E8=BD=AC=E7=A0=81=E3=80=81=E6=88=AA=E5=9B=BE?= =?UTF-8?q?=E3=80=81=E6=B0=B4=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加视频剪切、转码、截图、添加水印、视频转成GIF、图片合成视频 --- .../ffmpeg/activity/AudioHandleActivity.java | 58 ++++- .../frank/ffmpeg/activity/MainActivity.java | 5 +- .../ffmpeg/activity/MediaHandleActivity.java | 101 ++++---- .../ffmpeg/activity/VideoHandleActivity.java | 218 +++++++++++++++++- .../com/frank/ffmpeg/util/BitmapUtil.java | 92 ++++++++ .../com/frank/ffmpeg/util/FFmpegUtil.java | 109 ++++++++- .../main/res/layout/activity_audio_handle.xml | 7 + .../main/res/layout/activity_media_handle.xml | 7 + .../main/res/layout/activity_video_handle.xml | 80 +++++++ app/src/main/res/values/strings.xml | 5 +- 10 files changed, 619 insertions(+), 63 deletions(-) create mode 100644 app/src/main/java/com/frank/ffmpeg/util/BitmapUtil.java diff --git a/app/src/main/java/com/frank/ffmpeg/activity/AudioHandleActivity.java b/app/src/main/java/com/frank/ffmpeg/activity/AudioHandleActivity.java index 32b41ae..8a0d5c7 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/AudioHandleActivity.java +++ b/app/src/main/java/com/frank/ffmpeg/activity/AudioHandleActivity.java @@ -1,12 +1,14 @@ package com.frank.ffmpeg.activity; +import android.annotation.SuppressLint; import android.os.Environment; +import android.os.Handler; +import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; -import android.widget.Toast; - +import android.widget.ProgressBar; import java.io.File; import com.frank.ffmpeg.FFmpegCmd; import com.frank.ffmpeg.R; @@ -20,9 +22,32 @@ import com.frank.ffmpeg.util.FFmpegUtil; public class AudioHandleActivity extends AppCompatActivity implements View.OnClickListener{ private final static String TAG = AudioHandleActivity.class.getSimpleName(); - private static final String PATH = Environment.getExternalStorageDirectory().getPath(); - String srcFile = PATH + File.separator + "tiger.mp3"; - String appendFile = PATH + File.separator + "test.mp3"; + private final static String PATH = Environment.getExternalStorageDirectory().getPath(); + private String srcFile = PATH + File.separator + "tiger.mp3"; + private String appendFile = PATH + File.separator + "test.mp3"; + private final static int MSG_BEGIN = 11; + private final static int MSG_FINISH = 12; + private ProgressBar progress_audio; + + @SuppressLint("HandlerLeak") + private Handler mHandler = new Handler(){ + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what){ + case MSG_BEGIN: + progress_audio.setVisibility(View.VISIBLE); + setGone(); + break; + case MSG_FINISH: + progress_audio.setVisibility(View.GONE); + setVisible(); + break; + default: + break; + } + } + }; @Override protected void onCreate(Bundle savedInstanceState) { @@ -33,12 +58,27 @@ public class AudioHandleActivity extends AppCompatActivity implements View.OnCli } private void initView() { + progress_audio = (ProgressBar) findViewById(R.id.progress_audio); findViewById(R.id.btn_transform).setOnClickListener(this); findViewById(R.id.btn_cut).setOnClickListener(this); findViewById(R.id.btn_concat).setOnClickListener(this); findViewById(R.id.btn_mix).setOnClickListener(this); } + private void setVisible() { + findViewById(R.id.btn_transform).setVisibility(View.VISIBLE); + findViewById(R.id.btn_cut).setVisibility(View.VISIBLE); + findViewById(R.id.btn_concat).setVisibility(View.VISIBLE); + findViewById(R.id.btn_mix).setVisibility(View.VISIBLE); + } + + private void setGone() { + findViewById(R.id.btn_transform).setVisibility(View.GONE); + findViewById(R.id.btn_cut).setVisibility(View.GONE); + findViewById(R.id.btn_concat).setVisibility(View.GONE); + findViewById(R.id.btn_mix).setVisibility(View.GONE); + } + @Override public void onClick(View v) { int handleType; @@ -103,17 +143,13 @@ public class AudioHandleActivity extends AppCompatActivity implements View.OnCli @Override public void onBegin() { Log.i(TAG, "handle audio onBegin..."); + mHandler.obtainMessage(MSG_BEGIN).sendToTarget(); } @Override public void onEnd(int result) { Log.i(TAG, "handle audio onEnd..."); - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(AudioHandleActivity.this, "handle audio finish...", Toast.LENGTH_SHORT).show(); - } - }); + mHandler.obtainMessage(MSG_FINISH).sendToTarget(); } }); } diff --git a/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java b/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java index 01bd390..27173ec 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java +++ b/app/src/main/java/com/frank/ffmpeg/activity/MainActivity.java @@ -4,8 +4,6 @@ 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; /** @@ -38,8 +36,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe 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)); + 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 index c223f09..7bfa747 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.java +++ b/app/src/main/java/com/frank/ffmpeg/activity/MediaHandleActivity.java @@ -10,12 +10,10 @@ import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; -import android.widget.Toast; - +import android.widget.ProgressBar; import com.frank.ffmpeg.FFmpegCmd; import com.frank.ffmpeg.R; import com.frank.ffmpeg.util.FFmpegUtil; - import java.io.File; /** @@ -30,42 +28,58 @@ public class MediaHandleActivity extends AppCompatActivity implements View.OnCli private String videoFile = PATH + File.separator + "flash-tree.mp4";//flash-tree.mp4 String temp = PATH + File.separator + "temp.mp4"; private boolean isMux; + private final static int MSG_MUX = 100; + private final static int MSG_BEGIN = 101; + private final static int MSG_FINISH = 102; + private ProgressBar progress_media; @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"; + switch (msg.what){ + case MSG_MUX: + 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(); - } + 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(); + } + break; + case MSG_BEGIN: + progress_media.setVisibility(View.VISIBLE); + setGone(); + break; + case MSG_FINISH: + progress_media.setVisibility(View.GONE); + setVisible(); + break; + default: + break; } } }; @@ -79,11 +93,24 @@ public class MediaHandleActivity extends AppCompatActivity implements View.OnCli } private void initView() { + progress_media = (ProgressBar) findViewById(R.id.progress_media) ; findViewById(R.id.btn_mux).setOnClickListener(this); findViewById(R.id.btn_extract_audio).setOnClickListener(this); findViewById(R.id.btn_extract_video).setOnClickListener(this); } + private void setVisible() { + findViewById(R.id.btn_mux).setVisibility(View.VISIBLE); + findViewById(R.id.btn_extract_audio).setVisibility(View.VISIBLE); + findViewById(R.id.btn_extract_video).setVisibility(View.VISIBLE); + } + + private void setGone() { + findViewById(R.id.btn_mux).setVisibility(View.GONE); + findViewById(R.id.btn_extract_audio).setVisibility(View.GONE); + findViewById(R.id.btn_extract_video).setVisibility(View.GONE); + } + @Override public void onClick(View v) { int handleType; @@ -146,20 +173,16 @@ public class MediaHandleActivity extends AppCompatActivity implements View.OnCli @Override public void onBegin() { Log.i(TAG, "handle media onBegin..."); + mHandler.obtainMessage(MSG_BEGIN).sendToTarget(); } @Override public void onEnd(int result) { Log.i(TAG, "handle media onEnd..."); if(isMux){ - mHandler.obtainMessage(100).sendToTarget(); + mHandler.obtainMessage(MSG_MUX).sendToTarget(); }else { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(MediaHandleActivity.this, "handle media finish...", Toast.LENGTH_SHORT).show(); - } - }); + mHandler.obtainMessage(MSG_FINISH).sendToTarget(); } } }); diff --git a/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java b/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java index 0e570f8..f034c51 100644 --- a/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java +++ b/app/src/main/java/com/frank/ffmpeg/activity/VideoHandleActivity.java @@ -1,20 +1,228 @@ package com.frank.ffmpeg.activity; +import android.annotation.SuppressLint; 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.ProgressBar; +import com.frank.ffmpeg.FFmpegCmd; import com.frank.ffmpeg.R; +import com.frank.ffmpeg.util.FFmpegUtil; -/** - * 使用ffmpeg进行视频处理 - * Created by frank on 2018/1/23. - */ -public class VideoHandleActivity extends AppCompatActivity { +import java.io.File; + +public class VideoHandleActivity extends AppCompatActivity implements View.OnClickListener{ + + private static final String TAG = VideoHandleActivity.class.getSimpleName(); + private static final int MSG_BEGIN = 101; + private static final int MSG_FINISH = 102; + + private static final String PATH = Environment.getExternalStorageDirectory().getPath(); + private static final String srcFile = PATH + File.separator + "hello.mp4"; + private static final String appendVideo = PATH + File.separator + "test.mp4"; + private ProgressBar progress_video; + + @SuppressLint("HandlerLeak") + private Handler mHandler = new Handler(){ + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what){ + case MSG_BEGIN: + progress_video.setVisibility(View.VISIBLE); + setGone(); + break; + case MSG_FINISH: + progress_video.setVisibility(View.GONE); + setVisible(); + break; + default: + break; + } + } + }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_video_handle); + + intView(); } + private void intView() { + progress_video = (ProgressBar)findViewById(R.id.progress_video); + findViewById(R.id.btn_video_transform).setOnClickListener(this); + findViewById(R.id.btn_video_cut).setOnClickListener(this); + findViewById(R.id.btn_video_concat).setOnClickListener(this); + findViewById(R.id.btn_screen_shot).setOnClickListener(this); + findViewById(R.id.btn_water_mark).setOnClickListener(this); + findViewById(R.id.btn_generate_gif).setOnClickListener(this); + findViewById(R.id.btn_screen_record).setOnClickListener(this); + findViewById(R.id.btn_combine_video).setOnClickListener(this); + } + + private void setVisible() { + findViewById(R.id.btn_video_transform).setVisibility(View.VISIBLE); + findViewById(R.id.btn_video_cut).setVisibility(View.VISIBLE); + findViewById(R.id.btn_video_concat).setVisibility(View.GONE); + findViewById(R.id.btn_screen_shot).setVisibility(View.VISIBLE); + findViewById(R.id.btn_water_mark).setVisibility(View.VISIBLE); + findViewById(R.id.btn_generate_gif).setVisibility(View.VISIBLE); + findViewById(R.id.btn_screen_record).setVisibility(View.GONE); + findViewById(R.id.btn_combine_video).setVisibility(View.VISIBLE); + } + + private void setGone() { + findViewById(R.id.btn_video_transform).setVisibility(View.GONE); + findViewById(R.id.btn_video_cut).setVisibility(View.GONE); + findViewById(R.id.btn_video_concat).setVisibility(View.GONE); + findViewById(R.id.btn_screen_shot).setVisibility(View.GONE); + findViewById(R.id.btn_water_mark).setVisibility(View.GONE); + findViewById(R.id.btn_generate_gif).setVisibility(View.GONE); + findViewById(R.id.btn_screen_record).setVisibility(View.GONE); + findViewById(R.id.btn_combine_video).setVisibility(View.GONE); + } + + @Override + public void onClick(View v) { + int handleType; + switch (v.getId()){ + case R.id.btn_video_transform: + handleType = 0; + break; + case R.id.btn_video_cut: + handleType = 1; + break; + case R.id.btn_video_concat: + handleType = 2; + break; + case R.id.btn_screen_shot: + handleType = 3; + break; + case R.id.btn_water_mark: + handleType = 4; + break; + case R.id.btn_generate_gif: + handleType = 5; + break; + case R.id.btn_screen_record: + handleType = 6; + break; + case R.id.btn_combine_video: + handleType = 7; + break; + default: + handleType = 0; + break; + } + doHandleVideo(handleType); + } + + /** + * 调用ffmpeg处理视频 + * @param handleType handleType + */ + private void doHandleVideo(int handleType){ + String[] commandLine = null; + switch (handleType){ + case 0://视频转码 + String transformVideo = PATH + File.separator + "transformVideo.wmv"; + commandLine = FFmpegUtil.transformVideo(srcFile, transformVideo); + break; + case 1://视频剪切 + String cutVideo = PATH + File.separator + "cutVideo.mp4"; + int startTime = 0; + int duration = 20; + commandLine = FFmpegUtil.cutVideo(srcFile, startTime, duration, cutVideo); + break; + case 2://视频合并 +// commandLine = FFmpegUtil.toTs(srcFile, ts1); +// concatStep ++; +// String concatVideo = PATH + File.separator + "concatVideo.mp4"; +// String appendVideo = PATH + File.separator + "test.mp4"; +// File concatFile = new File(PATH + File.separator + "fileList.txt"); +// try { +// FileOutputStream fileOutputStream = new FileOutputStream(concatFile); +// fileOutputStream.write(("file \'" + srcFile + "\'").getBytes()); +// fileOutputStream.write("\n".getBytes()); +// fileOutputStream.write(("file \'" + appendVideo + "\'").getBytes()); +// fileOutputStream.flush(); +// fileOutputStream.close(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// +// commandLine = FFmpegUtil.concatVideo(srcFile, concatFile.getAbsolutePath(), concatVideo); + break; + case 3://视频截图 + String screenShot = PATH + File.separator + "screenShot.jpg"; + String size = "1080x720"; + commandLine = FFmpegUtil.screenShot(srcFile, size, screenShot); + break; + case 4://视频添加水印 + //1、图片 + String photo = PATH + File.separator + "launcher.png"; + String photoMark = PATH + File.separator + "photoMark.mp4"; + commandLine = FFmpegUtil.addWaterMark(appendVideo, photo, photoMark); + //2、文字 + //String text = "Hello,FFmpeg"; + //String textPath = PATH + File.separator + "text.jpg"; + //boolean result = BitmapUtil.textToPicture(textPath, text, this); + //Log.i(TAG, "text to pitcture result=" + result); + //String textMark = PATH + File.separator + "textMark.mp4"; + //commandLine = FFmpegUtil.addWaterMark(appendVideo, photo, textMark); + break; + case 5://视频转成gif + String Video2Gif = PATH + File.separator + "Video2Gif.gif"; + int gifStart = 30; + int gifDuration = 5; + commandLine = FFmpegUtil.generateGif(srcFile, gifStart, gifDuration, Video2Gif); + break; + case 6://屏幕录制 +// String screenRecord = PATH + File.separator + "screenRecord.mp4"; +// String screenSize = "320x240"; +// int recordTime = 10; +// commandLine = FFmpegUtil.screenRecord(screenSize, recordTime, screenRecord); + break; + case 7://图片合成视频 + //图片所在路径,图片命名格式img+number.jpg + String picturePath = PATH + File.separator + "img/"; + String combineVideo = PATH + File.separator + "combineVideo.mp4"; + commandLine = FFmpegUtil.pictureToVideo(picturePath, combineVideo); + 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 video onBegin..."); + mHandler.obtainMessage(MSG_BEGIN).sendToTarget(); + } + + @Override + public void onEnd(int result) { + Log.i(TAG, "handle video onEnd..."); + + mHandler.obtainMessage(MSG_FINISH).sendToTarget(); + } + }); + } } diff --git a/app/src/main/java/com/frank/ffmpeg/util/BitmapUtil.java b/app/src/main/java/com/frank/ffmpeg/util/BitmapUtil.java new file mode 100644 index 0000000..7776cf0 --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/util/BitmapUtil.java @@ -0,0 +1,92 @@ +package com.frank.ffmpeg.util; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * bitmap工具类:文字转成图片 + * Created by frank on 2018/1/24. + */ + +public class BitmapUtil { + + private final static int TEXT_SIZE = 16; + private final static int TEXT_COLOR = Color.RED; + + /** + * 文本转成Bitmap + * @param text 文本内容 + * @param context 上下文 + * @return 图片的bitmap + */ + private static Bitmap textToBitmap(String text , Context context) { + float scale = context.getResources().getDisplayMetrics().scaledDensity; + TextView tv = new TextView(context); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + tv.setLayoutParams(layoutParams); + tv.setText(text); + tv.setTextSize(scale * TEXT_SIZE); + tv.setGravity(Gravity.CENTER_HORIZONTAL); + tv.setDrawingCacheEnabled(true); + tv.setTextColor(TEXT_COLOR); + tv.setBackgroundColor(Color.WHITE); + tv.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight()); + tv.buildDrawingCache(); + Bitmap bitmap = tv.getDrawingCache(); + int rate = bitmap.getHeight() / 20; + return Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/rate, 20, false); + } + + /** + * 文字生成图片 + * @param filePath filePath + * @param text text + * @param context context + * @return 生成图片是否成功 + */ + public static boolean textToPicture(String filePath, String text , Context context){ + Bitmap bitmap = textToBitmap(text , context); + FileOutputStream outputStream = null; + try { + outputStream = new FileOutputStream(filePath); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream); + outputStream.flush(); + } catch (IOException e) { + e.printStackTrace(); + return false; + }finally { + try { + if(outputStream != null){ + outputStream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return true; + } + + /** + * 删除源文件 + * @param filePath filePath + * @return 删除是否成功 + */ + public static boolean deleteTextFile(String filePath) { + File file = new File(filePath); + return file.exists() && file.delete(); + } + +} 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 9e69292..b904748 100644 --- a/app/src/main/java/com/frank/ffmpeg/util/FFmpegUtil.java +++ b/app/src/main/java/com/frank/ffmpeg/util/FFmpegUtil.java @@ -1,9 +1,10 @@ package com.frank.ffmpeg.util; import android.annotation.SuppressLint; +import android.util.Log; /** - * ffmpeg工具:拼接命令行处理音频 + * ffmpeg工具:拼接命令行处理音视频 * Created by frank on 2018/1/23. */ @@ -75,7 +76,7 @@ public class FFmpegUtil { @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"; + String mixAudioCmd = "ffmpeg -i %s -i %s -t %d %s"; mixAudioCmd = String.format(mixAudioCmd, videoFile, audioFile, duration, muxFile); return mixAudioCmd.split(" ");//以空格分割为字符串数组 } @@ -106,4 +107,108 @@ public class FFmpegUtil { return mixAudioCmd.split(" ");//以空格分割为字符串数组 } + + /** + * 使用ffmpeg命令行进行视频转码 + * @param srcFile 源文件 + * @param targetFile 目标文件(后缀指定转码格式) + * @return 转码后的文件 + */ + public static String[] transformVideo(String srcFile, String targetFile){ +// String transformVideoCmd = "ffmpeg -i %s -r 25 -b 200 -s 1080x720 %s"; + String transformVideoCmd = "ffmpeg -i %s %s"; + transformVideoCmd = String.format(transformVideoCmd, srcFile, targetFile); + return transformVideoCmd.split(" ");//以空格分割为字符串数组 + } + + /** + * 使用ffmpeg命令行进行视频剪切 + * @param srcFile 源文件 + * @param startTime 剪切的开始时间(单位为秒) + * @param duration 剪切时长(单位为秒) + * @param targetFile 目标文件 + * @return 剪切后的文件 + */ + @SuppressLint("DefaultLocale") + public static String[] cutVideo(String srcFile, int startTime, int duration, String targetFile){ + String cutVideoCmd = "ffmpeg -i %s -ss %d -t %d %s"; + cutVideoCmd = String.format(cutVideoCmd, srcFile, startTime, duration, targetFile); + return cutVideoCmd.split(" ");//以空格分割为字符串数组 + } + + /** + * 使用ffmpeg命令行进行视频截图 + * @param srcFile 源文件 + * @param size 图片尺寸大小 + * @param targetFile 目标文件 + * @return 截图后的文件 + */ + public static String[] screenShot(String srcFile, String size, String targetFile){ + String screenShotCmd = "ffmpeg -i %s -f image2 -t 0.001 -s %s %s"; + screenShotCmd = String.format(screenShotCmd, srcFile, size, targetFile); + return screenShotCmd.split(" ");//以空格分割为字符串数组 + } + + /** + * 使用ffmpeg命令行给视频添加水印 + * @param srcFile 源文件 + * @param waterMark 水印文件路径 + * @param targetFile 目标文件 + * @return 添加水印后的文件 + */ + public static String[] addWaterMark(String srcFile, String waterMark, String targetFile){ + String waterMarkCmd = "ffmpeg -i %s -i %s -filter_complex overlay=0:0 %s"; + waterMarkCmd = String.format(waterMarkCmd, srcFile, waterMark, targetFile); + return waterMarkCmd.split(" ");//以空格分割为字符串数组 + } + + /** + * 使用ffmpeg命令行进行视频转成Gif动图 + * @param srcFile 源文件 + * @param startTime 开始时间 + * @param duration 截取时长 + * @param targetFile 目标文件 + * @return Gif文件 + */ + @SuppressLint("DefaultLocale") + public static String[] generateGif(String srcFile, int startTime, int duration, String targetFile){ + //String screenShotCmd = "ffmpeg -i %s -vframes %d -f gif %s"; + String screenShotCmd = "ffmpeg -i %s -ss %d -t %d -s 320x240 -f gif %s"; + screenShotCmd = String.format(screenShotCmd, srcFile, startTime, duration, targetFile); + return screenShotCmd.split(" ");//以空格分割为字符串数组 + } + + /** + * 使用ffmpeg命令行进行屏幕录制 + * @param size 视频尺寸大小 + * @param recordTime 录屏时间 + * @param targetFile 目标文件 + * @return 屏幕录制文件 + */ + @SuppressLint("DefaultLocale") + public static String[] screenRecord(String size, int recordTime, String targetFile){ + //-vd x11:0,0 指录制所使用的偏移为 x=0 和 y=0 + //String screenRecordCmd = "ffmpeg -vcodec mpeg4 -b 1000 -r 10 -g 300 -vd x11:0,0 -s %s %s"; + String screenRecordCmd = "ffmpeg -vcodec mpeg4 -b 1000 -r 10 -g 300 -vd x11:0,0 -s %s -t %d %s"; + screenRecordCmd = String.format(screenRecordCmd, size, recordTime, targetFile); + Log.i("VideoHandleActivity", "screenRecordCmd=" + screenRecordCmd); + return screenRecordCmd.split(" ");//以空格分割为字符串数组 + } + + /** + * 使用ffmpeg命令行进行图片合成视频 + * @param srcFile 源文件 + * @param targetFile 目标文件(mpg格式) + * @return 合成的视频文件 + */ + @SuppressLint("DefaultLocale") + public static String[] pictureToVideo(String srcFile, String targetFile){ + //-f image2:代表使用image2格式,需要放在输入文件前面 + String combineVideo = "ffmpeg -f image2 -r 1 -i %simg#d.jpg -vcodec mpeg4 %s"; + combineVideo = String.format(combineVideo, srcFile, targetFile); + combineVideo = combineVideo.replace("#", "%"); + Log.i("VideoHandleActivity", "combineVideo=" + combineVideo); + return combineVideo.split(" ");//以空格分割为字符串数组 + } + } diff --git a/app/src/main/res/layout/activity_audio_handle.xml b/app/src/main/res/layout/activity_audio_handle.xml index 9783ad2..5565d6d 100644 --- a/app/src/main/res/layout/activity_audio_handle.xml +++ b/app/src/main/res/layout/activity_audio_handle.xml @@ -41,4 +41,11 @@ android:layout_marginTop="10dp" android:layout_centerHorizontal="true"/> + + diff --git a/app/src/main/res/layout/activity_media_handle.xml b/app/src/main/res/layout/activity_media_handle.xml index 57d7a07..a886fa7 100644 --- a/app/src/main/res/layout/activity_media_handle.xml +++ b/app/src/main/res/layout/activity_media_handle.xml @@ -31,4 +31,11 @@ android:layout_centerHorizontal="true" android:layout_below="@+id/btn_extract_audio"/> + + diff --git a/app/src/main/res/layout/activity_video_handle.xml b/app/src/main/res/layout/activity_video_handle.xml index d526645..c32a039 100644 --- a/app/src/main/res/layout/activity_video_handle.xml +++ b/app/src/main/res/layout/activity_video_handle.xml @@ -5,4 +5,84 @@ android:layout_height="match_parent" tools:context="com.frank.ffmpeg.activity.VideoHandleActivity"> +