【发布时间】:2012-01-10 10:14:22
【问题描述】:
我是 Android 开发的新手,我被要求在 Android 中为 Google TV 创建一个应用程序,该应用程序将向用户显示一些直播频道,并在用户选择一个时播放直播流。我已经设法做到了,而且工作正常。我使用 MediaPlayer 播放我的流媒体,而频道大部分时间都可以正常播放。
我已重写 setOnErrorListener 以了解是否有问题。这会捕获大部分错误(如果有),并且我会在显示正确消息后finish()播放器活动。
最初,当流准备就绪时,我会在进度条中向用户显示 正在加载 消息。我在调用 setOnPreparedListener 侦听器后 dismiss() 进度条和 start() MediaPlayer。
我无法运行 rtsp:// 流。玩了一会儿就挂了。
- 进度条仍然存在,应用程序有点卡住了。
- 按方向键上的返回按钮也不起作用
- 我在 setOnErrorListener 监听器中没有收到任何错误
- 我无法关闭应用程序,因为每当我单击我的应用程序图标时,它都会打开相同的黑色“正在加载”播放器页面..
使用 Android 3.1 (API 12) 并且所有流 URL 都以 rtsp://
以下是 xml/java 文件的代码:
注意:我复制并更改了 VideoPlayer.java 和 video_player.xml 文件 MediaPlayer_Demo example。
video_player.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#000000">
<SurfaceView android:id="@+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</SurfaceView>
</LinearLayout>
错误的VideoPlayer.Java如下:
public class VideoPlayer extends Activity implements OnBufferingUpdateListener,
OnCompletionListener, OnPreparedListener, OnVideoSizeChangedListener,
SurfaceHolder.Callback, OnErrorListener {
private static final String TAG = "MediaPlayerDemo";
private int mVideoWidth;
private int mVideoHeight;
private MediaPlayer mMediaPlayer;
private SurfaceView mPreview;
private SurfaceHolder holder;
private Bundle extras;
private boolean mIsVideoSizeKnown = false;
private boolean mIsVideoReadyToBePlayed = false;
ProgressDialog progressDialog;
/**
*
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.video_player);
this.extras = getIntent().getExtras();
mPreview = (SurfaceView) findViewById(R.id.surface);
holder = mPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
private void playVideo() {
doCleanUp();
try {
this.progressDialog = ProgressDialog.show(this, "", "Loading...",
true);
// Check Internet Status
if (!AppStatus.isInternetAvailable(this)) {
showErrorToUser(getResources().getText(R.string.about_net)
.toString(),
"Internet connection is not available or Wi-Fi is not enabled.");
} else {
// Create a new media player and set the listeners
String videoStreamUrl = extras.getString("streamUrl");
if (videoStreamUrl != null) {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(videoStreamUrl);
mMediaPlayer.setDisplay(holder);
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnVideoSizeChangedListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.prepareAsync();
}
else
{
showErrorToUser("Invalid Stream URI",
"The Video's URI is not valid. Please provide correct URI.");
}
}
} catch (Exception e) {
Log.e(TAG, "error: " + e.getMessage(), e);
errorOccured();
}
}
public void onBufferingUpdate(MediaPlayer arg0, int percent) {
Log.d(TAG, "onBufferingUpdate percent:" + percent);
}
public void onCompletion(MediaPlayer arg0) {
Log.d(TAG, "onCompletion called");
}
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
Log.v(TAG, "onVideoSizeChanged called");
if (width == 0 || height == 0) {
Log.e(TAG, "invalid video width(" + width + ") or height(" + height
+ ")");
return;
}
mIsVideoSizeKnown = true;
mVideoWidth = width;
mVideoHeight = height;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
public void onPrepared(MediaPlayer mediaplayer) {
Log.d(TAG, "onPrepared called");
mIsVideoReadyToBePlayed = true;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
startVideoPlayback();
}
}
public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) {
Log.d(TAG, "surfaceChanged called");
}
public void surfaceDestroyed(SurfaceHolder surfaceholder) {
Log.d(TAG, "surfaceDestroyed called");
}
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated called");
playVideo();
}
@Override
protected void onPause() {
super.onPause();
releaseMediaPlayer();
doCleanUp();
}
@Override
protected void onStop() {
super.onStop();
releaseMediaPlayer();
doCleanUp();
}
@Override
protected void onDestroy() {
super.onDestroy();
releaseMediaPlayer();
doCleanUp();
}
private void releaseMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
}
private void doCleanUp() {
mVideoWidth = 0;
mVideoHeight = 0;
mIsVideoReadyToBePlayed = false;
mIsVideoSizeKnown = false;
}
private void startVideoPlayback() {
Log.v(TAG, "startVideoPlayback");
holder.setFixedSize(mVideoWidth, mVideoHeight);
this.progressDialog.dismiss();
mMediaPlayer.start();
}
public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
errorOccured();
return true;
}
private void errorOccured() {
UserMessage
.showPopup(
this,
"Channel not available",
"We are sorry for the inconvenience but this channel is not available right now. Please try later.");
}
private void showErrorToUser(String title, String message) {
// Hide Progress Bar
this.progressDialog.dismiss();
releaseMediaPlayer();
doCleanUp();
UserMessage.showPopup(this, title, message);
}
}
我创建了 UserMessage 和 AppStatus 类来加快开发速度,我从 SO 中学到了它们。这些课程很好,根据我的知识和理解,不会导致任何错误。我提供它们只是为了分享和更好地了解 VideoPlayer.java。
这些类如下,仅供分享,方便其他人使用:
UserMessage.Java
public class UserMessage {
public static void showPopup(final Activity activity, String title, String message) {
View view = View.inflate(activity, R.layout.about, null);
TextView textView = (TextView) view.findViewById(R.id.message);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(message);
new AlertDialog.Builder(activity)
.setTitle(title)
.setView(view)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
activity.finish();
}
}).show();
}
}
AppStatus.Java
public class AppStatus {
public static boolean isInternetAvailable(Context context) {
ConnectivityManager mgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = mgr.getActiveNetworkInfo();
return (netInfo != null && netInfo.isConnected() && netInfo.isAvailable());
}
}
非常感谢任何帮助,因为我的应用程序即将完成。
感谢您的阅读和思考,即使您无法回答我。
【问题讨论】:
-
流是什么视频类型?
-
好吧,我不确定流的类型……但我播放的所有 URL 都以 rtsp:// 开头……我在某处看到 Android 支持这种格式
-
应该是支持的,但是对于一个应用来说并不常见。 Flash 主要使用它。首先 - 看看您是否可以在手机或平板电脑上播放视频。如果可行,请将您的网址发给我,我会看看。 google-tv-fishtank-team (at) googlegroups dot com
-
好的,当它给我带来问题时,我会将特定链接发送给您,因为我有很多链接,我不确定是哪一个导致了问题。非常感谢
-
@Les ...几天前我已经在 google-tv-fishtank-team (at) googlegroups dot com 发送了带有 URL 的电子邮件.. 你能检查一下吗,因为这是不将我的应用程序放在市场上的唯一原因..