Использование произвольного потока в качестве источника для MediaPlayer

StackOverflow https://stackoverflow.com/questions/8809608

Вопрос

Я хотел бы использовать произвольный inputstream в качестве источника данных для объекта MediaPlayer.

Причина этого заключается в том, что используемым INPUTSTREAM, который я использую, является авторизованным HTTPS -соединением с медиа -ресурсом на удаленном сервере. Передача URL в этом случае, очевидно, не будет работать как аутентификация. Однако я могу выполнить аутентификацию отдельно и получить входную серию для ресурса - проблема в том, что мне делать, когда у меня есть?

Я подумал о возможности использования именованной трубы и передачи его FileScriptor в метод SetDatareSource MediaPlayer. Есть ли способ создать названные трубы в Android (без использования NDK)?

Любое другое предложение приветствуются.

Это было полезно?

Решение 2

Другим решением было бы запустить прокси -сервер HTTP на LocalHost. Медиаплеер подключится к этому серверу с SetDataSource (контекст контекста, URI URI). Это решение работает лучше, чем предыдущее и не вызывает воспроизведения сбоя.

Другие советы

Я думаю, что нашел решение. Я был бы признателен, если бы другие заинтересованные лица попробовали это самостоятельно и сообщили о результатах с помощью моделей устройств и версии SDK.

Я видел подобные посты, которые прямо к этому, но я подумал, что все равно опубликую их, так как они новее и, кажется, работают над более новыми версиями SDK - пока он работает на моем Nexus One, работающем Android 2.3.6.

Решение опирается на то, что вводится входной поток в локальный файл (у меня есть этот файл на внешнем хранилище, но, вероятно, можно поместить его на хранение Intenal) и предоставить дескриптор этого файла для экземпляра MediaPlayer.

Следующее работает в методе Doinbackground некоторой Asynctask, который делает Audioplayback:

@Override
protected
Void doInBackground(LibraryItem... params)
{
    ...

    MediaPlayer player = new MediaPlayer();
    setListeners(player);

    try {
        _remoteStream = getMyInputStreamSomehow();
        File tempFile = File.createTempFile(...);
        tempFile.deleteOnExit();
        _localInStream = new FileInputStream(tempFile);
        _localOutStream = new FileOutputStream(tempFile);
        int buffered = bufferMedia(
            _remoteStream, _localOutStream, BUFFER_TARGET_SIZE      // = 128KB for instance
        );

        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
        player.setDataSource(_localInStream.getFD());
        player.prepareAsync();

        int streamed = 0;
        while (buffered >= 0) {
            buffered = bufferMedia(
                _remoteStream, _localOutStream, BUFFER_TARGET_SIZE
            );
        }
    } 
    catch (Exception exception) {
        // Handle errors as you see fit
    }

    return null;
}

Метод Buffermedia буферизирует байты nbytes или до тех пор, пока не будет достигнут конец ввода:

private
int bufferMedia(InputStream inStream, OutputStream outStream, int nBytes)
throws IOException
{
    final int BUFFER_SIZE = 8 * (1 << 10);
    byte[] buffer = new byte[BUFFER_SIZE];          // TODO: Do static allocation instead

    int buffered = 0, read = -1;
    while (buffered < nBytes) {
        read = inStream.read(buffer);
        if (read == -1) {
            break;
        }           
        outStream.write(buffer, 0, read);
        outStream.flush();
        buffered += read;
    }

    if (read == -1 && buffered == 0) {
        return -1;
    }

    return buffered;
}

Метод SetListeners устанавливает обработчики для различных событий MediaPlayer. Наиболее важным является OnCompletionListener, который вызывается, когда воспроизведение завершено. В случаях поднятия буфера (из -за, скажем, временного медленного сетевого соединения) игрок достигнет конца локального файла и транзит в состояние PlaybackCompleted. Я определяю эти ситуации, сравнивая положение _localinStream с размером входного потока. Если позиция меньше, то воспроизведение теперь действительно завершено, и я сбросил MediaPlayer:

private
void setListeners(MediaPlayer player)
{
    // Set some other listeners as well

    player.setOnSeekCompleteListener(
        new MediaPlayer.OnSeekCompleteListener()
        {
            @Override
            public
            void onSeekComplete(MediaPlayer mp)
            {
                mp.start();
            }
        }
    );

    player.setOnCompletionListener(
        new MediaPlayer.OnCompletionListener() 
        {
            @Override
            public 
            void onCompletion(MediaPlayer mp) 
            {
                try {
                    long bytePosition = _localInStream.getChannel().position();
                    int timePosition = mp.getCurrentPosition();
                    int duration = mp.getDuration();

                    if (bytePosition < _track.size) {                           
                        mp.reset();
                        mp.setDataSource(_localInStream.getFD());
                        mp.prepare();
                        mp.seekTo(timePosition);
                    } else {                            
                        mp.release();
                    }
                } catch (IOException exception) {
                    // Handle errors as you see fit
                }
            }
        }
    );
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top