use of com.google.android.exoplayer2.extractor.ExtractorOutput in project ExoPlayer by google.
the class FlacExtractorSeekTest method seeking_binarySearch_handlesSeekToZero.
@Test
public void seeking_binarySearch_handlesSeekToZero() throws IOException {
String fileName = TEST_FILE_BINARY_SEARCH;
Uri fileUri = TestUtil.buildAssetUri(fileName);
SeekMap seekMap = TestUtil.extractSeekMap(extractor, extractorOutput, dataSource, fileUri);
FakeTrackOutput trackOutput = extractorOutput.trackOutputs.get(0);
long targetSeekTimeUs = 0;
int extractedFrameIndex = TestUtil.seekToTimeUs(extractor, seekMap, targetSeekTimeUs, dataSource, trackOutput, fileUri);
assertThat(extractedFrameIndex).isNotEqualTo(C.INDEX_UNSET);
assertFirstFrameAfterSeekContainsTargetSeekTime(fileName, trackOutput, targetSeekTimeUs, extractedFrameIndex);
}
use of com.google.android.exoplayer2.extractor.ExtractorOutput in project ExoPlayer by google.
the class FlvExtractorSeekTest method seeking_handlesSeekToEof.
@Test
public void seeking_handlesSeekToEof() throws Exception {
String fileName = TEST_FILE_KEY_FRAME_INDEX;
Uri fileUri = TestUtil.buildAssetUri(fileName);
SeekMap seekMap = TestUtil.extractSeekMap(extractor, extractorOutput, dataSource, fileUri);
int trackId = extractorOutput.trackOutputs.keyAt(0);
FakeTrackOutput trackOutput = extractorOutput.trackOutputs.get(trackId);
long targetSeekTimeUs = seekMap.getDurationUs();
int extractedFrameIndex = TestUtil.seekToTimeUs(extractor, seekMap, targetSeekTimeUs, dataSource, trackOutput, fileUri);
assertThat(extractedFrameIndex).isNotEqualTo(C.INDEX_UNSET);
assertFirstFrameAfterSeekIsWithinKeyFrameInterval(fileName, trackId, trackOutput, extractedFrameIndex, targetSeekTimeUs);
}
use of com.google.android.exoplayer2.extractor.ExtractorOutput in project ExoPlayer by google.
the class FlvExtractorSeekTest method seeking_handlesSeekingForward.
@Test
public void seeking_handlesSeekingForward() throws Exception {
String fileName = TEST_FILE_KEY_FRAME_INDEX;
Uri fileUri = TestUtil.buildAssetUri(fileName);
SeekMap seekMap = TestUtil.extractSeekMap(extractor, extractorOutput, dataSource, fileUri);
int trackId = extractorOutput.trackOutputs.keyAt(0);
FakeTrackOutput trackOutput = extractorOutput.trackOutputs.get(trackId);
long firstSeekTimeUs = seekMap.getDurationUs() / 3;
TestUtil.seekToTimeUs(extractor, seekMap, firstSeekTimeUs, dataSource, trackOutput, fileUri);
long targetSeekTimeUs = seekMap.getDurationUs() * 2 / 3;
int extractedFrameIndex = TestUtil.seekToTimeUs(extractor, seekMap, targetSeekTimeUs, dataSource, trackOutput, fileUri);
assertThat(extractedFrameIndex).isNotEqualTo(C.INDEX_UNSET);
assertFirstFrameAfterSeekIsWithinKeyFrameInterval(fileName, trackId, trackOutput, extractedFrameIndex, targetSeekTimeUs);
}
use of com.google.android.exoplayer2.extractor.ExtractorOutput in project ExoPlayer by google.
the class Mp4Extractor method processMoovAtom.
/**
* Updates the stored track metadata to reflect the contents of the specified moov atom.
*/
private void processMoovAtom(ContainerAtom moov) throws ParserException {
int firstVideoTrackIndex = C.INDEX_UNSET;
long durationUs = C.TIME_UNSET;
List<Mp4Track> tracks = new ArrayList<>();
// Process metadata.
@Nullable Metadata udtaMetaMetadata = null;
@Nullable Metadata smtaMetadata = null;
boolean isQuickTime = fileType == FILE_TYPE_QUICKTIME;
GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder();
@Nullable Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
if (udta != null) {
Pair<@NullableType Metadata, @NullableType Metadata> udtaMetadata = AtomParsers.parseUdta(udta);
udtaMetaMetadata = udtaMetadata.first;
smtaMetadata = udtaMetadata.second;
if (udtaMetaMetadata != null) {
gaplessInfoHolder.setFromMetadata(udtaMetaMetadata);
}
}
@Nullable Metadata mdtaMetadata = null;
@Nullable Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta);
if (meta != null) {
mdtaMetadata = AtomParsers.parseMdtaFromMeta(meta);
}
boolean ignoreEditLists = (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0;
List<TrackSampleTable> trackSampleTables = parseTraks(moov, gaplessInfoHolder, /* duration= */
C.TIME_UNSET, /* drmInitData= */
null, ignoreEditLists, isQuickTime, /* modifyTrackFunction= */
track -> track);
ExtractorOutput extractorOutput = checkNotNull(this.extractorOutput);
int trackCount = trackSampleTables.size();
for (int i = 0; i < trackCount; i++) {
TrackSampleTable trackSampleTable = trackSampleTables.get(i);
if (trackSampleTable.sampleCount == 0) {
continue;
}
Track track = trackSampleTable.track;
long trackDurationUs = track.durationUs != C.TIME_UNSET ? track.durationUs : trackSampleTable.durationUs;
durationUs = max(durationUs, trackDurationUs);
Mp4Track mp4Track = new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type));
int maxInputSize;
if (MimeTypes.AUDIO_TRUEHD.equals(track.format.sampleMimeType)) {
// TrueHD groups samples per chunks of TRUEHD_RECHUNK_SAMPLE_COUNT samples.
maxInputSize = trackSampleTable.maximumSize * Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT;
} else {
// Each sample has up to three bytes of overhead for the start code that replaces its
// length. Allow ten source samples per output sample, like the platform extractor.
maxInputSize = trackSampleTable.maximumSize + 3 * 10;
}
Format.Builder formatBuilder = track.format.buildUpon();
formatBuilder.setMaxInputSize(maxInputSize);
if (track.type == C.TRACK_TYPE_VIDEO && trackDurationUs > 0 && trackSampleTable.sampleCount > 1) {
float frameRate = trackSampleTable.sampleCount / (trackDurationUs / 1000000f);
formatBuilder.setFrameRate(frameRate);
}
MetadataUtil.setFormatGaplessInfo(track.type, gaplessInfoHolder, formatBuilder);
MetadataUtil.setFormatMetadata(track.type, udtaMetaMetadata, mdtaMetadata, formatBuilder, smtaMetadata, slowMotionMetadataEntries.isEmpty() ? null : new Metadata(slowMotionMetadataEntries));
mp4Track.trackOutput.format(formatBuilder.build());
if (track.type == C.TRACK_TYPE_VIDEO && firstVideoTrackIndex == C.INDEX_UNSET) {
firstVideoTrackIndex = tracks.size();
}
tracks.add(mp4Track);
}
this.firstVideoTrackIndex = firstVideoTrackIndex;
this.durationUs = durationUs;
this.tracks = tracks.toArray(new Mp4Track[0]);
accumulatedSampleSizes = calculateAccumulatedSampleSizes(this.tracks);
extractorOutput.endTracks();
extractorOutput.seekMap(this);
}
use of com.google.android.exoplayer2.extractor.ExtractorOutput in project ExoPlayer by google.
the class MatroskaExtractor method endMasterElement.
/**
* Called when the end of a master element is encountered.
*
* @see EbmlProcessor#endMasterElement(int)
*/
@CallSuper
protected void endMasterElement(int id) throws ParserException {
assertInitialized();
switch(id) {
case ID_SEGMENT_INFO:
if (timecodeScale == C.TIME_UNSET) {
// timecodeScale was omitted. Use the default value.
timecodeScale = 1000000;
}
if (durationTimecode != C.TIME_UNSET) {
durationUs = scaleTimecodeToUs(durationTimecode);
}
break;
case ID_SEEK:
if (seekEntryId == UNSET_ENTRY_ID || seekEntryPosition == C.POSITION_UNSET) {
throw ParserException.createForMalformedContainer("Mandatory element SeekID or SeekPosition not found", /* cause= */
null);
}
if (seekEntryId == ID_CUES) {
cuesContentPosition = seekEntryPosition;
}
break;
case ID_CUES:
if (!sentSeekMap) {
extractorOutput.seekMap(buildSeekMap(cueTimesUs, cueClusterPositions));
sentSeekMap = true;
} else {
// We have already built the cues. Ignore.
}
this.cueTimesUs = null;
this.cueClusterPositions = null;
break;
case ID_BLOCK_GROUP:
if (blockState != BLOCK_STATE_DATA) {
// We've skipped this block (due to incompatible track number).
return;
}
// Commit sample metadata.
int sampleOffset = 0;
for (int i = 0; i < blockSampleCount; i++) {
sampleOffset += blockSampleSizes[i];
}
Track track = tracks.get(blockTrackNumber);
track.assertOutputInitialized();
for (int i = 0; i < blockSampleCount; i++) {
long sampleTimeUs = blockTimeUs + (i * track.defaultSampleDurationNs) / 1000;
int sampleFlags = blockFlags;
if (i == 0 && !blockHasReferenceBlock) {
// If the ReferenceBlock element was not found in this block, then the first frame is a
// keyframe.
sampleFlags |= C.BUFFER_FLAG_KEY_FRAME;
}
int sampleSize = blockSampleSizes[i];
// The offset is to the end of the sample.
sampleOffset -= sampleSize;
commitSampleToOutput(track, sampleTimeUs, sampleFlags, sampleSize, sampleOffset);
}
blockState = BLOCK_STATE_START;
break;
case ID_CONTENT_ENCODING:
assertInTrackEntry(id);
if (currentTrack.hasContentEncryption) {
if (currentTrack.cryptoData == null) {
throw ParserException.createForMalformedContainer("Encrypted Track found but ContentEncKeyID was not found", /* cause= */
null);
}
currentTrack.drmInitData = new DrmInitData(new SchemeData(C.UUID_NIL, MimeTypes.VIDEO_WEBM, currentTrack.cryptoData.encryptionKey));
}
break;
case ID_CONTENT_ENCODINGS:
assertInTrackEntry(id);
if (currentTrack.hasContentEncryption && currentTrack.sampleStrippedBytes != null) {
throw ParserException.createForMalformedContainer("Combining encryption and compression is not supported", /* cause= */
null);
}
break;
case ID_TRACK_ENTRY:
Track currentTrack = checkStateNotNull(this.currentTrack);
if (currentTrack.codecId == null) {
throw ParserException.createForMalformedContainer("CodecId is missing in TrackEntry element", /* cause= */
null);
} else {
if (isCodecSupported(currentTrack.codecId)) {
currentTrack.initializeOutput(extractorOutput, currentTrack.number);
tracks.put(currentTrack.number, currentTrack);
}
}
this.currentTrack = null;
break;
case ID_TRACKS:
if (tracks.size() == 0) {
throw ParserException.createForMalformedContainer("No valid tracks were found", /* cause= */
null);
}
extractorOutput.endTracks();
break;
default:
break;
}
}
Aggregations