smoothstreaming simpleexoplayer mediasource extensions exoplayer2 app android exoplayer2.x

android - simpleexoplayer - Actualizar fuente de medios en exoplayer



mediasource exoplayer (1)

Para agregar nuevos archivos de video a su lista de reproducción, necesita una nueva implementación de MediaSource que pueda manejar una lista de fuentes para habilitar el cambio de tamaño. Esto es bastante simple de lograr, la forma más fácil de hacerlo es crear una implementación modificada de ConcaternatingMediaSource que use listas en lugar de matrices para almacenar e iterar sobre fuentes de medios. A continuación, reemplaza ConcaternatingMediaSource en playAndUpdateVideo con la nueva implementación usando listas. Esto le permitirá agregar y eliminar de su lista de reproducción como desee, puede agregar nuevos archivos de medios cuando se active la escucha completa de la descarga. Aquí está la clase completa para una implementación de fuente de medios usando listas:

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

Para verificar cuándo se descarga el archivo y configurar un servicio de escucha de descarga completa, puede usar un BroadcastReceiver . Un ejemplo detallado de cómo configurar BroadcastReceiver se proporciona aquí.

Estoy usando Exo Player ExtractorMediaSource para reproducir videos en mi aplicación de Android. Estoy descargando medios desde el servidor y los guardo en una base de datos local y en un momento específico. Alarma reproduzco estos medios utilizando ConcatenatingMediaSource en exo player. pero primero verifico si todos los archivos de video se descargaron o no, y comienzo el reproductor con la fuente de medios descargada. y si no se descarga ningún video, entonces quiero descargarlo en segundo plano cuando lo descargué, entonces quiero agregar este video a mi lista de reproducción ya creada

Este es un código de muestra.

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

Y aquí estoy comprobando si el archivo de video está descargado o no

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 }

Por favor, ayude a agregar el archivo de video faltante a la lista de reproducción si no se ha descargado.