Commit 2623b4b3 by olly Committed by Toni

Pre-resolve HlsUrl urls

This is to make it possible to use equality of HlsUrl.url fields
to determine whether two HlsUrls point at the same media playlist.
This doesn't work currently because it's possible to mix absolute
and relative urls, which will not be equal until after the relative
url is resolved against the playlist baseUrl.

Issue: #5596
Issue: #2600
PiperOrigin-RevId: 240966503
parent 32924e3f
......@@ -78,16 +78,15 @@ public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
@Override
protected List<Segment> getSegments(
DataSource dataSource, HlsPlaylist playlist, boolean allowIncompleteList) throws IOException {
String baseUri = playlist.baseUri;
ArrayList<DataSpec> mediaPlaylistDataSpecs = new ArrayList<>();
if (playlist instanceof HlsMasterPlaylist) {
HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) playlist;
addMediaPlaylistDataSpecs(baseUri, masterPlaylist.variants, mediaPlaylistDataSpecs);
addMediaPlaylistDataSpecs(baseUri, masterPlaylist.audios, mediaPlaylistDataSpecs);
addMediaPlaylistDataSpecs(baseUri, masterPlaylist.subtitles, mediaPlaylistDataSpecs);
addMediaPlaylistDataSpecs(masterPlaylist.variants, mediaPlaylistDataSpecs);
addMediaPlaylistDataSpecs(masterPlaylist.audios, mediaPlaylistDataSpecs);
addMediaPlaylistDataSpecs(masterPlaylist.subtitles, mediaPlaylistDataSpecs);
} else {
mediaPlaylistDataSpecs.add(SegmentDownloader.getCompressibleDataSpec(Uri.parse(baseUri)));
mediaPlaylistDataSpecs.add(
SegmentDownloader.getCompressibleDataSpec(Uri.parse(playlist.baseUri)));
}
ArrayList<Segment> segments = new ArrayList<>();
......@@ -119,11 +118,9 @@ public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
return segments;
}
private void addMediaPlaylistDataSpecs(
String baseUri, List<? extends HlsUrl> urls, List<DataSpec> out) {
private void addMediaPlaylistDataSpecs(List<? extends HlsUrl> urls, List<DataSpec> out) {
for (int i = 0; i < urls.size(); i++) {
Uri playlistUri = UriUtil.resolveToUri(baseUri, urls.get(i).url);
out.add(SegmentDownloader.getCompressibleDataSpec(playlistUri));
out.add(SegmentDownloader.getCompressibleDataSpec(urls.get(i).url));
}
}
......
......@@ -32,7 +32,6 @@ import com.google.android.exoplayer2.upstream.Loader;
import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction;
import com.google.android.exoplayer2.upstream.ParsingLoadable;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.UriUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.IdentityHashMap;
......@@ -454,7 +453,7 @@ public final class DefaultHlsPlaylistTracker
mediaPlaylistLoadable =
new ParsingLoadable<>(
dataSourceFactory.createDataSource(C.DATA_TYPE_MANIFEST),
UriUtil.resolveToUri(masterPlaylist.baseUri, playlistUrl.url),
playlistUrl.url,
C.DATA_TYPE_MANIFEST,
mediaPlaylistParser);
}
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source.hls.playlist;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.drm.DrmInitData;
......@@ -52,10 +53,8 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
/** Represents a url in an HLS master playlist. */
public abstract static class HlsUrl {
/**
* The http url from which the media playlist can be obtained.
*/
public final String url;
/** The http url from which the media playlist can be obtained. */
public final Uri url;
/**
* Format information associated with the HLS url.
*/
......@@ -65,7 +64,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
* @param url See {@link #url}.
* @param format See {@link #format}.
*/
public HlsUrl(String url, Format format) {
public HlsUrl(Uri url, Format format) {
this.url = url;
this.format = format;
}
......@@ -95,7 +94,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
* @param captionGroupId See {@link #captionGroupId}.
*/
public Variant(
String url,
Uri url,
Format format,
@Nullable String videoGroupId,
@Nullable String audioGroupId,
......@@ -114,7 +113,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
* @param url The media playlist url.
* @return The variant instance.
*/
public static Variant createMediaPlaylistVariantUrl(String url) {
public static Variant createMediaPlaylistVariantUrl(Uri url) {
Format format =
Format.createContainerFormat(
"0",
......@@ -151,7 +150,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
* @param groupId See {@link #groupId}.
* @param name See {@link #name}.
*/
public Rendition(String url, Format format, String groupId, String name) {
public Rendition(Uri url, Format format, String groupId, String name) {
super(url, format);
this.groupId = groupId;
this.name = name;
......@@ -253,7 +252,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
*/
public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) {
List<Variant> variant =
Collections.singletonList(Variant.createMediaPlaylistVariantUrl(variantUrl));
Collections.singletonList(Variant.createMediaPlaylistVariantUrl(Uri.parse(variantUrl)));
return new HlsMasterPlaylist(
/* baseUri= */ null,
/* tags= */ Collections.emptyList(),
......
......@@ -31,6 +31,7 @@ import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Varia
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment;
import com.google.android.exoplayer2.upstream.ParsingLoadable;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.UriUtil;
import com.google.android.exoplayer2.util.Util;
import java.io.BufferedReader;
import java.io.IOException;
......@@ -337,6 +338,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
line =
replaceVariableReferences(
iterator.next(), variableDefinitions); // #EXT-X-STREAM-INF's URI.
Uri uri = UriUtil.resolveToUri(baseUri, line);
Format format =
Format.createVideoContainerFormat(
/* id= */ Integer.toString(variants.size()),
......@@ -353,7 +355,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
/* roleFlags= */ 0);
Variant variant =
new Variant(
line, format, videoGroupId, audioGroupId, subtitlesGroupId, closedCaptionsGroupId);
uri, format, videoGroupId, audioGroupId, subtitlesGroupId, closedCaptionsGroupId);
variants.add(variant);
// TODO: Don't deduplicate variants by URL.
if (variantUrls.add(line)) {
......@@ -366,7 +368,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
line = mediaTags.get(i);
String groupId = parseStringAttr(line, REGEX_GROUP_ID, variableDefinitions);
String name = parseStringAttr(line, REGEX_NAME, variableDefinitions);
String uri = parseOptionalStringAttr(line, REGEX_URI, variableDefinitions);
String referenceUri = parseOptionalStringAttr(line, REGEX_URI, variableDefinitions);
Uri uri = referenceUri == null ? null : UriUtil.resolveToUri(baseUri, referenceUri);
String language = parseOptionalStringAttr(line, REGEX_LANGUAGE, variableDefinitions);
@C.SelectionFlags int selectionFlags = parseSelectionFlags(line);
@C.RoleFlags int roleFlags = parseRoleFlags(line, variableDefinitions);
......
......@@ -88,14 +88,14 @@ public interface HlsPlaylistTracker {
final class PlaylistStuckException extends IOException {
/** The url of the stuck playlist. */
public final String url;
public final Uri url;
/**
* Creates an instance.
*
* @param url See {@link #url}.
*/
public PlaylistStuckException(String url) {
public PlaylistStuckException(Uri url) {
this.url = url;
}
}
......@@ -104,14 +104,14 @@ public interface HlsPlaylistTracker {
final class PlaylistResetException extends IOException {
/** The url of the reset playlist. */
public final String url;
public final Uri url;
/**
* Creates an instance.
*
* @param url See {@link #url}.
*/
public PlaylistResetException(String url) {
public PlaylistResetException(Uri url) {
this.url = url;
}
}
......
......@@ -19,6 +19,7 @@ import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
......@@ -120,7 +121,6 @@ public final class HlsMediaPeriodTest {
private static Variant createMuxedVideoAudioVariant(int bitrate) {
return createVariant(
"http://url",
Format.createVideoContainerFormat(
/* id= */ null,
/* label= */ null,
......@@ -138,7 +138,6 @@ public final class HlsMediaPeriodTest {
private static Variant createAudioOnlyVariant(int bitrate) {
return createVariant(
"http://url",
Format.createVideoContainerFormat(
/* id= */ null,
/* label= */ null,
......@@ -155,19 +154,19 @@ public final class HlsMediaPeriodTest {
}
private static Rendition createAudioRendition(String language) {
return createRendition("http://url", createAudioFormat(language), "", "");
return createRendition(createAudioFormat(language), "", "");
}
private static Rendition createSubtitleRendition(String language) {
return createRendition("http://url", createSubtitleFormat(language), "", "");
return createRendition(createSubtitleFormat(language), "", "");
}
private static Variant createVariant(String url, Format format) {
return new Variant(url, format, null, null, null, null);
private static Variant createVariant(Format format) {
return new Variant(Uri.parse("https://variant"), format, null, null, null, null);
}
private static Rendition createRendition(String url, Format format, String groupId, String name) {
return new Rendition(url, format, groupId, name);
private static Rendition createRendition(Format format, String groupId, String name) {
return new Rendition(Uri.parse("https://rendition"), format, groupId, name);
}
private static Format createAudioFormat(String language) {
......
......@@ -158,32 +158,33 @@ public class HlsMasterPlaylistParserTest {
assertThat(variants.get(0).format.codecs).isEqualTo("mp4a.40.2,avc1.66.30");
assertThat(variants.get(0).format.width).isEqualTo(304);
assertThat(variants.get(0).format.height).isEqualTo(128);
assertThat(variants.get(0).url).isEqualTo("http://example.com/low.m3u8");
assertThat(variants.get(0).url).isEqualTo(Uri.parse("http://example.com/low.m3u8"));
assertThat(variants.get(1).format.bitrate).isEqualTo(1280000);
assertThat(variants.get(1).format.codecs).isEqualTo("mp4a.40.2 , avc1.66.30 ");
assertThat(variants.get(1).url).isEqualTo("http://example.com/spaces_in_codecs.m3u8");
assertThat(variants.get(1).url)
.isEqualTo(Uri.parse("http://example.com/spaces_in_codecs.m3u8"));
assertThat(variants.get(2).format.bitrate).isEqualTo(2560000);
assertThat(variants.get(2).format.codecs).isNull();
assertThat(variants.get(2).format.width).isEqualTo(384);
assertThat(variants.get(2).format.height).isEqualTo(160);
assertThat(variants.get(2).format.frameRate).isEqualTo(25.0f);
assertThat(variants.get(2).url).isEqualTo("http://example.com/mid.m3u8");
assertThat(variants.get(2).url).isEqualTo(Uri.parse("http://example.com/mid.m3u8"));
assertThat(variants.get(3).format.bitrate).isEqualTo(7680000);
assertThat(variants.get(3).format.codecs).isNull();
assertThat(variants.get(3).format.width).isEqualTo(Format.NO_VALUE);
assertThat(variants.get(3).format.height).isEqualTo(Format.NO_VALUE);
assertThat(variants.get(3).format.frameRate).isEqualTo(29.997f);
assertThat(variants.get(3).url).isEqualTo("http://example.com/hi.m3u8");
assertThat(variants.get(3).url).isEqualTo(Uri.parse("http://example.com/hi.m3u8"));
assertThat(variants.get(4).format.bitrate).isEqualTo(65000);
assertThat(variants.get(4).format.codecs).isEqualTo("mp4a.40.5");
assertThat(variants.get(4).format.width).isEqualTo(Format.NO_VALUE);
assertThat(variants.get(4).format.height).isEqualTo(Format.NO_VALUE);
assertThat(variants.get(4).format.frameRate).isEqualTo((float) Format.NO_VALUE);
assertThat(variants.get(4).url).isEqualTo("http://example.com/audio-only.m3u8");
assertThat(variants.get(4).url).isEqualTo(Uri.parse("http://example.com/audio-only.m3u8"));
}
@Test
......@@ -291,7 +292,8 @@ public class HlsMasterPlaylistParserTest {
parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_VARIABLE_SUBSTITUTION);
HlsMasterPlaylist.HlsUrl variant = playlistWithSubstitutions.variants.get(0);
assertThat(variant.format.codecs).isEqualTo("mp4a.40.5");
assertThat(variant.url).isEqualTo("http://example.com/This/{$nested}/reference/shouldnt/work");
assertThat(variant.url)
.isEqualTo(Uri.parse("http://example.com/This/{$nested}/reference/shouldnt/work"));
}
private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment