mirror of
https://github.com/androidx/media.git
synced 2025-05-10 17:22:13 +08:00
Merge pull request #574 from hugohlln:main
PiperOrigin-RevId: 570037211 (cherry picked from commit b06d82323865870e5c3572e867d3cc165200e497)
This commit is contained in:
parent
ecfddb9aeb
commit
948491f665
@ -24,6 +24,8 @@
|
|||||||
* Cronet Extension:
|
* Cronet Extension:
|
||||||
* RTMP Extension:
|
* RTMP Extension:
|
||||||
* HLS Extension:
|
* HLS Extension:
|
||||||
|
* DASH Extension:
|
||||||
|
* Allow multiple of the same DASH identifier in segment template url.
|
||||||
* Smooth Streaming Extension:
|
* Smooth Streaming Extension:
|
||||||
* RTSP Extension:
|
* RTSP Extension:
|
||||||
* Decoder Extensions (FFmpeg, VP9, AV1, etc.):
|
* Decoder Extensions (FFmpeg, VP9, AV1, etc.):
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
package androidx.media3.exoplayer.dash.manifest;
|
package androidx.media3.exoplayer.dash.manifest;
|
||||||
|
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,10 +40,9 @@ public final class UrlTemplate {
|
|||||||
private static final int BANDWIDTH_ID = 3;
|
private static final int BANDWIDTH_ID = 3;
|
||||||
private static final int TIME_ID = 4;
|
private static final int TIME_ID = 4;
|
||||||
|
|
||||||
private final String[] urlPieces;
|
private final List<String> urlPieces;
|
||||||
private final int[] identifiers;
|
private final List<Integer> identifiers;
|
||||||
private final String[] identifierFormatTags;
|
private final List<String> identifierFormatTags;
|
||||||
private final int identifierCount;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile an instance from the provided template string.
|
* Compile an instance from the provided template string.
|
||||||
@ -51,22 +52,20 @@ public final class UrlTemplate {
|
|||||||
* @throws IllegalArgumentException If the template string is malformed.
|
* @throws IllegalArgumentException If the template string is malformed.
|
||||||
*/
|
*/
|
||||||
public static UrlTemplate compile(String template) {
|
public static UrlTemplate compile(String template) {
|
||||||
// These arrays are sizes assuming each of the four possible identifiers will be present at
|
List<String> urlPieces = new ArrayList<>();
|
||||||
// most once in the template, which seems like a reasonable assumption.
|
List<Integer> identifiers = new ArrayList<>();
|
||||||
String[] urlPieces = new String[5];
|
List<String> identifierFormatTags = new ArrayList<>();
|
||||||
int[] identifiers = new int[4];
|
|
||||||
String[] identifierFormatTags = new String[4];
|
parseTemplate(template, urlPieces, identifiers, identifierFormatTags);
|
||||||
int identifierCount = parseTemplate(template, urlPieces, identifiers, identifierFormatTags);
|
return new UrlTemplate(urlPieces, identifiers, identifierFormatTags);
|
||||||
return new UrlTemplate(urlPieces, identifiers, identifierFormatTags, identifierCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Internal constructor. Use {@link #compile(String)} to build instances of this class. */
|
/** Internal constructor. Use {@link #compile(String)} to build instances of this class. */
|
||||||
private UrlTemplate(
|
private UrlTemplate(
|
||||||
String[] urlPieces, int[] identifiers, String[] identifierFormatTags, int identifierCount) {
|
List<String> urlPieces, List<Integer> identifiers, List<String> identifierFormatTags) {
|
||||||
this.urlPieces = urlPieces;
|
this.urlPieces = urlPieces;
|
||||||
this.identifiers = identifiers;
|
this.identifiers = identifiers;
|
||||||
this.identifierFormatTags = identifierFormatTags;
|
this.identifierFormatTags = identifierFormatTags;
|
||||||
this.identifierCount = identifierCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,58 +81,65 @@ public final class UrlTemplate {
|
|||||||
*/
|
*/
|
||||||
public String buildUri(String representationId, long segmentNumber, int bandwidth, long time) {
|
public String buildUri(String representationId, long segmentNumber, int bandwidth, long time) {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
for (int i = 0; i < identifierCount; i++) {
|
for (int i = 0; i < identifiers.size(); i++) {
|
||||||
builder.append(urlPieces[i]);
|
builder.append(urlPieces.get(i));
|
||||||
if (identifiers[i] == REPRESENTATION_ID) {
|
if (identifiers.get(i) == REPRESENTATION_ID) {
|
||||||
builder.append(representationId);
|
builder.append(representationId);
|
||||||
} else if (identifiers[i] == NUMBER_ID) {
|
} else if (identifiers.get(i) == NUMBER_ID) {
|
||||||
builder.append(String.format(Locale.US, identifierFormatTags[i], segmentNumber));
|
builder.append(String.format(Locale.US, identifierFormatTags.get(i), segmentNumber));
|
||||||
} else if (identifiers[i] == BANDWIDTH_ID) {
|
} else if (identifiers.get(i) == BANDWIDTH_ID) {
|
||||||
builder.append(String.format(Locale.US, identifierFormatTags[i], bandwidth));
|
builder.append(String.format(Locale.US, identifierFormatTags.get(i), bandwidth));
|
||||||
} else if (identifiers[i] == TIME_ID) {
|
} else if (identifiers.get(i) == TIME_ID) {
|
||||||
builder.append(String.format(Locale.US, identifierFormatTags[i], time));
|
builder.append(String.format(Locale.US, identifierFormatTags.get(i), time));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.append(urlPieces[identifierCount]);
|
builder.append(urlPieces.get(identifiers.size()));
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses {@code template}, placing the decomposed components into the provided arrays.
|
* Parses {@code template}, placing the decomposed components into the provided lists.
|
||||||
*
|
*
|
||||||
* <p>If the return value is N, {@code urlPieces} will contain (N+1) strings that must be
|
* <p>If the number of identifiers in the {@code template} is N, {@code urlPieces} will contain
|
||||||
* interleaved with N arguments in order to construct a url. The N identifiers that correspond to
|
* (N+1) strings that must be interleaved with those N arguments in order to construct a url. The
|
||||||
* the required arguments, together with the tags that define their required formatting, are
|
* N identifiers that correspond to the required arguments, together with the tags that define
|
||||||
* returned in {@code identifiers} and {@code identifierFormatTags} respectively.
|
* their required formatting, are returned in {@code identifiers} and {@code identifierFormatTags}
|
||||||
|
* respectively.
|
||||||
*
|
*
|
||||||
* @param template The template to parse.
|
* @param template The template to parse.
|
||||||
* @param urlPieces A holder for pieces of url parsed from the template.
|
* @param urlPieces A holder for pieces of url parsed from the template.
|
||||||
* @param identifiers A holder for identifiers parsed from the template.
|
* @param identifiers A holder for identifiers parsed from the template.
|
||||||
* @param identifierFormatTags A holder for format tags corresponding to the parsed identifiers.
|
* @param identifierFormatTags A holder for format tags corresponding to the parsed identifiers.
|
||||||
* @return The number of identifiers in the template url.
|
|
||||||
* @throws IllegalArgumentException If the template string is malformed.
|
* @throws IllegalArgumentException If the template string is malformed.
|
||||||
*/
|
*/
|
||||||
private static int parseTemplate(
|
private static void parseTemplate(
|
||||||
String template, String[] urlPieces, int[] identifiers, String[] identifierFormatTags) {
|
String template,
|
||||||
urlPieces[0] = "";
|
List<String> urlPieces,
|
||||||
|
List<Integer> identifiers,
|
||||||
|
List<String> identifierFormatTags) {
|
||||||
|
urlPieces.add("");
|
||||||
int templateIndex = 0;
|
int templateIndex = 0;
|
||||||
int identifierCount = 0;
|
|
||||||
while (templateIndex < template.length()) {
|
while (templateIndex < template.length()) {
|
||||||
int dollarIndex = template.indexOf("$", templateIndex);
|
int dollarIndex = template.indexOf("$", templateIndex);
|
||||||
if (dollarIndex == -1) {
|
if (dollarIndex == -1) {
|
||||||
urlPieces[identifierCount] += template.substring(templateIndex);
|
urlPieces.set(
|
||||||
|
identifiers.size(),
|
||||||
|
urlPieces.get(identifiers.size()) + template.substring(templateIndex));
|
||||||
templateIndex = template.length();
|
templateIndex = template.length();
|
||||||
} else if (dollarIndex != templateIndex) {
|
} else if (dollarIndex != templateIndex) {
|
||||||
urlPieces[identifierCount] += template.substring(templateIndex, dollarIndex);
|
urlPieces.set(
|
||||||
|
identifiers.size(),
|
||||||
|
urlPieces.get(identifiers.size()) + template.substring(templateIndex, dollarIndex));
|
||||||
templateIndex = dollarIndex;
|
templateIndex = dollarIndex;
|
||||||
} else if (template.startsWith(ESCAPED_DOLLAR, templateIndex)) {
|
} else if (template.startsWith(ESCAPED_DOLLAR, templateIndex)) {
|
||||||
urlPieces[identifierCount] += "$";
|
urlPieces.set(identifiers.size(), urlPieces.get(identifiers.size()) + "$");
|
||||||
templateIndex += 2;
|
templateIndex += 2;
|
||||||
} else {
|
} else {
|
||||||
|
identifierFormatTags.add("");
|
||||||
int secondIndex = template.indexOf("$", templateIndex + 1);
|
int secondIndex = template.indexOf("$", templateIndex + 1);
|
||||||
String identifier = template.substring(templateIndex + 1, secondIndex);
|
String identifier = template.substring(templateIndex + 1, secondIndex);
|
||||||
if (identifier.equals(REPRESENTATION)) {
|
if (identifier.equals(REPRESENTATION)) {
|
||||||
identifiers[identifierCount] = REPRESENTATION_ID;
|
identifiers.add(REPRESENTATION_ID);
|
||||||
} else {
|
} else {
|
||||||
int formatTagIndex = identifier.indexOf("%0");
|
int formatTagIndex = identifier.indexOf("%0");
|
||||||
String formatTag = DEFAULT_FORMAT_TAG;
|
String formatTag = DEFAULT_FORMAT_TAG;
|
||||||
@ -149,24 +155,22 @@ public final class UrlTemplate {
|
|||||||
}
|
}
|
||||||
switch (identifier) {
|
switch (identifier) {
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
identifiers[identifierCount] = NUMBER_ID;
|
identifiers.add(NUMBER_ID);
|
||||||
break;
|
break;
|
||||||
case BANDWIDTH:
|
case BANDWIDTH:
|
||||||
identifiers[identifierCount] = BANDWIDTH_ID;
|
identifiers.add(BANDWIDTH_ID);
|
||||||
break;
|
break;
|
||||||
case TIME:
|
case TIME:
|
||||||
identifiers[identifierCount] = TIME_ID;
|
identifiers.add(TIME_ID);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid template: " + template);
|
throw new IllegalArgumentException("Invalid template: " + template);
|
||||||
}
|
}
|
||||||
identifierFormatTags[identifierCount] = formatTag;
|
identifierFormatTags.set(identifiers.size() - 1, formatTag);
|
||||||
}
|
}
|
||||||
identifierCount++;
|
urlPieces.add("");
|
||||||
urlPieces[identifierCount] = "";
|
|
||||||
templateIndex = secondIndex + 1;
|
templateIndex = secondIndex + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return identifierCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,4 +70,22 @@ public class UrlTemplateTest {
|
|||||||
// Expected.
|
// Expected.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fullWithMultipleOccurrences() {
|
||||||
|
String template =
|
||||||
|
"$Bandwidth$_a1_$RepresentationID$_b1_$Time$_c1_$Number$_$Bandwidth$_a2_$RepresentationID$_b2_$Time$_c2_$Number$";
|
||||||
|
UrlTemplate urlTemplate = UrlTemplate.compile(template);
|
||||||
|
String url = urlTemplate.buildUri("abc1", 10, 650000, 5000);
|
||||||
|
assertThat(url).isEqualTo("650000_a1_abc1_b1_5000_c1_10_650000_a2_abc1_b2_5000_c2_10");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fullWithMultipleOccurrencesAndDollarEscaping() {
|
||||||
|
String template =
|
||||||
|
"$$$Bandwidth$$$_a1$$_$RepresentationID$_b1_$Time$_c1_$Number$$$_$$$Bandwidth$$$_a2$$_$RepresentationID$_b2_$Time$_c2_$Number$$$";
|
||||||
|
UrlTemplate urlTemplate = UrlTemplate.compile(template);
|
||||||
|
String url = urlTemplate.buildUri("abc1", 10, 650000, 5000);
|
||||||
|
assertThat(url).isEqualTo("$650000$_a1$_abc1_b1_5000_c1_10$_$650000$_a2$_abc1_b2_5000_c2_10$");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user