2016-09-21 11 views
4

ExoPlayer2를 dinamically 트랙을 변경 (재생 목록에 추가 또는 삭제)하고 루프 설정을 변경할 가능성이있는 재생 목록을 사용하고 싶습니다.Exoplayer 2의 동적 재생 목록

ConcatenatingMediaSource는 목록이 아닌 정적 배열을 가지고 있으므로 하나를 연결하지만 배열 대신 배열로, 하나의 모드 메서드로 addSource를 사용하여 하나의 미디어 소스를 목록에 추가하는 등의 DynamicMediaSource를 구현합니다.

public void addSource(MediaSource mediaSource) { 
    this.mediaSources.add(mediaSource); 
    duplicateFlags = buildDuplicateFlags(this.mediaSources); 
    if(!mediaSources.isEmpty()) 
     prepareSource(mediaSources.size() -1); 
    else 
     prepareSource(0); 
} 

내가 ADDSOURCE

   MediaSource ms = buildMediaSource(mynewuri, null); 
       mediaSource.addSource(ms); 

트랙이 배열에 추가를 호출하지만 난 항상 createPeriod 방법에 ArrayOutOfBoundsException를 얻을 수 있기 때문에 빠진 것 같다합니다.

mediaSources.get(sourceIndex)... 

인덱스 = mediaSources.size 액세스하려는

createPeriod에있어서().

도와 주시겠습니까?

답변

2

나는 결국 그것을 관리했다. 배열에서 목록으로 변환하는 동안 내 잘못이었습니다. 타임 라인 및 매니페스트에 SparseArrays를 사용해야하고 모든 것이 작동하기 시작했습니다. 간단하게 다음과 같은 유형의 설정 DynamicMediaSource에서

: 당신이 방법 여기

private void handleSourceInfoRefreshed(int sourceFirstIndex, Timeline sourceTimeline, 
             Object sourceManifest) { 
    // Set the timeline and manifest. 
    timelines.put(sourceFirstIndex, sourceTimeline); 
    manifests.put(sourceFirstIndex, sourceManifest); 

    // Also set the timeline and manifest for any duplicate entries of the same source. 
    for (int i = sourceFirstIndex + 1; i < mediaSources.size(); i++) { 
     if (mediaSources.get(i).equals(mediaSources.get(sourceFirstIndex))) { 
      timelines.put(i, sourceTimeline); 
      manifests.put(i, sourceManifest); 
     } 
    } 

    for(int i= 0; i<mediaSources.size(); i++){ 
     if(timelines.get(i) == null){ 
      // Don't invoke the listener until all sources have timelines. 
      return; 
     } 
    } 

    timeline = new DynamicTimeline(new ArrayList(asList(timelines))); 
    listener.onSourceInfoRefreshed(timeline, new ArrayList(asList(manifests))); 
} 

의 일정과 매니페스트에 적절한 값을 설정하는 스파 스 배열을 사용할 필요가

private final List<MediaSource> mediaSources; 
private final SparseArray<Timeline> timelines; 
private final SparseArray<Object> manifests; 
private final Map<MediaPeriod, Integer> sourceIndexByMediaPeriod; 
private SparseArray<Boolean> duplicateFlags; 

은 완료 DynamicMediaSource 클래스 코드 :

public final class DynamicMediaSource implements MediaSource { 

private static final String TAG = "DynamicSource"; 

private final List<MediaSource> mediaSources; 
private final List<Timeline> timelines; 
private final List<Object> manifests; 
private final Map<MediaPeriod, Integer> sourceIndexByMediaPeriod; 
private SparseArray<Boolean> duplicateFlags; 

private Listener listener; 
private DynamicTimeline timeline; 

/** 
* @param mediaSources The {@link MediaSource}s to concatenate. It is valid for the same 
*      {@link MediaSource} instance to be present more than once in the array. 
*/ 
public DynamicMediaSource(MediaSource... mediaSources) { 
    this.mediaSources = new ArrayList<MediaSource>(Arrays.asList(mediaSources)); 
    timelines = new ArrayList<Timeline>(); 
    manifests = new ArrayList<Object>(); 
    sourceIndexByMediaPeriod = new HashMap<>(); 
    duplicateFlags = buildDuplicateFlags(this.mediaSources); 
} 

public void addSource(MediaSource mediaSource) { 
    this.mediaSources.add(mediaSource); 
    duplicateFlags = buildDuplicateFlags(this.mediaSources); 
    /*if(!mediaSources.isEmpty()) 
     prepareSource(mediaSources.size() -1); 
    else 
     prepareSource(0);*/ 
} 

@Override 
public void prepareSource(Listener listener) { 
    this.listener = listener; 
    for (int i = 0; i < mediaSources.size(); i++) { 
     prepareSource(i); 
     /*if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) { 
      final int index = i; 
      mediaSources.get(i).prepareSource(new Listener() { 
       @Override 
       public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { 
        handleSourceInfoRefreshed(index, timeline, manifest); 
       } 
      }); 
     }*/ 
    } 
} 

private void prepareSource(int sourceindex) { 
    if (duplicateFlags.get(sourceindex) == null || !duplicateFlags.get(sourceindex)) { 
     final int index = sourceindex; 
     mediaSources.get(sourceindex).prepareSource(new Listener() { 
      @Override 
      public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { 
       handleSourceInfoRefreshed(index, timeline, manifest); 
      } 
     }); 
    } 
} 

@Override 
public void maybeThrowSourceInfoRefreshError() throws IOException { 
    for (int i = 0; i < mediaSources.size(); i++) { 
     if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) { 
      mediaSources.get(i).maybeThrowSourceInfoRefreshError(); 
     } 
    } 
} 

@Override 
public MediaPeriod createPeriod(int index, Callback callback, Allocator allocator, 
           long positionUs) { 
    int sourceIndex = timeline.getSourceIndexForPeriod(index); 
    int periodIndexInSource = index - timeline.getFirstPeriodIndexInSource(sourceIndex); 
    MediaPeriod mediaPeriod = mediaSources.get(sourceIndex).createPeriod(periodIndexInSource, callback, 
      allocator, positionUs); 
    sourceIndexByMediaPeriod.put(mediaPeriod, sourceIndex); 
    return mediaPeriod; 
} 

@Override 
public void releasePeriod(MediaPeriod mediaPeriod) { 
    int sourceIndex = sourceIndexByMediaPeriod.get(mediaPeriod); 
    sourceIndexByMediaPeriod.remove(mediaPeriod); 
    mediaSources.get(sourceIndex).releasePeriod(mediaPeriod); 
} 

@Override 
public void releaseSource() { 
    for (int i = 0; i < mediaSources.size(); i++) { 
     if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) { 
      mediaSources.get(i).releaseSource(); 
     } 
    } 
} 

private void handleSourceInfoRefreshed(int sourceFirstIndex, Timeline sourceTimeline, 
             Object sourceManifest) { 
    // Set the timeline and manifest. 
    timelines.add(sourceFirstIndex, sourceTimeline); 
    manifests.add(sourceFirstIndex, sourceManifest); 
    // Also set the timeline and manifest for any duplicate entries of the same source. 
    for (int i = sourceFirstIndex + 1; i < mediaSources.size(); i++) { 
     if (mediaSources.get(i).equals(mediaSources.get(sourceFirstIndex))) { 
      timelines.add(i, sourceTimeline); 
      manifests.add(i, sourceManifest); 
     } 
    } 
    for (Timeline timeline : timelines) { 
     if (timeline == null) { 
      // Don't invoke the listener until all sources have timelines. 
      return; 
     } 
    } 
    timeline = new DynamicTimeline(new ArrayList(timelines)); 
    listener.onSourceInfoRefreshed(timeline, new ArrayList(manifests)); 
} 

private static SparseArray<Boolean> buildDuplicateFlags(List<MediaSource> mediaSources) { 
    SparseArray<Boolean> duplicateFlags = new SparseArray<Boolean>(); 
    IdentityHashMap<MediaSource, Void> sources = new IdentityHashMap<>(mediaSources.size()); 
    for (int i = 0; i < mediaSources.size(); i++) { 
     MediaSource mediaSource = mediaSources.get(i); 
     if (!sources.containsKey(mediaSource)) { 
      sources.put(mediaSource, null); 
     } else { 
      duplicateFlags.setValueAt(i, true); 
     } 
    } 
    return duplicateFlags; 
} 

/** 
* A {@link Timeline} that is the concatenation of one or more {@link Timeline}s. 
*/ 
private static final class DynamicTimeline extends Timeline { 

    private final List<Timeline> timelines; 
    private final List<Integer> sourcePeriodOffsets; 
    private final List<Integer> sourceWindowOffsets; 

    public DynamicTimeline(List<Timeline> timelines) { 
     List<Integer> sourcePeriodOffsets = new ArrayList<>(); 
     List<Integer> sourceWindowOffsets = new ArrayList<>(); 
     int periodCount = 0; 
     int windowCount = 0; 
     for (Timeline timeline : timelines) { 
      periodCount += timeline.getPeriodCount(); 
      windowCount += timeline.getWindowCount(); 
      sourcePeriodOffsets.add(periodCount); 
      sourceWindowOffsets.add(windowCount); 
     } 
     this.timelines = timelines; 
     this.sourcePeriodOffsets = sourcePeriodOffsets; 
     this.sourceWindowOffsets = sourceWindowOffsets; 
    } 

    @Override 
    public int getWindowCount() { 
     return sourceWindowOffsets.get(sourceWindowOffsets.size() - 1); 
    } 

    @Override 
    public Window getWindow(int windowIndex, Window window, boolean setIds) { 
     int sourceIndex = getSourceIndexForWindow(windowIndex); 
     int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex); 
     int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex); 
     timelines.get(sourceIndex).getWindow(windowIndex - firstWindowIndexInSource, window, setIds); 
     window.firstPeriodIndex += firstPeriodIndexInSource; 
     window.lastPeriodIndex += firstPeriodIndexInSource; 
     return window; 
    } 

    @Override 
    public int getPeriodCount() { 
     return sourcePeriodOffsets.get(sourcePeriodOffsets.size() - 1); 
    } 

    @Override 
    public Period getPeriod(int periodIndex, Period period, boolean setIds) { 
     int sourceIndex = getSourceIndexForPeriod(periodIndex); 
     int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex); 
     int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex); 
     timelines.get(sourceIndex).getPeriod(periodIndex - firstPeriodIndexInSource, period, setIds); 
     period.windowIndex += firstWindowIndexInSource; 
     if (setIds) { 
      period.uid = Pair.create(sourceIndex, period.uid); 
     } 
     return period; 
    } 

    @Override 
    public int getIndexOfPeriod(Object uid) { 
     if (!(uid instanceof Pair)) { 
      return C.INDEX_UNSET; 
     } 
     Pair<?, ?> sourceIndexAndPeriodId = (Pair<?, ?>) uid; 
     if (!(sourceIndexAndPeriodId.first instanceof Integer)) { 
      return C.INDEX_UNSET; 
     } 
     int sourceIndex = (Integer) sourceIndexAndPeriodId.first; 
     Object periodId = sourceIndexAndPeriodId.second; 
     if (sourceIndex < 0 || sourceIndex >= timelines.size()) { 
      return C.INDEX_UNSET; 
     } 
     int periodIndexInSource = timelines.get(sourceIndex).getIndexOfPeriod(periodId); 
     return periodIndexInSource == C.INDEX_UNSET ? C.INDEX_UNSET 
       : getFirstPeriodIndexInSource(sourceIndex) + periodIndexInSource; 
    } 

    private int getSourceIndexForPeriod(int periodIndex) { 
     return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1; 
    } 

    private int getFirstPeriodIndexInSource(int sourceIndex) { 
     return sourceIndex == 0 ? 0 : sourcePeriodOffsets.get(sourceIndex - 1); 
    } 

    private int getSourceIndexForWindow(int windowIndex) { 
     return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1; 
    } 

    private int getFirstWindowIndexInSource(int sourceIndex) { 
     return sourceIndex == 0 ? 0 : sourceWindowOffsets.get(sourceIndex - 1); 
    } 

} 
} 
+3

전체 구현을 공유 할 수 있습니까? DynamicMediaSource? –

+0

전체 코드를 공유 할 수 있다면 정말 좋을 것입니다. – lelloman

+0

안녕하세요, 저는 DynamicMediaSource의 전체 구현으로 답변을 편집했습니다. 누군가가 도움이되기를 바랍니다. – Manuela