赞
踩
前两篇文章介绍过FFmpeg进行音频处理、音视频处理:android端采用FFmpeg进行音频混合与拼接剪切, android端采用FFmpeg进行音视频合成与分离。关于FFmpeg涉及文件导入以及cmake配置,可查看第一篇文章。现在接着探讨视频相关处理:视频转码、视频剪切、视频截图、添加水印、视频转Gif动图、图片合成视频。
视频转码包括格式、码率、尺寸大小等转换,-f代表强制转换格式,-b代表码率,-s代表尺寸,-r代表帧率:
- /**
- * 使用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";
- transformVideoCmd = String.format(transformVideoCmd, srcFile, targetFile);
- return transformVideoCmd.split(" ");//以空格分割为字符串数组
- }
视频剪切是从视频指定开始时间,剪切指定时长视频,-ss代表开始时间,-t代表时长:
- /**
- * 使用ffmpeg命令行进行视频剪切
- * @param srcFile 源文件
- * @param startTime 剪切的开始时间(单位为秒)
- * @param duration 剪切时长(单位为秒)
- * @param targetFile 目标文件
- * @return 剪切后的文件
- */
- 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(" ");//以空格分割为字符串数组
- }
视频截图是从视频截取当前一帧画面,保存为指定格式的图片,使用image2工具:
- /**
- * 使用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(" ");//以空格分割为字符串数组
- }
给视频添加水印包括:文字和图片,使用到filter_complex滤波器,overlay指定图片在视频的位置:
- /**
- * 使用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(" ");//以空格分割为字符串数组
- }
添加图片水印效果:
- /**
- * 文本转成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;
- }
添加文字水印的效果:
- /**
- * 使用ffmpeg命令行进行视频转成Gif动图
- * @param srcFile 源文件
- * @param startTime 开始时间
- * @param duration 截取时长
- * @param targetFile 目标文件
- * @return Gif文件
- */
- 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(" ");//以空格分割为字符串数组
- }
截取出来的GIF动图效果:
图片合成视频是把文件夹的有序命名图片,使用-image2合成视频,用-r指定帧率,这里指定一秒播放一帧:
- /**
- * 使用ffmpeg命令行进行图片合成视频
- * @param srcFile 源文件
- * @param targetFile 目标文件(mpg格式)
- * @return 合成的视频文件
- */
- 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(" ");//以空格分割为字符串数组
- }
由于合成的视频无法上传到这里,我使用FFmpeg把视频再转成GIF动图:
拼接好命令行后,调用FFmpeg的native方法处理:
- /**
- * 调用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://视频合并
- 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://屏幕录制
- 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处理的回调与更新界面:
- /**
- * 执行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();
- }
- });
- }
最终调用的FFmpeg的run方法:
- JNIEXPORT jint JNICALL Java_com_frank_ffmpeg_FFmpegCmd_handle
- (JNIEnv *env, jclass obj, jobjectArray commands){
- int argc = (*env)->GetArrayLength(env, commands);
- char **argv = (char**)malloc(argc * sizeof(char*));
- int i;
- int result;
- for (i = 0; i < argc; i++) {
- jstring jstr = (jstring) (*env)->GetObjectArrayElement(env, commands, i);
- char* temp = (char*) (*env)->GetStringUTFChars(env, jstr, 0);
- argv[i] = malloc(1024);
- strcpy(argv[i], temp);
- (*env)->ReleaseStringUTFChars(env, jstr, temp);
- }
- //执行ffmpeg命令
- result = run(argc, argv);
- //释放内存
- for (i = 0; i < argc; i++) {
- free(argv[i]);
- }
- free(argv);
- return result;
- }
好了,使用FFmpeg进行视频剪切、转码、截图、添加水印、截取GIF图等介绍完毕。如果各位有什么问题或者建议,欢迎交流。
源码:https://github.com/xufuji456/FFmpegAndroid。如果对您有帮助,麻烦fork和star。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。