JAVA获取视频(TS类型)

JAVA获取视频(TS类型)

在爬取视频的时候有的时候会碰到m3u8格式的视频,这种类型的视频是通过一个个片段进行播放。

1.这种视频(https://ifeng.com-v-ifeng.com/20180716/21960_f0f836f8/index.m3u8)直接去访问的时候会显示如下图所示文件。

第一次访问所获得内容

2.所获得的内容中有“1000k/hls/index.m3u8”这样一行,发现这个正好是视频中第一个请求的地址,根据这个地址再访问(https://ifeng.com-v-ifeng.com/20180716/21960_f0f836f8/1000k/hls/index.m3u8),便可获得每个片段的地址,我们可以通过访问这些片段进行下载,最后合成视频。

 

再次访问所获得内容

具体代码如下

package Test.Write;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
 *  
 * 获取视频(MP4类型)
 * @author Zzh
 *
 */
public class CatchVideo2 {

	/** 视频名称*/
	private static String videoName;

	/** 视频前缀*/
	private static String videoPathPrefix;
	
	/** 设置日期格式*/
	private static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	/**
	 * 主程序
	 * @param args
	 */
	public static void main(String[] args) {
		
		System.out.println(df.format(new Date()) + ":开始准备下载。");
		// 地址集
		List<String> downLoadUrls = new ArrayList<String>();
		// 视频的主页面
		String htmlmain = getHtml("http://www.yhdm.tv/show/1014.html");
		// 获取每集页面的地址
		List<String> urls = parseHtmlMain(htmlmain);

		String mainurl = "http://www.yhdm.tv";
		for (String url : urls) {
			// 每集真正播放地址
			String html = getHtml(mainurl + url);
			String downLoadUrl = parseHtml(html);
			downLoadUrls.add(downLoadUrl);
		}

		httpDownload(downLoadUrls);
	}

	/**
	 * 获取网页html代码
	 * @param 网址
	 */
	private static String getHtml(String path){

		System.out.println(df.format(new Date()) + ":获取" + path + "页面代码。");
		// 保存整个html文档的数据
		StringBuffer html = new StringBuffer();

		try {
			// 发起一个url网址的请求
			URL url = new URL(path);
			URLConnection connection = url.openConnection();

			// 获取网页的数据流
			InputStream input = connection.getInputStream();                 
			InputStreamReader reader = new InputStreamReader(input, "UTF-8");  
			BufferedReader bufferedReader = new BufferedReader(reader);  
			// 解析并且获取InputStream中具体的数据,并且输出到控制台
			String line = "";
			while((line = bufferedReader.readLine()) != null)
			{
				// 将所有读到的每行信息line追加到(拼接到)html对象上
				html.append(line); 
			}

		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return html.toString();
	}

	/**
	 * 获取集数
	 * @param HTML内容
	 * @return 视频地址
	 */
	private static List<String> parseHtmlMain(String html) {
		
		System.out.println(df.format(new Date()) + ":获取集数。");
		Document document = Jsoup.parse(html);
		// 获取id为main0的元素
		Element main = document.getElementById("main0");
		Elements urlLinks = main.getElementsByTag("a");
		List<String> urls = new ArrayList<String>();
		// 每集地址添加
		for (Element urlLink : urlLinks) {
			String name = urlLink.html();
			if (name.contains("CM") || name.contains("PV")) {
				continue;
			}
			urlLink.attr("href");
			urls.add(urlLink.attr("href"));
		}
		Elements videoNameH1= document.getElementsByTag("h1");
		// 视频名
		videoName = videoNameH1.get(0).text().replace(":", "").replace("/", "")
				.replace("\\", "").replace("*", "").replace("?", "")
				.replace("|", "").replace("<", "").replace(">", "");

		return urls;
	}

	/**
	 * 解析HTML
	 * @param HTML内容
	 * @return 视频地址
	 */
	private static String parseHtml(String html) {
		Document document = Jsoup.parse(html);
		Element dplayer = document.getElementById("play_1");
		String videoUrl = dplayer.attr("onclick");
		videoUrl = videoUrl.replace("changeplay('", "");
		videoUrl = videoUrl.replace("$mp4');", "");

		return videoUrl;
	}

	/**
	 * 下载视频
	 * @param 视频地址集
	 */
	public static boolean httpDownload(List<String> httpUrls) {

		// 设置路径
		String saveFile = "D:\\视频\\" + videoName;
		String saveFileVideo = "D:\\视频\\" + videoName +"\\" + videoName;
		System.out.println(df.format(new Date()) + ":地址集获取完毕准备开始下载。");
		int i = 0;
		
		for (String httpUrl : httpUrls) {
			// 合成用MAP
			HashMap<Integer, String> keyFileMap = new HashMap<Integer, String>();
			// 下载索引文件
			String indexStr = getIndexFile(httpUrl);
			// 解析索引文件
			List<String> videoUrlsList = analysisIndex(indexStr);
			i++;
			int j = 0;
			for (String videoUrl : videoUrlsList) {
				try {
					j++;
					int byteRead;
					URL url;
					// 创建文件
					File file = new File(saveFile);
					if(!file.exists()){
						file.getParentFile().mkdir();
						file.mkdirs();
					}
					
					File fileVideo = new File(saveFileVideo);
					if(!fileVideo.exists()){
						fileVideo.getParentFile().mkdir();
						fileVideo.mkdirs();
					}

					try {
						url = new URL(videoPathPrefix + videoUrl);
					} catch (MalformedURLException e1) {
						e1.printStackTrace();
						continue;
					}

					try {

						// 写入文件
						String st_saveFilename = "";
						st_saveFilename= saveFile + "\\" + videoName + i + "_" + j + ".mp4";
						File file_saveFilename = new File(st_saveFilename);
						if(!file_saveFilename.exists()){
							// 获取链接
							URLConnection conn = url.openConnection();
							HttpURLConnection httpURLConnection = (HttpURLConnection)conn;
							httpURLConnection.setInstanceFollowRedirects(false);
							// 输入流
							InputStream inStream = httpURLConnection.getInputStream();
							FileOutputStream fs = new FileOutputStream(st_saveFilename);

							byte[] buffer = new byte[1024];
							while ((byteRead = inStream.read(buffer)) != -1) {
								fs.write(buffer, 0, byteRead);
							}
							inStream.close();
							fs.close();
							System.out.println(videoName + "第" + i + "集" + j + "片段下载好了");
						} else {
							System.out.println(videoName + "第" + i + "集" + j + "片段已存在");
						}
						keyFileMap.put(j - 1, st_saveFilename);
					} catch (FileNotFoundException e) {
						System.out.println(videoName + "第" + i + "集" + j + "片段不存在");
					} 
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println(videoName + "第" + i + "集" + j + "片段超时");
				} 
			}
			// 合成视频片段
			composeFile(saveFileVideo + "\\" + videoName + i + ".mp4", keyFileMap);
			System.out.println(df.format(new Date()) + ":" + videoName + i + "集完成");
		}
		return true;
	}

	/**
	 * 下载索引
	 * @param content
	 */
	public static String getIndexFile(String urlpath){
		try{
			URL url = new URL(urlpath);

			//下在资源
			BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
			String content = "" ;
			String line;
			String indexUrl = "";
			int i = 0;
			while ((line = in.readLine()) != null) {
				i++;
				content += line + "\n";
				if (i==2) {
					indexUrl = content;
				}
			}
			// 转换为获取到的索引文件地址
			urlpath = urlpath.replace("index.m3u8", "") + content.replace(indexUrl,"");
			// 获取视频链接目录
			videoPathPrefix= urlpath.replace("index.m3u8", "").replace("\n", "");
			// 获取索引
			URL url2 = new URL(urlpath);
			URLConnection conn2 = url2.openConnection();
			HttpURLConnection httpURLConnection2 = (HttpURLConnection)conn2;
			httpURLConnection2.setInstanceFollowRedirects(false);

			try {
				// 输入流
				BufferedReader in2 = new BufferedReader(new InputStreamReader(httpURLConnection2.getInputStream(), "UTF-8"));
				String content2 = "" ;
				String line2;
				while ((line2 = in2.readLine()) != null) {
					content2 += line2 + "\n";
				}
				in2.close();

				return content2;
			} catch (FileNotFoundException e) {
				System.out.println(videoName + "链接错误");
			} 

			return content;
		}catch (Exception e){
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 解析索引
	 * @param content
	 */
	public static List<String> analysisIndex(String content){
		Pattern pattern = Pattern.compile(".*ts");
		Matcher ma = pattern.matcher(content);

		List<String> list = new ArrayList<String>();

		while(ma.find()){
			String s = ma.group();
			list.add(s);
		}
		return list;
	}

	/**
	 * 视频片段合成
	 * @param fileOutPath
	 * @param keyFileMap
	 */
	public static void composeFile(String fileOutPath, HashMap<Integer,String> keyFileMap){
		try {
			FileOutputStream fileOutputStream = new FileOutputStream(new File(fileOutPath));
			byte[] bytes = new byte[1024];
			int length = 0;
			for(int i=0;i<keyFileMap.size();i++){
				String nodePath = keyFileMap.get(i);
				File file = new File(nodePath);
				if(!file.exists())
					continue;
				FileInputStream fis = new FileInputStream(file);
				while ((length = fis.read(bytes)) != -1) {
					fileOutputStream.write(bytes, 0, length);
				}
			}
		}catch (Exception e){
			System.out.println("视频合成失败");
		}
	}
}

 

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,可以通过解析文件的头部信息来判断TS文件视频还是音频。TS文件的头部信息包含了很多有用的信息,比如文件类型、分辨率、音频/视频编码等等。其中,可以通过检查PAT/PMT表来判断TS文件视频还是音频。PAT表是Program Association Table,PMT表是Program Map Table,它们都是TS流的一部分,可以在TS文件头部找到。 下面是一个示例代码,展示了如何使用Java解析TS文件头部信息来判断TS文件视频还是音频: ``` import java.io.File; import java.io.FileInputStream; public class TsFileChecker { public static final int TS_PACKET_SIZE = 188; // TS分组大小 public static final int PAT_PID = 0x0000; // PAT表的PID public static final int PMT_PID = 0x1000; // PMT表的PID public static final int VIDEO_STREAM_TYPE = 0x1B; // 视频流类型 public static final int AUDIO_STREAM_TYPE = 0x0F; // 音频流的类型 public static boolean isVideoFile(String filePath) { try { FileInputStream fis = new FileInputStream(new File(filePath)); byte[] buffer = new byte[TS_PACKET_SIZE]; int bytesRead = fis.read(buffer); while (bytesRead >= 0) { if (bytesRead == TS_PACKET_SIZE && buffer[0] == 0x47) { // 检查分组头 int pid = ((buffer[1] & 0x1F) << 8) | (buffer[2] & 0xFF); int payloadStart = (buffer[1] & 0x40) != 0 ? 4 + buffer[4] : 4; if (pid == PAT_PID && buffer[payloadStart] == 0) { // 检查PAT表 int pmtPid = ((buffer[payloadStart + 1] & 0x1F) << 8) | (buffer[payloadStart + 2] & 0xFF); bytesRead = fis.read(buffer); while (bytesRead >= 0) { if (bytesRead == TS_PACKET_SIZE && buffer[0] == 0x47 && ((buffer[1] & 0x1F) == pmtPid)) { // 检查PMT表 int streamType = buffer[payloadStart + 1]; if (streamType == VIDEO_STREAM_TYPE) { return true; // 视频流 } else if (streamType == AUDIO_STREAM_TYPE) { return false; // 音频流 } } bytesRead = fis.read(buffer); } } } bytesRead = fis.read(buffer); } fis.close(); } catch (Exception e) { e.printStackTrace(); } return false; // 未知文件类型 } } ``` 这个示例代码通过读取TS文件的头部信息,检查PAT表和PMT表来判断TS文件视频还是音频。如果PAT表中包含PMT表的PID,就读取PMT表,检查其中的音频流和视频流类型来判断文件类型。如果流类型视频流,则返回true,表示TS文件视频;如果流类型为音频流,则返回false,表示TS文件是音频。如果不能识别文件类型,则返回false。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值