2016-09-21 30 views
4

ExoPlayer2を使用して、トラックをdinamically(プレイリストに追加または削除)し、ループ設定を変更する可能性のあるプレイリストを使用したいと思います。Exoplayer 2を使用したダイナミックプレイリスト

ConcatenatingMediaSourceは静的な配列(リストではない)を持っているので、配列の代わりにリストを連結するようなDynamicMediaSourceを実装しています。また、1つのモードメソッドaddSourceを使用してリストにメディアソースを追加します。

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を得るためには何かが欠けているようです。

createPeriodで方法

mediaSources.get(sourceIndex)... 

)は、インデックス= mediaSources.sizeを(アクセスしようとしています。

私を助けることができますか?

答えて

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

関連する問題