Search in sources :

Example 46 with Segment

use of com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment in project ExoPlayer by google.

the class SegmentSpeedProvider method buildSpeedByStartTimeUsMap.

private static ImmutableSortedMap<Long, Float> buildSpeedByStartTimeUsMap(Format format, float baseSpeed) {
    List<Segment> segments = extractSlowMotionSegments(format);
    if (segments.isEmpty()) {
        return ImmutableSortedMap.of();
    }
    TreeMap<Long, Float> speedsByStartTimeUs = new TreeMap<>();
    // Start time maps to the segment speed.
    for (int i = 0; i < segments.size(); i++) {
        Segment currentSegment = segments.get(i);
        speedsByStartTimeUs.put(Util.msToUs(currentSegment.startTimeMs), baseSpeed / currentSegment.speedDivisor);
    }
    // segment.
    for (int i = 0; i < segments.size(); i++) {
        Segment currentSegment = segments.get(i);
        if (!speedsByStartTimeUs.containsKey(Util.msToUs(currentSegment.endTimeMs))) {
            speedsByStartTimeUs.put(Util.msToUs(currentSegment.endTimeMs), baseSpeed);
        }
    }
    return ImmutableSortedMap.copyOf(speedsByStartTimeUs);
}
Also used : TreeMap(java.util.TreeMap) Segment(com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment)

Example 47 with Segment

use of com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment in project ExoPlayer by google.

the class FakeDataSetTest method testSegmentTypes.

@Test
public void testSegmentTypes() {
    byte[] testData = TestUtil.buildTestData(3);
    Runnable runnable = () -> {
    // Do nothing.
    };
    IOException exception = new IOException();
    FakeDataSet fakeDataSet = new FakeDataSet().newDefaultData().appendReadData(testData).appendReadData(testData).appendReadData(50).appendReadAction(runnable).appendReadError(exception).endData();
    List<Segment> segments = fakeDataSet.getData((Uri) null).getSegments();
    assertThat(segments.size()).isEqualTo(5);
    assertSegment(segments.get(0), testData, 3, 0, null, null);
    assertSegment(segments.get(1), testData, 3, 3, null, null);
    assertSegment(segments.get(2), null, 50, 6, null, null);
    assertSegment(segments.get(3), null, 0, 56, runnable, null);
    assertSegment(segments.get(4), null, 0, 56, null, exception);
    byte[] allData = new byte[6];
    System.arraycopy(testData, 0, allData, 0, 3);
    System.arraycopy(testData, 0, allData, 3, 3);
    assertThat(fakeDataSet.getData((Uri) null).getData()).isEqualTo(allData);
}
Also used : IOException(java.io.IOException) Uri(android.net.Uri) Segment(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment) Test(org.junit.Test)

Example 48 with Segment

use of com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment in project ExoPlayer by google.

the class SegmentDownloader method download.

@Override
public final void download(@Nullable ProgressListener progressListener) throws IOException, InterruptedException {
    ArrayDeque<Segment> pendingSegments = new ArrayDeque<>();
    ArrayDeque<SegmentDownloadRunnable> recycledRunnables = new ArrayDeque<>();
    if (priorityTaskManager != null) {
        priorityTaskManager.add(C.PRIORITY_DOWNLOAD);
    }
    try {
        CacheDataSource dataSource = cacheDataSourceFactory.createDataSourceForDownloading();
        // Get the manifest and all of the segments.
        M manifest = getManifest(dataSource, manifestDataSpec, /* removing= */
        false);
        if (!streamKeys.isEmpty()) {
            manifest = manifest.copy(streamKeys);
        }
        List<Segment> segments = getSegments(dataSource, manifest, /* removing= */
        false);
        // Sort the segments so that we download media in the right order from the start of the
        // content, and merge segments where possible to minimize the number of server round trips.
        Collections.sort(segments);
        mergeSegments(segments, cacheKeyFactory);
        // Scan the segments, removing any that are fully downloaded.
        int totalSegments = segments.size();
        int segmentsDownloaded = 0;
        long contentLength = 0;
        long bytesDownloaded = 0;
        for (int i = segments.size() - 1; i >= 0; i--) {
            DataSpec dataSpec = segments.get(i).dataSpec;
            String cacheKey = cacheKeyFactory.buildCacheKey(dataSpec);
            long segmentLength = dataSpec.length;
            if (segmentLength == C.LENGTH_UNSET) {
                long resourceLength = ContentMetadata.getContentLength(cache.getContentMetadata(cacheKey));
                if (resourceLength != C.LENGTH_UNSET) {
                    segmentLength = resourceLength - dataSpec.position;
                }
            }
            long segmentBytesDownloaded = cache.getCachedBytes(cacheKey, dataSpec.position, segmentLength);
            bytesDownloaded += segmentBytesDownloaded;
            if (segmentLength != C.LENGTH_UNSET) {
                if (segmentLength == segmentBytesDownloaded) {
                    // The segment is fully downloaded.
                    segmentsDownloaded++;
                    segments.remove(i);
                }
                if (contentLength != C.LENGTH_UNSET) {
                    contentLength += segmentLength;
                }
            } else {
                contentLength = C.LENGTH_UNSET;
            }
        }
        // Download the segments.
        @Nullable ProgressNotifier progressNotifier = progressListener != null ? new ProgressNotifier(progressListener, contentLength, totalSegments, bytesDownloaded, segmentsDownloaded) : null;
        pendingSegments.addAll(segments);
        while (!isCanceled && !pendingSegments.isEmpty()) {
            // Block until there aren't any higher priority tasks.
            if (priorityTaskManager != null) {
                priorityTaskManager.proceed(C.PRIORITY_DOWNLOAD);
            }
            // Create and execute a runnable to download the next segment.
            CacheDataSource segmentDataSource;
            byte[] temporaryBuffer;
            if (!recycledRunnables.isEmpty()) {
                SegmentDownloadRunnable recycledRunnable = recycledRunnables.removeFirst();
                segmentDataSource = recycledRunnable.dataSource;
                temporaryBuffer = recycledRunnable.temporaryBuffer;
            } else {
                segmentDataSource = cacheDataSourceFactory.createDataSourceForDownloading();
                temporaryBuffer = new byte[BUFFER_SIZE_BYTES];
            }
            Segment segment = pendingSegments.removeFirst();
            SegmentDownloadRunnable downloadRunnable = new SegmentDownloadRunnable(segment, segmentDataSource, progressNotifier, temporaryBuffer);
            addActiveRunnable(downloadRunnable);
            executor.execute(downloadRunnable);
            // Clean up runnables that have finished.
            for (int j = activeRunnables.size() - 1; j >= 0; j--) {
                SegmentDownloadRunnable activeRunnable = (SegmentDownloadRunnable) activeRunnables.get(j);
                // it's already finished.
                if (pendingSegments.isEmpty() || activeRunnable.isDone()) {
                    try {
                        activeRunnable.get();
                        removeActiveRunnable(j);
                        recycledRunnables.addLast(activeRunnable);
                    } catch (ExecutionException e) {
                        Throwable cause = Assertions.checkNotNull(e.getCause());
                        if (cause instanceof PriorityTooLowException) {
                            // We need to schedule this segment again in a future loop iteration.
                            pendingSegments.addFirst(activeRunnable.segment);
                            removeActiveRunnable(j);
                            recycledRunnables.addLast(activeRunnable);
                        } else if (cause instanceof IOException) {
                            throw (IOException) cause;
                        } else {
                            // The cause must be an uncaught Throwable type.
                            Util.sneakyThrow(cause);
                        }
                    }
                }
            }
            // Don't move on to the next segment until the runnable for this segment has started. This
            // drip feeds runnables to the executor, rather than providing them all up front.
            downloadRunnable.blockUntilStarted();
        }
    } finally {
        // Cancel them to speed this up.
        for (int i = 0; i < activeRunnables.size(); i++) {
            activeRunnables.get(i).cancel(/* interruptIfRunning= */
            true);
        }
        // do this for the case where the main download thread was interrupted as part of cancelation.
        for (int i = activeRunnables.size() - 1; i >= 0; i--) {
            activeRunnables.get(i).blockUntilFinished();
            removeActiveRunnable(i);
        }
        if (priorityTaskManager != null) {
            priorityTaskManager.remove(C.PRIORITY_DOWNLOAD);
        }
    }
}
Also used : IOException(java.io.IOException) ArrayDeque(java.util.ArrayDeque) PriorityTooLowException(com.google.android.exoplayer2.util.PriorityTaskManager.PriorityTooLowException) CacheDataSource(com.google.android.exoplayer2.upstream.cache.CacheDataSource) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) ExecutionException(java.util.concurrent.ExecutionException) Nullable(androidx.annotation.Nullable)

Example 49 with Segment

use of com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment in project ExoPlayer by google.

the class SefSlowMotionFlattenerTest method getCurrentFrameOutputTimeUs_120fps_outputsExpectedTimes.

@Test
public void getCurrentFrameOutputTimeUs_120fps_outputsExpectedTimes() {
    int captureFrameRate = 120;
    int inputMaxLayer = 3;
    int frameCount = 16;
    SlowMotionData.Segment segment1 = new SlowMotionData.Segment(/* startTimeMs= */
    50, /* endTimeMs= */
    150, /* speedDivisor= */
    2);
    SlowMotionData.Segment segment2 = new SlowMotionData.Segment(/* startTimeMs= */
    210, /* endTimeMs= */
    360, /* speedDivisor= */
    8);
    Format format = createSefSlowMotionFormat(captureFrameRate, inputMaxLayer, Arrays.asList(segment1, segment2));
    SefSlowMotionFlattener sefSlowMotionFlattener = new SefSlowMotionFlattener(format);
    List<Long> outputTimesUs = getOutputTimesUs(sefSlowMotionFlattener, LAYER_SEQUENCE_MAX_LAYER_THREE, frameCount);
    // Test frame inside segment.
    assertThat(outputTimesUs.get(9)).isEqualTo(Math.round((300.0 + 100 + (300 - 210) * 7) * 1000 * 30 / 120));
    // Test frame outside segment.
    assertThat(outputTimesUs.get(13)).isEqualTo(Math.round((433 + 1 / 3.0 + 100 + 150 * 7) * 1000 * 30 / 120));
}
Also used : Format(com.google.android.exoplayer2.Format) SlowMotionData(com.google.android.exoplayer2.metadata.mp4.SlowMotionData) Test(org.junit.Test)

Example 50 with Segment

use of com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment in project ExoPlayer by google.

the class SefSlowMotionFlattenerTest method getCurrentFrameOutputTimeUs_contiguousSegments_outputsExpectedTimes.

@Test
public void getCurrentFrameOutputTimeUs_contiguousSegments_outputsExpectedTimes() {
    int captureFrameRate = 240;
    int inputMaxLayer = 3;
    int frameCount = 16;
    SlowMotionData.Segment segment1 = new SlowMotionData.Segment(/* startTimeMs= */
    50, /* endTimeMs= */
    210, /* speedDivisor= */
    2);
    SlowMotionData.Segment segment2 = new SlowMotionData.Segment(/* startTimeMs= */
    210, /* endTimeMs= */
    360, /* speedDivisor= */
    8);
    Format format = createSefSlowMotionFormat(captureFrameRate, inputMaxLayer, Arrays.asList(segment1, segment2));
    SefSlowMotionFlattener sefSlowMotionFlattener = new SefSlowMotionFlattener(format);
    List<Long> outputTimesUs = getOutputTimesUs(sefSlowMotionFlattener, LAYER_SEQUENCE_MAX_LAYER_THREE, frameCount);
    // Test frame inside second segment.
    assertThat(outputTimesUs.get(9)).isEqualTo(136_250);
}
Also used : Format(com.google.android.exoplayer2.Format) SlowMotionData(com.google.android.exoplayer2.metadata.mp4.SlowMotionData) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)20 Uri (android.net.Uri)18 Segment (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)18 Nullable (androidx.annotation.Nullable)16 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)11 ByteArrayInputStream (java.io.ByteArrayInputStream)9 IOException (java.io.IOException)9 InputStream (java.io.InputStream)9 ArrayList (java.util.ArrayList)9 HlsMediaPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist)8 Format (com.google.android.exoplayer2.Format)6 SlowMotionData (com.google.android.exoplayer2.metadata.mp4.SlowMotionData)5 SingleSampleMediaChunk (com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk)5 RangedUri (com.google.android.exoplayer2.source.dash.manifest.RangedUri)5 Representation (com.google.android.exoplayer2.source.dash.manifest.Representation)5 BehindLiveWindowException (com.google.android.exoplayer2.source.BehindLiveWindowException)4 ContainerMediaChunk (com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)4 Segment (com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)4 Window (com.google.android.exoplayer2.Timeline.Window)3 Segment (com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment)3