use of androidx.media3.extractor.metadata.id3.Id3Decoder in project ExoPlayer by google.
the class Id3Peeker method peekId3Data.
/**
* Peeks ID3 data from the input and parses the first ID3 tag.
*
* @param input The {@link ExtractorInput} from which data should be peeked.
* @param id3FramePredicate Determines which ID3 frames are decoded. May be null to decode all
* frames.
* @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
* present in the input.
* @throws IOException If an error occurred peeking from the input.
*/
@Nullable
public Metadata peekId3Data(ExtractorInput input, @Nullable Id3Decoder.FramePredicate id3FramePredicate) throws IOException {
int peekedId3Bytes = 0;
@Nullable Metadata metadata = null;
while (true) {
try {
input.peekFully(scratch.getData(), /* offset= */
0, Id3Decoder.ID3_HEADER_LENGTH);
} catch (EOFException e) {
// If input has less than ID3_HEADER_LENGTH, ignore the rest.
break;
}
scratch.setPosition(0);
if (scratch.readUnsignedInt24() != Id3Decoder.ID3_TAG) {
// Not an ID3 tag.
break;
}
// Skip major version, minor version and flags.
scratch.skipBytes(3);
int framesLength = scratch.readSynchSafeInt();
int tagLength = Id3Decoder.ID3_HEADER_LENGTH + framesLength;
if (metadata == null) {
byte[] id3Data = new byte[tagLength];
System.arraycopy(scratch.getData(), 0, id3Data, 0, Id3Decoder.ID3_HEADER_LENGTH);
input.peekFully(id3Data, Id3Decoder.ID3_HEADER_LENGTH, framesLength);
metadata = new Id3Decoder(id3FramePredicate).decode(id3Data, tagLength);
} else {
input.advancePeekPosition(framesLength);
}
peekedId3Bytes += tagLength;
}
input.resetPeekPosition();
input.advancePeekPosition(peekedId3Bytes);
return metadata;
}
use of androidx.media3.extractor.metadata.id3.Id3Decoder in project ExoPlayer by google.
the class HlsMediaChunk method createInstance.
/**
* Creates a new instance.
*
* @param extractorFactory A {@link HlsExtractorFactory} from which the {@link
* HlsMediaChunkExtractor} is obtained.
* @param dataSource The source from which the data should be loaded.
* @param format The chunk format.
* @param startOfPlaylistInPeriodUs The position of the playlist in the period in microseconds.
* @param mediaPlaylist The media playlist from which this chunk was obtained.
* @param segmentBaseHolder The segment holder.
* @param playlistUrl The url of the playlist from which this chunk was obtained.
* @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption
* information is available in the multivariant playlist.
* @param trackSelectionReason See {@link #trackSelectionReason}.
* @param trackSelectionData See {@link #trackSelectionData}.
* @param isMasterTimestampSource True if the chunk can initialize the timestamp adjuster.
* @param timestampAdjusterProvider The provider from which to obtain the {@link
* TimestampAdjuster}.
* @param previousChunk The {@link HlsMediaChunk} that preceded this one. May be null.
* @param mediaSegmentKey The media segment decryption key, if fully encrypted. Null otherwise.
* @param initSegmentKey The initialization segment decryption key, if fully encrypted. Null
* otherwise.
* @param shouldSpliceIn Whether samples for this chunk should be spliced into existing samples.
*/
public static HlsMediaChunk createInstance(HlsExtractorFactory extractorFactory, DataSource dataSource, Format format, long startOfPlaylistInPeriodUs, HlsMediaPlaylist mediaPlaylist, HlsChunkSource.SegmentBaseHolder segmentBaseHolder, Uri playlistUrl, @Nullable List<Format> muxedCaptionFormats, @C.SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, boolean isMasterTimestampSource, TimestampAdjusterProvider timestampAdjusterProvider, @Nullable HlsMediaChunk previousChunk, @Nullable byte[] mediaSegmentKey, @Nullable byte[] initSegmentKey, boolean shouldSpliceIn, PlayerId playerId) {
// Media segment.
HlsMediaPlaylist.SegmentBase mediaSegment = segmentBaseHolder.segmentBase;
DataSpec dataSpec = new DataSpec.Builder().setUri(UriUtil.resolveToUri(mediaPlaylist.baseUri, mediaSegment.url)).setPosition(mediaSegment.byteRangeOffset).setLength(mediaSegment.byteRangeLength).setFlags(segmentBaseHolder.isPreload ? FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED : 0).build();
boolean mediaSegmentEncrypted = mediaSegmentKey != null;
@Nullable byte[] mediaSegmentIv = mediaSegmentEncrypted ? getEncryptionIvArray(Assertions.checkNotNull(mediaSegment.encryptionIV)) : null;
DataSource mediaDataSource = buildDataSource(dataSource, mediaSegmentKey, mediaSegmentIv);
// Init segment.
HlsMediaPlaylist.Segment initSegment = mediaSegment.initializationSegment;
DataSpec initDataSpec = null;
boolean initSegmentEncrypted = false;
@Nullable DataSource initDataSource = null;
if (initSegment != null) {
initSegmentEncrypted = initSegmentKey != null;
@Nullable byte[] initSegmentIv = initSegmentEncrypted ? getEncryptionIvArray(Assertions.checkNotNull(initSegment.encryptionIV)) : null;
Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
initDataSpec = new DataSpec(initSegmentUri, initSegment.byteRangeOffset, initSegment.byteRangeLength);
initDataSource = buildDataSource(dataSource, initSegmentKey, initSegmentIv);
}
long segmentStartTimeInPeriodUs = startOfPlaylistInPeriodUs + mediaSegment.relativeStartTimeUs;
long segmentEndTimeInPeriodUs = segmentStartTimeInPeriodUs + mediaSegment.durationUs;
int discontinuitySequenceNumber = mediaPlaylist.discontinuitySequence + mediaSegment.relativeDiscontinuitySequence;
@Nullable HlsMediaChunkExtractor previousExtractor = null;
Id3Decoder id3Decoder;
ParsableByteArray scratchId3Data;
if (previousChunk != null) {
boolean isSameInitData = initDataSpec == previousChunk.initDataSpec || (initDataSpec != null && previousChunk.initDataSpec != null && initDataSpec.uri.equals(previousChunk.initDataSpec.uri) && initDataSpec.position == previousChunk.initDataSpec.position);
boolean isFollowingChunk = playlistUrl.equals(previousChunk.playlistUrl) && previousChunk.loadCompleted;
id3Decoder = previousChunk.id3Decoder;
scratchId3Data = previousChunk.scratchId3Data;
previousExtractor = isSameInitData && isFollowingChunk && !previousChunk.extractorInvalidated && previousChunk.discontinuitySequenceNumber == discontinuitySequenceNumber ? previousChunk.extractor : null;
} else {
id3Decoder = new Id3Decoder();
scratchId3Data = new ParsableByteArray(Id3Decoder.ID3_HEADER_LENGTH);
}
return new HlsMediaChunk(extractorFactory, mediaDataSource, dataSpec, format, mediaSegmentEncrypted, initDataSource, initDataSpec, initSegmentEncrypted, playlistUrl, muxedCaptionFormats, trackSelectionReason, trackSelectionData, segmentStartTimeInPeriodUs, segmentEndTimeInPeriodUs, segmentBaseHolder.mediaSequence, segmentBaseHolder.partIndex, /* isPublished= */
!segmentBaseHolder.isPreload, discontinuitySequenceNumber, mediaSegment.hasGapTag, isMasterTimestampSource, /* timestampAdjuster= */
timestampAdjusterProvider.getAdjuster(discontinuitySequenceNumber), mediaSegment.drmInitData, previousExtractor, id3Decoder, scratchId3Data, shouldSpliceIn, playerId);
}
use of androidx.media3.extractor.metadata.id3.Id3Decoder in project Telegram-FOSS by Telegram-FOSS-Team.
the class Id3Peeker method peekId3Data.
/**
* Peeks ID3 data from the input and parses the first ID3 tag.
*
* @param input The {@link ExtractorInput} from which data should be peeked.
* @param id3FramePredicate Determines which ID3 frames are decoded. May be null to decode all
* frames.
* @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
* present in the input.
* @throws IOException If an error occurred peeking from the input.
* @throws InterruptedException If the thread was interrupted.
*/
@Nullable
public Metadata peekId3Data(ExtractorInput input, @Nullable Id3Decoder.FramePredicate id3FramePredicate) throws IOException, InterruptedException {
int peekedId3Bytes = 0;
Metadata metadata = null;
while (true) {
try {
input.peekFully(scratch.data, /* offset= */
0, Id3Decoder.ID3_HEADER_LENGTH);
} catch (EOFException e) {
// If input has less than ID3_HEADER_LENGTH, ignore the rest.
break;
}
scratch.setPosition(0);
if (scratch.readUnsignedInt24() != Id3Decoder.ID3_TAG) {
// Not an ID3 tag.
break;
}
// Skip major version, minor version and flags.
scratch.skipBytes(3);
int framesLength = scratch.readSynchSafeInt();
int tagLength = Id3Decoder.ID3_HEADER_LENGTH + framesLength;
if (metadata == null) {
byte[] id3Data = new byte[tagLength];
System.arraycopy(scratch.data, 0, id3Data, 0, Id3Decoder.ID3_HEADER_LENGTH);
input.peekFully(id3Data, Id3Decoder.ID3_HEADER_LENGTH, framesLength);
metadata = new Id3Decoder(id3FramePredicate).decode(id3Data, tagLength);
} else {
input.advancePeekPosition(framesLength);
}
peekedId3Bytes += tagLength;
}
input.resetPeekPosition();
input.advancePeekPosition(peekedId3Bytes);
return metadata;
}
use of androidx.media3.extractor.metadata.id3.Id3Decoder in project Telegram-FOSS by Telegram-FOSS-Team.
the class HlsMediaChunk method createInstance.
/**
* Creates a new instance.
*
* @param extractorFactory A {@link HlsExtractorFactory} from which the HLS media chunk extractor
* is obtained.
* @param dataSource The source from which the data should be loaded.
* @param format The chunk format.
* @param startOfPlaylistInPeriodUs The position of the playlist in the period in microseconds.
* @param mediaPlaylist The media playlist from which this chunk was obtained.
* @param playlistUrl The url of the playlist from which this chunk was obtained.
* @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption
* information is available in the master playlist.
* @param trackSelectionReason See {@link #trackSelectionReason}.
* @param trackSelectionData See {@link #trackSelectionData}.
* @param isMasterTimestampSource True if the chunk can initialize the timestamp adjuster.
* @param timestampAdjusterProvider The provider from which to obtain the {@link
* TimestampAdjuster}.
* @param previousChunk The {@link HlsMediaChunk} that preceded this one. May be null.
* @param mediaSegmentKey The media segment decryption key, if fully encrypted. Null otherwise.
* @param initSegmentKey The initialization segment decryption key, if fully encrypted. Null
* otherwise.
*/
public static HlsMediaChunk createInstance(HlsExtractorFactory extractorFactory, DataSource dataSource, Format format, long startOfPlaylistInPeriodUs, HlsMediaPlaylist mediaPlaylist, int segmentIndexInPlaylist, Uri playlistUrl, @Nullable List<Format> muxedCaptionFormats, int trackSelectionReason, @Nullable Object trackSelectionData, boolean isMasterTimestampSource, TimestampAdjusterProvider timestampAdjusterProvider, @Nullable HlsMediaChunk previousChunk, @Nullable byte[] mediaSegmentKey, @Nullable byte[] initSegmentKey) {
// Media segment.
HlsMediaPlaylist.Segment mediaSegment = mediaPlaylist.segments.get(segmentIndexInPlaylist);
DataSpec dataSpec = new DataSpec(UriUtil.resolveToUri(mediaPlaylist.baseUri, mediaSegment.url), mediaSegment.byterangeOffset, mediaSegment.byterangeLength, /* key= */
null);
boolean mediaSegmentEncrypted = mediaSegmentKey != null;
byte[] mediaSegmentIv = mediaSegmentEncrypted ? getEncryptionIvArray(Assertions.checkNotNull(mediaSegment.encryptionIV)) : null;
DataSource mediaDataSource = buildDataSource(dataSource, mediaSegmentKey, mediaSegmentIv);
// Init segment.
HlsMediaPlaylist.Segment initSegment = mediaSegment.initializationSegment;
DataSpec initDataSpec = null;
boolean initSegmentEncrypted = false;
DataSource initDataSource = null;
if (initSegment != null) {
initSegmentEncrypted = initSegmentKey != null;
byte[] initSegmentIv = initSegmentEncrypted ? getEncryptionIvArray(Assertions.checkNotNull(initSegment.encryptionIV)) : null;
Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
initDataSpec = new DataSpec(initSegmentUri, initSegment.byterangeOffset, initSegment.byterangeLength, /* key= */
null);
initDataSource = buildDataSource(dataSource, initSegmentKey, initSegmentIv);
}
long segmentStartTimeInPeriodUs = startOfPlaylistInPeriodUs + mediaSegment.relativeStartTimeUs;
long segmentEndTimeInPeriodUs = segmentStartTimeInPeriodUs + mediaSegment.durationUs;
int discontinuitySequenceNumber = mediaPlaylist.discontinuitySequence + mediaSegment.relativeDiscontinuitySequence;
Extractor previousExtractor = null;
Id3Decoder id3Decoder;
ParsableByteArray scratchId3Data;
boolean shouldSpliceIn;
if (previousChunk != null) {
id3Decoder = previousChunk.id3Decoder;
scratchId3Data = previousChunk.scratchId3Data;
shouldSpliceIn = !playlistUrl.equals(previousChunk.playlistUrl) || !previousChunk.loadCompleted;
previousExtractor = previousChunk.isExtractorReusable && previousChunk.discontinuitySequenceNumber == discontinuitySequenceNumber && !shouldSpliceIn ? previousChunk.extractor : null;
} else {
id3Decoder = new Id3Decoder();
scratchId3Data = new ParsableByteArray(Id3Decoder.ID3_HEADER_LENGTH);
shouldSpliceIn = false;
}
return new HlsMediaChunk(extractorFactory, mediaDataSource, dataSpec, format, mediaSegmentEncrypted, initDataSource, initDataSpec, initSegmentEncrypted, playlistUrl, muxedCaptionFormats, trackSelectionReason, trackSelectionData, segmentStartTimeInPeriodUs, segmentEndTimeInPeriodUs, /* chunkMediaSequence= */
mediaPlaylist.mediaSequence + segmentIndexInPlaylist, discontinuitySequenceNumber, mediaSegment.hasGapTag, isMasterTimestampSource, /* timestampAdjuster= */
timestampAdjusterProvider.getAdjuster(discontinuitySequenceNumber), mediaSegment.drmInitData, previousExtractor, id3Decoder, scratchId3Data, shouldSpliceIn);
}
use of androidx.media3.extractor.metadata.id3.Id3Decoder in project media by androidx.
the class HlsMediaChunk method createInstance.
/**
* Creates a new instance.
*
* @param extractorFactory A {@link HlsExtractorFactory} from which the {@link
* HlsMediaChunkExtractor} is obtained.
* @param dataSource The source from which the data should be loaded.
* @param format The chunk format.
* @param startOfPlaylistInPeriodUs The position of the playlist in the period in microseconds.
* @param mediaPlaylist The media playlist from which this chunk was obtained.
* @param segmentBaseHolder The segment holder.
* @param playlistUrl The url of the playlist from which this chunk was obtained.
* @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption
* information is available in the multivariant playlist.
* @param trackSelectionReason See {@link #trackSelectionReason}.
* @param trackSelectionData See {@link #trackSelectionData}.
* @param isMasterTimestampSource True if the chunk can initialize the timestamp adjuster.
* @param timestampAdjusterProvider The provider from which to obtain the {@link
* TimestampAdjuster}.
* @param previousChunk The {@link HlsMediaChunk} that preceded this one. May be null.
* @param mediaSegmentKey The media segment decryption key, if fully encrypted. Null otherwise.
* @param initSegmentKey The initialization segment decryption key, if fully encrypted. Null
* otherwise.
* @param shouldSpliceIn Whether samples for this chunk should be spliced into existing samples.
*/
public static HlsMediaChunk createInstance(HlsExtractorFactory extractorFactory, DataSource dataSource, Format format, long startOfPlaylistInPeriodUs, HlsMediaPlaylist mediaPlaylist, HlsChunkSource.SegmentBaseHolder segmentBaseHolder, Uri playlistUrl, @Nullable List<Format> muxedCaptionFormats, @C.SelectionReason int trackSelectionReason, @Nullable Object trackSelectionData, boolean isMasterTimestampSource, TimestampAdjusterProvider timestampAdjusterProvider, @Nullable HlsMediaChunk previousChunk, @Nullable byte[] mediaSegmentKey, @Nullable byte[] initSegmentKey, boolean shouldSpliceIn, PlayerId playerId) {
// Media segment.
HlsMediaPlaylist.SegmentBase mediaSegment = segmentBaseHolder.segmentBase;
DataSpec dataSpec = new DataSpec.Builder().setUri(UriUtil.resolveToUri(mediaPlaylist.baseUri, mediaSegment.url)).setPosition(mediaSegment.byteRangeOffset).setLength(mediaSegment.byteRangeLength).setFlags(segmentBaseHolder.isPreload ? FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED : 0).build();
boolean mediaSegmentEncrypted = mediaSegmentKey != null;
@Nullable byte[] mediaSegmentIv = mediaSegmentEncrypted ? getEncryptionIvArray(Assertions.checkNotNull(mediaSegment.encryptionIV)) : null;
DataSource mediaDataSource = buildDataSource(dataSource, mediaSegmentKey, mediaSegmentIv);
// Init segment.
HlsMediaPlaylist.Segment initSegment = mediaSegment.initializationSegment;
DataSpec initDataSpec = null;
boolean initSegmentEncrypted = false;
@Nullable DataSource initDataSource = null;
if (initSegment != null) {
initSegmentEncrypted = initSegmentKey != null;
@Nullable byte[] initSegmentIv = initSegmentEncrypted ? getEncryptionIvArray(Assertions.checkNotNull(initSegment.encryptionIV)) : null;
Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
initDataSpec = new DataSpec(initSegmentUri, initSegment.byteRangeOffset, initSegment.byteRangeLength);
initDataSource = buildDataSource(dataSource, initSegmentKey, initSegmentIv);
}
long segmentStartTimeInPeriodUs = startOfPlaylistInPeriodUs + mediaSegment.relativeStartTimeUs;
long segmentEndTimeInPeriodUs = segmentStartTimeInPeriodUs + mediaSegment.durationUs;
int discontinuitySequenceNumber = mediaPlaylist.discontinuitySequence + mediaSegment.relativeDiscontinuitySequence;
@Nullable HlsMediaChunkExtractor previousExtractor = null;
Id3Decoder id3Decoder;
ParsableByteArray scratchId3Data;
if (previousChunk != null) {
boolean isSameInitData = initDataSpec == previousChunk.initDataSpec || (initDataSpec != null && previousChunk.initDataSpec != null && initDataSpec.uri.equals(previousChunk.initDataSpec.uri) && initDataSpec.position == previousChunk.initDataSpec.position);
boolean isFollowingChunk = playlistUrl.equals(previousChunk.playlistUrl) && previousChunk.loadCompleted;
id3Decoder = previousChunk.id3Decoder;
scratchId3Data = previousChunk.scratchId3Data;
previousExtractor = isSameInitData && isFollowingChunk && !previousChunk.extractorInvalidated && previousChunk.discontinuitySequenceNumber == discontinuitySequenceNumber ? previousChunk.extractor : null;
} else {
id3Decoder = new Id3Decoder();
scratchId3Data = new ParsableByteArray(Id3Decoder.ID3_HEADER_LENGTH);
}
return new HlsMediaChunk(extractorFactory, mediaDataSource, dataSpec, format, mediaSegmentEncrypted, initDataSource, initDataSpec, initSegmentEncrypted, playlistUrl, muxedCaptionFormats, trackSelectionReason, trackSelectionData, segmentStartTimeInPeriodUs, segmentEndTimeInPeriodUs, segmentBaseHolder.mediaSequence, segmentBaseHolder.partIndex, /* isPublished= */
!segmentBaseHolder.isPreload, discontinuitySequenceNumber, mediaSegment.hasGapTag, isMasterTimestampSource, /* timestampAdjuster= */
timestampAdjusterProvider.getAdjuster(discontinuitySequenceNumber), mediaSegment.drmInitData, previousExtractor, id3Decoder, scratchId3Data, shouldSpliceIn, playerId);
}
Aggregations