【问题标题】:Video Streaming not works on Google TV in an Android Application in 3.1视频流在 3.1 的 Android 应用程序中无法在 Google TV 上运行
【发布时间】:2012-01-10 10:14:22
【问题描述】:

我是 Android 开发的新手,我被要求在 Android 中为 Google TV 创建一个应用程序,该应用程序将向用户显示一些直播频道,并在用户选择一个时播放直播流。我已经设法做到了,而且工作正常。我使用 MediaPlayer 播放我的流媒体,而频道大部分时间都可以正常播放。

我已重写 setOnErrorListener 以了解是否有问题。这会捕获大部分错误(如果有),并且我会在显示正确消息后finish()播放器活动。

最初,当流准备就绪时,我会在进度条中向用户显示 正在加载 消息。我在调用 setOnPreparedListener 侦听器后 dismiss() 进度条和 start() MediaPlayer。

我无法运行 rtsp:// 流。玩了一会儿就挂了。

  1. 进度条仍然存在,应用程序有点卡住了。
  2. 按方向键上的返回按钮也不起作用
  3. 我在 setOnErrorListener 监听器中没有收到任何错误
  4. 我无法关闭应用程序,因为每当我单击我的应用程序图标时,它都会打开相同的黑色“正在加载”播放器页面..

使用 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);
    }
}

我创建了 UserMessageAppStatus 类来加快开发速度,我从 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 的电子邮件.. 你能检查一下吗,因为这是不将我的应用程序放在市场上的唯一原因..

标签: android eclipse google-tv


【解决方案1】:

您的问题的答案是,虽然我们确实支持 RTSP,但它是通过软件完成的,而不是硬件。当您需要重新调整它时,这也是在软件中完成的。当您展示一个相当大的尺寸(例如您的尺寸)并且需要对其进行缩放时,它会运行。给行为你所看到的。 MP4 是更好的解决方案。

【讨论】:

  • 非常感谢您的努力.. 非常感谢.. 我现在明白了这个问题的原因...但是您能更具体地了解 MP4 吗?因为它也可以有 Codec: H264 - MPEG-4 AVC (part 10) (h264) .. 我们的 RTSP 流有.. 所以具有相同编解码器的 MP4 流可能无法再次运行.... 我们使用 Wowze Server 进行流式传输.. 你能指导我了解 Wowza 服务器可以为 Android 设备生成的最佳编解码器/流类型吗??
  • Wowza 说它流式传输 H.264。 wowza.com/media-server 那应该很好用。如果我从头开始构建系统,我会使用 HLS。 Wowza 说它支持它。
  • 好吧,我们的 RTSP 流实际上是 H.264 ......但你会看到它根本不起作用......我会和我们的流媒体负责人谈谈 HLS ......我们已经等了长...所以我认为我们也应该尝试一下..非常感谢你
  • 我又打扰你了.. 但我不知道还有人问这个。我尝试运行 HTTP Live Streaming (HLS),但它也没有运行……你可以通过用 HTTP 替换 RTSP 并将“/playlist.m3u8”添加到我已经发送给你的同一个 url 来检查。
  • 下周我会再看一遍 - 不久也会有更新,应该会在这方面有所帮助。你用什么样的盒子来开发?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-15
  • 1970-01-01
  • 1970-01-01
  • 2015-02-13
  • 1970-01-01
  • 2021-06-10
  • 1970-01-01
相关资源
最近更新 更多