make merged segment size configurable

This commit is contained in:
lemondoglol 2023-01-30 10:57:45 -05:00
parent e2ece2f5bc
commit b65baf7d72
4 changed files with 158 additions and 21 deletions

View File

@ -76,7 +76,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
} }
private static final int BUFFER_SIZE_BYTES = 128 * 1024; private static final int BUFFER_SIZE_BYTES = 128 * 1024;
private static final long MAX_MERGED_SEGMENT_START_TIME_DIFF_US = 20 * C.MICROS_PER_SECOND; public static final long DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_US = 20 * C.MICROS_PER_SECOND;
private final DataSpec manifestDataSpec; private final DataSpec manifestDataSpec;
private final Parser<M> manifestParser; private final Parser<M> manifestParser;
@ -86,6 +86,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
private final CacheKeyFactory cacheKeyFactory; private final CacheKeyFactory cacheKeyFactory;
@Nullable private final PriorityTaskManager priorityTaskManager; @Nullable private final PriorityTaskManager priorityTaskManager;
private final Executor executor; private final Executor executor;
private final long maxMergedSegmentStartTimeDiffUs;
/** /**
* The currently active runnables. * The currently active runnables.
@ -100,19 +101,16 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
private volatile boolean isCanceled; private volatile boolean isCanceled;
/** /**
* @param mediaItem The {@link MediaItem} to be downloaded. * @deprecated Use {@link SegmentDownloader#SegmentDownloader(MediaItem, Parser,
* @param manifestParser A parser for manifests belonging to the media to be downloaded. * CacheDataSource.Factory, Executor, long)} instead.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
* @param executor An {@link Executor} used to make requests for the media being downloaded.
* Providing an {@link Executor} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel.
*/ */
@Deprecated
public SegmentDownloader( public SegmentDownloader(
MediaItem mediaItem, MediaItem mediaItem,
Parser<M> manifestParser, Parser<M> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory, CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) { Executor executor
) {
checkNotNull(mediaItem.localConfiguration); checkNotNull(mediaItem.localConfiguration);
this.manifestDataSpec = getCompressibleDataSpec(mediaItem.localConfiguration.uri); this.manifestDataSpec = getCompressibleDataSpec(mediaItem.localConfiguration.uri);
this.manifestParser = manifestParser; this.manifestParser = manifestParser;
@ -123,6 +121,39 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
cacheKeyFactory = cacheDataSourceFactory.getCacheKeyFactory(); cacheKeyFactory = cacheDataSourceFactory.getCacheKeyFactory();
priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager(); priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager();
activeRunnables = new ArrayList<>(); activeRunnables = new ArrayList<>();
maxMergedSegmentStartTimeDiffUs = DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_US;
}
/**
* @param mediaItem The {@link MediaItem} to be downloaded.
* @param manifestParser A parser for manifests belonging to the media to be downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
* @param executor An {@link Executor} used to make requests for the media being downloaded.
* Providing an {@link Executor} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel.
* @param maxMergedSegmentStartTimeDiffMs The maximum difference of the start time of two segments,
* up to which the segments (of the same URI) should be merged into a single download segment,
* in milliseconds.
*/
public SegmentDownloader(
MediaItem mediaItem,
Parser<M> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor,
long maxMergedSegmentStartTimeDiffMs
) {
checkNotNull(mediaItem.localConfiguration);
this.manifestDataSpec = getCompressibleDataSpec(mediaItem.localConfiguration.uri);
this.manifestParser = manifestParser;
this.streamKeys = new ArrayList<>(mediaItem.localConfiguration.streamKeys);
this.cacheDataSourceFactory = cacheDataSourceFactory;
this.executor = executor;
cache = Assertions.checkNotNull(cacheDataSourceFactory.getCache());
cacheKeyFactory = cacheDataSourceFactory.getCacheKeyFactory();
priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager();
activeRunnables = new ArrayList<>();
maxMergedSegmentStartTimeDiffUs = Util.msToUs(maxMergedSegmentStartTimeDiffMs);
} }
@Override @Override
@ -145,7 +176,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
// Sort the segments so that we download media in the right order from the start of the // 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. // content, and merge segments where possible to minimize the number of server round trips.
Collections.sort(segments); Collections.sort(segments);
mergeSegments(segments, cacheKeyFactory); mergeSegments(segments, cacheKeyFactory, maxMergedSegmentStartTimeDiffUs);
// Scan the segments, removing any that are fully downloaded. // Scan the segments, removing any that are fully downloaded.
int totalSegments = segments.size(); int totalSegments = segments.size();
@ -416,7 +447,11 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
} }
} }
private static void mergeSegments(List<Segment> segments, CacheKeyFactory keyFactory) { private static void mergeSegments(
List<Segment> segments,
CacheKeyFactory keyFactory,
long maxMergedSegmentStartTimeDiffUs
) {
HashMap<String, Integer> lastIndexByCacheKey = new HashMap<>(); HashMap<String, Integer> lastIndexByCacheKey = new HashMap<>();
int nextOutIndex = 0; int nextOutIndex = 0;
for (int i = 0; i < segments.size(); i++) { for (int i = 0; i < segments.size(); i++) {
@ -425,7 +460,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
@Nullable Integer lastIndex = lastIndexByCacheKey.get(cacheKey); @Nullable Integer lastIndex = lastIndexByCacheKey.get(cacheKey);
@Nullable Segment lastSegment = lastIndex == null ? null : segments.get(lastIndex); @Nullable Segment lastSegment = lastIndex == null ? null : segments.get(lastIndex);
if (lastSegment == null if (lastSegment == null
|| segment.startTimeUs > lastSegment.startTimeUs + MAX_MERGED_SEGMENT_START_TIME_DIFF_US || segment.startTimeUs > lastSegment.startTimeUs + maxMergedSegmentStartTimeDiffUs
|| !canMergeSegments(lastSegment.dataSpec, segment.dataSpec)) { || !canMergeSegments(lastSegment.dataSpec, segment.dataSpec)) {
lastIndexByCacheKey.put(cacheKey, nextOutIndex); lastIndexByCacheKey.put(cacheKey, nextOutIndex);
segments.set(nextOutIndex, segment); segments.set(nextOutIndex, segment);

View File

@ -100,7 +100,28 @@ public final class DashDownloader extends SegmentDownloader<DashManifest> {
*/ */
public DashDownloader( public DashDownloader(
MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) { MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) {
this(mediaItem, new DashManifestParser(), cacheDataSourceFactory, executor); this(mediaItem, new DashManifestParser(), cacheDataSourceFactory, executor, DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_US);
}
/**
* @deprecated Use {@link DashDownloader#DashDownloader(MediaItem, Parser,
* CacheDataSource.Factory, Executor, long)} instead.
*/
@Deprecated
public DashDownloader(
MediaItem mediaItem,
Parser<DashManifest> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_US
);
baseUrlExclusionList = new BaseUrlExclusionList();
} }
/** /**
@ -113,13 +134,24 @@ public final class DashDownloader extends SegmentDownloader<DashManifest> {
* @param executor An {@link Executor} used to make requests for the media being downloaded. * @param executor An {@link Executor} used to make requests for the media being downloaded.
* Providing an {@link Executor} that uses multiple threads will speed up the download by * Providing an {@link Executor} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel. * allowing parts of it to be executed in parallel.
* @param maxMergedSegmentStartTimeDiffMs The maximum difference of the start time of two segments,
* up to which the segments (of the same URI) should be merged into a single download segment,
* in milliseconds.
*/ */
public DashDownloader( public DashDownloader(
MediaItem mediaItem, MediaItem mediaItem,
Parser<DashManifest> manifestParser, Parser<DashManifest> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory, CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) { Executor executor,
super(mediaItem, manifestParser, cacheDataSourceFactory, executor); long maxMergedSegmentStartTimeDiffMs
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
maxMergedSegmentStartTimeDiffMs
);
baseUrlExclusionList = new BaseUrlExclusionList(); baseUrlExclusionList = new BaseUrlExclusionList();
} }

View File

@ -89,7 +89,33 @@ public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
*/ */
public HlsDownloader( public HlsDownloader(
MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) { MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) {
this(mediaItem, new HlsPlaylistParser(), cacheDataSourceFactory, executor); this(
mediaItem,
new HlsPlaylistParser(),
cacheDataSourceFactory,
executor,
DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_US
);
}
/**
* @deprecated Use {@link HlsDownloader#HlsDownloader(MediaItem, Parser,
* CacheDataSource.Factory, Executor, long)} instead.
*/
@Deprecated
public HlsDownloader(
MediaItem mediaItem,
Parser<HlsPlaylist> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_US
);
} }
/** /**
@ -102,13 +128,24 @@ public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
* @param executor An {@link Executor} used to make requests for the media being downloaded. * @param executor An {@link Executor} used to make requests for the media being downloaded.
* Providing an {@link Executor} that uses multiple threads will speed up the download by * Providing an {@link Executor} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel. * allowing parts of it to be executed in parallel.
* @param maxMergedSegmentStartTimeDiffMs The maximum difference of the start time of two segments,
* up to which the segments (of the same URI) should be merged into a single download segment,
* in milliseconds.
*/ */
public HlsDownloader( public HlsDownloader(
MediaItem mediaItem, MediaItem mediaItem,
Parser<HlsPlaylist> manifestParser, Parser<HlsPlaylist> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory, CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) { Executor executor,
super(mediaItem, manifestParser, cacheDataSourceFactory, executor); long maxMergedSegmentStartTimeDiffMs
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
maxMergedSegmentStartTimeDiffMs
);
} }
@Override @Override

View File

@ -93,7 +93,29 @@ public final class SsDownloader extends SegmentDownloader<SsManifest> {
.build(), .build(),
new SsManifestParser(), new SsManifestParser(),
cacheDataSourceFactory, cacheDataSourceFactory,
executor); executor,
DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_US
);
}
/**
* @deprecated Use {@link SsDownloader#SsDownloader(MediaItem, Parser,
* CacheDataSource.Factory, Executor, long)} instead.
*/
@Deprecated
public SsDownloader(
MediaItem mediaItem,
Parser<SsManifest> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
DEFAULT_MAX_MERGED_SEGMENT_START_TIME_DIFF_US
);
} }
/** /**
@ -106,13 +128,24 @@ public final class SsDownloader extends SegmentDownloader<SsManifest> {
* @param executor An {@link Executor} used to make requests for the media being downloaded. * @param executor An {@link Executor} used to make requests for the media being downloaded.
* Providing an {@link Executor} that uses multiple threads will speed up the download by * Providing an {@link Executor} that uses multiple threads will speed up the download by
* allowing parts of it to be executed in parallel. * allowing parts of it to be executed in parallel.
* @param maxMergedSegmentStartTimeDiffMs The maximum difference of the start time of two segments,
* up to which the segments (of the same URI) should be merged into a single download segment,
* in milliseconds.
*/ */
public SsDownloader( public SsDownloader(
MediaItem mediaItem, MediaItem mediaItem,
Parser<SsManifest> manifestParser, Parser<SsManifest> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory, CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) { Executor executor,
super(mediaItem, manifestParser, cacheDataSourceFactory, executor); long maxMergedSegmentStartTimeDiffMs
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
maxMergedSegmentStartTimeDiffMs
);
} }
@Override @Override