Fix SmoothStreaming where audio FourCC is missing.
This commit is contained in:
parent
b2fc944af1
commit
8378019839
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer.smoothstreaming;
|
||||
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.MimeTypes;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.net.Uri;
|
||||
@ -103,12 +102,9 @@ public class SmoothStreamingManifest {
|
||||
public final int bitrate;
|
||||
|
||||
// Audio-video
|
||||
public final String fourCC;
|
||||
public final byte[][] csd;
|
||||
public final int profile;
|
||||
public final int level;
|
||||
|
||||
// Audio-video (derived)
|
||||
public final String mimeType;
|
||||
|
||||
// Video-only
|
||||
@ -125,12 +121,12 @@ public class SmoothStreamingManifest {
|
||||
public final int nalUnitLengthField;
|
||||
public final String content;
|
||||
|
||||
public TrackElement(int index, int bitrate, String fourCC, byte[][] csd, int profile, int level,
|
||||
int maxWidth, int maxHeight, int sampleRate, int channels, int packetSize, int audioTag,
|
||||
int bitPerSample, int nalUnitLengthField, String content) {
|
||||
public TrackElement(int index, int bitrate, String mimeType, byte[][] csd, int profile,
|
||||
int level, int maxWidth, int maxHeight, int sampleRate, int channels, int packetSize,
|
||||
int audioTag, int bitPerSample, int nalUnitLengthField, String content) {
|
||||
this.index = index;
|
||||
this.bitrate = bitrate;
|
||||
this.fourCC = fourCC;
|
||||
this.mimeType = mimeType;
|
||||
this.csd = csd;
|
||||
this.profile = profile;
|
||||
this.level = level;
|
||||
@ -143,19 +139,6 @@ public class SmoothStreamingManifest {
|
||||
this.bitPerSample = bitPerSample;
|
||||
this.nalUnitLengthField = nalUnitLengthField;
|
||||
this.content = content;
|
||||
this.mimeType = fourCCToMimeType(fourCC);
|
||||
}
|
||||
|
||||
private static String fourCCToMimeType(String fourCC) {
|
||||
if (fourCC.equalsIgnoreCase("H264") || fourCC.equalsIgnoreCase("AVC1")
|
||||
|| fourCC.equalsIgnoreCase("DAVC")) {
|
||||
return MimeTypes.VIDEO_H264;
|
||||
} else if (fourCC.equalsIgnoreCase("AACL") || fourCC.equalsIgnoreCase("AACH")) {
|
||||
return MimeTypes.AUDIO_AAC;
|
||||
} else if (fourCC.equalsIgnoreCase("TTML")) {
|
||||
return MimeTypes.APPLICATION_TTML;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.Trac
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.CodecSpecificDataUtil;
|
||||
import com.google.android.exoplayer.util.ManifestParser;
|
||||
import com.google.android.exoplayer.util.MimeTypes;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Base64;
|
||||
@ -586,7 +587,7 @@ public class SmoothStreamingManifestParser implements ManifestParser<SmoothStrea
|
||||
|
||||
private int index;
|
||||
private int bitrate;
|
||||
private String fourCC;
|
||||
private String mimeType;
|
||||
private int profile;
|
||||
private int level;
|
||||
private int maxWidth;
|
||||
@ -618,11 +619,14 @@ public class SmoothStreamingManifestParser implements ManifestParser<SmoothStrea
|
||||
if (type == StreamElement.TYPE_VIDEO) {
|
||||
maxHeight = parseRequiredInt(parser, KEY_MAX_HEIGHT);
|
||||
maxWidth = parseRequiredInt(parser, KEY_MAX_WIDTH);
|
||||
fourCC = parseRequiredString(parser, KEY_FOUR_CC);
|
||||
mimeType = fourCCToMimeType(parseRequiredString(parser, KEY_FOUR_CC));
|
||||
} else {
|
||||
maxHeight = -1;
|
||||
maxWidth = -1;
|
||||
fourCC = parser.getAttributeValue(null, KEY_FOUR_CC);
|
||||
String fourCC = parser.getAttributeValue(null, KEY_FOUR_CC);
|
||||
// If fourCC is missing and the stream type is audio, we assume AAC.
|
||||
mimeType = fourCC != null ? fourCCToMimeType(fourCC)
|
||||
: type == StreamElement.TYPE_AUDIO ? MimeTypes.AUDIO_AAC : null;
|
||||
}
|
||||
|
||||
if (type == StreamElement.TYPE_AUDIO) {
|
||||
@ -658,17 +662,6 @@ public class SmoothStreamingManifestParser implements ManifestParser<SmoothStrea
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] hexStringToByteArray(String hexString) {
|
||||
int length = hexString.length();
|
||||
byte[] data = new byte[length / 2];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
int stringOffset = i * 2;
|
||||
data[i] = (byte) ((Character.digit(hexString.charAt(stringOffset), 16) << 4)
|
||||
+ Character.digit(hexString.charAt(stringOffset + 1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseText(XmlPullParser parser) {
|
||||
content = parser.getText();
|
||||
@ -681,8 +674,33 @@ public class SmoothStreamingManifestParser implements ManifestParser<SmoothStrea
|
||||
csdArray = new byte[csd.size()][];
|
||||
csd.toArray(csdArray);
|
||||
}
|
||||
return new TrackElement(index, bitrate, fourCC, csdArray, profile, level, maxWidth, maxHeight,
|
||||
samplingRate, channels, packetSize, audioTag, bitPerSample, nalUnitLengthField, content);
|
||||
return new TrackElement(index, bitrate, mimeType, csdArray, profile, level, maxWidth,
|
||||
maxHeight, samplingRate, channels, packetSize, audioTag, bitPerSample, nalUnitLengthField,
|
||||
content);
|
||||
}
|
||||
|
||||
private static String fourCCToMimeType(String fourCC) {
|
||||
if (fourCC.equalsIgnoreCase("H264") || fourCC.equalsIgnoreCase("X264")
|
||||
|| fourCC.equalsIgnoreCase("AVC1") || fourCC.equalsIgnoreCase("DAVC")) {
|
||||
return MimeTypes.VIDEO_H264;
|
||||
} else if (fourCC.equalsIgnoreCase("AAC") || fourCC.equalsIgnoreCase("AACL")
|
||||
|| fourCC.equalsIgnoreCase("AACH") || fourCC.equalsIgnoreCase("AACP")) {
|
||||
return MimeTypes.AUDIO_AAC;
|
||||
} else if (fourCC.equalsIgnoreCase("TTML")) {
|
||||
return MimeTypes.APPLICATION_TTML;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[] hexStringToByteArray(String hexString) {
|
||||
int length = hexString.length();
|
||||
byte[] data = new byte[length / 2];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
int stringOffset = i * 2;
|
||||
data[i] = (byte) ((Character.digit(hexString.charAt(stringOffset), 16) << 4)
|
||||
+ Character.digit(hexString.charAt(stringOffset + 1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer.smoothstreaming;
|
||||
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
|
||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.TrackElement;
|
||||
import com.google.android.exoplayer.util.CodecSpecificDataUtil;
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class SmoothStreamingUtil {
|
||||
|
||||
private SmoothStreamingUtil() {}
|
||||
|
||||
/**
|
||||
* Builds a {@link MediaFormat} for the specified track of the specified {@link StreamElement}.
|
||||
*
|
||||
* @param element The stream element.
|
||||
* @param track The index of the track for which to build the format.
|
||||
* @return The format.
|
||||
*/
|
||||
public static MediaFormat getMediaFormat(StreamElement element, int track) {
|
||||
TrackElement trackElement = element.tracks[track];
|
||||
String mimeType = trackElement.mimeType;
|
||||
if (element.type == StreamElement.TYPE_VIDEO) {
|
||||
MediaFormat format = MediaFormat.createVideoFormat(mimeType, -1, trackElement.maxWidth,
|
||||
trackElement.maxHeight, Arrays.asList(trackElement.csd));
|
||||
format.setMaxVideoDimensions(element.maxWidth, element.maxHeight);
|
||||
return format;
|
||||
} else if (element.type == StreamElement.TYPE_AUDIO) {
|
||||
List<byte[]> csd;
|
||||
if (trackElement.csd != null) {
|
||||
csd = Arrays.asList(trackElement.csd);
|
||||
} else {
|
||||
csd = Collections.singletonList(CodecSpecificDataUtil.buildAudioSpecificConfig(
|
||||
trackElement.sampleRate, trackElement.numChannels));
|
||||
}
|
||||
MediaFormat format = MediaFormat.createAudioFormat(mimeType, -1, trackElement.numChannels,
|
||||
trackElement.sampleRate, csd);
|
||||
return format;
|
||||
}
|
||||
// TODO: Do subtitles need a format? MediaFormat supports KEY_LANGUAGE.
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] getKeyId(byte[] initData) {
|
||||
StringBuilder initDataStringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < initData.length; i += 2) {
|
||||
initDataStringBuilder.append((char) initData[i]);
|
||||
}
|
||||
String initDataString = initDataStringBuilder.toString();
|
||||
String keyIdString = initDataString.substring(
|
||||
initDataString.indexOf("<KID>") + 5, initDataString.indexOf("</KID>"));
|
||||
byte[] keyId = Base64.decode(keyIdString, Base64.DEFAULT);
|
||||
swap(keyId, 0, 3);
|
||||
swap(keyId, 1, 2);
|
||||
swap(keyId, 4, 5);
|
||||
swap(keyId, 6, 7);
|
||||
return keyId;
|
||||
}
|
||||
|
||||
private static void swap(byte[] data, int firstPosition, int secondPosition) {
|
||||
byte temp = data[firstPosition];
|
||||
data[firstPosition] = data[secondPosition];
|
||||
data[secondPosition] = temp;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user