MediaExtractor не понимает потоки аудио /aacp

У меня есть своя MediaDataSource:



    class MyDataSource extends MediaDataSource {
        private static final String TAG = "MyDataSource";
        private HttpURLConnection connection;
        private BufferedInputStream inputStream;

        MyDataSource(@NonNull URL streamURL) throws Throwable {
            this.connection = (HttpURLConnection) streamURL.openConnection();
            this.connection.setRequestMethod("GET");
            this.connection.addRequestProperty("Icy-Metadata", "0");
            this.connection.connect();
            int responseCode = this.connection.getResponseCode();
            if (responseCode != 200)
                throw new IOException("http response code " + responseCode);
            for (Map.Entry<String, List<String>> header: this.connection.getHeaderFields().entrySet()) {
                for (String headerValue : header.getValue())
                    Log.v(TAG, "responseHeader(" + header.getKey() + ") = \"" + headerValue + "\"");
            }
            this.inputStream = new BufferedInputStream(connection.getInputStream());
        }

        @Override
        public long getSize() {
            return -1;
        }

        @Override
        public int readAt(long position, @NonNull byte[] buffer, int offset, int size) throws IOException {
            int bytesRead;
            int bytesReadTotal = 0;
            do {
                bytesRead = this.inputStream.read(buffer, offset + bytesReadTotal, size - bytesReadTotal);
                bytesReadTotal += bytesRead;
            } while(bytesRead != 0 && bytesReadTotal < size);
            return bytesReadTotal;
        }

        @Override
        public void close() {
            try {
                if (inputStream != null) {
                    inputStream.close();
                    inputStream = null;
                }
                if (connection != null) {
                    connection.disconnect();
                    connection = null;
                }
            } catch(IOException e) {
                Log.e(TAG, "close", e);
            }
        }
    }

И когда я пытаюсь играть MP3 поток (напр. A.0.0.00Radio):



    MyDataSource dataSource = new MyDataSource(new URL("http://streaming.shoutcast.com/80sPlanet"));
    MediaExtractor mediaExtractor = new MediaExtractor();
    mediaExtractor.setDataSource();
    MediaFormat mediaFormat = mediaExtractor.getTrackFormat(0);
    String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
    Log.v("Player", "mime: " + mime);
    mediaExtractor.selectTrack(0);
    MediaCodec mediaCodec = MediaCodec.createDecoderByType(mime);
    mediaCodec.configure(this.mediaFormat, null, null, 0);
    int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
    AudioTrack audioTrack = new AudioTrack(
        AudioManager.STREAM_MUSIC,
        sampleRate,
        AudioFormat.CHANNEL_OUT_STEREO,
        AudioFormat.ENCODING_PCM_16BIT,
        AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT),
        AudioTrack.MODE_STREAM);
    mediaCodec.setCallback(new MyCodecCallback());
    mediaCodec.start();
    audioTrack.play();

Я вижу следующее Logcat trace:

    07-24 18: 11: 49.958 7408-7671 / com.sample.sandbox V / MyDataSource: responseHeader (null) = "HTTP / 1.1 200 OK" 07-24 18: 11: 49.958 7408-7671 / com.sample.sandbox V / MyDataSource: responseHeader (Access-Control-Allow-Headers) = "Источник, Принять, X-Запрошенный-с, Тип контента"
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Access-Control-Allow-Methods) = "GET, OPTIONS, HEAD"
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Access-Control-Allow-Origin) = "*"
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Cache-Control) = "no-cache, no-store"
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Connection) = "close"
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Content-Type) = "audio/mpeg"
    07-24 18:11:49,958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Date) = " Пн, 24 июля 2017 18:11:59 GMT"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Expires) = "Пн, 26 июля 1997, 05:00:00 GMT", 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-br) = "128"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-genre) = "Десятилетия,80-е годы"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-name) = "A.0.0.00Radio: все 80-е годы за все время"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-note1) = "
Для этого потока требуется Winamp
" 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-note2) = "SHOUTcast DNAS / posix (linux x64) v2.5.1.725
" 07-24 18: 11: 49.959 7408-7671 / com.sample. песочница V/MyDataSource: responseHeader(icy-pub) = "1" 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-sr) = "44100" 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-url) = "http://a.0.00radio.com/80s/" 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Pragma) = "no-cache" 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Server) = "Icecast 2.3.3-kh8" 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Received-Millis) = "1500919909958" 07-24 18:11:49,959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Response-Source) = "NETWORK 200" 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Selected-Protocol) = "http/1.1" 07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Sent-Millis) = "1500919909816" 07-24 18:11:49.961 7408-7671/com.sample.sandbox E/WVMExtractor: Не удалось открыть libwvm.so: Ошибка dlopen: библиотека "libwvm.so" не найдена 07-24 18:11:49.962 7408-7671/com.sample.sandbox V/Player: mime: audio/mpeg 07-24 18:11:49.964 7408-7681/com.sample.sandbox I/OMXClient: Using клиент OMX mux. 07-24 18:11:50.170 7408-7681/com.sample.sandbox I/MediaCodec: MediaCodec будет работать в асинхронном режиме [...]

Кажется, что все в порядке (поток на самом деле играет через устройство).
Но если я попытаюсь открыть AAC поток (напр. COOLfahrenheit 93):



    MyDataSource dataSource = new MyDataSource(new URL("http://111.223.51.8:8005"));
    [...]

MediaExtractor сходит с ума

    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(null) = "HTTP/1.0 200 OK"
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(content-type) = "audio/aacp"
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-br) = "128"
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-genre) = "Easy Listening, Pop"
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-name) = "COOLfahrenheit 93 - (4)"
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-note1) = "
Для этого потока требуется Winamp
" 07-24 18: 38: 43.863 32284-32690 / com.sample.sandbox V / MyDataSource: responseHeader (icy-note2) = "SHOUTcast DNAS / posix (linux x64) v2.4.7.256
" 07-24 18: 38: 43.863 32284-32690 / com.sample.sandbox V / MyDataSource: responseHeader (icy-pub) = "1" 07-24 18: 38: 43.863 32284-32690 / com.sample.sandbox V / MyDataSource: responseHeader (icy-url) = " http://www.coolism.net/ " 07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Received-Millis) = "1500921523862" 07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Response-Source) = "NETWORK 200" 07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Selected-Protocol) = "http/1.0" 07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Sent-Millis) = "1500921523387" 07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Clacks-Overhead) = "GNU Terry Pratchett" 07-24 18:38:45.424 32284-32690/com.sample.sandbox E/WVMExtractor: Не удалось открыть libwvm.so: сбой dlopen: библиотека "libwvm.so" не найдена 07-24: 38: 45,425 32284-32690/com.sample.sandbox E/PlayerThread: error java.io.IOException: Не удалось создать экземпляр экстрактора. на android.media.MediaExtractor.setDataSource(собственный метод) на com.sample.sandbox.Player.open (Player.java:204) at com.sample.sandbox.Player. (Player.java:231) на com.sample.sandbox.PlayerThread.run(PlayerThread.java:28)

Кто-нибудь знает в чем проблема? Вопрос определенно не в самом потоке - он полностью актуален.

1 ответ

Решение

Моей главной ошибкой было игнорировать position аргумент MediaDataSource::readAt() метод.
Оказалось, что MediaExtractor выполняет много пропусков по файлу (как вперед, так и назад! - и это очень раздражает при потоковой передаче HLS).
Я заметил, что количество этих пропусков (и его диапазон) зависит от типа контента, а также от конкретного кодека. И мой главный вопрос в этом вопросе былMediaExtractor не понимает aacp"потому что кодек AAC настоятельно требует пропуска, а кодек MP3 - нет.

Другие вопросы по тегам