下面列出了android.media.MediaCrypto#com.google.android.exoplayer2.util.Util 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public int compareTo(PendingMessageInfo other) {
if ((resolvedPeriodUid == null) != (other.resolvedPeriodUid == null)) {
// PendingMessageInfos with a resolved period position are always smaller.
return resolvedPeriodUid != null ? -1 : 1;
}
if (resolvedPeriodUid == null) {
// Don't sort message with unresolved positions.
return 0;
}
// Sort resolved media times by period index and then by period position.
int comparePeriodIndex = resolvedPeriodIndex - other.resolvedPeriodIndex;
if (comparePeriodIndex != 0) {
return comparePeriodIndex;
}
return Util.compareLong(resolvedPeriodTimeUs, other.resolvedPeriodTimeUs);
}
@Override
protected List<SampleGroup> doInBackground(String... uris) {
List<SampleGroup> result = new ArrayList<>();
Context context = getApplicationContext();
String userAgent = Util.getUserAgent(context, "ExoPlayerDemo");
DataSource dataSource = new DefaultDataSource(context, null, userAgent, false);
for (String uri : uris) {
DataSpec dataSpec = new DataSpec(Uri.parse(uri));
InputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try {
readSampleGroups(new JsonReader(new InputStreamReader(inputStream, "UTF-8")), result);
} catch (Exception e) {
Log.e(TAG, "Error loading sample list: " + uri, e);
sawError = true;
} finally {
Util.closeQuietly(dataSource);
}
}
return result;
}
@Override
public int compareTo(@NonNull PendingMessageInfo other) {
if ((resolvedPeriodUid == null) != (other.resolvedPeriodUid == null)) {
// PendingMessageInfos with a resolved period position are always smaller.
return resolvedPeriodUid != null ? -1 : 1;
}
if (resolvedPeriodUid == null) {
// Don't sort message with unresolved positions.
return 0;
}
// Sort resolved media times by period index and then by period position.
int comparePeriodIndex = resolvedPeriodIndex - other.resolvedPeriodIndex;
if (comparePeriodIndex != 0) {
return comparePeriodIndex;
}
return Util.compareLong(resolvedPeriodTimeUs, other.resolvedPeriodTimeUs);
}
private void processOutputFormat(MediaCodec codec, int width, int height) {
currentWidth = width;
currentHeight = height;
currentPixelWidthHeightRatio = pendingPixelWidthHeightRatio;
if (Util.SDK_INT >= 21) {
// On API level 21 and above the decoder applies the rotation when rendering to the surface.
// Hence currentUnappliedRotation should always be 0. For 90 and 270 degree rotations, we need
// to flip the width, height and pixel aspect ratio to reflect the rotation that was applied.
if (pendingRotationDegrees == 90 || pendingRotationDegrees == 270) {
int rotatedHeight = currentWidth;
currentWidth = currentHeight;
currentHeight = rotatedHeight;
currentPixelWidthHeightRatio = 1 / currentPixelWidthHeightRatio;
}
} else {
// On API level 20 and below the decoder does not apply the rotation.
currentUnappliedRotationDegrees = pendingRotationDegrees;
}
// Must be applied each time the output format changes.
codec.setVideoScalingMode(scalingMode);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ChapterFrame other = (ChapterFrame) obj;
return startTimeMs == other.startTimeMs
&& endTimeMs == other.endTimeMs
&& startOffset == other.startOffset
&& endOffset == other.endOffset
&& Util.areEqual(chapterId, other.chapterId)
&& Arrays.equals(subFrames, other.subFrames);
}
private DefaultBandwidthMeter(
@Nullable Context context,
SparseArray<Long> initialBitrateEstimates,
int maxWeight,
Clock clock,
boolean resetOnNetworkTypeChange) {
this.context = context == null ? null : context.getApplicationContext();
this.initialBitrateEstimates = initialBitrateEstimates;
this.eventDispatcher = new EventDispatcher<>();
this.slidingPercentile = new SlidingPercentile(maxWeight);
this.clock = clock;
// Set the initial network type and bitrate estimate
networkType = context == null ? C.NETWORK_TYPE_UNKNOWN : Util.getNetworkType(context);
bitrateEstimate = getInitialBitrateEstimateForNetworkType(networkType);
// Register to receive connectivity actions if possible.
if (context != null && resetOnNetworkTypeChange) {
ConnectivityActionReceiver connectivityActionReceiver =
ConnectivityActionReceiver.getInstance(context);
connectivityActionReceiver.register(/* bandwidthMeter= */ this);
}
}
/**
* Sets the {@link AudioTrack} to wrap. Subsequent method calls on this instance relate to this
* track's position, until the next call to {@link #reset()}.
*
* @param audioTrack The audio track to wrap.
* @param outputEncoding The encoding of the audio track.
* @param outputPcmFrameSize For PCM output encodings, the frame size. The value is ignored
* otherwise.
* @param bufferSize The audio track buffer size in bytes.
*/
public void setAudioTrack(
AudioTrack audioTrack,
@C.Encoding int outputEncoding,
int outputPcmFrameSize,
int bufferSize) {
this.audioTrack = audioTrack;
this.outputPcmFrameSize = outputPcmFrameSize;
this.bufferSize = bufferSize;
audioTimestampPoller = new AudioTimestampPoller(audioTrack);
outputSampleRate = audioTrack.getSampleRate();
needsPassthroughWorkarounds = needsPassthroughWorkarounds(outputEncoding);
isOutputPcm = Util.isEncodingLinearPcm(outputEncoding);
bufferSizeUs = isOutputPcm ? framesToDurationUs(bufferSize / outputPcmFrameSize) : C.TIME_UNSET;
lastRawPlaybackHeadPosition = 0;
rawPlaybackHeadWrapCount = 0;
passthroughWorkaroundPauseOffset = 0;
hasData = false;
stopTimestampUs = C.TIME_UNSET;
forceResetWorkaroundTimeMs = C.TIME_UNSET;
latencyUs = 0;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
IcyHeaders other = (IcyHeaders) obj;
return bitrate == other.bitrate
&& Util.areEqual(genre, other.genre)
&& Util.areEqual(name, other.name)
&& Util.areEqual(url, other.url)
&& isPublic == other.isPublic
&& metadataInterval == other.metadataInterval;
}
/**
* Prepares exoplayer for audio playback from a remote URL audiofile. Should work with most
* popular audiofile types (.mp3, .m4a,...)
* @param uri Provide a Uri in a form of Uri.parse("http://blabla.bleble.com/blublu.mp3)
*/
private void prepareExoPlayerFromURL(Uri uri){
TrackSelector trackSelector = new DefaultTrackSelector();
LoadControl loadControl = new DefaultLoadControl();
exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "exoplayer2example"), null);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource audioSource = new ExtractorMediaSource(uri, dataSourceFactory, extractorsFactory, null, null);
exoPlayer.addListener(eventListener);
exoPlayer.prepare(audioSource);
initMediaControls();
}
@Override
public void setAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus) {
verifyApplicationThread();
if (!Util.areEqual(this.audioAttributes, audioAttributes)) {
this.audioAttributes = audioAttributes;
for (Renderer renderer : renderers) {
if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) {
player
.createMessage(renderer)
.setType(C.MSG_SET_AUDIO_ATTRIBUTES)
.setPayload(audioAttributes)
.send();
}
}
for (AudioListener audioListener : audioListeners) {
audioListener.onAudioAttributesChanged(audioAttributes);
}
}
@AudioFocusManager.PlayerCommand
int playerCommand =
audioFocusManager.setAudioAttributes(
handleAudioFocus ? audioAttributes : null, getPlayWhenReady(), getPlaybackState());
updatePlayWhenReady(getPlayWhenReady(), playerCommand);
}
/**
* Returns the framework {@link MediaFormat} that can be used to configure a {@link MediaCodec}
* for decoding the given {@link Format} for playback.
*
* @param format The format of the media.
* @param codecMimeType The MIME type handled by the codec.
* @param codecMaxInputSize The maximum input size supported by the codec.
* @param codecOperatingRate The codec operating rate, or {@link #CODEC_OPERATING_RATE_UNSET} if
* no codec operating rate should be set.
* @return The framework media format.
*/
@SuppressLint("InlinedApi")
protected MediaFormat getMediaFormat(
Format format, String codecMimeType, int codecMaxInputSize, float codecOperatingRate) {
MediaFormat mediaFormat = new MediaFormat();
// Set format parameters that should always be set.
mediaFormat.setString(MediaFormat.KEY_MIME, codecMimeType);
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, format.channelCount);
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, format.sampleRate);
MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
// Set codec max values.
MediaFormatUtil.maybeSetInteger(mediaFormat, MediaFormat.KEY_MAX_INPUT_SIZE, codecMaxInputSize);
// Set codec configuration values.
if (Util.SDK_INT >= 23) {
mediaFormat.setInteger(MediaFormat.KEY_PRIORITY, 0 /* realtime priority */);
if (codecOperatingRate != CODEC_OPERATING_RATE_UNSET && !deviceDoesntSupportOperatingRate()) {
mediaFormat.setFloat(MediaFormat.KEY_OPERATING_RATE, codecOperatingRate);
}
}
if (Util.SDK_INT <= 28 && MimeTypes.AUDIO_AC4.equals(format.sampleMimeType)) {
// On some older builds, the AC-4 decoder expects to receive samples formatted as raw frames
// not sync frames. Set a format key to override this.
mediaFormat.setInteger("ac4-is-sync", 1);
}
return mediaFormat;
}
private void parsePaletteSection(ParsableByteArray buffer, int sectionLength) {
if ((sectionLength % 5) != 2) {
// Section must be two bytes followed by a whole number of (index, y, cb, cr, a) entries.
return;
}
buffer.skipBytes(2);
Arrays.fill(colors, 0);
int entryCount = sectionLength / 5;
for (int i = 0; i < entryCount; i++) {
int index = buffer.readUnsignedByte();
int y = buffer.readUnsignedByte();
int cr = buffer.readUnsignedByte();
int cb = buffer.readUnsignedByte();
int a = buffer.readUnsignedByte();
int r = (int) (y + (1.40200 * (cr - 128)));
int g = (int) (y - (0.34414 * (cb - 128)) - (0.71414 * (cr - 128)));
int b = (int) (y + (1.77200 * (cb - 128)));
colors[index] =
(a << 24)
| (Util.constrainValue(r, 0, 255) << 16)
| (Util.constrainValue(g, 0, 255) << 8)
| Util.constrainValue(b, 0, 255);
}
colorsSet = true;
}
/**
* Parses the number of channels from the value attribute of an AudioElementConfiguration with
* schemeIdUri "tag:dolby.com,2014:dash:audio_channel_configuration:2011", as defined by table E.5
* in ETSI TS 102 366.
*
* @param xpp The parser from which to read.
* @return The parsed number of channels, or {@link Format#NO_VALUE} if the channel count could
* not be parsed.
*/
protected static int parseDolbyChannelConfiguration(XmlPullParser xpp) {
String value = Util.toLowerInvariant(xpp.getAttributeValue(null, "value"));
if (value == null) {
return Format.NO_VALUE;
}
switch (value) {
case "4000":
return 1;
case "a000":
return 2;
case "f801":
return 6;
case "fa01":
return 8;
default:
return Format.NO_VALUE;
}
}
/**
* Returns the extent to which a renderer supports adaptation between specified tracks within a
* {@link TrackGroup}.
*
* @param rendererIndex The renderer index.
* @param groupIndex The index of the track group.
* @return One of {@link RendererCapabilities#ADAPTIVE_SEAMLESS}, {@link
* RendererCapabilities#ADAPTIVE_NOT_SEAMLESS} and {@link
* RendererCapabilities#ADAPTIVE_NOT_SUPPORTED}.
*/
public int getAdaptiveSupport(int rendererIndex, int groupIndex, int[] trackIndices) {
int handledTrackCount = 0;
int adaptiveSupport = RendererCapabilities.ADAPTIVE_SEAMLESS;
boolean multipleMimeTypes = false;
String firstSampleMimeType = null;
for (int i = 0; i < trackIndices.length; i++) {
int trackIndex = trackIndices[i];
String sampleMimeType =
rendererTrackGroups[rendererIndex].get(groupIndex).getFormat(trackIndex).sampleMimeType;
if (handledTrackCount++ == 0) {
firstSampleMimeType = sampleMimeType;
} else {
multipleMimeTypes |= !Util.areEqual(firstSampleMimeType, sampleMimeType);
}
adaptiveSupport =
Math.min(
adaptiveSupport,
rendererFormatSupports[rendererIndex][groupIndex][i]
& RendererCapabilities.ADAPTIVE_SUPPORT_MASK);
}
return multipleMimeTypes
? Math.min(adaptiveSupport, rendererMixedMimeTypeAdaptiveSupports[rendererIndex])
: adaptiveSupport;
}
@GuardedBy("this")
private void removePublicMediaSources(
int fromIndex,
int toIndex,
@Nullable Handler handler,
@Nullable Runnable onCompletionAction) {
Assertions.checkArgument((handler == null) == (onCompletionAction == null));
Handler playbackThreadHandler = this.playbackThreadHandler;
Util.removeRange(mediaSourcesPublic, fromIndex, toIndex);
if (playbackThreadHandler != null) {
HandlerAndRunnable callbackAction = createOnCompletionAction(handler, onCompletionAction);
playbackThreadHandler
.obtainMessage(MSG_REMOVE, new MessageData<>(fromIndex, toIndex, callbackAction))
.sendToTarget();
} else if (onCompletionAction != null && handler != null) {
handler.post(onCompletionAction);
}
}
@Override
public void initPlayer() {
mInternalPlayer = new SimpleExoPlayer.Builder(
mAppContext,
mRenderersFactory == null ? mRenderersFactory = new DefaultRenderersFactory(mAppContext) : mRenderersFactory,
mTrackSelector == null ? mTrackSelector = new DefaultTrackSelector(mAppContext) : mTrackSelector,
mLoadControl == null ? mLoadControl = new DefaultLoadControl() : mLoadControl,
DefaultBandwidthMeter.getSingletonInstance(mAppContext),
Util.getLooper(),
new AnalyticsCollector(Clock.DEFAULT),
/* useLazyPreparation= */ true,
Clock.DEFAULT)
.build();
setOptions();
//播放器日志
if (VideoViewManager.getConfig().mIsEnableLog && mTrackSelector instanceof MappingTrackSelector) {
mInternalPlayer.addAnalyticsListener(new EventLogger((MappingTrackSelector) mTrackSelector, "ExoPlayer"));
}
mInternalPlayer.addListener(this);
mInternalPlayer.addVideoListener(this);
}
@Override
public void onPause() {
super.onPause();
if (Util.SDK_INT <= 23) {
releasePlayer();
}
}
/**
* Returns the tag name for the given tag contents.
*
* @param tagExpression Characters between &lt: and &gt; of a start or end tag.
* @return The name of tag.
*/
private static String getTagName(String tagExpression) {
tagExpression = tagExpression.trim();
if (tagExpression.isEmpty()) {
return null;
}
return Util.splitAtFirst(tagExpression, "[ \\.]")[0];
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(colorSpace);
dest.writeInt(colorRange);
dest.writeInt(colorTransfer);
Util.writeBoolean(dest, hdrStaticInfo != null);
if (hdrStaticInfo != null) {
dest.writeByteArray(hdrStaticInfo);
}
}
public void testWidevineH265Fixed() throws DecoderQueryException {
if (Util.SDK_INT < 23) {
// Pass.
return;
}
String streamName = "test_widevine_h265_fixed";
testDashPlayback(getActivity(), streamName, WIDEVINE_H265_MANIFEST_PREFIX,
WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, true, MimeTypes.VIDEO_H265, false,
WIDEVINE_H265_CDD_FIXED);
}
private static ApicFrame decodeApicFrame(ParsableByteArray id3Data, int frameSize,
int majorVersion) throws UnsupportedEncodingException {
int encoding = id3Data.readUnsignedByte();
String charset = getCharsetName(encoding);
byte[] data = new byte[frameSize - 1];
id3Data.readBytes(data, 0, frameSize - 1);
String mimeType;
int mimeTypeEndIndex;
if (majorVersion == 2) {
mimeTypeEndIndex = 2;
mimeType = "image/" + Util.toLowerInvariant(new String(data, 0, 3, "ISO-8859-1"));
if ("image/jpg".equals(mimeType)) {
mimeType = "image/jpeg";
}
} else {
mimeTypeEndIndex = indexOfZeroByte(data, 0);
mimeType = Util.toLowerInvariant(new String(data, 0, mimeTypeEndIndex, "ISO-8859-1"));
if (mimeType.indexOf('/') == -1) {
mimeType = "image/" + mimeType;
}
}
int pictureType = data[mimeTypeEndIndex + 1] & 0xFF;
int descriptionStartIndex = mimeTypeEndIndex + 2;
int descriptionEndIndex = indexOfEos(data, descriptionStartIndex, encoding);
String description = new String(data, descriptionStartIndex,
descriptionEndIndex - descriptionStartIndex, charset);
int pictureDataStartIndex = descriptionEndIndex + delimiterLength(encoding);
byte[] pictureData = copyOfRangeIfValid(data, pictureDataStartIndex, data.length);
return new ApicFrame(mimeType, description, pictureType, pictureData);
}
private ByteBuffer getInputBuffer(int inputIndex) {
if (Util.SDK_INT >= 21) {
return codec.getInputBuffer(inputIndex);
} else {
return inputBuffers[inputIndex];
}
}
public void testWidevine24FpsH264Fixed() throws DecoderQueryException {
if (Util.SDK_INT < 23) {
// Pass.
return;
}
String streamName = "test_widevine_24fps_h264_fixed";
testDashPlayback(getActivity(), streamName, WIDEVINE_H264_24_MANIFEST_PREFIX,
WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, true, MimeTypes.VIDEO_H264, false,
WIDEVINE_H264_BASELINE_480P_24FPS_VIDEO_REPRESENTATION_ID);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
IcyInfo other = (IcyInfo) obj;
// title & url are derived from rawMetadata, so no need to include them in the comparison.
return Util.areEqual(rawMetadata, other.rawMetadata);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ApicFrame other = (ApicFrame) obj;
return pictureType == other.pictureType && Util.areEqual(mimeType, other.mimeType)
&& Util.areEqual(description, other.description)
&& Arrays.equals(pictureData, other.pictureData);
}
@TargetApi(21)
private static Point alignVideoSizeV21(VideoCapabilities capabilities, int width, int height) {
int widthAlignment = capabilities.getWidthAlignment();
int heightAlignment = capabilities.getHeightAlignment();
return new Point(
Util.ceilDivide(width, widthAlignment) * widthAlignment,
Util.ceilDivide(height, heightAlignment) * heightAlignment);
}
/**
* Returns the media sequence number of the segment to load next in {@code mediaPlaylist}.
*
* @param previous The last (at least partially) loaded segment.
* @param switchingTrack Whether the segment to load is not preceded by a segment in the same
* track.
* @param mediaPlaylist The media playlist to which the segment to load belongs.
* @param startOfPlaylistInPeriodUs The start of {@code mediaPlaylist} relative to the period
* start in microseconds.
* @param loadPositionUs The current load position relative to the period start in microseconds.
* @return The media sequence of the segment to load.
*/
private long getChunkMediaSequence(
@Nullable HlsMediaChunk previous,
boolean switchingTrack,
HlsMediaPlaylist mediaPlaylist,
long startOfPlaylistInPeriodUs,
long loadPositionUs) {
if (previous == null || switchingTrack) {
long endOfPlaylistInPeriodUs = startOfPlaylistInPeriodUs + mediaPlaylist.durationUs;
long targetPositionInPeriodUs =
(previous == null || independentSegments) ? loadPositionUs : previous.startTimeUs;
if (!mediaPlaylist.hasEndTag && targetPositionInPeriodUs >= endOfPlaylistInPeriodUs) {
// If the playlist is too old to contain the chunk, we need to refresh it.
return mediaPlaylist.mediaSequence + mediaPlaylist.segments.size();
}
long targetPositionInPlaylistUs = targetPositionInPeriodUs - startOfPlaylistInPeriodUs;
return Util.binarySearchFloor(
mediaPlaylist.segments,
/* value= */ targetPositionInPlaylistUs,
/* inclusive= */ true,
/* stayInBounds= */ !playlistTracker.isLive() || previous == null)
+ mediaPlaylist.mediaSequence;
}
// We ignore the case of previous not having loaded completely, in which case we load the next
// segment.
return previous.getNextChunkIndex();
}
/**
* Seeks to the specified position in microseconds.
*
* @param positionUs The seek position in microseconds.
*/
public void seekToUs(long positionUs) {
currentIndex =
Util.binarySearchCeil(
eventTimesUs, positionUs, /* inclusive= */ true, /* stayInBounds= */ false);
boolean isPendingSeek = eventStreamAppendable && currentIndex == eventTimesUs.length;
pendingSeekPositionUs = isPendingSeek ? positionUs : C.TIME_UNSET;
}
@SuppressWarnings("NonAtomicVolatileUpdate")
@Override
public final void load() throws IOException, InterruptedException {
DataSpec loadDataSpec = dataSpec.subrange(nextLoadPosition);
try {
// Create and open the input.
ExtractorInput input = new DefaultExtractorInput(dataSource,
loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
if (nextLoadPosition == 0) {
// Configure the output and set it as the target for the extractor wrapper.
BaseMediaChunkOutput output = getOutput();
output.setSampleOffsetUs(sampleOffsetUs);
extractorWrapper.init(
getTrackOutputProvider(output),
clippedStartTimeUs == C.TIME_UNSET
? C.TIME_UNSET
: (clippedStartTimeUs - sampleOffsetUs),
clippedEndTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedEndTimeUs - sampleOffsetUs));
}
// Load and decode the sample data.
try {
Extractor extractor = extractorWrapper.extractor;
int result = Extractor.RESULT_CONTINUE;
while (result == Extractor.RESULT_CONTINUE && !loadCanceled) {
result = extractor.read(input, DUMMY_POSITION_HOLDER);
}
Assertions.checkState(result != Extractor.RESULT_SEEK);
} finally {
nextLoadPosition = input.getPosition() - dataSpec.absoluteStreamPosition;
}
} finally {
Util.closeQuietly(dataSource);
}
loadCompleted = true;
}
@Override
public boolean shouldStartPlayback(
long bufferedDurationUs, float playbackSpeed, boolean rebuffering) {
bufferedDurationUs = Util.getPlayoutDurationForMediaDuration(bufferedDurationUs, playbackSpeed);
long minBufferDurationUs = rebuffering ? bufferForPlaybackAfterRebufferUs : bufferForPlaybackUs;
return minBufferDurationUs <= 0
|| bufferedDurationUs >= minBufferDurationUs
|| (!prioritizeTimeOverSizeThresholds
&& allocator.getTotalBytesAllocated() >= targetBufferSize);
}