Commit b405d3d9 by Oliver Woodman

Have Representation, TrackElement and Variant consistently expose Format.

And delete things that we're parsing but don't use from TrackElement.
parent 8673cafc
......@@ -218,10 +218,9 @@ public class DashRendererBuilder implements RendererBuilder,
// Determine which video representations we should use for playback.
int[] videoRepresentationIndices = null;
if (videoAdaptationSet != null) {
Format[] formats = getFormats(videoAdaptationSet.representations);
try {
videoRepresentationIndices = VideoFormatSelectorUtil.selectVideoFormatsForDefaultDisplay(
context, formats, null, filterHdContent);
context, videoAdaptationSet.representations, null, filterHdContent);
} catch (DecoderQueryException e) {
callback.onRenderersError(e);
return;
......@@ -363,14 +362,6 @@ public class DashRendererBuilder implements RendererBuilder,
callback.onRenderers(trackNames, multiTrackChunkSources, renderers);
}
private static Format[] getFormats(List<Representation> representations) {
Format[] formats = new Format[representations.size()];
for (int i = 0; i < formats.length; i++) {
formats[i] = representations.get(i).format;
}
return formats;
}
@TargetApi(18)
private static class V18Compat {
......
......@@ -23,7 +23,6 @@ import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.chunk.ChunkSampleSource;
import com.google.android.exoplayer.chunk.ChunkSource;
import com.google.android.exoplayer.chunk.Format;
import com.google.android.exoplayer.chunk.FormatEvaluator;
import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;
import com.google.android.exoplayer.chunk.MultiTrackChunkSource;
......@@ -36,7 +35,6 @@ import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingChunkSource;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.TrackElement;
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifestParser;
import com.google.android.exoplayer.text.TextTrackRenderer;
import com.google.android.exoplayer.text.ttml.TtmlParser;
......@@ -56,6 +54,7 @@ import android.os.Handler;
import android.widget.TextView;
import java.io.IOException;
import java.util.Arrays;
import java.util.UUID;
/**
......@@ -145,10 +144,9 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
// Determine which video tracks we should use for playback.
int[] videoTrackIndices = null;
if (videoStreamElementIndex != -1) {
Format[] formats = getFormats(manifest.streamElements[videoStreamElementIndex].tracks);
try {
videoTrackIndices = VideoFormatSelectorUtil.selectVideoFormatsForDefaultDisplay(context,
formats, null, false);
Arrays.asList(manifest.streamElements[videoStreamElementIndex].tracks), null, false);
} catch (DecoderQueryException e) {
callback.onRenderersError(e);
return;
......@@ -254,17 +252,6 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
callback.onRenderers(trackNames, multiTrackChunkSources, renderers);
}
private static Format[] getFormats(TrackElement[] trackElements) {
Format[] formats = new Format[trackElements.length];
for (int i = 0; i < formats.length; i++) {
TrackElement trackElement = trackElements[i];
formats[i] = new Format(String.valueOf(i), trackElement.mimeType, trackElement.maxWidth,
trackElement.maxHeight, -1, trackElement.numChannels, trackElement.sampleRate,
trackElement.bitrate);
}
return formats;
}
@TargetApi(18)
private static class V18Compat {
......
/*
* 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.chunk;
/**
* Represents an object that wraps a {@link Format}.
*/
public interface FormatWrapper {
/**
* Returns the wrapped format.
*/
Format getFormat();
}
......@@ -26,6 +26,7 @@ import android.view.Display;
import android.view.WindowManager;
import java.util.ArrayList;
import java.util.List;
/**
* Selects from possible video formats.
......@@ -44,19 +45,20 @@ public final class VideoFormatSelectorUtil {
* default display.
*
* @param context A context.
* @param formats The formats from which to select.
* @param formatWrappers Wrapped formats from which to select.
* @param allowedContainerMimeTypes An array of allowed container mime types. Null allows all
* mime types.
* @param filterHdFormats True to filter HD formats. False otherwise.
* @return An array holding the indices of the selected formats.
* @throws DecoderQueryException
*/
public static int[] selectVideoFormatsForDefaultDisplay(Context context, Format[] formats,
String[] allowedContainerMimeTypes, boolean filterHdFormats) throws DecoderQueryException {
public static int[] selectVideoFormatsForDefaultDisplay(Context context,
List<? extends FormatWrapper> formatWrappers, String[] allowedContainerMimeTypes,
boolean filterHdFormats) throws DecoderQueryException {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point displaySize = getDisplaySize(display);
return selectVideoFormats(formats, allowedContainerMimeTypes, filterHdFormats, true,
return selectVideoFormats(formatWrappers, allowedContainerMimeTypes, filterHdFormats, true,
displaySize.x, displaySize.y);
}
......@@ -73,7 +75,7 @@ public final class VideoFormatSelectorUtil {
* in pixels that the video can be rendered within the viewport.
* </ul>
*
* @param formats The formats from which to select.
* @param formatWrappers Wrapped formats from which to select.
* @param allowedContainerMimeTypes An array of allowed container mime types. Null allows all
* mime types.
* @param filterHdFormats True to filter HD formats. False otherwise.
......@@ -88,16 +90,17 @@ public final class VideoFormatSelectorUtil {
* @return An array holding the indices of the selected formats.
* @throws DecoderQueryException
*/
public static int[] selectVideoFormats(Format[] formats, String[] allowedContainerMimeTypes,
boolean filterHdFormats, boolean orientationMayChange, int viewportWidth, int viewportHeight)
throws DecoderQueryException {
public static int[] selectVideoFormats(List<? extends FormatWrapper> formatWrappers,
String[] allowedContainerMimeTypes, boolean filterHdFormats, boolean orientationMayChange,
int viewportWidth, int viewportHeight) throws DecoderQueryException {
int maxVideoPixelsToRetain = Integer.MAX_VALUE;
ArrayList<Integer> selectedIndexList = new ArrayList<Integer>();
int maxDecodableFrameSize = MediaCodecUtil.maxH264DecodableFrameSize();
// First pass to filter out formats that individually fail to meet the selection criteria.
for (int i = 0; i < formats.length; i++) {
Format format = formats[i];
int formatWrapperCount = formatWrappers.size();
for (int i = 0; i < formatWrapperCount; i++) {
Format format = formatWrappers.get(i).getFormat();
if (isFormatPlayable(format, allowedContainerMimeTypes, filterHdFormats,
maxDecodableFrameSize)) {
// Select the format for now. It may still be filtered in the second pass below.
......@@ -122,7 +125,7 @@ public final class VideoFormatSelectorUtil {
// unnecessarily high resolution given the size at which the video will be displayed within the
// viewport.
for (int i = selectedIndexList.size() - 1; i >= 0; i--) {
Format format = formats[selectedIndexList.get(i)];
Format format = formatWrappers.get(i).getFormat();
int videoPixels = format.width * format.height;
if (format.width != -1 && format.height != -1 && videoPixels > maxVideoPixelsToRetain) {
selectedIndexList.remove(i);
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer.dash.mpd;
import com.google.android.exoplayer.chunk.Format;
import com.google.android.exoplayer.chunk.FormatWrapper;
import com.google.android.exoplayer.dash.DashSegmentIndex;
import com.google.android.exoplayer.dash.DashSingleSegmentIndex;
import com.google.android.exoplayer.dash.mpd.SegmentBase.MultiSegmentBase;
......@@ -26,7 +27,7 @@ import android.net.Uri;
/**
* A DASH representation.
*/
public abstract class Representation {
public abstract class Representation implements FormatWrapper {
/**
* Identifies the piece of content to which this {@link Representation} belongs.
......@@ -105,6 +106,11 @@ public abstract class Representation {
presentationTimeOffsetUs = segmentBase.getPresentationTimeOffsetUs();
}
@Override
public Format getFormat() {
return format;
}
/**
* Gets a {@link RangedUri} defining the location of the representation's initialization data.
* May be null if no initialization data exists.
......
......@@ -29,7 +29,6 @@ import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.HttpDataSource.InvalidResponseCodeException;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.UriUtil;
import com.google.android.exoplayer.util.Util;
......@@ -118,7 +117,7 @@ public class HlsChunkSource {
private final DataSource dataSource;
private final HlsPlaylistParser playlistParser;
private final List<Variant> variants;
private final HlsFormat[] enabledFormats;
private final Format[] enabledFormats;
private final BandwidthMeter bandwidthMeter;
private final int adaptiveMode;
private final String baseUri;
......@@ -173,7 +172,7 @@ public class HlsChunkSource {
playlistParser = new HlsPlaylistParser();
if (playlist.type == HlsPlaylist.TYPE_MEDIA) {
variants = Collections.singletonList(new Variant(playlistUrl, 0, null, -1, -1));
variants = Collections.singletonList(new Variant(0, playlistUrl, 0, null, -1, -1));
variantIndices = null;
mediaPlaylists = new HlsMediaPlaylist[1];
mediaPlaylistBlacklistTimesMs = new long[1];
......@@ -194,8 +193,9 @@ public class HlsChunkSource {
// Select the first variant from the master playlist that's enabled.
int minEnabledVariantIndex = Integer.MAX_VALUE;
for (int i = 0; i < enabledFormats.length; i++) {
if (enabledFormats[i].variantIndex < minEnabledVariantIndex) {
minEnabledVariantIndex = enabledFormats[i].variantIndex;
int variantIndex = getVariantIndex(enabledFormats[i]);
if (variantIndex < minEnabledVariantIndex) {
minEnabledVariantIndex = variantIndex;
formatIndex = i;
}
maxWidth = Math.max(enabledFormats[i].width, maxWidth);
......@@ -246,7 +246,7 @@ public class HlsChunkSource {
switchingVariantSpliced = switchingVariant && adaptiveMode == ADAPTIVE_MODE_SPLICE;
}
int variantIndex = enabledFormats[nextFormatIndex].variantIndex;
int variantIndex = getVariantIndex(enabledFormats[nextFormatIndex]);
HlsMediaPlaylist mediaPlaylist = mediaPlaylists[variantIndex];
if (mediaPlaylist == null) {
// We don't have the media playlist for the next variant. Request it now.
......@@ -432,7 +432,7 @@ public class HlsChunkSource {
private int getFormatIndexForBandwidth(int bitrate) {
int lowestQualityEnabledFormatIndex = -1;
for (int i = 0; i < enabledFormats.length; i++) {
int variantIndex = enabledFormats[i].variantIndex;
int variantIndex = getVariantIndex(enabledFormats[i]);
if (mediaPlaylistBlacklistTimesMs[variantIndex] == 0) {
if (enabledFormats[i].bitrate <= bitrate) {
return i;
......@@ -507,7 +507,7 @@ public class HlsChunkSource {
durationUs = mediaPlaylist.durationUs;
}
private static HlsFormat[] buildEnabledFormats(List<Variant> variants, int[] variantIndices) {
private static Format[] buildEnabledFormats(List<Variant> variants, int[] variantIndices) {
ArrayList<Variant> enabledVariants = new ArrayList<Variant>();
if (variantIndices != null) {
for (int i = 0; i < variantIndices.length; i++) {
......@@ -522,7 +522,7 @@ public class HlsChunkSource {
ArrayList<Variant> definiteAudioOnlyVariants = new ArrayList<Variant>();
for (int i = 0; i < enabledVariants.size(); i++) {
Variant variant = enabledVariants.get(i);
if (variant.height > 0 || variantHasExplicitCodecWithPrefix(variant, "avc")) {
if (variant.format.height > 0 || variantHasExplicitCodecWithPrefix(variant, "avc")) {
definiteVideoVariants.add(variant);
} else if (variantHasExplicitCodecWithPrefix(variant, "mp4a")) {
definiteAudioOnlyVariants.add(variant);
......@@ -542,12 +542,9 @@ public class HlsChunkSource {
// Leave the enabled variants unchanged. They're likely either all video or all audio.
}
HlsFormat[] enabledFormats = new HlsFormat[enabledVariants.size()];
Format[] enabledFormats = new Format[enabledVariants.size()];
for (int i = 0; i < enabledFormats.length; i++) {
Variant variant = enabledVariants.get(i);
int variantIndex = variants.indexOf(variant);
enabledFormats[i] = new HlsFormat(Integer.toString(variantIndex), variant.width,
variant.height, variant.bitrate, variant.codecs, variantIndex);
enabledFormats[i] = enabledVariants.get(i).format;
}
Arrays.sort(enabledFormats, new Format.DecreasingBandwidthComparator());
......@@ -555,7 +552,7 @@ public class HlsChunkSource {
}
private static boolean variantHasExplicitCodecWithPrefix(Variant variant, String prefix) {
String codecs = variant.codecs;
String codecs = variant.format.codecs;
if (TextUtils.isEmpty(codecs)) {
return false;
}
......@@ -587,6 +584,16 @@ public class HlsChunkSource {
}
}
private int getVariantIndex(Format format) {
for (int i = 0; i < variants.size(); i++) {
if (format == variants.get(i).format) {
return i;
}
}
// Should never happen.
throw new IllegalStateException("Invalid format: " + format);
}
private static class MediaPlaylistChunk extends DataChunk {
public final int variantIndex;
......@@ -640,16 +647,4 @@ public class HlsChunkSource {
}
private static final class HlsFormat extends Format {
public final int variantIndex;
public HlsFormat(String id, int width, int height, int bitrate, String codecs,
int variantIndex) {
super(id, MimeTypes.APPLICATION_M3U8, width, height, -1, -1, -1, bitrate, null, codecs);
this.variantIndex = variantIndex;
}
}
}
......@@ -176,7 +176,7 @@ public final class HlsPlaylistParser implements UriLoadable.Parser<HlsPlaylist>
}
expectingStreamInfUrl = true;
} else if (!line.startsWith("#") && expectingStreamInfUrl) {
variants.add(new Variant(line, bitrate, codecs, width, height));
variants.add(new Variant(variants.size(), line, bitrate, codecs, width, height));
bitrate = 0;
codecs = null;
width = -1;
......
......@@ -15,23 +15,27 @@
*/
package com.google.android.exoplayer.hls;
import com.google.android.exoplayer.chunk.Format;
import com.google.android.exoplayer.chunk.FormatWrapper;
import com.google.android.exoplayer.util.MimeTypes;
/**
* Variant stream reference.
*/
public final class Variant {
public final class Variant implements FormatWrapper {
public final int bitrate;
public final String url;
public final String codecs;
public final int width;
public final int height;
public final Format format;
public Variant(String url, int bitrate, String codecs, int width, int height) {
this.bitrate = bitrate;
public Variant(int index, String url, int bitrate, String codecs, int width, int height) {
this.url = url;
this.codecs = codecs;
this.width = width;
this.height = height;
format = new Format(Integer.toString(index), MimeTypes.APPLICATION_M3U8, width, height, -1, -1,
-1, bitrate, null, codecs);
}
@Override
public Format getFormat() {
return format;
}
}
......@@ -73,7 +73,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
private final SparseArray<ChunkExtractorWrapper> extractorWrappers;
private final SparseArray<MediaFormat> mediaFormats;
private final DrmInitData drmInitData;
private final SmoothStreamingFormat[] formats;
private final Format[] formats;
private SmoothStreamingManifest currentManifest;
private int currentManifestChunkOffset;
......@@ -135,7 +135,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
this.liveEdgeLatencyUs = liveEdgeLatencyMs * 1000;
StreamElement streamElement = getElement(initialManifest);
trackInfo = new TrackInfo(streamElement.tracks[0].mimeType, initialManifest.durationUs);
trackInfo = new TrackInfo(streamElement.tracks[0].format.mimeType, initialManifest.durationUs);
evaluation = new Evaluation();
TrackEncryptionBox[] trackEncryptionBoxes = null;
......@@ -152,19 +152,16 @@ public class SmoothStreamingChunkSource implements ChunkSource {
}
int trackCount = trackIndices != null ? trackIndices.length : streamElement.tracks.length;
formats = new SmoothStreamingFormat[trackCount];
formats = new Format[trackCount];
extractorWrappers = new SparseArray<ChunkExtractorWrapper>();
mediaFormats = new SparseArray<MediaFormat>();
int maxWidth = 0;
int maxHeight = 0;
for (int i = 0; i < trackCount; i++) {
int trackIndex = trackIndices != null ? trackIndices[i] : i;
TrackElement trackElement = streamElement.tracks[trackIndex];
formats[i] = new SmoothStreamingFormat(String.valueOf(trackIndex), trackElement.mimeType,
trackElement.maxWidth, trackElement.maxHeight, trackElement.numChannels,
trackElement.sampleRate, trackElement.bitrate, trackIndex);
maxWidth = Math.max(maxWidth, trackElement.maxWidth);
maxHeight = Math.max(maxHeight, trackElement.maxHeight);
formats[i] = streamElement.tracks[trackIndex].format;
maxWidth = Math.max(maxWidth, formats[i].width);
maxHeight = Math.max(maxHeight, formats[i].height);
MediaFormat mediaFormat = getMediaFormat(streamElement, trackIndex);
int trackType = streamElement.type == StreamElement.TYPE_VIDEO ? Track.TYPE_VIDEO
......@@ -244,7 +241,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
evaluation.queueSize = queue.size();
formatEvaluator.evaluate(queue, playbackPositionUs, formats, evaluation);
SmoothStreamingFormat selectedFormat = (SmoothStreamingFormat) evaluation.format;
Format selectedFormat = evaluation.format;
out.queueSize = evaluation.queueSize;
if (selectedFormat == null) {
......@@ -304,7 +301,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
: chunkStartTimeUs + streamElement.getChunkDurationUs(chunkIndex);
int currentAbsoluteChunkIndex = chunkIndex + currentManifestChunkOffset;
int trackIndex = selectedFormat.trackIndex;
int trackIndex = getTrackIndex(selectedFormat);
Uri uri = streamElement.buildRequestUri(trackIndex, chunkIndex);
Chunk mediaChunk = newMediaChunk(selectedFormat, uri, null, extractorWrappers.get(trackIndex),
drmInitData, dataSource, currentAbsoluteChunkIndex, isLastChunk, chunkStartTimeUs,
......@@ -352,12 +349,24 @@ public class SmoothStreamingChunkSource implements ChunkSource {
return manifest.streamElements[streamElementIndex];
}
private int getTrackIndex(Format format) {
TrackElement[] tracks = currentManifest.streamElements[streamElementIndex].tracks;
for (int i = 0; i < tracks.length; i++) {
if (format == tracks[i].format) {
return i;
}
}
// Should never happen.
throw new IllegalStateException("Invalid format: " + format);
}
private static MediaFormat getMediaFormat(StreamElement streamElement, int trackIndex) {
TrackElement trackElement = streamElement.tracks[trackIndex];
String mimeType = trackElement.mimeType;
Format trackFormat = trackElement.format;
String mimeType = trackFormat.mimeType;
if (streamElement.type == StreamElement.TYPE_VIDEO) {
MediaFormat format = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE,
trackElement.maxWidth, trackElement.maxHeight, Arrays.asList(trackElement.csd));
trackFormat.width, trackFormat.height, Arrays.asList(trackElement.csd));
format.setMaxVideoDimensions(streamElement.maxWidth, streamElement.maxHeight);
return format;
} else if (streamElement.type == StreamElement.TYPE_AUDIO) {
......@@ -366,13 +375,13 @@ public class SmoothStreamingChunkSource implements ChunkSource {
csd = Arrays.asList(trackElement.csd);
} else {
csd = Collections.singletonList(CodecSpecificDataUtil.buildAudioSpecificConfig(
trackElement.sampleRate, trackElement.numChannels));
trackFormat.audioSamplingRate, trackFormat.numChannels));
}
MediaFormat format = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE,
trackElement.numChannels, trackElement.sampleRate, csd);
trackFormat.numChannels, trackFormat.audioSamplingRate, csd);
return format;
} else if (streamElement.type == StreamElement.TYPE_TEXT) {
return MediaFormat.createFormatForMimeType(streamElement.tracks[trackIndex].mimeType);
return MediaFormat.createFormatForMimeType(trackFormat.mimeType);
}
return null;
}
......@@ -412,16 +421,4 @@ public class SmoothStreamingChunkSource implements ChunkSource {
data[secondPosition] = temp;
}
private static final class SmoothStreamingFormat extends Format {
public final int trackIndex;
public SmoothStreamingFormat(String id, String mimeType, int width, int height,
int numChannels, int audioSamplingRate, int bitrate, int trackIndex) {
super(id, mimeType, width, height, -1, numChannels, audioSamplingRate, bitrate);
this.trackIndex = trackIndex;
}
}
}
......@@ -16,6 +16,8 @@
package com.google.android.exoplayer.smoothstreaming;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.chunk.Format;
import com.google.android.exoplayer.chunk.FormatWrapper;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.UriUtil;
import com.google.android.exoplayer.util.Util;
......@@ -124,50 +126,21 @@ public class SmoothStreamingManifest {
/**
* Represents a QualityLevel element.
*/
public static class TrackElement {
public static class TrackElement implements FormatWrapper {
// Required for all
public final int index;
public final int bitrate;
// Audio-video
public final Format format;
public final byte[][] csd;
public final int profile;
public final int level;
public final String mimeType;
// Video-only
public final int maxWidth;
public final int maxHeight;
// Audio-only
public final int sampleRate;
public final int numChannels;
public final int packetSize;
public final int audioTag;
public final int bitPerSample;
public final int nalUnitLengthField;
public final 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.mimeType = mimeType;
public TrackElement(int index, int bitrate, String mimeType, byte[][] csd, int maxWidth,
int maxHeight, int sampleRate, int numChannels) {
this.csd = csd;
this.profile = profile;
this.level = level;
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
this.sampleRate = sampleRate;
this.numChannels = channels;
this.packetSize = packetSize;
this.audioTag = audioTag;
this.bitPerSample = bitPerSample;
this.nalUnitLengthField = nalUnitLengthField;
this.content = content;
format = new Format(String.valueOf(index), mimeType, maxWidth, maxHeight, -1, numChannels,
sampleRate, bitrate);
}
@Override
public Format getFormat() {
return format;
}
}
......@@ -273,7 +246,7 @@ public class SmoothStreamingManifest {
Assertions.checkState(chunkStartTimes != null);
Assertions.checkState(chunkIndex < chunkStartTimes.size());
String chunkUrl = chunkTemplate
.replace(URL_PLACEHOLDER_BITRATE, Integer.toString(tracks[track].bitrate))
.replace(URL_PLACEHOLDER_BITRATE, Integer.toString(tracks[track].format.bitrate))
.replace(URL_PLACEHOLDER_START_TIME, chunkStartTimes.get(chunkIndex).toString());
return UriUtil.resolveToUri(baseUri, chunkUrl);
}
......
......@@ -585,11 +585,7 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
private static final String KEY_CODEC_PRIVATE_DATA = "CodecPrivateData";
private static final String KEY_SAMPLING_RATE = "SamplingRate";
private static final String KEY_CHANNELS = "Channels";
private static final String KEY_BITS_PER_SAMPLE = "BitsPerSample";
private static final String KEY_PACKET_SIZE = "PacketSize";
private static final String KEY_AUDIO_TAG = "AudioTag";
private static final String KEY_FOUR_CC = "FourCC";
private static final String KEY_NAL_UNIT_LENGTH_FIELD = "NALUnitLengthField";
private static final String KEY_TYPE = "Type";
private static final String KEY_MAX_WIDTH = "MaxWidth";
private static final String KEY_MAX_HEIGHT = "MaxHeight";
......@@ -599,18 +595,10 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
private int index;
private int bitrate;
private String mimeType;
private int profile;
private int level;
private int maxWidth;
private int maxHeight;
private int samplingRate;
private int channels;
private int packetSize;
private int audioTag;
private int bitPerSample;
private int nalUnitLengthField;
private String content;
public TrackElementParser(ElementParser parent, String baseUri) {
super(parent, baseUri, TAG);
......@@ -620,12 +608,10 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
@Override
public void parseStartTag(XmlPullParser parser) throws ParserException {
int type = (Integer) getNormalizedAttribute(KEY_TYPE);
content = null;
String value;
index = parseInt(parser, KEY_INDEX, -1);
bitrate = parseRequiredInt(parser, KEY_BITRATE);
nalUnitLengthField = parseInt(parser, KEY_NAL_UNIT_LENGTH_FIELD, 4);
if (type == StreamElement.TYPE_VIDEO) {
maxHeight = parseRequiredInt(parser, KEY_MAX_HEIGHT);
......@@ -643,15 +629,9 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
if (type == StreamElement.TYPE_AUDIO) {
samplingRate = parseRequiredInt(parser, KEY_SAMPLING_RATE);
channels = parseRequiredInt(parser, KEY_CHANNELS);
bitPerSample = parseRequiredInt(parser, KEY_BITS_PER_SAMPLE);
packetSize = parseRequiredInt(parser, KEY_PACKET_SIZE);
audioTag = parseRequiredInt(parser, KEY_AUDIO_TAG);
} else {
samplingRate = -1;
channels = -1;
bitPerSample = -1;
packetSize = -1;
audioTag = -1;
}
value = parser.getAttributeValue(null, KEY_CODEC_PRIVATE_DATA);
......@@ -662,11 +642,6 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
csd.add(codecPrivateData);
} else {
for (int i = 0; i < split.length; i++) {
Pair<Integer, Integer> spsParameters = CodecSpecificDataUtil.parseSpsNalUnit(split[i]);
if (spsParameters != null) {
profile = spsParameters.first;
level = spsParameters.second;
}
csd.add(split[i]);
}
}
......@@ -674,20 +649,14 @@ public class SmoothStreamingManifestParser implements UriLoadable.Parser<SmoothS
}
@Override
public void parseText(XmlPullParser parser) {
content = parser.getText();
}
@Override
public Object build() {
byte[][] csdArray = null;
if (!csd.isEmpty()) {
csdArray = new byte[csd.size()][];
csd.toArray(csdArray);
}
return new TrackElement(index, bitrate, mimeType, csdArray, profile, level, maxWidth,
maxHeight, samplingRate, channels, packetSize, audioTag, bitPerSample, nalUnitLengthField,
content);
return new TrackElement(index, bitrate, mimeType, csdArray, maxWidth, maxHeight, samplingRate,
channels);
}
private static String fourCCToMimeType(String fourCC) {
......
......@@ -60,35 +60,35 @@ public class HlsMasterPlaylistParserTest extends TestCase {
assertNotNull(variants);
assertEquals(5, variants.size());
assertEquals(1280000, variants.get(0).bitrate);
assertNotNull(variants.get(0).codecs);
assertEquals("mp4a.40.2,avc1.66.30", variants.get(0).codecs);
assertEquals(304, variants.get(0).width);
assertEquals(128, variants.get(0).height);
assertEquals(1280000, variants.get(0).format.bitrate);
assertNotNull(variants.get(0).format.codecs);
assertEquals("mp4a.40.2,avc1.66.30", variants.get(0).format.codecs);
assertEquals(304, variants.get(0).format.width);
assertEquals(128, variants.get(0).format.height);
assertEquals("http://example.com/low.m3u8", variants.get(0).url);
assertEquals(1280000, variants.get(1).bitrate);
assertNotNull(variants.get(1).codecs);
assertEquals("mp4a.40.2 , avc1.66.30 ", variants.get(1).codecs);
assertEquals(1280000, variants.get(1).format.bitrate);
assertNotNull(variants.get(1).format.codecs);
assertEquals("mp4a.40.2 , avc1.66.30 ", variants.get(1).format.codecs);
assertEquals("http://example.com/spaces_in_codecs.m3u8", variants.get(1).url);
assertEquals(2560000, variants.get(2).bitrate);
assertEquals(null, variants.get(2).codecs);
assertEquals(384, variants.get(2).width);
assertEquals(160, variants.get(2).height);
assertEquals(2560000, variants.get(2).format.bitrate);
assertEquals(null, variants.get(2).format.codecs);
assertEquals(384, variants.get(2).format.width);
assertEquals(160, variants.get(2).format.height);
assertEquals("http://example.com/mid.m3u8", variants.get(2).url);
assertEquals(7680000, variants.get(3).bitrate);
assertEquals(null, variants.get(3).codecs);
assertEquals(-1, variants.get(3).width);
assertEquals(-1, variants.get(3).height);
assertEquals(7680000, variants.get(3).format.bitrate);
assertEquals(null, variants.get(3).format.codecs);
assertEquals(-1, variants.get(3).format.width);
assertEquals(-1, variants.get(3).format.height);
assertEquals("http://example.com/hi.m3u8", variants.get(3).url);
assertEquals(65000, variants.get(4).bitrate);
assertNotNull(variants.get(4).codecs);
assertEquals("mp4a.40.5", variants.get(4).codecs);
assertEquals(-1, variants.get(4).width);
assertEquals(-1, variants.get(4).height);
assertEquals(65000, variants.get(4).format.bitrate);
assertNotNull(variants.get(4).format.codecs);
assertEquals("mp4a.40.5", variants.get(4).format.codecs);
assertEquals(-1, variants.get(4).format.width);
assertEquals(-1, variants.get(4).format.height);
assertEquals("http://example.com/audio-only.m3u8", variants.get(4).url);
} catch (IOException exception) {
fail(exception.getMessage());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment