Commit 71186ef1 by cblay Committed by Oliver Woodman

Improving handling of atoms with size less than header in FragmentedMp4Extractor.

These currently lead to cryptic ArrayIndexOutOfBoundsExceptions being thrown from System.arraycopy() so my proposal is to throw a more useful ParserException instead.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=142087132
parent da9c10a1
Showing with 86 additions and 314 deletions
# Release notes #
### r2.1.1 ###
Bugfix release only. Users of r2.1.0 and r2.0.x should proactively update to
this version.
* Fix some subtitle types (e.g. WebVTT) being displayed out of sync
([#2208](https://github.com/google/ExoPlayer/issues/2208)).
* Fix incorrect position reporting for on-demand HLS media that includes
EXT-X-PROGRAM-DATE-TIME tags
([#2224](https://github.com/google/ExoPlayer/issues/2224)).
* Fix issue where playbacks could get stuck in the initial buffering state if
over 1MB of data needs to be read to initialize the playback.
### r2.1.0 ###
This release contains important bug fixes. Users of r2.0.x should proactively
update to this version.
* HLS: Support for seeking in live streams
([#87](https://github.com/google/ExoPlayer/issues/87)).
* HLS: Improved support:
......
......@@ -35,7 +35,7 @@ allprojects {
releaseRepoName = 'exoplayer'
releaseUserOrg = 'google'
releaseGroupId = 'com.google.android.exoplayer'
releaseVersion = 'r2.1.1'
releaseVersion = 'r2.1.0'
releaseWebsite = 'https://github.com/google/ExoPlayer'
}
}
......@@ -16,8 +16,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.exoplayer2.demo"
android:versionCode="2101"
android:versionName="2.1.1">
android:versionCode="2100"
android:versionName="2.1.0">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
......
......@@ -183,54 +183,30 @@
"uri": "https://storage.googleapis.com/wvmedia/clear/vp9/tears/tears_uhd.mpd"
},
{
"name": "WV: Secure Fullsample SD & HD (WebM,VP9)",
"name": "WV: Secure SD & HD (WebM,VP9)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure Fullsample SD (WebM,VP9)",
"name": "WV: Secure SD (WebM,VP9)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears_sd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure Fullsample HD (WebM,VP9)",
"name": "WV: Secure HD (WebM,VP9)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears_hd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure Fullsample UHD (WebM,VP9)",
"name": "WV: Secure UHD (WebM,VP9)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/tears/tears_uhd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure Subsample SD & HD (WebM,VP9)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/subsample/24fps/tears/tears.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure Subsample SD (WebM,VP9)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/subsample/24fps/tears/tears_sd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure Subsample HD (WebM,VP9)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/subsample/24fps/tears/tears_hd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure Subsample UHD (WebM,VP9)",
"uri": "https://storage.googleapis.com/wvmedia/cenc/vp9/subsample/24fps/tears/tears_uhd.mpd",
"drm_scheme": "widevine",
"drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
},
{
"name": "WV: Secure Subsample (WebM, VP9 with altref)",
"uri": "https://storage.googleapis.com/widevine_test/vp9/sintel_1080p_vp9_altref_subsample/sintel_1080p_vp9_altref_subsample.mpd",
"drm_scheme": "widevine",
......
......@@ -31,7 +31,6 @@ import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
......@@ -49,25 +48,12 @@ public final class ExoPlayerTest extends TestCase {
*/
private static final int TIMEOUT_MS = 10000;
/**
* Tests playback of a source that exposes a single period.
*/
public void testPlayToEnd() throws Exception {
PlayerWrapper playerWrapper = new PlayerWrapper();
Format format = Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H264, null,
Format.NO_VALUE, Format.NO_VALUE, 1280, 720, Format.NO_VALUE, null, null);
playerWrapper.setup(new SinglePeriodTimeline(0, false), null, format);
playerWrapper.blockUntilEnded(TIMEOUT_MS);
}
/**
* Tests playback of a source that exposes an empty timeline. Playback is expected to end without
* error.
*/
public void testPlayEmptyTimeline() throws Exception {
PlayerWrapper playerWrapper = new PlayerWrapper();
playerWrapper.setup(Timeline.EMPTY, null, null);
playerWrapper.blockUntilEnded(TIMEOUT_MS);
playerWrapper.setup(new SinglePeriodTimeline(0, false), new Object(), format);
playerWrapper.blockUntilEndedOrError(TIMEOUT_MS);
}
/**
......@@ -84,6 +70,7 @@ public final class ExoPlayerTest extends TestCase {
private Format expectedFormat;
private ExoPlayer player;
private Exception exception;
private boolean seenPositionDiscontinuity;
public PlayerWrapper() {
endedCountDownLatch = new CountDownLatch(1);
......@@ -94,11 +81,12 @@ public final class ExoPlayerTest extends TestCase {
// Called on the test thread.
public void blockUntilEnded(long timeoutMs) throws Exception {
public void blockUntilEndedOrError(long timeoutMs) throws Exception {
if (!endedCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
exception = new TimeoutException("Test playback timed out.");
}
release();
// Throw any pending exception (from playback, timing out or releasing).
if (exception != null) {
throw exception;
......@@ -120,7 +108,7 @@ public final class ExoPlayerTest extends TestCase {
player.setPlayWhenReady(true);
player.prepare(new FakeMediaSource(timeline, manifest, format));
} catch (Exception e) {
handleError(e);
handlePlayerException(e);
}
}
});
......@@ -135,7 +123,7 @@ public final class ExoPlayerTest extends TestCase {
player.release();
}
} catch (Exception e) {
handleError(e);
handlePlayerException(e);
} finally {
playerThread.quit();
}
......@@ -144,7 +132,7 @@ public final class ExoPlayerTest extends TestCase {
playerThread.join();
}
private void handleError(Exception exception) {
private void handlePlayerException(Exception exception) {
if (this.exception == null) {
this.exception = exception;
}
......@@ -179,13 +167,20 @@ public final class ExoPlayerTest extends TestCase {
@Override
public void onPlayerError(ExoPlaybackException exception) {
handleError(exception);
this.exception = exception;
endedCountDownLatch.countDown();
}
@Override
public void onPositionDiscontinuity() {
// Should never happen.
handleError(new IllegalStateException("Received position discontinuity"));
assertFalse(seenPositionDiscontinuity);
assertEquals(0, player.getCurrentWindowIndex());
assertEquals(0, player.getCurrentPeriodIndex());
assertEquals(0, player.getCurrentPosition());
assertEquals(0, player.getBufferedPosition());
assertEquals(expectedTimeline, player.getCurrentTimeline());
assertEquals(expectedManifest, player.getCurrentManifest());
seenPositionDiscontinuity = true;
}
}
......@@ -199,16 +194,17 @@ public final class ExoPlayerTest extends TestCase {
private final Timeline timeline;
private final Object manifest;
private final Format format;
private final ArrayList<FakeMediaPeriod> activeMediaPeriods;
private FakeMediaPeriod mediaPeriod;
private boolean preparedSource;
private boolean releasedPeriod;
private boolean releasedSource;
public FakeMediaSource(Timeline timeline, Object manifest, Format format) {
Assertions.checkArgument(timeline.getPeriodCount() == 1);
this.timeline = timeline;
this.manifest = manifest;
this.format = format;
activeMediaPeriods = new ArrayList<>();
}
@Override
......@@ -225,29 +221,33 @@ public final class ExoPlayerTest extends TestCase {
@Override
public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) {
Assertions.checkIndex(index, 0, timeline.getPeriodCount());
assertTrue(preparedSource);
assertNull(mediaPeriod);
assertFalse(releasedPeriod);
assertFalse(releasedSource);
assertEquals(0, index);
assertEquals(0, positionUs);
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(format);
activeMediaPeriods.add(mediaPeriod);
mediaPeriod = new FakeMediaPeriod(format);
return mediaPeriod;
}
@Override
public void releasePeriod(MediaPeriod mediaPeriod) {
assertTrue(preparedSource);
assertNotNull(this.mediaPeriod);
assertFalse(releasedPeriod);
assertFalse(releasedSource);
assertTrue(activeMediaPeriods.remove(mediaPeriod));
((FakeMediaPeriod) mediaPeriod).release();
assertEquals(this.mediaPeriod, mediaPeriod);
this.mediaPeriod.release();
releasedPeriod = true;
}
@Override
public void releaseSource() {
assertTrue(preparedSource);
assertNotNull(this.mediaPeriod);
assertTrue(releasedPeriod);
assertFalse(releasedSource);
assertTrue(activeMediaPeriods.isEmpty());
releasedSource = true;
}
......@@ -400,6 +400,7 @@ public final class ExoPlayerTest extends TestCase {
public FakeVideoRenderer(Format expectedFormat) {
super(C.TRACK_TYPE_VIDEO);
Assertions.checkArgument(MimeTypes.isVideo(expectedFormat.sampleMimeType));
this.expectedFormat = expectedFormat;
}
......
......@@ -267,12 +267,6 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
return streamIsFinal ? C.RESULT_BUFFER_READ : C.RESULT_NOTHING_READ;
}
buffer.timeUs += streamOffsetUs;
} else if (result == C.RESULT_FORMAT_READ) {
Format format = formatHolder.format;
if (format.subsampleOffsetUs != Format.OFFSET_SAMPLE_RELATIVE) {
format = format.copyWithSubsampleOffsetUs(format.subsampleOffsetUs + streamOffsetUs);
formatHolder.format = format;
}
}
return result;
}
......
......@@ -97,13 +97,6 @@ public final class C {
public static final int CRYPTO_MODE_AES_CBC = MediaCodec.CRYPTO_MODE_AES_CBC;
/**
* Represents an unset {@link android.media.AudioTrack} session identifier. Equal to
* {@link AudioManager#AUDIO_SESSION_ID_GENERATE}.
*/
@SuppressWarnings("InlinedApi")
public static final int AUDIO_SESSION_ID_UNSET = AudioManager.AUDIO_SESSION_ID_GENERATE;
/**
* Represents an audio encoding, or an invalid or unset value.
*/
@Retention(RetentionPolicy.SOURCE)
......
......@@ -332,10 +332,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
case ExoPlayerImplInternal.MSG_SEEK_ACK: {
if (--pendingSeekAcks == 0) {
playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj;
if (msg.arg1 != 0) {
for (EventListener listener : listeners) {
listener.onPositionDiscontinuity();
}
for (EventListener listener : listeners) {
listener.onPositionDiscontinuity();
}
}
break;
......
......@@ -559,7 +559,7 @@ import java.io.IOException;
// The seek position was valid for the timeline that it was performed into, but the
// timeline has changed and a suitable seek position could not be resolved in the new one.
playbackInfo = new PlaybackInfo(0, 0);
eventHandler.obtainMessage(MSG_SEEK_ACK, 1, 0, playbackInfo).sendToTarget();
eventHandler.obtainMessage(MSG_SEEK_ACK, playbackInfo).sendToTarget();
// Set the internal position to (0,TIME_UNSET) so that a subsequent seek to (0,0) isn't
// ignored.
playbackInfo = new PlaybackInfo(0, C.TIME_UNSET);
......@@ -569,7 +569,6 @@ import java.io.IOException;
return;
}
boolean seekPositionAdjusted = seekPosition.windowPositionUs == C.TIME_UNSET;
int periodIndex = periodPosition.first;
long periodPositionUs = periodPosition.second;
......@@ -579,13 +578,10 @@ import java.io.IOException;
// Seek position equals the current position. Do nothing.
return;
}
long newPeriodPositionUs = seekToPeriodPosition(periodIndex, periodPositionUs);
seekPositionAdjusted |= periodPositionUs != newPeriodPositionUs;
periodPositionUs = newPeriodPositionUs;
periodPositionUs = seekToPeriodPosition(periodIndex, periodPositionUs);
} finally {
playbackInfo = new PlaybackInfo(periodIndex, periodPositionUs);
eventHandler.obtainMessage(MSG_SEEK_ACK, seekPositionAdjusted ? 1 : 0, 0, playbackInfo)
.sendToTarget();
eventHandler.obtainMessage(MSG_SEEK_ACK, playbackInfo).sendToTarget();
}
}
......@@ -680,7 +676,6 @@ import java.io.IOException;
standaloneMediaClock.stop();
rendererMediaClock = null;
rendererMediaClockSource = null;
rendererPositionUs = RENDERER_TIMESTAMP_OFFSET_US;
for (Renderer renderer : enabledRenderers) {
try {
ensureStopped(renderer);
......@@ -828,6 +823,9 @@ import java.io.IOException;
}
private boolean haveSufficientBuffer(boolean rebuffering) {
if (loadingPeriodHolder == null) {
return false;
}
long loadingPeriodBufferedPositionUs = !loadingPeriodHolder.prepared
? loadingPeriodHolder.startPositionUs
: loadingPeriodHolder.mediaPeriod.getBufferedPositionUs();
......@@ -1289,8 +1287,7 @@ import java.io.IOException;
}
private void maybeContinueLoading() {
long nextLoadPositionUs = !loadingPeriodHolder.prepared ? 0
: loadingPeriodHolder.mediaPeriod.getNextLoadPositionUs();
long nextLoadPositionUs = loadingPeriodHolder.mediaPeriod.getNextLoadPositionUs();
if (nextLoadPositionUs == C.TIME_END_OF_SOURCE) {
setIsLoading(false);
} else {
......
......@@ -23,7 +23,7 @@ public interface ExoPlayerLibraryInfo {
/**
* The version of the library, expressed as a string.
*/
String VERSION = "2.1.1";
String VERSION = "2.1.0";
/**
* The version of the library, expressed as an integer.
......@@ -32,7 +32,7 @@ public interface ExoPlayerLibraryInfo {
* corresponding integer version 1002003 (001-002-003), and "123.45.6" has the corresponding
* integer version 123045006 (123-045-006).
*/
int VERSION_INT = 2001001;
int VERSION_INT = 2001000;
/**
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
......
......@@ -29,6 +29,7 @@ import android.view.SurfaceView;
import android.view.TextureView;
import com.google.android.exoplayer2.audio.AudioCapabilities;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.audio.AudioTrack;
import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DrmSessionManager;
......@@ -177,7 +178,7 @@ public class SimpleExoPlayer implements ExoPlayer {
// Set initial values.
audioVolume = 1;
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
audioStreamType = C.STREAM_TYPE_DEFAULT;
videoScalingMode = C.VIDEO_SCALING_MODE_DEFAULT;
......@@ -392,7 +393,7 @@ public class SimpleExoPlayer implements ExoPlayer {
}
/**
* Returns the audio session identifier, or {@link C#AUDIO_SESSION_ID_UNSET} if not set.
* Returns the audio session identifier, or {@code AudioTrack.SESSION_ID_NOT_SET} if not set.
*/
public int getAudioSessionId() {
return audioSessionId;
......@@ -948,7 +949,7 @@ public class SimpleExoPlayer implements ExoPlayer {
}
audioFormat = null;
audioDecoderCounters = null;
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
}
// TextRenderer.Output implementation
......
......@@ -129,7 +129,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
boolean playClearSamplesWithoutKeys, Handler eventHandler,
AudioRendererEventListener eventListener, AudioCapabilities audioCapabilities) {
super(C.TRACK_TYPE_AUDIO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys);
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
audioTrack = new AudioTrack(audioCapabilities, this);
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
}
......@@ -274,7 +274,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override
protected void onDisabled() {
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
try {
audioTrack.release();
} finally {
......@@ -328,8 +328,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
if (!audioTrack.isInitialized()) {
// Initialize the AudioTrack now.
try {
if (audioSessionId == C.AUDIO_SESSION_ID_UNSET) {
audioSessionId = audioTrack.initialize(C.AUDIO_SESSION_ID_UNSET);
if (audioSessionId == AudioTrack.SESSION_ID_NOT_SET) {
audioSessionId = audioTrack.initialize(AudioTrack.SESSION_ID_NOT_SET);
eventDispatcher.audioSessionId(audioSessionId);
onAudioSessionId(audioSessionId);
} else {
......@@ -387,7 +387,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
case C.MSG_SET_STREAM_TYPE:
@C.StreamType int streamType = (Integer) message;
if (audioTrack.setStreamType(streamType)) {
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
}
break;
default:
......
......@@ -145,7 +145,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
this.drmSessionManager = drmSessionManager;
formatHolder = new FormatHolder();
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
audioTrackNeedsConfigure = true;
}
......@@ -245,8 +245,8 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
}
if (!audioTrack.isInitialized()) {
if (audioSessionId == C.AUDIO_SESSION_ID_UNSET) {
audioSessionId = audioTrack.initialize(C.AUDIO_SESSION_ID_UNSET);
if (audioSessionId == AudioTrack.SESSION_ID_NOT_SET) {
audioSessionId = audioTrack.initialize(AudioTrack.SESSION_ID_NOT_SET);
eventDispatcher.audioSessionId(audioSessionId);
onAudioSessionId(audioSessionId);
} else {
......@@ -425,7 +425,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
@Override
protected void onDisabled() {
inputFormat = null;
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
audioTrackNeedsConfigure = true;
waitingForKeys = false;
try {
......@@ -554,7 +554,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
case C.MSG_SET_STREAM_TYPE:
@C.StreamType int streamType = (Integer) message;
if (audioTrack.setStreamType(streamType)) {
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
}
break;
default:
......
......@@ -244,7 +244,7 @@ import java.io.IOException;
@Override
public long getNextLoadPositionUs() {
return enabledTrackCount == 0 ? C.TIME_END_OF_SOURCE : getBufferedPositionUs();
return getBufferedPositionUs();
}
@Override
......
......@@ -133,32 +133,4 @@ public interface MediaPeriod extends SequenceableLoader {
*/
long seekToUs(long positionUs);
// SequenceableLoader interface. Overridden to provide more specific documentation.
/**
* Returns the next load time, or {@link C#TIME_END_OF_SOURCE} if loading has finished.
* <p>
* This method should only be called after the period has been prepared. It may be called when no
* tracks are selected.
*/
@Override
long getNextLoadPositionUs();
/**
* Attempts to continue loading.
* <p>
* This method may be called both during and after the period has been prepared.
* <p>
* A period may call {@link Callback#onContinueLoadingRequested(SequenceableLoader)} on the
* {@link Callback} passed to {@link #prepare(Callback)} to request that this method be called
* when the period is permitted to continue loading data. A period may do this both during and
* after preparation.
*
* @param positionUs The current playback position.
* @return True if progress was made, meaning that {@link #getNextLoadPositionUs()} will return
* a different value than prior to the call. False otherwise.
*/
@Override
boolean continueLoading(long positionUs);
}
......@@ -104,14 +104,15 @@ public final class HlsMediaSource implements MediaSource,
SinglePeriodTimeline timeline;
if (playlistTracker.isLive()) {
// TODO: fix windowPositionInPeriodUs when playlist is empty.
long windowPositionInPeriodUs = playlist.startTimeUs;
List<HlsMediaPlaylist.Segment> segments = playlist.segments;
long windowDefaultStartPositionUs = segments.isEmpty() ? 0
: segments.get(Math.max(0, segments.size() - 3)).relativeStartTimeUs;
timeline = new SinglePeriodTimeline(C.TIME_UNSET, playlist.durationUs,
playlist.startTimeUs, windowDefaultStartPositionUs, true, !playlist.hasEndTag);
windowPositionInPeriodUs, windowDefaultStartPositionUs, true, !playlist.hasEndTag);
} else /* not live */ {
timeline = new SinglePeriodTimeline(playlist.startTimeUs + playlist.durationUs,
playlist.durationUs, playlist.startTimeUs, 0, true, false);
timeline = new SinglePeriodTimeline(playlist.durationUs, playlist.durationUs, 0, 0, true,
false);
}
sourceListener.onSourceInfoRefreshed(timeline, playlist);
}
......
......@@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer2.text;
import android.graphics.Color;
import android.support.annotation.IntDef;
import android.text.Layout.Alignment;
import java.lang.annotation.Retention;
......@@ -37,23 +36,19 @@ public class Cue {
@Retention(RetentionPolicy.SOURCE)
@IntDef({TYPE_UNSET, ANCHOR_TYPE_START, ANCHOR_TYPE_MIDDLE, ANCHOR_TYPE_END})
public @interface AnchorType {}
/**
* An unset anchor or line type value.
*/
public static final int TYPE_UNSET = Integer.MIN_VALUE;
/**
* Anchors the left (for horizontal positions) or top (for vertical positions) edge of the cue
* box.
*/
public static final int ANCHOR_TYPE_START = 0;
/**
* Anchors the middle of the cue box.
*/
public static final int ANCHOR_TYPE_MIDDLE = 1;
/**
* Anchors the right (for horizontal positions) or bottom (for vertical positions) edge of the cue
* box.
......@@ -66,12 +61,10 @@ public class Cue {
@Retention(RetentionPolicy.SOURCE)
@IntDef({TYPE_UNSET, LINE_TYPE_FRACTION, LINE_TYPE_NUMBER})
public @interface LineType {}
/**
* Value for {@link #lineType} when {@link #line} is a fractional position.
*/
public static final int LINE_TYPE_FRACTION = 0;
/**
* Value for {@link #lineType} when {@link #line} is a line number.
*/
......@@ -81,12 +74,10 @@ public class Cue {
* The cue text. Note the {@link CharSequence} may be decorated with styling spans.
*/
public final CharSequence text;
/**
* The alignment of the cue text within the cue box, or null if the alignment is undefined.
*/
public final Alignment textAlignment;
/**
* The position of the {@link #lineAnchor} of the cue box within the viewport in the direction
* orthogonal to the writing direction, or {@link #DIMEN_UNSET}. When set, the interpretation of
......@@ -95,7 +86,6 @@ public class Cue {
* For horizontal text and {@link #lineType} equal to {@link #LINE_TYPE_FRACTION}, this is the
* fractional vertical position relative to the top of the viewport.
*/
public final float line;
/**
* The type of the {@link #line} value.
......@@ -122,7 +112,6 @@ public class Cue {
* {@code (line == -2 && lineAnchor == ANCHOR_TYPE_START)} position a cue so that only its first
* line is visible at the bottom of the viewport.
*/
@LineType
public final int lineType;
/**
......@@ -133,7 +122,6 @@ public class Cue {
* and {@link #ANCHOR_TYPE_END} correspond to the top, middle and bottom of the cue box
* respectively.
*/
@AnchorType
public final int lineAnchor;
/**
......@@ -145,7 +133,6 @@ public class Cue {
* text.
*/
public final float position;
/**
* The cue box anchor positioned by {@link #position}. One of {@link #ANCHOR_TYPE_START},
* {@link #ANCHOR_TYPE_MIDDLE}, {@link #ANCHOR_TYPE_END} and {@link #TYPE_UNSET}.
......@@ -156,7 +143,6 @@ public class Cue {
*/
@AnchorType
public final int positionAnchor;
/**
* The size of the cue box in the writing direction specified as a fraction of the viewport size
* in that direction, or {@link #DIMEN_UNSET}.
......@@ -164,16 +150,6 @@ public class Cue {
public final float size;
/**
* Specifies whether or not the {@link #windowColor} property is set.
*/
public final boolean windowColorSet;
/**
* The fill color of the window.
*/
public final int windowColor;
/**
* Constructs a cue whose {@link #textAlignment} is null, whose type parameters are set to
* {@link #TYPE_UNSET} and whose dimension parameters are set to {@link #DIMEN_UNSET}.
*
......@@ -195,25 +171,6 @@ public class Cue {
*/
public Cue(CharSequence text, Alignment textAlignment, float line, @LineType int lineType,
@AnchorType int lineAnchor, float position, @AnchorType int positionAnchor, float size) {
this(text, textAlignment, line, lineType, lineAnchor, position, positionAnchor, size, false,
Color.BLACK);
}
/**
* @param text See {@link #text}.
* @param textAlignment See {@link #textAlignment}.
* @param line See {@link #line}.
* @param lineType See {@link #lineType}.
* @param lineAnchor See {@link #lineAnchor}.
* @param position See {@link #position}.
* @param positionAnchor See {@link #positionAnchor}.
* @param size See {@link #size}.
* @param windowColorSet See {@link #windowColorSet}.
* @param windowColor See {@link #windowColor}.
*/
public Cue(CharSequence text, Alignment textAlignment, float line, @LineType int lineType,
@AnchorType int lineAnchor, float position, @AnchorType int positionAnchor, float size,
boolean windowColorSet, int windowColor) {
this.text = text;
this.textAlignment = textAlignment;
this.line = line;
......@@ -222,8 +179,6 @@ public class Cue {
this.position = position;
this.positionAnchor = positionAnchor;
this.size = size;
this.windowColorSet = windowColorSet;
this.windowColor = windowColor;
}
}
......@@ -65,13 +65,6 @@ import java.util.List;
* <li>Default: {@code true}</li>
* </ul>
* </li>
* <li><b>{@code default_artwork}</b> - Default artwork to use if no artwork available in audio
* streams.
* <ul>
* <li>Corresponding method: {@link #setDefaultArtwork(Bitmap)}</li>
* <li>Default: {@code null}</li>
* </ul>
* </li>
* <li><b>{@code use_controller}</b> - Whether playback controls are displayed.
* <ul>
* <li>Corresponding method: {@link #setUseController(boolean)}</li>
......@@ -186,7 +179,6 @@ public final class SimpleExoPlayerView extends FrameLayout {
private SimpleExoPlayer player;
private boolean useController;
private boolean useArtwork;
private Bitmap defaultArtwork;
private int controllerShowTimeoutMs;
public SimpleExoPlayerView(Context context) {
......@@ -202,7 +194,6 @@ public final class SimpleExoPlayerView extends FrameLayout {
int playerLayoutId = R.layout.exo_simple_player_view;
boolean useArtwork = true;
int defaultArtwork = 0;
boolean useController = true;
int surfaceType = SURFACE_TYPE_SURFACE_VIEW;
int resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
......@@ -214,8 +205,6 @@ public final class SimpleExoPlayerView extends FrameLayout {
playerLayoutId = a.getResourceId(R.styleable.SimpleExoPlayerView_player_layout_id,
playerLayoutId);
useArtwork = a.getBoolean(R.styleable.SimpleExoPlayerView_use_artwork, useArtwork);
defaultArtwork = a.getResourceId(R.styleable.SimpleExoPlayerView_default_artwork,
defaultArtwork);
useController = a.getBoolean(R.styleable.SimpleExoPlayerView_use_controller, useController);
surfaceType = a.getInt(R.styleable.SimpleExoPlayerView_surface_type, surfaceType);
resizeMode = a.getInt(R.styleable.SimpleExoPlayerView_resize_mode, resizeMode);
......@@ -257,9 +246,6 @@ public final class SimpleExoPlayerView extends FrameLayout {
// Artwork view.
artworkView = (ImageView) findViewById(R.id.exo_artwork);
this.useArtwork = useArtwork && artworkView != null;
if (defaultArtwork != 0) {
this.defaultArtwork = BitmapFactory.decodeResource(context.getResources(), defaultArtwork);
}
// Subtitle view.
subtitleView = (SubtitleView) findViewById(R.id.exo_subtitles);
......@@ -366,26 +352,6 @@ public final class SimpleExoPlayerView extends FrameLayout {
}
/**
* Returns the default artwork to display.
*/
public Bitmap getDefaultArtwork() {
return defaultArtwork;
}
/**
* Sets the default artwork to display if {@code useArtwork} is {@code true} and no artwork is
* present in the media.
*
* @param defaultArtwork the default artwork to display.
*/
public void setDefaultArtwork(Bitmap defaultArtwork) {
if (this.defaultArtwork != defaultArtwork) {
this.defaultArtwork = defaultArtwork;
updateForCurrentTrackSelections();
}
}
/**
* Returns whether the playback controls are enabled.
*/
public boolean getUseController() {
......@@ -603,9 +569,6 @@ public final class SimpleExoPlayerView extends FrameLayout {
}
}
}
if (setArtworkFromBitmap(defaultArtwork)) {
return;
}
}
// Artwork disabled or unavailable.
hideArtwork();
......@@ -617,23 +580,18 @@ public final class SimpleExoPlayerView extends FrameLayout {
if (metadataEntry instanceof ApicFrame) {
byte[] bitmapData = ((ApicFrame) metadataEntry).pictureData;
Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length);
return setArtworkFromBitmap(bitmap);
}
}
return false;
}
private boolean setArtworkFromBitmap(Bitmap bitmap) {
if (bitmap != null) {
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
if (bitmapWidth > 0 && bitmapHeight > 0) {
if (contentFrame != null) {
contentFrame.setAspectRatio((float) bitmapWidth / bitmapHeight);
if (bitmap != null) {
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
if (bitmapWidth > 0 && bitmapHeight > 0) {
if (contentFrame != null) {
contentFrame.setAspectRatio((float) bitmapWidth / bitmapHeight);
}
artworkView.setImageBitmap(bitmap);
artworkView.setVisibility(VISIBLE);
return true;
}
}
artworkView.setImageBitmap(bitmap);
artworkView.setVisibility(VISIBLE);
return true;
}
}
return false;
......
......@@ -146,13 +146,9 @@ import com.google.android.exoplayer2.util.Util;
// Nothing to draw.
return;
}
int windowColor = cue.windowColorSet ? cue.windowColor : style.windowColor;
if (!applyEmbeddedStyles) {
// Strip out any embedded styling.
cueText = cueText.toString();
windowColor = style.windowColor;
}
if (areCharSequencesEqual(this.cueText, cueText)
&& Util.areEqual(this.cueTextAlignment, cue.textAlignment)
......@@ -165,7 +161,7 @@ import com.google.android.exoplayer2.util.Util;
&& this.applyEmbeddedStyles == applyEmbeddedStyles
&& this.foregroundColor == style.foregroundColor
&& this.backgroundColor == style.backgroundColor
&& this.windowColor == windowColor
&& this.windowColor == style.windowColor
&& this.edgeType == style.edgeType
&& this.edgeColor == style.edgeColor
&& Util.areEqual(this.textPaint.getTypeface(), style.typeface)
......@@ -191,7 +187,7 @@ import com.google.android.exoplayer2.util.Util;
this.applyEmbeddedStyles = applyEmbeddedStyles;
this.foregroundColor = style.foregroundColor;
this.backgroundColor = style.backgroundColor;
this.windowColor = windowColor;
this.windowColor = style.windowColor;
this.edgeType = style.edgeType;
this.edgeColor = style.edgeColor;
this.textPaint.setTypeface(style.typeface);
......
......@@ -403,7 +403,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
bufferPresentationTimeUs, unadjustedFrameReleaseTimeNs);
earlyUs = (adjustedReleaseTimeNs - systemTimeNs) / 1000;
if (shouldDropOutputBuffer(earlyUs, elapsedRealtimeUs)) {
if (earlyUs < -30000) {
// We're more than 30ms late rendering the frame.
dropOutputBuffer(codec, bufferIndex);
return true;
......@@ -437,17 +437,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
return false;
}
/**
* Returns true if the current frame should be dropped.
*
* @param earlyUs Time indicating how early the frame is. Negative values indicate late frame.
* @param elapsedRealtimeUs Wall clock time.
*/
protected boolean shouldDropOutputBuffer(long earlyUs, long elapsedRealtimeUs) {
// Drop the frame if we're more than 30ms late rendering the frame.
return earlyUs < -30000;
}
private void skipOutputBuffer(MediaCodec codec, int bufferIndex) {
TraceUtil.beginSection("skipVideoBuffer");
codec.releaseOutputBuffer(bufferIndex, false);
......

354 Bytes | W: | H:

1.09 KB | W: | H:

library/src/main/res/drawable-hdpi/exo_controls_fastforward.png
library/src/main/res/drawable-hdpi/exo_controls_fastforward.png
library/src/main/res/drawable-hdpi/exo_controls_fastforward.png
library/src/main/res/drawable-hdpi/exo_controls_fastforward.png
  • 2-up
  • Swipe
  • Onion skin

323 Bytes | W: | H:

1.05 KB | W: | H:

library/src/main/res/drawable-hdpi/exo_controls_next.png
library/src/main/res/drawable-hdpi/exo_controls_next.png
library/src/main/res/drawable-hdpi/exo_controls_next.png
library/src/main/res/drawable-hdpi/exo_controls_next.png
  • 2-up
  • Swipe
  • Onion skin

108 Bytes | W: | H:

599 Bytes | W: | H:

library/src/main/res/drawable-hdpi/exo_controls_pause.png
library/src/main/res/drawable-hdpi/exo_controls_pause.png
library/src/main/res/drawable-hdpi/exo_controls_pause.png
library/src/main/res/drawable-hdpi/exo_controls_pause.png
  • 2-up
  • Swipe
  • Onion skin

286 Bytes | W: | H:

1.14 KB | W: | H:

library/src/main/res/drawable-hdpi/exo_controls_play.png
library/src/main/res/drawable-hdpi/exo_controls_play.png
library/src/main/res/drawable-hdpi/exo_controls_play.png
library/src/main/res/drawable-hdpi/exo_controls_play.png
  • 2-up
  • Swipe
  • Onion skin

292 Bytes | W: | H:

1.04 KB | W: | H:

library/src/main/res/drawable-hdpi/exo_controls_previous.png
library/src/main/res/drawable-hdpi/exo_controls_previous.png
library/src/main/res/drawable-hdpi/exo_controls_previous.png
library/src/main/res/drawable-hdpi/exo_controls_previous.png
  • 2-up
  • Swipe
  • Onion skin

347 Bytes | W: | H:

1.22 KB | W: | H:

library/src/main/res/drawable-hdpi/exo_controls_rewind.png
library/src/main/res/drawable-hdpi/exo_controls_rewind.png
library/src/main/res/drawable-hdpi/exo_controls_rewind.png
library/src/main/res/drawable-hdpi/exo_controls_rewind.png
  • 2-up
  • Swipe
  • Onion skin

192 Bytes | W: | H:

886 Bytes | W: | H:

library/src/main/res/drawable-ldpi/exo_controls_fastforward.png
library/src/main/res/drawable-ldpi/exo_controls_fastforward.png
library/src/main/res/drawable-ldpi/exo_controls_fastforward.png
library/src/main/res/drawable-ldpi/exo_controls_fastforward.png
  • 2-up
  • Swipe
  • Onion skin

167 Bytes | W: | H:

735 Bytes | W: | H:

library/src/main/res/drawable-ldpi/exo_controls_next.png
library/src/main/res/drawable-ldpi/exo_controls_next.png
library/src/main/res/drawable-ldpi/exo_controls_next.png
library/src/main/res/drawable-ldpi/exo_controls_next.png
  • 2-up
  • Swipe
  • Onion skin

91 Bytes | W: | H:

3.17 KB | W: | H:

library/src/main/res/drawable-ldpi/exo_controls_pause.png
library/src/main/res/drawable-ldpi/exo_controls_pause.png
library/src/main/res/drawable-ldpi/exo_controls_pause.png
library/src/main/res/drawable-ldpi/exo_controls_pause.png
  • 2-up
  • Swipe
  • Onion skin

182 Bytes | W: | H:

673 Bytes | W: | H:

library/src/main/res/drawable-ldpi/exo_controls_play.png
library/src/main/res/drawable-ldpi/exo_controls_play.png
library/src/main/res/drawable-ldpi/exo_controls_play.png
library/src/main/res/drawable-ldpi/exo_controls_play.png
  • 2-up
  • Swipe
  • Onion skin

187 Bytes | W: | H:

770 Bytes | W: | H:

library/src/main/res/drawable-ldpi/exo_controls_previous.png
library/src/main/res/drawable-ldpi/exo_controls_previous.png
library/src/main/res/drawable-ldpi/exo_controls_previous.png
library/src/main/res/drawable-ldpi/exo_controls_previous.png
  • 2-up
  • Swipe
  • Onion skin

214 Bytes | W: | H:

906 Bytes | W: | H:

library/src/main/res/drawable-ldpi/exo_controls_rewind.png
library/src/main/res/drawable-ldpi/exo_controls_rewind.png
library/src/main/res/drawable-ldpi/exo_controls_rewind.png
library/src/main/res/drawable-ldpi/exo_controls_rewind.png
  • 2-up
  • Swipe
  • Onion skin

255 Bytes | W: | H:

929 Bytes | W: | H:

library/src/main/res/drawable-mdpi/exo_controls_fastforward.png
library/src/main/res/drawable-mdpi/exo_controls_fastforward.png
library/src/main/res/drawable-mdpi/exo_controls_fastforward.png
library/src/main/res/drawable-mdpi/exo_controls_fastforward.png
  • 2-up
  • Swipe
  • Onion skin

276 Bytes | W: | H:

843 Bytes | W: | H:

library/src/main/res/drawable-mdpi/exo_controls_next.png
library/src/main/res/drawable-mdpi/exo_controls_next.png
library/src/main/res/drawable-mdpi/exo_controls_next.png
library/src/main/res/drawable-mdpi/exo_controls_next.png
  • 2-up
  • Swipe
  • Onion skin

153 Bytes | W: | H:

540 Bytes | W: | H:

library/src/main/res/drawable-mdpi/exo_controls_pause.png
library/src/main/res/drawable-mdpi/exo_controls_pause.png
library/src/main/res/drawable-mdpi/exo_controls_pause.png
library/src/main/res/drawable-mdpi/exo_controls_pause.png
  • 2-up
  • Swipe
  • Onion skin

228 Bytes | W: | H:

897 Bytes | W: | H:

library/src/main/res/drawable-mdpi/exo_controls_play.png
library/src/main/res/drawable-mdpi/exo_controls_play.png
library/src/main/res/drawable-mdpi/exo_controls_play.png
library/src/main/res/drawable-mdpi/exo_controls_play.png
  • 2-up
  • Swipe
  • Onion skin

227 Bytes | W: | H:

837 Bytes | W: | H:

library/src/main/res/drawable-mdpi/exo_controls_previous.png
library/src/main/res/drawable-mdpi/exo_controls_previous.png
library/src/main/res/drawable-mdpi/exo_controls_previous.png
library/src/main/res/drawable-mdpi/exo_controls_previous.png
  • 2-up
  • Swipe
  • Onion skin

273 Bytes | W: | H:

997 Bytes | W: | H:

library/src/main/res/drawable-mdpi/exo_controls_rewind.png
library/src/main/res/drawable-mdpi/exo_controls_rewind.png
library/src/main/res/drawable-mdpi/exo_controls_rewind.png
library/src/main/res/drawable-mdpi/exo_controls_rewind.png
  • 2-up
  • Swipe
  • Onion skin
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path android:fillColor="#FFF" android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path android:fillColor="#FFF" android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path android:fillColor="#FFF" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path android:fillColor="#FFF" android:pathData="M8,5v14l11,-7z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path android:fillColor="#FFF" android:pathData="M6,6h2v12L6,18zM9.5,12l8.5,6L18,6z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path android:fillColor="#FFF" android:pathData="M11,18L11,6l-8.5,6 8.5,6zM11.5,12l8.5,6L20,6l-8.5,6z"/>
</vector>

392 Bytes | W: | H:

1.44 KB | W: | H:

library/src/main/res/drawable-xhdpi/exo_controls_fastforward.png
library/src/main/res/drawable-xhdpi/exo_controls_fastforward.png
library/src/main/res/drawable-xhdpi/exo_controls_fastforward.png
library/src/main/res/drawable-xhdpi/exo_controls_fastforward.png
  • 2-up
  • Swipe
  • Onion skin

334 Bytes | W: | H:

1.33 KB | W: | H:

library/src/main/res/drawable-xhdpi/exo_controls_next.png
library/src/main/res/drawable-xhdpi/exo_controls_next.png
library/src/main/res/drawable-xhdpi/exo_controls_next.png
library/src/main/res/drawable-xhdpi/exo_controls_next.png
  • 2-up
  • Swipe
  • Onion skin

164 Bytes | W: | H:

685 Bytes | W: | H:

library/src/main/res/drawable-xhdpi/exo_controls_pause.png
library/src/main/res/drawable-xhdpi/exo_controls_pause.png
library/src/main/res/drawable-xhdpi/exo_controls_pause.png
library/src/main/res/drawable-xhdpi/exo_controls_pause.png
  • 2-up
  • Swipe
  • Onion skin

343 Bytes | W: | H:

1.58 KB | W: | H:

library/src/main/res/drawable-xhdpi/exo_controls_play.png
library/src/main/res/drawable-xhdpi/exo_controls_play.png
library/src/main/res/drawable-xhdpi/exo_controls_play.png
library/src/main/res/drawable-xhdpi/exo_controls_play.png
  • 2-up
  • Swipe
  • Onion skin

339 Bytes | W: | H:

1.34 KB | W: | H:

library/src/main/res/drawable-xhdpi/exo_controls_previous.png
library/src/main/res/drawable-xhdpi/exo_controls_previous.png
library/src/main/res/drawable-xhdpi/exo_controls_previous.png
library/src/main/res/drawable-xhdpi/exo_controls_previous.png
  • 2-up
  • Swipe
  • Onion skin

400 Bytes | W: | H:

1.64 KB | W: | H:

library/src/main/res/drawable-xhdpi/exo_controls_rewind.png
library/src/main/res/drawable-xhdpi/exo_controls_rewind.png
library/src/main/res/drawable-xhdpi/exo_controls_rewind.png
library/src/main/res/drawable-xhdpi/exo_controls_rewind.png
  • 2-up
  • Swipe
  • Onion skin

391 Bytes | W: | H:

1.29 KB | W: | H:

library/src/main/res/drawable-xxhdpi/exo_controls_next.png
library/src/main/res/drawable-xxhdpi/exo_controls_next.png
library/src/main/res/drawable-xxhdpi/exo_controls_next.png
library/src/main/res/drawable-xxhdpi/exo_controls_next.png
  • 2-up
  • Swipe
  • Onion skin

113 Bytes | W: | H:

611 Bytes | W: | H:

library/src/main/res/drawable-xxhdpi/exo_controls_pause.png
library/src/main/res/drawable-xxhdpi/exo_controls_pause.png
library/src/main/res/drawable-xxhdpi/exo_controls_pause.png
library/src/main/res/drawable-xxhdpi/exo_controls_pause.png
  • 2-up
  • Swipe
  • Onion skin

384 Bytes | W: | H:

1.16 KB | W: | H:

library/src/main/res/drawable-xxhdpi/exo_controls_play.png
library/src/main/res/drawable-xxhdpi/exo_controls_play.png
library/src/main/res/drawable-xxhdpi/exo_controls_play.png
library/src/main/res/drawable-xxhdpi/exo_controls_play.png
  • 2-up
  • Swipe
  • Onion skin

464 Bytes | W: | H:

1.26 KB | W: | H:

library/src/main/res/drawable-xxhdpi/exo_controls_previous.png
library/src/main/res/drawable-xxhdpi/exo_controls_previous.png
library/src/main/res/drawable-xxhdpi/exo_controls_previous.png
library/src/main/res/drawable-xxhdpi/exo_controls_previous.png
  • 2-up
  • Swipe
  • Onion skin

571 Bytes | W: | H:

1.17 KB | W: | H:

library/src/main/res/drawable-xxhdpi/exo_controls_rewind.png
library/src/main/res/drawable-xxhdpi/exo_controls_rewind.png
library/src/main/res/drawable-xxhdpi/exo_controls_rewind.png
library/src/main/res/drawable-xxhdpi/exo_controls_rewind.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -37,7 +37,6 @@
<declare-styleable name="SimpleExoPlayerView">
<attr name="use_artwork" format="boolean"/>
<attr name="default_artwork" format="reference"/>
<attr name="use_controller" format="boolean"/>
<attr name="surface_type"/>
<attr name="show_timeout"/>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment