浏览器的video标签,只支持部分编码格式的视频播放,由于客户的视频编码各不相同,所以需要通过后端帮忙转码成统一的编码。记录一下通过 ffmpeg 工具解决视频编码问题。
首先下载ffmpeg工具,下载windows版本的,地址:https://ffmpeg.zeranoe.com/builds/
这个builds版本自动很多编码器,通过ffmpeg命令可以看到
使用windows版是因为在Linux上折腾很久,编码器没有安装成功,所以就放弃了,在windows上通过Kafka弄了个视频转码服务。
命令参数:http://www.mikewootc.com/wiki/sw_develop/multimedia/ffmpeg_app_param.html (找了很多,这是比较全的参数说明)
以下是视频解码的工具类,功能是将视频转码成视频编码为 H.264,音频编码为 aac,是为了支持video标签,直接在浏览器播放,其他参数是为了压缩视频大小:
package com.spider.culture.process;
import java.util.ArrayList;
import java.util.List;
import com.spider.culture.util.Logger;
/**
* 关于moov在前的说明
* 一、关于chrome的快速播放和拖拽
* 1、chrome使用H5的video标签来播放
* 2、chrome很智能,如果读取MP4文件,发现moov box不在文件前部,会直接读取MP4的文件尾部,加载moov box
* 3、拖拽时,chrome根据moov box得到的关键帧的字节偏移量,采用range请求来请求
* 二、关于Flash
* 1、Flash如果读取MP4文件,发现moov box不在文件前部,不会直接读取MP4的文件尾部去寻找moov box,所以Flash要等文件全部下载完,取到文件尾部的moov头,才可以正常播放。
* @author spider
*
*/
public class TransCodec {
/**
* 视频转码 (PC端MP4)
* @param ffmpegPath 转码工具的存放路径
* @param upFilePath 用于指定要转换格式的文件,要截图的视频源文件
* @param codcFilePath 格式转换后的的文件保存路径
* @return
* @throws Exception
*/
public static boolean exchangeToMp4(String ffmpegPath,String upFilePath, String codcFilePath) {
// 创建List集合来保存转换视频文件为flv格式的命令
List<String> convert = new ArrayList<String>();
convert.add(ffmpegPath); // 添加转换工具路径
convert.add("-y"); // 该参数指定将覆盖已存在的文件
convert.add("-i"); //输入文件
convert.add(upFilePath);
convert.add("-c:v"); //视频
convert.add("libx264"); //视频编码格式
convert.add("-c:a"); //音频编码格式
convert.add("aac");
convert.add("-strict"); //FFmpeg自带的aac音频编码要带上-strict -2 参数
convert.add("-2");
convert.add("-pix_fmt"); //像素格式
convert.add("yuv420p");
convert.add("-movflags"); //moov头在前
convert.add("faststart");
convert.add("-s"); //屏幕大小
convert.add("320x240");
convert.add("-b:v"); //视频比特率 值越小文件越小(单位b/s)
convert.add("262144"); //262144 = 256*1024 bit/s
convert.add("-b:a"); //音频比特率(单位b/s)
convert.add("131072"); //131072 = 1024*128 bit/s
convert.add("-ac"); //音频通道
convert.add("2");
convert.add("-ar"); //音频采样率
convert.add("44100");
//convert.add("-vf"); // 添加水印
//convert.add("movie=watermark.gif[wm];[in][wm]overlay=20:20[out]");
convert.add(codcFilePath); //输出文件
boolean mark = true;
try {
// redirectErrorStream(true) 标准错误将与标准输出合并,使得关联错误消息和相应的输出变得更容易
Process videoProcess = new ProcessBuilder(convert).
redirectErrorStream(true).start();
// 合并的数据可从 Process.getInputStream() 返回的流读取
new PrintStream(videoProcess.getInputStream()).start();
// 加上这句,系统会等待转换完成。不加,就会在服务器后台自行转换。
// 但是后期测试一直报错,ffmpeg卡住,无法转换,线程也在一直等待
// videoProcess.waitFor();
} catch (Exception e) {
mark = false;
Logger.error(String.format("视频%s编码转换出错", upFilePath),e);
}
return mark;
}
}
/**
* 视频转换过程
* @author spider
*
*/
class PrintStream extends Thread{
java.io.InputStream __is = null;
public PrintStream(java.io.InputStream is)
{
__is = is;
}
public void run()
{
try
{
while(this != null)
{
int _ch = __is.read();
if(_ch != -1)
System.out.print((char)_ch);
else break;
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
网友评论