MediaExtractor无法理解音频

MediaExtractor无法理解音频

本文介绍了MediaExtractor无法理解音频/aacp流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有自己的MediaDataSource:

I have my own 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 ):

And when I'm trying to play MP3 stream (ex. 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:

I see the following 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) = "Origin, Accept, X-Requested-With, Content-Type"
    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) = "Mon, 24 Jul 2017 18:11:59 GMT"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Expires) = "Mon, 26 Jul 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) = "Decades,80s"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-name) = "A.0.0.00Radio:All 80s All The Time"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice1) = "<BR>This stream requires <a href="http://www.winamp.com">Winamp</a><BR>"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice2) = "SHOUTcast DNAS/posix(linux x64) v2.5.1.725<BR>"
    07-24 18:11:49.959 7408-7671/com.sample.sandbox 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: Failed to open libwvm.so: dlopen failed: library "libwvm.so" not found
    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 client-side OMX mux.
    07-24 18:11:50.170 7408-7681/com.sample.sandbox I/MediaCodec: MediaCodec will operate in async mode
    [...]

似乎一切正常(流实际上正在通过设备播放).
但是,如果我尝试打开AAC流(例如 COOLfahrenheit 93 ):

It seems that everything is OK (the stream is actually playing through the device).
But if I try to open AAC stream (ex. 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-notice1) = "<BR>This stream requires <a href="http://www.winamp.com">Winamp</a><BR>"
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice2) = "SHOUTcast DNAS/posix(linux x64) v2.4.7.256<BR>"
    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: Failed to open libwvm.so: dlopen failed: library "libwvm.so" not found
    07-24 18:38:45.425 32284-32690/com.sample.sandbox E/PlayerThread: error
                                                                              java.io.IOException: Failed to instantiate extractor.
                                                                                  at android.media.MediaExtractor.setDataSource(Native Method)
                                                                                  at com.sample.sandbox.Player.open(Player.java:204)
                                                                                  at com.sample.sandbox.Player.<init>(Player.java:231)
                                                                                  at com.sample.sandbox.PlayerThread.run(PlayerThread.java:28)


有人知道这是什么问题吗?问题绝对不在流本身中,而是完全有效的.


Does anybody know what is the issue? The issue is definitely is not in the stream itself - it is fully valid.

推荐答案

我的主要错误是忽略MediaDataSource::readAt()方法的position自变量.
事实证明,MediaExtractor在文件中执行了很多跳跃(向前和向后!-当您流式传输HLS时,这非常烦人).
我注意到这些跳过的数量(及其范围)取决于内容类型以及特定的编解码器.我在这个问题中的主要观点是"MediaExtractor不理解aacp",因为AAC编解码器强烈要求跳过,而MP3编解码器则不需要.

My main mistake was to ignore the position argument of the MediaDataSource::readAt() method.
It turned out that MediaExtractor performs A LOT of skips through the file (forward as well as backward! - and this is very annoying when you are streaming HLS).
I've been noticed that amount of these skips (and its' range) depend on the content type as well as particular codec. And my main point in this question was "MediaExtractor does not understand aacp" because AAC codec strongly requires skipping, but MP3 codec does not.

这篇关于MediaExtractor无法理解音频/aacp流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 09:13