mirror of
https://github.com/samsonjs/media.git
synced 2026-04-05 11:15:46 +00:00
Fixes for Issue #1962
- Use A/V tracks only for buffering position when available in ExtractorMediaPeriod. - Fix layering of exo_simple_player_view so that subtitles are above album art. The test stream provided has both. - Make album art in SimpleExoPlayer view respect the resize mode, like we do for video. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=137698473
This commit is contained in:
parent
daf7b948a1
commit
488c2d8270
6 changed files with 93 additions and 51 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,27 +17,29 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout android:id="@id/exo_video_frame"
|
||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout android:id="@id/exo_content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<!-- Video surface will be inserted as the first child of the content frame. -->
|
||||
|
||||
<View android:id="@id/exo_shutter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/black"/>
|
||||
|
||||
<ImageView android:id="@id/exo_artwork"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitXY"/>
|
||||
|
||||
<com.google.android.exoplayer2.ui.SubtitleView android:id="@id/exo_subtitles"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
|
||||
|
||||
<ImageView android:id="@id/exo_artwork"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<View android:id="@id/exo_controller_placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
<enum name="fit" value="0"/>
|
||||
<enum name="fixed_width" value="1"/>
|
||||
<enum name="fixed_height" value="2"/>
|
||||
<enum name="fill" value="3"/>
|
||||
</attr>
|
||||
<!-- Must be kept in sync with SimpleExoPlayerView -->
|
||||
<attr name="surface_type" format="enum">
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<item name="exo_video_frame" type="id"/>
|
||||
<item name="exo_content_frame" type="id"/>
|
||||
<item name="exo_shutter" type="id"/>
|
||||
<item name="exo_subtitles" type="id"/>
|
||||
<item name="exo_artwork" type="id"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue