我们如何使用Android媒体播放器播放youtube视频?
任何人都有想法,请解释我。
我必须使用Android默认媒体播放器播放网址:“http://www.youtube.com/embed/bIPcobKMB94?autoplay=1”。
当我使用Android媒体播放器播放此网址时,我收到了MediaPlayer错误(1,-2147483648)。
我在我的Android设备媒体播放器中播放该网址,但现在我无法在平板电脑中播放。有人帮帮我。 为什么我无法在平板电脑上播放该视频?
RTSP://v6.cache3.c.youtube.com/CiILENy73wIaGQnokCRYfXXPsBMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp
由于
答案 0 :(得分:1)
嗯,Android部分非常简单。您只需要YouTube视频的原始URI并触发其意图:
Uri uri = Uri.parse("http://<link-to-RAW-youtube-video>"); // i.e. mp4 version
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "video/*"); // important! otherwise you just download the video
startActivity(intent); // called directly from an other activity as you see
如果用户安装了多个视频播放器,用户还可以选择要用于播放的视频播放器。
这里棘手的部分与Android无关,它是如何获取YouTube视频的原始URI。通常它们是从原始YouTube视频页面的源代码中提取的,但这是另一个主题。我尝试使用自解压URI到视频的mp4版本上面的代码,它在我的Android 4.0手机上工作得很好。
编辑:
你真的必须使用原始URI到YouTube视频,对于你的视频它将是:
它很长但它会起作用:)
答案 1 :(得分:0)
我很难实现支持许多功能和格式的播放器。甚至VideoView也无法满足我的所有需求。最后,我最终编写了基于SurfaceView和MediaPlayer的自己的解决方案。这是源代码。对于本地3gp,本地mp4,http 3gp和youtube rtsp流,它在4.0.3和4.1.2上得到了验证。
请记住,目前,android上有效youtube视频的URI应如下所示:rtsp://v5.cache1.c.youtube.com/CjYLENy73wIaLQnhycnrJQ8qmRMYESARFEIJbXYtZ29vZ2xlSARSBXdhdGNoYPj_hYjnq6uUTQw=/0/0/0/video.3gp
。你可以通过http://m.youtube.video获得它们。
活动的参数由Intent设置。有很多种选择。请参阅我的评论中提供的最新源代码。您可以删除与Sequencer,Scenario和Test类相关的代码。它们特定于我的程序(用于平台测试的自动化系统)
package my.package;
import java.io.IOException;
import java.lang.ref.WeakReference;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Point;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.text.format.Time;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import my.package.Log;
import my.package.R;
import my.package.Scenario;
import my.package.Sequencer;
import my.package.Test;
import my.package.TestUtil;
/**
* An activity to display local or remote video or play audio file.
*/
public class MediaPlayerActivity extends Activity implements
OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener,
OnVideoSizeChangedListener, OnErrorListener, SurfaceHolder.Callback {
private static final String LOG_TAG = MediaPlayerActivity.class
.getSimpleName();
// Mandatory creation arguments passed by extras in starting Intent
public static final String SEQUENCER = "sequencer"; //$NON-NLS-1$
public static final String SCENARIO = "scenario"; //$NON-NLS-1$
public static final String TEST = "test"; //$NON-NLS-1$
public static final String SOURCE_URI = "uri"; //$NON-NLS-1$
// Optional creation arguments passed by extras in starting Intent
public static final String PAUSE_ON_BACKGROUND = "auto_pause"; //$NON-NLS-1$
public static final String TIMEOUT = "timeout"; //$NON-NLS-1$
public static final String LOOP = "loop"; //$NON-NLS-1$
public static final String SCREEN_ON_WHILE_PLAYING = "screen_on_while_playing"; //$NON-NLS-1$
// data arguments returned by Intent on finish
public static final String REASON = "cause"; //$NON-NLS-1$
public static final String EXCEPTION = "exception"; //$NON-NLS-1$
// additional state bundle arguments.
private static final String START_POSITION = "start"; //$NON-NLS-1$
private static final String VIDEO_WIDTH = "video_width"; //$NON-NLS-1$
private static final String VIDEO_HEIGHT = "video_height"; //$NON-NLS-1$
private WeakReference<Sequencer> mSequencer = new WeakReference<Sequencer> (null);
private WeakReference<Test> mTest = new WeakReference<Test> (null);
/**
* URI of the video/audio source.
*
* This player supports a variety of videos and audio sources, either local
* or remote.
* <p>
* An HTTP live streaming URI would be:
* {@code httplive://xboodangx.api.channel.livestream.com/3.0/playlist.m3u8}
* </p>
* <p>
* A local video file URI would be {@code file:///sdcard/spiderman.mp4}
* </p>
* <p>
* A remote 3GPP format video URI would be
* {@code http://commonsware.com/misc/test2.3gp}
* </p>
* <p>
* And finally an RTP or RTSP video source URI would be
* {@code rtsp://v4.cache1.c.youtube.com/CjYLENy73wIaLQk4RDShYkdS1BMYDSANFEIJbXYtZ29vZ2xlSARSBXdhdGNoYK-Cn8qh8J6-Tgw=/0/0/0/video.3gp}
* </p>
*/
private Uri mMediaURI;
/**
* Input: this flag is set to true if the video must be paused when the
* activity is not visible any more. The video will resume when the activity
* is visible again.
*/
private boolean mPauseOnBackground;
/**
* Input: number of milliseconds until automatic shutdown, or -1 if no
* timeout.
*/
private long mTimeout;
/**
* Input: flag set to true to loop back to the beginning of the video when
* reaching its end
*/
private boolean mLoop;
/**
* The width of the video, obtained by
* {@link #onVideoSizeChanged(MediaPlayer, int, int)}
*/
private int mVideoWidth;
/**
* The height of the video, obtained by
* {@link #onVideoSizeChanged(MediaPlayer, int, int)}
*/
private int mVideoHeight;
private MediaPlayer mMediaPlayer;
private SurfaceView mPreview;
private boolean mIsVideoSizeKnown = false;
private boolean mMediaPrepared = false;
/**
* This member is set to position the video should start. It is set when
* pausing the video and used when restoring the instance.
*/
private int mStartPosition;
private boolean mTimeoutSet;
private boolean mScreenOnWhilePlaying;
private SurfaceHolder mHolder;
private static class ShutdownHandler extends Handler {
WeakReference<MediaPlayerActivity> mActivity;
public ShutdownHandler(MediaPlayerActivity activity) {
mActivity = new WeakReference<MediaPlayerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MediaPlayerActivity activity = mActivity.get();
if (activity != null) {
activity.finishTest(Activity.RESULT_OK, null);
} else {
//Log.w(LOG_TAG, "no activity for shutdown");
}
}
}
public MediaPlayerActivity() {
super();
// These members are initialized in onCreate(Bundle) by the
// starting Intent, the first time the activity is created, and restored
// in the same method with the arguments in the saved instance bundle.
mSequencer = new WeakReference<Sequencer> (null);
mTest = new WeakReference<Test> (null);
setSourceURI(null);
setPauseOnBackground(false);
setPlayTimeout(-1);
setLooping(false);
setScreenOnWhilePlaying(true);
// Initialize internals.
mIsVideoSizeKnown = false;
mVideoWidth = mVideoHeight = 0; // unknown
mMediaPrepared = false;
mMediaPlayer = null;
mPreview = null; // set in onCreate(Bundle)
setStartPosition(0); // beginning of the video
mTimeoutSet = false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.video_player);
Intent intent = getIntent();
if (savedInstanceState != null) {
onRestoreInstanceState(savedInstanceState);
} else if (intent != null) {
Log.d(LOG_TAG, "Loading starting Intent extras...");
// read starting Intent extras.
_updateForeignReferences(intent);
setSourceURI((Uri) intent.getParcelableExtra(SOURCE_URI));
setPlayTimeout(intent.getLongExtra(TIMEOUT, -1L));
setPauseOnBackground(intent.getBooleanExtra(PAUSE_ON_BACKGROUND,
false));
setLooping(intent.getBooleanExtra(LOOP, false));
setScreenOnWhilePlaying(intent.getBooleanExtra(SCREEN_ON_WHILE_PLAYING, true));
}
mTimeoutSet = false;
_updateWidgets();
}
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(LOG_TAG, "Restoring instance state...");
// restore saved references
_updateSavedForeignReferences(savedInstanceState);
// restore saved inputs
setSourceURI(Uri.parse(savedInstanceState.getString(SOURCE_URI)));
setPlayTimeout(savedInstanceState.getLong(TIMEOUT));
setPauseOnBackground(savedInstanceState.getBoolean(PAUSE_ON_BACKGROUND));
setLooping(savedInstanceState.getBoolean(LOOP));
setScreenOnWhilePlaying(savedInstanceState.getBoolean(SCREEN_ON_WHILE_PLAYING));
// restore internals
setStartPosition(savedInstanceState.getInt(START_POSITION, 0));
mVideoWidth = savedInstanceState.getInt(VIDEO_WIDTH);
mVideoHeight = savedInstanceState.getInt(VIDEO_HEIGHT); // unknown
mIsVideoSizeKnown = (mVideoWidth > 0) && (mVideoHeight > 0);
}
@Override
protected void onResume() {
super.onResume();
if (mMediaPlayer == null) {
try {
_playMedia();
} catch (Exception e) {
_fail(e);
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(LOG_TAG, "Saving instance state");
Sequencer sequencer = mSequencer.get();
if (sequencer != null) {
outState.putInt(SEQUENCER, sequencer.getPosition());
Scenario scenario = sequencer.getScenario();
if (scenario != null) {
outState.putInt(SCENARIO, scenario.getScenarioId());
}
}
Test test = mTest.get();
if (test != null) {
outState.putString(TEST, TestUtil.getTestPath(test, TestUtil.Path.Static));
}
if (getSourceURI() != null) {
outState.putString(SOURCE_URI, getSourceURI().toString());
}
outState.putBoolean(LOOP, isLooping());
outState.putBoolean(PAUSE_ON_BACKGROUND, isPausingOnBackground());
outState.putLong(TIMEOUT, getPlayTimeout());
outState.putBoolean(SCREEN_ON_WHILE_PLAYING, isScreenOnWhilePlaying());
outState.putInt(START_POSITION, getStartPosition());
}
@Override
protected void onPause() {
super.onPause();
if (isPausingOnBackground()) {
_pausePlayback();
}
}
@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "onStop");
if (isPausingOnBackground()) {
_releaseMediaPlayer();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
// TODO: It would be fine to fail the test if the activity was destroyed
// if we didn't finished the test yet but there are far too many cases
// and I failed to implement one working with all of them!
/* if (!mInstanceSaved) {
finishTest(Activity.RESULT_FIRST_USER, new Intent().putExtra(REASON,
"Activity destroyed. Something certainly goes wrong there."));
}
*/
_releaseMediaPlayer();
}
// Restore sequencer, scenario and test references from saved state.
private void _updateSavedForeignReferences(Bundle savedInstanceState) {
int sequencer = savedInstanceState.getInt(SEQUENCER, -1);
int scenarioId = savedInstanceState.getInt(SCENARIO, -1);
mSequencer = new WeakReference<Sequencer>(null);
mTest = new WeakReference<Test>(null);
if (scenarioId >= 0 && sequencer >= 0) {
Scenario scenario = Controller.controller.getData().scenarios()
.getScenario(scenarioId);
mSequencer = new WeakReference<Sequencer>(Controller.controller
.engine().getSequencerAt(sequencer));
String testPath = savedInstanceState.getString(TEST);
if (!TextUtils.isEmpty(testPath)) {
mTest = new WeakReference<Test>(TestUtil.fromPath(
scenario.getRootTest(), testPath));
}
}
}
// Update sequencer, scenario and test references from starting Intent
protected void _updateForeignReferences(Intent intent) {
int scenarioId = intent.getIntExtra(MediaPlayerActivity.SCENARIO, -1);
Scenario scenario = Controller.controller.getData().scenarios()
.getScenario(scenarioId);
int sequencer = intent.getIntExtra(MediaPlayerActivity.SEQUENCER, -1);
mSequencer = new WeakReference<Sequencer>(null);
mTest = new WeakReference<Test>(null);
if (scenarioId >= 0 && sequencer >= 0) {
mSequencer = new WeakReference<Sequencer>(Controller.controller
.engine().getSequencerAt(sequencer));
String testPath = intent.getStringExtra(MediaPlayerActivity.TEST);
if (!TextUtils.isEmpty(testPath)) {
mTest = new WeakReference<Test>(TestUtil.fromPath(
scenario.getRootTest(), testPath));
}
}
}
/**
* Terminate the test case and finish the activity at the same time.
* <p>
* The result code and data are passed to both the parent activity and the
* {@link Test#terminate(int, Sequencer, Object)} method.
* </p>
*
* @param resultCode
* the result code. May be on of the Activity result code but
* also any other one having a meaning for the test and caller
* activity.
* @param data
* extra result data. Can be null.
*/
public void finishTest(int resultCode, Intent data) {
Test test = mTest.get();
Sequencer sequencer = mSequencer.get();
if ((test != null) && (sequencer != null)) {
test.terminate(resultCode, sequencer, data);
// prevent any further call to finishTest.
mTest = new WeakReference<Test> (null);
}
if (!isFinishing()) {
setResult(Activity.RESULT_OK, data);
finish();
}
}
@SuppressWarnings("deprecation")
private void _updateWidgets() {
SurfaceView surface = (SurfaceView) findViewById(R.id.surface);
mPreview = surface;
SurfaceHolder holder = surface.getHolder();
holder.addCallback(this);
if (VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) {
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
Log.d(LOG_TAG, "onBufferingUpdate percent:" + percent);
if (percent >= 100) {
mMediaPlayer.setOnBufferingUpdateListener(null);
}
// no display so don't bother.
}
public void onCompletion(MediaPlayer player) {
_releaseMediaPlayer();
finishTest(Activity.RESULT_OK, null);
}
private void _rearmPlayer() {
mVideoWidth = 0;
mVideoHeight = 0;
mMediaPrepared = false;
mIsVideoSizeKnown = false;
}
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
if (mIsVideoSizeKnown) return; // further notifications are completely wrong!!
Log.i(LOG_TAG, "Video size: " + width + "x" + height);
mIsVideoSizeKnown = true;
mVideoWidth = width;
mVideoHeight = height;
if (width > 0 && height > 0) {
_fitSurfaceForVideo();
} else {
// audio only or video size unknown.
}
if (mMediaPrepared) {
_startPlayback();
}
}
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private void _fitSurfaceForVideo() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
if (VERSION.SDK_INT >= 13) {
display.getSize(size);
} else {
size.x = display.getWidth();
size.y = display.getHeight();
}
double ratioVideo = (double)mVideoWidth / mVideoHeight;
double ratioScreen = (double)size.x / size.y;
if (ratioScreen > ratioVideo) {
// fit in height and scale the width to match the video ratio
mVideoHeight = size.y;
mVideoWidth = (int) (size.y / ratioVideo);
} else {
// fit in width and scale height to keep the video ratio
mVideoWidth = size.x;
mVideoHeight = (int) (size.x / ratioVideo);
}
}
public void onPrepared(MediaPlayer mediaplayer) {
mMediaPrepared = true;
if (mIsVideoSizeKnown) {
_startPlayback();
}
}
private void _startPlayback() {
SurfaceHolder holder = mPreview.getHolder();
if (mVideoWidth > 0 && mVideoHeight > 0) {
holder.setFixedSize(mVideoWidth, mVideoHeight);
}
if (mStartPosition > 0) {
Log.i(LOG_TAG, String.format("Resume at %f seconds", mStartPosition / 1000.f));
mMediaPlayer.seekTo(mStartPosition);
} else {
Log.i(LOG_TAG, "Start video");
}
if (!mTimeoutSet && (getPlayTimeout() > 0)) {
// this is a constant time reference: deduce the time already played.
long remaining = getPlayTimeout() - mStartPosition;
Time time = new Time();
time.setToNow();
time.second += remaining / 1000;
time.normalize(false);
Log.i(LOG_TAG, "Will end the video on " + time.format2445());
new ShutdownHandler(this).sendEmptyMessageDelayed(0, remaining);
mTimeoutSet = true;
}
mMediaPlayer.start();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.d(LOG_TAG, String.format(
"surfaceChanged called: format=%d, width=%d, height=%d",
format, width, height));
}
public void surfaceDestroyed(SurfaceHolder surfaceholder) {
Log.d(LOG_TAG, "surfaceDestroyed called");
mHolder = null;
if (mMediaPlayer != null) {
mMediaPlayer.setDisplay(null);
}
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(LOG_TAG, "surfaceCreated called");
mHolder = holder;
if (mMediaPlayer != null) {
// surface created after the media player
try {
mMediaPlayer.setDisplay(holder);
mMediaPlayer.setScreenOnWhilePlaying(isScreenOnWhilePlaying());
mMediaPlayer.setOnCompletionListener(this);
if (!mMediaPrepared) {
mMediaPlayer.setDataSource(this, mMediaURI);
mMediaPlayer.prepareAsync();
}
} catch (IllegalStateException e) {
_fail(e);
} catch (IllegalArgumentException e) {
_fail(e);
} catch (SecurityException e) {
_fail(e);
} catch (IOException e) {
_fail(e);
}
}
}
private void _playMedia() throws IllegalArgumentException,
SecurityException, IllegalStateException, IOException {
Log.d(LOG_TAG, "_playMedia()");
_rearmPlayer();
/*
* The video should be in a streamable mp4 or 3gpp format. The URI
* scheme may be Http. Mediaplayer can only play
* "progressive streamable contents" which basically means: 1. the movie
* atom has to precede all the media data atoms. 2. The clip has to be
* reasonably interleaved.
*/
if (mMediaURI != null) {
Log.i(LOG_TAG, "Source: " + mMediaURI);
// Create a new media player and set the listeners
if (mMediaPlayer != null) {
mMediaPlayer.reset();
} else {
mMediaPlayer = new MediaPlayer();
}
// mMediaPlayer.setDataSource(this, mMediaURI);
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setLooping(isLooping());
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnVideoSizeChangedListener(this);
if (mHolder != null) {
// surface created before the media player
mMediaPlayer.setDisplay(mHolder);
mMediaPlayer.setScreenOnWhilePlaying(isScreenOnWhilePlaying());
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setDataSource(this, mMediaURI);
mMediaPlayer.prepareAsync();
}
} else {
_fail("No video source defined");
}
}
// fail due to exception
private void _fail(Exception e) {
Log.e(LOG_TAG, e);
Intent data = new Intent();
data.putExtra(EXCEPTION, e);
finishTest(Activity.RESULT_FIRST_USER, data);
}
// fail due to generic error
private void _fail(String text) {
Log.e(LOG_TAG, text);
Intent data = new Intent();
data.putExtra(REASON, text);
finishTest(Activity.RESULT_FIRST_USER, data);
}
private void _pausePlayback() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
Log.i(LOG_TAG, "Pause playback");
mMediaPlayer.pause();
// retain position for use by onSaveInstanceState(Bundle)
setStartPosition(mMediaPlayer.getCurrentPosition());
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
Intent data = new Intent();
data.putExtra(REASON, "canceled by user");
finishTest(Activity.RESULT_CANCELED, data);
}
private void _releaseMediaPlayer() {
_stopPlayback();
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
_rearmPlayer();
}
private void _stopPlayback() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
_pausePlayback();
Log.i(LOG_TAG, "stop video");
mMediaPlayer.stop();
}
}
public boolean isPausingOnBackground() {
return mPauseOnBackground;
}
public void setPauseOnBackground(boolean pause) {
Log.d(LOG_TAG, "Pausing on background: " + pause);
this.mPauseOnBackground = pause;
}
public Uri getSourceURI() {
return mMediaURI;
}
public void setSourceURI(Uri uri) {
Log.d(LOG_TAG, "Media source: " + uri);
this.mMediaURI = uri;
}
public long getPlayTimeout() {
return mTimeout;
}
public void setPlayTimeout(long timeout) {
Log.d(LOG_TAG, "Play length (ms): " + timeout);
this.mTimeout = timeout;
}
public boolean isLooping() {
return mLoop;
}
public void setLooping(boolean loop) {
Log.d(LOG_TAG, "Is looping: " + loop);
this.mLoop = loop;
}
public int getStartPosition() {
int position = 0;
if (mMediaPlayer != null) {
position = mMediaPlayer.getCurrentPosition();
}
return position;
}
public void setStartPosition(int position) {
Log.d(LOG_TAG, String.format("Start at %fs", position / 1000.));
this.mStartPosition = position;
}
public boolean isScreenOnWhilePlaying() {
return mScreenOnWhilePlaying;
}
public void setScreenOnWhilePlaying(boolean screenOnWhilePlaying) {
Log.d(LOG_TAG, "Screen ON while playing: " + screenOnWhilePlaying);
this.mScreenOnWhilePlaying = screenOnWhilePlaying;
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
_fail(String.format("Media player error: what=%d, extra=%d", what, extra));
return true;
}
}
包含SurfaceView的布局资源:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<SurfaceView
android:id="@+id/surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
使用活动的一个例子:
Intent intent = new Intent(parent, MediaPlayerActivity.class);
intent.putExtra(MediaPlayerActivity.SOURCE_URI, this.getSourceURI());
intent.putExtra(MediaPlayerActivity.PAUSE_ON_BACKGROUND,
this.getPauseOnBackground());
Scenario scenario = sequencer.getScenario();
intent.putExtra(MediaPlayerActivity.SCENARIO, scenario.getScenarioId());
intent.putExtra(MediaPlayerActivity.SEQUENCER, sequencer.getPosition());
intent.putExtra(MediaPlayerActivity.TEST, TestUtil.getTestPath(
scenario.getCurrentTest(), TestUtil.Path.Static));
// timeout option
TimeSpan timeout = this.getTimeout();
if (!timeout.isNull()) {
timeout.renew();
intent.putExtra(MediaPlayerActivity.TIMEOUT, timeout.value());
}
intent.putExtra(MediaPlayerActivity.LOOP, this.isLooping());
startActivity(intent);
答案 2 :(得分:0)
@Sock您是否考虑过使用适用于Android的YouTube API。他们拥有出色的播放器视图,可以为您提供视频上的大量控制和事件监听功能。我最近发布了一个关于使用API的教程,如果它可能符合您的需求,请查看here