利用ffmpeg处理视频并提取缩略图和视频详情


为了满足视频的编辑以及视频基本信息的获取,需要在你的gradle中引入: 

 implementation 'com.github.microshow:RxFFmpeg:2.2.0'
 implementation 'com.yyl.ffmpeg:ffmpeg_cmd:4.1.3'

以及在你的app gradle文件中的defaultConfig{}下添加:
     ndk {
            abiFilters "armeabi-v7a", "arm64-v8a"
         }
这样你就可以正式开始你的ffmpeg视频剪辑之路了。其实两个框架都可以单独使用,只不过结合我自己的实际问题,我把这两个框架都列举出来了。

ffmpeg的命令有有两种:ffprobe 和 ffmpeg
ffprobe命令主要用于获取视频文件流的信息,例如编码格式、时间长度、帧数、视频的长宽等信息。而ffmpeg是对视频进行编辑的命令,例如裁剪、剪辑等。

而RxFFmpeg好像对ffprobe命令不感冒,不是信口胡诌,是这个家伙确实让我吃了不少苦头,下面我结合实际情况讲述一下。

首先列举一下相关功能:
 1. 获取视频的元数据信息:包括时长、帧数、宽、高、码率、编码格式(用于判断从图库中挑选的视频文件是否符合要求(分辨率大小、编码方式是否为H264、码率是否满足))
 
 RxFfmpeg框架:
 
 String videoInfo = RxFFmpegInvoke.getInstance().getMediaInfo(filePath);
 
 对于该方法我只能说绝对很坑,Android5.1以下版本只要调用该方法大概率崩溃,Android5.1以上也会造成一定的影响,系统版本越低应该越明显,我在这上面浪费了很多时间,因为每次崩溃我都看到了内存不够的相关信息:real_molloc什么东西,可能比较吃内存,刚开始真的不知道是这的问题一直以为是Camera的问题。如果你非要使用,给你提供点便利:
视频信息内容 major_brand=isom; 以这样的形式存在,所以我直接列举几个关键信息的键值:
 videostream_avcodocname 视频的编码格式
 bit_rate   视频的码率
 videostream_codecpar_width   视频的宽
 videostream_codecpar_height  视频的高
 videostream_nb_frames   视频的总帧数
 duration    视频时长

ffmpeg_cmd框架:
public static String getVideoInfo(String inputFile) {
        return "ffprobe -v quiet -select_streams video -print_format json -show_format -show_streams " + inputFile;
}
String command = FfmpegCommandUtils.getVideoInfo(filePath);  
String json = FFmpegUtils.getInstance().execffprobe(command);

这两个框架都值得注意的是,从手机图库中获取的视频文件名可能带有空格,但是ffmpeg命令,对于**文件名有空格的视频**视频文件不能忍,所以记得写一个方法,把文件重新命名,然后把新的名称传递给ffmpeg命令。
renameFile(filePath, filePath.replace(" ", ""))
 
 2. 剪切:扣视频(視頻尺寸),裁减:截取视频(按時間段截取),视频编码:将视频进行硬编码变成H264格式的视频
 	a.ffmpeg命令:視頻尺寸的裁剪
 	public static String cropCommand(String inputFile, String outputFile, int width, int height, int x, int y) {
        String command_source = "ffmpeg -y -i " + inputFile + " -vf crop=%d:%d:%d:%d " + outputFile;
        return String.format(command_source, width, height, x, y);
    }
 	
 	b.ffmpeg命令:按照時間段截取視頻:
 	 public static String trimCommand(String inputFile, String outputFile, long startPos, long endPos) {
        String command_source = "ffmpeg -y -i %s -ss %d -t %d %s";
        String command = String.format(command_source, inputFile, startPos / 1000, (endPos - startPos) / 1000, outputFile);
        return command;
    }
    
   c.ffmpeg命令:編碼為H264編碼格式的視頻文件
   public static String decodeH264(String inputFile, String outputFile) {
        return "ffmpeg -i " + inputFile + " -vcodec h264 " + outputFile;
    }

 3. 创建视频时间轴,通过时间轴预览视频。
 	a.ffmpeg命令:提取视频缩略图,按照一秒n张的频率,由于图片是多张,所以文件名以“%03d”的形式表示,  -s 90x160 表示最终提取的图片大小,可以自由定义;-y 表示覆盖,即存在该文件名的文件直接覆盖;-r 表示帧率 即 一秒中提取的图片数量。
    public static String thumbVideoByTime(String filePath, double fps, String outputFile) {
        return "ffmpeg -i " + filePath + " -y -f image2 -r " + fps + " -s 90x160 " + outputFile + "_img%03d.jpg";
    }

  b.ffmpeg命令:将视频进行镜像处理,在找到视频边录制边镜像处理之前用的是这种方法,但是太费时间,最后放弃。
  public static String mirrorVideo(String inputPath, String outputFile) {
        return "ffmpeg -i " + inputPath + " -vf hflip " + outputFile;
  }

 c.ffmpeg命令:按照帧间隔截取视频(参看:[获取视频间隔缩略图](https://stackoverflow.com/questions/32043680/ffmpeg-select-frames-at-position-of-video)public static String trimFrameVideo(String inputFile, long deltaFrame, int countFrame, String outputFile) {
        return "ffmpeg -i " + inputFile + " -vf select=between(n\\,0\\," + countFrame + ")*not(mod(n\\," + deltaFrame + ")) -vsync 0 -s 90x160 " + outputFile + "_img%03d.jpg";
    }

d.ffmpeg命令:按照时间间隔截取视频
public static String trimTimeVideo(String inputFile, double deltaTime, String outputFile) {
        return "ffmpeg -i " + inputFile + " -filter:v select=(gte(t\\," + deltaTime + "))*(isnan(prev_selected_t)+gte(t-prev_selected_t\\," + deltaTime + ")) -frames:v 1 -y -s 90x160 " + outputFile + "_img%03d.jpg";
    }


猜你喜欢

转载自blog.csdn.net/qq_35920289/article/details/107566135