@Override public Object build() { TrackElement[] trackElements = new TrackElement[tracks.size()]; tracks.toArray(trackElements); return new StreamElement(baseUri, url, type, subType, timescale, name, qualityLevels, maxWidth, maxHeight, displayWidth, displayHeight, language, trackElements, startTimes, lastChunkDuration); }
@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, maxWidth, maxHeight, samplingRate, channels); }
private int getTrackIndex(Format format) { TrackElement[] tracks = currentManifest.streamElements[streamElementIndex].tracks; for (int i = 0; i < tracks.length; i++) { if (tracks[i].format.equals(format)) { return i; } } // Should never happen. throw new IllegalStateException("Invalid format: " + format); }
@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, maxWidth, maxHeight, samplingRate, channels, language); }
@Override public void selectTracks(SmoothStreamingManifest manifest, Output output) throws IOException { for (int i = 0; i < manifest.streamElements.length; i++) { TrackElement[] tracks = manifest.streamElements[i].tracks; if (manifest.streamElements[i].type == streamElementType) { if (streamElementType == StreamElement.TYPE_VIDEO) { int[] trackIndices; if (filterVideoRepresentations) { trackIndices = VideoFormatSelectorUtil.selectVideoFormatsForDefaultDisplay( context, Arrays.asList(tracks), null, filterProtectedHdContent && manifest.protectionElement != null); } else { trackIndices = Util.firstIntegersArray(tracks.length); } int trackCount = trackIndices.length; if (trackCount > 1) { output.adaptiveTrack(manifest, i, trackIndices); } for (int j = 0; j < trackCount; j++) { output.fixedTrack(manifest, i, trackIndices[j]); } } else { for (int j = 0; j < tracks.length; j++) { output.fixedTrack(manifest, i, j); } } } } }
private static int getManifestTrackIndex(StreamElement element, Format format) { TrackElement[] tracks = element.tracks; for (int i = 0; i < tracks.length; i++) { if (tracks[i].format.equals(format)) { return i; } } // Should never happen. throw new IllegalStateException("Invalid format: " + format); }
@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); }
@Override public Object build() { TrackElement[] trackElements = new TrackElement[tracks.size()]; tracks.toArray(trackElements); return new StreamElement(type, subType, timeScale, name, qualityLevels, url, maxWidth, maxHeight, displayWidth, displayHeight, language, trackElements, startTimes); }
@Override public Object build() { byte[][] csdArray = null; if (!csd.isEmpty()) { 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); }
@Override public void addChild(Object child) { if (child instanceof TrackElement) { tracks.add((TrackElement) child); } }
@Override public void onManifest(String contentId, SmoothStreamingManifest manifest) { Handler mainHandler = playerActivity.getMainHandler(); LoadControl loadControl = new DefaultLoadControl(new BufferPool(BUFFER_SEGMENT_SIZE)); DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); // Obtain stream elements for playback. int maxDecodableFrameSize = MediaCodecUtil.maxH264DecodableFrameSize(); int audioStreamElementIndex = -1; int videoStreamElementIndex = -1; ArrayList<Integer> videoTrackIndexList = new ArrayList<Integer>(); for (int i = 0; i < manifest.streamElements.length; i++) { if (audioStreamElementIndex == -1 && manifest.streamElements[i].type == StreamElement.TYPE_AUDIO) { audioStreamElementIndex = i; } else if (videoStreamElementIndex == -1 && manifest.streamElements[i].type == StreamElement.TYPE_VIDEO) { videoStreamElementIndex = i; StreamElement streamElement = manifest.streamElements[i]; for (int j = 0; j < streamElement.tracks.length; j++) { TrackElement trackElement = streamElement.tracks[j]; if (trackElement.maxWidth * trackElement.maxHeight <= maxDecodableFrameSize) { videoTrackIndexList.add(j); } else { // The device isn't capable of playing this stream. } } } } int[] videoTrackIndices = Util.toArray(videoTrackIndexList); // Build the video renderer. DataSource videoDataSource = new UriDataSource(userAgent, bandwidthMeter); ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher, videoStreamElementIndex, videoTrackIndices, videoDataSource, new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS); ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true); MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(videoSampleSource, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, mainHandler, playerActivity, 50); // Build the audio renderer. DataSource audioDataSource = new UriDataSource(userAgent, bandwidthMeter); ChunkSource audioChunkSource = new SmoothStreamingChunkSource(manifestFetcher, audioStreamElementIndex, new int[] {0}, audioDataSource, new FormatEvaluator.FixedEvaluator(), LIVE_EDGE_LATENCY_MS); SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true); MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer( audioSampleSource); callback.onRenderers(videoRenderer, audioRenderer); }
public StreamElementParser(ElementParser parent, Uri baseUri) { super(parent, baseUri, TAG); this.baseUri = baseUri; tracks = new LinkedList<TrackElement>(); }
private SmoothStreamingChunkSource(ManifestFetcher<SmoothStreamingManifest> manifestFetcher, SmoothStreamingManifest initialManifest, int streamElementIndex, int[] trackIndices, DataSource dataSource, FormatEvaluator formatEvaluator, long liveEdgeLatencyMs) { this.manifestFetcher = manifestFetcher; this.streamElementIndex = streamElementIndex; this.currentManifest = initialManifest; this.dataSource = dataSource; this.formatEvaluator = formatEvaluator; this.liveEdgeLatencyUs = liveEdgeLatencyMs * 1000; StreamElement streamElement = getElement(initialManifest); trackInfo = new TrackInfo(streamElement.tracks[0].mimeType, initialManifest.durationUs); evaluation = new Evaluation(); TrackEncryptionBox[] trackEncryptionBoxes = null; ProtectionElement protectionElement = initialManifest.protectionElement; if (protectionElement != null) { byte[] keyId = getKeyId(protectionElement.data); trackEncryptionBoxes = new TrackEncryptionBox[1]; trackEncryptionBoxes[0] = new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId); psshInfo = Collections.singletonMap(protectionElement.uuid, protectionElement.data); } else { psshInfo = null; } int trackCount = trackIndices != null ? trackIndices.length : streamElement.tracks.length; formats = new SmoothStreamingFormat[trackCount]; extractors = new SparseArray<FragmentedMp4Extractor>(); 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); MediaFormat mediaFormat = getMediaFormat(streamElement, trackIndex); int trackType = streamElement.type == StreamElement.TYPE_VIDEO ? Track.TYPE_VIDEO : Track.TYPE_AUDIO; FragmentedMp4Extractor extractor = new FragmentedMp4Extractor( FragmentedMp4Extractor.WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME); extractor.setTrack(new Track(trackIndex, trackType, streamElement.timescale, mediaFormat, trackEncryptionBoxes)); extractors.put(trackIndex, extractor); } this.maxHeight = maxHeight; this.maxWidth = maxWidth; Arrays.sort(formats, new DecreasingBandwidthComparator()); }
private SmoothStreamingChunkSource(ManifestFetcher<SmoothStreamingManifest> manifestFetcher, SmoothStreamingManifest initialManifest, int streamElementIndex, int[] trackIndices, DataSource dataSource, FormatEvaluator formatEvaluator, long liveEdgeLatencyMs) { this.manifestFetcher = manifestFetcher; this.streamElementIndex = streamElementIndex; this.currentManifest = initialManifest; this.dataSource = dataSource; this.formatEvaluator = formatEvaluator; this.liveEdgeLatencyUs = liveEdgeLatencyMs * 1000; StreamElement streamElement = getElement(initialManifest); trackInfo = new TrackInfo(streamElement.tracks[0].mimeType, initialManifest.durationUs); evaluation = new Evaluation(); TrackEncryptionBox[] trackEncryptionBoxes = null; ProtectionElement protectionElement = initialManifest.protectionElement; if (protectionElement != null) { byte[] keyId = getKeyId(protectionElement.data); trackEncryptionBoxes = new TrackEncryptionBox[1]; trackEncryptionBoxes[0] = new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId); psshInfo = Collections.singletonMap(protectionElement.uuid, protectionElement.data); } else { psshInfo = null; } int trackCount = trackIndices != null ? trackIndices.length : streamElement.tracks.length; formats = new SmoothStreamingFormat[trackCount]; extractors = new SparseArray<FragmentedMp4Extractor>(); 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); MediaFormat mediaFormat = getMediaFormat(streamElement, trackIndex); int trackType = streamElement.type == StreamElement.TYPE_VIDEO ? Track.TYPE_VIDEO : Track.TYPE_AUDIO; FragmentedMp4Extractor extractor = new FragmentedMp4Extractor( FragmentedMp4Extractor.WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME); extractor.setTrack(new Track(trackIndex, trackType, streamElement.timescale, initialManifest.durationUs, mediaFormat, trackEncryptionBoxes)); extractors.put(trackIndex, extractor); } this.maxHeight = maxHeight; this.maxWidth = maxWidth; Arrays.sort(formats, new DecreasingBandwidthComparator()); }
public StreamElementParser(ElementParser parent) { super(TAG, parent); tracks = new LinkedList<TrackElement>(); }
/** * @param baseUrl The base URL for the streams. * @param manifest The manifest parsed from {@code baseUrl + "/Manifest"}. * @param streamElementIndex The index of the stream element in the manifest to be provided by * the source. * @param trackIndices The indices of the tracks within the stream element to be considered by * the source. May be null if all tracks within the element should be considered. * @param dataSource A {@link DataSource} suitable for loading the media data. * @param formatEvaluator Selects from the available formats. */ public SmoothStreamingChunkSource(String baseUrl, SmoothStreamingManifest manifest, int streamElementIndex, int[] trackIndices, DataSource dataSource, FormatEvaluator formatEvaluator) { this.baseUrl = baseUrl; this.streamElement = manifest.streamElements[streamElementIndex]; this.trackInfo = new TrackInfo(streamElement.tracks[0].mimeType, manifest.getDurationUs()); this.dataSource = dataSource; this.formatEvaluator = formatEvaluator; this.evaluation = new Evaluation(); TrackEncryptionBox[] trackEncryptionBoxes = null; ProtectionElement protectionElement = manifest.protectionElement; if (protectionElement != null) { byte[] keyId = getKeyId(protectionElement.data); trackEncryptionBoxes = new TrackEncryptionBox[1]; trackEncryptionBoxes[0] = new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId); } int trackCount = trackIndices != null ? trackIndices.length : streamElement.tracks.length; formats = new SmoothStreamingFormat[trackCount]; extractors = new SparseArray<FragmentedMp4Extractor>(); 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); MediaFormat mediaFormat = getMediaFormat(streamElement, trackIndex); int trackType = streamElement.type == StreamElement.TYPE_VIDEO ? Track.TYPE_VIDEO : Track.TYPE_AUDIO; FragmentedMp4Extractor extractor = new FragmentedMp4Extractor( FragmentedMp4Extractor.WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME); extractor.setTrack(new Track(trackIndex, trackType, streamElement.timeScale, mediaFormat, trackEncryptionBoxes)); if (protectionElement != null) { extractor.putPsshInfo(protectionElement.uuid, protectionElement.data); } extractors.put(trackIndex, extractor); } this.maxHeight = maxHeight; this.maxWidth = maxWidth; Arrays.sort(formats, new DecreasingBandwidthComparator()); }