diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java
index 18de1b9df9..3b18a06c75 100644
--- a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java
+++ b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java
@@ -39,6 +39,7 @@ import com.google.android.exoplayer2.upstream.Loader;
import com.google.android.exoplayer2.upstream.Loader.Loadable;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ConditionVariable;
+import com.google.android.exoplayer2.util.MimeTypes;
import java.io.EOFException;
import java.io.IOException;
@@ -80,6 +81,8 @@ import java.io.IOException;
private TrackGroupArray tracks;
private long durationUs;
private boolean[] trackEnabledStates;
+ private boolean[] trackIsAudioVideoFlags;
+ private boolean haveAudioVideoTracks;
private long length;
private long lastSeekPositionUs;
@@ -259,11 +262,23 @@ import java.io.IOException;
return C.TIME_END_OF_SOURCE;
} else if (isPendingReset()) {
return pendingResetPositionUs;
- } else {
- long largestQueuedTimestampUs = getLargestQueuedTimestampUs();
- return largestQueuedTimestampUs == Long.MIN_VALUE ? lastSeekPositionUs
- : largestQueuedTimestampUs;
}
+ long largestQueuedTimestampUs;
+ if (haveAudioVideoTracks) {
+ // Ignore non-AV tracks, which may be sparse or poorly interleaved.
+ largestQueuedTimestampUs = Long.MAX_VALUE;
+ int trackCount = sampleQueues.size();
+ for (int i = 0; i < trackCount; i++) {
+ if (trackIsAudioVideoFlags[i]) {
+ largestQueuedTimestampUs = Math.min(largestQueuedTimestampUs,
+ sampleQueues.valueAt(i).getLargestQueuedTimestampUs());
+ }
+ }
+ } else {
+ largestQueuedTimestampUs = getLargestQueuedTimestampUs();
+ }
+ return largestQueuedTimestampUs == Long.MIN_VALUE ? lastSeekPositionUs
+ : largestQueuedTimestampUs;
}
@Override
@@ -404,10 +419,16 @@ import java.io.IOException;
}
loadCondition.close();
TrackGroup[] trackArray = new TrackGroup[trackCount];
+ trackIsAudioVideoFlags = new boolean[trackCount];
trackEnabledStates = new boolean[trackCount];
durationUs = seekMap.getDurationUs();
for (int i = 0; i < trackCount; i++) {
- trackArray[i] = new TrackGroup(sampleQueues.valueAt(i).getUpstreamFormat());
+ Format trackFormat = sampleQueues.valueAt(i).getUpstreamFormat();
+ trackArray[i] = new TrackGroup(trackFormat);
+ String mimeType = trackFormat.sampleMimeType;
+ boolean isAudioVideo = MimeTypes.isVideo(mimeType) || MimeTypes.isAudio(mimeType);
+ trackIsAudioVideoFlags[i] = isAudioVideo;
+ haveAudioVideoTracks |= isAudioVideo;
}
tracks = new TrackGroupArray(trackArray);
prepared = true;
diff --git a/library/src/main/java/com/google/android/exoplayer2/ui/AspectRatioFrameLayout.java b/library/src/main/java/com/google/android/exoplayer2/ui/AspectRatioFrameLayout.java
index f92903d65a..d3034a8bc8 100644
--- a/library/src/main/java/com/google/android/exoplayer2/ui/AspectRatioFrameLayout.java
+++ b/library/src/main/java/com/google/android/exoplayer2/ui/AspectRatioFrameLayout.java
@@ -34,7 +34,7 @@ public final class AspectRatioFrameLayout extends FrameLayout {
* Resize modes for {@link AspectRatioFrameLayout}.
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RESIZE_MODE_FIT, RESIZE_MODE_FIXED_WIDTH, RESIZE_MODE_FIXED_HEIGHT})
+ @IntDef({RESIZE_MODE_FIT, RESIZE_MODE_FIXED_WIDTH, RESIZE_MODE_FIXED_HEIGHT, RESIZE_MODE_FILL})
public @interface ResizeMode {}
/**
@@ -49,6 +49,10 @@ public final class AspectRatioFrameLayout extends FrameLayout {
* The height is fixed and the width is increased or decreased to obtain the desired aspect ratio.
*/
public static final int RESIZE_MODE_FIXED_HEIGHT = 2;
+ /**
+ * The specified aspect ratio is ignored.
+ */
+ public static final int RESIZE_MODE_FILL = 3;
/**
* The {@link FrameLayout} will not resize itself if the fractional difference between its natural
@@ -109,7 +113,7 @@ public final class AspectRatioFrameLayout extends FrameLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (videoAspectRatio == 0) {
+ if (resizeMode == RESIZE_MODE_FILL || videoAspectRatio <= 0) {
// Aspect ratio not set.
return;
}
diff --git a/library/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java
index ecb9319c1d..90a15da12c 100644
--- a/library/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java
+++ b/library/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java
@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.ui;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.AttributeSet;
import android.view.KeyEvent;
@@ -56,8 +57,7 @@ public final class SimpleExoPlayerView extends FrameLayout {
private static final int SURFACE_TYPE_SURFACE_VIEW = 1;
private static final int SURFACE_TYPE_TEXTURE_VIEW = 2;
- private final ViewGroup videoFrame;
- private final AspectRatioFrameLayout aspectRatioVideoFrame;
+ private final AspectRatioFrameLayout contentFrame;
private final View shutterView;
private final View surfaceView;
private final ImageView artworkView;
@@ -112,40 +112,39 @@ public final class SimpleExoPlayerView extends FrameLayout {
LayoutInflater.from(context).inflate(playerLayoutId, this);
componentListener = new ComponentListener();
- videoFrame = (ViewGroup) findViewById(R.id.exo_video_frame);
- if (videoFrame != null) {
- if (videoFrame instanceof AspectRatioFrameLayout) {
- aspectRatioVideoFrame = (AspectRatioFrameLayout) videoFrame;
- setResizeModeRaw(aspectRatioVideoFrame, resizeMode);
- } else {
- aspectRatioVideoFrame = null;
- }
- shutterView = Assertions.checkNotNull(videoFrame.findViewById(R.id.exo_shutter));
- if (surfaceType != SURFACE_TYPE_NONE) {
- ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
- surfaceView = surfaceType == SURFACE_TYPE_TEXTURE_VIEW ? new TextureView(context)
- : new SurfaceView(context);
- surfaceView.setLayoutParams(params);
- videoFrame.addView(surfaceView, 0);
- } else {
- surfaceView = null;
- }
+ // Content frame.
+ contentFrame = (AspectRatioFrameLayout) findViewById(R.id.exo_content_frame);
+ if (contentFrame != null) {
+ setResizeModeRaw(contentFrame, resizeMode);
+ }
+
+ // Shutter view.
+ shutterView = findViewById(R.id.exo_shutter);
+
+ // Create a surface view and insert it into the content frame, if there is one.
+ if (contentFrame != null && surfaceType != SURFACE_TYPE_NONE) {
+ ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ surfaceView = surfaceType == SURFACE_TYPE_TEXTURE_VIEW ? new TextureView(context)
+ : new SurfaceView(context);
+ surfaceView.setLayoutParams(params);
+ contentFrame.addView(surfaceView, 0);
} else {
- aspectRatioVideoFrame = null;
- shutterView = null;
surfaceView = null;
}
+ // Artwork view.
artworkView = (ImageView) findViewById(R.id.exo_artwork);
this.useArtwork = useArtwork && artworkView != null;
+ // Subtitle view.
subtitleView = (SubtitleView) findViewById(R.id.exo_subtitles);
if (subtitleView != null) {
subtitleView.setUserDefaultStyle();
subtitleView.setUserDefaultTextSize();
}
+ // Playback control view.
PlaybackControlView controller = (PlaybackControlView) findViewById(R.id.exo_controller);
if (controller != null) {
controller.setRewindIncrementMs(rewindMs);
@@ -223,8 +222,8 @@ public final class SimpleExoPlayerView extends FrameLayout {
* @param resizeMode The resize mode.
*/
public void setResizeMode(@ResizeMode int resizeMode) {
- Assertions.checkState(aspectRatioVideoFrame != null);
- aspectRatioVideoFrame.setResizeMode(resizeMode);
+ Assertions.checkState(contentFrame != null);
+ contentFrame.setResizeMode(resizeMode);
}
/**
@@ -403,16 +402,8 @@ public final class SimpleExoPlayerView extends FrameLayout {
if (selection != null) {
for (int j = 0; j < selection.length(); j++) {
Metadata metadata = selection.getFormat(j).metadata;
- if (metadata != null) {
- for (int k = 0; k < metadata.length(); k++) {
- Metadata.Entry metadataEntry = metadata.get(k);
- if (metadataEntry instanceof ApicFrame) {
- byte[] data = ((ApicFrame) metadataEntry).pictureData;;
- artworkView.setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
- artworkView.setVisibility(VISIBLE);
- return;
- }
- }
+ if (metadata != null && setArtworkFromMetadata(metadata)) {
+ return;
}
}
}
@@ -422,6 +413,29 @@ public final class SimpleExoPlayerView extends FrameLayout {
hideArtwork();
}
+ private boolean setArtworkFromMetadata(Metadata metadata) {
+ for (int i = 0; i < metadata.length(); i++) {
+ Metadata.Entry metadataEntry = metadata.get(i);
+ if (metadataEntry instanceof ApicFrame) {
+ byte[] bitmapData = ((ApicFrame) metadataEntry).pictureData;
+ Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length);
+ 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;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
private void hideArtwork() {
if (artworkView != null) {
artworkView.setImageResource(android.R.color.transparent); // Clears any bitmap reference.
@@ -457,9 +471,9 @@ public final class SimpleExoPlayerView extends FrameLayout {
@Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
float pixelWidthHeightRatio) {
- if (aspectRatioVideoFrame != null) {
+ if (contentFrame != null) {
float aspectRatio = height == 0 ? 1 : (width * pixelWidthHeightRatio) / height;
- aspectRatioVideoFrame.setAspectRatio(aspectRatio);
+ contentFrame.setAspectRatio(aspectRatio);
}
}
diff --git a/library/src/main/res/layout/exo_simple_player_view.xml b/library/src/main/res/layout/exo_simple_player_view.xml
index f89eafdd58..c4f34ef285 100644
--- a/library/src/main/res/layout/exo_simple_player_view.xml
+++ b/library/src/main/res/layout/exo_simple_player_view.xml
@@ -17,27 +17,29 @@
android:layout_height="match_parent"
android:layout_width="match_parent">
-
+
+
+
+
-
-
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
index 4be7cd590f..c3fc16495c 100644
--- a/library/src/main/res/values/attrs.xml
+++ b/library/src/main/res/values/attrs.xml
@@ -19,6 +19,7 @@
+
diff --git a/library/src/main/res/values/ids.xml b/library/src/main/res/values/ids.xml
index b768b75e89..00f35d9098 100644
--- a/library/src/main/res/values/ids.xml
+++ b/library/src/main/res/values/ids.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-
+