diff --git a/demo/assets/ic_launcher.svg b/demo/assets/ic_launcher.svg new file mode 100644 index 0000000000..5486b27e29 --- /dev/null +++ b/demo/assets/ic_launcher.svg @@ -0,0 +1,660 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/assets/ic_launcher.svg~ b/demo/assets/ic_launcher.svg~ new file mode 100644 index 0000000000..c01934f697 --- /dev/null +++ b/demo/assets/ic_launcher.svg~ @@ -0,0 +1,665 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index ee2f978324..ff3821f8fb 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -29,6 +29,7 @@ diff --git a/demo/src/main/res/drawable-hdpi/ic_launcher.png b/demo/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000..3e5716b8ad Binary files /dev/null and b/demo/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/demo/src/main/res/drawable-mdpi/ic_launcher.png b/demo/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000..a5d2a53b13 Binary files /dev/null and b/demo/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/demo/src/main/res/drawable-xhdpi/ic_launcher.png b/demo/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..1d00268635 Binary files /dev/null and b/demo/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/demo/src/main/res/drawable-xxhdpi/ic_launcher.png b/demo/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..ef2f312fd4 Binary files /dev/null and b/demo/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/demo/src/main/res/drawable-xxxhdpi/ic_launcher.png b/demo/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..0acebb43c1 Binary files /dev/null and b/demo/src/main/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/demo/src/main/res/layout/player_activity_full.xml b/demo/src/main/res/layout/player_activity_full.xml index d2e069620f..21fe68e5da 100644 --- a/demo/src/main/res/layout/player_activity_full.xml +++ b/demo/src/main/res/layout/player_activity_full.xml @@ -14,6 +14,7 @@ limitations under the License. --> + android:textSize="10sp" + tools:ignore="SmallSp"/> + android:textSize="10sp" + tools:ignore="SmallSp"/> (); this.rendererEnabledFlags = new boolean[rendererCount]; diff --git a/library/src/main/java/com/google/android/exoplayer/MediaFormat.java b/library/src/main/java/com/google/android/exoplayer/MediaFormat.java index 18f47bf8b0..5d1bf3945b 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaFormat.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaFormat.java @@ -164,7 +164,7 @@ public class MediaFormat { public int hashCode() { if (hashCode == 0) { int result = 17; - result = 31 * result + mimeType == null ? 0 : mimeType.hashCode(); + result = 31 * result + (mimeType == null ? 0 : mimeType.hashCode()); result = 31 * result + maxInputSize; result = 31 * result + width; result = 31 * result + height; diff --git a/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java b/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java index 2b109e79d3..52602e1483 100644 --- a/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java +++ b/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java @@ -310,8 +310,8 @@ public final class AudioTrack { // TODO: Does channelConfig determine channelCount? boolean isAc3 = encoding == AudioFormat.ENCODING_AC3 || encoding == AudioFormat.ENCODING_E_AC3; - if (audioTrack != null && this.sampleRate == sampleRate - && this.channelConfig == channelConfig && !this.isAc3 && !isAc3) { + if (isInitialized() && this.sampleRate == sampleRate && this.channelConfig == channelConfig + && !this.isAc3 && !isAc3) { // We already have an existing audio track with the correct sample rate and channel config. return; } @@ -450,7 +450,7 @@ public final class AudioTrack { /** Returns whether the audio track has more data pending that will be played back. */ public boolean hasPendingData() { - return audioTrack != null && bytesToFrames(submittedBytes) > getPlaybackPositionFrames(); + return isInitialized() && bytesToFrames(submittedBytes) > getPlaybackPositionFrames(); } /** Returns whether enough data has been supplied via {@link #handleBuffer} to begin playback. */ @@ -461,7 +461,7 @@ public final class AudioTrack { /** Sets the playback volume. */ public void setVolume(float volume) { this.volume = volume; - if (audioTrack != null) { + if (isInitialized()) { if (Util.SDK_INT >= 21) { setVolumeV21(audioTrack, volume); } else { @@ -482,7 +482,7 @@ public final class AudioTrack { /** Pauses playback. */ public void pause() { - if (audioTrack != null) { + if (isInitialized()) { resetSyncParams(); audioTrack.pause(); } @@ -494,7 +494,7 @@ public final class AudioTrack { * after resetting. */ public void reset() { - if (audioTrack != null) { + if (isInitialized()) { submittedBytes = 0; temporaryBufferSize = 0; lastRawPlaybackHeadPosition = 0; diff --git a/library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java b/library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java index 9a2341e904..36383dcea1 100644 --- a/library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java +++ b/library/src/main/java/com/google/android/exoplayer/parser/mp4/Atom.java @@ -80,9 +80,11 @@ import java.util.ArrayList; public final static class ContainerAtom extends Atom { public final ArrayList children; + public final int endByteOffset; - public ContainerAtom(int type) { + public ContainerAtom(int type, int endByteOffset) { super(type); + this.endByteOffset = endByteOffset; children = new ArrayList(); } diff --git a/library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java b/library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java index 52fe8a94a1..599d0b0eab 100644 --- a/library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java +++ b/library/src/main/java/com/google/android/exoplayer/parser/mp4/FragmentedMp4Extractor.java @@ -139,7 +139,6 @@ public final class FragmentedMp4Extractor implements Extractor { private final ParsableByteArray atomHeader; private final byte[] extendedTypeScratch; private final Stack containerAtoms; - private final Stack containerAtomEndPoints; private final TrackFragment fragmentRun; private int parserState; @@ -174,7 +173,6 @@ public final class FragmentedMp4Extractor implements Extractor { atomHeader = new ParsableByteArray(ATOM_HEADER_SIZE); extendedTypeScratch = new byte[16]; containerAtoms = new Stack(); - containerAtomEndPoints = new Stack(); fragmentRun = new TrackFragment(); psshData = new HashMap(); } @@ -258,7 +256,6 @@ public final class FragmentedMp4Extractor implements Extractor { } } containerAtoms.clear(); - containerAtomEndPoints.clear(); enterState(STATE_READING_ATOM_HEADER); return true; } @@ -267,7 +264,7 @@ public final class FragmentedMp4Extractor implements Extractor { switch (state) { case STATE_READING_ATOM_HEADER: atomBytesRead = 0; - if (containerAtomEndPoints.isEmpty()) { + if (containerAtoms.isEmpty()) { rootAtomBytesRead = 0; } break; @@ -300,11 +297,12 @@ public final class FragmentedMp4Extractor implements Extractor { return 0; } - if (PARSED_ATOMS.contains(atomType)) { - if (CONTAINER_TYPES.contains(atomType)) { + Integer atomTypeInteger = atomType; // Avoids boxing atomType twice. + if (PARSED_ATOMS.contains(atomTypeInteger)) { + if (CONTAINER_TYPES.contains(atomTypeInteger)) { enterState(STATE_READING_ATOM_HEADER); - containerAtoms.add(new ContainerAtom(atomType)); - containerAtomEndPoints.add(rootAtomBytesRead + atomSize - ATOM_HEADER_SIZE); + containerAtoms.add(new ContainerAtom(atomType, + rootAtomBytesRead + atomSize - ATOM_HEADER_SIZE)); } else { atomData = new ParsableByteArray(atomSize); System.arraycopy(atomHeader.data, 0, atomData.data, 0, ATOM_HEADER_SIZE); @@ -339,9 +337,7 @@ public final class FragmentedMp4Extractor implements Extractor { results |= onLeafAtomRead(new LeafAtom(atomType, atomData)); } - while (!containerAtomEndPoints.isEmpty() - && containerAtomEndPoints.peek() == rootAtomBytesRead) { - containerAtomEndPoints.pop(); + while (!containerAtoms.isEmpty() && containerAtoms.peek().endByteOffset == rootAtomBytesRead) { results |= onContainerAtomRead(containerAtoms.pop()); } diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java index 0bc36a0b8b..dfd7b9f3c1 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java @@ -343,8 +343,8 @@ public class SmoothStreamingChunkSource implements ChunkSource { TrackElement trackElement = streamElement.tracks[trackIndex]; String mimeType = trackElement.mimeType; if (streamElement.type == StreamElement.TYPE_VIDEO) { - MediaFormat format = MediaFormat.createVideoFormat(mimeType, -1, trackElement.maxWidth, - trackElement.maxHeight, Arrays.asList(trackElement.csd)); + MediaFormat format = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, + trackElement.maxWidth, trackElement.maxHeight, Arrays.asList(trackElement.csd)); format.setMaxVideoDimensions(streamElement.maxWidth, streamElement.maxHeight); return format; } else if (streamElement.type == StreamElement.TYPE_AUDIO) { @@ -355,8 +355,8 @@ public class SmoothStreamingChunkSource implements ChunkSource { csd = Collections.singletonList(CodecSpecificDataUtil.buildAudioSpecificConfig( trackElement.sampleRate, trackElement.numChannels)); } - MediaFormat format = MediaFormat.createAudioFormat(mimeType, -1, trackElement.numChannels, - trackElement.sampleRate, csd); + MediaFormat format = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, + trackElement.numChannels, trackElement.sampleRate, csd); return format; } else if (streamElement.type == StreamElement.TYPE_TEXT) { return MediaFormat.createFormatForMimeType(streamElement.tracks[trackIndex].mimeType); diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java index 7a6a32e44a..d7e6ee1358 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java @@ -273,7 +273,7 @@ public class SmoothStreamingManifest { Assertions.checkState(chunkIndex < chunkStartTimes.size()); String chunkUrl = chunkTemplate .replace(URL_PLACEHOLDER_BITRATE, Integer.toString(tracks[track].bitrate)) - .replace(URL_PLACEHOLDER_START_TIME, Long.toString(chunkStartTimes.get(chunkIndex))); + .replace(URL_PLACEHOLDER_START_TIME, chunkStartTimes.get(chunkIndex).toString()); return Util.getMergedUri(baseUri, chunkUrl); } diff --git a/library/src/main/java/com/google/android/exoplayer/text/SubtitleView.java b/library/src/main/java/com/google/android/exoplayer/text/SubtitleView.java index 7b2ecf5494..6ff3015afa 100644 --- a/library/src/main/java/com/google/android/exoplayer/text/SubtitleView.java +++ b/library/src/main/java/com/google/android/exoplayer/text/SubtitleView.java @@ -97,7 +97,7 @@ public class SubtitleView extends View { Resources resources = getContext().getResources(); DisplayMetrics displayMetrics = resources.getDisplayMetrics(); - int twoDpInPx = Math.round((2 * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT); + int twoDpInPx = Math.round((2f * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT); cornerRadius = twoDpInPx; outlineWidth = twoDpInPx; shadowRadius = twoDpInPx; diff --git a/library/src/main/java/com/google/android/exoplayer/upstream/NetworkLock.java b/library/src/main/java/com/google/android/exoplayer/upstream/NetworkLock.java index 26df7db5c4..2576fff1cd 100644 --- a/library/src/main/java/com/google/android/exoplayer/upstream/NetworkLock.java +++ b/library/src/main/java/com/google/android/exoplayer/upstream/NetworkLock.java @@ -53,10 +53,17 @@ public final class NetworkLock { */ public static final int DOWNLOAD_PRIORITY = 10; + private final Object lock = new Object(); + + /** Guarded by {@link #lock}. */ private final PriorityQueue queue; + /** Guarded by {@link #lock}. */ + private int highestPriority; + private NetworkLock() { queue = new PriorityQueue(); + highestPriority = Integer.MAX_VALUE; } /** @@ -64,9 +71,11 @@ public final class NetworkLock { * * @param priority The priority of the task that would like to proceed. */ - public synchronized void proceed(int priority) throws InterruptedException { - while (queue.peek() < priority) { - wait(); + public void proceed(int priority) throws InterruptedException { + synchronized (lock) { + while (highestPriority < priority) { + lock.wait(); + } } } @@ -76,8 +85,10 @@ public final class NetworkLock { * @param priority The priority of the task that would like to proceed. * @return Whether the passed priority is allowed to proceed. */ - public synchronized boolean proceedNonBlocking(int priority) { - return queue.peek() >= priority; + public boolean proceedNonBlocking(int priority) { + synchronized (lock) { + return highestPriority >= priority; + } } /** @@ -86,10 +97,11 @@ public final class NetworkLock { * @param priority The priority of the task that would like to proceed. * @throws PriorityTooLowException If the passed priority is not high enough to proceed. */ - public synchronized void proceedOrThrow(int priority) throws PriorityTooLowException { - int highestPriority = queue.peek(); - if (highestPriority < priority) { - throw new PriorityTooLowException(priority, highestPriority); + public void proceedOrThrow(int priority) throws PriorityTooLowException { + synchronized (lock) { + if (highestPriority < priority) { + throw new PriorityTooLowException(priority, highestPriority); + } } } @@ -100,8 +112,11 @@ public final class NetworkLock { * * @param priority The priority of the task. */ - public synchronized void add(int priority) { - queue.add(priority); + public void add(int priority) { + synchronized (lock) { + queue.add(priority); + highestPriority = Math.min(highestPriority, priority); + } } /** @@ -109,9 +124,12 @@ public final class NetworkLock { * * @param priority The priority of the task. */ - public synchronized void remove(int priority) { - queue.remove(priority); - notifyAll(); + public void remove(int priority) { + synchronized (lock) { + queue.remove(priority); + highestPriority = queue.isEmpty() ? Integer.MAX_VALUE : queue.peek(); + lock.notifyAll(); + } } } diff --git a/library/src/main/java/com/google/android/exoplayer/util/Util.java b/library/src/main/java/com/google/android/exoplayer/util/Util.java index 4d51fda9b0..ae2e014f0d 100644 --- a/library/src/main/java/com/google/android/exoplayer/util/Util.java +++ b/library/src/main/java/com/google/android/exoplayer/util/Util.java @@ -317,8 +317,8 @@ public final class Util { } else if (matcher.group(9).equalsIgnoreCase("Z")) { timezoneShift = 0; } else { - timezoneShift = ((Integer.valueOf(matcher.group(12)) * 60 - + Integer.valueOf(matcher.group(13)))); + timezoneShift = ((Integer.parseInt(matcher.group(12)) * 60 + + Integer.parseInt(matcher.group(13)))); if (matcher.group(11).equals("-")) { timezoneShift *= -1; } @@ -328,12 +328,12 @@ public final class Util { dateTime.clear(); // Note: The month value is 0-based, hence the -1 on group(2) - dateTime.set(Integer.valueOf(matcher.group(1)), - Integer.valueOf(matcher.group(2)) - 1, - Integer.valueOf(matcher.group(3)), - Integer.valueOf(matcher.group(4)), - Integer.valueOf(matcher.group(5)), - Integer.valueOf(matcher.group(6))); + dateTime.set(Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)) - 1, + Integer.parseInt(matcher.group(3)), + Integer.parseInt(matcher.group(4)), + Integer.parseInt(matcher.group(5)), + Integer.parseInt(matcher.group(6))); if (!TextUtils.isEmpty(matcher.group(8))) { final BigDecimal bd = new BigDecimal("0." + matcher.group(8)); // we care only for milliseconds, so movePointRight(3)