Skip to content

Commit

Permalink
Migrate SmoothStreaming to Format.Builder
Browse files Browse the repository at this point in the history
Bitrates in SmoothStreaming manifests are average bitrates, as per
the ref'd issue.

Issue: #5978
PiperOrigin-RevId: 296467667
  • Loading branch information
ojw28 committed Feb 25, 2020
1 parent bc8fd2c commit d6650e6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ public static byte[] buildNalUnit(byte[] data, int offset, int length) {
* @return The individual NAL units, or null if the input did not consist of NAL start code
* delimited units.
*/
public static @Nullable byte[][] splitNalUnits(byte[] data) {
@Nullable
public static byte[][] splitNalUnits(byte[] data) {
if (!isNalStartCode(data, 0)) {
// data does not consist of NAL start code delimited units.
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -663,96 +663,65 @@ public QualityLevelParser(ElementParser parent, String baseUri) {

@Override
public void parseStartTag(XmlPullParser parser) throws ParserException {
int type = (Integer) getNormalizedAttribute(KEY_TYPE);
String id = parser.getAttributeValue(null, KEY_INDEX);
String name = (String) getNormalizedAttribute(KEY_NAME);
int bitrate = parseRequiredInt(parser, KEY_BITRATE);
String sampleMimeType = fourCCToMimeType(parseRequiredString(parser, KEY_FOUR_CC));
Format.Builder formatBuilder = new Format.Builder();

@Nullable String sampleMimeType = fourCCToMimeType(parseRequiredString(parser, KEY_FOUR_CC));
int type = (Integer) getNormalizedAttribute(KEY_TYPE);
if (type == C.TRACK_TYPE_VIDEO) {
int width = parseRequiredInt(parser, KEY_MAX_WIDTH);
int height = parseRequiredInt(parser, KEY_MAX_HEIGHT);
List<byte[]> codecSpecificData = buildCodecSpecificData(
parser.getAttributeValue(null, KEY_CODEC_PRIVATE_DATA));
format =
Format.createVideoContainerFormat(
id,
name,
MimeTypes.VIDEO_MP4,
sampleMimeType,
/* codecs= */ null,
/* metadata= */ null,
bitrate,
width,
height,
/* frameRate= */ Format.NO_VALUE,
codecSpecificData,
/* selectionFlags= */ 0,
/* roleFlags= */ 0);
formatBuilder
.setContainerMimeType(MimeTypes.VIDEO_MP4)
.setWidth(parseRequiredInt(parser, KEY_MAX_WIDTH))
.setHeight(parseRequiredInt(parser, KEY_MAX_HEIGHT))
.setInitializationData(codecSpecificData);
} else if (type == C.TRACK_TYPE_AUDIO) {
sampleMimeType = sampleMimeType == null ? MimeTypes.AUDIO_AAC : sampleMimeType;
int channels = parseRequiredInt(parser, KEY_CHANNELS);
int samplingRate = parseRequiredInt(parser, KEY_SAMPLING_RATE);
if (sampleMimeType == null) {
// If we don't know the MIME type, assume AAC.
sampleMimeType = MimeTypes.AUDIO_AAC;
}
int channelCount = parseRequiredInt(parser, KEY_CHANNELS);
int sampleRate = parseRequiredInt(parser, KEY_SAMPLING_RATE);
List<byte[]> codecSpecificData = buildCodecSpecificData(
parser.getAttributeValue(null, KEY_CODEC_PRIVATE_DATA));
if (codecSpecificData.isEmpty() && MimeTypes.AUDIO_AAC.equals(sampleMimeType)) {
codecSpecificData = Collections.singletonList(
CodecSpecificDataUtil.buildAacLcAudioSpecificConfig(samplingRate, channels));
codecSpecificData =
Collections.singletonList(
CodecSpecificDataUtil.buildAacLcAudioSpecificConfig(sampleRate, channelCount));
}
String language = (String) getNormalizedAttribute(KEY_LANGUAGE);
format =
Format.createAudioContainerFormat(
id,
name,
MimeTypes.AUDIO_MP4,
sampleMimeType,
/* codecs= */ null,
/* metadata= */ null,
bitrate,
channels,
samplingRate,
codecSpecificData,
/* selectionFlags= */ 0,
/* roleFlags= */ 0,
language);
formatBuilder
.setContainerMimeType(MimeTypes.AUDIO_MP4)
.setChannelCount(channelCount)
.setSampleRate(sampleRate)
.setInitializationData(codecSpecificData);
} else if (type == C.TRACK_TYPE_TEXT) {
String subType = (String) getNormalizedAttribute(KEY_SUB_TYPE);
@C.RoleFlags int roleFlags = 0;
switch (subType) {
case "CAPT":
roleFlags = C.ROLE_FLAG_CAPTION;
break;
case "DESC":
roleFlags = C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND;
break;
default:
break;
@Nullable String subType = (String) getNormalizedAttribute(KEY_SUB_TYPE);
if (subType != null) {
switch (subType) {
case "CAPT":
roleFlags = C.ROLE_FLAG_CAPTION;
break;
case "DESC":
roleFlags = C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND;
break;
default:
break;
}
}
String language = (String) getNormalizedAttribute(KEY_LANGUAGE);
format =
Format.createTextContainerFormat(
id,
name,
MimeTypes.APPLICATION_MP4,
sampleMimeType,
/* codecs= */ null,
bitrate,
/* selectionFlags= */ 0,
roleFlags,
language);
formatBuilder.setContainerMimeType(MimeTypes.APPLICATION_MP4).setRoleFlags(roleFlags);
} else {
format =
Format.createContainerFormat(
id,
name,
MimeTypes.APPLICATION_MP4,
sampleMimeType,
/* codecs= */ null,
bitrate,
/* selectionFlags= */ 0,
/* roleFlags= */ 0,
/* language= */ null);
formatBuilder.setContainerMimeType(MimeTypes.APPLICATION_MP4);
}

format =
formatBuilder
.setId(parser.getAttributeValue(null, KEY_INDEX))
.setLabel((String) getNormalizedAttribute(KEY_NAME))
.setSampleMimeType(sampleMimeType)
.setAverageBitrate(parseRequiredInt(parser, KEY_BITRATE))
.setLanguage((String) getNormalizedAttribute(KEY_LANGUAGE))
.build();
}

@Override
Expand All @@ -764,7 +733,7 @@ private static List<byte[]> buildCodecSpecificData(String codecSpecificDataStrin
ArrayList<byte[]> csd = new ArrayList<>();
if (!TextUtils.isEmpty(codecSpecificDataString)) {
byte[] codecPrivateData = Util.getBytesFromHexString(codecSpecificDataString);
byte[][] split = CodecSpecificDataUtil.splitNalUnits(codecPrivateData);
@Nullable byte[][] split = CodecSpecificDataUtil.splitNalUnits(codecPrivateData);
if (split == null) {
csd.add(codecPrivateData);
} else {
Expand All @@ -774,6 +743,7 @@ private static List<byte[]> buildCodecSpecificData(String codecSpecificDataStrin
return csd;
}

@Nullable
private static String fourCCToMimeType(String fourCC) {
if (fourCC.equalsIgnoreCase("H264") || fourCC.equalsIgnoreCase("X264")
|| fourCC.equalsIgnoreCase("AVC1") || fourCC.equalsIgnoreCase("DAVC")) {
Expand Down

0 comments on commit d6650e6

Please sign in to comment.