下面展示的是通过M3U8地址,把这个地址转为一个视频文件;只是一个基本案例,当然,有些下载的M3U8文件里面格式是不一样的,还有的是加过密的,道理都是一个道理。
开始
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.io.IOUtils;
/**
* 根据M3U8地址下载视频
* IOUtils.copyLarge 需要引入commons.io包
*
* java.version 1.7
*/
public class M3U8Downloader {
/** m3u8地址 */
private static String url = "http://playertest.longtailvideo.com/adaptive/bipbop/gear4/prog_index.m3u8";
/** 正式文件存储地址(合并之后的文件) */
private static String tofile = "E:\\m3u8\\Movie.ts";
/** 临时文件存储地址(M3U8视频段) */
private static String tofileTemp = "E:\\m3u8\\temp";
private static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws IOException, InterruptedException {
//解析M3U8地址为对象
M3U8 m3u8 = parseIndex(url);
//根据M3U8对象获取时长
float duration = getDuration(m3u8);
System.out.println("时长: " + ((int) duration / 60) + "分" + (int) duration % 60 + "秒");
//根据M3U8对象下载视频段
download(m3u8, tofileTemp);
//关闭线程池
executor.shutdown();
System.out.println("等待下载中...");
while (!executor.isTerminated()) {
Thread.sleep(100);
}
//合并文件
merge(m3u8, tofile, tofileTemp);
System.out.println("下载完成,合并的文件在: " + tofile);
}
/**
* 根据M3U8对象获取时长
* @param m3u8
* @return
*/
private static float getDuration(M3U8 m3u8){
float duration = 0;
for (M3U8Ts ts : m3u8.getTsList()) {
duration += ts.getSeconds();
}
return duration;
}
/**
* 合并文件
* @param m3u8
* @param tofile
* @throws IOException
*/
public static void merge(M3U8 m3u8, String tofile, String tofileTemp) throws IOException {
File file = new File(tofile);
FileOutputStream fos = new FileOutputStream(file);
File fileTempDir = new File(tofileTemp);
for (File fileTemp : fileTempDir.listFiles()) {
IOUtils.copyLarge(new FileInputStream(fileTemp), fos);
}
fos.close();
}
/**
* 根据M3U8对象下载视频段
* @param m3u8
* @param tofile
* @throws IOException
*/
public static void download(final M3U8 m3u8, final String tofileTemp) throws IOException {
final File dir = new File(tofileTemp);
if (!dir.exists()) {
dir.mkdirs();
}
for (final M3U8Ts ts : m3u8.getTsList()) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
FileOutputStream writer = new FileOutputStream(new File(dir, ts.getFile()));
IOUtils.copyLarge(new URL(m3u8.getBasepath() + ts.getFile()).openStream(), writer);
writer.close();
System.out.println("视频段: " + ts + "下载完成");
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
/**
* 解析M3U8地址为对象
* @param url M3U8地址
*/
static M3U8 parseIndex(String url) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()));
String basepath = url.substring(0, url.lastIndexOf("/") + 1);
M3U8 ret = new M3U8();
ret.setBasepath(basepath);
String line;
float seconds = 0;
while ((line = reader.readLine()) != null) {
if (line.startsWith("#")) {
if (line.startsWith("#EXTINF:")) {
line = line.substring(8);
if (line.endsWith(",")) {
line = line.substring(0, line.length() - 1);
}
if (line.contains(",")) {
line = line.substring(0, line.indexOf(","));
}
seconds = Float.parseFloat(line);
}
continue;
}
if (line.endsWith("m3u8")) {
return parseIndex(basepath + line);
}
ret.addTs(new M3U8Ts(line, seconds));
seconds = 0;
}
reader.close();
return ret;
}
static class M3U8 {
private String basepath;
private List<M3U8Ts> tsList = new ArrayList<M3U8Ts>();
public String getBasepath() {
return basepath;
}
public void setBasepath(String basepath) {
this.basepath = basepath;
}
public List<M3U8Ts> getTsList() {
return tsList;
}
public void setTsList(List<M3U8Ts> tsList) {
this.tsList = tsList;
}
public void addTs(M3U8Ts ts) {
this.tsList.add(ts);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("basepath: " + basepath);
for (M3U8Ts ts : tsList) {
sb.append("\nts: " + ts);
}
return sb.toString();
}
}
static class M3U8Ts {
private String file;
private float seconds;
public M3U8Ts(String file, float seconds) {
this.file = file;
this.seconds = seconds;
}
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
public float getSeconds() {
return seconds;
}
public void setSeconds(float seconds) {
this.seconds = seconds;
}
@Override
public String toString() {
return file + " (" + seconds + "sec)";
}
}
}