@Override public void buildRenderers(ExoPlayerHelper player) { Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE); // Build the video and audio renderers. Extractor webmExtractor = new WebmExtractor(); Extractor mp4Extractor = new Mp4Extractor(); DataSource dataSource = new FileDataSource(); ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE, webmExtractor, mp4Extractor); MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, player.getMainHandler(), player, 50); MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource, MediaCodecSelector.DEFAULT, null, true, player.getMainHandler(), player); TrackRenderer textRenderer = new TextTrackRenderer(sampleSource, player, player.getMainHandler().getLooper()); // Invoke the callback. TrackRenderer[] renderers = new TrackRenderer[ExoPlayerHelper.RENDERER_COUNT]; renderers[ExoPlayerHelper.TYPE_VIDEO] = videoRenderer; renderers[ExoPlayerHelper.TYPE_AUDIO] = audioRenderer; renderers[ExoPlayerHelper.TYPE_TEXT] = textRenderer; player.onRenderers(renderers, null); }
@Override public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { while (true) { switch (parserState) { case STATE_READING_ATOM_HEADER: if (!readAtomHeader(input)) { return Extractor.RESULT_END_OF_INPUT; } break; case STATE_READING_ATOM_PAYLOAD: readAtomPayload(input); break; case STATE_READING_ENCRYPTION_DATA: readEncryptionData(input); break; default: if (readSample(input)) { return RESULT_CONTINUE; } } } }
@SuppressWarnings("NonAtomicVolatileUpdate") @Override public void load() throws IOException, InterruptedException { DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); if (bytesLoaded == 0) { // Set the target to ourselves. extractorWrapper.init(this); } // Load and parse the initialization data. try { int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { result = extractorWrapper.read(input); } } finally { bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); } } finally { dataSource.close(); } }
@SuppressWarnings("NonAtomicVolatileUpdate") @Override public final void load() throws IOException, InterruptedException { DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); if (bytesLoaded == 0) { // Set the target to ourselves. extractorWrapper.init(this); } // Load and parse the initialization data. try { int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { result = extractorWrapper.read(input); } } finally { bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); } } finally { dataSource.close(); } }
@Override public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { int currentFileSize = (int) input.getLength(); // Increase the size of sampleData if necessary. if (sampleSize == sampleData.length) { sampleData = Arrays.copyOf(sampleData, (currentFileSize != C.LENGTH_UNBOUNDED ? currentFileSize : sampleData.length) * 3 / 2); } // Consume to the input. int bytesRead = input.read(sampleData, sampleSize, sampleData.length - sampleSize); if (bytesRead != C.RESULT_END_OF_INPUT) { sampleSize += bytesRead; if (currentFileSize == C.LENGTH_UNBOUNDED || sampleSize != currentFileSize) { return Extractor.RESULT_CONTINUE; } } // We've reached the end of the input, which corresponds to the end of the current file. processSample(); return Extractor.RESULT_END_OF_INPUT; }
@Override public final int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { while (true) { switch (parserState) { case STATE_READING_ATOM_HEADER: if (!readAtomHeader(input)) { return Extractor.RESULT_END_OF_INPUT; } break; case STATE_READING_ATOM_PAYLOAD: readAtomPayload(input); break; case STATE_READING_ENCRYPTION_DATA: readEncryptionData(input); break; default: if (readSample(input)) { return RESULT_CONTINUE; } } } }
@SuppressWarnings("NonAtomicVolatileUpdate") @Override public final void load() throws IOException, InterruptedException { DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded); try { // Create and open the input. ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); if (bytesLoaded == 0) { // Set the target to ourselves. extractorWrapper.init(this); } // Load and parse the sample data. try { int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { result = extractorWrapper.read(input); } } finally { bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); } } finally { dataSource.close(); } }
public HlsExtractorWrapper(int trigger, Format format, long startTimeUs, Extractor extractor, boolean shouldSpliceIn) { this.trigger = trigger; this.format = format; this.startTimeUs = startTimeUs; this.extractor = extractor; this.shouldSpliceIn = shouldSpliceIn; sampleQueues = new SparseArray<>(); }
@Override public void load() throws IOException, InterruptedException { // If we previously fed part of this chunk to the extractor, we need to skip it this time. For // encrypted content we need to skip the data by reading it through the source, so as to ensure // correct decryption of the remainder of the chunk. For clear content, we can request the // remainder of the chunk directly. DataSpec loadDataSpec; boolean skipLoadedBytes; if (isEncrypted) { loadDataSpec = dataSpec; skipLoadedBytes = bytesLoaded != 0; } else { loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded); skipLoadedBytes = false; } try { ExtractorInput input = new DefaultExtractorInput(dataSource, loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec)); if (skipLoadedBytes) { input.skipFully(bytesLoaded); } try { int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { result = extractorWrapper.read(input); } } finally { bytesLoaded = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); } } finally { dataSource.close(); } }
@Override public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { sampleRead = false; boolean continueReading = true; while (continueReading && !sampleRead) { continueReading = reader.read(input); if (continueReading && maybeSeekForCues(seekPosition, input.getPosition())) { return Extractor.RESULT_SEEK; } } return continueReading ? Extractor.RESULT_CONTINUE : Extractor.RESULT_END_OF_INPUT; }
public HlsExtractorWrapper(int trigger, Format format, long startTimeUs, Extractor extractor, boolean shouldSpliceIn, int adaptiveMaxWidth, int adaptiveMaxHeight) { this.trigger = trigger; this.format = format; this.startTimeUs = startTimeUs; this.extractor = extractor; this.shouldSpliceIn = shouldSpliceIn; this.adaptiveMaxWidth = adaptiveMaxWidth; this.adaptiveMaxHeight = adaptiveMaxHeight; sampleQueues = new SparseArray<>(); }
public static void consumeTestData(Extractor extractor, byte[] data) throws IOException, InterruptedException { FakeExtractorInput input = new FakeExtractorInput.Builder().setData(data).build(); PositionHolder seekPositionHolder = new PositionHolder(); int readResult = Extractor.RESULT_CONTINUE; while (readResult != Extractor.RESULT_END_OF_INPUT) { readResult = extractor.read(input, seekPositionHolder); if (readResult == Extractor.RESULT_SEEK) { long seekPosition = seekPositionHolder.position; Assertions.checkState(0 < seekPosition && seekPosition <= Integer.MAX_VALUE); input.setPosition((int) seekPosition); } } }
public static void consumeTestData(Extractor extractor, byte[] data) throws IOException, InterruptedException { ExtractorInput input = createTestExtractorInput(data); PositionHolder seekPositionHolder = new PositionHolder(); int readResult = Extractor.RESULT_CONTINUE; while (readResult != Extractor.RESULT_END_OF_INPUT) { readResult = extractor.read(input, seekPositionHolder); if (readResult == Extractor.RESULT_SEEK) { input = createTestExtractorInput(data, (int) seekPositionHolder.position); } } }
/** * @param extractor The extractor to wrap. */ public ChunkExtractorWrapper(Extractor extractor) { this.extractor = extractor; }
DashChunkSource(ManifestFetcher<MediaPresentationDescription> manifestFetcher, MediaPresentationDescription initialManifest, int adaptationSetIndex, int[] representationIndices, DataSource dataSource, FormatEvaluator formatEvaluator, Clock systemClock, long liveEdgeLatencyUs, long elapsedRealtimeOffsetUs, boolean startAtLiveEdge, Handler eventHandler, EventListener eventListener) { this.manifestFetcher = manifestFetcher; this.currentManifest = initialManifest; this.adaptationSetIndex = adaptationSetIndex; this.representationIndices = representationIndices; this.dataSource = dataSource; this.formatEvaluator = formatEvaluator; this.systemClock = systemClock; this.liveEdgeLatencyUs = liveEdgeLatencyUs; this.elapsedRealtimeOffsetUs = elapsedRealtimeOffsetUs; this.startAtLiveEdge = startAtLiveEdge; this.eventHandler = eventHandler; this.eventListener = eventListener; this.evaluation = new Evaluation(); this.headerBuilder = new StringBuilder(); this.seekRangeValues = new long[2]; drmInitData = getDrmInitData(currentManifest, adaptationSetIndex); Representation[] representations = getFilteredRepresentations(currentManifest, adaptationSetIndex, representationIndices); long periodDurationUs = (representations[0].periodDurationMs == TrackRenderer.UNKNOWN_TIME_US) ? TrackRenderer.UNKNOWN_TIME_US : representations[0].periodDurationMs * 1000; this.trackInfo = new TrackInfo(representations[0].format.mimeType, periodDurationUs); this.formats = new Format[representations.length]; this.representationHolders = new HashMap<>(); int maxWidth = 0; int maxHeight = 0; for (int i = 0; i < representations.length; i++) { formats[i] = representations[i].format; maxWidth = Math.max(formats[i].width, maxWidth); maxHeight = Math.max(formats[i].height, maxHeight); Extractor extractor = mimeTypeIsWebm(formats[i].mimeType) ? new WebmExtractor() : new FragmentedMp4Extractor(); representationHolders.put(formats[i].id, new RepresentationHolder(representations[i], new ChunkExtractorWrapper(extractor))); } this.maxWidth = maxWidth; this.maxHeight = maxHeight; Arrays.sort(formats, new DecreasingBandwidthComparator()); }
@Override public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { long position = input.getPosition(); if (!oggParser.readPacket(input, scratch)) { return Extractor.RESULT_END_OF_INPUT; } byte[] data = scratch.data; if (streamInfo == null) { streamInfo = new FlacStreamInfo(data, 17); byte[] metadata = Arrays.copyOfRange(data, 9, scratch.limit()); metadata[4] = (byte) 0x80; // Set the last metadata block flag, ignore the other blocks List<byte[]> initializationData = Collections.singletonList(metadata); MediaFormat mediaFormat = MediaFormat.createAudioFormat(null, MimeTypes.AUDIO_FLAC, streamInfo.bitRate(), MediaFormat.NO_VALUE, streamInfo.durationUs(), streamInfo.channels, streamInfo.sampleRate, initializationData, null); trackOutput.format(mediaFormat); } else if (data[0] == AUDIO_PACKET_TYPE) { if (!firstAudioPacketProcessed) { if (seekTable != null) { extractorOutput.seekMap(seekTable.createSeekMap(position, streamInfo.sampleRate)); seekTable = null; } else { extractorOutput.seekMap(SeekMap.UNSEEKABLE); } firstAudioPacketProcessed = true; } trackOutput.sampleData(scratch, scratch.limit()); scratch.setPosition(0); long timeUs = FlacUtil.extractSampleTimestamp(streamInfo, scratch); trackOutput.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, scratch.limit(), 0, null); } else if ((data[0] & 0x7F) == SEEKTABLE_PACKET_TYPE && seekTable == null) { seekTable = FlacSeekTable.parseSeekTable(scratch); } scratch.reset(); return Extractor.RESULT_CONTINUE; }
/** * Reads from the provided {@link ExtractorInput}. * * @param input The {@link ExtractorInput} from which to read. * @return One of {@link Extractor#RESULT_CONTINUE} and {@link Extractor#RESULT_END_OF_INPUT}. * @throws IOException If an error occurred reading from the source. * @throws InterruptedException If the thread was interrupted. */ public int read(ExtractorInput input) throws IOException, InterruptedException { int result = extractor.read(input, null); Assertions.checkState(result != Extractor.RESULT_SEEK); return result; }