安卓緩存m3u8視頻

最近慶餘年大火,找到了一些盜版資源,但是無奈太卡,就想到能不能把他緩存下來

嘗試過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流下載下來以後可以合併,也可以不合並播放的時候直接傳文件夾路徑,依次播放文件夾內的視頻,有什麼不懂的可以在下面問我,共同交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章