Add CMCD logging when requesting initialization chunk for DASH and HLS
Additionally, two existing methods to `buildDataSpec` in `DashUtil` have been deprecated, while a new method has been added that allows the inclusion of `httpRequestHeaders`. Issue: google/ExoPlayer#8699 #minor-release PiperOrigin-RevId: 540594444
This commit is contained in:
parent
8bf40e7355
commit
52878b2aca
@ -37,8 +37,10 @@ import androidx.media3.extractor.ChunkIndex;
|
||||
import androidx.media3.extractor.Extractor;
|
||||
import androidx.media3.extractor.mkv.MatroskaExtractor;
|
||||
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Utility methods for DASH streams. */
|
||||
@UnstableApi
|
||||
@ -52,33 +54,47 @@ public final class DashUtil {
|
||||
* @param requestUri The {@link RangedUri} of the data to request.
|
||||
* @param flags Flags to be set on the returned {@link DataSpec}. See {@link
|
||||
* DataSpec.Builder#setFlags(int)}.
|
||||
* @param httpRequestHeaders The {@link DataSpec#httpRequestHeaders}.
|
||||
* @return The {@link DataSpec}.
|
||||
*/
|
||||
public static DataSpec buildDataSpec(
|
||||
Representation representation, String baseUrl, RangedUri requestUri, int flags) {
|
||||
Representation representation,
|
||||
String baseUrl,
|
||||
RangedUri requestUri,
|
||||
int flags,
|
||||
Map<String, String> httpRequestHeaders) {
|
||||
return new DataSpec.Builder()
|
||||
.setUri(requestUri.resolveUri(baseUrl))
|
||||
.setPosition(requestUri.start)
|
||||
.setLength(requestUri.length)
|
||||
.setKey(resolveCacheKey(representation, requestUri))
|
||||
.setFlags(flags)
|
||||
.setHttpRequestHeaders(httpRequestHeaders)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link DataSpec} for a given {@link RangedUri} belonging to {@link Representation}.
|
||||
*
|
||||
* <p>Uses the first base URL of the representation to build the data spec.
|
||||
*
|
||||
* @param representation The {@link Representation} to which the request belongs.
|
||||
* @param requestUri The {@link RangedUri} of the data to request.
|
||||
* @param flags Flags to be set on the returned {@link DataSpec}. See {@link
|
||||
* DataSpec.Builder#setFlags(int)}.
|
||||
* @return The {@link DataSpec}.
|
||||
* @deprecated Use {@link #buildDataSpec(Representation, String, RangedUri, int, Map)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static DataSpec buildDataSpec(
|
||||
Representation representation, String baseUrl, RangedUri requestUri, int flags) {
|
||||
return buildDataSpec(
|
||||
representation, baseUrl, requestUri, flags, /* httpRequestHeaders= */ ImmutableMap.of());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #buildDataSpec(Representation, String, RangedUri, int, Map)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static DataSpec buildDataSpec(
|
||||
Representation representation, RangedUri requestUri, int flags) {
|
||||
return buildDataSpec(representation, representation.baseUrls.get(0).url, requestUri, flags);
|
||||
return buildDataSpec(
|
||||
representation,
|
||||
representation.baseUrls.get(0).url,
|
||||
requestUri,
|
||||
flags,
|
||||
/* httpRequestHeaders= */ ImmutableMap.of());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -292,7 +308,8 @@ public final class DashUtil {
|
||||
representation,
|
||||
representation.baseUrls.get(baseUrlIndex).url,
|
||||
requestUri,
|
||||
/* flags= */ 0);
|
||||
/* flags= */ 0,
|
||||
/* httpRequestHeaders= */ ImmutableMap.of());
|
||||
InitializationChunk initializationChunk =
|
||||
new InitializationChunk(
|
||||
dataSource,
|
||||
|
@ -370,6 +370,13 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
trackSelection.updateSelectedTrack(
|
||||
playbackPositionUs, bufferedDurationUs, availableLiveDurationUs, queue, chunkIterators);
|
||||
|
||||
@Nullable
|
||||
CmcdLog cmcdLog =
|
||||
cmcdConfiguration == null
|
||||
? null
|
||||
: CmcdLog.createInstance(
|
||||
cmcdConfiguration, trackSelection, playbackPositionUs, loadPositionUs);
|
||||
|
||||
RepresentationHolder representationHolder =
|
||||
updateSelectedBaseUrl(trackSelection.getSelectedIndex());
|
||||
if (representationHolder.chunkExtractor != null) {
|
||||
@ -392,7 +399,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
trackSelection.getSelectionReason(),
|
||||
trackSelection.getSelectionData(),
|
||||
pendingInitializationUri,
|
||||
pendingIndexUri);
|
||||
pendingIndexUri,
|
||||
cmcdLog);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -445,13 +453,6 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
CmcdLog cmcdLog =
|
||||
cmcdConfiguration == null
|
||||
? null
|
||||
: CmcdLog.createInstance(
|
||||
cmcdConfiguration, trackSelection, playbackPositionUs, loadPositionUs);
|
||||
|
||||
long seekTimeUs = queue.isEmpty() ? loadPositionUs : C.TIME_UNSET;
|
||||
out.chunk =
|
||||
newMediaChunk(
|
||||
@ -639,7 +640,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
@C.SelectionReason int trackSelectionReason,
|
||||
@Nullable Object trackSelectionData,
|
||||
@Nullable RangedUri initializationUri,
|
||||
@Nullable RangedUri indexUri) {
|
||||
@Nullable RangedUri indexUri,
|
||||
@Nullable CmcdLog cmcdLog) {
|
||||
Representation representation = representationHolder.representation;
|
||||
@Nullable RangedUri requestUri;
|
||||
if (initializationUri != null) {
|
||||
@ -653,9 +655,15 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
} else {
|
||||
requestUri = indexUri;
|
||||
}
|
||||
ImmutableMap<@CmcdConfiguration.HeaderKey String, String> httpRequestHeaders =
|
||||
cmcdLog == null ? ImmutableMap.of() : cmcdLog.getHttpRequestHeaders();
|
||||
DataSpec dataSpec =
|
||||
DashUtil.buildDataSpec(
|
||||
representation, representationHolder.selectedBaseUrl.url, requestUri, /* flags= */ 0);
|
||||
representation,
|
||||
representationHolder.selectedBaseUrl.url,
|
||||
requestUri,
|
||||
/* flags= */ 0,
|
||||
httpRequestHeaders);
|
||||
return new InitializationChunk(
|
||||
dataSource,
|
||||
dataSpec,
|
||||
@ -691,8 +699,11 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
: DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED;
|
||||
DataSpec dataSpec =
|
||||
DashUtil.buildDataSpec(
|
||||
representation, representationHolder.selectedBaseUrl.url, segmentUri, flags);
|
||||
dataSpec = dataSpec.buildUpon().setHttpRequestHeaders(httpRequestHeaders).build();
|
||||
representation,
|
||||
representationHolder.selectedBaseUrl.url,
|
||||
segmentUri,
|
||||
flags,
|
||||
httpRequestHeaders);
|
||||
return new SingleSampleMediaChunk(
|
||||
dataSource,
|
||||
dataSpec,
|
||||
@ -731,8 +742,11 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
: DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED;
|
||||
DataSpec dataSpec =
|
||||
DashUtil.buildDataSpec(
|
||||
representation, representationHolder.selectedBaseUrl.url, segmentUri, flags);
|
||||
dataSpec = dataSpec.buildUpon().setHttpRequestHeaders(httpRequestHeaders).build();
|
||||
representation,
|
||||
representationHolder.selectedBaseUrl.url,
|
||||
segmentUri,
|
||||
flags,
|
||||
httpRequestHeaders);
|
||||
long sampleOffsetUs = -representation.presentationTimeOffsetUs;
|
||||
return new ContainerMediaChunk(
|
||||
dataSource,
|
||||
@ -803,7 +817,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
representationHolder.representation,
|
||||
representationHolder.selectedBaseUrl.url,
|
||||
segmentUri,
|
||||
flags);
|
||||
flags,
|
||||
/* httpRequestHeaders= */ ImmutableMap.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,6 +40,7 @@ import androidx.media3.exoplayer.offline.DownloadException;
|
||||
import androidx.media3.exoplayer.offline.SegmentDownloader;
|
||||
import androidx.media3.exoplayer.upstream.ParsingLoadable.Parser;
|
||||
import androidx.media3.extractor.ChunkIndex;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -227,7 +228,13 @@ public final class DashDownloader extends SegmentDownloader<DashManifest> {
|
||||
|
||||
private Segment createSegment(
|
||||
Representation representation, String baseUrl, long startTimeUs, RangedUri rangedUri) {
|
||||
DataSpec dataSpec = DashUtil.buildDataSpec(representation, baseUrl, rangedUri, /* flags= */ 0);
|
||||
DataSpec dataSpec =
|
||||
DashUtil.buildDataSpec(
|
||||
representation,
|
||||
baseUrl,
|
||||
rangedUri,
|
||||
/* flags= */ 0,
|
||||
/* httpRequestHeaders= */ ImmutableMap.of());
|
||||
return new Segment(startTimeUs, dataSpec);
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@ import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
|
||||
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
||||
import androidx.media3.exoplayer.upstream.CmcdLog;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.primitives.Ints;
|
||||
import java.io.IOException;
|
||||
@ -478,17 +479,24 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
seenExpectedPlaylistError = false;
|
||||
expectedPlaylistUrl = null;
|
||||
|
||||
@Nullable
|
||||
CmcdLog cmcdLog =
|
||||
cmcdConfiguration == null
|
||||
? null
|
||||
: CmcdLog.createInstance(
|
||||
cmcdConfiguration, trackSelection, playbackPositionUs, loadPositionUs);
|
||||
|
||||
// Check if the media segment or its initialization segment are fully encrypted.
|
||||
@Nullable
|
||||
Uri initSegmentKeyUri =
|
||||
getFullEncryptionKeyUri(playlist, segmentBaseHolder.segmentBase.initializationSegment);
|
||||
out.chunk = maybeCreateEncryptionChunkFor(initSegmentKeyUri, selectedTrackIndex);
|
||||
out.chunk = maybeCreateEncryptionChunkFor(initSegmentKeyUri, selectedTrackIndex, cmcdLog);
|
||||
if (out.chunk != null) {
|
||||
return;
|
||||
}
|
||||
@Nullable
|
||||
Uri mediaSegmentKeyUri = getFullEncryptionKeyUri(playlist, segmentBaseHolder.segmentBase);
|
||||
out.chunk = maybeCreateEncryptionChunkFor(mediaSegmentKeyUri, selectedTrackIndex);
|
||||
out.chunk = maybeCreateEncryptionChunkFor(mediaSegmentKeyUri, selectedTrackIndex, cmcdLog);
|
||||
if (out.chunk != null) {
|
||||
return;
|
||||
}
|
||||
@ -504,13 +512,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
return;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
CmcdLog cmcdLog =
|
||||
cmcdConfiguration == null
|
||||
? null
|
||||
: CmcdLog.createInstance(
|
||||
cmcdConfiguration, trackSelection, playbackPositionUs, loadPositionUs);
|
||||
|
||||
out.chunk =
|
||||
HlsMediaChunk.createInstance(
|
||||
extractorFactory,
|
||||
@ -838,7 +839,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Chunk maybeCreateEncryptionChunkFor(@Nullable Uri keyUri, int selectedTrackIndex) {
|
||||
private Chunk maybeCreateEncryptionChunkFor(
|
||||
@Nullable Uri keyUri, int selectedTrackIndex, @Nullable CmcdLog cmcdLog) {
|
||||
if (keyUri == null) {
|
||||
return null;
|
||||
}
|
||||
@ -851,8 +853,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
keyCache.put(keyUri, encryptionKey);
|
||||
return null;
|
||||
}
|
||||
ImmutableMap<@CmcdConfiguration.HeaderKey String, String> httpRequestHeaders =
|
||||
cmcdLog == null ? ImmutableMap.of() : cmcdLog.getHttpRequestHeaders();
|
||||
DataSpec dataSpec =
|
||||
new DataSpec.Builder().setUri(keyUri).setFlags(DataSpec.FLAG_ALLOW_GZIP).build();
|
||||
new DataSpec.Builder()
|
||||
.setUri(keyUri)
|
||||
.setFlags(DataSpec.FLAG_ALLOW_GZIP)
|
||||
.setHttpRequestHeaders(httpRequestHeaders)
|
||||
.build();
|
||||
return new EncryptionKeyChunk(
|
||||
encryptionDataSource,
|
||||
dataSpec,
|
||||
|
Loading…
x
Reference in New Issue
Block a user