@Override public int readData( int track, long positionUs, MediaFormatHolder formatHolder, SampleHolder sampleHolder) { Assertions.checkState(state == STATE_ENABLED); downstreamPositionUs = positionUs; if (pendingDiscontinuity || isPendingReset()) { return NOTHING_READ; } boolean haveSamples = !sampleQueue.isEmpty(); BaseMediaChunk currentChunk = mediaChunks.getFirst(); while (haveSamples && mediaChunks.size() > 1 && mediaChunks.get(1).getFirstSampleIndex() <= sampleQueue.getReadIndex()) { mediaChunks.removeFirst(); currentChunk = mediaChunks.getFirst(); } Format format = currentChunk.format; if (!format.equals(downstreamFormat)) { notifyDownstreamFormatChanged(format, currentChunk.trigger, currentChunk.startTimeUs); } downstreamFormat = format; if (haveSamples || currentChunk.isMediaFormatFinal) { MediaFormat mediaFormat = currentChunk.getMediaFormat(); if (!mediaFormat.equals(downstreamMediaFormat)) { formatHolder.format = mediaFormat; formatHolder.drmInitData = currentChunk.getDrmInitData(); downstreamMediaFormat = mediaFormat; return FORMAT_READ; } // If mediaFormat and downstreamMediaFormat are equal but different objects then the equality // check above will have been expensive, comparing the fields in each format. We update // downstreamMediaFormat here so that referential equality can be cheaply established during // subsequent calls. downstreamMediaFormat = mediaFormat; } if (!haveSamples) { if (loadingFinished) { return END_OF_STREAM; } return NOTHING_READ; } if (sampleQueue.getSample(sampleHolder)) { boolean decodeOnly = sampleHolder.timeUs < lastSeekPositionUs; sampleHolder.flags |= decodeOnly ? C.SAMPLE_FLAG_DECODE_ONLY : 0; onSampleRead(currentChunk, sampleHolder); return SAMPLE_READ; } return NOTHING_READ; }
@Override public int readSample(int track, SampleHolder sampleHolder) throws IOException { if (sampleHolder.data == null) { sampleHolder.size = 0; return SampleSource.SAMPLE_READ; } if (!ffReadSample(pFormatCtx, sampleHolder)) { return SampleSource.NOTHING_READ; } // Log.d(TAG, "PTS: " + sampleHolder.timeUs); // Log.d(TAG, "frame start: " + sampleHolder.data.getInt(1)); return SampleSource.SAMPLE_READ; }
@Override protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { currentPositionUs = positionUs; try { source.continueBuffering(positionUs); } catch (IOException e) { throw new ExoPlaybackException(e); } if (parserHelper.isParsing()) { return; } Subtitle dequeuedSubtitle = null; if (subtitle == null) { try { dequeuedSubtitle = parserHelper.getAndClearResult(); } catch (IOException e) { throw new ExoPlaybackException(e); } } if (subtitle == null && dequeuedSubtitle != null) { // We've dequeued a new subtitle. Sync the event index and update the subtitle. subtitle = dequeuedSubtitle; syncNextEventIndex(positionUs); textRendererNeedsUpdate = true; } else if (subtitle != null) { // We're iterating through the events in a subtitle. Set textRendererNeedsUpdate if we // advance to the next event. long nextEventTimeUs = getNextEventTime(); while (nextEventTimeUs <= positionUs) { nextSubtitleEventIndex++; nextEventTimeUs = getNextEventTime(); textRendererNeedsUpdate = true; } if (nextEventTimeUs == Long.MAX_VALUE) { // We've finished processing the subtitle. subtitle = null; } } // We don't have a subtitle. Try and read the next one from the source, and if we succeed then // sync and set textRendererNeedsUpdate. if (!inputStreamEnded && subtitle == null) { try { SampleHolder sampleHolder = parserHelper.getSampleHolder(); sampleHolder.clearData(); int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false); if (result == SampleSource.SAMPLE_READ && !sampleHolder.decodeOnly) { parserHelper.startParseOperation(); textRendererNeedsUpdate = false; } else if (result == SampleSource.END_OF_STREAM) { inputStreamEnded = true; } } catch (IOException e) { throw new ExoPlaybackException(e); } } // Update the text renderer if we're both playing and textRendererNeedsUpdate is set. if (textRendererNeedsUpdate && getState() == TrackRenderer.STATE_STARTED) { textRendererNeedsUpdate = false; if (subtitle == null) { clearTextRenderer(); } else { updateTextRenderer(positionUs); } } }