Add parsed essential/supplemental properties to the Representation.
We already parse essential and supplemental properties from the Representation, but don't add them to our Representation class so that they can be accessed by users. Issue: google/ExoPlayer#9579 PiperOrigin-RevId: 409961990
This commit is contained in:
parent
c0ffeb262c
commit
1618e0ef8e
@ -755,6 +755,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
drmSchemeType,
|
||||
drmSchemeDatas,
|
||||
inbandEventStreams,
|
||||
essentialProperties,
|
||||
supplementalProperties,
|
||||
Representation.REVISION_ID_DEFAULT);
|
||||
}
|
||||
|
||||
@ -843,7 +845,10 @@ public class DashManifestParser extends DefaultHandler
|
||||
formatBuilder.build(),
|
||||
representationInfo.baseUrls,
|
||||
representationInfo.segmentBase,
|
||||
inbandEventStreams);
|
||||
inbandEventStreams,
|
||||
representationInfo.essentialProperties,
|
||||
representationInfo.supplementalProperties,
|
||||
/* cacheKey= */ null);
|
||||
}
|
||||
|
||||
// SegmentBase, SegmentList and SegmentTemplate parsing.
|
||||
@ -1912,6 +1917,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
public final ArrayList<SchemeData> drmSchemeDatas;
|
||||
public final ArrayList<Descriptor> inbandEventStreams;
|
||||
public final long revisionId;
|
||||
public final List<Descriptor> essentialProperties;
|
||||
public final List<Descriptor> supplementalProperties;
|
||||
|
||||
public RepresentationInfo(
|
||||
Format format,
|
||||
@ -1920,6 +1927,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
@Nullable String drmSchemeType,
|
||||
ArrayList<SchemeData> drmSchemeDatas,
|
||||
ArrayList<Descriptor> inbandEventStreams,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties,
|
||||
long revisionId) {
|
||||
this.format = format;
|
||||
this.baseUrls = ImmutableList.copyOf(baseUrls);
|
||||
@ -1927,6 +1936,8 @@ public class DashManifestParser extends DefaultHandler
|
||||
this.drmSchemeType = drmSchemeType;
|
||||
this.drmSchemeDatas = drmSchemeDatas;
|
||||
this.inbandEventStreams = inbandEventStreams;
|
||||
this.essentialProperties = essentialProperties;
|
||||
this.supplementalProperties = supplementalProperties;
|
||||
this.revisionId = revisionId;
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,10 @@ public abstract class Representation {
|
||||
public final long presentationTimeOffsetUs;
|
||||
/** The in-band event streams in the representation. May be empty. */
|
||||
public final List<Descriptor> inbandEventStreams;
|
||||
/** Essential properties in the representation. May be empty. */
|
||||
public final List<Descriptor> essentialProperties;
|
||||
/** Supplemental properties in the adaptation set. May be empty. */
|
||||
public final List<Descriptor> supplementalProperties;
|
||||
|
||||
private final RangedUri initializationUri;
|
||||
|
||||
@ -66,27 +70,15 @@ public abstract class Representation {
|
||||
*/
|
||||
public static Representation newInstance(
|
||||
long revisionId, Format format, List<BaseUrl> baseUrls, SegmentBase segmentBase) {
|
||||
return newInstance(revisionId, format, baseUrls, segmentBase, /* inbandEventStreams= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*
|
||||
* @param revisionId Identifies the revision of the content.
|
||||
* @param format The format of the representation.
|
||||
* @param baseUrls The list of base URLs of the representation.
|
||||
* @param segmentBase A segment base element for the representation.
|
||||
* @param inbandEventStreams The in-band event streams in the representation. May be null.
|
||||
* @return The constructed instance.
|
||||
*/
|
||||
public static Representation newInstance(
|
||||
long revisionId,
|
||||
Format format,
|
||||
List<BaseUrl> baseUrls,
|
||||
SegmentBase segmentBase,
|
||||
@Nullable List<Descriptor> inbandEventStreams) {
|
||||
return newInstance(
|
||||
revisionId, format, baseUrls, segmentBase, inbandEventStreams, /* cacheKey= */ null);
|
||||
revisionId,
|
||||
format,
|
||||
baseUrls,
|
||||
segmentBase,
|
||||
/* inbandEventStreams= */ null,
|
||||
/* essentialProperties= */ ImmutableList.of(),
|
||||
/* supplementalProperties= */ ImmutableList.of(),
|
||||
/* cacheKey= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,6 +89,8 @@ public abstract class Representation {
|
||||
* @param baseUrls The list of base URLs of the representation.
|
||||
* @param segmentBase A segment base element for the representation.
|
||||
* @param inbandEventStreams The in-band event streams in the representation. May be null.
|
||||
* @param essentialProperties Essential properties in the representation. May be empty.
|
||||
* @param supplementalProperties Supplemental properties in the representation. May be empty.
|
||||
* @param cacheKey An optional key to be returned from {@link #getCacheKey()}, or null. This
|
||||
* parameter is ignored if {@code segmentBase} consists of multiple segments.
|
||||
* @return The constructed instance.
|
||||
@ -107,6 +101,8 @@ public abstract class Representation {
|
||||
List<BaseUrl> baseUrls,
|
||||
SegmentBase segmentBase,
|
||||
@Nullable List<Descriptor> inbandEventStreams,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties,
|
||||
@Nullable String cacheKey) {
|
||||
if (segmentBase instanceof SingleSegmentBase) {
|
||||
return new SingleSegmentRepresentation(
|
||||
@ -115,11 +111,19 @@ public abstract class Representation {
|
||||
baseUrls,
|
||||
(SingleSegmentBase) segmentBase,
|
||||
inbandEventStreams,
|
||||
essentialProperties,
|
||||
supplementalProperties,
|
||||
cacheKey,
|
||||
C.LENGTH_UNSET);
|
||||
/* contentLength= */ C.LENGTH_UNSET);
|
||||
} else if (segmentBase instanceof MultiSegmentBase) {
|
||||
return new MultiSegmentRepresentation(
|
||||
revisionId, format, baseUrls, (MultiSegmentBase) segmentBase, inbandEventStreams);
|
||||
revisionId,
|
||||
format,
|
||||
baseUrls,
|
||||
(MultiSegmentBase) segmentBase,
|
||||
inbandEventStreams,
|
||||
essentialProperties,
|
||||
supplementalProperties);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"segmentBase must be of type SingleSegmentBase or " + "MultiSegmentBase");
|
||||
@ -131,7 +135,9 @@ public abstract class Representation {
|
||||
Format format,
|
||||
List<BaseUrl> baseUrls,
|
||||
SegmentBase segmentBase,
|
||||
@Nullable List<Descriptor> inbandEventStreams) {
|
||||
@Nullable List<Descriptor> inbandEventStreams,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties) {
|
||||
checkArgument(!baseUrls.isEmpty());
|
||||
this.revisionId = revisionId;
|
||||
this.format = format;
|
||||
@ -140,6 +146,8 @@ public abstract class Representation {
|
||||
inbandEventStreams == null
|
||||
? Collections.emptyList()
|
||||
: Collections.unmodifiableList(inbandEventStreams);
|
||||
this.essentialProperties = essentialProperties;
|
||||
this.supplementalProperties = supplementalProperties;
|
||||
initializationUri = segmentBase.getInitialization(this);
|
||||
presentationTimeOffsetUs = segmentBase.getPresentationTimeOffsetUs();
|
||||
}
|
||||
@ -209,7 +217,15 @@ public abstract class Representation {
|
||||
new SingleSegmentBase(rangedUri, 1, 0, indexStart, indexEnd - indexStart + 1);
|
||||
List<BaseUrl> baseUrls = ImmutableList.of(new BaseUrl(uri));
|
||||
return new SingleSegmentRepresentation(
|
||||
revisionId, format, baseUrls, segmentBase, inbandEventStreams, cacheKey, contentLength);
|
||||
revisionId,
|
||||
format,
|
||||
baseUrls,
|
||||
segmentBase,
|
||||
inbandEventStreams,
|
||||
/* essentialProperties= */ ImmutableList.of(),
|
||||
/* supplementalProperties= */ ImmutableList.of(),
|
||||
cacheKey,
|
||||
contentLength);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -218,6 +234,8 @@ public abstract class Representation {
|
||||
* @param baseUrls The base urls of the representation.
|
||||
* @param segmentBase The segment base underlying the representation.
|
||||
* @param inbandEventStreams The in-band event streams in the representation. May be null.
|
||||
* @param essentialProperties Essential properties in the representation. May be empty.
|
||||
* @param supplementalProperties Supplemental properties in the representation. May be empty.
|
||||
* @param cacheKey An optional key to be returned from {@link #getCacheKey()}, or null.
|
||||
* @param contentLength The content length, or {@link C#LENGTH_UNSET} if unknown.
|
||||
*/
|
||||
@ -227,9 +245,18 @@ public abstract class Representation {
|
||||
List<BaseUrl> baseUrls,
|
||||
SingleSegmentBase segmentBase,
|
||||
@Nullable List<Descriptor> inbandEventStreams,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties,
|
||||
@Nullable String cacheKey,
|
||||
long contentLength) {
|
||||
super(revisionId, format, baseUrls, segmentBase, inbandEventStreams);
|
||||
super(
|
||||
revisionId,
|
||||
format,
|
||||
baseUrls,
|
||||
segmentBase,
|
||||
inbandEventStreams,
|
||||
essentialProperties,
|
||||
supplementalProperties);
|
||||
this.uri = Uri.parse(baseUrls.get(0).url);
|
||||
this.indexUri = segmentBase.getIndex();
|
||||
this.cacheKey = cacheKey;
|
||||
@ -273,14 +300,25 @@ public abstract class Representation {
|
||||
* @param baseUrls The base URLs of the representation.
|
||||
* @param segmentBase The segment base underlying the representation.
|
||||
* @param inbandEventStreams The in-band event streams in the representation. May be null.
|
||||
* @param essentialProperties Essential properties in the representation. May be empty.
|
||||
* @param supplementalProperties Supplemental properties in the representation. May be empty.
|
||||
*/
|
||||
public MultiSegmentRepresentation(
|
||||
long revisionId,
|
||||
Format format,
|
||||
List<BaseUrl> baseUrls,
|
||||
MultiSegmentBase segmentBase,
|
||||
@Nullable List<Descriptor> inbandEventStreams) {
|
||||
super(revisionId, format, baseUrls, segmentBase, inbandEventStreams);
|
||||
@Nullable List<Descriptor> inbandEventStreams,
|
||||
List<Descriptor> essentialProperties,
|
||||
List<Descriptor> supplementalProperties) {
|
||||
super(
|
||||
revisionId,
|
||||
format,
|
||||
baseUrls,
|
||||
segmentBase,
|
||||
inbandEventStreams,
|
||||
essentialProperties,
|
||||
supplementalProperties);
|
||||
this.segmentBase = segmentBase;
|
||||
}
|
||||
|
||||
|
@ -79,6 +79,8 @@ public final class DashUtilTest {
|
||||
baseUrls,
|
||||
new SingleSegmentBase(),
|
||||
/* inbandEventStreams= */ null,
|
||||
/* essentialProperties= */ ImmutableList.of(),
|
||||
/* supplementalProperties= */ ImmutableList.of(),
|
||||
/* cacheKey= */ null,
|
||||
/* contentLength= */ 1);
|
||||
RangedUri rangedUri = new RangedUri("path/to/resource", /* start= */ 0, /* length= */ 1);
|
||||
@ -99,6 +101,8 @@ public final class DashUtilTest {
|
||||
baseUrls,
|
||||
new SingleSegmentBase(),
|
||||
/* inbandEventStreams= */ null,
|
||||
/* essentialProperties= */ ImmutableList.of(),
|
||||
/* supplementalProperties= */ ImmutableList.of(),
|
||||
"cacheKey",
|
||||
/* contentLength= */ 1);
|
||||
RangedUri rangedUri = new RangedUri("path/to/resource", /* start= */ 0, /* length= */ 1);
|
||||
|
@ -23,6 +23,8 @@ import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.exoplayer.dash.manifest.Representation.MultiSegmentRepresentation;
|
||||
import androidx.media3.exoplayer.dash.manifest.Representation.SingleSegmentRepresentation;
|
||||
import androidx.media3.exoplayer.dash.manifest.SegmentBase.SegmentTimelineElement;
|
||||
import androidx.media3.extractor.metadata.emsg.EventMessage;
|
||||
import androidx.media3.test.utils.TestUtil;
|
||||
@ -53,6 +55,8 @@ public class DashManifestParserTest {
|
||||
private static final String SAMPLE_MPD_ASSET_IDENTIFIER = "media/mpd/sample_mpd_asset_identifier";
|
||||
private static final String SAMPLE_MPD_TEXT = "media/mpd/sample_mpd_text";
|
||||
private static final String SAMPLE_MPD_TRICK_PLAY = "media/mpd/sample_mpd_trick_play";
|
||||
private static final String SAMPLE_MPD_ESSENTIAL_SUPPLEMENTAL_PROPERTIES =
|
||||
"media/mpd/sample_mpd_essential_supplemental_properties";
|
||||
private static final String SAMPLE_MPD_AVAILABILITY_TIME_OFFSET_BASE_URL =
|
||||
"media/mpd/sample_mpd_availabilityTimeOffset_baseUrl";
|
||||
private static final String SAMPLE_MPD_MULTIPLE_BASE_URLS =
|
||||
@ -504,6 +508,74 @@ public class DashManifestParserTest {
|
||||
assertThat(assetIdentifier.id).isEqualTo("uniqueId");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseEssentialAndSupplementalProperties() throws IOException {
|
||||
DashManifestParser parser = new DashManifestParser();
|
||||
DashManifest manifest =
|
||||
parser.parse(
|
||||
Uri.parse("https://example.com/test.mpd"),
|
||||
TestUtil.getInputStream(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
SAMPLE_MPD_ESSENTIAL_SUPPLEMENTAL_PROPERTIES));
|
||||
|
||||
// Verify test setup.
|
||||
assertThat(manifest.getPeriodCount()).isEqualTo(1);
|
||||
assertThat(manifest.getPeriod(0).adaptationSets).hasSize(1);
|
||||
AdaptationSet adaptationSet = manifest.getPeriod(0).adaptationSets.get(0);
|
||||
assertThat(adaptationSet.representations).hasSize(2);
|
||||
Representation representation0 = adaptationSet.representations.get(0);
|
||||
Representation representation1 = adaptationSet.representations.get(1);
|
||||
assertThat(representation0).isInstanceOf(SingleSegmentRepresentation.class);
|
||||
assertThat(representation1).isInstanceOf(MultiSegmentRepresentation.class);
|
||||
|
||||
// Verify parsed properties.
|
||||
assertThat(adaptationSet.essentialProperties).hasSize(1);
|
||||
assertThat(adaptationSet.essentialProperties.get(0).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:essential-scheme:2050");
|
||||
assertThat(adaptationSet.essentialProperties.get(0).value).isEqualTo("adaptationEssential");
|
||||
assertThat(adaptationSet.supplementalProperties).hasSize(1);
|
||||
assertThat(adaptationSet.supplementalProperties.get(0).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:supplemental-scheme:2050");
|
||||
assertThat(adaptationSet.supplementalProperties.get(0).value)
|
||||
.isEqualTo("adaptationSupplemental");
|
||||
|
||||
assertThat(representation0.essentialProperties).hasSize(2);
|
||||
assertThat(representation0.essentialProperties.get(0).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:essential-scheme:2050");
|
||||
assertThat(representation0.essentialProperties.get(0).value).isEqualTo("adaptationEssential");
|
||||
assertThat(representation0.essentialProperties.get(1).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:essential-scheme:2050");
|
||||
assertThat(representation0.essentialProperties.get(1).value)
|
||||
.isEqualTo("representationEssential");
|
||||
assertThat(representation0.supplementalProperties).hasSize(2);
|
||||
assertThat(representation0.supplementalProperties.get(0).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:supplemental-scheme:2050");
|
||||
assertThat(representation0.supplementalProperties.get(0).value)
|
||||
.isEqualTo("adaptationSupplemental");
|
||||
assertThat(representation0.supplementalProperties.get(1).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:supplemental-scheme:2050");
|
||||
assertThat(representation0.supplementalProperties.get(1).value)
|
||||
.isEqualTo("representationSupplemental");
|
||||
|
||||
assertThat(representation1.essentialProperties).hasSize(2);
|
||||
assertThat(representation0.essentialProperties.get(0).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:essential-scheme:2050");
|
||||
assertThat(representation0.essentialProperties.get(0).value).isEqualTo("adaptationEssential");
|
||||
assertThat(representation1.essentialProperties.get(1).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:essential-scheme:2050");
|
||||
assertThat(representation1.essentialProperties.get(1).value)
|
||||
.isEqualTo("representationEssential");
|
||||
assertThat(representation1.supplementalProperties).hasSize(2);
|
||||
assertThat(representation0.supplementalProperties.get(0).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:supplemental-scheme:2050");
|
||||
assertThat(representation0.supplementalProperties.get(0).value)
|
||||
.isEqualTo("adaptationSupplemental");
|
||||
assertThat(representation1.supplementalProperties.get(1).schemeIdUri)
|
||||
.isEqualTo("urn:mpeg:dash:supplemental-scheme:2050");
|
||||
assertThat(representation1.supplementalProperties.get(1).value)
|
||||
.isEqualTo("representationSupplemental");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void availabilityTimeOffset_staticManifest_setToTimeUnset() throws IOException {
|
||||
DashManifestParser parser = new DashManifestParser();
|
||||
|
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD availabilityStartTime="2014-06-19T23:07:42" type="dynamic">
|
||||
<Period start="PT7462826.784S" id="0">
|
||||
<AdaptationSet id="0" mimeType="video/mp4">
|
||||
<SupplementalProperty
|
||||
schemeIdUri="urn:mpeg:dash:supplemental-scheme:2050"
|
||||
value="adaptationSupplemental"/>
|
||||
<EssentialProperty
|
||||
schemeIdUri="urn:mpeg:dash:essential-scheme:2050"
|
||||
value="adaptationEssential"/>
|
||||
<Representation id="singleSegment">
|
||||
<SegmentBase/>
|
||||
<SupplementalProperty
|
||||
schemeIdUri="urn:mpeg:dash:supplemental-scheme:2050"
|
||||
value="representationSupplemental"/>
|
||||
<EssentialProperty
|
||||
schemeIdUri="urn:mpeg:dash:essential-scheme:2050"
|
||||
value="representationEssential"/>
|
||||
</Representation>
|
||||
<Representation id="multiSegment">
|
||||
<SegmentList/>
|
||||
<SupplementalProperty
|
||||
schemeIdUri="urn:mpeg:dash:supplemental-scheme:2050"
|
||||
value="representationSupplemental"/>
|
||||
<EssentialProperty
|
||||
schemeIdUri="urn:mpeg:dash:essential-scheme:2050"
|
||||
value="representationEssential"/>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
Loading…
x
Reference in New Issue
Block a user