最近在做项目的时候发现,使用jwplayer播放视频会出现只有声音没有画面的情况,经过调查发现是视频的编码格式问题造成的,简单的解决方式是下载一个格式工厂,将视频格式设置为h264就可以正常播放了。如何想实现在上传的时候进行转码,请往下看。
- 首先是判断上传的视频编码格式是否是h264
- 需要使用我们的工具类jave,详细的介绍请看JAVE - Java Audio Video Encoder e Transcoder
- 下载地址JAVE - DownloadJAVE binaries and sources, licensed under the GPL.http://www.sauronsoftware.it/projects/jave/download.php
<!-- https://mvnrepository.com/artifact/it.sauronsoftware/jave --> <dependency> <groupId>it.sauronsoftware</groupId> <artifactId>jave</artifactId> <version>1.0.2</version> </dependency>
- 下载完成后,我们对源码进行进一步的扩展,在it.sauronsoftware.jave.Encoder中重载了getInfo方法,具体功能是获取视频的编码格式
public MultimediaInfo getInfo(File source, File desc) throws InputFormatException, EncoderException {
FFMPEGExecutor ffmpeg = this.locator.createExecutor();
ffmpeg.addArgument("-i");
ffmpeg.addArgument(source.getAbsolutePath());
String imagePath = "";
if (desc != null && (desc.getPath().endsWith(".jpg") || desc.getPath().endsWith(".jpeg"))) {
ffmpeg.addArgument("-y");
ffmpeg.addArgument("-f");
ffmpeg.addArgument("image2");
ffmpeg.addArgument("-ss");
ffmpeg.addArgument("1");
ffmpeg.addArgument("-t");
ffmpeg.addArgument("0.001");
ffmpeg.addArgument(desc.getAbsolutePath());
imagePath = desc.getPath();
}
try {
ffmpeg.execute();
} catch (IOException var12) {
imagePath = "";
throw new EncoderException(var12);
}
MultimediaInfo var7;
try {
RBufferedReader reader = null;
reader = new RBufferedReader(new InputStreamReader(ffmpeg.getErrorStream()));
MultimediaInfo info = this.parseMultimediaInfo(source, reader);
info.setImagePath(imagePath);
var7 = info;
} finally {
ffmpeg.destroy();
}
return var7;
}
- 然后调用该方法, sourceVideoPath指视频文件的位置
Encoder encoder = new Encoder();
String fileName = sourceVideoPath.substring(sourceVideoPath.lastIndexOf("/"));
String videoCover = fileName.substring(0, fileName.lastIndexOf("."))+".jpg";
try {
MultimediaInfo info = encoder.getInfo(new File(sourceVideoPath), new File(sourceVideoPath.substring(0, sourceVideoPath.lastIndexOf("/")) +"/changeToH264/"+videoCover));
if(info.getVideo() == null || info.getVideo().getDecoder().indexOf("h264") == -1){
System.out.println("info.getVideo().getDecoder(): "+info.getVideo().getDecoder());
}
} catch (EncoderException e) {
e.printStackTrace();
}
- 如果是h264文件,不需要转码
- 然后如果不是,进行转码
- 转码前要判断一下当前视频的类型是否支持转码,参数是视频文件的路径,如果返回值为0,代表支持转码,否则不支持,需要先将文件转为支持的类型,此处暂时没有做处理,因为项目要求只能上传MP4格式的视频
private int checkContentType(String sourceVideoPath) {
String type = sourceVideoPath.substring(sourceVideoPath.lastIndexOf(".") + 1).toLowerCase();
// ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
if (type.equals("avi")) {
return 0;
} else if (type.equals("mpg")) {
return 0;
} else if (type.equals("wmv")) {
return 0;
} else if (type.equals("3gp")) {
return 0;
} else if (type.equals("mov")) {
return 0;
} else if (type.equals("mp4")) {
return 0;
} else if (type.equals("asf")) {
return 0;
} else if (type.equals("asx")) {
return 0;
} else if (type.equals("flv")) {
return 0;
}
// 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等),
// 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.
else if (type.equals("wmv9")) {
return 1;
} else if (type.equals("rm")) {
return 1;
} else if (type.equals("rmvb")) {
return 1;
}
return 9;
}
- 如果视频支持转码,,调用process方法开始进行转码,传入视频文件和转码后的目录文件,返回转码后文件路径
private static final String FORMAT = "mp4";
private static final String VIDEO_CODE = "libx264";//视频编码格式
private static final String AUDIO_CODE = "libmp3lame";//音频编码格式
private String process(File sourceFile, File targetFile) {
int type = checkContentType(sourceFile.getPath());
if (type == 0) {
VideoAttributes videoAttributes = new VideoAttributes();
videoAttributes.setCodec(VIDEO_CODE);
videoAttributes.setBitRate(new Integer(180000));
videoAttributes.setFrameRate(new Integer(1));
AudioAttributes audio = new AudioAttributes();
audio.setCodec(AUDIO_CODE);
audio.setBitRate(new Integer(64000));
audio.setChannels(new Integer(1));
audio.setSamplingRate(new Integer(22050));
EncodingAttributes attrs1 = new EncodingAttributes();
attrs1.setVideoAttributes(videoAttributes);
attrs1.setAudioAttributes(audio);
attrs1.setFormat(FORMAT);
Encoder encoder = new Encoder();
try {
String path = targetFile.getPath();
targetFile = new File(path + File.separator + sourceFile.getName());
encoder.encode(sourceFile, targetFile, attrs1);
if (targetFile.exists()) {
return targetFile.getAbsolutePath();
}
} catch (EncoderException e) {
e.printStackTrace();
}
}
return "";
}
- 具体转码时可以设置的参数,请详见JAVE - Manual
- 可以根据返回信息判断视频是否转码成功