vlambda博客
学习文章列表

【视频压缩】全网最好用的JAVA视频压缩(附代码)


【视频压缩】全网最好用的JAVA视频压缩(附代码)


最近要用到视频压缩功能。通过搜索发现了ffmpeg,javacv。这两个是比较主流的流媒体组件。但是研究下来发现。如果仅仅是需要视频压缩的话,那么就有点大材小用了。FFmpeg是C语言开发的,对于我们java来说使用起来有点难,而javacv是java语言写的,源码读起来还容易上手,但是由于这两个组件功能较多,就被作者放弃了。最后找到了另外一个小众的工具JAVE,这也是本文推荐的技术。


前言

在了解视频压缩之前,首先要先了解几个流媒体领域的专业词汇,因为下面这些参数你都会要用到。

1.视频转码

  视频转码(Video Transcoding)是指将已经压缩编码的视频码流转换成另一个视频码流,以适应不同的网络带宽、不同的终端处理能力和不同的用户需求。转码本质上是一个先解码,再编码的过程,因此转换前后的码流可能遵循相同的视频编码标准,也可能不遵循相同的视频编码标准。

                                                                                         ——摘自:百度百科

2.比特率

    比特率是指每秒传送的比特(bit)数。单位为 bps(Bit Per Second),比特率越高,每秒传送数据就越多,画质就越清晰。声音中的比特率是指将模拟声音信号转换成数字声音信号后,单位时间内的二进制数据量,是间接衡量音频质量的一个指标。视频中的比特率(码率)原理与声音中的相同,都是指由模拟信号转换为数字信号后,单位时间内的二进制数据量。

                                                                                     ——摘自:百度百科

3.采样频率

    采样频率,也称为采样速度或者采样率,定义了每秒从连续信号中提取并组成离散信号的采样个数,它用赫兹(Hz)来表示。采样频率的倒数是采样周期或者叫作采样时间,它是采样之间的时间间隔。通俗的讲采样频率是指计算机每秒钟采集多少个信号样本

                                                                                     ——摘自:百度百科


4.视频帧率

    视频帧率(Frame rate)是用于测量显示帧数的量度。所谓的测量单位为每秒显示帧数(Frames per Second,简:FPS)或“赫兹”(Hz)。此词多用于影视制作和电子游戏。

                                                                                     ——摘自:百度百科



正文

在了解了上面几个流媒体领域的专业名词后,接下来就进入正题:视频压缩


视频压缩

JAVE简介

简单的说,JAVE是对ffmege进行了简单的封装,只提供了视频和音频的转码功能。(视频转码(Video Transcoding)是指将已经压缩编码的视频码流转换成另一个视频码流,以适应不同的网络带宽、不同的终端处理能力和不同的用户需求。转码本质上是一个先解码,再编码的过程)所以如果你需要视频压缩的话,那么这个组件是最好的选择。

官网:http://www.sauronsoftware.it/projects/jave/manual.php


package tomatocc.zip;
/** * @author tomatocc * @email [email protected] * @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倍以上!! * 这样,我们可以得到结论,那就是在压缩的时候,比特率应该是一个变量,而这个变量应该跟时长,原文件比特率相关,这 * 里我建议先获得源文件的视频比特率,然后在进行减少其数值,以达到压缩目的。


上面的转码参数都是写死的,感觉不是很友好。jave也提供了获取源视频参数信息的方法,我们可以在获取源参数后,对参数按照一定比例进行修改,这样会更灵活的进行压缩。

package tomatocc.zip;
import it.sauronsoftware.jave.*;
import java.io.File;
/** * @author tomatocc * @email [email protected] * @desc */public class TestThree {
public static void main(String[] args) throws EncoderException { 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();
System.out.println(sourceVideo.getBitRate() + " -- " + sourceVideo.getFrameRate() + " -- " + sourceVideo.getDecoder() + " -- " + sourceVideo.getSize().getHeight()); long duration = info.getDuration();// 视频时长(毫秒) System.out.println(duration);
String format = info.getFormat(); System.out.println(format);

// 音频编码属性配置 AudioAttributes audio= new AudioAttributes(); audio.setCodec("libmp3lame"); // 比特率越高,清晰度/音质越好 audio.setBitRate(sourceAudio.getBitRate());//设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 56000 = 56kb) audio.setChannels(sourceAudio.getChannels());// 设置重新编码的音频流中使用的声道数(1 =单声道,2 = 双声道(立体声))。如果未设置任何声道值,则编码器将选择默认值 0。 // 采样率越高声音的还原度越好,文件越大 audio.setSamplingRate(sourceAudio.getSamplingRate());//设置音频采样率,单位:赫兹 hz // 设置编码时候的音量值,未设置为0,如果256,则音量值不会改变
// 视频编码属性配置 VideoAttributes video=new VideoAttributes(); video.setCodec("mpeg4"); // 比特率越高,清晰度/音质越好 video.setBitRate(sourceVideo.getBitRate() * 100);;//设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 56000 = 56kb) // 视频帧率:15 f / s 帧率越低,效果越差 int i = Math.round(sourceVideo.getFrameRate()); video.setFrameRate(new Integer(15));// 设置视频帧率(帧率越低,视频会出现断层,越高让人感觉越连续),视频帧率(Frame rate)是用于测量显示帧数的量度。所谓的测量单位为每秒显示帧数(Frames per Second,简:FPS)或“赫兹”(Hz)。
video.setSize(sourceVideo.getSize());

// 编码设置 EncodingAttributes attr=new EncodingAttributes(); attr.setFormat("mpegvideo"); attr.setAudioAttributes(audio); attr.setVideoAttributes(video);

// 设置值编码 Encoder ec = new Encoder(); ec.encode(source, target, attr);
}}

视频压缩升级版:JAVE2

上面的版本,尽管可以压缩。但是如果压缩安卓手机拍摄后的视频的话。会出现视频方向旋转90度的问题。具体原因是由于安卓手机视频编码为yuv420p的问题。针对这个问题,本人又找到了一个升级版的jave->jave2

jave2官网

https://github.com/a-schild/jave2


package tomatocc.java2;


import ws.schild.jave.*;
import java.io.File;
/** * @author tomatocc * @email [email protected] * @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(); }
}}


写在最后的话




解锁更多精彩内容