Last active
December 11, 2016 09:37
-
-
Save ueno-yuhei/001e3e6421faa1ce99fb8fb52e403575 to your computer and use it in GitHub Desktop.
動画プレイヤーのシークバーの上にサムネイルを表示! on ExoPlayer ref: http://qiita.com/ueno-yuhei/items/67d46f696c15c93c4058
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ExoPlayerActivity extends FragmentActivity implements TextureView.SurfaceTextureListener { | |
private ExoPlayerActivityBinding binding; | |
private SimpleExoPlayer simpleExoPlayer; | |
// Apple sample HLS | |
private static final String videoUrl = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"; | |
private Timer playerTimer; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
binding = DataBindingUtil.setContentView(this, R.layout.exo_player_activity); | |
// TextureViewのコールバックをセット | |
binding.textureView.setSurfaceTextureListener(this); | |
// ステータスバー、ナビゲーションバーを非表示に | |
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); | |
View decor = getWindow().getDecorView(); | |
if (Build.VERSION.SDK_INT > 18) { | |
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | |
| View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); | |
} else if (Build.VERSION.SDK_INT > 15) { | |
decor.setSystemUiVisibility( | |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN); | |
} else if (Build.VERSION.SDK_INT > 13) { | |
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); | |
} else { | |
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); | |
} | |
// Playerの領域を16 : 9 へ | |
binding.raitoFrameLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { | |
@Override | |
public void onGlobalLayout() { | |
if (binding.raitoFrameLayout.getWidth() > 0 && binding.raitoFrameLayout.getHeight() > 0) { | |
int width = binding.raitoFrameLayout.getWidth(); | |
ViewGroup.LayoutParams params = binding.raitoFrameLayout.getLayoutParams(); | |
params.height = width / 16 * 9; | |
binding.raitoFrameLayout.setLayoutParams(params); | |
if (Build.VERSION.SDK_INT >= 16) { | |
binding.raitoFrameLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); | |
} else { | |
binding.raitoFrameLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); | |
} | |
} | |
} | |
}); | |
// 読み込み中のProgressbar表示 | |
binding.loadingProgress.setVisibility(View.VISIBLE); | |
// SeekBarのイベントセット | |
binding.controlSeek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { | |
@Override | |
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { | |
if (progress == 0 || seekBar.getMax() == 0) return; | |
if (fromUser) { | |
// ユーザーがSeekBarをいじってシークしたらPlayerをその秒数へ | |
simpleExoPlayer.seekTo(progress * 1000); | |
setThumbnailX(progress, seekBar.getMax()); | |
} | |
} | |
@Override | |
public void onStartTrackingTouch(SeekBar seekBar) { | |
// ユーザーがシーク開始 | |
binding.loadingProgress.setVisibility(View.VISIBLE); | |
} | |
@Override | |
public void onStopTrackingTouch(SeekBar seekBar) { | |
// ユーザーがシーク終了 | |
binding.loadingProgress.setVisibility(View.INVISIBLE); | |
} | |
}); | |
} | |
// 秒数とSeekBarの位置を更新するPlayer監視Timer | |
private void setTimer() { | |
stopTimer(); | |
playerTimer = new Timer(); | |
playerTimer.scheduleAtFixedRate(new TimerTask() { | |
@Override | |
public void run() { | |
final int durationSecond = (int) (simpleExoPlayer.getDuration() / 1000); | |
final int currentSecond = (int) (simpleExoPlayer.getCurrentPosition() / 1000); | |
binding.time.post(new Runnable() { | |
@Override | |
public void run() { | |
binding.time.setText(currentSecond + "/" + durationSecond); | |
binding.controlSeek.setMax(durationSecond); // SeekBarのMax値を動画の秒数に | |
binding.controlSeek.setProgress(currentSecond); // SeekBarのつまみを現在の秒数の箇所へ移動 | |
setThumbnailX(currentSecond, durationSecond); | |
} | |
}); | |
} | |
}, 1000, 1000); | |
} | |
// SeekBar上の画像の位置を移動 Viewの大きさから位置を計算 | |
private void setThumbnailX(int currentPosition, int durationPosition) { | |
int seekWidth = binding.controlSeek.getWidth(); | |
int imageWidth = binding.videoImage.getWidth(); | |
double videoImageX = (double) seekWidth * currentPosition / durationPosition; | |
if (videoImageX > seekWidth - imageWidth / 2) { | |
binding.videoImage.setX(seekWidth - imageWidth); | |
} else if (videoImageX > imageWidth / 2) { | |
binding.videoImage.setX((int) videoImageX - imageWidth / 2); | |
} else { | |
binding.videoImage.setX(0); | |
} | |
} | |
// Player監視Timerを削除 | |
private void stopTimer() { | |
if (playerTimer != null) { | |
playerTimer.cancel(); | |
playerTimer.purge(); | |
playerTimer = null; | |
} | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
if (simpleExoPlayer != null) { | |
setTimer(); | |
simpleExoPlayer.setPlayWhenReady(true); | |
} | |
} | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
stopTimer(); | |
if (simpleExoPlayer != null) { | |
simpleExoPlayer.setPlayWhenReady(false); | |
} | |
} | |
// ExoPlayer2 TextureViewの準備ができたらExoPlayerにTextureViewをセットして再生開始 | |
@Override | |
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) { | |
Handler mainHandler = new Handler(); | |
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); | |
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter); | |
TrackSelector trackSelector = new DefaultTrackSelector(mainHandler, videoTrackSelectionFactory); | |
LoadControl loadControl = new DefaultLoadControl(); | |
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(getApplicationContext(), trackSelector, loadControl); | |
simpleExoPlayer.setVideoTextureView(binding.textureView); | |
DefaultBandwidthMeter defaultBandwidthMeter = new DefaultBandwidthMeter(); | |
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, | |
Util.getUserAgent(this, new WebView(getApplicationContext()).getSettings().getUserAgentString()), defaultBandwidthMeter); | |
HlsMediaSource hlsMediaSource = new HlsMediaSource(Uri.parse(videoUrl), dataSourceFactory, mainHandler, null); | |
simpleExoPlayer.prepare(hlsMediaSource); | |
simpleExoPlayer.setVideoListener(new SimpleExoPlayer.VideoListener() { | |
@Override | |
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { | |
} | |
@Override | |
public void onRenderedFirstFrame() { | |
// 再生開始 | |
binding.loadingProgress.setVisibility(View.INVISIBLE); | |
setTimer(); | |
} | |
@Override | |
public void onVideoTracksDisabled() { | |
} | |
}); | |
simpleExoPlayer.setPlayWhenReady(true); | |
} | |
@Override | |
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) { | |
} | |
@Override | |
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { | |
return false; | |
} | |
@Override | |
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { | |
} | |
// ExoPlayer2 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<layout> | |
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="#000"> | |
<RelativeLayout xmlns:tools="http://schemas.android.com/tools" | |
android:id="@+id/raito_frame_layout" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_gravity="center" | |
tools:context=".activity.ExoPlayerActivity"> | |
<TextureView | |
android:id="@+id/texture_view" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_gravity="center" /> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_alignParentBottom="true" | |
android:layout_margin="8dp" | |
android:orientation="vertical"> | |
<TextView | |
android:id="@+id/time" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_gravity="right|bottom" | |
android:layout_margin="8dp" | |
android:textColor="#FFF" | |
android:textSize="16sp" /> | |
<ImageView | |
android:id="@+id/video_image" | |
android:layout_width="64dp" | |
android:layout_height="36dp" | |
android:layout_margin="8dp" | |
android:background="#FFF" /> | |
<SeekBar | |
android:id="@+id/control_seek" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_gravity="bottom" /> | |
</LinearLayout> | |
<ProgressBar | |
android:id="@+id/loading_progress" | |
style="?android:attr/progressBarStyle" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_centerInParent="true" /> | |
</RelativeLayout> | |
</FrameLayout> | |
</layout> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment