当前位置: 首页 > 知识库问答 >
问题:

在exoplayer中刷新媒体源

楚宪
2023-03-14

我正在使用Exo Playerextractoremiasource在我的android应用程序中播放视频。我从服务器下载媒体并保存在本地数据库中,在特定的时间报警时,我在exo player中使用连接媒体源播放媒体。但首先我要检查所有的视频文件是否下载,并用下载的媒体源启动播放器。如果有任何视频没有下载,那么我想在下载时在后台下载,然后我想把这个视频添加到我已经创建的播放列表中

这是示例代码

  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个答案

许出野
2023-03-14

要将新的视频文件添加到播放列表中,您需要一个新的MediaSource实现,它可以处理源列表,以便调整大小。这很容易实现,最简单的方法是创建一个修改后的ConcaternatingMediaSource实现,它使用列表而不是数组来存储和迭代媒体源。然后将play和updatevideo中的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;
        }

    }

}

要检查文件何时下载并设置下载完成的侦听器,可以使用BroadcastRecencer。此处提供了如何设置BroadcastRecencer的详细示例。

 类似资料:
  • 我有一个应用程序,可以显示来自互联网的图片和视频。现在我正在实现一个“保存”功能,将图片/视频保存到外部或内部存储器中,无需再次下载。 对于图片,我只是用抓取绘图。我如何用Exoplayer2. x/PlayerView中当前缓冲的视频实现同样的效果?我没有找到一个函数。

  • 你好,我正在开发一个应用程序,我可以在其中使用widevine drm保护来播放dash stream。我已经阅读了exoplayer的示例,但我的需求不同,我会在我的网站上,当单击dash url时,它将开始在exoplayer中播放流。我已经成功地完成了打开exoplayer活动的第一部分,但是我不知道如何在exoplayer上运行受drm保护的流。 我知道流和drm许可证url。 我正在编写

  • 我正在开发一个应用程序,它可以流式传输mp3文件列表,为此,我使用了ExoPlayer和,如下所示: 这很好,文件以列表的形式播放,完全没有错误,但是我需要的是将所有这些流作为一个流播放,我在搜索栏上显示所有流的总长度,用户将在它们之间无缝搜索。 当然,我没有使用ExoPlayer提供的VideoPlayer,因为我需要seekbar来跨越所有媒体源,这显然是ExoPlayerUi无法做到的。 这

  • 一旦我向concatenatingMediaSource添加一首歌,我就会在它旁边添加一个标签,所以我想知道如何通过这个特定的标签播放一首歌。 obs:ctd是歌曲位置的参考号;

  • 有时我们需要更新媒体库以让应用自动发现最新的媒体库。 通过startMediaScan方法开始更新媒体库1: chrome.mediaGalleries.startMediaScan(); 1 从Chrome 35开始支持。 startMediaScan没有然后返回值,也不会调用任何回调函数,因为更新的过程所花费的时间可能非常长,所以要使用onScanProgress来监听更新过程: chrom

  • 1. 请分享一下你在选题方面的经验和思路,以及如何确保选题的新颖性和吸引力? 2.  当账号运营数据不太理想时,你会从哪些方面进行分析和复盘? 3. 对于私信维护和评论区维护,你有哪些具体的策略和方法? 4. 能否举例说明你是如何快速捕捉到热点并将其运用到账号内容中的? 5. 你在文案撰写方面有什么优势和成果? 6. 请谈一谈你对私域运营的理解以及如果让你负责私域运营,你会怎么做? 7. 在团队合