Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make merged segment size configurable #248

Merged
merged 1 commit into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public int compareTo(Segment other) {
}

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 Parser<M> manifestParser;
Expand All @@ -86,6 +86,7 @@ public int compareTo(Segment other) {
private final CacheKeyFactory cacheKeyFactory;
@Nullable private final PriorityTaskManager priorityTaskManager;
private final Executor executor;
private final long maxMergedSegmentStartTimeDiffUs;

/**
* The currently active runnables.
Expand All @@ -99,6 +100,30 @@ public int compareTo(Segment other) {

private volatile boolean isCanceled;

/**
* @deprecated Use {@link SegmentDownloader#SegmentDownloader(MediaItem, Parser,
* CacheDataSource.Factory, Executor, long)} instead.
*/
@Deprecated
public SegmentDownloader(
MediaItem mediaItem,
Parser<M> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor
) {
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 = 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.
Expand All @@ -107,12 +132,17 @@ public int compareTo(Segment other) {
* @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) {
Executor executor,
long maxMergedSegmentStartTimeDiffMs
) {
checkNotNull(mediaItem.localConfiguration);
this.manifestDataSpec = getCompressibleDataSpec(mediaItem.localConfiguration.uri);
this.manifestParser = manifestParser;
Expand All @@ -123,6 +153,7 @@ public SegmentDownloader(
cacheKeyFactory = cacheDataSourceFactory.getCacheKeyFactory();
priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager();
activeRunnables = new ArrayList<>();
maxMergedSegmentStartTimeDiffUs = Util.msToUs(maxMergedSegmentStartTimeDiffMs);
}

@Override
Expand All @@ -145,7 +176,7 @@ public final void download(@Nullable ProgressListener progressListener)
// 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);
mergeSegments(segments, cacheKeyFactory, maxMergedSegmentStartTimeDiffUs);

// Scan the segments, removing any that are fully downloaded.
int totalSegments = segments.size();
Expand Down Expand Up @@ -416,7 +447,11 @@ private void removeActiveRunnable(int index) {
}
}

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<>();
int nextOutIndex = 0;
for (int i = 0; i < segments.size(); i++) {
Expand All @@ -425,7 +460,7 @@ private static void mergeSegments(List<Segment> segments, CacheKeyFactory keyFac
@Nullable Integer lastIndex = lastIndexByCacheKey.get(cacheKey);
@Nullable Segment lastSegment = lastIndex == null ? null : segments.get(lastIndex);
if (lastSegment == null
|| segment.startTimeUs > lastSegment.startTimeUs + MAX_MERGED_SEGMENT_START_TIME_DIFF_US
|| segment.startTimeUs > lastSegment.startTimeUs + maxMergedSegmentStartTimeDiffUs
|| !canMergeSegments(lastSegment.dataSpec, segment.dataSpec)) {
lastIndexByCacheKey.put(cacheKey, nextOutIndex);
segments.set(nextOutIndex, segment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,28 @@ public DashDownloader(MediaItem mediaItem, CacheDataSource.Factory cacheDataSour
*/
public DashDownloader(
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();
}

/**
Expand All @@ -113,13 +134,24 @@ public DashDownloader(
* @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 DashDownloader(
MediaItem mediaItem,
Parser<DashManifest> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
super(mediaItem, manifestParser, cacheDataSourceFactory, executor);
Executor executor,
long maxMergedSegmentStartTimeDiffMs
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
maxMergedSegmentStartTimeDiffMs
);
baseUrlExclusionList = new BaseUrlExclusionList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,33 @@ public HlsDownloader(MediaItem mediaItem, CacheDataSource.Factory cacheDataSourc
*/
public HlsDownloader(
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
);
}

/**
Expand All @@ -102,13 +128,24 @@ public HlsDownloader(
* @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 HlsDownloader(
MediaItem mediaItem,
Parser<HlsPlaylist> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
super(mediaItem, manifestParser, cacheDataSourceFactory, executor);
Executor executor,
long maxMergedSegmentStartTimeDiffMs
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
maxMergedSegmentStartTimeDiffMs
);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,29 @@ public SsDownloader(
.build(),
new SsManifestParser(),
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
);
}

/**
Expand All @@ -106,13 +128,24 @@ public SsDownloader(
* @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 SsDownloader(
MediaItem mediaItem,
Parser<SsManifest> manifestParser,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
super(mediaItem, manifestParser, cacheDataSourceFactory, executor);
Executor executor,
long maxMergedSegmentStartTimeDiffMs
) {
super(
mediaItem,
manifestParser,
cacheDataSourceFactory,
executor,
maxMergedSegmentStartTimeDiffMs
);
}

@Override
Expand Down