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