hls 直播下载实现

This commit is contained in:
laoyuyu
2019-06-06 21:19:30 +08:00
parent b052ef6642
commit b670e3e383
40 changed files with 1378 additions and 241 deletions

View File

@@ -36,7 +36,8 @@ import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.base.adapter.AbsHolder;
import com.arialyy.simple.base.adapter.AbsRVAdapter;
import com.arialyy.simple.base.adapter.RvItemClickSupport;
import com.arialyy.simple.core.download.m3u8.M3U8DownloadActivity;
import com.arialyy.simple.core.download.m3u8.M3U8LiveDownloadActivity;
import com.arialyy.simple.core.download.m3u8.M3U8VodDownloadActivity;
import com.arialyy.simple.databinding.ActivityMainBinding;
import com.arialyy.simple.core.download.DownloadActivity;
import com.arialyy.simple.core.download.FtpDownloadActivity;
@@ -109,7 +110,11 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
break;
case 6:
module.startNextActivity(MainActivity.this, data.get(position),
M3U8DownloadActivity.class);
M3U8VodDownloadActivity.class);
break;
case 7:
module.startNextActivity(MainActivity.this, data.get(position),
M3U8LiveDownloadActivity.class);
break;
}
}

View File

@@ -0,0 +1,270 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.simple.core.download.m3u8;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.arialyy.annotations.Download;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTarget;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.download.m3u8.ILiveTsUrlConverter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.frame.util.show.T;
import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.common.ModifyPathDialog;
import com.arialyy.simple.common.ModifyUrlDialog;
import com.arialyy.simple.databinding.ActivityM3u8LiveBinding;
import java.io.File;
public class M3U8LiveDownloadActivity extends BaseActivity<ActivityM3u8LiveBinding> {
private String mUrl;
private String mFilePath;
private M3U8LiveModule mModule;
private DownloadTarget mTarget;
@Override
protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
setTitle(getString(R.string.m3u8_live));
Aria.download(this).register();
mModule = ViewModelProviders.of(this).get(M3U8LiveModule.class);
mModule.getHttpDownloadInfo(this).observe(this, new Observer<DownloadEntity>() {
@Override public void onChanged(@Nullable DownloadEntity entity) {
if (entity == null) {
return;
}
mTarget = Aria.download(M3U8LiveDownloadActivity.this).load(entity.getUrl());
getBinding().setStateStr(getString(R.string.start));
getBinding().setUrl(entity.getUrl());
getBinding().setFilePath(entity.getFilePath());
mUrl = entity.getUrl();
mFilePath = entity.getFilePath();
}
});
getBinding().setViewModel(this);
}
public void chooseUrl() {
ModifyUrlDialog dialog =
new ModifyUrlDialog(this, getString(R.string.modify_url_dialog_title), mUrl);
dialog.show(getSupportFragmentManager(), "ModifyUrlDialog");
}
public void chooseFilePath() {
ModifyPathDialog dialog =
new ModifyPathDialog(this, getString(R.string.modify_file_path), mFilePath);
dialog.show(getSupportFragmentManager(), "ModifyPathDialog");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_single_task_activity, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onMenuItemClick(MenuItem item) {
int speed = -1;
String msg = "";
switch (item.getItemId()) {
case R.id.help:
msg = "一些小知识点:\n"
+ "1、你可以在注解中增加链接用于指定被注解的方法只能被特定的下载任务回调以防止progress乱跳\n"
+ "2、当遇到网络慢的情况时你可以先使用onPre()更新UI界面待连接成功时再在onTaskPre()获取完整的task数据然后给UI界面设置正确的数据\n"
+ "3、你可以在界面初始化时通过Aria.download(this).load(URL).getPercent()等方法快速获取相关任务的一些数据";
showMsgDialog("tip", msg);
break;
case R.id.speed_0:
speed = 0;
break;
case R.id.speed_128:
speed = 128;
break;
case R.id.speed_256:
speed = 256;
break;
case R.id.speed_512:
speed = 512;
break;
case R.id.speed_1m:
speed = 1024;
break;
}
if (speed > -1) {
msg = item.getTitle().toString();
Aria.download(this).setMaxSpeed(speed);
T.showShort(this, msg);
}
return true;
}
@Download.onWait
void onWait(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
Log.d(TAG, "wait ==> " + task.getDownloadEntity().getFileName());
}
}
@Download.onPre
protected void onPre(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
getBinding().setStateStr(getString(R.string.stop));
}
}
@Download.onTaskStart
void taskStart(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
getBinding().setFileSize(task.getConvertFileSize());
ALog.d(TAG, "isComplete = " + task.isComplete() + ", state = " + task.getState());
}
}
@Download.onTaskRunning
protected void running(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
ALog.d(TAG, "isRunning");
getBinding().setProgress(task.getPercent());
getBinding().setSpeed(task.getConvertSpeed());
}
}
@Download.onTaskResume
void taskResume(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
getBinding().setStateStr(getString(R.string.stop));
}
}
@Download.onTaskStop
void taskStop(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
getBinding().setStateStr(getString(R.string.resume));
getBinding().setSpeed("");
}
}
@Download.onTaskCancel
void taskCancel(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
getBinding().setProgress(0);
getBinding().setStateStr(getString(R.string.start));
getBinding().setSpeed("");
Log.d(TAG, "cancel");
}
}
@Download.onTaskFail
void taskFail(DownloadTask task, Exception e) {
if (task.getKey().equals(mUrl)) {
Toast.makeText(M3U8LiveDownloadActivity.this, getString(R.string.download_fail),
Toast.LENGTH_SHORT)
.show();
getBinding().setStateStr(getString(R.string.start));
}
}
@Download.onTaskComplete
void taskComplete(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
getBinding().setProgress(100);
Toast.makeText(M3U8LiveDownloadActivity.this, getString(R.string.download_success),
Toast.LENGTH_SHORT).show();
getBinding().setStateStr(getString(R.string.re_start));
getBinding().setSpeed("");
ALog.d(TAG, "md5: " + CommonUtil.getFileMD5(new File(task.getDownloadPath())));
}
}
@Override
protected int setLayoutId() {
return R.layout.activity_m3u8_live;
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.start:
ALog.d(TAG, "isRunning = " + mTarget.isRunning());
if (mTarget.isRunning()) {
Aria.download(this).load(mUrl).stop();
} else {
startD();
}
break;
case R.id.cancel:
Aria.download(this).load(mUrl).cancel(true);
break;
}
}
private void startD() {
Aria.download(M3U8LiveDownloadActivity.this)
.load(mUrl)
.useServerFileName(true)
.setFilePath(mFilePath, true)
.asM3U8()
//.setBandWidthUrlConverter(new IBandWidthUrlConverter() {
// @Override public String convert(String bandWidthUrl) {
// int index = mUrl.lastIndexOf("/");
// return mUrl.substring(0, index + 1) + bandWidthUrl;
// }
//})
.asLive()
.setLiveTsUrlConvert(new ILiveTsUrlConverter() {
@Override public String convert(String m3u8Url, String tsUrl) {
int index = m3u8Url.lastIndexOf("/");
String parentUrl = m3u8Url.substring(0, index + 1);
return parentUrl + tsUrl;
}
})
//.setLiveTsUrlConvert(new IVodTsUrlConverter() {
// @Override public List<String> convert(String m3u8Url, List<String> tsUrls) {
// int index = m3u8Url.lastIndexOf("/");
// String parentUrl = m3u8Url.substring(0, index + 1);
// List<String> newUrls = new ArrayList<>();
// for (String url : tsUrls) {
// newUrls.add(parentUrl + url);
// }
//
// return newUrls;
// }
//})
.start();
}
@Override protected void dataCallback(int result, Object data) {
super.dataCallback(result, data);
if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) {
mModule.uploadUrl(this, String.valueOf(data));
} else if (result == ModifyPathDialog.MODIFY_PATH_RESULT) {
mModule.updateFilePath(this, String.valueOf(data));
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.simple.core.download.m3u8;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.content.Context;
import android.os.Environment;
import android.text.TextUtils;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.frame.base.BaseViewModule;
import com.arialyy.simple.util.AppUtil;
import java.io.File;
public class M3U8LiveModule extends BaseViewModule {
private final String M3U8_LIVE_URL_KEY = "M3U8_LIVE_URL_KEY";
private final String M3U8_LIVE_PATH_KEY = "M3U8_LIVE_PATH_KEY";
// 多码率地址:
private final String defUrl = "http://ivi.bupt.edu.cn/hls/cctv6hd.m3u8";
private final String filePath =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
+ "/live.ts";
private MutableLiveData<DownloadEntity> liveData = new MutableLiveData<>();
private DownloadEntity singDownloadInfo;
/**
* 单任务下载的信息
*/
LiveData<DownloadEntity> getHttpDownloadInfo(Context context) {
String url = AppUtil.getConfigValue(context, M3U8_LIVE_URL_KEY, defUrl);
String filePath = AppUtil.getConfigValue(context, M3U8_LIVE_PATH_KEY, this.filePath);
singDownloadInfo = Aria.download(context).getDownloadEntity(url);
if (singDownloadInfo == null) {
singDownloadInfo = new DownloadEntity();
singDownloadInfo.setUrl(url);
File temp = new File(this.filePath);
singDownloadInfo.setFilePath(filePath);
singDownloadInfo.setFileName(temp.getName());
} else {
AppUtil.setConfigValue(context, M3U8_LIVE_PATH_KEY, singDownloadInfo.getDownloadPath());
AppUtil.setConfigValue(context, M3U8_LIVE_URL_KEY, singDownloadInfo.getUrl());
}
liveData.postValue(singDownloadInfo);
return liveData;
}
/**
* 更新文件保存路径
*
* @param filePath 文件保存路径
*/
void updateFilePath(Context context, String filePath) {
if (TextUtils.isEmpty(filePath)) {
ALog.e(TAG, "文件保存路径为空");
return;
}
File temp = new File(filePath);
AppUtil.setConfigValue(context, M3U8_LIVE_PATH_KEY, filePath);
singDownloadInfo.setFileName(temp.getName());
singDownloadInfo.setFilePath(filePath);
liveData.postValue(singDownloadInfo);
}
/**
* 更新url
*/
void uploadUrl(Context context, String url) {
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "下载地址为空");
return;
}
AppUtil.setConfigValue(context, M3U8_LIVE_URL_KEY, url);
singDownloadInfo.setUrl(url);
liveData.postValue(singDownloadInfo);
}
}

View File

@@ -18,7 +18,6 @@ package com.arialyy.simple.core.download.m3u8;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
@@ -32,9 +31,8 @@ import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTarget;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.download.m3u8.IBandWidthUrlConverter;
import com.arialyy.aria.core.download.m3u8.ITsUrlConverter;
import com.arialyy.aria.core.download.m3u8.IVodTsUrlConverter;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.frame.util.show.T;
@@ -42,17 +40,16 @@ import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.common.ModifyPathDialog;
import com.arialyy.simple.common.ModifyUrlDialog;
import com.arialyy.simple.databinding.ActivityM3u8Binding;
import com.arialyy.simple.databinding.ActivityM3u8VodBinding;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class M3U8DownloadActivity extends BaseActivity<ActivityM3u8Binding> {
public class M3U8VodDownloadActivity extends BaseActivity<ActivityM3u8VodBinding> {
private String mUrl;
private String mFilePath;
private M3U8Module mModule;
private M3U8VodModule mModule;
private DownloadTarget mTarget;
@Override
@@ -60,14 +57,14 @@ public class M3U8DownloadActivity extends BaseActivity<ActivityM3u8Binding> {
super.init(savedInstanceState);
setTitle(getString(R.string.m3u8_file));
Aria.download(this).register();
mModule = ViewModelProviders.of(this).get(M3U8Module.class);
mModule = ViewModelProviders.of(this).get(M3U8VodModule.class);
mModule.getHttpDownloadInfo(this).observe(this, new Observer<DownloadEntity>() {
@Override public void onChanged(@Nullable DownloadEntity entity) {
if (entity == null) {
return;
}
mTarget = Aria.download(M3U8DownloadActivity.this).load(entity.getUrl());
mTarget = Aria.download(M3U8VodDownloadActivity.this).load(entity.getUrl());
if (mTarget.getTaskState() == IEntity.STATE_STOP) {
getBinding().setStateStr(getString(R.string.resume));
} else if (mTarget.isRunning()) {
@@ -200,7 +197,7 @@ public class M3U8DownloadActivity extends BaseActivity<ActivityM3u8Binding> {
@Download.onTaskFail
void taskFail(DownloadTask task, Exception e) {
if (task.getKey().equals(mUrl)) {
Toast.makeText(M3U8DownloadActivity.this, getString(R.string.download_fail),
Toast.makeText(M3U8VodDownloadActivity.this, getString(R.string.download_fail),
Toast.LENGTH_SHORT)
.show();
getBinding().setStateStr(getString(R.string.start));
@@ -211,7 +208,7 @@ public class M3U8DownloadActivity extends BaseActivity<ActivityM3u8Binding> {
void taskComplete(DownloadTask task) {
if (task.getKey().equals(mUrl)) {
getBinding().setProgress(100);
Toast.makeText(M3U8DownloadActivity.this, getString(R.string.download_success),
Toast.makeText(M3U8VodDownloadActivity.this, getString(R.string.download_success),
Toast.LENGTH_SHORT).show();
getBinding().setStateStr(getString(R.string.re_start));
getBinding().setSpeed("");
@@ -221,7 +218,7 @@ public class M3U8DownloadActivity extends BaseActivity<ActivityM3u8Binding> {
@Override
protected int setLayoutId() {
return R.layout.activity_m3u8;
return R.layout.activity_m3u8_vod;
}
public void onClick(View view) {
@@ -241,7 +238,7 @@ public class M3U8DownloadActivity extends BaseActivity<ActivityM3u8Binding> {
}
private void startD() {
Aria.download(M3U8DownloadActivity.this)
Aria.download(M3U8VodDownloadActivity.this)
.load(mUrl)
.useServerFileName(true)
.setFilePath(mFilePath, true)
@@ -252,7 +249,7 @@ public class M3U8DownloadActivity extends BaseActivity<ActivityM3u8Binding> {
return mUrl.substring(0, index + 1) + bandWidthUrl;
}
})
.setTsUrlConvert(new ITsUrlConverter() {
.setTsUrlConvert(new IVodTsUrlConverter() {
@Override public List<String> convert(String m3u8Url, List<String> tsUrls) {
int index = m3u8Url.lastIndexOf("/");
String parentUrl = m3u8Url.substring(0, index + 1);
@@ -267,12 +264,6 @@ public class M3U8DownloadActivity extends BaseActivity<ActivityM3u8Binding> {
.start();
}
@Override
protected void onStop() {
super.onStop();
//Aria.download(this).unRegister();
}
@Override protected void dataCallback(int result, Object data) {
super.dataCallback(result, data);
if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) {

View File

@@ -28,13 +28,13 @@ import com.arialyy.frame.base.BaseViewModule;
import com.arialyy.simple.util.AppUtil;
import java.io.File;
public class M3U8Module extends BaseViewModule {
public class M3U8VodModule extends BaseViewModule {
private final String M3U8_URL_KEY = "M3U8_URL_KEY";
private final String M3U8_PATH_KEY = "M3U8_PATH_KEY";
// m3u8测试集合http://www.voidcn.com/article/p-snaliarm-ct.html
//private final String defUrl = "https://www.gaoya123.cn/2019/1557993797897.m3u8";
// 多码率地址
private final String defUrl = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";
private final String defUrl = "http://ivi.bupt.edu.cn/hls/cctv6hd.m3u8";
private final String filePath =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
+ "/1557993797897.ts";
@@ -54,10 +54,10 @@ public class M3U8Module extends BaseViewModule {
singDownloadInfo = new DownloadEntity();
singDownloadInfo.setUrl(url);
File temp = new File(this.filePath);
singDownloadInfo.setDownloadPath(filePath);
singDownloadInfo.setFilePath(filePath);
singDownloadInfo.setFileName(temp.getName());
} else {
AppUtil.setConfigValue(context, M3U8_PATH_KEY, singDownloadInfo.getDownloadPath());
AppUtil.setConfigValue(context, M3U8_PATH_KEY, singDownloadInfo.getFilePath());
AppUtil.setConfigValue(context, M3U8_URL_KEY, singDownloadInfo.getUrl());
}
liveData.postValue(singDownloadInfo);
@@ -78,7 +78,7 @@ public class M3U8Module extends BaseViewModule {
File temp = new File(filePath);
AppUtil.setConfigValue(context, M3U8_PATH_KEY, filePath);
singDownloadInfo.setFileName(temp.getName());
singDownloadInfo.setDownloadPath(filePath);
singDownloadInfo.setFilePath(filePath);
liveData.postValue(singDownloadInfo);
}

View File

@@ -77,7 +77,8 @@ public class CommonModule extends BaseViewModule {
R.drawable.ic_ftp,
R.drawable.ic_ftp_dir,
R.drawable.ic_ftp,
R.drawable.ic_ts
R.drawable.ic_ts,
R.drawable.ic_live
};
int i = 0;
for (String title : titles) {