Fix SmoothStreaming where audio FourCC is missing.

This commit is contained in:
Oliver Woodman 2014-09-19 18:29:34 +01:00
parent b2fc944af1
commit 8378019839
3 changed files with 38 additions and 123 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}