最近要用到视频压缩功能。通过搜索发现了ffmpeg,javacv,这两个是比较主流的流媒体组件,但是研究下来发现,如果仅仅是需要视频压缩的话,那么就有点大材小用了。FFmpeg是C语言开发的,对于我们java来说有点难了,而javacv是java语言写的,源码读起来还容易上手,但是由于这两个组件功能较多,就被作者放弃了,最后找到了另外一个小众的工具
JAVE
。
JAVE简介
- 简单的说,JAVE是对ffmege进行了简单的封装,只提供了视频和音频的转码功能。(视频转码(Video Transcoding)是指将已经压缩编码的视频码流转换成另一个视频码流,以适应不同的网络带宽、不同的终端处理能力和不同的用户需求。转码本质上是一个先解码,再编码的过程)所以如果你需要视频压缩的话,那么这个组件是最好的选择。
- JAVE官网
- JAVE的jar包和压缩demo: 本示例代码和jar
package tomatocc.zip;
/**
* @author tomatocc
* @email 553866242@qq.com
* @desc
*
* 比特率是指将模拟声音信号转换成数字声音信号后,单位时间内的二进制数据量,比特率越大的音质就越好(在相同的编码格式下,不同格式,无法比较)。
* 作为一种数字音乐压缩效率的参考性指标,比特率表示单位时间(1秒)内传送的比特数bps(bit per second,位/秒)的速度。
* 通常使用kbps(通俗地讲就是每秒钟1000比特)作为单位。
* CD中的数字音乐比特率为1411.2kbps(也就是记录1秒钟的cd音乐,需要1411.2×1000比特的数据),音乐文件的BIT RATE高是意味着在单位时间(1秒)内需要处理的数据量(BIT)多,也就是音乐文件的音质好的意思。
* 但是,BIT RATE高时文件大小变大,会占据很多的内存容量,音乐文件最常用的bit rate是128kbps,MP3文件可以使用的一般是8-320kbps,但不同MP3机在这方面支持的范围不一样,大部分的是32-256Kbps,这个指数当然是越广越好了,不过320Kbps是暂时最高等级了。
*/
import java.io.File;
import it.sauronsoftware.jave.*;
public class VideoZip {
public static void main(String[] args) {
// 压缩前文件路径
File source = new File("D:/video/000.mp4");
// 压缩后的文件路径
File target = new File("D:/video/test000.mp4");
try {
long start = System.currentTimeMillis();
System.out.println("begin");
// 音频编码属性配置
AudioAttributes audio= new AudioAttributes();
audio.setCodec("libmp3lame");
// 比特率越高,清晰度/音质越好
audio.setBitRate(new Integer(56000));//设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 56000 = 56kb)
audio.setChannels(new Integer(1));// 设置重新编码的音频流中使用的声道数(1 =单声道,2 = 双声道(立体声))。如果未设置任何声道值,则编码器将选择默认值 0。
// 采样率越高声音的还原度越好,文件越大
audio.setSamplingRate(new Integer(44100));//设置音频采样率,单位:赫兹 hz
// 设置编码时候的音量值,未设置为0,如果256,则音量值不会改变
// audio.setVolume();
// 视频编码属性配置
VideoAttributes video=new VideoAttributes();
video.setCodec("mpeg4");
// 比特率越高,清晰度/音质越好
video.setBitRate(new Integer(56000));//设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 5600000 = 5600kb)
// 视频帧率:15 f / s 帧率越低,效果越差
video.setFrameRate(new Integer(15));// 设置视频帧率(帧率越低,视频会出现断层,越高让人感觉越连续),视频帧率(Frame rate)是用于测量显示帧数的量度。所谓的测量单位为每秒显示帧数(Frames per Second,简:FPS)或“赫兹”(Hz)。
// 编码设置
EncodingAttributes attr=new EncodingAttributes();
attr.setFormat("mp4");
attr.setAudioAttributes(audio);
attr.setVideoAttributes(video);
// 设置值编码
Encoder encoder = new Encoder();
encoder.encode(source, target, attr);
System.out.println("end");
long end = System.currentTimeMillis();
System.out.println("压缩前大小: "+source.length() + " 压缩后大小:" + target.length());
System.out.println("压缩耗时: " + (end -start));
} catch (Exception e) {
e.printStackTrace();
}
}
}
* 经验总结:
* 1.如果压缩前的视频时长很短,但是文件很大,比如4秒钟,10m,那么压缩的时候视频的比特率必须要设置很大,才能保证压缩后的视频失真度较少,否则压缩后的视频会很模糊。
* 2.如果你用压缩4秒钟,10m文件大小的压缩参数,区压缩1分钟10兆的视频,那么你会发现压缩后的视频竟然变大了!!!!
* 这个原因是由于两个文件大小相差不大,但是时长却相差很大,如果你查看这两个视频的比特率信息就会发现。4秒钟的那个文件比特率可能是1分钟那个文件的10倍以上!!
* 这样,我们可以得到结论,那就是在压缩的时候,比特率应该是一个变量,而这个变量应该跟时长,原文件比特率相关,这
* 里我建议先获得源文件的视频比特率,然后在进行减少其数值,以达到压缩目的。
获取视频文件信息
File source = new File("D:/video/8.mp4");
File target = new File("D:/video/test00088.mp4");
Encoder encoder = new Encoder();
MultimediaInfo info = encoder.getInfo(source);
AudioInfo sourceAudio = info.getAudio();
System.out.println(sourceAudio.getBitRate() + " -- " +sourceAudio.getChannels() + " -- " + sourceAudio.getSamplingRate() + " -- " +sourceAudio.getDecoder() );
VideoInfo sourceVideo = info.getVideo();
JAVE升级版,适用于安卓手机视频压缩
上面的版本,尽管可以压缩。但是如果压缩安卓手机拍摄后的视频的话。会出现视频方向旋转90度的问题。具体原因是由于安卓手机视频编码为yuv420p的问题。针对这个问题,本人又找到了一个升级版的jave->jave
2
- JAVE2开源地址
- JAVE2的jar包和压缩demo: 本示例代码用到的jar
package tomatocc.java2;
import ws.schild.jave.*;
import java.io.File;
/**
* @author tomatocc
* @email 553866242@qq.com
* @desc
*/
public class Jave2 {
public static void main(String[] args) {
// 压缩前文件路径
File source = new File("D:/video/000.mp4");
// 压缩后的文件路径
File target = new File("D:/video/comp000.mp4");
compre(source,target,1);
}
/**
* 视频压缩
* @param source 源文件
* @param target 目标文件
* @param rate 压缩比
*/
public static void compre(File source , File target , Integer rate) {
try {
System.out.println("begin");
long start = System.currentTimeMillis();
// 音频编码属性配置
AudioAttributes audio= new AudioAttributes();
audio.setCodec("libmp3lame");
// 设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 56000 = 56kb)
audio.setBitRate(new Integer(56_000));
// 设置重新编码的音频流中使用的声道数(1 =单声道,2 = 双声道(立体声))
audio.setChannels(1);
// 采样率越高声音的还原度越好,文件越大
audio.setSamplingRate(new Integer(44100));
// 视频编码属性配置
VideoAttributes video=new VideoAttributes();
// 设置编码
video.setCodec("mpeg4");
//设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 5600000 = 5600kb)
video.setBitRate(new Integer(5_600_000 / rate));
// 设置视频帧率(帧率越低,视频会出现断层,越高让人感觉越连续),这里 除1000是为了单位转换
video.setFrameRate(new Integer(15));
// 编码设置
EncodingAttributes attr=new EncodingAttributes();
attr.setFormat("mp4");
attr.setAudioAttributes(audio);
attr.setVideoAttributes(video);
// 设置值编码
Encoder ec = new Encoder();
ec.encode(new MultimediaObject(source), target, attr);
System.out.println("end");
long end = System.currentTimeMillis();
System.out.println("压缩前大小: "+source.length() + " 压缩后大小:" + target.length());
System.out.println("压缩耗时: " + (end -start));
} catch (EncoderException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
欢迎关注本人个人公众号,交流更多技术信息