前阵子研究了下视频转码,公司需要视频加密,虽然加密m3u8直播流的形式并不能完全阻止有心人下载视频(有心人利用第三方软件可以下载转码成mp4,或者直接录屏),但掌握技术符合公司需求就好,鉴于我只是普通后台开发人员,所以画了个最基本交互页面,如下图
解决思路:首先读取配置文件,然后根据大家的需求修改并保存,讲保存的结果注入到配置文件中,配置文件如下
ifStart=0
url=E:/scipmedresource
format=.rmvb,.flv,.mp4,.mov,.3gp,.mkv,.avi,wmv
time = 10
isDelete =0
jpgSize =420x320
returnPath =
ffmpegPath =E\:/ffmpeg/bin/ffmpeg.exe
当点击开始的时候改变ifstart的值,然后利用spring定时器,定时扫描转码加密 具体代码如下
@Scheduled(cron = "0/20 * * * * ? ")
public void toIndex() throws IOException, InterruptedException {
Properties prop = new Properties();
InputStream in = this.getClass().getClassLoader().getResourceAsStream("config.properties");
prop.load(in); // /加载属性列表
// 是否开始转码
String ifStart = prop.getProperty("ifStart");
// 文件夹路径
String url = prop.getProperty("url");
// 文件支持类型
String format = prop.getProperty("format");
// 切片时间
String time = prop.getProperty("time");
// 是否删除源文件
final String isDelete = prop.getProperty("isDelete");
// 缩略图大小
String jpgSize = prop.getProperty("jpgSize");
// 成功返回地址
String returnPath = prop.getProperty("returnPath");
// 软件路径
String ffmpegPath = prop.getProperty("ffmpegPath");
in.close();
File file = new File(url);
List<String> list = new ArrayList<String>();
if (ifStart.equals("1")) {
List<String> fileList = getAllVideo(url, file, list, format);
for (String f : fileList) {
// 创建文件夹
String mkdir = f.substring(0, f.lastIndexOf("."));
File realwatermarkDirFile = new File(mkdir);
// Check
if (!realwatermarkDirFile.exists() && !realwatermarkDirFile.isDirectory()) {
realwatermarkDirFile.mkdir();
}
String scan = f.substring(0, f.lastIndexOf(".")) + ".scan";
File scanFile = new File(scan);
if (!scanFile.exists()) {
scanFile.createNewFile();
}
// key和keyinfo文件
writeKey(mkdir);
writeKeyInfo(mkdir);
// 获取缩略图
List<String> commend = new ArrayList<String>();
commend.add(ffmpegPath);
commend.add("-i");
commend.add(f);
commend.add("-y");
commend.add("-f");
commend.add("image2");
commend.add("-ss");
commend.add("10");
commend.add("-t");
commend.add("0.001");
commend.add("-s");
commend.add(jpgSize);
commend.add(mkdir + "/1.jpg");
ProcessBuilder builder = new ProcessBuilder(commend);
builder.command(commend);
builder.start();
// 加密转码
List<String> commend1 = new ArrayList<String>();
commend1.add(ffmpegPath);
commend1.add("-i");
commend1.add(f);
commend1.add("-acodec");
commend1.add("copy");
commend1.add("-vcodec");
commend1.add("copy");
commend1.add("-c:v");
commend1.add("libx264");
commend1.add("-f");
commend1.add("hls");
commend1.add("-hls_time");
commend1.add(time);
commend1.add("-hls_list_size");
commend1.add("0");
commend1.add("-hls_key_info_file");
commend1.add(mkdir + "/key_info");
commend1.add(mkdir + "/index.m3u8");
ProcessBuilder builder1 = new ProcessBuilder(commend1);
builder1.command(commend1);
try {
final Process process = builder1.start();
// 处理InputStream的线程
new Thread() {
@Override
public void run() {
InputStream input = process.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader in = new BufferedReader(isr);
String line = null;
try {
while ((line = in.readLine()) != null) {
System.out.println("output: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
isr.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
@Override
public void run() {
InputStream input = process.getErrorStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader err = new BufferedReader(isr);
String line = null;
try {
while ((line = err.readLine()) != null) {
System.out.println("err: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
err.close();
isr.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
process.waitFor();
if (isDelete.equals("1")) {
String scan1 = f.substring(0, f.lastIndexOf(".")) + ".scan";
File fileScan = new File(scan1);
if (fileScan.exists()) {
fileScan.delete();
}
boolean result = false;
int i = 0;
while (!result) {
i++;
File gcFile = new File(f);
result = gcFile.delete();
System.gc();
if (result) {
System.out.println("第" + i + "次为:" + result);
}
}
}
if (!returnPath.equals("")) {
// 根据地址获取请求
HttpGet request = new HttpGet(returnPath + "?name=" + f);// 这里发送get请求
// 获取当前客户端对象
HttpClient httpClient = new DefaultHttpClient();
// 通过请求对象获取响应对象
HttpResponse response = httpClient.execute(request);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private static List<String> getAllVideo(String url, File file, List<String> list, String format) {
String[] filelist = file.list();
String[] formats = format.split(",");
for (int i = 0; i < filelist.length; i++) {
File readfile = new File(url + "\\" + filelist[i]);
if (!readfile.isDirectory()) {
for (String f : formats) {
if (readfile.getName().indexOf(f) > -1) {
String scan = readfile.getAbsolutePath().substring(0, readfile.getAbsolutePath().lastIndexOf("."));
scan += ".scan";
File fileScan = new File(scan);
if (!fileScan.exists()) {
list.add(readfile.getAbsolutePath());
}
break;
}
}
} else {
getAllVideo(readfile.getPath(), readfile, list, format);
}
}
return list;
}
/**
* 生成key
*
* @author 李禚
* @date 2017-10-18上午11:28:44
*/
private static void writeKey(String mkdir) throws IOException {
FileOutputStream fos = null;
PrintWriter pw = null;
File file = new File(mkdir + "\\" + "key.key");// 文件路径(包括文件名称)
// 将文件读入输入流
StringBuffer buffer = new StringBuffer();
buffer.append(getStringRandom(16));
// buffer.append("3aa1c008d8effdbc");
try {
fos = new FileOutputStream(file);
pw = new PrintWriter(fos);
pw.write(buffer.toString().toCharArray());
pw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (pw != null) {
pw.close();
}
if (fos != null) {
fos.close();
}
}
}
/**
* 生成keyinfo
*
* @author 李禚
* @date 2017-10-18上午11:28:22
*/
private static void writeKeyInfo(String mkdir) throws IOException {
FileOutputStream fos = null;
PrintWriter pw = null;
File file = new File(mkdir + "\\" + "key_info");// 文件路径(包括文件名称)
// 将文件读入输入流
StringBuffer buffer = new StringBuffer();
buffer.append("key.key\n");
buffer.append(mkdir + "\\key.key");
try {
fos = new FileOutputStream(file);
pw = new PrintWriter(fos);
pw.write(buffer.toString().toCharArray());
pw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (pw != null) {
pw.close();
}
if (fos != null) {
fos.close();
}
}
}
/**
* 生成16位字母和数字
*
* @author 李禚
* @date 2017-10-18上午11:26:03
*/
private static String getStringRandom(int length) {
String val = "";
Random random = new Random();
// 参数length,表示生成几位随机数
for (int i = 0; i < length; i++) {
String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
// 输出字母还是数字
if ("char".equalsIgnoreCase(charOrNum)) {
// 小写字母
int temp = 97;
val += (char) (random.nextInt(26) + temp);
} else if ("num".equalsIgnoreCase(charOrNum)) {
val += String.valueOf(random.nextInt(10));
}
}
return val;
}
具体参数含义可以查看ffmepg官方网站http://ffmpeg.org/
ok加密转码服务搞定,如有疑问或问题请多多指教