下面展示的是通过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)"; } } }