如何使用自定义android.media.MediaDataSource和android.media.MediaPlayer?

Eug*_*ene 7 java android url-scheme android-mediaplayer

我知道Android MediaPlayer是一件好事.它允许我们播放本地文件和媒体流.它很容易使用(例如):

MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource("http://streaming.shoutcast.com/80sPlanet"); // this steam broadcasts audio/mpeg
mediaPlayer.prepareAsync();
mediaPlayer.start();
Run Code Online (Sandbox Code Playgroud)

可以通过调用setDataSource()带有不同参数集的重载来设置不同类型的DataSource .这个函数有一个有趣的原型:

void setDataSource(MediaDataSource dataSource) 
Run Code Online (Sandbox Code Playgroud)

看起来可以完全覆盖DataSource您自己的实现.它确实有效:

import android.media.MediaDataSource;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.HttpURLConnection;

public class UrlMediaDataSource extends MediaDataSource {
    URL url;
    HttpURLConnection connection;
    BufferedInputStream stream;

    public UrlMediaDataSource(URL url) throws IOException {
        this.url = url;
        connection = (HttpURLConnection) url.openConnection();
    }

    @Override
    public long getSize() {
        return 0;
    }

    @Override
    public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
        if (stream == null)
            stream = new BufferedInputStream(connection.getInputStream());
        return stream.read(buffer, offset, size);
    }

    @Override
    public void close() throws IOException {
        stream.close();
        stream = null;
        connection.disconnect();
        connection = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

并在主要代码中:

UrlMediaDataSource dataSource = new UrlMediaDataSource(new URL("http://streaming.shoutcast.com/80sPlanet"));
mediaPlayer.setDataSource(dataSource);
Run Code Online (Sandbox Code Playgroud)

是的,这很好用.但是如果我尝试音频/ aacp广播流(例如:" http://111.223.51.8:8005 " - 它是"COOLfahrenheit 93"收音机),则播放器不播放.Logcat跟踪:

06-07 23:26:01.680 1352-1147/? E/GenericSource: Failed to init from data source!
06-07 23:26:01.681 1352-1093/? D/NuPlayerDriver: notifyListener_l(0xf3e051e0), (100, 1, -2147483648)
06-07 23:26:01.735 1352-2013/? D/NuPlayerDriver: reset(0xf3e051e0)
06-07 23:26:01.735 1352-2013/? D/NuPlayerDriver: notifyListener_l(0xf3e051e0), (8, 0, 0)
06-07 23:26:01.736 1352-1093/? D/NuPlayerDriver: notifyResetComplete(0xf3e051e0)
Run Code Online (Sandbox Code Playgroud)

但是,当没有使用自定义时,URL工作正常(音乐播放)MediaDataSource:

mediaPlayer.setDataSource("http://111.223.51.8:8005");
Run Code Online (Sandbox Code Playgroud)

有人知道管理这个的正确方法吗?只是不建议我URL直接使用- 我需要一个自定义MediaDataSource来访问流的原始数据.

azi*_*ian 3

要点是,确实MediaPlayer可以播放音频/mpeg(两种方式 - 通过 URL 和通过自定义MediaDataSource),但音频/aacp流只能通过 URL as 播放DataSource

那么,让我们了解一下幕后发生了什么。

当您将 URL 作为数据源传递时,将执行此检查:


    if ("file".equals(scheme)) {
        path = uri.getPath();
    } else if (scheme != null) {
        // handle non-file sources
        nativeSetDataSource(
            MediaHTTPService.createHttpServiceBinderIfNecessary(path),
            path,
            keys,
            values);
        return;
    }

MediaPlayer 使用 MediaHTTPService类,它负责提供来自httphttpswidevine协议的数据。MediaHTTPService内部使用MediaHTTPConnection,它承担了处理此类流的所有繁重工作。不幸的是,这些 API 尚未公开,但您可以在MediaHTTPConnection源(特别是seekTo方法)中看到如何建立连接。因此,您提供的自定义数据源MediaPlayer应该大致描述该类实现的逻辑MediaHTTPConnection