Skip to content

Commit

Permalink
Impr/doris 1281 support cmcd (#62)
Browse files Browse the repository at this point in the history
* Impr/doris 1281 cmcd base (#56)

* cmcd: base architecture and basic functionality.

* cmcd: have CMCD be default off, be able to activate it easily through single API call.

* cmcd: implement manifest cmcd payload collector of HLS/DASH/SS. (#57)

* cmcd: Implement cmcd payload collector of HLS chunk request. (#58)

* cmcd: Implement cmcd payload collector of DASH chunk request. (#59)

* cmcd: Implement cmcd payload collector of SS chunk request. (#60)

* cmcd: Implement cmcd payload collector of progressive and side-loaded subtitle request. (#61)
  • Loading branch information
guoen21 authored Sep 1, 2022
1 parent e7f6e44 commit e726068
Show file tree
Hide file tree
Showing 32 changed files with 1,626 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.google.android.exoplayer2.MediaItem.ClippingConfiguration;
import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.endeavor.CMCDManager;
import com.google.android.exoplayer2.offline.DownloadService;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSourceInputStream;
Expand Down Expand Up @@ -90,7 +91,10 @@ public void onCreate(Bundle savedInstanceState) {

sampleListView.setAdapter(sampleAdapter);
sampleListView.setOnChildClickListener(this);

// Global Setting.
Log.setLogLevel(Log.LOG_LEVEL_ALL);
CMCDManager.getInstance().setAllActivations(true);

Intent intent = getIntent();
String dataUri = intent.getDataString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,10 @@ protected UrlRequest.Builder buildRequestBuilder(DataSpec dataSpec) throws IOExc
}
requestHeaders.putAll(requestProperties.getSnapshot());
requestHeaders.putAll(dataSpec.httpRequestHeaders);
Map<String, String> cmcdHeaders = dataSpec.buildCMCDHeaders();
if (cmcdHeaders != null) {
requestHeaders.putAll(cmcdHeaders);
}

for (Entry<String, String> headerEntry : requestHeaders.entrySet()) {
String key = headerEntry.getKey();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@ private Request makeRequest(DataSpec dataSpec) throws HttpDataSourceException {

headers.putAll(requestProperties.getSnapshot());
headers.putAll(dataSpec.httpRequestHeaders);
Map<String, String> cmcdHeaders = dataSpec.buildCMCDHeaders();
if (cmcdHeaders != null) {
headers.putAll(cmcdHeaders);
}

for (Map.Entry<String, String> header : headers.entrySet()) {
builder.header(header.getKey(), header.getValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class DebugBase {
public static boolean debug_track = false;
public static boolean debug_media = false;
public static boolean debug_manifest = true;
public static boolean debug_cmcd = true;
public static boolean debug_lowlatency = false;

public static boolean use_info = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package com.google.android.exoplayer2.endeavor.cmcd;

import android.net.Uri;
import com.google.android.exoplayer2.endeavor.DebugBase;
import com.google.android.exoplayer2.endeavor.WebUtil;
import com.google.android.exoplayer2.endeavor.cmcd.CMCDType.CMCDKey;
import com.google.android.exoplayer2.endeavor.cmcd.CMCDType.CMCDObjectType;
import com.google.android.exoplayer2.util.Log;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

public class CMCDCollector {

private final CMCDContext context;
private final EnumMap<CMCDKey, Object> dataMap;

public CMCDCollector(CMCDContext context) {
this.context = context;
this.dataMap = new EnumMap<>(CMCDKey.class);
}

// Public method.

public void updateEncodedBitrate(int encodedBitrate) {
if (encodedBitrate > 0) {
setPayload(CMCDKey.ENCODED_BITRATE, encodedBitrate);
}
}

public void updateObjectDuration(int objectDuration) {
setPayload(CMCDKey.OBJECT_DURATION, objectDuration);
}

public void updateNextObjectRequest(String nextObjectRequest) {
setPayload(CMCDKey.NEXT_OBJECT_REQUEST, nextObjectRequest);
}

public void updateNextRangeRequest(String nextRangeRequest) {
setPayload(CMCDKey.NEXT_RANGE_REQUEST, nextRangeRequest);
}

public void updateObjectType(CMCDObjectType objectType) {
setPayload(CMCDKey.OBJECT_TYPE, objectType == null ? null : objectType.getToken());
}

public void updateRequestedThroughput(int requestedThroughput) {
setPayload(CMCDKey.REQUESTED_MAXIMUM_THROUGHPUT, requestedThroughput);
}

public void updateStartup(boolean startup) {
setPayload(CMCDKey.STARTUP, startup ? "" : null);
}

public void updateTopBitrate(int topBitrate) {
context.updateTopBitrate(topBitrate);
}

public Map<String, String> buildHeaders(Uri dataSpecUri) {
boolean isAudioVideoType = CMCDObjectType.isAudioVideo(getPayload(CMCDKey.OBJECT_TYPE));
Map<String, String> headers = new HashMap<>();
for (CMCDKey key : CMCDKey.values()) {
buildPayload(isAudioVideoType, key, headers);
}

if (DebugBase.debug_cmcd) {
StringBuilder message = new StringBuilder("CMCDHeader");
for (Map.Entry<String, String> entry : headers.entrySet()) {
message.append("; ").append(entry);
}
message.append("; dataSpecUrl ").append(dataSpecUri);
Log.d(WebUtil.DEBUG, message.toString());
}

return headers;
}

// Internal method.

private void buildPayload(boolean isAudioVideoType, CMCDKey key, Map<String, String> headers) {
// Find payload from collector and context.
Object payload = getAdjustedPayload(isAudioVideoType, key);
if (payload == null) {
return;
}

// Convert payload value.
String strValue = null;
switch (key) {
case ENCODED_BITRATE:
case OBJECT_DURATION:
case TOP_BITRATE:
strValue = CMCDType.intToString((int) payload);
break;
case BUFFER_LENGTH:
case DEADLINE:
case MEASURED_THROUGHPUT:
case REQUESTED_MAXIMUM_THROUGHPUT:
strValue = CMCDType.intRoundToString((int) payload);
break;
case BUFFER_STARVATION:
strValue = (String) payload;
context.finishBufferStarvation();
break;
case CONTENT_ID:
case NEXT_RANGE_REQUEST:
case SESSION_ID:
strValue = CMCDType.toQuoteString((String) payload);
break;
case NEXT_OBJECT_REQUEST:
strValue = CMCDType.toEncodeString((String) payload);
break;
case OBJECT_TYPE:
case STREAM_FORMAT:
case STREAM_TYPE:
case STARTUP:
strValue = (String) payload;
break;
case PLAYBACK_RATE:
strValue = CMCDType.speedToString((double) payload);
break;
case VERSION:
strValue = CMCDType.versionToString((int) payload);
break;
}
if (strValue == null) {
return;
}

// Put the payload pair to header map.
String payloadName = key.getKey();
String headerName = key.getHeader().getKey();
String headerValue = headers.containsKey(headerName) ? headers.get(headerName) + "," + payloadName : payloadName;
if (strValue.length() > 0) {
headerValue += "=" + strValue;
}
headers.put(headerName, headerValue);
}

private Object getAdjustedPayload(boolean isAudioVideoType, CMCDKey key) {
if (!isAudioVideoType) {
switch (key) {
case BUFFER_LENGTH:
case BUFFER_STARVATION:
case DEADLINE:
return null;
}
}
boolean isDeadLine = (key == CMCDKey.DEADLINE);
Object payload = getPayload(isDeadLine ? CMCDKey.BUFFER_LENGTH : key);
if (payload == null) {
return null;
}
if (isDeadLine) {
Object obj = getPayload(CMCDKey.PLAYBACK_RATE);
double speed = (obj == null ? 0 : (double) obj);
if (speed == 0) {
return null;
}
payload = (int) Math.round(((int) payload) / speed);
}
return payload;
}

protected synchronized Object getPayload(CMCDKey key) {
Object payload = dataMap.get(key);
if (payload == null) {
payload = context.getPayload(key);
}
return payload;
}

private synchronized void setPayload(CMCDKey key, Object value) {
if (context.config.isActive(key)) {
dataMap.put(key, value);
}
}

public boolean isActiveNextPayload() {
return context.config.isActive(CMCDKey.NEXT_OBJECT_REQUEST) || context.config.isActive(CMCDKey.NEXT_RANGE_REQUEST);
}

public synchronized void release() {
dataMap.clear();
}

public static CMCDCollector createCollector(CMCDCollector cmcdCollector) {
return (cmcdCollector == null ? null : CMCDContext.createCollector(cmcdCollector.context));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.google.android.exoplayer2.endeavor.cmcd;

import com.google.android.exoplayer2.endeavor.cmcd.CMCDType.CMCDKey;
import java.util.EnumMap;

public class CMCDConfig {

private final EnumMap<CMCDKey, Boolean> activationMap;

public CMCDConfig() {
this.activationMap = new EnumMap<>(CMCDKey.class);
}

public void setActivation(CMCDKey key, boolean activation) {
activationMap.put(key, activation);
}

public boolean isActive(CMCDKey key) {
Boolean activation = activationMap.get(key);
return activation != null && activation;
}
}
Loading

0 comments on commit e726068

Please sign in to comment.