直播配置支持读取自定义hosts;尝试优化ijk

pull/137/head
jun 10 months ago
parent 758e06878d
commit 3fa48217e8
  1. 17
      app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java
  2. 19
      app/src/main/java/com/github/tvbox/osc/player/IjkMediaPlayer.java
  3. 1
      app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java
  4. 1
      app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java
  5. 1
      app/src/main/java/com/github/tvbox/osc/ui/fragment/PlayFragment.java
  6. 1
      app/src/main/java/com/github/tvbox/osc/util/HawkConfig.java
  7. 47
      app/src/main/java/com/github/tvbox/osc/util/OkGoHelper.java
  8. 17
      player/src/main/java/xyz/doikki/videoplayer/exo/ExoMediaPlayer.java

@ -19,6 +19,7 @@ import com.github.tvbox.osc.util.AES;
import com.github.tvbox.osc.util.AdBlocker;
import com.github.tvbox.osc.util.DefaultConfig;
import com.github.tvbox.osc.util.HawkConfig;
import com.github.tvbox.osc.util.LOG;
import com.github.tvbox.osc.util.MD5;
import com.github.tvbox.osc.util.VideoParseRuler;
import com.google.gson.Gson;
@ -58,6 +59,7 @@ public class ApiConfig {
private List<LiveChannelGroup> liveChannelGroupList;
private List<ParseBean> parseBeanList;
private List<String> vipParseFlags;
private Map<String,String> myHosts;
private List<IJKCode> ijkCodes;
private String spider = null;
public String wallpaper = "";
@ -491,6 +493,17 @@ public class ApiConfig {
}
}
}
myHosts = new HashMap<>();
if (infoJson.has("hosts")) {
JsonArray hostsArray = infoJson.getAsJsonArray("hosts");
for (int i = 0; i < hostsArray.size(); i++) {
String entry = hostsArray.get(i).getAsString();
String[] parts = entry.split("=", 2); // 只分割一次,防止 value 里有 =
if (parts.length == 2) {
myHosts.put(parts[0], parts[1]);
}
}
}
String defaultIJKADS="{\"ijk\":[{\"options\":[{\"name\":\"opensles\",\"category\":4,\"value\":\"0\"},{\"name\":\"framedrop\",\"category\":4,\"value\":\"1\"},{\"name\":\"soundtouch\",\"category\":4,\"value\":\"1\"},{\"name\":\"start-on-prepared\",\"category\":4,\"value\":\"1\"},{\"name\":\"http-detect-rangeupport\",\"category\":1,\"value\":\"0\"},{\"name\":\"fflags\",\"category\":1,\"value\":\"fastseek\"},{\"name\":\"skip_loop_filter\",\"category\":2,\"value\":\"48\"},{\"name\":\"reconnect\",\"category\":4,\"value\":\"1\"},{\"name\":\"enable-accurate-seek\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec-all-videos\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec-auto-rotate\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec-handle-resolution-change\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec-hevc\",\"category\":4,\"value\":\"0\"},{\"name\":\"max-buffer-size\",\"category\":4,\"value\":\"15728640\"}],\"group\":\"软解码\"},{\"options\":[{\"name\":\"opensles\",\"category\":4,\"value\":\"0\"},{\"name\":\"framedrop\",\"category\":4,\"value\":\"1\"},{\"name\":\"soundtouch\",\"category\":4,\"value\":\"1\"},{\"name\":\"start-on-prepared\",\"category\":4,\"value\":\"1\"},{\"name\":\"http-detect-rangeupport\",\"category\":1,\"value\":\"0\"},{\"name\":\"fflags\",\"category\":1,\"value\":\"fastseek\"},{\"name\":\"skip_loop_filter\",\"category\":2,\"value\":\"48\"},{\"name\":\"reconnect\",\"category\":4,\"value\":\"1\"},{\"name\":\"enable-accurate-seek\",\"category\":4,\"value\":\"0\"},{\"name\":\"mediacodec\",\"category\":4,\"value\":\"1\"},{\"name\":\"mediacodec-all-videos\",\"category\":4,\"value\":\"1\"},{\"name\":\"mediacodec-auto-rotate\",\"category\":4,\"value\":\"1\"},{\"name\":\"mediacodec-handle-resolution-change\",\"category\":4,\"value\":\"1\"},{\"name\":\"mediacodec-hevc\",\"category\":4,\"value\":\"1\"},{\"name\":\"max-buffer-size\",\"category\":4,\"value\":\"15728640\"}],\"group\":\"硬解码\"}],\"ads\":[\"mimg.0c1q0l.cn\",\"www.googletagmanager.com\",\"www.google-analytics.com\",\"mc.usihnbcq.cn\",\"mg.g1mm3d.cn\",\"mscs.svaeuzh.cn\",\"cnzz.hhttm.top\",\"tp.vinuxhome.com\",\"cnzz.mmstat.com\",\"www.baihuillq.com\",\"s23.cnzz.com\",\"z3.cnzz.com\",\"c.cnzz.com\",\"stj.v1vo.top\",\"z12.cnzz.com\",\"img.mosflower.cn\",\"tips.gamevvip.com\",\"ehwe.yhdtns.com\",\"xdn.cqqc3.com\",\"www.jixunkyy.cn\",\"sp.chemacid.cn\",\"hm.baidu.com\",\"s9.cnzz.com\",\"z6.cnzz.com\",\"um.cavuc.com\",\"mav.mavuz.com\",\"wofwk.aoidf3.com\",\"z5.cnzz.com\",\"xc.hubeijieshikj.cn\",\"tj.tianwenhu.com\",\"xg.gars57.cn\",\"k.jinxiuzhilv.com\",\"cdn.bootcss.com\",\"ppl.xunzhuo123.com\",\"xomk.jiangjunmh.top\",\"img.xunzhuo123.com\",\"z1.cnzz.com\",\"s13.cnzz.com\",\"xg.huataisangao.cn\",\"z7.cnzz.com\",\"xg.huataisangao.cn\",\"z2.cnzz.com\",\"s96.cnzz.com\",\"q11.cnzz.com\",\"thy.dacedsfa.cn\",\"xg.whsbpw.cn\",\"s19.cnzz.com\",\"z8.cnzz.com\",\"s4.cnzz.com\",\"f5w.as12df.top\",\"ae01.alicdn.com\",\"www.92424.cn\",\"k.wudejia.com\",\"vivovip.mmszxc.top\",\"qiu.xixiqiu.com\",\"cdnjs.hnfenxun.com\",\"cms.qdwght.com\"]}";
JsonObject defaultJson=new Gson().fromJson(defaultIJKADS, JsonObject.class);
@ -708,4 +721,8 @@ public class ApiConfig {
}
return content;
}
public Map<String,String> getMyHost() {
return myHosts;
}
}

@ -7,6 +7,7 @@ import com.github.tvbox.osc.api.ApiConfig;
import com.github.tvbox.osc.bean.IJKCode;
import com.github.tvbox.osc.util.FileUtils;
import com.github.tvbox.osc.util.HawkConfig;
import com.github.tvbox.osc.util.LOG;
import com.github.tvbox.osc.util.MD5;
import com.orhanobut.hawk.Hawk;
@ -48,9 +49,8 @@ public class IjkMediaPlayer extends IjkPlayer {
}
}
}
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-fps", 60);
// 在每个数据包之后启用 I/O 上下文的刷新
// mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1);
// 设置视频流格式
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", tv.danmaku.ijk.media.player.IjkMediaPlayer.SDL_FCC_RV32);
@ -59,6 +59,19 @@ public class IjkMediaPlayer extends IjkPlayer {
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1);
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_timeout", -1);
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT,"safe",0);
if(Hawk.get(HawkConfig.PLAYER_IS_LIVE)){
LOG.i("type-直播");
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0);
// mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fflags", "nobuffer"); // 减少协议层缓冲
}else{
LOG.i("type-点播");
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", 100);
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_FORMAT, "infbuf", 0);
mMediaPlayer.setOption(tv.danmaku.ijk.media.player.IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", 5);
}
}
@Override
@ -159,4 +172,4 @@ public class IjkMediaPlayer extends IjkPlayer {
mMediaPlayer.setOnTimedTextListener(listener);
}
}
}

@ -371,6 +371,7 @@ public class LivePlayActivity extends BaseActivity {
initSettingItemView();
initLiveChannelList();
initLiveSettingGroupList();
Hawk.put(HawkConfig.PLAYER_IS_LIVE,true);
}
//获取EPG并存储 // 百川epg DIYP epg 51zmt epg ------- 自建EPG格式输出格式请参考 51zmt
private List<Epginfo> epgdata = new ArrayList<>();

@ -131,6 +131,7 @@ public class PlayActivity extends BaseActivity {
initView();
initViewModel();
initData();
Hawk.put(HawkConfig.PLAYER_IS_LIVE,false);
}
public long getSavedProgress(String url) {

@ -140,6 +140,7 @@ public class PlayFragment extends BaseLazyFragment {
initView();
initViewModel();
initData();
Hawk.put(HawkConfig.PLAYER_IS_LIVE,false);
}
public long getSavedProgress(String url) {

@ -39,5 +39,6 @@ public class HawkConfig {
public static final String NOW_DATE = "now_date"; //当前日期
public static final String REMOTE_TVBOX = "remote_tvbox_host";
public static final String IJK_CACHE_PLAY = "ijk_cache_play";
public static final String PLAYER_IS_LIVE = "player_is_live";
public static boolean hotVodDelete;
}

@ -2,6 +2,9 @@ package com.github.tvbox.osc.util;
import android.graphics.Bitmap;
import androidx.annotation.NonNull;
import com.github.tvbox.osc.api.ApiConfig;
import com.github.tvbox.osc.base.App;
import com.github.tvbox.osc.picasso.MyOkhttpDownLoader;
import com.github.tvbox.osc.util.SSL.SSLSocketFactoryCompat;
@ -13,8 +16,13 @@ import com.orhanobut.hawk.Hawk;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@ -24,6 +32,7 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.Cache;
import okhttp3.Dns;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.dnsoverhttps.DnsOverHttps;
@ -56,7 +65,8 @@ public class OkGoHelper {
} catch (Throwable th) {
th.printStackTrace();
}
builder.dns(dnsOverHttps);
builder.dns(new CustomDns());
ExoMediaSourceHelper.getInstance(App.getInstance()).setOkClient(builder.build());
}
@ -65,6 +75,9 @@ public class OkGoHelper {
public static ArrayList<String> dnsHttpsList = new ArrayList<>();
public static boolean is_doh = false;
public static Map<String,String> myHosts = null;
public static String getDohUrl(int type) {
switch (type) {
@ -112,9 +125,37 @@ public class OkGoHelper {
builder.cache(new Cache(new File(App.getInstance().getCacheDir().getAbsolutePath(), "dohcache"), 100 * 1024 * 1024));
OkHttpClient dohClient = builder.build();
String dohUrl = getDohUrl(Hawk.get(HawkConfig.DOH_URL, 0));
dnsOverHttps = new DnsOverHttps.Builder().client(dohClient).url(dohUrl.isEmpty() ? null : HttpUrl.get(dohUrl)).build();
if(!dohUrl.isEmpty())is_doh=true;
dnsOverHttps = new DnsOverHttps.Builder()
.client(dohClient)
.url(dohUrl.isEmpty()?null:HttpUrl.get(dohUrl))
.build();
}
// 自定义 DNS 解析器,优先使用 DoH,失败时降级到系统 DNS
static class CustomDns implements Dns {
@NonNull
@Override
public List<InetAddress> lookup(@NonNull String hostname) throws UnknownHostException {
if(myHosts==null){
LOG.i("echo-exo-setHOSTS");
myHosts= ApiConfig.get().getMyHost();
}
if (is_doh && !hostname.equals("127.0.0.1")) {
if (!myHosts.isEmpty() && myHosts.containsKey(hostname)) {
return dnsOverHttps.lookup(Objects.requireNonNull(myHosts.get(hostname)));
}else {
return dnsOverHttps.lookup(hostname);
}
}else {
if (!myHosts.isEmpty() && myHosts.containsKey(hostname)) {
return Dns.SYSTEM.lookup(Objects.requireNonNull(myHosts.get(hostname)));
}else {
return Dns.SYSTEM.lookup(hostname);
}
}
}
}
static OkHttpClient defaultClient = null;
static OkHttpClient noRedirectClient = null;
@ -149,7 +190,7 @@ public class OkGoHelper {
builder.writeTimeout(DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
builder.connectTimeout(DEFAULT_MILLISECONDS, TimeUnit.MILLISECONDS);
builder.dns(dnsOverHttps);
if(dnsOverHttps!=null)builder.dns(dnsOverHttps);
try {
setOkHttpSsl(builder);
} catch (Throwable th) {

@ -54,24 +54,7 @@ public class ExoMediaPlayer extends AbstractPlayer implements Player.Listener {
public ExoMediaPlayer(Context context) {
mAppContext = context.getApplicationContext();
// 初始化 ExoMediaSourceHelper 实例
mMediaSourceHelper = ExoMediaSourceHelper.getInstance(context);
// 构造自定义的 OkHttpClient,加入自定义 DNS 逻辑:
// 当请求的域名以 "cache.ott" 开头时,使用 "base-v4-free-mghy.e.cdn.chinamobile.com" 解析
OkHttpClient customOkHttpClient = new OkHttpClient.Builder()
.dns(new Dns() {
@Override
public List<InetAddress> lookup(@NonNull String hostname) throws UnknownHostException {
if (hostname.matches("^cache\\.ott\\..*\\.cmvideo\\.cn$")) {
// 这里将 hostname 强制解析为目标域名
return Dns.SYSTEM.lookup("base-v4-free-mghy.e.cdn.chinamobile.com");
}
return Dns.SYSTEM.lookup(hostname);
}
})
.build();
// 注入自定义 OkHttpClient 到 ExoMediaSourceHelper 中
mMediaSourceHelper.setOkClient(customOkHttpClient);
}
@Override

Loading…
Cancel
Save