当前位置:   article > 正文

android端采用FFmpeg进行视频剪切、转码与添加水印_android ffmpeg 学习 视频剪辑

android ffmpeg 学习 视频剪辑

前两篇文章介绍过FFmpeg进行音频处理、音视频处理:android端采用FFmpeg进行音频混合与拼接剪切 android端采用FFmpeg进行音视频合成与分离。关于FFmpeg涉及文件导入以及cmake配置,可查看第一篇文章。现在接着探讨视频相关处理:视频转码、视频剪切、视频截图、添加水印、视频转Gif动图、图片合成视频。

1、视频转码

视频转码包括格式、码率、尺寸大小等转换,-f代表强制转换格式,-b代表码率,-s代表尺寸,-r代表帧率:

  1. /**
  2. * 使用ffmpeg命令行进行视频转码
  3. * @param srcFile 源文件
  4. * @param targetFile 目标文件(后缀指定转码格式)
  5. * @return 转码后的文件
  6. */
  7. public static String[] transformVideo(String srcFile, String targetFile){
  8. String transformVideoCmd = "ffmpeg -i %s -r 25 -b 200 -s 1080x720 %s";
  9. transformVideoCmd = String.format(transformVideoCmd, srcFile, targetFile);
  10. return transformVideoCmd.split(" ");//以空格分割为字符串数组
  11. }

2、视频剪切

视频剪切是从视频指定开始时间,剪切指定时长视频,-ss代表开始时间,-t代表时长:

  1. /**
  2. * 使用ffmpeg命令行进行视频剪切
  3. * @param srcFile 源文件
  4. * @param startTime 剪切的开始时间(单位为秒)
  5. * @param duration 剪切时长(单位为秒)
  6. * @param targetFile 目标文件
  7. * @return 剪切后的文件
  8. */
  9. public static String[] cutVideo(String srcFile, int startTime, int duration, String targetFile){
  10. String cutVideoCmd = "ffmpeg -i %s -ss %d -t %d %s";
  11. cutVideoCmd = String.format(cutVideoCmd, srcFile, startTime, duration, targetFile);
  12. return cutVideoCmd.split(" ");//以空格分割为字符串数组
  13. }

3、视频截图

视频截图是从视频截取当前一帧画面,保存为指定格式的图片,使用image2工具:

  1. /**
  2. * 使用ffmpeg命令行进行视频截图
  3. * @param srcFile 源文件
  4. * @param size 图片尺寸大小
  5. * @param targetFile 目标文件
  6. * @return 截图后的文件
  7. */
  8. public static String[] screenShot(String srcFile, String size, String targetFile){
  9. String screenShotCmd = "ffmpeg -i %s -f image2 -t 0.001 -s %s %s";
  10. screenShotCmd = String.format(screenShotCmd, srcFile, size, targetFile);
  11. return screenShotCmd.split(" ");//以空格分割为字符串数组
  12. }

4、添加水印

给视频添加水印包括:文字和图片,使用到filter_complex滤波器,overlay指定图片在视频的位置:

  1. /**
  2. * 使用ffmpeg命令行给视频添加水印
  3. * @param srcFile 源文件
  4. * @param waterMark 水印文件路径
  5. * @param targetFile 目标文件
  6. * @return 添加水印后的文件
  7. */
  8. public static String[] addWaterMark(String srcFile, String waterMark, String targetFile){
  9. String waterMarkCmd = "ffmpeg -i %s -i %s -filter_complex overlay=0:0 %s";
  10. waterMarkCmd = String.format(waterMarkCmd, srcFile, waterMark, targetFile);
  11. return waterMarkCmd.split(" ");//以空格分割为字符串数组
  12. }
添加图片水印效果:

添加文字水印,其实是把文字转成图片,最终都是以图片的形式添加的,文字转图片过程如下:

  1. /**
  2. * 文本转成Bitmap
  3. * @param text 文本内容
  4. * @param context 上下文
  5. * @return 图片的bitmap
  6. */
  7. private static Bitmap textToBitmap(String text , Context context) {
  8. float scale = context.getResources().getDisplayMetrics().scaledDensity;
  9. TextView tv = new TextView(context);
  10. LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
  11. LinearLayout.LayoutParams.WRAP_CONTENT,
  12. LinearLayout.LayoutParams.WRAP_CONTENT);
  13. tv.setLayoutParams(layoutParams);
  14. tv.setText(text);
  15. tv.setTextSize(scale * TEXT_SIZE);
  16. tv.setGravity(Gravity.CENTER_HORIZONTAL);
  17. tv.setDrawingCacheEnabled(true);
  18. tv.setTextColor(TEXT_COLOR);
  19. tv.setBackgroundColor(Color.WHITE);
  20. tv.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
  21. View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
  22. tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
  23. tv.buildDrawingCache();
  24. Bitmap bitmap = tv.getDrawingCache();
  25. int rate = bitmap.getHeight() / 20;
  26. return Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/rate, 20, false);
  27. }
  28. /**
  29. * 文字生成图片
  30. * @param filePath filePath
  31. * @param text text
  32. * @param context context
  33. * @return 生成图片是否成功
  34. */
  35. public static boolean textToPicture(String filePath, String text , Context context){
  36. Bitmap bitmap = textToBitmap(text , context);
  37. FileOutputStream outputStream = null;
  38. try {
  39. outputStream = new FileOutputStream(filePath);
  40. bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream);
  41. outputStream.flush();
  42. } catch (IOException e) {
  43. e.printStackTrace();
  44. return false;
  45. }finally {
  46. try {
  47. if(outputStream != null){
  48. outputStream.close();
  49. }
  50. } catch (IOException e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. return true;
  55. }
添加文字水印的效果:


5、视频截取GIF动图

从视频截取一段画面,以GIF格式保存,使用到GIF工具,用-ss指定开始时间,-t指定截取时长:

  1. /**
  2. * 使用ffmpeg命令行进行视频转成Gif动图
  3. * @param srcFile 源文件
  4. * @param startTime 开始时间
  5. * @param duration 截取时长
  6. * @param targetFile 目标文件
  7. * @return Gif文件
  8. */
  9. public static String[] generateGif(String srcFile, int startTime, int duration, String targetFile){
  10. //String screenShotCmd = "ffmpeg -i %s -vframes %d -f gif %s";
  11. String screenShotCmd = "ffmpeg -i %s -ss %d -t %d -s 320x240 -f gif %s";
  12. screenShotCmd = String.format(screenShotCmd, srcFile, startTime, duration, targetFile);
  13. return screenShotCmd.split(" ");//以空格分割为字符串数组
  14. }
截取出来的GIF动图效果:


6、图片合成视频

图片合成视频是把文件夹的有序命名图片,使用-image2合成视频,用-r指定帧率,这里指定一秒播放一帧:

  1. /**
  2. * 使用ffmpeg命令行进行图片合成视频
  3. * @param srcFile 源文件
  4. * @param targetFile 目标文件(mpg格式)
  5. * @return 合成的视频文件
  6. */
  7. public static String[] pictureToVideo(String srcFile, String targetFile){
  8. //-f image2:代表使用image2格式,需要放在输入文件前面
  9. String combineVideo = "ffmpeg -f image2 -r 1 -i %simg#d.jpg -vcodec mpeg4 %s";
  10. combineVideo = String.format(combineVideo, srcFile, targetFile);
  11. combineVideo = combineVideo.replace("#", "%");
  12. Log.i("VideoHandleActivity", "combineVideo=" + combineVideo);
  13. return combineVideo.split(" ");//以空格分割为字符串数组
  14. }
由于合成的视频无法上传到这里,我使用FFmpeg把视频再转成GIF动图:


拼接好命令行后,调用FFmpeg的native方法处理:

  1. /**
  2. * 调用ffmpeg处理视频
  3. * @param handleType handleType
  4. */
  5. private void doHandleVideo(int handleType){
  6. String[] commandLine = null;
  7. switch (handleType){
  8. case 0://视频转码
  9. String transformVideo = PATH + File.separator + "transformVideo.wmv";
  10. commandLine = FFmpegUtil.transformVideo(srcFile, transformVideo);
  11. break;
  12. case 1://视频剪切
  13. String cutVideo = PATH + File.separator + "cutVideo.mp4";
  14. int startTime = 0;
  15. int duration = 20;
  16. commandLine = FFmpegUtil.cutVideo(srcFile, startTime, duration, cutVideo);
  17. break;
  18. case 2://视频合并
  19. break;
  20. case 3://视频截图
  21. String screenShot = PATH + File.separator + "screenShot.jpg";
  22. String size = "1080x720";
  23. commandLine = FFmpegUtil.screenShot(srcFile, size, screenShot);
  24. break;
  25. case 4://视频添加水印
  26. //1、图片
  27. String photo = PATH + File.separator + "launcher.png";
  28. String photoMark = PATH + File.separator + "photoMark.mp4";
  29. commandLine = FFmpegUtil.addWaterMark(appendVideo, photo, photoMark);
  30. //2、文字
  31. //String text = "Hello,FFmpeg";
  32. //String textPath = PATH + File.separator + "text.jpg";
  33. //boolean result = BitmapUtil.textToPicture(textPath, text, this);
  34. //Log.i(TAG, "text to pitcture result=" + result);
  35. //String textMark = PATH + File.separator + "textMark.mp4";
  36. //commandLine = FFmpegUtil.addWaterMark(appendVideo, photo, textMark);
  37. break;
  38. case 5://视频转成gif
  39. String Video2Gif = PATH + File.separator + "Video2Gif.gif";
  40. int gifStart = 30;
  41. int gifDuration = 5;
  42. commandLine = FFmpegUtil.generateGif(srcFile, gifStart, gifDuration, Video2Gif);
  43. break;
  44. case 6://屏幕录制
  45. break;
  46. case 7://图片合成视频
  47. //图片所在路径,图片命名格式img+number.jpg
  48. String picturePath = PATH + File.separator + "img/";
  49. String combineVideo = PATH + File.separator + "combineVideo.mp4";
  50. commandLine = FFmpegUtil.pictureToVideo(picturePath, combineVideo);
  51. break;
  52. default:
  53. break;
  54. }
  55. executeFFmpegCmd(commandLine);
  56. }
FFmpeg处理的回调与更新界面:

  1. /**
  2. * 执行ffmpeg命令行
  3. * @param commandLine commandLine
  4. */
  5. private void executeFFmpegCmd(final String[] commandLine){
  6. if(commandLine == null){
  7. return;
  8. }
  9. FFmpegCmd.execute(commandLine, new FFmpegCmd.OnHandleListener() {
  10. @Override
  11. public void onBegin() {
  12. Log.i(TAG, "handle video onBegin...");
  13. mHandler.obtainMessage(MSG_BEGIN).sendToTarget();
  14. }
  15. @Override
  16. public void onEnd(int result) {
  17. Log.i(TAG, "handle video onEnd...");
  18. mHandler.obtainMessage(MSG_FINISH).sendToTarget();
  19. }
  20. });
  21. }
最终调用的FFmpeg的run方法:

  1. JNIEXPORT jint JNICALL Java_com_frank_ffmpeg_FFmpegCmd_handle
  2. (JNIEnv *env, jclass obj, jobjectArray commands){
  3. int argc = (*env)->GetArrayLength(env, commands);
  4. char **argv = (char**)malloc(argc * sizeof(char*));
  5. int i;
  6. int result;
  7. for (i = 0; i < argc; i++) {
  8. jstring jstr = (jstring) (*env)->GetObjectArrayElement(env, commands, i);
  9. char* temp = (char*) (*env)->GetStringUTFChars(env, jstr, 0);
  10. argv[i] = malloc(1024);
  11. strcpy(argv[i], temp);
  12. (*env)->ReleaseStringUTFChars(env, jstr, temp);
  13. }
  14. //执行ffmpeg命令
  15. result = run(argc, argv);
  16. //释放内存
  17. for (i = 0; i < argc; i++) {
  18. free(argv[i]);
  19. }
  20. free(argv);
  21. return result;
  22. }

好了,使用FFmpeg进行视频剪切、转码、截图、添加水印、截取GIF图等介绍完毕。如果各位有什么问题或者建议,欢迎交流。

源码:https://github.com/xufuji456/FFmpegAndroid。如果对您有帮助,麻烦fork和star。






声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/970095
推荐阅读
相关标签
  

闽ICP备14008679号