exo支持音轨切换

main
于俊 11 months ago
parent 32416d5fee
commit a2478ed429
  1. 17
      app/src/main/java/com/github/tvbox/osc/player/ExoMediaPlayerFactory.java
  2. 174
      app/src/main/java/com/github/tvbox/osc/player/ExoPlayer.java
  3. 1
      app/src/main/java/com/github/tvbox/osc/player/TrackInfoBean.java
  4. 2
      app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java
  5. 20
      app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java
  6. 20
      app/src/main/java/com/github/tvbox/osc/ui/fragment/PlayFragment.java
  7. 2
      app/src/main/java/com/github/tvbox/osc/util/PlayerHelper.java
  8. 2
      player/src/main/java/xyz/doikki/videoplayer/exo/ExoMediaPlayer.java

@ -0,0 +1,17 @@
package com.github.tvbox.osc.player;
import android.content.Context;
import xyz.doikki.videoplayer.player.PlayerFactory;
public class ExoMediaPlayerFactory extends PlayerFactory<ExoPlayer> {
public static ExoMediaPlayerFactory create() {
return new ExoMediaPlayerFactory();
}
@Override
public ExoPlayer createPlayer(Context context) {
return new ExoPlayer(context);
}
}

@ -0,0 +1,174 @@
package com.github.tvbox.osc.player;
import android.content.Context;
import android.util.Pair;
import com.github.tvbox.osc.util.LOG;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import xyz.doikki.videoplayer.exo.ExoMediaPlayer;
import com.google.android.exoplayer2.C;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ExoPlayer extends ExoMediaPlayer {
public ExoPlayer(Context context) {
super(context);
}
// 3. 获取所有轨道信息
public TrackInfo getTrackInfo() {
TrackInfo data = new TrackInfo();
MappingTrackSelector.MappedTrackInfo mappedInfo = getMappingTrackSelector().getCurrentMappedTrackInfo();
if (mappedInfo == null) return data;
DefaultTrackSelector.Parameters params = ((DefaultTrackSelector) getMappingTrackSelector()).getParameters();
for (int rendererIndex = 0; rendererIndex < mappedInfo.getRendererCount(); rendererIndex++) {
int type = mappedInfo.getRendererType(rendererIndex);
TrackGroupArray groups = mappedInfo.getTrackGroups(rendererIndex);
DefaultTrackSelector.SelectionOverride override = params.getSelectionOverride(rendererIndex, groups);
boolean hasSelected = false;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup group = groups.get(groupIndex);
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
Format fmt = group.getFormat(trackIndex);
TrackInfoBean bean = new TrackInfoBean();
bean.language = getLanguage(fmt);
bean.name = getName(fmt);
bean.groupIndex = groupIndex;
bean.index = trackIndex;
boolean selected = false;
if (override != null) {
if(override.groupIndex == groupIndex){
for (int t : override.tracks) {
if (t == trackIndex) {
selected = true;
hasSelected = true;
break;
}
}
}
}else if (type == C.TRACK_TYPE_AUDIO && !hasSelected) {
selected = true;
hasSelected = true;
}
bean.selected = selected;
if (type == C.TRACK_TYPE_AUDIO) {
data.addAudio(bean);
} else if (type == C.TRACK_TYPE_TEXT) {
data.addSubtitle(bean);
}
}
}
}
return data;
}
protected MappingTrackSelector getMappingTrackSelector() {
if (mTrackSelector instanceof MappingTrackSelector) {
return (MappingTrackSelector) mTrackSelector;
}
throw new IllegalStateException("trackSelector 必须是 MappingTrackSelector 类型");
}
/**
* 设置当前播放的音轨
* @param groupIndex 音轨组的索引
* @param trackIndex 音轨在组内的索引
*/
public void setTrack(int groupIndex, int trackIndex) {
try {
DefaultTrackSelector trackSelector = (DefaultTrackSelector) getMappingTrackSelector();
MappingTrackSelector.MappedTrackInfo mappedInfo = trackSelector.getCurrentMappedTrackInfo();
if (mappedInfo == null) {
LOG.i("echo-setTrack: MappedTrackInfo is null");
return;
}
int audioRendererIndex = findAudioRendererIndex(mappedInfo);
if (audioRendererIndex == C.INDEX_UNSET) {
LOG.i("echo-setTrack: No audio renderer found");
return;
}
TrackGroupArray audioGroups = mappedInfo.getTrackGroups(audioRendererIndex);
if (!isTrackIndexValid(audioGroups, groupIndex, trackIndex)) {
LOG.i("echo-setTrack: Invalid track index - group:" + groupIndex + ", track:" + trackIndex);
return;
}
DefaultTrackSelector.SelectionOverride newOverride = new DefaultTrackSelector.SelectionOverride(groupIndex, trackIndex);
DefaultTrackSelector.ParametersBuilder builder = trackSelector.buildUponParameters();
builder.clearSelectionOverrides(audioRendererIndex);
builder.setSelectionOverride(audioRendererIndex, audioGroups, newOverride);
trackSelector.setParameters(builder.build());
} catch (Exception e) {
LOG.i("echo-setTrack error: " + e.getMessage());
}
}
/**
* 查找音频渲染器索引
*/
private int findAudioRendererIndex(MappingTrackSelector.MappedTrackInfo mappedInfo) {
for (int i = 0; i < mappedInfo.getRendererCount(); i++) {
if (mappedInfo.getRendererType(i) == C.TRACK_TYPE_AUDIO) {
return i;
}
}
return C.INDEX_UNSET;
}
/**
* 验证音轨索引是否有效
*/
private boolean isTrackIndexValid(TrackGroupArray groups, int groupIndex, int trackIndex) {
if (groupIndex < 0 || groupIndex >= groups.length) {
return false;
}
TrackGroup group = groups.get(groupIndex);
return trackIndex >= 0 && trackIndex < group.length;
}
private static final Map<String, String> LANG_MAP = new HashMap<>();
static {
LANG_MAP.put("zh", "中文");
LANG_MAP.put("zh-cn", "中文");
LANG_MAP.put("en", "英语");
LANG_MAP.put("en-us", "英语");
}
private String getLanguage(Format fmt){
String lang = fmt.language;
if (lang == null || lang.isEmpty() || "und".equalsIgnoreCase(lang)) {
return "未知";
}
String name = LANG_MAP.get(lang.toLowerCase());
return name != null ? name : lang;
}
private String getName(Format fmt){
String channelLabel;
if (fmt.channelCount <= 0) {
channelLabel = "";
} else if (fmt.channelCount == 1) {
channelLabel = "单声道";
} else if (fmt.channelCount == 2) {
channelLabel = "立体声";
} else {
channelLabel = fmt.channelCount + " 声道";
}
String codec = "";
if (fmt.sampleMimeType != null) {
String mime = fmt.sampleMimeType.substring(fmt.sampleMimeType.indexOf('/') + 1);
codec = mime.toUpperCase();
}
return String.join(", ", channelLabel, codec);
}
}

@ -3,6 +3,7 @@ package com.github.tvbox.osc.player;
public class TrackInfoBean {
public String name;
public String language;
public int groupIndex;
public int index;
public boolean selected;
}

@ -764,7 +764,7 @@ public class VodController extends BaseController {
mPlayerSpeedBtn.setText("x" + mPlayerConfig.getDouble("sp"));
mPlayerTimeStartBtn.setText(stringForTime(mPlayerConfig.getInt("st") * 1000));
mPlayerTimeSkipBtn.setText(stringForTime(mPlayerConfig.getInt("et") * 1000));
mAudioTrackBtn.setVisibility((playerType == 1) ? VISIBLE : GONE);
mAudioTrackBtn.setVisibility((playerType == 1 || playerType == 2) ? VISIBLE : GONE);
} catch (JSONException e) {
e.printStackTrace();
}

@ -50,6 +50,7 @@ import com.github.tvbox.osc.bean.Subtitle;
import com.github.tvbox.osc.bean.VodInfo;
import com.github.tvbox.osc.cache.CacheManager;
import com.github.tvbox.osc.event.RefreshEvent;
import com.github.tvbox.osc.player.ExoPlayer;
import com.github.tvbox.osc.player.IjkMediaPlayer;
import com.github.tvbox.osc.player.MyVideoView;
import com.github.tvbox.osc.player.TrackInfo;
@ -356,11 +357,13 @@ public class PlayActivity extends BaseActivity {
void selectMyAudioTrack() {
AbstractPlayer mediaPlayer = mVideoView.getMediaPlayer();
if (!(mediaPlayer instanceof IjkMediaPlayer)) {
return;
}
TrackInfo trackInfo = null;
trackInfo = ((IjkMediaPlayer) mediaPlayer).getTrackInfo();
if (mediaPlayer instanceof IjkMediaPlayer) {
trackInfo = ((IjkMediaPlayer)mediaPlayer).getTrackInfo();
}
if (mediaPlayer instanceof ExoPlayer) {
trackInfo = ((ExoPlayer)mediaPlayer).getTrackInfo();
}
if (trackInfo == null) {
Toast.makeText(mContext, "没有音轨", Toast.LENGTH_SHORT).show();
return;
@ -378,14 +381,15 @@ public class PlayActivity extends BaseActivity {
}
mediaPlayer.pause();
long progress = mediaPlayer.getCurrentPosition();//保存当前进度,ijk 切换轨道 会有快进几秒
((IjkMediaPlayer) mediaPlayer).setTrack(value.index);
if (mediaPlayer instanceof IjkMediaPlayer)((IjkMediaPlayer)mediaPlayer).setTrack(value.index);
if (mediaPlayer instanceof ExoPlayer)((ExoPlayer)mediaPlayer).setTrack(value.groupIndex,value.index);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mediaPlayer.seekTo(progress);
if(mediaPlayer instanceof IjkMediaPlayer)mediaPlayer.seekTo(progress);
mediaPlayer.start();
}
}, 800);
}, 200);
dialog.dismiss();
} catch (Exception e) {
LOG.e("切换音轨出错");
@ -394,7 +398,7 @@ public class PlayActivity extends BaseActivity {
@Override
public String getDisplay(TrackInfoBean val) {
return val.index + " . " + val.language + " : " + val.name;
return val.groupIndex + val.index + " . " + val.language + " : " + val.name;
}
}, new DiffUtil.ItemCallback<TrackInfoBean>() {
@Override

@ -50,6 +50,7 @@ import com.github.tvbox.osc.bean.Subtitle;
import com.github.tvbox.osc.bean.VodInfo;
import com.github.tvbox.osc.cache.CacheManager;
import com.github.tvbox.osc.event.RefreshEvent;
import com.github.tvbox.osc.player.ExoPlayer;
import com.github.tvbox.osc.player.IjkMediaPlayer;
import com.github.tvbox.osc.player.MyVideoView;
import com.github.tvbox.osc.player.TrackInfo;
@ -374,11 +375,13 @@ public class PlayFragment extends BaseLazyFragment {
void selectMyAudioTrack() {
AbstractPlayer mediaPlayer = mVideoView.getMediaPlayer();
if (!(mediaPlayer instanceof IjkMediaPlayer)) {
return;
}
TrackInfo trackInfo = null;
trackInfo = ((IjkMediaPlayer)mediaPlayer).getTrackInfo();
if (mediaPlayer instanceof IjkMediaPlayer) {
trackInfo = ((IjkMediaPlayer)mediaPlayer).getTrackInfo();
}
if (mediaPlayer instanceof ExoPlayer) {
trackInfo = ((ExoPlayer)mediaPlayer).getTrackInfo();
}
if (trackInfo == null) {
Toast.makeText(mContext, "没有音轨", Toast.LENGTH_SHORT).show();
return;
@ -396,14 +399,15 @@ public class PlayFragment extends BaseLazyFragment {
}
mediaPlayer.pause();
long progress = mediaPlayer.getCurrentPosition();//保存当前进度,ijk 切换轨道 会有快进几秒
((IjkMediaPlayer)mediaPlayer).setTrack(value.index);
if (mediaPlayer instanceof IjkMediaPlayer)((IjkMediaPlayer)mediaPlayer).setTrack(value.index);
if (mediaPlayer instanceof ExoPlayer)((ExoPlayer)mediaPlayer).setTrack(value.groupIndex,value.index);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mediaPlayer.seekTo(progress);
if(mediaPlayer instanceof IjkMediaPlayer)mediaPlayer.seekTo(progress);
mediaPlayer.start();
}
}, 800);
}, 200);
dialog.dismiss();
} catch (Exception e) {
LOG.e("切换音轨出错");
@ -412,7 +416,7 @@ public class PlayFragment extends BaseLazyFragment {
@Override
public String getDisplay(TrackInfoBean val) {
return val.index + " . " + val.language + " : " + val.name;
return val.groupIndex + val.index + " . " + val.language + " : " + val.name;
}
}, new DiffUtil.ItemCallback<TrackInfoBean>() {
@Override

@ -5,6 +5,7 @@ import android.content.Context;
import com.github.tvbox.osc.api.ApiConfig;
import com.github.tvbox.osc.bean.IJKCode;
import com.github.tvbox.osc.player.ExoMediaPlayerFactory;
import com.github.tvbox.osc.player.IjkMediaPlayer;
import com.github.tvbox.osc.player.render.SurfaceRenderViewFactory;
import com.github.tvbox.osc.player.thirdparty.Kodi;
@ -22,7 +23,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import tv.danmaku.ijk.media.player.IjkLibLoader;
import xyz.doikki.videoplayer.exo.ExoMediaPlayerFactory;
import xyz.doikki.videoplayer.player.AndroidMediaPlayerFactory;
import xyz.doikki.videoplayer.player.PlayerFactory;
import xyz.doikki.videoplayer.player.VideoView;

@ -51,7 +51,7 @@ public class ExoMediaPlayer extends AbstractPlayer implements Player.Listener {
private LoadControl mLoadControl;
private RenderersFactory mRenderersFactory;
private TrackSelector mTrackSelector;
protected TrackSelector mTrackSelector;
public ExoMediaPlayer(Context context) {
mAppContext = context.getApplicationContext();

Loading…
Cancel
Save