Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
ChunkSampleStream.ReleaseCallback<DashChunkSource> {

private static final Pattern CEA608_SERVICE_DESCRIPTOR_REGEX = Pattern.compile("CC([1-4])=(.+)");
private static final Pattern CEA708_SERVICE_DESCRIPTOR_REGEX = Pattern.compile("([1-4])=lang:(\\w+)(,.+)?");

/* package */ final int id;
private final DashChunkSource.Factory chunkSourceFactory;
Expand Down Expand Up @@ -488,14 +489,14 @@ private static Pair<TrackGroupArray, TrackGroupInfo[]> buildTrackGroups(

int primaryGroupCount = groupedAdaptationSetIndices.length;
boolean[] primaryGroupHasEventMessageTrackFlags = new boolean[primaryGroupCount];
Format[][] primaryGroupCea608TrackFormats = new Format[primaryGroupCount][];
Format[][] primaryGroupClosedCaptionsTrackFormats = new Format[primaryGroupCount][];
int totalEmbeddedTrackGroupCount =
identifyEmbeddedTracks(
primaryGroupCount,
adaptationSets,
groupedAdaptationSetIndices,
primaryGroupHasEventMessageTrackFlags,
primaryGroupCea608TrackFormats);
primaryGroupClosedCaptionsTrackFormats);

int totalGroupCount = primaryGroupCount + totalEmbeddedTrackGroupCount + eventStreams.size();
TrackGroup[] trackGroups = new TrackGroup[totalGroupCount];
Expand All @@ -508,7 +509,7 @@ private static Pair<TrackGroupArray, TrackGroupInfo[]> buildTrackGroups(
groupedAdaptationSetIndices,
primaryGroupCount,
primaryGroupHasEventMessageTrackFlags,
primaryGroupCea608TrackFormats,
primaryGroupClosedCaptionsTrackFormats,
trackGroups,
trackGroupInfos);

Expand Down Expand Up @@ -616,25 +617,25 @@ private static int[][] getGroupedAdaptationSetIndices(List<AdaptationSet> adapta
* same primary group, grouped in primary track groups order.
* @param primaryGroupHasEventMessageTrackFlags An output array to be filled with flags indicating
* whether each of the primary track groups contains an embedded event message track.
* @param primaryGroupCea608TrackFormats An output array to be filled with track formats for
* CEA-608 tracks embedded in each of the primary track groups.
* @param primaryGroupClosedCaptionsTrackFormats An output array to be filled with track formats for
* closed captions tracks embedded in each of the primary track groups.
* @return Total number of embedded track groups.
*/
private static int identifyEmbeddedTracks(
int primaryGroupCount,
List<AdaptationSet> adaptationSets,
int[][] groupedAdaptationSetIndices,
boolean[] primaryGroupHasEventMessageTrackFlags,
Format[][] primaryGroupCea608TrackFormats) {
Format[][] primaryGroupClosedCaptionsTrackFormats) {
int numEmbeddedTrackGroups = 0;
for (int i = 0; i < primaryGroupCount; i++) {
if (hasEventMessageTrack(adaptationSets, groupedAdaptationSetIndices[i])) {
primaryGroupHasEventMessageTrackFlags[i] = true;
numEmbeddedTrackGroups++;
}
primaryGroupCea608TrackFormats[i] =
getCea608TrackFormats(adaptationSets, groupedAdaptationSetIndices[i]);
if (primaryGroupCea608TrackFormats[i].length != 0) {
primaryGroupClosedCaptionsTrackFormats[i] =
getClosedCaptionsTrackFormats(adaptationSets, groupedAdaptationSetIndices[i]);
if (primaryGroupClosedCaptionsTrackFormats[i].length != 0) {
numEmbeddedTrackGroups++;
}
}
Expand All @@ -647,7 +648,7 @@ private static int buildPrimaryAndEmbeddedTrackGroupInfos(
int[][] groupedAdaptationSetIndices,
int primaryGroupCount,
boolean[] primaryGroupHasEventMessageTrackFlags,
Format[][] primaryGroupCea608TrackFormats,
Format[][] primaryGroupClosedCaptionsTrackFormats,
TrackGroup[] trackGroups,
TrackGroupInfo[] trackGroupInfos) {
int trackGroupCount = 0;
Expand All @@ -673,8 +674,8 @@ private static int buildPrimaryAndEmbeddedTrackGroupInfos(
int primaryTrackGroupIndex = trackGroupCount++;
int eventMessageTrackGroupIndex =
primaryGroupHasEventMessageTrackFlags[i] ? trackGroupCount++ : C.INDEX_UNSET;
int cea608TrackGroupIndex =
primaryGroupCea608TrackFormats[i].length != 0 ? trackGroupCount++ : C.INDEX_UNSET;
int closedCaptionsTrackGroupIndex =
primaryGroupClosedCaptionsTrackFormats[i].length != 0 ? trackGroupCount++ : C.INDEX_UNSET;

trackGroups[primaryTrackGroupIndex] = new TrackGroup(formats);
trackGroupInfos[primaryTrackGroupIndex] =
Expand All @@ -683,7 +684,7 @@ private static int buildPrimaryAndEmbeddedTrackGroupInfos(
adaptationSetIndices,
primaryTrackGroupIndex,
eventMessageTrackGroupIndex,
cea608TrackGroupIndex);
closedCaptionsTrackGroupIndex);
if (eventMessageTrackGroupIndex != C.INDEX_UNSET) {
Format format =
new Format.Builder()
Expand All @@ -694,10 +695,11 @@ private static int buildPrimaryAndEmbeddedTrackGroupInfos(
trackGroupInfos[eventMessageTrackGroupIndex] =
TrackGroupInfo.embeddedEmsgTrack(adaptationSetIndices, primaryTrackGroupIndex);
}
if (cea608TrackGroupIndex != C.INDEX_UNSET) {
trackGroups[cea608TrackGroupIndex] = new TrackGroup(primaryGroupCea608TrackFormats[i]);
trackGroupInfos[cea608TrackGroupIndex] =
TrackGroupInfo.embeddedCea608Track(adaptationSetIndices, primaryTrackGroupIndex);
if (closedCaptionsTrackGroupIndex != C.INDEX_UNSET) {
trackGroups[closedCaptionsTrackGroupIndex] =
new TrackGroup(primaryGroupClosedCaptionsTrackFormats[i]);
trackGroupInfos[closedCaptionsTrackGroupIndex] =
TrackGroupInfo.embeddedClosedCaptionsTrack(adaptationSetIndices, primaryTrackGroupIndex);
}
}
return trackGroupCount;
Expand Down Expand Up @@ -728,11 +730,13 @@ private ChunkSampleStream<DashChunkSource> buildSampleStream(TrackGroupInfo trac
trackGroups.get(trackGroupInfo.embeddedEventMessageTrackGroupIndex);
embeddedTrackCount++;
}
boolean enableCea608Tracks = trackGroupInfo.embeddedCea608TrackGroupIndex != C.INDEX_UNSET;
TrackGroup embeddedCea608TrackGroup = null;
if (enableCea608Tracks) {
embeddedCea608TrackGroup = trackGroups.get(trackGroupInfo.embeddedCea608TrackGroupIndex);
embeddedTrackCount += embeddedCea608TrackGroup.length;
boolean enableClosedCaptionsTracks =
trackGroupInfo.embeddedClosedCaptionsTrackGroupIndex != C.INDEX_UNSET;
TrackGroup embeddedClosedCaptionsTrackGroup = null;
if (enableClosedCaptionsTracks) {
embeddedClosedCaptionsTrackGroup =
trackGroups.get(trackGroupInfo.embeddedClosedCaptionsTrackGroupIndex);
embeddedTrackCount += embeddedClosedCaptionsTrackGroup.length;
}

Format[] embeddedTrackFormats = new Format[embeddedTrackCount];
Expand All @@ -743,12 +747,12 @@ private ChunkSampleStream<DashChunkSource> buildSampleStream(TrackGroupInfo trac
embeddedTrackTypes[embeddedTrackCount] = C.TRACK_TYPE_METADATA;
embeddedTrackCount++;
}
List<Format> embeddedCea608TrackFormats = new ArrayList<>();
if (enableCea608Tracks) {
for (int i = 0; i < embeddedCea608TrackGroup.length; i++) {
embeddedTrackFormats[embeddedTrackCount] = embeddedCea608TrackGroup.getFormat(i);
List<Format> embeddedClosedCaptionsTrackFormats = new ArrayList<>();
if (enableClosedCaptionsTracks) {
for (int i = 0; i < embeddedClosedCaptionsTrackGroup.length; i++) {
embeddedTrackFormats[embeddedTrackCount] = embeddedClosedCaptionsTrackGroup.getFormat(i);
embeddedTrackTypes[embeddedTrackCount] = C.TRACK_TYPE_TEXT;
embeddedCea608TrackFormats.add(embeddedTrackFormats[embeddedTrackCount]);
embeddedClosedCaptionsTrackFormats.add(embeddedTrackFormats[embeddedTrackCount]);
embeddedTrackCount++;
}
}
Expand All @@ -767,7 +771,7 @@ private ChunkSampleStream<DashChunkSource> buildSampleStream(TrackGroupInfo trac
trackGroupInfo.trackType,
elapsedRealtimeOffsetMs,
enableEventMessageTrack,
embeddedCea608TrackFormats,
embeddedClosedCaptionsTrackFormats,
trackPlayerEmsgHandler,
transferListener);
ChunkSampleStream<DashChunkSource> stream =
Expand Down Expand Up @@ -824,57 +828,61 @@ private static boolean hasEventMessageTrack(List<AdaptationSet> adaptationSets,
return false;
}

private static Format[] getCea608TrackFormats(
private static Format[] getClosedCaptionsTrackFormats(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of the enum through this code is IMO making it quite a bit harder to read than it needs to be. Can't you just do something like (warning, untested):


  private static Format[] getClosedCaptionTrackFormats(
      List<AdaptationSet> adaptationSets, int[] adaptationSetIndices) {
    for (int i : adaptationSetIndices) {
      AdaptationSet adaptationSet = adaptationSets.get(i);
      List<Descriptor> descriptors = adaptationSets.get(i).accessibilityDescriptors;
      for (int j = 0; j < descriptors.size(); j++) {
        Descriptor descriptor = descriptors.get(j);
        if ("urn:scte:dash:cc:cea-608:2015".equals(descriptor.schemeIdUri)) {
          Format cea608Format =
              new Format.Builder()
                  .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
                  .setId(adaptationSet.id + ":cea608")
                  .build();
          return parseClosedCaptionDescriptor(
              descriptor, CEA608_SERVICE_DESCRIPTOR_REGEX, cea608Format);
        } else if ("urn:scte:dash:cc:cea-708:2015".equals(descriptor.schemeIdUri)) {
          Format cea708Format =
              new Format.Builder()
                  .setSampleMimeType(MimeTypes.APPLICATION_CEA708)
                  .setId(adaptationSet.id + ":cea708")
                  .build();
          return parseClosedCaptionDescriptor(
              descriptor, CEA708_SERVICE_DESCRIPTOR_REGEX, cea708Format);
        }
      }
    }
    return new Format[0];
  }

  private static Format[] parseClosedCaptionDescriptor(
      Descriptor descriptor, Pattern serviceDescriptorRegex, Format baseFormat) {
    @Nullable String value = descriptor.value;
    if (value == null) {
      // There are embedded closed caption tracks, but service information is not declared.
      return new Format[] {baseFormat};
    }
    String[] services = Util.split(value, ";");
    Format[] formats = new Format[services.length];
    for (int i = 0; i < services.length; i++) {
      Matcher matcher = serviceDescriptorRegex.matcher(services[i]);
      if (!matcher.matches()) {
        // If we can't parse service information for all services, assume a single track.
        return new Format[] {baseFormat};
      }
      int accessibilityChannel = Integer.parseInt(matcher.group(1));
      formats[i] =
          baseFormat
              .buildUpon()
              .setId(baseFormat.id + ":" + accessibilityChannel)
              .setAccessibilityChannel(accessibilityChannel)
              .setLanguage(matcher.group(2))
              .build();
    }
    return formats;
  }

and get rid of the enum and all the little helper methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

List<AdaptationSet> adaptationSets, int[] adaptationSetIndices) {
for (int i : adaptationSetIndices) {
AdaptationSet adaptationSet = adaptationSets.get(i);
List<Descriptor> descriptors = adaptationSets.get(i).accessibilityDescriptors;
for (int j = 0; j < descriptors.size(); j++) {
Descriptor descriptor = descriptors.get(j);
if ("urn:scte:dash:cc:cea-608:2015".equals(descriptor.schemeIdUri)) {
@Nullable String value = descriptor.value;
if (value == null) {
// There are embedded CEA-608 tracks, but service information is not declared.
return new Format[] {buildCea608TrackFormat(adaptationSet.id)};
}
String[] services = Util.split(value, ";");
Format[] formats = new Format[services.length];
for (int k = 0; k < services.length; k++) {
Matcher matcher = CEA608_SERVICE_DESCRIPTOR_REGEX.matcher(services[k]);
if (!matcher.matches()) {
// If we can't parse service information for all services, assume a single track.
return new Format[] {buildCea608TrackFormat(adaptationSet.id)};
}
formats[k] =
buildCea608TrackFormat(
adaptationSet.id,
/* language= */ matcher.group(2),
/* accessibilityChannel= */ Integer.parseInt(matcher.group(1)));
}
return formats;
Format cea608Format =
new Format.Builder()
.setSampleMimeType(MimeTypes.APPLICATION_CEA608)
.setId(adaptationSet.id + ":cea608")
.build();
return parseClosedCaptionsDescriptor(
descriptor, CEA608_SERVICE_DESCRIPTOR_REGEX, cea608Format);
} else if ("urn:scte:dash:cc:cea-708:2015".equals(descriptor.schemeIdUri)) {
Format cea708Format =
new Format.Builder()
.setSampleMimeType(MimeTypes.APPLICATION_CEA708)
.setId(adaptationSet.id + ":cea708")
.build();
return parseClosedCaptionsDescriptor(
descriptor, CEA708_SERVICE_DESCRIPTOR_REGEX, cea708Format);
}
}
}
return new Format[0];
}

private static Format buildCea608TrackFormat(int adaptationSetId) {
return buildCea608TrackFormat(
adaptationSetId, /* language= */ null, /* accessibilityChannel= */ Format.NO_VALUE);
}

private static Format buildCea608TrackFormat(
int adaptationSetId, @Nullable String language, int accessibilityChannel) {
String id =
adaptationSetId
+ ":cea608"
+ (accessibilityChannel != Format.NO_VALUE ? ":" + accessibilityChannel : "");
return new Format.Builder()
.setId(id)
.setSampleMimeType(MimeTypes.APPLICATION_CEA608)
.setLanguage(language)
.setAccessibilityChannel(accessibilityChannel)
.build();
@SuppressWarnings("ConstantConditions")
private static Format[] parseClosedCaptionsDescriptor(
Descriptor descriptor, Pattern serviceDescriptorRegex, Format baseFormat) {
@Nullable String value = descriptor.value;
if (value == null) {
// There are embedded closed caption tracks, but service information is not declared.
return new Format[] {baseFormat};
}
String[] services = Util.split(value, ";");
Format[] formats = new Format[services.length];
for (int i = 0; i < services.length; i++) {
Matcher matcher = serviceDescriptorRegex.matcher(services[i]);
if (!matcher.matches()) {
// If we can't parse service information for all services, assume a single track.
return new Format[] {baseFormat};
}
int accessibilityChannel = Integer.parseInt(matcher.group(1));
formats[i] =
baseFormat
.buildUpon()
.setId(baseFormat.id + ":" + accessibilityChannel)
.setAccessibilityChannel(accessibilityChannel)
.setLanguage(matcher.group(2))
.build();
}
return formats;
}

// We won't assign the array to a variable that erases the generic type, and then write into it.
Expand Down Expand Up @@ -916,21 +924,21 @@ private static final class TrackGroupInfo {
public final int eventStreamGroupIndex;
public final int primaryTrackGroupIndex;
public final int embeddedEventMessageTrackGroupIndex;
public final int embeddedCea608TrackGroupIndex;
public final int embeddedClosedCaptionsTrackGroupIndex;

public static TrackGroupInfo primaryTrack(
int trackType,
int[] adaptationSetIndices,
int primaryTrackGroupIndex,
int embeddedEventMessageTrackGroupIndex,
int embeddedCea608TrackGroupIndex) {
int embeddedClosedCaptionsTrackGroupIndex) {
return new TrackGroupInfo(
trackType,
CATEGORY_PRIMARY,
adaptationSetIndices,
primaryTrackGroupIndex,
embeddedEventMessageTrackGroupIndex,
embeddedCea608TrackGroupIndex,
embeddedClosedCaptionsTrackGroupIndex,
/* eventStreamGroupIndex= */ -1);
}

Expand All @@ -946,7 +954,7 @@ public static TrackGroupInfo embeddedEmsgTrack(int[] adaptationSetIndices,
/* eventStreamGroupIndex= */ -1);
}

public static TrackGroupInfo embeddedCea608Track(int[] adaptationSetIndices,
public static TrackGroupInfo embeddedClosedCaptionsTrack(int[] adaptationSetIndices,
int primaryTrackGroupIndex) {
return new TrackGroupInfo(
C.TRACK_TYPE_TEXT,
Expand Down Expand Up @@ -975,14 +983,14 @@ private TrackGroupInfo(
int[] adaptationSetIndices,
int primaryTrackGroupIndex,
int embeddedEventMessageTrackGroupIndex,
int embeddedCea608TrackGroupIndex,
int embeddedClosedCaptionsTrackGroupIndex,
int eventStreamGroupIndex) {
this.trackType = trackType;
this.adaptationSetIndices = adaptationSetIndices;
this.trackGroupCategory = trackGroupCategory;
this.primaryTrackGroupIndex = primaryTrackGroupIndex;
this.embeddedEventMessageTrackGroupIndex = embeddedEventMessageTrackGroupIndex;
this.embeddedCea608TrackGroupIndex = embeddedCea608TrackGroupIndex;
this.embeddedClosedCaptionsTrackGroupIndex = embeddedClosedCaptionsTrackGroupIndex;
this.eventStreamGroupIndex = eventStreamGroupIndex;
}
}
Expand Down