在安卓设备上播放m3u8视频

23

我想进行m3u8格式的实时视频流传输。因此,我尝试了下面的代码

public class StreamingPlayer extends Activity implements
OnBufferingUpdateListener, OnCompletionListener,
OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback{

    private static final String TAG = StreamingPlayer.class.getSimpleName();
    private int mVideoWidth;
    private int mVideoHeight;
    private MediaPlayer mMediaPlayer;
    private SurfaceView mPreview;
    private SurfaceHolder holder;
    private String path;

    private boolean mIsVideoSizeKnown = false;
    private boolean mIsVideoReadyToBePlayed = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mediaplayer_2);
        mPreview = (SurfaceView) findViewById(R.id.surface);
        holder = mPreview.getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    private void playVideo() {
        doCleanUp();
        try {

            /*
             * TODO: Set path variable to progressive streamable mp4 or
             * 3gpp format URL. Http protocol should be used.
             * 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.
             * 
             */

            path = "httplive://xboodangx.api.channel.livestream.com/3.0/playlist.m3u8";

            if (path == "") {
                // Tell the user to provide a media file URL.
                Toast
                .makeText(
                        this,
                        "Please edit MediaPlayerDemo_Video Activity,"
                        + " and set the path variable to your media file URL.",
                        Toast.LENGTH_LONG).show();
            } 

            Log.e("PATH", "Path = " + path);
            // Create a new media player and set the listeners
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setDataSource(path);
            mMediaPlayer.setDisplay(holder);
                    mMediaPlayer.setOnBufferingUpdateListener(this);
                    mMediaPlayer.setOnPreparedListener(this);
            mMediaPlayer.prepare();
            mMediaPlayer.setOnCompletionListener(this);
            mMediaPlayer.setOnVideoSizeChangedListener(this);
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

        } catch (Exception e) {
            Log.e(TAG, "error: " + e.getMessage(), e);
        }
    }

    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 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);
        mMediaPlayer.start();
    }


}
在logcat中显示onBufferingUpdate percent:100,但我无法看到视频。 音频可以工作,但突然卡住了。 我尝试了这个视频链接http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8它正在工作。但我的视频链接不起作用,我更改了httplive://...而不是http://,但无济于事。 我还看到了这个答案Android video stream mms and m3u8。 在上面的链接中,它显示了无法播放视频的消息。

你有没有尝试在真实设备上测试?有时候模拟器处理HTTP直播流的时候会出现问题。 - yorkw
@yorkw 感谢您的回复。是的,我在真实设备上进行了测试,而不是模拟器。 - Ramakrishna
这个 URI h t t p://myvideo.m3u8 看起来有点奇怪,你是在哪里托管媒体的?是在远程服务器上吗?如果你可以访问服务器端的广播代码,尝试将其更改为更稳定的 URL,例如 h t t p://domain-name/service-name/myvideo.m3u8。不确定是否有效,但值得一试。 - yorkw
这段代码是否正常工作了,还是在修复问题之前的版本? - Guillermo Varini
6个回答

15

该视频存在于http://www.livestream.com上。其中有用于实时流的移动 Api。

Api 是:

http://www.livestream.com/userguide/index.php?title=Mobile_API#How_to_get_mobile_compatible_clips_from_a_channel.27s_library

在上面的链接中,提供了有关移动兼容性的完整信息。要获取来自频道的 rtsp 链接,请使用此链接

http://xproshowcasex.channel-api.livestream-api.com/2.0/getstream

用您的频道名称替换proshowcase。然后获取所有移动兼容的 url,如 IPhone、Android、Blackberry 等

使用该 url 可以通过使用 video view 或 media player 在 Android 中流式传输视频。

有关更多信息,请阅读 Mobile Api 链接。

如果有人遇到同样的问题,我希望这个答案能帮到您。

祝你好运。


@GuillermoVarini 上面的代码对我不起作用。请阅读我的答案并详细告诉我您的问题,然后如果我知道答案,我会告诉您。 - Ramakrishna
问题在于我需要在2.1应用上播放M3U8视频,但找不到真正的例子来实现。在这里找到2篇帖子,但都没用。也检查过developer.android.com/,但没有发现相关内容。你说这个API可以实现吗?有实现的示例吗? - Guillermo Varini
实际上我的视频存在于livestream.com,所以我已经有一个API了,我在上面发布了那个API链接。通过这个API,我得到了RTSP链接,然后使用视频视图播放了RTSP链接视频。 - Ramakrishna
2
此链接已失效。http://xproshowcasex.channel-api.livestream-api.com/2.0/getstream - chovy

8

我播放流媒体没有问题:

videoView1.setVideoPath("http://***.net/livedemo/_definst_/stream3.stream/playlist.m3u8?wowzasessionid=773395207");
videoView1.start();

关于此消息:

无法播放视频

可能需要在您的清单文件中添加权限:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

4
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 这行代码是不必要的。 - Jorgesys
同样的问题。你找到解决办法了吗? - Cătălin Florescu
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> - SerjG

1
你尝试过通过网络浏览器直接使用本地播放器播放链接吗? 如果你无法使用本地播放器播放它,那么这意味着你当前的Android版本不支持该文件。 HTTP Live Streaming格式可能具有一些特殊性,而Android对其支持不够好,而在IOS上可以播放。

感谢您的回复。在安卓本地播放器和IOS上它都能正常工作。这个任务已经完成了。 - Ramakrishna

1

我认为你应该移动这个:

mMediaPlayer.setOnPreparedListener(this);

在调用prepare()之前


谢谢您的回复。我实现了您的想法,但它没有起作用。直到它显示onBufferingUpdate百分比:100,我才能看到视频。 - Ramakrishna

0

我尝试使用m3u8视频格式超过6个月,但没有成功。它可以在我的iPhone应用程序和本地应用程序中播放。我的流媒体服务器是Red5,没有RTSP插件。它提供RTMP流,无法在Android上进行流式传输。我等了一年,希望能够获得支持RTSP流媒体的操作系统,但谷歌没有提供。目前我正在使用一个带有Flash播放器的Web视图来流式传输实时视频(清晰度不高)。我感到很惭愧,无法向客户承认这一点,并继续寻找在Android默认播放器中播放直播流的方法。

我认为您的视频URL可能不是RTSP格式。


0

如何在Android中播放.M3U8流媒体

activity_main.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="wrap_content"
    android:orientation="vertical" >

    <VideoView
        android:id="@+id/myVideoView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

Main.java

package com.grexample.ooyalalive;

import java.net.URL;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.MediaController;
import android.widget.VideoView;

public class Main extends Activity {

    private String urlStream;
    private VideoView myVideoView;
    private URL url;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_vv);//***************
            myVideoView = (VideoView)this.findViewById(R.id.myVideoView);
            MediaController mc = new MediaController(this);
            myVideoView.setMediaController(mc);         
            urlStream = "http://jorgesys.net/i/irina_delivery@117489/master.m3u8";

            myVideoView.setVideoURI(Uri.parse(urlStream)); 

    }
}

我看到很多人在播放 .M3U8 文件时遇到了问题,这取决于流媒体使用的编解码器以及与设备的兼容性。例如,我的一些 .m3u8 文件只支持屏幕分辨率为 1200 x 800 及以上的设备。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接