首页 文章

在exoplayer中刷新媒体源

提问于
浏览
17

我正在使用 Exo Player ExtractorMediaSource 在我的Android应用中播放视频 . 我正在从服务器下载媒体并保存在本地数据库中并在特定时间报警我在外部播放器中使用 ConcatenatingMediaSource 播放此媒体 . 但首先我检查所有视频文件是否已下载,并启动下载媒体源的播放器 . 如果没有下载任何视频,那么我想在后台下载它,然后我想在我已创建的播放列表中添加此视频

This is sample code

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);

    }

在这里,我正在检查是否下载的视频文件

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



    }

如果没有下载,请帮助您稍后将缺少的视频文件添加到播放列表 .

1 回答

  • 2

    要将新视频文件添加到播放列表,您需要一个新的 MediaSource 实现,该实现可以处理源列表以启用调整大小 . 这很容易实现,最简单的方法是创建 ConcaternatingMediaSource 的修改实现,它使用列表而不是数组来存储和迭代媒体源 . 然后使用列表将新实现替换为 playAndUpdateVideo 中的 ConcaternatingMediaSource . 这将允许您根据需要添加和删除播放列表,您可以在触发下载完整侦听器时附加新媒体文件 . 以下是使用列表的媒体源实现的完整类:

    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
         *     (i.e., 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 . A detailed example of how to set up the BroadcastReceiver is provided here.

相关问题