最近慶餘年大火,找到了一些盜版資源,但是無奈太卡,就想到能不能把他緩存下來
嘗試過rxffmpeg,想通過命令行轉碼來儲存到本地,但是這個開源項目目前還不支持https,無奈放棄
嘗試過自己編譯ffmpeg來支持https,最後https是支持了,但是安卓調用命令行一調用就炸掉了0.0.可能還是我編譯腳本哪裏沒寫好
最後還是選擇了最笨的辦法,通過分析輸入流來直接下載最後ts流。
網絡請求用的是Rxjava2+retrofit。下載框架用的是filedownloader
public class Utils {
private String TS_NAME = ".ts";
private String M3U8_NAME = ".m3u8";
public void downloadVideo(Context context, String videoUrl) {
int hostIndex = getIndex(videoUrl, 3, "/");
String host = videoUrl.substring(0, hostIndex);
String path = videoUrl.substring(getIndex(videoUrl, 3, "/"));
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(host)
.build();
GetData service = retrofit.create(GetData.class);
final Observable<ResponseBody> observable = service.downloadVideo(path);
observable.subscribeOn(Schedulers.io())
.subscribe(responseBody -> {
String line;
boolean hasTs = false;
String realPath = null;
InputStream inputStream = responseBody.byteStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
while ((line = bufferedReader.readLine()) != null) {
if (line.toLowerCase().contains(TS_NAME)) {
hasTs = true;
Log.i("DownloadVideo",host+line);
FileDownloader.getImpl()
.create(host + line)
.setPath(context.getFilesDir() + "/"
+ path.substring(0, path.length() - 5)
.replace("/", "") + "/"
+ line.replace("/", ""))
.setCallbackProgressTimes(0)
.setListener(queueTarget)
.asInQueueTask()
.enqueue();
}
if (line.toLowerCase().contains(M3U8_NAME)) {
realPath = line;
}
}
if (hasTs) {
FileDownloader.getImpl().start(queueTarget, false);
} else {
String realCompPath = host + realPath;
downloadVideo(context, realCompPath);
}
}
, throwable -> {
Log.i("Download1112", throwable.getMessage());
});
}
final FileDownloadListener queueTarget = new FileDownloadListener() {
@Override
protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {
}
@Override
protected void connected(BaseDownloadTask task, String etag, boolean isContinue, int soFarBytes, int totalBytes) {
}
@Override
protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {
}
@Override
protected void blockComplete(BaseDownloadTask task) {
Log.i("DownloadVideo", "blockComplete");
}
@Override
protected void retry(final BaseDownloadTask task, final Throwable ex, final int retryingTimes, final int soFarBytes) {
}
@Override
protected void completed(BaseDownloadTask task) {
Log.i("DownloadVideo", "下載完成");
}
@Override
protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) {
}
@Override
protected void error(BaseDownloadTask task, Throwable e) {
Log.i("DownloadVideo", "下載出錯");
}
@Override
protected void warn(BaseDownloadTask task) {
}
};
private int getIndex(String string, int i, String str) {
Matcher matcher = Pattern.compile(str).matcher(string);
int index = 0;
while (matcher.find()) {
index++;
if (index == i) {
break;
}
}
return matcher.start();
}
}
public interface GetData {
@GET
Observable<ResponseBody> downloadVideo(@Url String url);
}
代碼總體來講沒什麼難度,方法開頭之所以分離host和地址,是因爲有的m3u8鏈接直接是獲取不了ts流的,裏面寫的是一個重定向地址,需要重定向到另一個地址才能獲取到真正的ts流,這只是一個思路,代碼直接拿過去可能用不了,需要根據自己要下載的鏈接做一下適配,最後ts流下載下來以後可以合併,也可以不合並播放的時候直接傳文件夾路徑,依次播放文件夾內的視頻,有什麼不懂的可以在下面問我,共同交流。