在exoplayer中刷新媒体源

我使用Exo Player ExtractorMediaSource在我的android应用程序中播放video。 我正在从服务器下载媒体,并保存在本地数据库,并在特定的时间报警我使用ConcatenatingMediaSource播放器中的ConcatenatingMediaSource播放此媒体。 但首先我检查下载的所有video文件,并启动下载媒体源的播放器。 如果有任何video没有下载,那么我想在下载的时候下载它,然后我想添加这个video在我已经创build的播放列表

这是示例代码

  private void playAndUpdateVideo(ArrayList<String> mediaSourc) { simpleExoPlayerView.setVisibility(View.VISIBLE); simpleExoPlayerView.setDefaultArtwork(null); mainHandler = new Handler(); DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter); TrackSelector trackSelector = new DefaultTrackSelector( videoTrackSelectionFactory); dataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, "com.cloveritservices.hype"), bandwidthMeter); // 2. Create a default LoadControl extractorsFactory = new DefaultExtractorsFactory(); LoadControl loadControl = new DefaultLoadControl(); // 3. Create the player player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl); player.addListener(this); //Set media controller simpleExoPlayerView.setUseController(false); simpleExoPlayerView.requestFocus(); // Bind the player to the view. simpleExoPlayerView.setPlayer(player); MediaSource[] mediaSources = new MediaSource[mediaSourc.size()]; for (int i=0;i<mediaSourc.size();i++) { mediaSources[i]= buildMediaSource(Uri.parse(mediaSourc.get(i))); } MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources); LoopingMediaSource loopingSource = new LoopingMediaSource(mediaSource); player.prepare(loopingSource); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); boolean isChecked = settings.getBoolean("switch", false); if (!isChecked) player.setVolume(0f); else player.setVolume(2f); player.setPlayWhenReady(true); } 

在这里,我正在检查video文件,它是下载或不

  if (CommonUtils.isExternalStorageExistAndWritable()) { for (int i = 0; i < videoUrl.size(); i++) { if (!new File(Environment.getExternalStorageDirectory().toString() + Constants.PROFILE_VIDEO_FOLDER + CommonUtils.fileFromUrl(videoUrl.get(i))).exists() && !CommonUtils.currentlyDownloading(context,CommonUtils.fileFromUrl(videoUrl.get(i)))) { downloadByDownloadManager(videoUrl.get(i), CommonUtils.fileFromUrl(videoUrl.get(i))); if (flag==Constants.FLAG_PLAY){downloadFlag=true;} } } } else { Toast.makeText(getApplicationContext(), "SD Card not mounted.Please Mount SD Card", Toast.LENGTH_SHORT).show(); } if (flag==Constants.FLAG_PLAY && !downloadFlag) { playAndUpdateVideo(videoUrl); } public void downloadByDownloadManager(String url, String fileName1) { downloadUrl=url; fileName=fileName1; request = new DownloadManager.Request(Uri.parse(url)); request.setDescription("video file"); request.setTitle(fileName); request.setNotificationVisibility(2); request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); request.setDestinationInExternalPublicDir(Constants.PROFILE_VIDEO_FOLDER, fileName); DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); manager.enqueue(request); // get download service and enqueue file } 

如果没有下载,请帮助如何添加丢失的video文件到播放列表。

Solutions Collecting From Web of "在exoplayer中刷新媒体源"

要将新的video文件添加到您的播放列表中,您需要一个新的MediaSource实现,它可以处理源列表以启用resize。 实现起来相当简单,最简单的方法是创buildConcaternatingMediaSource的修改实现,它使用列表而不是数组来存储和迭代媒体源。 然后,您使用列表replaceConcaternatingMediaSource中的playAndUpdateVideo与新的实现。 这将允许您随意添加和从播放列表中删除,当您的下载完成监听器被触发时,您可以附加新的媒体文件。 以下是使用列表的媒体源实现的完整类:

 public final class DynamicMediaSource implements MediaSource { private List<MediaSource> mediaSources; private SparseArray<Timeline> timelines; private SparseArray<Object> manifests; private Map<MediaPeriod, Integer> sourceIndexByMediaPeriod; private SparseArray<Boolean> duplicateFlags; private boolean isRepeatOneAtomic; 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(List<MediaSource> mediaSources) { this(false, mediaSources); } /** * @param isRepeatOneAtomic Whether the concatenated media source shall be treated as atomic * (ie, repeated in its entirety) when repeat mode is set to {@code Player.REPEAT_MODE_ONE}. * @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(boolean isRepeatOneAtomic, List<MediaSource> mediaSources) { for (MediaSource mediaSource : mediaSources) { Assertions.checkNotNull(mediaSource); } this.mediaSources = mediaSources; this.isRepeatOneAtomic = isRepeatOneAtomic; timelines = new SparseArray<Timeline>(); manifests = new SparseArray<Object>(); sourceIndexByMediaPeriod = new HashMap<>(); duplicateFlags = buildDuplicateFlags(mediaSources); } @Override public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { this.listener = listener; for (int i = 0; i < mediaSources.size(); i++) { if (!duplicateFlags.get(i)) { final int index = i; mediaSources.get(i).prepareSource(player, false, 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)) { mediaSources.get(i).maybeThrowSourceInfoRefreshError(); } } } @Override public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { int sourceIndex = timeline.getChildIndexByPeriodIndex(id.periodIndex); MediaPeriodId periodIdInSource = new MediaPeriodId(id.periodIndex - timeline.getFirstPeriodIndexByChildIndex(sourceIndex)); MediaPeriod mediaPeriod = mediaSources.get(sourceIndex).createPeriod(periodIdInSource, allocator); 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)) { mediaSources.get(i).releaseSource(); } } } 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(timelines, isRepeatOneAtomic); listener.onSourceInfoRefreshed(timeline, new ArrayList(asList(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 source = mediaSources.get(i); if (!sources.containsKey(source)) { sources.put(source, null); duplicateFlags.append(i,false); } else { duplicateFlags.append(i,true); } } return duplicateFlags; } /** * A {@link Timeline} that is the concatenation of one or more {@link Timeline}s. */ public static final class DynamicTimeline extends AbstractConcatenatedTimeline { private final SparseArray<Timeline> timelines; private final int[] sourcePeriodOffsets; private final int[] sourceWindowOffsets; private final boolean isRepeatOneAtomic; public DynamicTimeline(SparseArray<Timeline> timelines, boolean isRepeatOneAtomic) { super(timelines.size()); int[] sourcePeriodOffsets = new int[timelines.size()]; int[] sourceWindowOffsets = new int[timelines.size()]; long periodCount = 0; int windowCount = 0; for (int i = 0; i < timelines.size(); i++) { Timeline timeline = timelines.get(i); periodCount += timeline.getPeriodCount(); Assertions.checkState(periodCount <= Integer.MAX_VALUE, "ConcatenatingMediaSource children contain too many periods"); sourcePeriodOffsets[i] = (int) periodCount; windowCount += timeline.getWindowCount(); sourceWindowOffsets[i] = windowCount; } this.timelines = timelines; this.sourcePeriodOffsets = sourcePeriodOffsets; this.sourceWindowOffsets = sourceWindowOffsets; this.isRepeatOneAtomic = isRepeatOneAtomic; } @Override public int getWindowCount() { return sourceWindowOffsets[sourceWindowOffsets.length - 1]; } @Override public int getPeriodCount() { return sourcePeriodOffsets[sourcePeriodOffsets.length - 1]; } @Override public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { if (isRepeatOneAtomic && repeatMode == Player.REPEAT_MODE_ONE) { repeatMode = Player.REPEAT_MODE_ALL; } return super.getNextWindowIndex(windowIndex, repeatMode); } @Override public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { if (isRepeatOneAtomic && repeatMode == Player.REPEAT_MODE_ONE) { repeatMode = Player.REPEAT_MODE_ALL; } return super.getPreviousWindowIndex(windowIndex, repeatMode); } @Override public int getChildIndexByPeriodIndex(int periodIndex) { return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1; } @Override protected int getChildIndexByWindowIndex(int windowIndex) { return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1; } @Override protected int getChildIndexByChildUid(Object childUid) { if (!(childUid instanceof Integer)) { return C.INDEX_UNSET; } return (Integer) childUid; } @Override protected Timeline getTimelineByChildIndex(int childIndex) { return timelines.get(childIndex); } @Override public int getFirstPeriodIndexByChildIndex(int childIndex) { return childIndex == 0 ? 0 : sourcePeriodOffsets[childIndex - 1]; } @Override protected int getFirstWindowIndexByChildIndex(int childIndex) { return childIndex == 0 ? 0 : sourceWindowOffsets[childIndex - 1]; } @Override protected Object getChildUidByChildIndex(int childIndex) { return childIndex; } } } 

要检查下载文件的时间并设置下载完成的监听器,可以使用BroadcastReceiver 。 这里提供了一个如何设置BroadcastReceiver的详细例子。