programacion - manual android studio avanzado
¿Se puede desconectar VideoView y volver a conectarlo sin detener la transmisión? (4)
Estoy construyendo una aplicación donde el usuario hace clic en un botón para mostrar un video a pantalla completa. Inicialmente, el video se adjunta a una vista dentro de un ViewPager. Para poder mostrarlo en pantalla completa, lo desconecto de su elemento principal y lo vuelvo a conectar a la vista raíz. Esto funciona bien, excepto cuando el video se cambia a pantalla completa mientras se reproduce. Cuando desconecto un VideoView que se reproduce, simplemente se detiene y necesito reiniciarlo. Esto no es aceptable ya que el video inicia el almacenamiento en búfer antes del currículum. Aquí la parte del código donde se realiza el desmontaje:
final ViewGroup parent = (ViewGroup) findViewById(R.id.parent);
final ViewGroup root = (ViewGroup) findViewById(R.id.root);
Button b = (Button) findViewById(R.id.button);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
parent.removeView(mVideoView);
LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
root.addView(mVideoView, lp);
}
});
Dependiendo del dispositivo, tengo un error de registro diferente. Probablemente porque el reproductor de video real es proporcionado por el fabricante y no por el SDK de Android. Aquí están los registros de errores de un Nexus 7:
10-30 20:26:18.618: D/NvOsDebugPrintf(124): NvMMDecTVMRDestroyParser Begin
10-30 20:26:18.618: D/NvOsDebugPrintf(124): --------- Closing TVMR Frame Delivery Thread -------------
10-30 20:26:18.678: D/NvOsDebugPrintf(124): ------- NvAvpClose -------
10-30 20:26:18.678: D/NvOsDebugPrintf(124): NvMMDecTVMRDestroyParser Done
10-30 20:26:18.678: D/NvOsDebugPrintf(124): NvMMLiteTVMRDecPrivateClose Done
No he podido separar el video sin detenerlo. Intenté usar SurfaceView o TextureView sin éxito.
También traté de encontrar un reproductor de video de terceros. Encontré uno comercial ( http://www.vitamio.org/ ) que no puedo usar realmente por razones comerciales. Encontré uno de código abierto, que no se actualizó en el último año ( https://code.google.com/p/dolphin-player/ ).
Actualmente me estoy orientando a Android 4.2 o mejor solo en la tableta.
Tenga en cuenta que ViewPager no es pantalla completa. Entonces no puedo usar LayoutParams para hacer que el video sea de pantalla completa. Necesito eliminar VideoView del padre en ViewPager y agregarlo a la vista raíz para poder mostrarlo en pantalla completa.
La URL con la que estoy probando: http://bellvps1.cpl.delvenetworks.com/media/e1b3e24ecb944abd8f4ed823a0b76ddc/68f78d35296243bfb46d2418f03f2fd0/bande-annonce---the-secret-life-of-walter-mitty-1-9efcc5c6e52ac07a3edf84a1b21967995b7796a2.m3u8
No lo he intentado, pero espero que te pueda ayudar.
final ViewGroup parent = (ViewGroup) findViewById(R.id.parent);
final ViewGroup root = (ViewGroup) findViewById(R.id.root);//assuming this full screen
Button b = (Button) findViewById(R.id.button);
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// parent.removeView(mVideoView);
LayoutParams parentParam = parent.getLayoutParams();
parentParam.height = root.getLayoutParams().height;
parentParam.width = root.getLayoutParams().width;
parent.setLayoutParams(parentParam);
LayoutParams lp = new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
root.addView(mVideoView, lp);
}
});
Gracias.
No sé los detalles de cómo funciona el reproductor de video, pero mi corazonada es que tienes que:
Override onSaveInstanceState to save the place in the video (maybe a timestamp?)
Override onRestoreInstanceState to reload the video and seek to the point saved in step 1
use textureview con esta modificación:
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
if (mediaPlayer != null) {
mediaPlayer.setSurface(new Surface (surfaceTexture));}
}
Upd: Y código completo: player2.java:
public class player2 extends TextureView
implements MediaPlayerControl {
private String TAG = "TextureVideoView";
// settable by the client
private Uri mUri;
private Map<String, String> mHeaders;
// all possible internal states
private static final int STATE_ERROR = -1;
private static final int STATE_IDLE = 0;
private static final int STATE_PREPARING = 1;
private static final int STATE_PREPARED = 2;
private static final int STATE_PLAYING = 3;
private static final int STATE_PAUSED = 4;
private static final int STATE_PLAYBACK_COMPLETED = 5;
private static int mCurrentState;
private static int mTargetState;
// All the stuff we need for playing and showing a video
static public SurfaceTexture sf;
static public MediaPlayer mMediaPlayer;
private int mAudioSession;
private int mVideoWidth;
private int mVideoHeight;
private int mSurfaceWidth;
private int mSurfaceHeight;
private MediaController mMediaController;
private OnCompletionListener mOnCompletionListener;
private MediaPlayer.OnPreparedListener mOnPreparedListener;
private int mCurrentBufferPercentage;
private OnErrorListener mOnErrorListener;
private OnInfoListener mOnInfoListener;
private int mSeekWhenPrepared; // recording the seek position while preparing
private static boolean mCanPause;
private static boolean mCanSeekBack;
private static boolean mCanSeekForward;
private Context mContext;
public player2(Context context) {
super(context);
initVideoView();
}
public player2(Context context, AttributeSet attrs) {
this(context, attrs, 0);
initVideoView();
}
public player2(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initVideoView();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
// + MeasureSpec.toString(heightMeasureSpec) + ")");
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mVideoWidth > 0 && mVideoHeight > 0) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
// the size is fixed
width = widthSpecSize;
height = heightSpecSize;
// for compatibility, we adjust size based on aspect ratio
if ( mVideoWidth * height < width * mVideoHeight ) {
//Log.i("@@@", "image too wide, correcting");
width = height * mVideoWidth / mVideoHeight;
} else if ( mVideoWidth * height > width * mVideoHeight ) {
//Log.i("@@@", "image too tall, correcting");
height = width * mVideoHeight / mVideoWidth;
}
} else if (widthSpecMode == MeasureSpec.EXACTLY) {
// only the width is fixed, adjust the height to match aspect ratio if possible
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
// couldn''t match aspect ratio within the constraints
height = heightSpecSize;
}
} else if (heightSpecMode == MeasureSpec.EXACTLY) {
// only the height is fixed, adjust the width to match aspect ratio if possible
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
// couldn''t match aspect ratio within the constraints
width = widthSpecSize;
}
} else {
// neither the width nor the height are fixed, try to use actual video size
width = mVideoWidth;
height = mVideoHeight;
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
// too tall, decrease both width and height
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
}
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
// too wide, decrease both width and height
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
}
}
} else {
// no size yet, just adopt the given spec sizes
}
setMeasuredDimension(width, height);
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(player2.class.getName());
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(player2.class.getName());
}
public int resolveAdjustedSize(int desiredSize, int measureSpec) {
return getDefaultSize(desiredSize, measureSpec);
}
private void initVideoView() {
mContext = getContext();
mVideoWidth = 0;
mVideoHeight = 0;
setSurfaceTextureListener(mSurfaceTextureListener);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
if (mMediaPlayer==null) {
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;}
}
public void setVideoPath(String path) {
setVideoURI(Uri.parse(path));
}
public void setVideoURI(Uri uri) {
setVideoURI(uri, null);
}
/**
* @hide
*/
private void setVideoURI(Uri uri, Map<String, String> headers) {
mUri = uri;
mHeaders = headers;
mSeekWhenPrepared = 0;
requestLayout();
invalidate();
}
private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks;
public void stopPlayback() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
}
}
private void setListeners() {
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnInfoListener(mInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mCurrentBufferPercentage = 0;
mMediaPlayer.setScreenOnWhilePlaying(true);
}
private void openVideo() {
if (mUri == null || sf == null) {
// not ready for playback just yet, will try again later
return;
}
// Tell the music playback service to pause
// TODO: these constants need to be published somewhere in the framework.
/* Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
mContext.sendBroadcast(i);*/
if (mMediaPlayer==null) {
try {
mMediaPlayer = new MediaPlayer();
if (mAudioSession != 0) {
mMediaPlayer.setAudioSessionId(mAudioSession);
} else {
mAudioSession = mMediaPlayer.getAudioSessionId();
}
setListeners();
mMediaPlayer.setSurface(new Surface (sf));
mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.prepareAsync();
// we don''t set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING;
attachMediaController();
} catch (IOException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
} catch (IllegalArgumentException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
} finally {
mPendingSubtitleTracks.clear();
}} else {
setListeners();
}
}
public void setMediaController(MediaController controller) {
if (mMediaController != null) {
mMediaController.hide();
}
mMediaController = controller;
attachMediaController();
}
private void attachMediaController() {
if (mMediaPlayer != null && mMediaController != null) {
mMediaController.setMediaPlayer(this);
View anchorView = this.getParent() instanceof View ?
(View)this.getParent() : this;
mMediaController.setAnchorView(anchorView);
mMediaController.setEnabled(isInPlaybackState());
}
}
MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
new MediaPlayer.OnVideoSizeChangedListener() {
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
if (mVideoWidth != 0 && mVideoHeight != 0) {
getSurfaceTexture().setDefaultBufferSize(mVideoWidth, mVideoHeight);
requestLayout();
}
}
};
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mCurrentState = STATE_PREPARED;
mCanPause = mCanSeekBack = mCanSeekForward = true;
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mMediaPlayer);
}
if (mMediaController != null) {
mMediaController.setEnabled(true);
}
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
if (seekToPosition != 0) {
seekTo(seekToPosition);
}
if (mVideoWidth != 0 && mVideoHeight != 0) {
//Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
getSurfaceTexture().setDefaultBufferSize(mVideoWidth, mVideoHeight);
requestLayout();
if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
// We didn''t actually change the size (it was already at the size
// we need), so we won''t get a "surface changed" callback, so
// start the video here instead of in the callback.
if (mTargetState == STATE_PLAYING) {
start();
if (mMediaController != null) {
mMediaController.show();
}
} else if (!isPlaying() &&
(seekToPosition != 0 || getCurrentPosition() > 0)) {
if (mMediaController != null) {
// Show the media controls when we''re paused into a video and make ''em stick.
mMediaController.show(0);
}
}
}
} else {
// We don''t know the video size yet, but should start anyway.
// The video size might be reported to us later.
if (mTargetState == STATE_PLAYING) {
start();
}
}
}
};
private MediaPlayer.OnCompletionListener mCompletionListener =
new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
if (mCurrentState == STATE_PLAYBACK_COMPLETED) {
return;
}
mCurrentState = STATE_PLAYBACK_COMPLETED;
mTargetState = STATE_PLAYBACK_COMPLETED;
if (mMediaController != null) {
mMediaController.hide();
}
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
}
}
};
private MediaPlayer.OnInfoListener mInfoListener =
new MediaPlayer.OnInfoListener() {
public boolean onInfo(MediaPlayer mp, int arg1, int arg2) {
if (mOnInfoListener != null) {
mOnInfoListener.onInfo(mp, arg1, arg2);
}
return true;
}
};
private MediaPlayer.OnErrorListener mErrorListener =
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
Log.d(TAG, "Error: " + framework_err + "," + impl_err);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
if (mMediaController != null) {
mMediaController.hide();
}
/* If an error handler has been supplied, use it and finish. */
if (mOnErrorListener != null) {
if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
return true;
}
}
if (getWindowToken() != null) {
// Resources r = mContext.getResources();
int messageId;
if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
messageId = R.string.VideoView_error_text_invalid_progressive_playback;
} else {
messageId = R.string.VideoView_error_text_unknown;
}
new AlertDialog.Builder(mContext)
.setMessage(messageId)
.setPositiveButton(R.string.VideoView_error_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* If we get here, there is no onError listener, so
* at least inform them that the video is over.
*/
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
}
}
})
.setCancelable(false)
.show();
}
return true;
}
};
private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
new MediaPlayer.OnBufferingUpdateListener() {
public void onBufferingUpdate(MediaPlayer mp, int percent) {
mCurrentBufferPercentage = percent;
}
};
/**
* Register a callback to be invoked when the media file
* is loaded and ready to go.
*
* @param l The callback that will be run
*/
public void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
{
mOnPreparedListener = l;
}
/**
* Register a callback to be invoked when the end of a media file
* has been reached during playback.
*
* @param l The callback that will be run
*/
public void setOnCompletionListener(OnCompletionListener l)
{
mOnCompletionListener = l;
}
/**
* Register a callback to be invoked when an error occurs
* during playback or setup. If no listener is specified,
* or if the listener returned false, TextureVideoView will inform
* the user of any errors.
*
* @param l The callback that will be run
*/
public void setOnErrorListener(OnErrorListener l)
{
mOnErrorListener = l;
}
/**
* Register a callback to be invoked when an informational event
* occurs during playback or setup.
*
* @param l The callback that will be run
*/
public void setOnInfoListener(OnInfoListener l) {
mOnInfoListener = l;
}
TextureView.SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener()
{
@Override
public void onSurfaceTextureSizeChanged(final SurfaceTexture surface, final int width, final int height) {
if (mMediaPlayer!=null) {
mVideoWidth = mMediaPlayer.getVideoWidth();
mVideoHeight = mMediaPlayer.getVideoHeight();
if (mVideoWidth != 0 && mVideoHeight != 0) {
surface.setDefaultBufferSize(mVideoWidth, mVideoHeight);
requestLayout();
}}
}
@Override
public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) {
sf=surface;
mSurfaceWidth = width;
mSurfaceHeight = height;
if (mMediaPlayer!=null) { mMediaPlayer.setSurface(new Surface (surface));
}
openVideo();
}
@Override
public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(final SurfaceTexture surface) {}
};
/*
* release the media player in any state
*/
private void release(boolean cleartargetstate) {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
mPendingSubtitleTracks.clear();
mCurrentState = STATE_IDLE;
if (cleartargetstate) {
mTargetState = STATE_IDLE;
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&
keyCode != KeyEvent.KEYCODE_MENU &&
keyCode != KeyEvent.KEYCODE_CALL &&
keyCode != KeyEvent.KEYCODE_ENDCALL;
if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (mMediaPlayer.isPlaying()) {
pause();
mMediaController.show();
} else {
start();
mMediaController.hide();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
if (!mMediaPlayer.isPlaying()) {
start();
mMediaController.hide();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
if (mMediaPlayer.isPlaying()) {
pause();
mMediaController.show();
}
return true;
} else {
toggleMediaControlsVisiblity();
}
}
return super.onKeyDown(keyCode, event);
}
private void toggleMediaControlsVisiblity() {
if (mMediaController.isShowing()) {
mMediaController.hide();
} else {
mMediaController.show();
}
}
@Override
public void start() {
if (isInPlaybackState()) {
mMediaPlayer.start();
mCurrentState = STATE_PLAYING;
}
mTargetState = STATE_PLAYING;
}
@Override
public void pause() {
if (isInPlaybackState()) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
mCurrentState = STATE_PAUSED;
}
}
mTargetState = STATE_PAUSED;
}
public void suspend() {
release(false);
}
public void resume() {
openVideo();
}
@Override
public int getDuration() {
if (isInPlaybackState()) {
return mMediaPlayer.getDuration();
}
return -1;
}
@Override
public int getCurrentPosition() {
if (isInPlaybackState()) {
return mMediaPlayer.getCurrentPosition();
}
return 0;
}
@Override
public void seekTo(int msec) {
if (isInPlaybackState()) {
mMediaPlayer.seekTo(msec);
mSeekWhenPrepared = 0;
} else {
mSeekWhenPrepared = msec;
}
}
@Override
public boolean isPlaying() {
return isInPlaybackState() && mMediaPlayer.isPlaying();
}
@Override
public int getBufferPercentage() {
if (mMediaPlayer != null) {
return mCurrentBufferPercentage;
}
return 0;
}
private boolean isInPlaybackState() {
return (mMediaPlayer != null &&
mCurrentState != STATE_ERROR &&
mCurrentState != STATE_IDLE &&
mCurrentState != STATE_PREPARING);
}
@Override
public boolean canPause() {
return mCanPause;
}
@Override
public boolean canSeekBackward() {
return mCanSeekBack;
}
@Override
public boolean canSeekForward() {
return mCanSeekForward;
}
public int getAudioSessionId() {
if (mAudioSession == 0) {
MediaPlayer foo = new MediaPlayer();
mAudioSession = foo.getAudioSessionId();
foo.release();
}
return mAudioSession;
}
}
Y algún código de MainActivity:
public class MainActivity extends Activity {
static View frame1;
static player2 textureView;
static boolean pause=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
}
@Override
protected void onDestroy() {
pause=false;
super.onDestroy();
}
@Override
public void onPause() {
pause=true;
super.onPause();
}
@Override
public void onResume() {
if ((player2.sf!=null)&&(pause==true)&&(textureView.getSurfaceTexture()==null)) {
textureView.setSurfaceTexture(player2.sf);}
super.onResume();
}
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
frame1=rootView.findViewById(R.id.frame1);
textureView = (player2)rootView.findViewById(R.id.textureView1);
textureView.setVideoPath("http://master255.org/res/Клипы/S/SKRILLEX/Skrillex - Summit (feat. Ellie Goulding) [Video by Pilerats].mp4");
textureView.setMediaController(new mediac(getActivity(), frame1));
if (player2.sf != null) {
if ((pause==false)&&(textureView.getSurfaceTexture()==null)) {
textureView.setSurfaceTexture(player2.sf);}
}
textureView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(final MediaPlayer mp) {
textureView.start();
}
});
return rootView;
}
public class mediac extends MediaController
{
public mediac(Context context, View anchor)
{
super(context);
super.setAnchorView(anchor);
}
@Override
public void setAnchorView(View view)
{}
}
}
}
Este efecto se puede lograr usando un TextureView
. Esencialmente, lo que hace es crear una instancia de MediaPlayer
, prepare()
y start (), luego puede usar el método MediaPlayer.setSurface()
en cualquier TextureView
para cambiar la superficie mientras se reproduce el video sin cambios en el estado del objeto MediaPlayer
. como se indica en los documentos de android para el método setSurface()
:
This method can be called in any state and calling it does not change the object state.
Tenga en cuenta que esta implementación es para demostración, probablemente debería usar mediaplayer.prepareAsync()
y esperar una devolución de llamada con onPreparedListener()
, también deberá establecer las dimensiones correctas para el segundo TextureView
acuerdo con su tamaño de video, manejar cambios de orientación y, por supuesto, manejar excepciones adecuadamente donde sea necesario.
activity_main.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_gravity="center"
android:background="#ff0000" />
<Button
android:id="@+id/btn"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:text="Switch to second surface" />
<TextureView
android:id="@+id/tv_full"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
MainActivity.java
public class MainActivity extends Activity {
private static final String VIDEO_URI = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
private TextureView tvFull;
private MediaPlayer mp;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mp = new MediaPlayer();
try {
mp.setDataSource(this, Uri.parse(VIDEO_URI));
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.prepare();
} catch (IOException e) {
e.printStackTrace();
}
((ViewPager) findViewById(R.id.pager)).setAdapter(new PagerAdapter() {
@Override public int getCount() {
return 1;
}
@Override public boolean isViewFromObject(View view, Object o) {
return view == o;
}
@Override public Object instantiateItem(ViewGroup container, int position) {
final TextureView tv = new TextureView(MainActivity.this);
tv.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
tv.setSurfaceTextureListener(null);
mp.setSurface(new Surface(surfaceTexture));
mp.start();
}
@Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {}
@Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}
});
if (tv.isAvailable()) {
tv.getSurfaceTextureListener().onSurfaceTextureAvailable(tv.getSurfaceTexture(),
tv.getWidth(), tv.getHeight());
}
container.addView(tv, 0);
return tv;
}
@Override public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
});
tvFull = (TextureView) findViewById(R.id.tv_full);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
tvFull.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
tvFull.setSurfaceTextureListener(null);
mp.setSurface(new Surface(surfaceTexture));
}
@Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {
}
@Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
});
if (tvFull.isAvailable()) {
tvFull.getSurfaceTextureListener().onSurfaceTextureAvailable(tvFull.getSurfaceTexture(),
tvFull.getWidth(), tvFull.getHeight());
}
}
});
}
@Override protected void onDestroy() {
mp.reset();
mp.release();
super.onDestroy();
}
}